ucom.c revision 1.13
1/*	$NetBSD: ucom.c,v 1.13 2000/01/25 13:56:23 augustss Exp $	*/
2
3/*
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (augustss@carlstedt.se) at
9 * Carlstedt Research & Technology.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 *    must display the following acknowledgement:
21 *        This product includes software developed by the NetBSD
22 *        Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 *    contributors may be used to endorse or promote products derived
25 *    from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/kernel.h>
43#include <sys/ioctl.h>
44#include <sys/conf.h>
45#include <sys/tty.h>
46#include <sys/file.h>
47#include <sys/select.h>
48#include <sys/proc.h>
49#include <sys/vnode.h>
50#include <sys/device.h>
51#include <sys/poll.h>
52
53#include <dev/usb/usb.h>
54
55#include <dev/usb/usbdi.h>
56#include <dev/usb/usbdi_util.h>
57#include <dev/usb/usbdevs.h>
58#include <dev/usb/usb_quirks.h>
59
60#include <dev/usb/ucomvar.h>
61
62#include "ucom.h"
63
64#if NUCOM > 0
65
66#ifdef UCOM_DEBUG
67#define DPRINTFN(n, x)	if (ucomdebug > (n)) logprintf x
68int ucomdebug = 0;
69#else
70#define DPRINTFN(n, x)
71#endif
72#define DPRINTF(x) DPRINTFN(0, x)
73
74#define	UCOMUNIT_MASK		0x3ffff
75#define	UCOMDIALOUT_MASK	0x80000
76#define	UCOMCALLUNIT_MASK	0x40000
77
78#define	UCOMUNIT(x)		(minor(x) & UCOMUNIT_MASK)
79#define	UCOMDIALOUT(x)		(minor(x) & UCOMDIALOUT_MASK)
80#define	UCOMCALLUNIT(x)		(minor(x) & UCOMCALLUNIT_MASK)
81
82/*
83 * These are the maximum number of bytes transferred per frame.
84 * If some really high speed devices should use this driver they
85 * may need to be increased, but this is good enough for modems.
86 */
87#define UCOMIBUFSIZE 64
88#define UCOMOBUFSIZE 256
89
90struct ucom_softc {
91	USBBASEDEVICE		sc_dev;		/* base device */
92
93	usbd_device_handle	sc_udev;	/* USB device */
94
95	usbd_interface_handle	sc_iface;	/* data interface */
96
97	int			sc_bulkin_no;	/* bulk in endpoint address */
98	usbd_pipe_handle	sc_bulkin_pipe;	/* bulk in pipe */
99	usbd_xfer_handle	sc_ixfer;	/* read request */
100	u_char			*sc_ibuf;	/* read buffer */
101
102	int			sc_bulkout_no;	/* bulk out endpoint address */
103	usbd_pipe_handle	sc_bulkout_pipe;/* bulk out pipe */
104	usbd_xfer_handle	sc_oxfer;	/* write request */
105	u_char			*sc_obuf;	/* write buffer */
106
107	struct ucom_methods     *sc_methods;
108	void                    *sc_parent;
109	int			sc_portno;
110
111	struct tty		*sc_tty;	/* our tty */
112	u_char			sc_lsr;
113	u_char			sc_msr;
114	u_char			sc_mcr;
115	u_char			sc_tx_stopped;
116	int			sc_swflags;
117
118	u_char			sc_opening;	/* lock during open */
119	u_char			sc_dying;	/* disconnecting */
120};
121
122cdev_decl(ucom);
123
124static void	ucom_cleanup	__P((struct ucom_softc *));
125static void	ucom_hwiflow	__P((struct ucom_softc *));
126static int	ucomparam	__P((struct tty *, struct termios *));
127static void	ucomstart	__P((struct tty *));
128static void	ucom_shutdown	__P((struct ucom_softc *));
129static void	ucom_dtr	__P((struct ucom_softc *, int));
130static void	ucom_rts	__P((struct ucom_softc *, int));
131static void	ucom_break	__P((struct ucom_softc *, int));
132static usbd_status ucomstartread __P((struct ucom_softc *));
133static void	ucomreadcb	__P((usbd_xfer_handle, usbd_private_handle,
134				     usbd_status status));
135static void	ucomwritecb	__P((usbd_xfer_handle, usbd_private_handle,
136				     usbd_status status));
137static void	tiocm_to_ucom	__P((struct ucom_softc *, int, int));
138static int	ucom_to_tiocm	__P((struct ucom_softc *));
139
140USB_DECLARE_DRIVER(ucom);
141
142USB_MATCH(ucom)
143{
144	return (1);
145}
146
147USB_ATTACH(ucom)
148{
149	struct ucom_softc *sc = (struct ucom_softc *)self;
150	struct ucom_attach_args *uca = aux;
151	struct tty *tp;
152
153	if (uca->portno != UCOM_UNK_PORTNO)
154		printf(": portno %d", uca->portno);
155	printf("\n");
156
157	sc->sc_udev = uca->device;
158	sc->sc_iface = uca->iface;
159	sc->sc_bulkout_no = uca->bulkout;
160	sc->sc_bulkin_no = uca->bulkin;
161	sc->sc_methods = uca->methods;
162	sc->sc_parent = uca->arg;
163	sc->sc_portno = uca->portno;
164
165	tp = ttymalloc();
166	tp->t_oproc = ucomstart;
167	tp->t_param = ucomparam;
168	sc->sc_tty = tp;
169
170	DPRINTF(("ucom_attach: tty_attach %p\n", tp));
171	tty_attach(tp);
172
173	USB_ATTACH_SUCCESS_RETURN;
174}
175
176USB_DETACH(ucom)
177{
178	struct ucom_softc *sc = (struct ucom_softc *)self;
179	int maj, mn;
180
181	DPRINTF(("ucom_detach: sc=%p flags=%d tp=%p\n",
182		 sc, flags, sc->sc_tty));
183
184	sc->sc_dying = 1;
185
186#ifdef DIAGNOSTIC
187	if (sc->sc_tty == NULL) {
188		DPRINTF(("ucom_detach: no tty\n"));
189		return (0);
190	}
191#endif
192
193	/* XXX  Use reference count? */
194
195	/* locate the major number */
196	for (maj = 0; maj < nchrdev; maj++)
197		if (cdevsw[maj].d_open == ucomopen)
198			break;
199
200	/* Nuke the vnodes for any open instances. */
201	mn = self->dv_unit;
202	vdevgone(maj, mn, mn, VCHR);
203	vdevgone(maj, mn, mn | UCOMDIALOUT_MASK, VCHR);
204	vdevgone(maj, mn, mn | UCOMCALLUNIT_MASK, VCHR);
205
206	/* Detach and free the tty. */
207	tty_detach(sc->sc_tty);
208	ttyfree(sc->sc_tty);
209	sc->sc_tty = 0;
210
211	return (0);
212}
213
214#if defined(__NetBSD__) || defined(__OpenBSD__)
215int
216ucom_activate(self, act)
217	device_ptr_t self;
218	enum devact act;
219{
220	struct ucom_softc *sc = (struct ucom_softc *)self;
221
222	switch (act) {
223	case DVACT_ACTIVATE:
224		return (EOPNOTSUPP);
225		break;
226
227	case DVACT_DEACTIVATE:
228		sc->sc_dying = 1;
229		break;
230	}
231	return (0);
232}
233#endif
234
235void
236ucom_shutdown(sc)
237	struct ucom_softc *sc;
238{
239	struct tty *tp = sc->sc_tty;
240
241	DPRINTF(("ucom_shutdown\n"));
242	/*
243	 * Hang up if necessary.  Wait a bit, so the other side has time to
244	 * notice even if we immediately open the port again.
245	 */
246	if (ISSET(tp->t_cflag, HUPCL)) {
247		ucom_dtr(sc, 0);
248		(void)tsleep(sc, TTIPRI, ttclos, hz);
249	}
250}
251
252int
253ucomopen(dev, flag, mode, p)
254	dev_t dev;
255	int flag, mode;
256	struct proc *p;
257{
258	int unit = UCOMUNIT(dev);
259	usbd_status err;
260	struct ucom_softc *sc;
261	struct tty *tp;
262	int s;
263	int error;
264
265	if (unit >= ucom_cd.cd_ndevs)
266		return (ENXIO);
267	sc = ucom_cd.cd_devs[unit];
268	if (sc == NULL)
269		return (ENXIO);
270
271	if (sc->sc_dying)
272		return (EIO);
273
274	if (ISSET(sc->sc_dev.dv_flags, DVF_ACTIVE) == 0)
275		return (ENXIO);
276
277	tp = sc->sc_tty;
278
279	DPRINTF(("ucomopen: unit=%d, tp=%p\n", unit, tp));
280
281	if (ISSET(tp->t_state, TS_ISOPEN) &&
282	    ISSET(tp->t_state, TS_XCLUDE) &&
283	    p->p_ucred->cr_uid != 0)
284		return (EBUSY);
285
286	s = spltty();
287
288	/*
289	 * Do the following iff this is a first open.
290	 */
291	while (sc->sc_opening)
292		tsleep(&sc->sc_opening, PRIBIO, "ucomop", 0);
293	sc->sc_opening = 1;
294
295	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
296		struct termios t;
297
298		tp->t_dev = dev;
299
300		ucom_status_change(sc);
301
302		/*
303		 * Initialize the termios status to the defaults.  Add in the
304		 * sticky bits from TIOCSFLAGS.
305		 */
306		t.c_ispeed = 0;
307		t.c_ospeed = TTYDEF_SPEED;
308		t.c_cflag = TTYDEF_CFLAG;
309		if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
310			SET(t.c_cflag, CLOCAL);
311		if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
312			SET(t.c_cflag, CRTSCTS);
313		if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF))
314			SET(t.c_cflag, MDMBUF);
315		/* Make sure ucomparam() will do something. */
316		tp->t_ospeed = 0;
317		(void) ucomparam(tp, &t);
318		tp->t_iflag = TTYDEF_IFLAG;
319		tp->t_oflag = TTYDEF_OFLAG;
320		tp->t_lflag = TTYDEF_LFLAG;
321		ttychars(tp);
322		ttsetwater(tp);
323
324		/*
325		 * Turn on DTR.  We must always do this, even if carrier is not
326		 * present, because otherwise we'd have to use TIOCSDTR
327		 * immediately after setting CLOCAL, which applications do not
328		 * expect.  We always assert DTR while the device is open
329		 * unless explicitly requested to deassert it.
330		 */
331		ucom_dtr(sc, 1);
332
333		// XXX CLR(sc->sc_rx_flags, RX_ANY_BLOCK);
334		ucom_hwiflow(sc);
335
336		DPRINTF(("ucomopen: open pipes in=%d out=%d\n",
337			 sc->sc_bulkin_no, sc->sc_bulkout_no));
338
339		/* Open the bulk pipes */
340		err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no, 0,
341				     &sc->sc_bulkin_pipe);
342		if (err) {
343			DPRINTF(("%s: open bulk out error (addr %d), err=%s\n",
344				 USBDEVNAME(sc->sc_dev), sc->sc_bulkin_no,
345				 usbd_errstr(err)));
346			return (EIO);
347		}
348		err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no,
349				     USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
350		if (err) {
351			DPRINTF(("%s: open bulk in error (addr %d), err=%s\n",
352				 USBDEVNAME(sc->sc_dev), sc->sc_bulkout_no,
353				 usbd_errstr(err)));
354			usbd_close_pipe(sc->sc_bulkin_pipe);
355			return (EIO);
356		}
357
358		/* Allocate a request and an input buffer and start reading. */
359		sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev);
360		if (sc->sc_ixfer == NULL) {
361			usbd_close_pipe(sc->sc_bulkin_pipe);
362			usbd_close_pipe(sc->sc_bulkout_pipe);
363			return (ENOMEM);
364		}
365		sc->sc_ibuf = usbd_alloc_buffer(sc->sc_ixfer, UCOMIBUFSIZE);
366		if (sc->sc_ibuf == NULL) {
367			usbd_free_xfer(sc->sc_ixfer);
368			usbd_close_pipe(sc->sc_bulkin_pipe);
369			usbd_close_pipe(sc->sc_bulkout_pipe);
370			return (ENOMEM);
371		}
372
373		sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev);
374		if (sc->sc_oxfer == NULL) {
375			usbd_free_xfer(sc->sc_ixfer);
376			usbd_close_pipe(sc->sc_bulkin_pipe);
377			usbd_close_pipe(sc->sc_bulkout_pipe);
378			return (ENOMEM);
379		}
380		sc->sc_obuf = usbd_alloc_buffer(sc->sc_oxfer, UCOMOBUFSIZE);
381		if (sc->sc_obuf == NULL) {
382			usbd_free_xfer(sc->sc_oxfer);
383			usbd_free_xfer(sc->sc_ixfer);
384			usbd_close_pipe(sc->sc_bulkin_pipe);
385			usbd_close_pipe(sc->sc_bulkout_pipe);
386			return (ENOMEM);
387		}
388
389		ucomstartread(sc);
390	}
391	sc->sc_opening = 0;
392	wakeup(&sc->sc_opening);
393	splx(s);
394
395	error = ttyopen(tp, UCOMDIALOUT(dev), ISSET(flag, O_NONBLOCK));
396	if (error)
397		goto bad;
398
399	error = (*linesw[tp->t_line].l_open)(dev, tp);
400	if (error)
401		goto bad;
402
403	return (0);
404
405bad:
406	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
407		/*
408		 * We failed to open the device, and nobody else had it opened.
409		 * Clean up the state as appropriate.
410		 */
411		ucom_cleanup(sc);
412	}
413
414	return (error);
415}
416
417int
418ucomclose(dev, flag, mode, p)
419	dev_t dev;
420	int flag, mode;
421	struct proc *p;
422{
423	struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
424	struct tty *tp = sc->sc_tty;
425
426	DPRINTF(("ucomclose: unit=%d\n", UCOMUNIT(dev)));
427	if (!ISSET(tp->t_state, TS_ISOPEN))
428		return (0);
429
430	(*linesw[tp->t_line].l_close)(tp, flag);
431	ttyclose(tp);
432
433	if (sc->sc_dying)
434		return (0);
435
436	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
437		/*
438		 * Although we got a last close, the device may still be in
439		 * use; e.g. if this was the dialout node, and there are still
440		 * processes waiting for carrier on the non-dialout node.
441		 */
442		ucom_cleanup(sc);
443	}
444
445	return (0);
446}
447
448int
449ucomread(dev, uio, flag)
450	dev_t dev;
451	struct uio *uio;
452	int flag;
453{
454	struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
455	struct tty *tp = sc->sc_tty;
456
457	if (sc->sc_dying)
458		return (EIO);
459
460	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
461}
462
463int
464ucomwrite(dev, uio, flag)
465	dev_t dev;
466	struct uio *uio;
467	int flag;
468{
469	struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
470	struct tty *tp = sc->sc_tty;
471
472	if (sc->sc_dying)
473		return (EIO);
474
475	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
476}
477
478struct tty *
479ucomtty(dev)
480	dev_t dev;
481{
482	struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
483	struct tty *tp = sc->sc_tty;
484
485	return (tp);
486}
487
488int
489ucomioctl(dev, cmd, data, flag, p)
490	dev_t dev;
491	u_long cmd;
492	caddr_t data;
493	int flag;
494	struct proc *p;
495{
496	struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
497	struct tty *tp = sc->sc_tty;
498	int error;
499	int s;
500
501	if (sc->sc_dying)
502		return (EIO);
503
504	DPRINTF(("ucomioctl: cmd=0x%08lx\n", cmd));
505
506	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
507	if (error >= 0)
508		return (error);
509
510	error = ttioctl(tp, cmd, data, flag, p);
511	if (error >= 0)
512		return (error);
513
514	if (sc->sc_methods->ucom_ioctl != NULL) {
515		error = sc->sc_methods->ucom_ioctl(sc->sc_parent,
516			    sc->sc_portno, cmd, data, flag, p);
517		if (error >= 0)
518			return (error);
519	}
520
521	error = 0;
522
523	DPRINTF(("ucomioctl: our cmd=0x%08lx\n", cmd));
524	s = spltty();
525
526	switch (cmd) {
527	case TIOCSBRK:
528		ucom_break(sc, 1);
529		break;
530
531	case TIOCCBRK:
532		ucom_break(sc, 0);
533		break;
534
535	case TIOCSDTR:
536		ucom_dtr(sc, 1);
537		break;
538
539	case TIOCCDTR:
540		ucom_dtr(sc, 0);
541		break;
542
543	case TIOCGFLAGS:
544		*(int *)data = sc->sc_swflags;
545		break;
546
547	case TIOCSFLAGS:
548		error = suser(p->p_ucred, &p->p_acflag);
549		if (error)
550			break;
551		sc->sc_swflags = *(int *)data;
552		break;
553
554	case TIOCMSET:
555	case TIOCMBIS:
556	case TIOCMBIC:
557		tiocm_to_ucom(sc, cmd, *(int *)data);
558		break;
559
560	case TIOCMGET:
561		*(int *)data = ucom_to_tiocm(sc);
562		break;
563
564	default:
565		error = ENOTTY;
566		break;
567	}
568
569	splx(s);
570
571	return (error);
572}
573
574void
575tiocm_to_ucom(sc, how, ttybits)
576	struct ucom_softc *sc;
577	int how, ttybits;
578{
579	u_char combits;
580
581	combits = 0;
582	if (ISSET(ttybits, TIOCM_DTR))
583		SET(combits, UMCR_DTR);
584	if (ISSET(ttybits, TIOCM_RTS))
585		SET(combits, UMCR_RTS);
586
587	switch (how) {
588	case TIOCMBIC:
589		CLR(sc->sc_mcr, combits);
590		break;
591
592	case TIOCMBIS:
593		SET(sc->sc_mcr, combits);
594		break;
595
596	case TIOCMSET:
597		CLR(sc->sc_mcr, UMCR_DTR | UMCR_RTS);
598		SET(sc->sc_mcr, combits);
599		break;
600	}
601
602	ucom_dtr(sc, (sc->sc_mcr & UMCR_DTR) != 0);
603	ucom_rts(sc, (sc->sc_mcr & UMCR_RTS) != 0);
604}
605
606int
607ucom_to_tiocm(sc)
608	struct ucom_softc *sc;
609{
610	u_char combits;
611	int ttybits = 0;
612
613	combits = sc->sc_mcr;
614	if (ISSET(combits, UMCR_DTR))
615		SET(ttybits, TIOCM_DTR);
616	if (ISSET(combits, UMCR_RTS))
617		SET(ttybits, TIOCM_RTS);
618
619	combits = sc->sc_msr;
620	if (ISSET(combits, UMSR_DCD))
621		SET(ttybits, TIOCM_CD);
622	if (ISSET(combits, UMSR_CTS))
623		SET(ttybits, TIOCM_CTS);
624	if (ISSET(combits, UMSR_DSR))
625		SET(ttybits, TIOCM_DSR);
626	if (ISSET(combits, UMSR_RI | UMSR_TERI))
627		SET(ttybits, TIOCM_RI);
628
629#if 0
630XXX;
631	if (sc->sc_ier != 0)
632		SET(ttybits, TIOCM_LE);
633#endif
634
635	return (ttybits);
636}
637
638void
639ucom_break(sc, onoff)
640	struct ucom_softc *sc;
641	int onoff;
642{
643	DPRINTF(("ucom_break: onoff=%d\n", onoff));
644
645	sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
646				 UCOM_SET_BREAK, onoff);
647}
648
649void
650ucom_dtr(sc, onoff)
651	struct ucom_softc *sc;
652	int onoff;
653{
654	DPRINTF(("ucom_dtr: onoff=%d\n", onoff));
655
656	sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
657				 UCOM_SET_DTR, onoff);
658}
659
660void
661ucom_rts(sc, onoff)
662	struct ucom_softc *sc;
663	int onoff;
664{
665	DPRINTF(("ucom_rts: onoff=%d\n", onoff));
666
667	sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
668				 UCOM_SET_RTS, onoff);
669}
670
671void
672ucom_status_change(sc)
673	struct ucom_softc *sc;
674{
675	sc->sc_methods->ucom_get_status(sc->sc_parent, sc->sc_portno,
676					&sc->sc_lsr, &sc->sc_msr);
677}
678
679int
680ucomparam(tp, t)
681	struct tty *tp;
682	struct termios *t;
683{
684	struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(tp->t_dev)];
685
686	if (sc->sc_dying)
687		return (EIO);
688
689	/* Check requested parameters. */
690	if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
691		return (EINVAL);
692
693	/*
694	 * For the console, always force CLOCAL and !HUPCL, so that the port
695	 * is always active.
696	 */
697	if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR)) {
698		SET(t->c_cflag, CLOCAL);
699		CLR(t->c_cflag, HUPCL);
700	}
701
702	/*
703	 * If there were no changes, don't do anything.  This avoids dropping
704	 * input and improves performance when all we did was frob things like
705	 * VMIN and VTIME.
706	 */
707	if (tp->t_ospeed == t->c_ospeed &&
708	    tp->t_cflag == t->c_cflag)
709		return (0);
710
711	//XXX lcr = ISSET(sc->sc_lcr, LCR_SBREAK) | cflag2lcr(t->c_cflag);
712
713	/* And copy to tty. */
714	tp->t_ispeed = 0;
715	tp->t_ospeed = t->c_ospeed;
716	tp->t_cflag = t->c_cflag;
717
718	sc->sc_methods->ucom_param(sc->sc_parent, sc->sc_portno, t);
719
720	// XXX worry about CHWFLOW
721
722	/*
723	 * Update the tty layer's idea of the carrier bit, in case we changed
724	 * CLOCAL or MDMBUF.  We don't hang up here; we only do that by
725	 * explicit request.
726	 */
727	DPRINTF(("ucomparam: l_modem\n"));
728	(void) (*linesw[tp->t_line].l_modem)(tp, 1 /* XXX carrier */ );
729
730#if 0
731XXX what if the hardware is not open
732	if (!ISSET(t->c_cflag, CHWFLOW)) {
733		if (sc->sc_tx_stopped) {
734			sc->sc_tx_stopped = 0;
735			ucomstart(tp);
736		}
737	}
738#endif
739
740	return (0);
741}
742
743/*
744 * (un)block input via hw flowcontrol
745 */
746void
747ucom_hwiflow(sc)
748	struct ucom_softc *sc;
749{
750#if 0
751XXX
752	bus_space_tag_t iot = sc->sc_iot;
753	bus_space_handle_t ioh = sc->sc_ioh;
754
755	if (sc->sc_mcr_rts == 0)
756		return;
757
758	if (ISSET(sc->sc_rx_flags, RX_ANY_BLOCK)) {
759		CLR(sc->sc_mcr, sc->sc_mcr_rts);
760		CLR(sc->sc_mcr_active, sc->sc_mcr_rts);
761	} else {
762		SET(sc->sc_mcr, sc->sc_mcr_rts);
763		SET(sc->sc_mcr_active, sc->sc_mcr_rts);
764	}
765	bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr_active);
766#endif
767}
768
769void
770ucomstart(tp)
771	struct tty *tp;
772{
773	struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(tp->t_dev)];
774	usbd_status err;
775	int s;
776	u_char *data;
777	int cnt;
778
779	if (sc->sc_dying)
780		return;
781
782	s = spltty();
783	if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) {
784		DPRINTFN(4,("ucomstart: stopped\n"));
785		goto out;
786	}
787	if (sc->sc_tx_stopped)
788		goto out;
789
790	if (tp->t_outq.c_cc <= tp->t_lowat) {
791		if (ISSET(tp->t_state, TS_ASLEEP)) {
792			CLR(tp->t_state, TS_ASLEEP);
793			wakeup(&tp->t_outq);
794		}
795		selwakeup(&tp->t_wsel);
796		if (tp->t_outq.c_cc == 0)
797			goto out;
798	}
799
800	/* Grab the first contiguous region of buffer space. */
801	data = tp->t_outq.c_cf;
802	cnt = ndqb(&tp->t_outq, 0);
803
804	if (cnt == 0) {
805		DPRINTF(("ucomstart: cnt==0\n"));
806		goto out;
807	}
808
809	SET(tp->t_state, TS_BUSY);
810
811	if (cnt > UCOMOBUFSIZE) {
812		DPRINTF(("ucomstart: big buffer %d chars\n", cnt));
813		cnt = UCOMOBUFSIZE;
814	}
815	memcpy(sc->sc_obuf, data, cnt);
816
817	DPRINTFN(4,("ucomstart: %d chars\n", cnt));
818	usbd_setup_xfer(sc->sc_oxfer, sc->sc_bulkout_pipe,
819			(usbd_private_handle)sc, sc->sc_obuf, cnt,
820			USBD_NO_COPY, USBD_NO_TIMEOUT, ucomwritecb);
821	/* What can we do on error? */
822	err = usbd_transfer(sc->sc_oxfer);
823#ifdef DIAGNOSTIC
824	if (err != USBD_IN_PROGRESS)
825		printf("ucomstart: err=%s\n", usbd_errstr(err));
826#endif
827
828out:
829	splx(s);
830}
831
832void
833ucomstop(tp, flag)
834	struct tty *tp;
835	int flag;
836{
837	struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(tp->t_dev)];
838	int s;
839
840	DPRINTF(("ucomstop: %d\n", flag));
841	s = spltty();
842	if (ISSET(tp->t_state, TS_BUSY)) {
843		DPRINTF(("ucomstop: XXX\n"));
844		sc->sc_tx_stopped = 1;
845		if (!ISSET(tp->t_state, TS_TTSTOP))
846			SET(tp->t_state, TS_FLUSH);
847	}
848	splx(s);
849}
850
851void
852ucomwritecb(xfer, p, status)
853	usbd_xfer_handle xfer;
854	usbd_private_handle p;
855	usbd_status status;
856{
857	struct ucom_softc *sc = (struct ucom_softc *)p;
858	struct tty *tp = sc->sc_tty;
859	u_int32_t cc;
860	int s;
861
862	DPRINTFN(5,("ucomwritecb: status=%d\n", status));
863
864	if (status == USBD_CANCELLED)
865		return;
866
867	if (status) {
868		DPRINTF(("ucomwritecb: status=%d\n", status));
869		usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
870		/* XXX we should restart after some delay. */
871		return;
872	}
873
874	usbd_get_xfer_status(xfer, 0, 0, &cc, 0);
875	DPRINTFN(5,("ucomwritecb: cc=%d\n", cc));
876
877	s = spltty();
878	CLR(tp->t_state, TS_BUSY);
879	if (ISSET(tp->t_state, TS_FLUSH))
880		CLR(tp->t_state, TS_FLUSH);
881	else
882		ndflush(&tp->t_outq, cc);
883	(*linesw[tp->t_line].l_start)(tp);
884	splx(s);
885}
886
887usbd_status
888ucomstartread(sc)
889	struct ucom_softc *sc;
890{
891	usbd_status err;
892
893	DPRINTFN(5,("ucomstartread: start\n"));
894	usbd_setup_xfer(sc->sc_ixfer, sc->sc_bulkin_pipe,
895			(usbd_private_handle)sc,
896			sc->sc_ibuf,  UCOMIBUFSIZE,
897			USBD_SHORT_XFER_OK | USBD_NO_COPY,
898			USBD_NO_TIMEOUT, ucomreadcb);
899	err = usbd_transfer(sc->sc_ixfer);
900	if (err != USBD_IN_PROGRESS) {
901		DPRINTF(("ucomstartread: err=%s\n", usbd_errstr(err)));
902		return (err);
903	}
904	return (USBD_NORMAL_COMPLETION);
905}
906
907void
908ucomreadcb(xfer, p, status)
909	usbd_xfer_handle xfer;
910	usbd_private_handle p;
911	usbd_status status;
912{
913	struct ucom_softc *sc = (struct ucom_softc *)p;
914	struct tty *tp = sc->sc_tty;
915	int (*rint) __P((int c, struct tty *tp)) = linesw[tp->t_line].l_rint;
916	usbd_status err;
917	u_int32_t cc;
918	u_char *cp;
919	int s;
920
921	if (status == USBD_CANCELLED)
922		return;
923
924	if (status) {
925		DPRINTF(("ucomreadcb: status=%d\n", status));
926		usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
927		/* XXX we should restart after some delay. */
928		return;
929	}
930
931	usbd_get_xfer_status(xfer, 0, (void **)&cp, &cc, 0);
932	DPRINTFN(5,("ucomreadcb: got %d chars, tp=%p\n", cc, tp));
933	s = spltty();
934	/* Give characters to tty layer. */
935	while (cc-- > 0) {
936		DPRINTFN(7,("ucomreadcb: char=0x%02x\n", *cp));
937		if ((*rint)(*cp++, tp) == -1) {
938			/* XXX what should we do? */
939			break;
940		}
941	}
942	splx(s);
943
944	err = ucomstartread(sc);
945	if (err) {
946		printf("%s: read start failed\n", USBDEVNAME(sc->sc_dev));
947		/* XXX what should we dow now? */
948	}
949}
950
951void
952ucom_cleanup(sc)
953	struct ucom_softc *sc;
954{
955	DPRINTF(("ucom_cleanup: closing pipes\n"));
956
957	ucom_shutdown(sc);
958	usbd_abort_pipe(sc->sc_bulkin_pipe);
959	usbd_close_pipe(sc->sc_bulkin_pipe);
960	usbd_abort_pipe(sc->sc_bulkout_pipe);
961	usbd_close_pipe(sc->sc_bulkout_pipe);
962	usbd_free_xfer(sc->sc_ixfer);
963	usbd_free_xfer(sc->sc_oxfer);
964}
965
966#endif /* NUCOM > 0 */
967
968int
969ucomprint(aux, pnp)
970	void *aux;
971	const char *pnp;
972{
973
974	if (pnp)
975		printf("ucom at %s\n", pnp);
976	return (UNCONF);
977}
978
979int
980ucomsubmatch(parent, cf, aux)
981	struct device *parent;
982	struct cfdata *cf;
983	void *aux;
984{
985	struct ucom_attach_args *uca = aux;
986
987	if (uca->portno != UCOM_UNK_PORTNO &&
988	    cf->ucomcf_portno != UCOM_UNK_PORTNO &&
989	    cf->ucomcf_portno != uca->portno)
990		return (0);
991	return ((*cf->cf_attach->ca_match)(parent, cf, aux));
992}
993