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