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