xref: /freebsd/sys/dev/usb/serial/usb_serial.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
1 /*	$NetBSD: ucom.c,v 1.40 2001/11/13 06:24:54 lukem Exp $	*/
2 
3 /*-
4  * SPDX-License-Identifier: BSD-2-Clause
5  *
6  * Copyright (c) 2001-2003, 2005, 2008
7  *	Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 /*-
34  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
35  * All rights reserved.
36  *
37  * This code is derived from software contributed to The NetBSD Foundation
38  * by Lennart Augustsson (lennart@augustsson.net) at
39  * Carlstedt Research & Technology.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  *
50  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
51  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
52  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
54  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
55  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
56  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
57  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
58  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
59  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
60  * POSSIBILITY OF SUCH DAMAGE.
61  */
62 
63 #include <sys/stdint.h>
64 #include <sys/stddef.h>
65 #include <sys/param.h>
66 #include <sys/queue.h>
67 #include <sys/types.h>
68 #include <sys/systm.h>
69 #include <sys/kernel.h>
70 #include <sys/bus.h>
71 #include <sys/module.h>
72 #include <sys/lock.h>
73 #include <sys/mutex.h>
74 #include <sys/condvar.h>
75 #include <sys/sysctl.h>
76 #include <sys/sx.h>
77 #include <sys/unistd.h>
78 #include <sys/callout.h>
79 #include <sys/malloc.h>
80 #include <sys/priv.h>
81 #include <sys/cons.h>
82 
83 #include <dev/uart/uart_ppstypes.h>
84 
85 #include <dev/usb/usb.h>
86 #include <dev/usb/usbdi.h>
87 #include <dev/usb/usbdi_util.h>
88 
89 #define	USB_DEBUG_VAR ucom_debug
90 #include <dev/usb/usb_debug.h>
91 #include <dev/usb/usb_busdma.h>
92 #include <dev/usb/usb_process.h>
93 
94 #include <dev/usb/serial/usb_serial.h>
95 
96 #include "opt_gdb.h"
97 
98 static SYSCTL_NODE(_hw_usb, OID_AUTO, ucom, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
99     "USB ucom");
100 
101 static int ucom_pps_mode;
102 
103 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, pps_mode, CTLFLAG_RWTUN,
104     &ucom_pps_mode, 0,
105     "pulse capture mode: 0/1/2=disabled/CTS/DCD; add 0x10 to invert");
106 
107 static int ucom_device_mode_console = 1;
108 
109 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, device_mode_console, CTLFLAG_RW,
110     &ucom_device_mode_console, 0,
111     "set to 1 to mark terminals as consoles when in device mode");
112 
113 #ifdef USB_DEBUG
114 static int ucom_debug = 0;
115 
116 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, debug, CTLFLAG_RWTUN,
117     &ucom_debug, 0, "ucom debug level");
118 #endif
119 
120 #define	UCOM_CONS_BUFSIZE 1024
121 
122 static uint8_t ucom_cons_rx_buf[UCOM_CONS_BUFSIZE];
123 static uint8_t ucom_cons_tx_buf[UCOM_CONS_BUFSIZE];
124 
125 static unsigned ucom_cons_rx_low = 0;
126 static unsigned ucom_cons_rx_high = 0;
127 
128 static unsigned ucom_cons_tx_low = 0;
129 static unsigned ucom_cons_tx_high = 0;
130 
131 static int ucom_cons_unit = -1;
132 static int ucom_cons_subunit = 0;
133 static int ucom_cons_baud = 115200;
134 static struct ucom_softc *ucom_cons_softc = NULL;
135 
136 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_unit, CTLFLAG_RWTUN,
137     &ucom_cons_unit, 0, "console unit number");
138 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_subunit, CTLFLAG_RWTUN,
139     &ucom_cons_subunit, 0, "console subunit number");
140 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_baud, CTLFLAG_RWTUN,
141     &ucom_cons_baud, 0, "console baud rate");
142 
143 static usb_proc_callback_t ucom_cfg_start_transfers;
144 static usb_proc_callback_t ucom_cfg_open;
145 static usb_proc_callback_t ucom_cfg_close;
146 static usb_proc_callback_t ucom_cfg_line_state;
147 static usb_proc_callback_t ucom_cfg_status_change;
148 static usb_proc_callback_t ucom_cfg_param;
149 
150 static int	ucom_unit_alloc(void);
151 static void	ucom_unit_free(int);
152 static int	ucom_attach_tty(struct ucom_super_softc *, struct ucom_softc *);
153 static void	ucom_detach_tty(struct ucom_super_softc *, struct ucom_softc *);
154 static void	ucom_queue_command(struct ucom_softc *,
155 		    usb_proc_callback_t *, struct termios *pt,
156 		    struct usb_proc_msg *t0, struct usb_proc_msg *t1);
157 static void	ucom_shutdown(struct ucom_softc *);
158 static void	ucom_ring(struct ucom_softc *, uint8_t);
159 static void	ucom_break(struct ucom_softc *, uint8_t);
160 static void	ucom_dtr(struct ucom_softc *, uint8_t);
161 static void	ucom_rts(struct ucom_softc *, uint8_t);
162 
163 static tsw_open_t ucom_open;
164 static tsw_close_t ucom_close;
165 static tsw_ioctl_t ucom_ioctl;
166 static tsw_modem_t ucom_modem;
167 static tsw_param_t ucom_param;
168 static tsw_outwakeup_t ucom_outwakeup;
169 static tsw_inwakeup_t ucom_inwakeup;
170 static tsw_free_t ucom_free;
171 static tsw_busy_t ucom_busy;
172 
173 static struct ttydevsw ucom_class = {
174 	.tsw_flags = TF_INITLOCK | TF_CALLOUT,
175 	.tsw_open = ucom_open,
176 	.tsw_close = ucom_close,
177 	.tsw_outwakeup = ucom_outwakeup,
178 	.tsw_inwakeup = ucom_inwakeup,
179 	.tsw_ioctl = ucom_ioctl,
180 	.tsw_param = ucom_param,
181 	.tsw_modem = ucom_modem,
182 	.tsw_free = ucom_free,
183 	.tsw_busy = ucom_busy,
184 };
185 
186 MODULE_DEPEND(ucom, usb, 1, 1, 1);
187 MODULE_VERSION(ucom, 1);
188 
189 #define	UCOM_UNIT_MAX 		128	/* maximum number of units */
190 #define	UCOM_TTY_PREFIX		"U"
191 
192 static struct unrhdr *ucom_unrhdr;
193 static struct mtx ucom_mtx;
194 static int ucom_close_refs;
195 
196 static void
197 ucom_init(void *arg)
198 {
199 	DPRINTF("\n");
200 	ucom_unrhdr = new_unrhdr(0, UCOM_UNIT_MAX - 1, NULL);
201 	mtx_init(&ucom_mtx, "UCOM MTX", NULL, MTX_DEF);
202 }
203 SYSINIT(ucom_init, SI_SUB_KLD - 1, SI_ORDER_ANY, ucom_init, NULL);
204 
205 static void
206 ucom_uninit(void *arg)
207 {
208 	struct unrhdr *hdr;
209 	hdr = ucom_unrhdr;
210 	ucom_unrhdr = NULL;
211 
212 	DPRINTF("\n");
213 
214 	if (hdr != NULL)
215 		delete_unrhdr(hdr);
216 
217 	mtx_destroy(&ucom_mtx);
218 }
219 SYSUNINIT(ucom_uninit, SI_SUB_KLD - 3, SI_ORDER_ANY, ucom_uninit, NULL);
220 
221 /*
222  * Mark a unit number (the X in cuaUX) as in use.
223  *
224  * Note that devices using a different naming scheme (see ucom_tty_name()
225  * callback) still use this unit allocation.
226  */
227 static int
228 ucom_unit_alloc(void)
229 {
230 	int unit;
231 
232 	/* sanity checks */
233 	if (ucom_unrhdr == NULL) {
234 		DPRINTF("ucom_unrhdr is NULL\n");
235 		return (-1);
236 	}
237 	unit = alloc_unr(ucom_unrhdr);
238 	DPRINTF("unit %d is allocated\n", unit);
239 	return (unit);
240 }
241 
242 /*
243  * Mark the unit number as not in use.
244  */
245 static void
246 ucom_unit_free(int unit)
247 {
248 	/* sanity checks */
249 	if (unit < 0 || unit >= UCOM_UNIT_MAX || ucom_unrhdr == NULL) {
250 		DPRINTF("cannot free unit number\n");
251 		return;
252 	}
253 	DPRINTF("unit %d is freed\n", unit);
254 	free_unr(ucom_unrhdr, unit);
255 }
256 
257 /*
258  * Setup a group of one or more serial ports.
259  *
260  * The mutex pointed to by "mtx" is applied before all
261  * callbacks are called back. Also "mtx" must be applied
262  * before calling into the ucom-layer!
263  */
264 int
265 ucom_attach(struct ucom_super_softc *ssc, struct ucom_softc *sc,
266     int subunits, void *parent,
267     const struct ucom_callback *callback, struct mtx *mtx)
268 {
269 	int subunit;
270 	int error = 0;
271 
272 	if ((sc == NULL) ||
273 	    (subunits <= 0) ||
274 	    (callback == NULL) ||
275 	    (mtx == NULL)) {
276 		return (EINVAL);
277 	}
278 
279 	/* allocate a uniq unit number */
280 	ssc->sc_unit = ucom_unit_alloc();
281 	if (ssc->sc_unit == -1)
282 		return (ENOMEM);
283 
284 	/* generate TTY name string */
285 	snprintf(ssc->sc_ttyname, sizeof(ssc->sc_ttyname),
286 	    UCOM_TTY_PREFIX "%d", ssc->sc_unit);
287 
288 	/* create USB request handling process */
289 	error = usb_proc_create(&ssc->sc_tq, mtx, "ucom", USB_PRI_MED);
290 	if (error) {
291 		ucom_unit_free(ssc->sc_unit);
292 		return (error);
293 	}
294 	ssc->sc_subunits = subunits;
295 	ssc->sc_flag = UCOM_FLAG_ATTACHED |
296 	    UCOM_FLAG_FREE_UNIT | (ssc->sc_flag & UCOM_FLAG_DEVICE_MODE);
297 
298 	if (callback->ucom_free == NULL)
299 		ssc->sc_flag |= UCOM_FLAG_WAIT_REFS;
300 
301 	/* increment reference count */
302 	ucom_ref(ssc);
303 
304 	for (subunit = 0; subunit < ssc->sc_subunits; subunit++) {
305 		sc[subunit].sc_subunit = subunit;
306 		sc[subunit].sc_super = ssc;
307 		sc[subunit].sc_mtx = mtx;
308 		sc[subunit].sc_parent = parent;
309 		sc[subunit].sc_callback = callback;
310 
311 		error = ucom_attach_tty(ssc, &sc[subunit]);
312 		if (error) {
313 			ucom_detach(ssc, &sc[0]);
314 			return (error);
315 		}
316 		/* increment reference count */
317 		ucom_ref(ssc);
318 
319 		/* set subunit attached */
320 		sc[subunit].sc_flag |= UCOM_FLAG_ATTACHED;
321 	}
322 
323 	DPRINTF("tp = %p, unit = %d, subunits = %d\n",
324 		sc->sc_tty, ssc->sc_unit, ssc->sc_subunits);
325 
326 	return (0);
327 }
328 
329 /*
330  * The following function will do nothing if the structure pointed to
331  * by "ssc" and "sc" is zero or has already been detached.
332  */
333 void
334 ucom_detach(struct ucom_super_softc *ssc, struct ucom_softc *sc)
335 {
336 	int subunit;
337 
338 	if (!(ssc->sc_flag & UCOM_FLAG_ATTACHED))
339 		return;		/* not initialized */
340 
341 	if (ssc->sc_sysctl_ttyname != NULL) {
342 		sysctl_remove_oid(ssc->sc_sysctl_ttyname, 1, 0);
343 		ssc->sc_sysctl_ttyname = NULL;
344 	}
345 
346 	if (ssc->sc_sysctl_ttyports != NULL) {
347 		sysctl_remove_oid(ssc->sc_sysctl_ttyports, 1, 0);
348 		ssc->sc_sysctl_ttyports = NULL;
349 	}
350 
351 	usb_proc_drain(&ssc->sc_tq);
352 
353 	for (subunit = 0; subunit < ssc->sc_subunits; subunit++) {
354 		if (sc[subunit].sc_flag & UCOM_FLAG_ATTACHED) {
355 			ucom_detach_tty(ssc, &sc[subunit]);
356 
357 			/* avoid duplicate detach */
358 			sc[subunit].sc_flag &= ~UCOM_FLAG_ATTACHED;
359 		}
360 	}
361 	usb_proc_free(&ssc->sc_tq);
362 
363 	ucom_unref(ssc);
364 
365 	if (ssc->sc_flag & UCOM_FLAG_WAIT_REFS)
366 		ucom_drain(ssc);
367 
368 	/* make sure we don't detach twice */
369 	ssc->sc_flag &= ~UCOM_FLAG_ATTACHED;
370 }
371 
372 void
373 ucom_drain(struct ucom_super_softc *ssc)
374 {
375 	mtx_lock(&ucom_mtx);
376 	while (ssc->sc_refs > 0) {
377 		printf("ucom: Waiting for a TTY device to close.\n");
378 		usb_pause_mtx(&ucom_mtx, hz);
379 	}
380 	mtx_unlock(&ucom_mtx);
381 }
382 
383 void
384 ucom_drain_all(void *arg)
385 {
386 	mtx_lock(&ucom_mtx);
387 	while (ucom_close_refs > 0) {
388 		printf("ucom: Waiting for all detached TTY "
389 		    "devices to have open fds closed.\n");
390 		usb_pause_mtx(&ucom_mtx, hz);
391 	}
392 	mtx_unlock(&ucom_mtx);
393 }
394 
395 static cn_probe_t ucom_cnprobe;
396 static cn_init_t ucom_cninit;
397 static cn_term_t ucom_cnterm;
398 static cn_getc_t ucom_cngetc;
399 static cn_putc_t ucom_cnputc;
400 static cn_grab_t ucom_cngrab;
401 static cn_ungrab_t ucom_cnungrab;
402 
403 const struct consdev_ops ucom_cnops = {
404         .cn_probe       = ucom_cnprobe,
405         .cn_init        = ucom_cninit,
406         .cn_term        = ucom_cnterm,
407         .cn_getc        = ucom_cngetc,
408         .cn_putc        = ucom_cnputc,
409         .cn_grab        = ucom_cngrab,
410         .cn_ungrab      = ucom_cnungrab,
411 };
412 
413 static int
414 ucom_attach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc)
415 {
416 	struct tty *tp;
417 	char buf[32];			/* temporary TTY device name buffer */
418 
419 	tp = tty_alloc_mutex(&ucom_class, sc, sc->sc_mtx);
420 	if (tp == NULL)
421 		return (ENOMEM);
422 
423 	/* Check if the client has a custom TTY name */
424 	buf[0] = '\0';
425 	if (sc->sc_callback->ucom_tty_name) {
426 		sc->sc_callback->ucom_tty_name(sc, buf,
427 		    sizeof(buf), ssc->sc_unit, sc->sc_subunit);
428 	}
429 	if (buf[0] == 0) {
430 		/* Use default TTY name */
431 		if (ssc->sc_subunits > 1) {
432 			/* multiple modems in one */
433 			snprintf(buf, sizeof(buf), UCOM_TTY_PREFIX "%u.%u",
434 			    ssc->sc_unit, sc->sc_subunit);
435 		} else {
436 			/* single modem */
437 			snprintf(buf, sizeof(buf), UCOM_TTY_PREFIX "%u",
438 			    ssc->sc_unit);
439 		}
440 	}
441 	tty_makedev(tp, NULL, "%s", buf);
442 
443 	sc->sc_tty = tp;
444 
445 	sc->sc_pps.ppscap = PPS_CAPTUREBOTH;
446 	sc->sc_pps.driver_abi = PPS_ABI_VERSION;
447 	sc->sc_pps.driver_mtx = sc->sc_mtx;
448 	pps_init_abi(&sc->sc_pps);
449 
450 	DPRINTF("ttycreate: %s\n", buf);
451 
452 	/* Check if this device should be a console */
453 	if ((ucom_cons_softc == NULL) &&
454 	    (ssc->sc_unit == ucom_cons_unit) &&
455 	    (sc->sc_subunit == ucom_cons_subunit)) {
456 		DPRINTF("unit %d subunit %d is console",
457 		    ssc->sc_unit, sc->sc_subunit);
458 
459 		ucom_cons_softc = sc;
460 
461 		tty_init_console(tp, ucom_cons_baud);
462 
463 		UCOM_MTX_LOCK(ucom_cons_softc);
464 		ucom_cons_rx_low = 0;
465 		ucom_cons_rx_high = 0;
466 		ucom_cons_tx_low = 0;
467 		ucom_cons_tx_high = 0;
468 		sc->sc_flag |= UCOM_FLAG_CONSOLE;
469 		ucom_open(ucom_cons_softc->sc_tty);
470 		ucom_param(ucom_cons_softc->sc_tty, &tp->t_termios_init_in);
471 		UCOM_MTX_UNLOCK(ucom_cons_softc);
472 	}
473 
474 	if ((ssc->sc_flag & UCOM_FLAG_DEVICE_MODE) != 0 &&
475 	    ucom_device_mode_console > 0 &&
476 	    ucom_cons_softc == NULL) {
477 		struct consdev *cp;
478 
479 		cp = malloc(sizeof(struct consdev), M_USBDEV,
480 		    M_WAITOK|M_ZERO);
481 		cp->cn_ops = &ucom_cnops;
482 		cp->cn_arg = NULL;
483 		cp->cn_pri = CN_NORMAL;
484 		strlcpy(cp->cn_name, "tty", sizeof(cp->cn_name));
485 		strlcat(cp->cn_name, buf, sizeof(cp->cn_name));
486 
487 		sc->sc_consdev = cp;
488 
489 		cnadd(cp);
490 	}
491 
492 	return (0);
493 }
494 
495 static void
496 ucom_detach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc)
497 {
498 	struct tty *tp = sc->sc_tty;
499 
500 	DPRINTF("sc = %p, tp = %p\n", sc, sc->sc_tty);
501 
502 	if (sc->sc_consdev != NULL) {
503 		cnremove(sc->sc_consdev);
504 		free(sc->sc_consdev, M_USBDEV);
505 		sc->sc_consdev = NULL;
506 	}
507 
508 	if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
509 		UCOM_MTX_LOCK(ucom_cons_softc);
510 		ucom_close(ucom_cons_softc->sc_tty);
511 		sc->sc_flag &= ~UCOM_FLAG_CONSOLE;
512 		UCOM_MTX_UNLOCK(ucom_cons_softc);
513 		ucom_cons_softc = NULL;
514 	}
515 
516 	/* the config thread has been stopped when we get here */
517 
518 	UCOM_MTX_LOCK(sc);
519 	sc->sc_flag |= UCOM_FLAG_GONE;
520 	sc->sc_flag &= ~(UCOM_FLAG_HL_READY | UCOM_FLAG_LL_READY);
521 	UCOM_MTX_UNLOCK(sc);
522 
523 	if (tp) {
524 		mtx_lock(&ucom_mtx);
525 		ucom_close_refs++;
526 		mtx_unlock(&ucom_mtx);
527 
528 		tty_lock(tp);
529 
530 		ucom_close(tp);	/* close, if any */
531 
532 		tty_rel_gone(tp);
533 
534 		UCOM_MTX_LOCK(sc);
535 		/*
536 		 * make sure that read and write transfers are stopped
537 		 */
538 		if (sc->sc_callback->ucom_stop_read)
539 			(sc->sc_callback->ucom_stop_read) (sc);
540 		if (sc->sc_callback->ucom_stop_write)
541 			(sc->sc_callback->ucom_stop_write) (sc);
542 		UCOM_MTX_UNLOCK(sc);
543 	}
544 }
545 
546 void
547 ucom_set_pnpinfo_usb(struct ucom_super_softc *ssc, device_t dev)
548 {
549 	char buf[64];
550 	uint8_t iface_index;
551 	struct usb_attach_arg *uaa;
552 
553 	snprintf(buf, sizeof(buf), "ttyname=" UCOM_TTY_PREFIX
554 	    "%d ttyports=%d", ssc->sc_unit, ssc->sc_subunits);
555 
556 	/* Store the PNP info in the first interface for the device */
557 	uaa = device_get_ivars(dev);
558 	iface_index = uaa->info.bIfaceIndex;
559 
560 	if (usbd_set_pnpinfo(uaa->device, iface_index, buf) != 0)
561 		device_printf(dev, "Could not set PNP info\n");
562 
563 	/*
564 	 * The following information is also replicated in the PNP-info
565 	 * string which is registered above:
566 	 */
567 	if (ssc->sc_sysctl_ttyname == NULL) {
568 		ssc->sc_sysctl_ttyname = SYSCTL_ADD_STRING(NULL,
569 		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
570 		    OID_AUTO, "ttyname", CTLFLAG_RD, ssc->sc_ttyname, 0,
571 		    "TTY device basename");
572 	}
573 	if (ssc->sc_sysctl_ttyports == NULL) {
574 		ssc->sc_sysctl_ttyports = SYSCTL_ADD_INT(NULL,
575 		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
576 		    OID_AUTO, "ttyports", CTLFLAG_RD,
577 		    NULL, ssc->sc_subunits, "Number of ports");
578 	}
579 }
580 
581 void
582 ucom_set_usb_mode(struct ucom_super_softc *ssc, enum usb_hc_mode usb_mode)
583 {
584 
585 	switch (usb_mode) {
586 	case USB_MODE_DEVICE:
587 		ssc->sc_flag |= UCOM_FLAG_DEVICE_MODE;
588 		break;
589 	default:
590 		ssc->sc_flag &= ~UCOM_FLAG_DEVICE_MODE;
591 		break;
592 	}
593 }
594 
595 static void
596 ucom_queue_command(struct ucom_softc *sc,
597     usb_proc_callback_t *fn, struct termios *pt,
598     struct usb_proc_msg *t0, struct usb_proc_msg *t1)
599 {
600 	struct ucom_super_softc *ssc = sc->sc_super;
601 	struct ucom_param_task *task;
602 
603 	UCOM_MTX_ASSERT(sc, MA_OWNED);
604 
605 	if (usb_proc_is_gone(&ssc->sc_tq)) {
606 		DPRINTF("proc is gone\n");
607 		return;         /* nothing to do */
608 	}
609 	/*
610 	 * NOTE: The task cannot get executed before we drop the
611 	 * "sc_mtx" mutex. It is safe to update fields in the message
612 	 * structure after that the message got queued.
613 	 */
614 	task = (struct ucom_param_task *)
615 	  usb_proc_msignal(&ssc->sc_tq, t0, t1);
616 
617 	/* Setup callback and softc pointers */
618 	task->hdr.pm_callback = fn;
619 	task->sc = sc;
620 
621 	/*
622 	 * Make a copy of the termios. This field is only present if
623 	 * the "pt" field is not NULL.
624 	 */
625 	if (pt != NULL)
626 		task->termios_copy = *pt;
627 
628 	/*
629 	 * Closing or opening the device should be synchronous.
630 	 */
631 	if (fn == ucom_cfg_close || fn == ucom_cfg_open)
632 		usb_proc_mwait(&ssc->sc_tq, t0, t1);
633 
634 	/*
635 	 * In case of multiple configure requests,
636 	 * keep track of the last one!
637 	 */
638 	if (fn == ucom_cfg_start_transfers)
639 		sc->sc_last_start_xfer = &task->hdr;
640 }
641 
642 static void
643 ucom_shutdown(struct ucom_softc *sc)
644 {
645 	struct tty *tp = sc->sc_tty;
646 
647 	UCOM_MTX_ASSERT(sc, MA_OWNED);
648 
649 	DPRINTF("\n");
650 
651 	/*
652 	 * Hang up if necessary:
653 	 */
654 	if (tp->t_termios.c_cflag & HUPCL) {
655 		ucom_modem(tp, 0, SER_DTR);
656 	}
657 }
658 
659 /*
660  * Return values:
661  *    0: normal
662  * else: taskqueue is draining or gone
663  */
664 uint8_t
665 ucom_cfg_is_gone(struct ucom_softc *sc)
666 {
667 	struct ucom_super_softc *ssc = sc->sc_super;
668 
669 	return (usb_proc_is_gone(&ssc->sc_tq));
670 }
671 
672 static void
673 ucom_cfg_start_transfers(struct usb_proc_msg *_task)
674 {
675 	struct ucom_cfg_task *task =
676 	    (struct ucom_cfg_task *)_task;
677 	struct ucom_softc *sc = task->sc;
678 
679 	if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
680 		return;
681 	}
682 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
683 		/* TTY device closed */
684 		return;
685 	}
686 
687 	if (_task == sc->sc_last_start_xfer)
688 		sc->sc_flag |= UCOM_FLAG_GP_DATA;
689 
690 	if (sc->sc_callback->ucom_start_read) {
691 		(sc->sc_callback->ucom_start_read) (sc);
692 	}
693 	if (sc->sc_callback->ucom_start_write) {
694 		(sc->sc_callback->ucom_start_write) (sc);
695 	}
696 }
697 
698 static void
699 ucom_start_transfers(struct ucom_softc *sc)
700 {
701 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
702 		return;
703 	}
704 	/*
705 	 * Make sure that data transfers are started in both
706 	 * directions:
707 	 */
708 	if (sc->sc_callback->ucom_start_read) {
709 		(sc->sc_callback->ucom_start_read) (sc);
710 	}
711 	if (sc->sc_callback->ucom_start_write) {
712 		(sc->sc_callback->ucom_start_write) (sc);
713 	}
714 }
715 
716 static void
717 ucom_cfg_open(struct usb_proc_msg *_task)
718 {
719 	struct ucom_cfg_task *task =
720 	    (struct ucom_cfg_task *)_task;
721 	struct ucom_softc *sc = task->sc;
722 
723 	DPRINTF("\n");
724 
725 	if (sc->sc_flag & UCOM_FLAG_LL_READY) {
726 		/* already opened */
727 
728 	} else {
729 		sc->sc_flag |= UCOM_FLAG_LL_READY;
730 
731 		if (sc->sc_callback->ucom_cfg_open) {
732 			(sc->sc_callback->ucom_cfg_open) (sc);
733 
734 			/* wait a little */
735 			usb_pause_mtx(sc->sc_mtx, hz / 10);
736 		}
737 	}
738 }
739 
740 static int
741 ucom_open(struct tty *tp)
742 {
743 	struct ucom_softc *sc = tty_softc(tp);
744 	int error;
745 
746 	UCOM_MTX_ASSERT(sc, MA_OWNED);
747 
748 	if (sc->sc_flag & UCOM_FLAG_GONE) {
749 		return (ENXIO);
750 	}
751 	if (sc->sc_flag & UCOM_FLAG_HL_READY) {
752 		/* already opened */
753 		return (0);
754 	}
755 	DPRINTF("tp = %p\n", tp);
756 
757 	if (sc->sc_callback->ucom_pre_open) {
758 		/*
759 		 * give the lower layer a chance to disallow TTY open, for
760 		 * example if the device is not present:
761 		 */
762 		error = (sc->sc_callback->ucom_pre_open) (sc);
763 		if (error) {
764 			return (error);
765 		}
766 	}
767 	sc->sc_flag |= UCOM_FLAG_HL_READY;
768 
769 	/* Disable transfers */
770 	sc->sc_flag &= ~UCOM_FLAG_GP_DATA;
771 
772 	sc->sc_lsr = 0;
773 	sc->sc_msr = 0;
774 	sc->sc_mcr = 0;
775 
776 	/* reset programmed line state */
777 	sc->sc_pls_curr = 0;
778 	sc->sc_pls_set = 0;
779 	sc->sc_pls_clr = 0;
780 
781 	/* reset jitter buffer */
782 	sc->sc_jitterbuf_in = 0;
783 	sc->sc_jitterbuf_out = 0;
784 
785 	ucom_queue_command(sc, ucom_cfg_open, NULL,
786 	    &sc->sc_open_task[0].hdr,
787 	    &sc->sc_open_task[1].hdr);
788 
789 	/* Queue transfer enable command last */
790 	ucom_queue_command(sc, ucom_cfg_start_transfers, NULL,
791 	    &sc->sc_start_task[0].hdr,
792 	    &sc->sc_start_task[1].hdr);
793 
794 	if (sc->sc_tty == NULL || (sc->sc_tty->t_termios.c_cflag & CNO_RTSDTR) == 0)
795 		ucom_modem(tp, SER_DTR | SER_RTS, 0);
796 
797 	ucom_ring(sc, 0);
798 
799 	ucom_break(sc, 0);
800 
801 	ucom_status_change(sc);
802 
803 	return (0);
804 }
805 
806 static void
807 ucom_cfg_close(struct usb_proc_msg *_task)
808 {
809 	struct ucom_cfg_task *task =
810 	    (struct ucom_cfg_task *)_task;
811 	struct ucom_softc *sc = task->sc;
812 
813 	DPRINTF("\n");
814 
815 	if (sc->sc_flag & UCOM_FLAG_LL_READY) {
816 		sc->sc_flag &= ~UCOM_FLAG_LL_READY;
817 		if (sc->sc_callback->ucom_cfg_close)
818 			(sc->sc_callback->ucom_cfg_close) (sc);
819 	} else {
820 		/* already closed */
821 	}
822 }
823 
824 static void
825 ucom_close(struct tty *tp)
826 {
827 	struct ucom_softc *sc = tty_softc(tp);
828 
829 	UCOM_MTX_ASSERT(sc, MA_OWNED);
830 
831 	DPRINTF("tp=%p\n", tp);
832 
833 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
834 		DPRINTF("tp=%p already closed\n", tp);
835 		return;
836 	}
837 	ucom_shutdown(sc);
838 
839 	ucom_queue_command(sc, ucom_cfg_close, NULL,
840 	    &sc->sc_close_task[0].hdr,
841 	    &sc->sc_close_task[1].hdr);
842 
843 	sc->sc_flag &= ~(UCOM_FLAG_HL_READY | UCOM_FLAG_RTS_IFLOW);
844 
845 	if (sc->sc_callback->ucom_stop_read) {
846 		(sc->sc_callback->ucom_stop_read) (sc);
847 	}
848 }
849 
850 static void
851 ucom_inwakeup(struct tty *tp)
852 {
853 	struct ucom_softc *sc = tty_softc(tp);
854 	uint16_t pos;
855 
856 	if (sc == NULL)
857 		return;
858 
859 	UCOM_MTX_ASSERT(sc, MA_OWNED);
860 
861 	DPRINTF("tp=%p\n", tp);
862 
863 	if (ttydisc_can_bypass(tp) != 0 ||
864 	    (sc->sc_flag & UCOM_FLAG_HL_READY) == 0 ||
865 	    (sc->sc_flag & UCOM_FLAG_INWAKEUP) != 0) {
866 		return;
867 	}
868 
869 	/* prevent recursion */
870 	sc->sc_flag |= UCOM_FLAG_INWAKEUP;
871 
872 	pos = sc->sc_jitterbuf_out;
873 
874 	while (sc->sc_jitterbuf_in != pos) {
875 		int c;
876 
877 		c = (char)sc->sc_jitterbuf[pos];
878 
879 		if (ttydisc_rint(tp, c, 0) == -1)
880 			break;
881 		pos++;
882 		if (pos >= UCOM_JITTERBUF_SIZE)
883 			pos -= UCOM_JITTERBUF_SIZE;
884 	}
885 
886 	sc->sc_jitterbuf_out = pos;
887 
888 	/* clear RTS in async fashion */
889 	if ((sc->sc_jitterbuf_in == pos) &&
890 	    (sc->sc_flag & UCOM_FLAG_RTS_IFLOW))
891 		ucom_rts(sc, 0);
892 
893 	sc->sc_flag &= ~UCOM_FLAG_INWAKEUP;
894 }
895 
896 static int
897 ucom_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
898 {
899 	struct ucom_softc *sc = tty_softc(tp);
900 	int error;
901 
902 	UCOM_MTX_ASSERT(sc, MA_OWNED);
903 
904 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
905 		return (EIO);
906 	}
907 	DPRINTF("cmd = 0x%08lx\n", cmd);
908 
909 	switch (cmd) {
910 #if 0
911 	case TIOCSRING:
912 		ucom_ring(sc, 1);
913 		error = 0;
914 		break;
915 	case TIOCCRING:
916 		ucom_ring(sc, 0);
917 		error = 0;
918 		break;
919 #endif
920 	case TIOCSBRK:
921 		ucom_break(sc, 1);
922 		error = 0;
923 		break;
924 	case TIOCCBRK:
925 		ucom_break(sc, 0);
926 		error = 0;
927 		break;
928 	default:
929 		if (sc->sc_callback->ucom_ioctl) {
930 			error = (sc->sc_callback->ucom_ioctl)
931 			    (sc, cmd, data, 0, td);
932 		} else {
933 			error = ENOIOCTL;
934 		}
935 		if (error == ENOIOCTL)
936 			error = pps_ioctl(cmd, data, &sc->sc_pps);
937 		break;
938 	}
939 	return (error);
940 }
941 
942 static int
943 ucom_modem(struct tty *tp, int sigon, int sigoff)
944 {
945 	struct ucom_softc *sc = tty_softc(tp);
946 	uint8_t onoff;
947 
948 	UCOM_MTX_ASSERT(sc, MA_OWNED);
949 
950 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
951 		return (0);
952 	}
953 	if ((sigon == 0) && (sigoff == 0)) {
954 		if (sc->sc_mcr & SER_DTR) {
955 			sigon |= SER_DTR;
956 		}
957 		if (sc->sc_mcr & SER_RTS) {
958 			sigon |= SER_RTS;
959 		}
960 		if (sc->sc_msr & SER_CTS) {
961 			sigon |= SER_CTS;
962 		}
963 		if (sc->sc_msr & SER_DCD) {
964 			sigon |= SER_DCD;
965 		}
966 		if (sc->sc_msr & SER_DSR) {
967 			sigon |= SER_DSR;
968 		}
969 		if (sc->sc_msr & SER_RI) {
970 			sigon |= SER_RI;
971 		}
972 		return (sigon);
973 	}
974 	if (sigon & SER_DTR) {
975 		sc->sc_mcr |= SER_DTR;
976 	}
977 	if (sigoff & SER_DTR) {
978 		sc->sc_mcr &= ~SER_DTR;
979 	}
980 	if (sigon & SER_RTS) {
981 		sc->sc_mcr |= SER_RTS;
982 	}
983 	if (sigoff & SER_RTS) {
984 		sc->sc_mcr &= ~SER_RTS;
985 	}
986 	onoff = (sc->sc_mcr & SER_DTR) ? 1 : 0;
987 	ucom_dtr(sc, onoff);
988 
989 	onoff = (sc->sc_mcr & SER_RTS) ? 1 : 0;
990 	ucom_rts(sc, onoff);
991 
992 	return (0);
993 }
994 
995 static void
996 ucom_cfg_line_state(struct usb_proc_msg *_task)
997 {
998 	struct ucom_cfg_task *task =
999 	    (struct ucom_cfg_task *)_task;
1000 	struct ucom_softc *sc = task->sc;
1001 	uint8_t notch_bits;
1002 	uint8_t any_bits;
1003 	uint8_t prev_value;
1004 	uint8_t last_value;
1005 	uint8_t mask;
1006 
1007 	if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
1008 		return;
1009 	}
1010 
1011 	mask = 0;
1012 	/* compute callback mask */
1013 	if (sc->sc_callback->ucom_cfg_set_dtr)
1014 		mask |= UCOM_LS_DTR;
1015 	if (sc->sc_callback->ucom_cfg_set_rts)
1016 		mask |= UCOM_LS_RTS;
1017 	if (sc->sc_callback->ucom_cfg_set_break)
1018 		mask |= UCOM_LS_BREAK;
1019 	if (sc->sc_callback->ucom_cfg_set_ring)
1020 		mask |= UCOM_LS_RING;
1021 
1022 	/* compute the bits we are to program */
1023 	notch_bits = (sc->sc_pls_set & sc->sc_pls_clr) & mask;
1024 	any_bits = (sc->sc_pls_set | sc->sc_pls_clr) & mask;
1025 	prev_value = sc->sc_pls_curr ^ notch_bits;
1026 	last_value = sc->sc_pls_curr;
1027 
1028 	/* reset programmed line state */
1029 	sc->sc_pls_curr = 0;
1030 	sc->sc_pls_set = 0;
1031 	sc->sc_pls_clr = 0;
1032 
1033 	/* ensure that we don't lose any levels */
1034 	if (notch_bits & UCOM_LS_DTR)
1035 		sc->sc_callback->ucom_cfg_set_dtr(sc,
1036 		    (prev_value & UCOM_LS_DTR) ? 1 : 0);
1037 	if (notch_bits & UCOM_LS_RTS)
1038 		sc->sc_callback->ucom_cfg_set_rts(sc,
1039 		    (prev_value & UCOM_LS_RTS) ? 1 : 0);
1040 	if (notch_bits & UCOM_LS_BREAK)
1041 		sc->sc_callback->ucom_cfg_set_break(sc,
1042 		    (prev_value & UCOM_LS_BREAK) ? 1 : 0);
1043 	if (notch_bits & UCOM_LS_RING)
1044 		sc->sc_callback->ucom_cfg_set_ring(sc,
1045 		    (prev_value & UCOM_LS_RING) ? 1 : 0);
1046 
1047 	/* set last value */
1048 	if (any_bits & UCOM_LS_DTR)
1049 		sc->sc_callback->ucom_cfg_set_dtr(sc,
1050 		    (last_value & UCOM_LS_DTR) ? 1 : 0);
1051 	if (any_bits & UCOM_LS_RTS)
1052 		sc->sc_callback->ucom_cfg_set_rts(sc,
1053 		    (last_value & UCOM_LS_RTS) ? 1 : 0);
1054 	if (any_bits & UCOM_LS_BREAK)
1055 		sc->sc_callback->ucom_cfg_set_break(sc,
1056 		    (last_value & UCOM_LS_BREAK) ? 1 : 0);
1057 	if (any_bits & UCOM_LS_RING)
1058 		sc->sc_callback->ucom_cfg_set_ring(sc,
1059 		    (last_value & UCOM_LS_RING) ? 1 : 0);
1060 }
1061 
1062 static void
1063 ucom_line_state(struct ucom_softc *sc,
1064     uint8_t set_bits, uint8_t clear_bits)
1065 {
1066 	UCOM_MTX_ASSERT(sc, MA_OWNED);
1067 
1068 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1069 		return;
1070 	}
1071 
1072 	DPRINTF("on=0x%02x, off=0x%02x\n", set_bits, clear_bits);
1073 
1074 	/* update current programmed line state */
1075 	sc->sc_pls_curr |= set_bits;
1076 	sc->sc_pls_curr &= ~clear_bits;
1077 	sc->sc_pls_set |= set_bits;
1078 	sc->sc_pls_clr |= clear_bits;
1079 
1080 	/* defer driver programming */
1081 	ucom_queue_command(sc, ucom_cfg_line_state, NULL,
1082 	    &sc->sc_line_state_task[0].hdr,
1083 	    &sc->sc_line_state_task[1].hdr);
1084 }
1085 
1086 static void
1087 ucom_ring(struct ucom_softc *sc, uint8_t onoff)
1088 {
1089 	DPRINTF("onoff = %d\n", onoff);
1090 
1091 	if (onoff)
1092 		ucom_line_state(sc, UCOM_LS_RING, 0);
1093 	else
1094 		ucom_line_state(sc, 0, UCOM_LS_RING);
1095 }
1096 
1097 static void
1098 ucom_break(struct ucom_softc *sc, uint8_t onoff)
1099 {
1100 	DPRINTF("onoff = %d\n", onoff);
1101 
1102 	if (onoff)
1103 		ucom_line_state(sc, UCOM_LS_BREAK, 0);
1104 	else
1105 		ucom_line_state(sc, 0, UCOM_LS_BREAK);
1106 }
1107 
1108 static void
1109 ucom_dtr(struct ucom_softc *sc, uint8_t onoff)
1110 {
1111 	DPRINTF("onoff = %d\n", onoff);
1112 
1113 	if (onoff)
1114 		ucom_line_state(sc, UCOM_LS_DTR, 0);
1115 	else
1116 		ucom_line_state(sc, 0, UCOM_LS_DTR);
1117 }
1118 
1119 static void
1120 ucom_rts(struct ucom_softc *sc, uint8_t onoff)
1121 {
1122 	DPRINTF("onoff = %d\n", onoff);
1123 
1124 	if (onoff)
1125 		ucom_line_state(sc, UCOM_LS_RTS, 0);
1126 	else
1127 		ucom_line_state(sc, 0, UCOM_LS_RTS);
1128 }
1129 
1130 static void
1131 ucom_cfg_status_change(struct usb_proc_msg *_task)
1132 {
1133 	struct ucom_cfg_task *task =
1134 	    (struct ucom_cfg_task *)_task;
1135 	struct ucom_softc *sc = task->sc;
1136 	struct tty *tp;
1137 	int onoff;
1138 	uint8_t new_msr;
1139 	uint8_t new_lsr;
1140 	uint8_t msr_delta;
1141 	uint8_t lsr_delta;
1142 	uint8_t pps_signal;
1143 
1144 	tp = sc->sc_tty;
1145 
1146 	UCOM_MTX_ASSERT(sc, MA_OWNED);
1147 
1148 	if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
1149 		return;
1150 	}
1151 	if (sc->sc_callback->ucom_cfg_get_status == NULL) {
1152 		return;
1153 	}
1154 	/* get status */
1155 
1156 	new_msr = 0;
1157 	new_lsr = 0;
1158 
1159 	(sc->sc_callback->ucom_cfg_get_status) (sc, &new_lsr, &new_msr);
1160 
1161 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1162 		/* TTY device closed */
1163 		return;
1164 	}
1165 	msr_delta = (sc->sc_msr ^ new_msr);
1166 	lsr_delta = (sc->sc_lsr ^ new_lsr);
1167 
1168 	sc->sc_msr = new_msr;
1169 	sc->sc_lsr = new_lsr;
1170 
1171 	/*
1172 	 * Time pulse counting support.
1173 	 */
1174 	switch(ucom_pps_mode & UART_PPS_SIGNAL_MASK) {
1175 	case UART_PPS_CTS:
1176 		pps_signal = SER_CTS;
1177 		break;
1178 	case UART_PPS_DCD:
1179 		pps_signal = SER_DCD;
1180 		break;
1181 	default:
1182 		pps_signal = 0;
1183 		break;
1184 	}
1185 
1186 	if ((sc->sc_pps.ppsparam.mode & PPS_CAPTUREBOTH) &&
1187 	    (msr_delta & pps_signal)) {
1188 		pps_capture(&sc->sc_pps);
1189 		onoff = (sc->sc_msr & pps_signal) ? 1 : 0;
1190 		if (ucom_pps_mode & UART_PPS_INVERT_PULSE)
1191 			onoff = !onoff;
1192 		pps_event(&sc->sc_pps, onoff ? PPS_CAPTUREASSERT :
1193 		    PPS_CAPTURECLEAR);
1194 	}
1195 
1196 	if (msr_delta & SER_DCD) {
1197 		onoff = (sc->sc_msr & SER_DCD) ? 1 : 0;
1198 
1199 		DPRINTF("DCD changed to %d\n", onoff);
1200 
1201 		ttydisc_modem(tp, onoff);
1202 	}
1203 
1204 	if ((lsr_delta & ULSR_BI) && (sc->sc_lsr & ULSR_BI)) {
1205 		DPRINTF("BREAK detected\n");
1206 
1207 		ttydisc_rint(tp, 0, TRE_BREAK);
1208 		ttydisc_rint_done(tp);
1209 	}
1210 
1211 	if ((lsr_delta & ULSR_FE) && (sc->sc_lsr & ULSR_FE)) {
1212 		DPRINTF("Frame error detected\n");
1213 
1214 		ttydisc_rint(tp, 0, TRE_FRAMING);
1215 		ttydisc_rint_done(tp);
1216 	}
1217 
1218 	if ((lsr_delta & ULSR_PE) && (sc->sc_lsr & ULSR_PE)) {
1219 		DPRINTF("Parity error detected\n");
1220 
1221 		ttydisc_rint(tp, 0, TRE_PARITY);
1222 		ttydisc_rint_done(tp);
1223 	}
1224 }
1225 
1226 void
1227 ucom_status_change(struct ucom_softc *sc)
1228 {
1229 	UCOM_MTX_ASSERT(sc, MA_OWNED);
1230 
1231 	if (sc->sc_flag & UCOM_FLAG_CONSOLE)
1232 		return;		/* not supported */
1233 
1234 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1235 		return;
1236 	}
1237 	DPRINTF("\n");
1238 
1239 	ucom_queue_command(sc, ucom_cfg_status_change, NULL,
1240 	    &sc->sc_status_task[0].hdr,
1241 	    &sc->sc_status_task[1].hdr);
1242 }
1243 
1244 static void
1245 ucom_cfg_param(struct usb_proc_msg *_task)
1246 {
1247 	struct ucom_param_task *task =
1248 	    (struct ucom_param_task *)_task;
1249 	struct ucom_softc *sc = task->sc;
1250 
1251 	if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
1252 		return;
1253 	}
1254 	if (sc->sc_callback->ucom_cfg_param == NULL) {
1255 		return;
1256 	}
1257 
1258 	(sc->sc_callback->ucom_cfg_param) (sc, &task->termios_copy);
1259 
1260 	/* wait a little */
1261 	usb_pause_mtx(sc->sc_mtx, hz / 10);
1262 }
1263 
1264 static int
1265 ucom_param(struct tty *tp, struct termios *t)
1266 {
1267 	struct ucom_softc *sc = tty_softc(tp);
1268 	uint8_t opened;
1269 	int error;
1270 
1271 	UCOM_MTX_ASSERT(sc, MA_OWNED);
1272 
1273 	opened = 0;
1274 	error = 0;
1275 
1276 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1277 		/* XXX the TTY layer should call "open()" first! */
1278 		/*
1279 		 * Not quite: Its ordering is partly backwards, but
1280 		 * some parameters must be set early in ttydev_open(),
1281 		 * possibly before calling ttydevsw_open().
1282 		 */
1283 		error = ucom_open(tp);
1284 		if (error)
1285 			goto done;
1286 
1287 		opened = 1;
1288 	}
1289 	DPRINTF("sc = %p\n", sc);
1290 
1291 	/* Check requested parameters. */
1292 	if (t->c_ispeed && (t->c_ispeed != t->c_ospeed)) {
1293 		/* XXX c_ospeed == 0 is perfectly valid. */
1294 		DPRINTF("mismatch ispeed and ospeed\n");
1295 		error = EINVAL;
1296 		goto done;
1297 	}
1298 	t->c_ispeed = t->c_ospeed;
1299 
1300 	if (sc->sc_callback->ucom_pre_param) {
1301 		/* Let the lower layer verify the parameters */
1302 		error = (sc->sc_callback->ucom_pre_param) (sc, t);
1303 		if (error) {
1304 			DPRINTF("callback error = %d\n", error);
1305 			goto done;
1306 		}
1307 	}
1308 
1309 	/* Disable transfers */
1310 	sc->sc_flag &= ~UCOM_FLAG_GP_DATA;
1311 
1312 	/* Queue baud rate programming command first */
1313 	ucom_queue_command(sc, ucom_cfg_param, t,
1314 	    &sc->sc_param_task[0].hdr,
1315 	    &sc->sc_param_task[1].hdr);
1316 
1317 	/* Queue transfer enable command last */
1318 	ucom_queue_command(sc, ucom_cfg_start_transfers, NULL,
1319 	    &sc->sc_start_task[0].hdr,
1320 	    &sc->sc_start_task[1].hdr);
1321 
1322 	if (t->c_cflag & CRTS_IFLOW) {
1323 		sc->sc_flag |= UCOM_FLAG_RTS_IFLOW;
1324 	} else if (sc->sc_flag & UCOM_FLAG_RTS_IFLOW) {
1325 		sc->sc_flag &= ~UCOM_FLAG_RTS_IFLOW;
1326 		ucom_modem(tp, SER_RTS, 0);
1327 	}
1328 done:
1329 	if (error) {
1330 		if (opened) {
1331 			ucom_close(tp);
1332 		}
1333 	}
1334 	return (error);
1335 }
1336 
1337 static void
1338 ucom_outwakeup(struct tty *tp)
1339 {
1340 	struct ucom_softc *sc = tty_softc(tp);
1341 
1342 	UCOM_MTX_ASSERT(sc, MA_OWNED);
1343 
1344 	DPRINTF("sc = %p\n", sc);
1345 
1346 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1347 		/* The higher layer is not ready */
1348 		return;
1349 	}
1350 	ucom_start_transfers(sc);
1351 }
1352 
1353 static bool
1354 ucom_busy(struct tty *tp)
1355 {
1356 	struct ucom_softc *sc = tty_softc(tp);
1357 	const uint8_t txidle = ULSR_TXRDY | ULSR_TSRE;
1358 
1359 	UCOM_MTX_ASSERT(sc, MA_OWNED);
1360 
1361 	DPRINTFN(3, "sc = %p lsr 0x%02x\n", sc, sc->sc_lsr);
1362 
1363 	/*
1364 	 * If the driver maintains the txidle bits in LSR, we can use them to
1365 	 * determine whether the transmitter is busy or idle.  Otherwise we have
1366 	 * to assume it is idle to avoid hanging forever on tcdrain(3).
1367 	 */
1368 	if (sc->sc_flag & UCOM_FLAG_LSRTXIDLE)
1369 		return ((sc->sc_lsr & txidle) != txidle);
1370 	else
1371 		return (false);
1372 }
1373 
1374 /*------------------------------------------------------------------------*
1375  *	ucom_get_data
1376  *
1377  * Return values:
1378  * 0: No data is available.
1379  * Else: Data is available.
1380  *------------------------------------------------------------------------*/
1381 uint8_t
1382 ucom_get_data(struct ucom_softc *sc, struct usb_page_cache *pc,
1383     uint32_t offset, uint32_t len, uint32_t *actlen)
1384 {
1385 	struct usb_page_search res;
1386 	struct tty *tp = sc->sc_tty;
1387 	uint32_t cnt;
1388 	uint32_t offset_orig;
1389 
1390 	UCOM_MTX_ASSERT(sc, MA_OWNED);
1391 
1392 	if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
1393 		unsigned temp;
1394 
1395 		/* get total TX length */
1396 
1397 		temp = ucom_cons_tx_high - ucom_cons_tx_low;
1398 		temp %= UCOM_CONS_BUFSIZE;
1399 
1400 		/* limit TX length */
1401 
1402 		if (temp > (UCOM_CONS_BUFSIZE - ucom_cons_tx_low))
1403 			temp = (UCOM_CONS_BUFSIZE - ucom_cons_tx_low);
1404 
1405 		if (temp > len)
1406 			temp = len;
1407 
1408 		/* copy in data */
1409 
1410 		usbd_copy_in(pc, offset, ucom_cons_tx_buf + ucom_cons_tx_low, temp);
1411 
1412 		/* update counters */
1413 
1414 		ucom_cons_tx_low += temp;
1415 		ucom_cons_tx_low %= UCOM_CONS_BUFSIZE;
1416 
1417 		/* store actual length */
1418 
1419 		*actlen = temp;
1420 
1421 		return (temp ? 1 : 0);
1422 	}
1423 
1424 	if (tty_gone(tp) ||
1425 	    !(sc->sc_flag & UCOM_FLAG_GP_DATA)) {
1426 		actlen[0] = 0;
1427 		return (0);		/* multiport device polling */
1428 	}
1429 	offset_orig = offset;
1430 
1431 	while (len != 0) {
1432 		usbd_get_page(pc, offset, &res);
1433 
1434 		if (res.length > len) {
1435 			res.length = len;
1436 		}
1437 		/* copy data directly into USB buffer */
1438 		cnt = ttydisc_getc(tp, res.buffer, res.length);
1439 
1440 		offset += cnt;
1441 		len -= cnt;
1442 
1443 		if (cnt < res.length) {
1444 			/* end of buffer */
1445 			break;
1446 		}
1447 	}
1448 
1449 	actlen[0] = offset - offset_orig;
1450 
1451 	DPRINTF("cnt=%d\n", actlen[0]);
1452 
1453 	if (actlen[0] == 0) {
1454 		return (0);
1455 	}
1456 	return (1);
1457 }
1458 
1459 void
1460 ucom_put_data(struct ucom_softc *sc, struct usb_page_cache *pc,
1461     uint32_t offset, uint32_t len)
1462 {
1463 	struct usb_page_search res;
1464 	struct tty *tp = sc->sc_tty;
1465 	char *buf;
1466 	uint32_t cnt;
1467 
1468 	UCOM_MTX_ASSERT(sc, MA_OWNED);
1469 
1470 	if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
1471 		unsigned temp;
1472 
1473 		/* get maximum RX length */
1474 
1475 		temp = (UCOM_CONS_BUFSIZE - 1) - ucom_cons_rx_high + ucom_cons_rx_low;
1476 		temp %= UCOM_CONS_BUFSIZE;
1477 
1478 		/* limit RX length */
1479 
1480 		if (temp > (UCOM_CONS_BUFSIZE - ucom_cons_rx_high))
1481 			temp = (UCOM_CONS_BUFSIZE - ucom_cons_rx_high);
1482 
1483 		if (temp > len)
1484 			temp = len;
1485 
1486 		/* copy out data */
1487 
1488 		usbd_copy_out(pc, offset, ucom_cons_rx_buf + ucom_cons_rx_high, temp);
1489 
1490 		/* update counters */
1491 
1492 		ucom_cons_rx_high += temp;
1493 		ucom_cons_rx_high %= UCOM_CONS_BUFSIZE;
1494 
1495 		return;
1496 	}
1497 
1498 	if (tty_gone(tp))
1499 		return;			/* multiport device polling */
1500 
1501 	if (len == 0)
1502 		return;			/* no data */
1503 
1504 	/* set a flag to prevent recursation ? */
1505 
1506 	while (len > 0) {
1507 		usbd_get_page(pc, offset, &res);
1508 
1509 		if (res.length > len) {
1510 			res.length = len;
1511 		}
1512 		len -= res.length;
1513 		offset += res.length;
1514 
1515 		/* pass characters to tty layer */
1516 
1517 		buf = res.buffer;
1518 		cnt = res.length;
1519 
1520 		/* first check if we can pass the buffer directly */
1521 
1522 		if (ttydisc_can_bypass(tp)) {
1523 			/* clear any jitter buffer */
1524 			sc->sc_jitterbuf_in = 0;
1525 			sc->sc_jitterbuf_out = 0;
1526 
1527 			if (ttydisc_rint_bypass(tp, buf, cnt) != cnt) {
1528 				DPRINTF("tp=%p, data lost\n", tp);
1529 			}
1530 			continue;
1531 		}
1532 		/* need to loop */
1533 
1534 		for (cnt = 0; cnt != res.length; cnt++) {
1535 			if (sc->sc_jitterbuf_in != sc->sc_jitterbuf_out ||
1536 			    ttydisc_rint(tp, buf[cnt], 0) == -1) {
1537 				uint16_t end;
1538 				uint16_t pos;
1539 
1540 				pos = sc->sc_jitterbuf_in;
1541 				end = sc->sc_jitterbuf_out +
1542 				    UCOM_JITTERBUF_SIZE - 1;
1543 				if (end >= UCOM_JITTERBUF_SIZE)
1544 					end -= UCOM_JITTERBUF_SIZE;
1545 
1546 				for (; cnt != res.length; cnt++) {
1547 					if (pos == end)
1548 						break;
1549 					sc->sc_jitterbuf[pos] = buf[cnt];
1550 					pos++;
1551 					if (pos >= UCOM_JITTERBUF_SIZE)
1552 						pos -= UCOM_JITTERBUF_SIZE;
1553 				}
1554 
1555 				sc->sc_jitterbuf_in = pos;
1556 
1557 				/* set RTS in async fashion */
1558 				if (sc->sc_flag & UCOM_FLAG_RTS_IFLOW)
1559 					ucom_rts(sc, 1);
1560 
1561 				DPRINTF("tp=%p, lost %d "
1562 				    "chars\n", tp, res.length - cnt);
1563 				break;
1564 			}
1565 		}
1566 	}
1567 	ttydisc_rint_done(tp);
1568 }
1569 
1570 static void
1571 ucom_free(void *xsc)
1572 {
1573 	struct ucom_softc *sc = xsc;
1574 
1575 	if (sc->sc_callback->ucom_free != NULL)
1576 		sc->sc_callback->ucom_free(sc);
1577 	else
1578 		ucom_unref(sc->sc_super);
1579 
1580 	mtx_lock(&ucom_mtx);
1581 	ucom_close_refs--;
1582 	mtx_unlock(&ucom_mtx);
1583 }
1584 
1585 CONSOLE_DRIVER(ucom);
1586 
1587 static void
1588 ucom_cnprobe(struct consdev  *cp)
1589 {
1590 	if (ucom_cons_unit != -1)
1591 		cp->cn_pri = CN_NORMAL;
1592 	else
1593 		cp->cn_pri = CN_DEAD;
1594 
1595 	strlcpy(cp->cn_name, "ucom", sizeof(cp->cn_name));
1596 }
1597 
1598 static void
1599 ucom_cninit(struct consdev  *cp)
1600 {
1601 }
1602 
1603 static void
1604 ucom_cnterm(struct consdev  *cp)
1605 {
1606 }
1607 
1608 static void
1609 ucom_cngrab(struct consdev *cp)
1610 {
1611 }
1612 
1613 static void
1614 ucom_cnungrab(struct consdev *cp)
1615 {
1616 }
1617 
1618 static int
1619 ucom_cngetc(struct consdev *cd)
1620 {
1621 	struct ucom_softc *sc = ucom_cons_softc;
1622 	int c;
1623 
1624 	if (sc == NULL)
1625 		return (-1);
1626 
1627 	UCOM_MTX_LOCK(sc);
1628 
1629 	if (ucom_cons_rx_low != ucom_cons_rx_high) {
1630 		c = ucom_cons_rx_buf[ucom_cons_rx_low];
1631 		ucom_cons_rx_low ++;
1632 		ucom_cons_rx_low %= UCOM_CONS_BUFSIZE;
1633 	} else {
1634 		c = -1;
1635 	}
1636 
1637 	/* start USB transfers */
1638 	ucom_outwakeup(sc->sc_tty);
1639 
1640 	UCOM_MTX_UNLOCK(sc);
1641 
1642 	/* poll if necessary */
1643 	if (USB_IN_POLLING_MODE_FUNC() && sc->sc_callback->ucom_poll)
1644 		(sc->sc_callback->ucom_poll) (sc);
1645 
1646 	return (c);
1647 }
1648 
1649 static void
1650 ucom_cnputc(struct consdev *cd, int c)
1651 {
1652 	struct ucom_softc *sc = ucom_cons_softc;
1653 	unsigned temp;
1654 
1655 	if (sc == NULL)
1656 		return;
1657 
1658  repeat:
1659 
1660 	UCOM_MTX_LOCK(sc);
1661 
1662 	/* compute maximum TX length */
1663 
1664 	temp = (UCOM_CONS_BUFSIZE - 1) - ucom_cons_tx_high + ucom_cons_tx_low;
1665 	temp %= UCOM_CONS_BUFSIZE;
1666 
1667 	if (temp) {
1668 		ucom_cons_tx_buf[ucom_cons_tx_high] = c;
1669 		ucom_cons_tx_high ++;
1670 		ucom_cons_tx_high %= UCOM_CONS_BUFSIZE;
1671 	}
1672 
1673 	/* start USB transfers */
1674 	ucom_outwakeup(sc->sc_tty);
1675 
1676 	UCOM_MTX_UNLOCK(sc);
1677 
1678 	/* poll if necessary */
1679 	if (USB_IN_POLLING_MODE_FUNC() && sc->sc_callback->ucom_poll) {
1680 		(sc->sc_callback->ucom_poll) (sc);
1681 		/* simple flow control */
1682 		if (temp == 0)
1683 			goto repeat;
1684 	}
1685 }
1686 
1687 /*------------------------------------------------------------------------*
1688  *	ucom_ref
1689  *
1690  * This function will increment the super UCOM reference count.
1691  *------------------------------------------------------------------------*/
1692 void
1693 ucom_ref(struct ucom_super_softc *ssc)
1694 {
1695 	mtx_lock(&ucom_mtx);
1696 	ssc->sc_refs++;
1697 	mtx_unlock(&ucom_mtx);
1698 }
1699 
1700 /*------------------------------------------------------------------------*
1701  *	ucom_free_unit
1702  *
1703  * This function will free the super UCOM's allocated unit
1704  * number. This function can be called on a zero-initialized
1705  * structure. This function can be called multiple times.
1706  *------------------------------------------------------------------------*/
1707 static void
1708 ucom_free_unit(struct ucom_super_softc *ssc)
1709 {
1710 	if (!(ssc->sc_flag & UCOM_FLAG_FREE_UNIT))
1711 		return;
1712 
1713 	ucom_unit_free(ssc->sc_unit);
1714 
1715 	ssc->sc_flag &= ~UCOM_FLAG_FREE_UNIT;
1716 }
1717 
1718 /*------------------------------------------------------------------------*
1719  *	ucom_unref
1720  *
1721  * This function will decrement the super UCOM reference count.
1722  *
1723  * Return values:
1724  * 0: UCOM structures are still referenced.
1725  * Else: UCOM structures are no longer referenced.
1726  *------------------------------------------------------------------------*/
1727 int
1728 ucom_unref(struct ucom_super_softc *ssc)
1729 {
1730 	int retval;
1731 
1732 	mtx_lock(&ucom_mtx);
1733 	retval = (ssc->sc_refs < 2);
1734 	ssc->sc_refs--;
1735 	mtx_unlock(&ucom_mtx);
1736 
1737 	if (retval)
1738 		ucom_free_unit(ssc);
1739 
1740 	return (retval);
1741 }
1742 
1743 #if defined(GDB)
1744 
1745 #include <gdb/gdb.h>
1746 
1747 static gdb_probe_f ucom_gdbprobe;
1748 static gdb_init_f ucom_gdbinit;
1749 static gdb_term_f ucom_gdbterm;
1750 static gdb_getc_f ucom_gdbgetc;
1751 static gdb_putc_f ucom_gdbputc;
1752 
1753 GDB_DBGPORT(ucom, ucom_gdbprobe, ucom_gdbinit, ucom_gdbterm, ucom_gdbgetc, ucom_gdbputc);
1754 
1755 static int
1756 ucom_gdbprobe(void)
1757 {
1758 	return ((ucom_cons_softc != NULL) ? 0 : -1);
1759 }
1760 
1761 static void
1762 ucom_gdbinit(void)
1763 {
1764 }
1765 
1766 static void
1767 ucom_gdbterm(void)
1768 {
1769 }
1770 
1771 static void
1772 ucom_gdbputc(int c)
1773 {
1774         ucom_cnputc(NULL, c);
1775 }
1776 
1777 static int
1778 ucom_gdbgetc(void)
1779 {
1780         return (ucom_cngetc(NULL));
1781 }
1782 
1783 #endif
1784