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