xref: /dragonfly/sys/bus/u4b/serial/usb_serial.c (revision b29f78b5)
1 /*	$NetBSD: ucom.c,v 1.40 2001/11/13 06:24:54 lukem Exp $	*/
2 
3 /*-
4  * Copyright (c) 2001-2003, 2005, 2008
5  *	Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 /*-
31  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
32  * All rights reserved.
33  *
34  * This code is derived from software contributed to The NetBSD Foundation
35  * by Lennart Augustsson (lennart@augustsson.net) at
36  * Carlstedt Research & Technology.
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  * 1. Redistributions of source code must retain the above copyright
42  *    notice, this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright
44  *    notice, this list of conditions and the following disclaimer in the
45  *    documentation and/or other materials provided with the distribution.
46  * 3. All advertising materials mentioning features or use of this software
47  *    must display the following acknowledgement:
48  *        This product includes software developed by the NetBSD
49  *        Foundation, Inc. and its contributors.
50  * 4. Neither the name of The NetBSD Foundation nor the names of its
51  *    contributors may be used to endorse or promote products derived
52  *    from this software without specific prior written permission.
53  *
54  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
55  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
56  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
57  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
58  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
59  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
60  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
61  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
62  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
63  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
64  * POSSIBILITY OF SUCH DAMAGE.
65  */
66 
67 /*
68  * XXX profmakx
69  * This is a Frankenstein of FreeBSD's usb4bsd ucom and Dragonfly's old ucom
70  * module. There might be bugs lurking everywhere still
71  *
72  * In particular serial console on ucom is completely untested and likely broken
73  * as well as anyting that requires the modem control lines.
74  */
75 
76 #include <sys/stdint.h>
77 #include <sys/param.h>
78 #include <sys/queue.h>
79 #include <sys/types.h>
80 #include <sys/systm.h>
81 #include <sys/kernel.h>
82 #include <sys/bus.h>
83 #include <sys/module.h>
84 #include <sys/lock.h>
85 #include <sys/condvar.h>
86 #include <sys/sysctl.h>
87 #include <sys/unistd.h>
88 #include <sys/callout.h>
89 #include <sys/malloc.h>
90 #include <sys/priv.h>
91 #include <sys/cons.h>
92 #include <sys/serial.h>
93 #include <sys/thread2.h>
94 #include <sys/conf.h>
95 #include <sys/clist.h>
96 
97 #include <bus/u4b/usb.h>
98 #include <bus/u4b/usbdi.h>
99 #include <bus/u4b/usbdi_util.h>
100 
101 #define	USB_DEBUG_VAR ucom_debug
102 #include <bus/u4b/usb_debug.h>
103 #include <bus/u4b/usb_busdma.h>
104 #include <bus/u4b/usb_process.h>
105 
106 #include <bus/u4b/serial/usb_serial.h>
107 
108 //#include "opt_gdb.h"
109 
110 static SYSCTL_NODE(_hw_usb, OID_AUTO, ucom, CTLFLAG_RW, 0, "USB ucom");
111 
112 #ifdef USB_DEBUG
113 static int ucom_debug = 0;
114 
115 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, debug, CTLFLAG_RW,
116     &ucom_debug, 0, "ucom debug level");
117 #endif
118 
119 #define	UCOM_CONS_BUFSIZE 1024
120 
121 static uint8_t ucom_cons_rx_buf[UCOM_CONS_BUFSIZE];
122 static uint8_t ucom_cons_tx_buf[UCOM_CONS_BUFSIZE];
123 
124 static unsigned int ucom_cons_rx_low = 0;
125 static unsigned int ucom_cons_rx_high = 0;
126 
127 static unsigned int ucom_cons_tx_low = 0;
128 static unsigned int ucom_cons_tx_high = 0;
129 
130 static int ucom_cons_unit = -1;
131 static int ucom_cons_subunit = 0;
132 static int ucom_cons_baud = 9600;
133 static struct ucom_softc *ucom_cons_softc = NULL;
134 
135 TUNABLE_INT("hw.usb.ucom.cons_unit", &ucom_cons_unit);
136 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_unit, CTLFLAG_RW,
137     &ucom_cons_unit, 0, "console unit number");
138 TUNABLE_INT("hw.usb.ucom.cons_subunit", &ucom_cons_subunit);
139 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_subunit, CTLFLAG_RW,
140     &ucom_cons_subunit, 0, "console subunit number");
141 TUNABLE_INT("hw.usb.ucom.cons_baud", &ucom_cons_baud);
142 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_baud, CTLFLAG_RW,
143     &ucom_cons_baud, 0, "console baud rate");
144 
145 static usb_proc_callback_t ucom_cfg_start_transfers;
146 static usb_proc_callback_t ucom_cfg_open;
147 static usb_proc_callback_t ucom_cfg_close;
148 static usb_proc_callback_t ucom_cfg_line_state;
149 static usb_proc_callback_t ucom_cfg_status_change;
150 static usb_proc_callback_t ucom_cfg_param;
151 
152 static int	ucom_unit_alloc(void);
153 static void	ucom_unit_free(int);
154 static int	ucom_attach_tty(struct ucom_super_softc *, struct ucom_softc *);
155 static void	ucom_detach_tty(struct ucom_super_softc *, struct ucom_softc *);
156 static void	ucom_queue_command(struct ucom_softc *,
157 		    usb_proc_callback_t *, struct termios *pt,
158 		    struct usb_proc_msg *t0, struct usb_proc_msg *t1);
159 static void	ucom_shutdown(struct ucom_softc *);
160 static void	ucom_ring(struct ucom_softc *, uint8_t);
161 static void	ucom_break(struct ucom_softc *, uint8_t);
162 static void	ucom_dtr(struct ucom_softc *, uint8_t);
163 static void	ucom_rts(struct ucom_softc *, uint8_t);
164 
165 static int ucom_open(struct ucom_softc *sc);
166 static int ucom_close(struct ucom_softc *sc);
167 static void ucom_start(struct tty *tp);
168 static void ucom_stop(struct tty *tp, int);
169 static int ucom_param(struct tty *tp, struct termios *t);
170 static int ucom_modem(struct tty *tp, int sigon, int sigoff);
171 
172 static int ucom_fromtio(int);
173 static int ucom_totio(int);
174 
175 static void disc_optim(struct tty *, struct termios *, struct ucom_softc *);
176 
177 static d_open_t ucom_dev_open;
178 static d_close_t ucom_dev_close;
179 static d_read_t ucom_dev_read;
180 static d_write_t ucom_dev_write;
181 static d_ioctl_t ucom_dev_ioctl;
182 
183 static struct dev_ops ucom_ops = {
184   { "ucom", 0, D_MPSAFE | D_TTY },
185   .d_open =       ucom_dev_open,
186   .d_close =      ucom_dev_close,
187   .d_read =       ucom_dev_read,
188   .d_write =      ucom_dev_write,
189   .d_ioctl =      ucom_dev_ioctl,
190   .d_kqfilter =   ttykqfilter,
191   .d_revoke =     ttyrevoke
192 };
193 
194 static moduledata_t ucom_mod = {
195         "ucom",
196         NULL,
197         NULL
198 };
199 
200 DECLARE_MODULE(ucom, ucom_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
201 MODULE_DEPEND(ucom, usb, 1, 1, 1);
202 MODULE_VERSION(ucom, UCOM_MODVER);
203 
204 /* XXXDF */
205 #define tty_gone(tp) ((tp->t_state) & (TS_ZOMBIE))
206 
207 #define	UCOM_UNIT_MAX 		128	/* maximum number of units */
208 #define	UCOM_TTY_PREFIX		"ucom"
209 
210 static struct unrhdr *ucom_unrhdr;
211 static struct lock ucom_lock;
212 static int ucom_close_refs;
213 
214 static void
215 ucom_init(void *arg)
216 {
217 	DPRINTF("\n");
218 	ucom_unrhdr = new_unrhdr(0, UCOM_UNIT_MAX - 1, NULL);
219 	lockinit(&ucom_lock, "UCOM LOCK", 0, 0);
220 }
221 SYSINIT(ucom_init, SI_BOOT2_KLD - 1, SI_ORDER_ANY, ucom_init, NULL);
222 
223 static void
224 ucom_uninit(void *arg)
225 {
226 	struct unrhdr *hdr;
227 	hdr = ucom_unrhdr;
228 	ucom_unrhdr = NULL;
229 
230 	DPRINTF("\n");
231 
232 	if (hdr != NULL)
233 		delete_unrhdr(hdr);
234 
235 	lockuninit(&ucom_lock);
236 }
237 SYSUNINIT(ucom_uninit, SI_BOOT2_KLD - 2, SI_ORDER_ANY, ucom_uninit, NULL);
238 
239 /*
240  * Mark a unit number (the X in cuaUX) as in use.
241  *
242  * Note that devices using a different naming scheme (see ucom_tty_name()
243  * callback) still use this unit allocation.
244  */
245 static int
246 ucom_unit_alloc(void)
247 {
248 	int unit;
249 
250 	/* sanity checks */
251 	if (ucom_unrhdr == NULL) {
252 		DPRINTF("ucom_unrhdr is NULL\n");
253 		return (-1);
254 	}
255 	unit = alloc_unr(ucom_unrhdr);
256 	DPRINTF("unit %d is allocated\n", unit);
257 	return (unit);
258 }
259 
260 /*
261  * Mark the unit number as not in use.
262  */
263 static void
264 ucom_unit_free(int unit)
265 {
266 	/* sanity checks */
267 	if (unit < 0 || unit >= UCOM_UNIT_MAX || ucom_unrhdr == NULL) {
268 		DPRINTF("cannot free unit number\n");
269 		return;
270 	}
271 	DPRINTF("unit %d is freed\n", unit);
272 	free_unr(ucom_unrhdr, unit);
273 }
274 
275 /*
276  * Setup a group of one or more serial ports.
277  *
278  * The lock pointed to by "lock" is applied before all
279  * callbacks are called back. Also "lock" must be applied
280  * before calling into the ucom-layer!
281  */
282 int
283 ucom_attach(struct ucom_super_softc *ssc, struct ucom_softc *sc,
284     int subunits, void *parent,
285     const struct ucom_callback *callback, struct lock *lock)
286 {
287 	int subunit;
288 	int error = 0;
289 
290 	if ((sc == NULL) ||
291 	    (subunits <= 0) ||
292 	    (callback == NULL) ||
293 	    (lock == NULL)) {
294 		return (EINVAL);
295 	}
296 
297 	/* XXX Do we want our own lock here maybe */
298 	sc->sc_lock = lock;
299 
300 	/* allocate a uniq unit number */
301 	ssc->sc_unit = ucom_unit_alloc();
302 	if (ssc->sc_unit == -1)
303 		return (ENOMEM);
304 
305 	/* generate TTY name string */
306 	ksnprintf(ssc->sc_ttyname, sizeof(ssc->sc_ttyname),
307 	    UCOM_TTY_PREFIX "%d", ssc->sc_unit);
308 
309 	/* create USB request handling process */
310 	error = usb_proc_create(&ssc->sc_tq, lock, "ucom", USB_PRI_MED);
311 	if (error) {
312 		ucom_unit_free(ssc->sc_unit);
313 		return (error);
314 	}
315 	ssc->sc_subunits = subunits;
316 	ssc->sc_flag = UCOM_FLAG_ATTACHED |
317 	    UCOM_FLAG_FREE_UNIT;
318 
319 	if (callback->ucom_free == NULL)
320 		ssc->sc_flag |= UCOM_FLAG_WAIT_REFS;
321 
322 	/* increment reference count */
323 	ucom_ref(ssc);
324 
325 	for (subunit = 0; subunit < ssc->sc_subunits; subunit++) {
326 		sc[subunit].sc_subunit = subunit;
327 		sc[subunit].sc_super = ssc;
328 		sc[subunit].sc_lock = lock;
329 		sc[subunit].sc_parent = parent;
330 		sc[subunit].sc_callback = callback;
331 
332 		error = ucom_attach_tty(ssc, &sc[subunit]);
333 		if (error) {
334 			ucom_detach(ssc, &sc[0]);
335 			return (error);
336 		}
337 		/* increment reference count */
338 		ucom_ref(ssc);
339 
340 		/* set subunit attached */
341 		sc[subunit].sc_flag |= UCOM_FLAG_ATTACHED;
342 	}
343 
344 	DPRINTF("tp = %p, unit = %d, subunits = %d\n",
345 		sc->sc_tty, ssc->sc_unit, ssc->sc_subunits);
346 
347 	return (0);
348 }
349 
350 /*
351  * The following function will do nothing if the structure pointed to
352  * by "ssc" and "sc" is zero or has already been detached.
353  */
354 void
355 ucom_detach(struct ucom_super_softc *ssc, struct ucom_softc *sc)
356 {
357 	int subunit;
358 
359 	if (!(ssc->sc_flag & UCOM_FLAG_ATTACHED))
360 		return;		/* not initialized */
361 
362 	destroy_dev(sc->sc_cdev);
363 
364 	lwkt_gettoken(&tty_token);
365 
366 	if (ssc->sc_sysctl_ttyname != NULL) {
367 		sysctl_remove_oid(ssc->sc_sysctl_ttyname, 1, 0);
368 		ssc->sc_sysctl_ttyname = NULL;
369 	}
370 
371 	if (ssc->sc_sysctl_ttyports != NULL) {
372 		sysctl_remove_oid(ssc->sc_sysctl_ttyports, 1, 0);
373 		ssc->sc_sysctl_ttyports = NULL;
374 	}
375 
376 	usb_proc_drain(&ssc->sc_tq);
377 
378 	for (subunit = 0; subunit < ssc->sc_subunits; subunit++) {
379 		if (sc[subunit].sc_flag & UCOM_FLAG_ATTACHED) {
380 			ucom_detach_tty(ssc, &sc[subunit]);
381 
382 			/* avoid duplicate detach */
383 			sc[subunit].sc_flag &= ~UCOM_FLAG_ATTACHED;
384 		}
385 	}
386 	usb_proc_free(&ssc->sc_tq);
387 
388 	ucom_unref(ssc);
389 
390 	if (ssc->sc_flag & UCOM_FLAG_WAIT_REFS)
391 		ucom_drain(ssc);
392 
393 	/* make sure we don't detach twice */
394 	ssc->sc_flag &= ~UCOM_FLAG_ATTACHED;
395 
396 	lwkt_reltoken(&tty_token);
397 }
398 
399 void
400 ucom_drain(struct ucom_super_softc *ssc)
401 {
402 	lockmgr(&ucom_lock, LK_EXCLUSIVE);
403 	while (ssc->sc_refs > 0) {
404 		kprintf("ucom: Waiting for a TTY device to close.\n");
405 		usb_pause_mtx(&ucom_lock, hz);
406 	}
407 	lockmgr(&ucom_lock, LK_RELEASE);
408 }
409 
410 void
411 ucom_drain_all(void *arg)
412 {
413 	lockmgr(&ucom_lock, LK_EXCLUSIVE);
414 	while (ucom_close_refs > 0) {
415 		kprintf("ucom: Waiting for all detached TTY "
416 		    "devices to have open fds closed.\n");
417 		usb_pause_mtx(&ucom_lock, hz);
418 	}
419 	lockmgr(&ucom_lock, LK_RELEASE);
420 }
421 
422 static int
423 ucom_attach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc)
424 {
425 	struct tty *tp;
426 	char buf[32];			/* temporary TTY device name buffer */
427 	cdev_t dev;
428 
429 	lwkt_gettoken(&tty_token);
430 
431 	sc->sc_tty = tp = ttymalloc(sc->sc_tty);
432 
433 	if (tp == NULL) {
434 		lwkt_reltoken(&tty_token);
435 		return (ENOMEM);
436 	}
437 
438 	tp->t_sc = (void *)sc;
439 
440 	tp->t_oproc = ucom_start;
441 	tp->t_param = ucom_param;
442 	tp->t_stop = ucom_stop;
443 
444 	/* Check if the client has a custom TTY name */
445 	buf[0] = '\0';
446 	if (sc->sc_callback->ucom_tty_name) {
447 		sc->sc_callback->ucom_tty_name(sc, buf,
448 		    sizeof(buf), ssc->sc_unit, sc->sc_subunit);
449 	}
450 	if (buf[0] == 0) {
451 		/* Use default TTY name */
452 		if (ssc->sc_subunits > 1) {
453 			/* multiple modems in one */
454 			ksnprintf(buf, sizeof(buf), UCOM_TTY_PREFIX "%u.%u",
455 			    ssc->sc_unit, sc->sc_subunit);
456 		} else {
457 			/* single modem */
458 			ksnprintf(buf, sizeof(buf), UCOM_TTY_PREFIX "%u",
459 			    ssc->sc_unit);
460 		}
461 	}
462 
463 	dev = make_dev(&ucom_ops, ssc->sc_unit | 0x80, // XXX UCOM_CALLOUT_MASK,
464 			UID_UUCP, GID_DIALER, 0660,
465 			buf, ssc->sc_unit);
466 	dev->si_tty = tp;
467 	sc->sc_tty = tp;
468 	dev->si_drv1 = sc;
469 	sc->sc_cdev = dev;
470 
471 	DPRINTF("ttycreate: %s\n", buf);
472 
473 	/* Check if this device should be a console */
474 	if ((ucom_cons_softc == NULL) &&
475 	    (ssc->sc_unit == ucom_cons_unit) &&
476 	    (sc->sc_subunit == ucom_cons_subunit)) {
477 
478 		DPRINTF("unit %d subunit %d is console",
479 		    ssc->sc_unit, sc->sc_subunit);
480 
481 		ucom_cons_softc = sc;
482 
483 		/* XXXDF
484 		tty_init_console(tp, ucom_cons_baud);
485 		*/
486 		tp->t_termios.c_ispeed = ucom_cons_baud;
487 		tp->t_termios.c_ospeed = ucom_cons_baud;
488 
489 		UCOM_MTX_LOCK(ucom_cons_softc);
490 		ucom_cons_rx_low = 0;
491 		ucom_cons_rx_high = 0;
492 		ucom_cons_tx_low = 0;
493 		ucom_cons_tx_high = 0;
494 		sc->sc_flag |= UCOM_FLAG_CONSOLE;
495 
496 		ucom_open(ucom_cons_softc);
497 		ucom_param(tp, &tp->t_termios);
498 		UCOM_MTX_UNLOCK(ucom_cons_softc);
499 	}
500 
501 	lwkt_reltoken(&tty_token);
502 	return (0);
503 }
504 
505 static void
506 ucom_detach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc)
507 {
508 	struct tty *tp = sc->sc_tty;
509 
510 	DPRINTF("sc = %p, tp = %p\n", sc, sc->sc_tty);
511 
512 	if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
513 		UCOM_MTX_LOCK(ucom_cons_softc);
514 		ucom_close(ucom_cons_softc);
515 		sc->sc_flag &= ~UCOM_FLAG_CONSOLE;
516 		UCOM_MTX_UNLOCK(ucom_cons_softc);
517 		ucom_cons_softc = NULL;
518 	}
519 
520 	/* the config thread has been stopped when we get here */
521 
522 	UCOM_MTX_LOCK(sc);
523 	sc->sc_flag |= UCOM_FLAG_GONE;
524 	sc->sc_flag &= ~(UCOM_FLAG_HL_READY | UCOM_FLAG_LL_READY);
525 	UCOM_MTX_UNLOCK(sc);
526 
527 	lwkt_gettoken(&tty_token);
528 	if (tp != NULL) {
529 		ucom_close_refs++;
530 
531 		UCOM_MTX_LOCK(sc);
532 		if (tp->t_state & TS_ISOPEN) {
533 			kprintf("device still open, forcing close\n");
534 			(*linesw[tp->t_line].l_close)(tp, 0);
535 			ttyclose(tp);
536 		}
537 		ucom_close(sc);	/* close, if any */
538 
539 		/*
540 		 * make sure that read and write transfers are stopped
541 		 */
542 		if (sc->sc_callback->ucom_stop_read) {
543 			(sc->sc_callback->ucom_stop_read) (sc);
544 		}
545 		if (sc->sc_callback->ucom_stop_write) {
546 			(sc->sc_callback->ucom_stop_write) (sc);
547 		}
548 		UCOM_MTX_UNLOCK(sc);
549 	} else {
550 		DPRINTF("no tty\n");
551 	}
552 
553 	dev_ops_remove_minor(&ucom_ops,ssc->sc_unit);
554 
555 	lwkt_reltoken(&tty_token);
556 	ucom_unref(ssc);
557 }
558 
559 void
560 ucom_set_pnpinfo_usb(struct ucom_super_softc *ssc, device_t dev)
561 {
562 	char buf[64];
563 	uint8_t iface_index;
564 	struct usb_attach_arg *uaa;
565 
566 	ksnprintf(buf, sizeof(buf), "ttyname=" UCOM_TTY_PREFIX
567 	    "%d ttyports=%d", ssc->sc_unit, ssc->sc_subunits);
568 
569 	/* Store the PNP info in the first interface for the device */
570 	uaa = device_get_ivars(dev);
571 	iface_index = uaa->info.bIfaceIndex;
572 
573 	if (usbd_set_pnpinfo(uaa->device, iface_index, buf) != 0)
574 		device_printf(dev, "Could not set PNP info\n");
575 
576 	/*
577 	 * The following information is also replicated in the PNP-info
578 	 * string which is registered above:
579 	 */
580 	if (ssc->sc_sysctl_ttyname == NULL) {
581 		/*
582 		ssc->sc_sysctl_ttyname = SYSCTL_ADD_STRING(NULL,
583 		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
584 		    OID_AUTO, "ttyname", CTLFLAG_RD, ssc->sc_ttyname, 0,
585 		    "TTY device basename");
586 		*/
587 	}
588 	if (ssc->sc_sysctl_ttyports == NULL) {
589 		/*
590 		ssc->sc_sysctl_ttyports = SYSCTL_ADD_INT(NULL,
591 		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
592 		    OID_AUTO, "ttyports", CTLFLAG_RD,
593 		    NULL, ssc->sc_subunits, "Number of ports");
594 		*/
595 	}
596 }
597 
598 static void
599 ucom_queue_command(struct ucom_softc *sc,
600     usb_proc_callback_t *fn, struct termios *pt,
601     struct usb_proc_msg *t0, struct usb_proc_msg *t1)
602 {
603 	struct ucom_super_softc *ssc = sc->sc_super;
604 	struct ucom_param_task *task;
605 
606 	UCOM_MTX_ASSERT(sc, MA_OWNED);
607 
608 	if (usb_proc_is_gone(&ssc->sc_tq)) {
609 		DPRINTF("proc is gone\n");
610 		return;         /* nothing to do */
611 	}
612 	/*
613 	 * NOTE: The task cannot get executed before we drop the
614 	 * "sc_lock" lock. It is safe to update fields in the message
615 	 * structure after that the message got queued.
616 	 */
617 	task = (struct ucom_param_task *)
618 	  usb_proc_msignal(&ssc->sc_tq, t0, t1);
619 
620 	/* Setup callback and softc pointers */
621 	task->hdr.pm_callback = fn;
622 	task->sc = sc;
623 
624 	/*
625 	 * Make a copy of the termios. This field is only present if
626 	 * the "pt" field is not NULL.
627 	 */
628 	if (pt != NULL)
629 		task->termios_copy = *pt;
630 
631 	/*
632 	 * Closing the device should be synchronous.
633 	 */
634 	if (fn == ucom_cfg_close)
635 		usb_proc_mwait(&ssc->sc_tq, t0, t1);
636 
637 	/*
638 	 * In case of multiple configure requests,
639 	 * keep track of the last one!
640 	 */
641 	if (fn == ucom_cfg_start_transfers)
642 		sc->sc_last_start_xfer = &task->hdr;
643 }
644 
645 static void
646 ucom_shutdown(struct ucom_softc *sc)
647 {
648 	struct tty *tp = sc->sc_tty;
649 
650 	UCOM_MTX_ASSERT(sc, MA_OWNED);
651 
652 	DPRINTF("\n");
653 
654 	/*
655 	 * Hang up if necessary:
656 	 */
657 	if (tp->t_termios.c_cflag & HUPCL) {
658 		ucom_modem(tp, 0, SER_DTR);
659 	}
660 }
661 
662 /*
663  * Return values:
664  *    0: normal
665  * else: taskqueue is draining or gone
666  */
667 uint8_t
668 ucom_cfg_is_gone(struct ucom_softc *sc)
669 {
670 	struct ucom_super_softc *ssc = sc->sc_super;
671 
672 	return (usb_proc_is_gone(&ssc->sc_tq));
673 }
674 
675 static void
676 ucom_cfg_start_transfers(struct usb_proc_msg *_task)
677 {
678 	struct ucom_cfg_task *task =
679 	    (struct ucom_cfg_task *)_task;
680 	struct ucom_softc *sc = task->sc;
681 
682 	if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
683 		return;
684 	}
685 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
686 		/* TTY device closed */
687 		return;
688 	}
689 
690 	if (_task == sc->sc_last_start_xfer)
691 		sc->sc_flag |= UCOM_FLAG_GP_DATA;
692 
693 	if (sc->sc_callback->ucom_start_read) {
694 		(sc->sc_callback->ucom_start_read) (sc);
695 	}
696 	if (sc->sc_callback->ucom_start_write) {
697 		(sc->sc_callback->ucom_start_write) (sc);
698 	}
699 }
700 
701 static void
702 ucom_start_transfers(struct ucom_softc *sc)
703 {
704 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
705 		return;
706 	}
707 	/*
708 	 * Make sure that data transfers are started in both
709 	 * directions:
710 	 */
711 	if (sc->sc_callback->ucom_start_read) {
712 		(sc->sc_callback->ucom_start_read) (sc);
713 	}
714 	if (sc->sc_callback->ucom_start_write) {
715 		(sc->sc_callback->ucom_start_write) (sc);
716 	}
717 }
718 
719 static void
720 ucom_cfg_open(struct usb_proc_msg *_task)
721 {
722 	struct ucom_cfg_task *task =
723 	    (struct ucom_cfg_task *)_task;
724 	struct ucom_softc *sc = task->sc;
725 
726 	DPRINTF("\n");
727 
728 	if (sc->sc_flag & UCOM_FLAG_LL_READY) {
729 
730 		/* already opened */
731 
732 	} else {
733 
734 		sc->sc_flag |= UCOM_FLAG_LL_READY;
735 
736 		if (sc->sc_callback->ucom_cfg_open) {
737 			(sc->sc_callback->ucom_cfg_open) (sc);
738 
739 			/* wait a little */
740 			usb_pause_mtx(sc->sc_lock, hz / 10);
741 		}
742 	}
743 }
744 
745 static int
746 ucom_dev_open(struct dev_open_args *ap)
747 {
748 	cdev_t dev = ap->a_head.a_dev;
749 	struct ucom_softc *sc = (struct ucom_softc *)dev->si_drv1;
750 	int error;
751 
752 	UCOM_MTX_LOCK(sc);
753 	error = ucom_open(sc);
754 	UCOM_MTX_UNLOCK(sc);
755 
756 	return error;
757 }
758 
759 static int
760 ucom_open(struct ucom_softc *sc)
761 {
762 	int error;
763 	struct tty *tp;
764 
765 	if (sc->sc_flag & UCOM_FLAG_GONE) {
766 		return (ENXIO);
767 	}
768 	if (sc->sc_flag & UCOM_FLAG_HL_READY) {
769 		/* already opened */
770 		return (0);
771 	}
772 	DPRINTF("tp = %p\n", sc->sc_tty);
773 
774 	if (sc->sc_callback->ucom_pre_open) {
775 		/*
776 		 * give the lower layer a chance to disallow TTY open, for
777 		 * example if the device is not present:
778 		 */
779 		error = (sc->sc_callback->ucom_pre_open) (sc);
780 		if (error) {
781 			return (error);
782 		}
783 	}
784 	sc->sc_flag |= UCOM_FLAG_HL_READY;
785 
786 	lwkt_gettoken(&tty_token);
787 	tp = sc->sc_tty;
788 
789 	crit_enter();
790 
791 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
792 		struct termios t;
793 
794 		tp->t_dev = reference_dev(sc->sc_cdev);
795 
796 		t.c_ispeed = 0;
797 		t.c_ospeed = TTYDEF_SPEED;
798 		t.c_cflag = TTYDEF_CFLAG;
799 		tp->t_ospeed = 0;
800 		ucom_param(tp, &t);
801 		tp->t_iflag = TTYDEF_IFLAG;
802 		tp->t_oflag = TTYDEF_OFLAG;
803 		tp->t_lflag = TTYDEF_LFLAG;
804 		ttychars(tp);
805 		ttsetwater(tp);
806 
807 		/* Disable transfers */
808 		sc->sc_flag &= ~UCOM_FLAG_GP_DATA;
809 
810 		sc->sc_lsr = 0;
811 		sc->sc_msr = 0;
812 		sc->sc_mcr = 0;
813 
814 		/* reset programmed line state */
815 		sc->sc_pls_curr = 0;
816 		sc->sc_pls_set = 0;
817 		sc->sc_pls_clr = 0;
818 
819 		/* reset jitter buffer */
820 		sc->sc_jitterbuf_in = 0;
821 		sc->sc_jitterbuf_out = 0;
822 
823 		ucom_queue_command(sc, ucom_cfg_open, NULL,
824 				&sc->sc_open_task[0].hdr,
825 				&sc->sc_open_task[1].hdr);
826 
827 		/* Queue transfer enable command last */
828 		ucom_queue_command(sc, ucom_cfg_start_transfers, NULL,
829 				&sc->sc_start_task[0].hdr,
830 				&sc->sc_start_task[1].hdr);
831 
832 		ucom_modem(sc->sc_tty, SER_DTR | SER_RTS, 0);
833 
834 		ucom_ring(sc, 0);
835 
836 		ucom_break(sc, 0);
837 
838 		ucom_status_change(sc);
839 
840 		if (ISSET(sc->sc_msr, SER_DCD)) {
841 			(*linesw[tp->t_line].l_modem)(tp, 1);
842 		}
843 	}
844 	crit_exit();
845 
846 	error = ttyopen(sc->sc_cdev, tp);
847 	if (error) {
848 		lwkt_reltoken(&tty_token);
849 		return (error);
850 	}
851 
852 	error = (*linesw[tp->t_line].l_open)(sc->sc_cdev, tp);
853 	if (error) {
854 		lwkt_reltoken(&tty_token);
855 		return (error);
856 	}
857 
858 	disc_optim(tp, &tp->t_termios, sc);
859 
860 	lwkt_reltoken(&tty_token);
861 
862 	return (0);
863 }
864 
865 static void
866 ucom_cfg_close(struct usb_proc_msg *_task)
867 {
868 	struct ucom_cfg_task *task =
869 	    (struct ucom_cfg_task *)_task;
870 	struct ucom_softc *sc = task->sc;
871 
872 	DPRINTF("\n");
873 
874 	if (sc->sc_flag & UCOM_FLAG_LL_READY) {
875 		sc->sc_flag &= ~UCOM_FLAG_LL_READY;
876 		if (sc->sc_callback->ucom_cfg_close)
877 			(sc->sc_callback->ucom_cfg_close) (sc);
878 	} else {
879 		/* already closed */
880 	}
881 }
882 
883 static int
884 ucom_dev_close(struct dev_close_args *ap)
885 {
886 	cdev_t dev = ap->a_head.a_dev;
887 	struct ucom_softc *sc = (struct ucom_softc *)dev->si_drv1;
888 	int error;
889 
890 	UCOM_MTX_LOCK(sc);
891 	error = ucom_close(sc);
892 	UCOM_MTX_UNLOCK(sc);
893 
894 	return error;
895 }
896 
897 static int
898 ucom_close(struct ucom_softc *sc)
899 {
900 	struct tty *tp = sc->sc_tty;
901 	int error = 0;
902 
903 	DPRINTF("tp=%p\n", tp);
904 
905 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
906 		DPRINTF("tp=%p already closed\n", tp);
907 		return (error);
908 	}
909 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
910 		return(error);
911 	}
912 	ucom_shutdown(sc);
913 
914 	ucom_queue_command(sc, ucom_cfg_close, NULL,
915 	    &sc->sc_close_task[0].hdr,
916 	    &sc->sc_close_task[1].hdr);
917 
918 	sc->sc_flag &= ~(UCOM_FLAG_HL_READY | UCOM_FLAG_RTS_IFLOW);
919 
920 	if (sc->sc_callback->ucom_stop_read) {
921 		(sc->sc_callback->ucom_stop_read) (sc);
922 	}
923 
924 	lwkt_gettoken(&tty_token);
925 	crit_enter();
926 	(*linesw[tp->t_line].l_close)(tp, 0); /* XXX: flags */
927 	disc_optim(tp, &tp->t_termios, sc);
928 	ttyclose(tp);
929 	crit_exit();
930 
931 	if (tp->t_dev) {
932 		release_dev(tp->t_dev);
933 		tp->t_dev = NULL;
934 	}
935 	/* XXX: Detach wakeup */
936 	lwkt_reltoken(&tty_token);
937 
938 	return (error);
939 }
940 
941 #if 0 /* XXX */
942 static void
943 ucom_inwakeup(struct tty *tp)
944 {
945 	struct ucom_softc *sc = tty_softc(tp);
946 	uint16_t pos;
947 
948 	if (sc == NULL)
949 		return;
950 
951 	UCOM_MTX_ASSERT(sc, MA_OWNED);
952 
953 	DPRINTF("tp=%p\n", tp);
954 
955 	if (ttydisc_can_bypass(tp) != 0 ||
956 	    (sc->sc_flag & UCOM_FLAG_HL_READY) == 0 ||
957 	    (sc->sc_flag & UCOM_FLAG_INWAKEUP) != 0) {
958 		return;
959 	}
960 
961 	/* prevent recursion */
962 	sc->sc_flag |= UCOM_FLAG_INWAKEUP;
963 
964 	pos = sc->sc_jitterbuf_out;
965 
966 	while (sc->sc_jitterbuf_in != pos) {
967 		int c;
968 
969 		c = (char)sc->sc_jitterbuf[pos];
970 
971 		if (ttydisc_rint(tp, c, 0) == -1)
972 			break;
973 		pos++;
974 		if (pos >= UCOM_JITTERBUF_SIZE)
975 			pos -= UCOM_JITTERBUF_SIZE;
976 	}
977 
978 	sc->sc_jitterbuf_out = pos;
979 
980 	/* clear RTS in async fashion */
981 	if ((sc->sc_jitterbuf_in == pos) &&
982 	    (sc->sc_flag & UCOM_FLAG_RTS_IFLOW))
983 		ucom_rts(sc, 0);
984 
985 	sc->sc_flag &= ~UCOM_FLAG_INWAKEUP;
986 }
987 #endif
988 
989 static int
990 ucom_dev_read(struct dev_read_args *ap)
991 {
992 	cdev_t dev = ap->a_head.a_dev;
993         struct ucom_softc *sc;
994         struct tty *tp;
995         int error;
996 
997 	sc = 0;
998 
999         lwkt_gettoken(&tty_token);
1000 
1001         tp = dev->si_tty;
1002 	KKASSERT(tp!=NULL);
1003 	sc = tp->t_sc;
1004 	KKASSERT(sc!=NULL);
1005 
1006         DPRINTF("tp = %p, flag = 0x%x\n", tp, ap->a_ioflag);
1007 
1008 	UCOM_MTX_LOCK(sc);
1009         error = (*linesw[tp->t_line].l_read)(tp, ap->a_uio, ap->a_ioflag);
1010 	UCOM_MTX_UNLOCK(sc);
1011 
1012         DPRINTF("error = %d\n", error);
1013 
1014         lwkt_reltoken(&tty_token);
1015         return (error);
1016 }
1017 
1018 static int
1019 ucom_dev_write(struct dev_write_args *ap)
1020 {
1021         cdev_t dev = ap->a_head.a_dev;
1022         struct ucom_softc *sc;
1023         struct tty *tp;
1024         int error;
1025 
1026         lwkt_gettoken(&tty_token);
1027         tp = dev->si_tty;
1028 	KKASSERT(tp!=NULL);
1029 	sc = tp->t_sc;
1030 	KKASSERT(sc!=NULL);
1031 
1032         DPRINTF("tp = %p, flag = 0x%x\n", tp, ap->a_ioflag);
1033 
1034 	UCOM_MTX_LOCK(sc);
1035         error = (*linesw[tp->t_line].l_write)(tp, ap->a_uio, ap->a_ioflag);
1036 	UCOM_MTX_UNLOCK(sc);
1037 
1038         DPRINTF("ucomwrite: error = %d\n", error);
1039 
1040         lwkt_reltoken(&tty_token);
1041         return (error);
1042 }
1043 
1044 static int
1045 ucom_dev_ioctl(struct dev_ioctl_args *ap)
1046 {
1047 	cdev_t dev = ap->a_head.a_dev;
1048 	struct ucom_softc *sc = (struct ucom_softc *)dev->si_drv1;
1049 	u_long cmd = ap->a_cmd;
1050 	caddr_t data = ap->a_data;
1051 	struct tty *tp = sc->sc_tty;
1052 	int d;
1053 	int error;
1054 
1055 	UCOM_MTX_LOCK(sc);
1056 	lwkt_gettoken(&tty_token);
1057 
1058 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1059 		lwkt_reltoken(&tty_token);
1060 		return (EIO);
1061 	}
1062 	DPRINTF("cmd = 0x%08lx\n", cmd);
1063 
1064 	error = (*linesw[tp->t_line].l_ioctl)(tp, ap->a_cmd, ap->a_data,
1065                                               ap->a_fflag, ap->a_cred);
1066 
1067 	if (error != ENOIOCTL) {
1068                 DPRINTF("ucomioctl: l_ioctl: error = %d\n", error);
1069                 lwkt_reltoken(&tty_token);
1070 		UCOM_MTX_UNLOCK(sc);
1071                 return (error);
1072         }
1073 
1074         crit_enter();
1075 
1076 	error = ttioctl(tp, ap->a_cmd, ap->a_data, ap->a_fflag);
1077         disc_optim(tp, &tp->t_termios, sc);
1078         if (error != ENOIOCTL) {
1079                 crit_exit();
1080                 DPRINTF("ucomioctl: ttioctl: error = %d\n", error);
1081                 lwkt_reltoken(&tty_token);
1082 		UCOM_MTX_UNLOCK(sc);
1083 
1084                 return (error);
1085         }
1086 
1087 	error = 0;
1088 
1089 	switch (cmd) {
1090 #if 0 /* XXXDF */
1091 	case TIOCSRING:
1092 		ucom_ring(sc, 1);
1093 		error = 0;
1094 		break;
1095 	case TIOCCRING:
1096 		ucom_ring(sc, 0);
1097 		error = 0;
1098 		break;
1099 #endif
1100 	case TIOCSBRK:
1101 		ucom_break(sc, 1);
1102 		error = 0;
1103 		break;
1104 	case TIOCCBRK:
1105 		ucom_break(sc, 0);
1106 		error = 0;
1107 		break;
1108 	case TIOCSDTR:
1109 		ucom_dtr(sc, 1);
1110 		break;
1111 	case TIOCCDTR:
1112 		ucom_dtr(sc, 0);
1113 		break;
1114 	case TIOCMSET:
1115 		d = *(int *)ap->a_data;
1116 		DPRINTF("ucomioctl: TIOCMSET, 0x%x\n", d);
1117 		ucom_modem(tp, ucom_fromtio(d), 0);
1118 		break;
1119 	case TIOCMGET:
1120 		d = ucom_modem(tp, 0, 0);
1121 		DPRINTF("ucomioctl: TIOCMGET, 0x%x\n", d);
1122 		*(int *)ap->a_data = ucom_totio(d);
1123 		break;
1124 	case TIOCMBIS:
1125 		d = *(int *)ap->a_data;
1126 		ucom_modem(tp, ucom_fromtio(d), 0);
1127 		break;
1128 	case TIOCMBIC:
1129 		d = *(int *)ap->a_data;
1130 		ucom_modem(tp, 0, ucom_fromtio(d));
1131 		break;
1132 	default:
1133 		if (sc->sc_callback->ucom_ioctl) {
1134 			error = (sc->sc_callback->ucom_ioctl)
1135 			    (sc, cmd, data, 0, curthread);
1136 			if (error>=0) {
1137 				crit_exit();
1138 
1139 				lwkt_reltoken(&tty_token);
1140 				UCOM_MTX_UNLOCK(sc);
1141 
1142 				return(error);
1143 			}
1144 		} else {
1145 			error = ENOIOCTL;
1146 		}
1147 		break;
1148 	}
1149 	crit_exit();
1150 
1151 	lwkt_reltoken(&tty_token);
1152 	UCOM_MTX_UNLOCK(sc);
1153 
1154 	return (error);
1155 }
1156 
1157 static int
1158 ucom_totio(int bits)
1159 {
1160 	int rbits = 0;
1161 
1162 	SET(bits, TIOCM_LE);
1163 
1164 	if (ISSET(bits, SER_DTR)) {
1165 		SET(rbits, TIOCM_DTR);
1166 	}
1167 	if (ISSET(bits, SER_RTS)) {
1168 		SET(rbits, TIOCM_RTS);
1169 	}
1170 	if (ISSET(bits, SER_CTS)) {
1171 		SET(rbits, TIOCM_CTS);
1172 	}
1173 	if (ISSET(bits, SER_DCD)) {
1174 		SET(rbits, TIOCM_CD);
1175 	}
1176 	if (ISSET(bits, SER_DSR)) {
1177 		SET(rbits, TIOCM_DSR);
1178 	}
1179 	if (ISSET(bits, SER_RI)) {
1180 		SET(rbits, TIOCM_RI);
1181 	}
1182 
1183 	return (rbits);
1184 }
1185 
1186 static int
1187 ucom_fromtio(int bits)
1188 {
1189 	int rbits = 0;
1190 
1191 	if (ISSET(bits, TIOCM_DTR)) {
1192 		SET(rbits, SER_DTR);
1193 	}
1194 	if (ISSET(bits, TIOCM_RTS)) {
1195 		SET(rbits, SER_RTS);
1196 	}
1197 	if (ISSET(bits, TIOCM_CTS)) {
1198 		SET(rbits, SER_CTS);
1199 	}
1200 	if (ISSET(bits, TIOCM_CD)) {
1201 		SET(rbits, SER_DCD);
1202 	}
1203 	if (ISSET(bits, TIOCM_DSR)) {
1204 		SET(rbits, SER_DSR);
1205 	}
1206 	if (ISSET(bits, TIOCM_RI)) {
1207 		SET(rbits, SER_RI);
1208 	}
1209 
1210 	return (rbits);
1211 }
1212 
1213 static int
1214 ucom_modem(struct tty *tp, int sigon, int sigoff)
1215 {
1216 	struct ucom_softc *sc = (struct ucom_softc *)tp->t_sc;
1217 	uint8_t onoff;
1218 
1219 	UCOM_MTX_ASSERT(sc, MA_OWNED);
1220 
1221 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1222 		return (0);
1223 	}
1224 	if ((sigon == 0) && (sigoff == 0)) {
1225 
1226 		if (sc->sc_mcr & SER_DTR) {
1227 			sigon |= SER_DTR;
1228 		}
1229 		if (sc->sc_mcr & SER_RTS) {
1230 			sigon |= SER_RTS;
1231 		}
1232 		if (sc->sc_msr & SER_CTS) {
1233 			sigon |= SER_CTS;
1234 		}
1235 		if (sc->sc_msr & SER_DCD) {
1236 			sigon |= SER_DCD;
1237 		}
1238 		if (sc->sc_msr & SER_DSR) {
1239 			sigon |= SER_DSR;
1240 		}
1241 		if (sc->sc_msr & SER_RI) {
1242 			sigon |= SER_RI;
1243 		}
1244 		return (sigon);
1245 	}
1246 	if (sigon & SER_DTR) {
1247 		sc->sc_mcr |= SER_DTR;
1248 	}
1249 	if (sigoff & SER_DTR) {
1250 		sc->sc_mcr &= ~SER_DTR;
1251 	}
1252 	if (sigon & SER_RTS) {
1253 		sc->sc_mcr |= SER_RTS;
1254 	}
1255 	if (sigoff & SER_RTS) {
1256 		sc->sc_mcr &= ~SER_RTS;
1257 	}
1258 	onoff = (sc->sc_mcr & SER_DTR) ? 1 : 0;
1259 	ucom_dtr(sc, onoff);
1260 
1261 	onoff = (sc->sc_mcr & SER_RTS) ? 1 : 0;
1262 	ucom_rts(sc, onoff);
1263 
1264 	return (0);
1265 }
1266 
1267 static void
1268 ucom_cfg_line_state(struct usb_proc_msg *_task)
1269 {
1270 	struct ucom_cfg_task *task =
1271 	    (struct ucom_cfg_task *)_task;
1272 	struct ucom_softc *sc = task->sc;
1273 	uint8_t notch_bits;
1274 	uint8_t any_bits;
1275 	uint8_t prev_value;
1276 	uint8_t last_value;
1277 	uint8_t mask;
1278 
1279 	if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
1280 		return;
1281 	}
1282 
1283 	mask = 0;
1284 	/* compute callback mask */
1285 	if (sc->sc_callback->ucom_cfg_set_dtr)
1286 		mask |= UCOM_LS_DTR;
1287 	if (sc->sc_callback->ucom_cfg_set_rts)
1288 		mask |= UCOM_LS_RTS;
1289 	if (sc->sc_callback->ucom_cfg_set_break)
1290 		mask |= UCOM_LS_BREAK;
1291 	if (sc->sc_callback->ucom_cfg_set_ring)
1292 		mask |= UCOM_LS_RING;
1293 
1294 	/* compute the bits we are to program */
1295 	notch_bits = (sc->sc_pls_set & sc->sc_pls_clr) & mask;
1296 	any_bits = (sc->sc_pls_set | sc->sc_pls_clr) & mask;
1297 	prev_value = sc->sc_pls_curr ^ notch_bits;
1298 	last_value = sc->sc_pls_curr;
1299 
1300 	/* reset programmed line state */
1301 	sc->sc_pls_curr = 0;
1302 	sc->sc_pls_set = 0;
1303 	sc->sc_pls_clr = 0;
1304 
1305 	/* ensure that we don't lose any levels */
1306 	if (notch_bits & UCOM_LS_DTR)
1307 		sc->sc_callback->ucom_cfg_set_dtr(sc,
1308 		    (prev_value & UCOM_LS_DTR) ? 1 : 0);
1309 	if (notch_bits & UCOM_LS_RTS)
1310 		sc->sc_callback->ucom_cfg_set_rts(sc,
1311 		    (prev_value & UCOM_LS_RTS) ? 1 : 0);
1312 	if (notch_bits & UCOM_LS_BREAK)
1313 		sc->sc_callback->ucom_cfg_set_break(sc,
1314 		    (prev_value & UCOM_LS_BREAK) ? 1 : 0);
1315 	if (notch_bits & UCOM_LS_RING)
1316 		sc->sc_callback->ucom_cfg_set_ring(sc,
1317 		    (prev_value & UCOM_LS_RING) ? 1 : 0);
1318 
1319 	/* set last value */
1320 	if (any_bits & UCOM_LS_DTR)
1321 		sc->sc_callback->ucom_cfg_set_dtr(sc,
1322 		    (last_value & UCOM_LS_DTR) ? 1 : 0);
1323 	if (any_bits & UCOM_LS_RTS)
1324 		sc->sc_callback->ucom_cfg_set_rts(sc,
1325 		    (last_value & UCOM_LS_RTS) ? 1 : 0);
1326 	if (any_bits & UCOM_LS_BREAK)
1327 		sc->sc_callback->ucom_cfg_set_break(sc,
1328 		    (last_value & UCOM_LS_BREAK) ? 1 : 0);
1329 	if (any_bits & UCOM_LS_RING)
1330 		sc->sc_callback->ucom_cfg_set_ring(sc,
1331 		    (last_value & UCOM_LS_RING) ? 1 : 0);
1332 }
1333 
1334 static void
1335 ucom_line_state(struct ucom_softc *sc,
1336     uint8_t set_bits, uint8_t clear_bits)
1337 {
1338 	UCOM_MTX_ASSERT(sc, MA_OWNED);
1339 
1340 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1341 		return;
1342 	}
1343 
1344 	DPRINTF("on=0x%02x, off=0x%02x\n", set_bits, clear_bits);
1345 
1346 	/* update current programmed line state */
1347 	sc->sc_pls_curr |= set_bits;
1348 	sc->sc_pls_curr &= ~clear_bits;
1349 	sc->sc_pls_set |= set_bits;
1350 	sc->sc_pls_clr |= clear_bits;
1351 
1352 	/* defer driver programming */
1353 	ucom_queue_command(sc, ucom_cfg_line_state, NULL,
1354 	    &sc->sc_line_state_task[0].hdr,
1355 	    &sc->sc_line_state_task[1].hdr);
1356 }
1357 
1358 static void
1359 ucom_ring(struct ucom_softc *sc, uint8_t onoff)
1360 {
1361 	DPRINTF("onoff = %d\n", onoff);
1362 
1363 	if (onoff)
1364 		ucom_line_state(sc, UCOM_LS_RING, 0);
1365 	else
1366 		ucom_line_state(sc, 0, UCOM_LS_RING);
1367 }
1368 
1369 static void
1370 ucom_break(struct ucom_softc *sc, uint8_t onoff)
1371 {
1372 	DPRINTF("onoff = %d\n", onoff);
1373 
1374 	if (onoff)
1375 		ucom_line_state(sc, UCOM_LS_BREAK, 0);
1376 	else
1377 		ucom_line_state(sc, 0, UCOM_LS_BREAK);
1378 }
1379 
1380 static void
1381 ucom_dtr(struct ucom_softc *sc, uint8_t onoff)
1382 {
1383 	DPRINTF("onoff = %d\n", onoff);
1384 
1385 	if (onoff)
1386 		ucom_line_state(sc, UCOM_LS_DTR, 0);
1387 	else
1388 		ucom_line_state(sc, 0, UCOM_LS_DTR);
1389 }
1390 
1391 static void
1392 ucom_rts(struct ucom_softc *sc, uint8_t onoff)
1393 {
1394 	DPRINTF("onoff = %d\n", onoff);
1395 
1396 	if (onoff)
1397 		ucom_line_state(sc, UCOM_LS_RTS, 0);
1398 	else
1399 		ucom_line_state(sc, 0, UCOM_LS_RTS);
1400 }
1401 
1402 static void
1403 ucom_cfg_status_change(struct usb_proc_msg *_task)
1404 {
1405 	struct ucom_cfg_task *task =
1406 	    (struct ucom_cfg_task *)_task;
1407 	struct ucom_softc *sc = task->sc;
1408 	struct tty *tp;
1409 	uint8_t new_msr;
1410 	uint8_t new_lsr;
1411 	uint8_t onoff;
1412 	uint8_t lsr_delta;
1413 
1414 	tp = sc->sc_tty;
1415 
1416 	UCOM_MTX_ASSERT(sc, MA_OWNED);
1417 
1418 	if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
1419 		return;
1420 	}
1421 	if (sc->sc_callback->ucom_cfg_get_status == NULL) {
1422 		return;
1423 	}
1424 	/* get status */
1425 
1426 	new_msr = 0;
1427 	new_lsr = 0;
1428 
1429 	(sc->sc_callback->ucom_cfg_get_status) (sc, &new_lsr, &new_msr);
1430 
1431 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1432 		/* TTY device closed */
1433 		return;
1434 	}
1435 	onoff = ((sc->sc_msr ^ new_msr) & SER_DCD);
1436 	lsr_delta = (sc->sc_lsr ^ new_lsr);
1437 
1438 	sc->sc_msr = new_msr;
1439 	sc->sc_lsr = new_lsr;
1440 
1441 	if (onoff) {
1442 
1443 		onoff = (sc->sc_msr & SER_DCD) ? 1 : 0;
1444 		DPRINTF("DCD changed to %d\n", onoff);
1445         	(*linesw[tp->t_line].l_modem)(tp, onoff);
1446 	}
1447 
1448 	if ((lsr_delta & ULSR_BI) && (sc->sc_lsr & ULSR_BI)) {
1449 
1450 		DPRINTF("BREAK detected\n");
1451         	(*linesw[tp->t_line].l_rint)(0, tp);
1452 
1453 		/*
1454 		ttydisc_rint(tp, 0, TRE_BREAK);
1455 		ttydisc_rint_done(tp);
1456 		*/
1457 	}
1458 
1459 	if ((lsr_delta & ULSR_FE) && (sc->sc_lsr & ULSR_FE)) {
1460 
1461 		DPRINTF("Frame error detected\n");
1462         	(*linesw[tp->t_line].l_rint)(0, tp);
1463 
1464 		/*
1465 		ttydisc_rint(tp, 0, TRE_FRAMING);
1466 		ttydisc_rint_done(tp);
1467 		*/
1468 	}
1469 
1470 	if ((lsr_delta & ULSR_PE) && (sc->sc_lsr & ULSR_PE)) {
1471 
1472 		DPRINTF("Parity error detected\n");
1473         	(*linesw[tp->t_line].l_rint)(0, tp);
1474 		/*
1475 		ttydisc_rint(tp, 0, TRE_PARITY);
1476 		ttydisc_rint_done(tp);
1477 		*/
1478 	}
1479 }
1480 
1481 void
1482 ucom_status_change(struct ucom_softc *sc)
1483 {
1484 	UCOM_MTX_ASSERT(sc, MA_OWNED);
1485 
1486 	if (sc->sc_flag & UCOM_FLAG_CONSOLE)
1487 		return;		/* not supported */
1488 
1489 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1490 		return;
1491 	}
1492 	DPRINTF("\n");
1493 
1494 	ucom_queue_command(sc, ucom_cfg_status_change, NULL,
1495 	    &sc->sc_status_task[0].hdr,
1496 	    &sc->sc_status_task[1].hdr);
1497 }
1498 
1499 static void
1500 ucom_cfg_param(struct usb_proc_msg *_task)
1501 {
1502 	struct ucom_param_task *task =
1503 	    (struct ucom_param_task *)_task;
1504 	struct ucom_softc *sc = task->sc;
1505 
1506 	if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
1507 		return;
1508 	}
1509 	if (sc->sc_callback->ucom_cfg_param == NULL) {
1510 		return;
1511 	}
1512 
1513 	(sc->sc_callback->ucom_cfg_param) (sc, &task->termios_copy);
1514 
1515 	/* wait a little */
1516 	usb_pause_mtx(sc->sc_lock, hz / 10);
1517 }
1518 
1519 static int
1520 ucom_param(struct tty *tp, struct termios *t)
1521 {
1522 	struct ucom_softc *sc = (struct ucom_softc *)tp->t_sc;
1523 	uint8_t opened;
1524 	int error;
1525 
1526 	lwkt_gettoken(&tty_token);
1527 	UCOM_MTX_ASSERT(sc, MA_OWNED);
1528 
1529 	opened = 0;
1530 	error = 0;
1531 
1532 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1533 
1534 		/* XXX the TTY layer should call "open()" first! */
1535 		/*
1536 		 * Not quite: Its ordering is partly backwards, but
1537 		 * some parameters must be set early in ttydev_open(),
1538 		 * possibly before calling ttydevsw_open().
1539 		 */
1540 		error = ucom_open(sc);
1541 
1542 		if (error) {
1543 			goto done;
1544 		}
1545 		opened = 1;
1546 	}
1547 	DPRINTF("sc = %p\n", sc);
1548 
1549 	/* Check requested parameters. */
1550 	if (t->c_ispeed && (t->c_ispeed != t->c_ospeed)) {
1551 		/* XXX c_ospeed == 0 is perfectly valid. */
1552 		DPRINTF("mismatch ispeed and ospeed\n");
1553 		error = EINVAL;
1554 		goto done;
1555 	}
1556 	t->c_ispeed = t->c_ospeed;
1557 
1558 	if (sc->sc_callback->ucom_pre_param) {
1559 		/* Let the lower layer verify the parameters */
1560 		error = (sc->sc_callback->ucom_pre_param) (sc, t);
1561 		if (error) {
1562 			DPRINTF("callback error = %d\n", error);
1563 			goto done;
1564 		}
1565 	}
1566 
1567 	/* Disable transfers */
1568 	sc->sc_flag &= ~UCOM_FLAG_GP_DATA;
1569 
1570 	/* Queue baud rate programming command first */
1571 	ucom_queue_command(sc, ucom_cfg_param, t,
1572 	    &sc->sc_param_task[0].hdr,
1573 	    &sc->sc_param_task[1].hdr);
1574 
1575 	/* Queue transfer enable command last */
1576 	ucom_queue_command(sc, ucom_cfg_start_transfers, NULL,
1577 	    &sc->sc_start_task[0].hdr,
1578 	    &sc->sc_start_task[1].hdr);
1579 
1580 	if (t->c_cflag & CRTS_IFLOW) {
1581 		sc->sc_flag |= UCOM_FLAG_RTS_IFLOW;
1582 	} else if (sc->sc_flag & UCOM_FLAG_RTS_IFLOW) {
1583 		sc->sc_flag &= ~UCOM_FLAG_RTS_IFLOW;
1584 		ucom_modem(tp, SER_RTS, 0);
1585 	}
1586 done:
1587 	if (error) {
1588 		if (opened) {
1589 			ucom_close(sc);
1590 		}
1591 	}
1592 
1593 	lwkt_reltoken(&tty_token);
1594 	return (error);
1595 }
1596 
1597 static void
1598 ucom_start(struct tty *tp)
1599 {
1600 	struct ucom_softc *sc = (struct ucom_softc *)tp->t_sc;
1601 
1602 	UCOM_MTX_ASSERT(sc, MA_OWNED);
1603 
1604 	DPRINTF("sc = %p\n", sc);
1605 
1606 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1607 		/* The higher layer is not ready */
1608 		return;
1609 	}
1610 
1611 	lwkt_gettoken(&tty_token);
1612 	crit_enter();
1613 
1614 	if (tp->t_state & TS_TBLOCK) {
1615 		if (ISSET(sc->sc_mcr, SER_RTS) &&
1616 		    ISSET(sc->sc_flag, UCOM_FLAG_RTS_IFLOW)) {
1617 			DPRINTF("ucom_start: clear RTS\n");
1618 			(void)ucom_modem(tp, 0, SER_RTS);
1619 		}
1620 	} else {
1621 		if (!ISSET(sc->sc_mcr, SER_RTS) &&
1622 		    tp->t_rawq.c_cc <= tp->t_ilowat &&
1623 		    ISSET(sc->sc_flag, UCOM_FLAG_RTS_IFLOW)) {
1624 			DPRINTF("ucom_start: set RTS\n");
1625 			(void)ucom_modem(tp, SER_RTS, 0);
1626 		}
1627 	}
1628 
1629 	if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) {
1630 		ttwwakeup(tp);
1631 		DPRINTF("ucom_start: stopped\n");
1632 		goto out;
1633 	}
1634 
1635 	if (tp->t_outq.c_cc <= tp->t_olowat) {
1636 		if (ISSET(tp->t_state, TS_SO_OLOWAT)) {
1637 			CLR(tp->t_state, TS_SO_OLOWAT);
1638 			wakeup(TSA_OLOWAT(tp));
1639 		}
1640 		KNOTE(&tp->t_wkq.ki_note, 0);
1641 		if (tp->t_outq.c_cc == 0) {
1642 			if (ISSET(tp->t_state, TS_BUSY | TS_SO_OCOMPLETE) ==
1643 					TS_SO_OCOMPLETE && tp->t_outq.c_cc == 0) {
1644 				CLR(tp->t_state, TS_SO_OCOMPLETE);
1645 				wakeup(TSA_OCOMPLETE(tp));
1646 			}
1647 			goto out;
1648 		}
1649 	}
1650 
1651 	DPRINTF("about to start write?\n");
1652 	ucom_start_transfers(sc);
1653 
1654 	ttwwakeup(tp);
1655 
1656 out:
1657 	crit_exit();
1658 	lwkt_reltoken(&tty_token);
1659 }
1660 
1661 static void
1662 ucom_stop(struct tty *tp, int flag)
1663 {
1664 	struct ucom_softc *sc = (struct ucom_softc *)tp->t_sc;
1665 
1666 	DPRINTF("sc = %p, x = 0x%x\n", sc, flag);
1667 
1668 	lwkt_gettoken(&tty_token);
1669 	if (flag & FREAD) {
1670 		/*
1671 		 * This is just supposed to flush pending receive data,
1672 		 * not stop the reception of data entirely!
1673 		 */
1674 		DPRINTF("read\n");
1675 		if (sc->sc_callback->ucom_stop_read) {
1676 			(sc->sc_callback->ucom_stop_read) (sc);
1677 		}
1678 		if (sc->sc_callback->ucom_start_read) {
1679 			(sc->sc_callback->ucom_start_read) (sc);
1680 		}
1681 /*		ucomstopread(sc);
1682 		ucomstartread(sc);
1683 */	}
1684 
1685 	if (flag & FWRITE) {
1686 		DPRINTF("write\n");
1687 		crit_enter();
1688 		if (ISSET(tp->t_state, TS_BUSY)) {
1689 			/* XXX do what? */
1690 			if (!ISSET(tp->t_state, TS_TTSTOP))
1691 				SET(tp->t_state, TS_FLUSH);
1692 		}
1693 		crit_exit();
1694 	}
1695 
1696 	DPRINTF("done\n");
1697 	lwkt_reltoken(&tty_token);
1698 }
1699 
1700 /*------------------------------------------------------------------------*
1701  *	ucom_get_data
1702  * Input values:
1703  * len: maximum length of data to get
1704  *
1705  * Get data from the TTY layer
1706  *
1707  * Return values:
1708  * 0: No data is available.
1709  * Else: Data is available.
1710  *------------------------------------------------------------------------*/
1711 
1712 /* Copy data from the tty layer to usb */
1713 uint8_t
1714 ucom_get_data(struct ucom_softc *sc, struct usb_page_cache *pc,
1715     uint32_t offset, uint32_t len, uint32_t *actlen)
1716 {
1717 	struct usb_page_search res;
1718 	struct tty *tp = sc->sc_tty;
1719 	uint32_t cnt;
1720 	uint32_t offset_orig;
1721 
1722 	DPRINTF("\n");
1723 
1724 	UCOM_MTX_ASSERT(sc, MA_OWNED);
1725 	if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
1726 		unsigned int temp;
1727 
1728 		/* get total TX length */
1729 
1730 		temp = ucom_cons_tx_high - ucom_cons_tx_low;
1731 		temp %= UCOM_CONS_BUFSIZE;
1732 
1733 		/* limit TX length */
1734 
1735 		if (temp > (UCOM_CONS_BUFSIZE - ucom_cons_tx_low))
1736 			temp = (UCOM_CONS_BUFSIZE - ucom_cons_tx_low);
1737 
1738 		if (temp > len)
1739 			temp = len;
1740 
1741 		/* copy in data */
1742 
1743 		usbd_copy_in(pc, offset, ucom_cons_tx_buf + ucom_cons_tx_low, temp);
1744 
1745 		/* update counters */
1746 
1747 		ucom_cons_tx_low += temp;
1748 		ucom_cons_tx_low %= UCOM_CONS_BUFSIZE;
1749 
1750 		/* store actual length */
1751 
1752 		*actlen = temp;
1753 
1754 		return (temp ? 1 : 0);
1755 	}
1756 
1757 	if (tty_gone(tp) ||
1758 	    !(sc->sc_flag & UCOM_FLAG_GP_DATA)) {
1759 		actlen[0] = 0;
1760 		return (0);		/* multiport device polling */
1761 	}
1762 
1763 	offset_orig = offset;
1764 
1765 	lwkt_gettoken(&tty_token);
1766 	crit_enter();
1767 	while (len != 0) {
1768 		usbd_get_page(pc, offset, &res);
1769 
1770 		/* Buffer bigger than max requested data */
1771 		if (res.length > len) {
1772 			res.length = len;
1773 		}
1774 		/* copy data directly into USB buffer */
1775 		SET(tp->t_state, TS_BUSY);
1776 		cnt = q_to_b(&tp->t_outq, res.buffer, len);
1777 		if (cnt == 0) {
1778 			DPRINTF("ucom_get_data: cnt == 0\n");
1779 			CLR(tp->t_state, TS_BUSY);
1780 			break;
1781 		}
1782 
1783 		CLR(tp->t_state, TS_BUSY);
1784 
1785 		/* XXX mp: This breaks avrdude,
1786                            does the flush need to happen
1787                            elsewhere?
1788 		if (ISSET(tp->t_state, TS_FLUSH))
1789 			CLR(tp->t_state, TS_FLUSH);
1790 		else
1791 			ndflush(&tp->t_outq,cnt);
1792 		*/
1793 
1794 		offset += cnt;
1795 		len -= cnt;
1796 
1797 		if (cnt < res.length) {
1798 			/* end of buffer */
1799 			break;
1800 		}
1801 	}
1802 	crit_exit();
1803 	lwkt_reltoken(&tty_token);
1804 
1805 	actlen[0] = offset - offset_orig;
1806 
1807 	DPRINTF("cnt=%d\n", actlen[0]);
1808 
1809 	if (actlen[0] == 0) {
1810 		return (0);
1811 	}
1812 	return (1);
1813 }
1814 
1815 /*
1816  * Write data to the tty layer
1817  */
1818 
1819 void
1820 ucom_put_data(struct ucom_softc *sc, struct usb_page_cache *pc,
1821     uint32_t offset, uint32_t len)
1822 {
1823 	struct usb_page_search res;
1824 	struct tty *tp = sc->sc_tty;
1825 	char *buf;
1826 	uint32_t cnt;
1827 	int lostcc;
1828 
1829 	DPRINTF("\n");
1830 
1831 	UCOM_MTX_ASSERT(sc, MA_OWNED);
1832 	lwkt_gettoken(&tty_token);
1833 
1834 	if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
1835 		unsigned int temp;
1836 
1837 		/* get maximum RX length */
1838 
1839 		temp = (UCOM_CONS_BUFSIZE - 1) - ucom_cons_rx_high + ucom_cons_rx_low;
1840 		temp %= UCOM_CONS_BUFSIZE;
1841 
1842 		/* limit RX length */
1843 
1844 		if (temp > (UCOM_CONS_BUFSIZE - ucom_cons_rx_high))
1845 			temp = (UCOM_CONS_BUFSIZE - ucom_cons_rx_high);
1846 
1847 		if (temp > len)
1848 			temp = len;
1849 
1850 		/* copy out data */
1851 
1852 		usbd_copy_out(pc, offset, ucom_cons_rx_buf + ucom_cons_rx_high, temp);
1853 
1854 		/* update counters */
1855 
1856 		ucom_cons_rx_high += temp;
1857 		ucom_cons_rx_high %= UCOM_CONS_BUFSIZE;
1858 
1859 		lwkt_reltoken(&tty_token);
1860 		return;
1861 	}
1862 
1863 	if (tty_gone(tp)) {
1864 		lwkt_reltoken(&tty_token);
1865 		return;			/* multiport device polling */
1866 	}
1867 	if (len == 0) {
1868 		lwkt_reltoken(&tty_token);
1869 		return;			/* no data */
1870 	}
1871 
1872 	/* set a flag to prevent recursation ? */
1873 
1874 	crit_enter();
1875 	while (len > 0) {
1876 		usbd_get_page(pc, offset, &res);
1877 
1878 		if (res.length > len) {
1879 			res.length = len;
1880 		}
1881 		len -= res.length;
1882 		offset += res.length;
1883 
1884 		/* pass characters to tty layer */
1885 
1886 		buf = res.buffer;
1887 		cnt = res.length;
1888 
1889 		/* first check if we can pass the buffer directly */
1890 
1891 		if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1892 			/* clear any jitter buffer */
1893 			sc->sc_jitterbuf_in = 0;
1894 			sc->sc_jitterbuf_out = 0;
1895 
1896 			if (tp->t_rawq.c_cc + cnt > tp->t_ihiwat
1897 			    && (sc->sc_flag & UCOM_FLAG_RTS_IFLOW
1898 				|| tp->t_iflag & IXOFF)
1899 			    && !(tp->t_state & TS_TBLOCK))
1900 			       ttyblock(tp);
1901 			lostcc = b_to_q((char *)buf, cnt, &tp->t_rawq);
1902 			tp->t_rawcc += cnt;
1903 			if (sc->hotchar) {
1904 				while (cnt) {
1905 					if (*buf == sc->hotchar)
1906 						break;
1907 					--cnt;
1908 					++buf;
1909 				}
1910 				if (cnt)
1911 					setsofttty();
1912 			}
1913 			ttwakeup(tp);
1914 			if (tp->t_state & TS_TTSTOP
1915 			    && (tp->t_iflag & IXANY
1916 				|| tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
1917 				tp->t_state &= ~TS_TTSTOP;
1918 				tp->t_lflag &= ~FLUSHO;
1919 				ucom_start(tp);
1920 			}
1921 			if (lostcc > 0)
1922 				kprintf("lost %d chars\n", lostcc);
1923 
1924 			/*
1925 			if (ttydisc_rint_bypass(tp, buf, cnt) != cnt) {
1926 				DPRINTF("tp=%p, data lost\n", tp);
1927 			}
1928 			*/
1929 			continue;
1930 		} else {
1931 		/* need to loop */
1932 			for (cnt = 0; cnt != res.length; cnt++) {
1933 				if (sc->sc_jitterbuf_in != sc->sc_jitterbuf_out ||
1934 				    (*linesw[tp->t_line].l_rint)(buf[cnt], tp) == -1) {
1935 					uint16_t end;
1936 					uint16_t pos;
1937 
1938 					pos = sc->sc_jitterbuf_in;
1939 					end = sc->sc_jitterbuf_out +
1940 					    UCOM_JITTERBUF_SIZE - 1;
1941 
1942 					if (end >= UCOM_JITTERBUF_SIZE)
1943 						end -= UCOM_JITTERBUF_SIZE;
1944 
1945 					for (; cnt != res.length; cnt++) {
1946 						if (pos == end)
1947 							break;
1948 						sc->sc_jitterbuf[pos] = buf[cnt];
1949 						pos++;
1950 						if (pos >= UCOM_JITTERBUF_SIZE)
1951 							pos -= UCOM_JITTERBUF_SIZE;
1952 					}
1953 
1954 					sc->sc_jitterbuf_in = pos;
1955 
1956 					/* set RTS in async fashion */
1957 					if (sc->sc_flag & UCOM_FLAG_RTS_IFLOW)
1958 						ucom_rts(sc, 1);
1959 
1960 					DPRINTF("tp=%p, lost %d "
1961 					    "chars\n", tp, res.length - cnt);
1962 					break;
1963 				}
1964 			}
1965 		}
1966 	}
1967 	crit_exit();
1968 	lwkt_reltoken(&tty_token);
1969 	/*
1970 	ttydisc_rint_done(tp);
1971 	*/
1972 }
1973 
1974 #if 0 /* XXX */
1975 static void
1976 ucom_free(void *xsc)
1977 {
1978 	struct ucom_softc *sc = xsc;
1979 
1980 	if (sc->sc_callback->ucom_free != NULL)
1981 		sc->sc_callback->ucom_free(sc);
1982 	else
1983 		/*ucom_unref(sc->sc_super) XXX hack, see end of ucom_detach_tty() */;
1984 
1985 	lockmgr(&ucom_lock, LK_EXCLUSIVE);
1986 	ucom_close_refs--;
1987 	lockmgr(&ucom_lock, LK_RELEASE);
1988 }
1989 
1990 static cn_probe_t ucom_cnprobe;
1991 static cn_init_t ucom_cninit;
1992 static cn_term_t ucom_cnterm;
1993 static cn_getc_t ucom_cngetc;
1994 static cn_putc_t ucom_cnputc;
1995 
1996 /*
1997 static cn_grab_t ucom_cngrab;
1998 static cn_ungrab_t ucom_cnungrab;
1999 CONSOLE_DRIVER(ucom);
2000 */
2001 
2002 static void
2003 ucom_cnprobe(struct consdev  *cp)
2004 {
2005 	if (ucom_cons_unit != -1)
2006 		cp->cn_pri = CN_NORMAL;
2007 	else
2008 		cp->cn_pri = CN_DEAD;
2009 
2010 	/*
2011 	strlcpy(cp->cn_name, "ucom", sizeof(cp->cn_name));
2012 	*/
2013 }
2014 
2015 static void
2016 ucom_cninit(struct consdev  *cp)
2017 {
2018 }
2019 
2020 static void
2021 ucom_cnterm(struct consdev  *cp)
2022 {
2023 }
2024 
2025 static void
2026 ucom_cngrab(struct consdev *cp)
2027 {
2028 }
2029 
2030 static void
2031 ucom_cnungrab(struct consdev *cp)
2032 {
2033 }
2034 
2035 static int
2036 ucom_cngetc(struct consdev *cd)
2037 {
2038 	struct ucom_softc *sc = ucom_cons_softc;
2039 	int c;
2040 
2041 	if (sc == NULL)
2042 		return (-1);
2043 
2044 	UCOM_MTX_LOCK(sc);
2045 
2046 	if (ucom_cons_rx_low != ucom_cons_rx_high) {
2047 		c = ucom_cons_rx_buf[ucom_cons_rx_low];
2048 		ucom_cons_rx_low ++;
2049 		ucom_cons_rx_low %= UCOM_CONS_BUFSIZE;
2050 	} else {
2051 		c = -1;
2052 	}
2053 
2054 	/* start USB transfers */
2055 	ucom_outwakeup(sc->sc_tty);
2056 
2057 	UCOM_MTX_UNLOCK(sc);
2058 
2059 	/* poll if necessary */
2060 	/*
2061 	if (kdb_active && sc->sc_callback->ucom_poll)
2062 		(sc->sc_callback->ucom_poll) (sc);
2063 	*/
2064 	return (c);
2065 }
2066 
2067 static void
2068 ucom_cnputc(void *cd, int c)
2069 	/*
2070 ucom_cnputc(struct consdev *cd, int c)
2071 	*/
2072 
2073 {
2074 	struct ucom_softc *sc = ucom_cons_softc;
2075 	unsigned int temp;
2076 
2077 	if (sc == NULL)
2078 		return;
2079 
2080  repeat:
2081 
2082 	UCOM_MTX_LOCK(sc);
2083 
2084 	/* compute maximum TX length */
2085 
2086 	temp = (UCOM_CONS_BUFSIZE - 1) - ucom_cons_tx_high + ucom_cons_tx_low;
2087 	temp %= UCOM_CONS_BUFSIZE;
2088 
2089 	if (temp) {
2090 		ucom_cons_tx_buf[ucom_cons_tx_high] = c;
2091 		ucom_cons_tx_high ++;
2092 		ucom_cons_tx_high %= UCOM_CONS_BUFSIZE;
2093 	}
2094 
2095 	/* start USB transfers */
2096 	ucom_outwakeup(sc->sc_tty);
2097 
2098 	UCOM_MTX_UNLOCK(sc);
2099 
2100 	/* poll if necessary */
2101 #if 0 /* XXX */
2102 	if (kdb_active && sc->sc_callback->ucom_poll) {
2103 		(sc->sc_callback->ucom_poll) (sc);
2104 		/* simple flow control */
2105 		if (temp == 0)
2106 			goto repeat;
2107 	}
2108 #endif
2109 }
2110 #endif
2111 /*------------------------------------------------------------------------*
2112  *	ucom_ref
2113  *
2114  * This function will increment the super UCOM reference count.
2115  *------------------------------------------------------------------------*/
2116 void
2117 ucom_ref(struct ucom_super_softc *ssc)
2118 {
2119 	lockmgr(&ucom_lock, LK_EXCLUSIVE);
2120 	ssc->sc_refs++;
2121 	lockmgr(&ucom_lock, LK_RELEASE);
2122 }
2123 
2124 /*------------------------------------------------------------------------*
2125  *	ucom_free_unit
2126  *
2127  * This function will free the super UCOM's allocated unit
2128  * number. This function can be called on a zero-initialized
2129  * structure. This function can be called multiple times.
2130  *------------------------------------------------------------------------*/
2131 static void
2132 ucom_free_unit(struct ucom_super_softc *ssc)
2133 {
2134 	if (!(ssc->sc_flag & UCOM_FLAG_FREE_UNIT))
2135 		return;
2136 
2137 	ucom_unit_free(ssc->sc_unit);
2138 
2139 	ssc->sc_flag &= ~UCOM_FLAG_FREE_UNIT;
2140 }
2141 
2142 /*------------------------------------------------------------------------*
2143  *	ucom_unref
2144  *
2145  * This function will decrement the super UCOM reference count.
2146  *
2147  * Return values:
2148  * 0: UCOM structures are still referenced.
2149  * Else: UCOM structures are no longer referenced.
2150  *------------------------------------------------------------------------*/
2151 int
2152 ucom_unref(struct ucom_super_softc *ssc)
2153 {
2154 	int retval;
2155 
2156 	lockmgr(&ucom_lock, LK_EXCLUSIVE);
2157 	retval = (ssc->sc_refs < 2);
2158 	ssc->sc_refs--;
2159 	lockmgr(&ucom_lock, LK_RELEASE);
2160 
2161 	if (retval)
2162 		ucom_free_unit(ssc);
2163 
2164 	return (retval);
2165 }
2166 
2167 /*
2168  * NOTE: Must be called with tty_token held.
2169  */
2170 static void
2171 disc_optim(struct tty *tp, struct termios *t, struct ucom_softc *sc)
2172 {
2173 	ASSERT_LWKT_TOKEN_HELD(&tty_token);
2174 	if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2175 	    && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2176 	    && (!(t->c_iflag & PARMRK)
2177 		|| (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2178 	    && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2179 	    && linesw[tp->t_line].l_rint == ttyinput) {
2180 		DPRINTF("disc_optim: bypass l_rint\n");
2181 		tp->t_state |= TS_CAN_BYPASS_L_RINT;
2182 	} else {
2183 		DPRINTF("disc_optim: can't bypass l_rint\n");
2184 		tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
2185 	}
2186 	sc->hotchar = linesw[tp->t_line].l_hotchar;
2187 }
2188 
2189 #if defined(GDB)
2190 
2191 #include <gdb/gdb.h>
2192 
2193 static gdb_probe_f ucom_gdbprobe;
2194 static gdb_init_f ucom_gdbinit;
2195 static gdb_term_f ucom_gdbterm;
2196 static gdb_getc_f ucom_gdbgetc;
2197 static gdb_putc_f ucom_gdbputc;
2198 
2199 GDB_DBGPORT(sio, ucom_gdbprobe, ucom_gdbinit, ucom_gdbterm, ucom_gdbgetc, ucom_gdbputc);
2200 
2201 static int
2202 ucom_gdbprobe(void)
2203 {
2204 	return ((ucom_cons_softc != NULL) ? 0 : -1);
2205 }
2206 
2207 static void
2208 ucom_gdbinit(void)
2209 {
2210 }
2211 
2212 static void
2213 ucom_gdbterm(void)
2214 {
2215 }
2216 
2217 static void
2218 ucom_gdbputc(int c)
2219 {
2220         ucom_cnputc(NULL, c);
2221 }
2222 
2223 static int
2224 ucom_gdbgetc(void)
2225 {
2226         return (ucom_cngetc(NULL));
2227 }
2228 
2229 #endif
2230 
2231 
2232