1 /* $NetBSD: ucom.c,v 1.40 2001/11/13 06:24:54 lukem Exp $ */
4 * Copyright (c) 2001-2003, 2005, 2008
5 * Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
31 * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
32 * All rights reserved.
34 * This code is derived from software contributed to The NetBSD Foundation
35 * by Lennart Augustsson (lennart@augustsson.net) at
36 * Carlstedt Research & Technology.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
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.
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.
69 * This is a Frankenstein of FreeBSD's usb4bsd ucom and Dragonfly's old ucom
70 * module. There might be bugs lurking everywhere still
72 * In particular serial console on ucom is completely untested and likely broken
73 * as well as anyting that requires the modem control lines.
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>
83 #include <sys/module.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>
92 #include <sys/serial.h>
93 #include <sys/thread2.h>
95 #include <sys/clist.h>
97 #include <bus/u4b/usb.h>
98 #include <bus/u4b/usbdi.h>
99 #include <bus/u4b/usbdi_util.h>
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>
106 #include <bus/u4b/serial/usb_serial.h>
108 //#include "opt_gdb.h"
110 static SYSCTL_NODE(_hw_usb, OID_AUTO, ucom, CTLFLAG_RW, 0, "USB ucom");
112 static int ucom_pps_mode;
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);
120 static int ucom_debug = 0;
122 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, debug, CTLFLAG_RW,
123 &ucom_debug, 0, "ucom debug level");
126 #define UCOM_CONS_BUFSIZE 1024
128 static uint8_t ucom_cons_rx_buf[UCOM_CONS_BUFSIZE];
129 static uint8_t ucom_cons_tx_buf[UCOM_CONS_BUFSIZE];
131 static unsigned int ucom_cons_rx_low = 0;
132 static unsigned int ucom_cons_rx_high = 0;
134 static unsigned int ucom_cons_tx_low = 0;
135 static unsigned int ucom_cons_tx_high = 0;
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;
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");
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;
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);
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);
179 static int ucom_fromtio(int);
180 static int ucom_totio(int);
182 static void disc_optim(struct tty *, struct termios *, struct ucom_softc *);
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;
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
201 static moduledata_t ucom_mod = {
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);
212 #define tty_gone(tp) ((tp->t_state) & (TS_ZOMBIE))
214 #define UCOM_UNIT_MAX 128 /* maximum number of units */
215 #define UCOM_TTY_PREFIX "ucom"
217 static struct unrhdr *ucom_unrhdr;
218 static struct lock ucom_lock;
219 static int ucom_close_refs;
225 ucom_unrhdr = new_unrhdr(0, UCOM_UNIT_MAX - 1, NULL);
226 lockinit(&ucom_lock, "UCOM LOCK", 0, 0);
228 SYSINIT(ucom_init, SI_BOOT2_KLD - 1, SI_ORDER_ANY, ucom_init, NULL);
231 ucom_uninit(void *arg)
242 lockuninit(&ucom_lock);
244 SYSUNINIT(ucom_uninit, SI_BOOT2_KLD - 2, SI_ORDER_ANY, ucom_uninit, NULL);
247 * Mark a unit number (the X in cuaUX) as in use.
249 * Note that devices using a different naming scheme (see ucom_tty_name()
250 * callback) still use this unit allocation.
253 ucom_unit_alloc(void)
258 if (ucom_unrhdr == NULL) {
259 DPRINTF("ucom_unrhdr is NULL\n");
262 unit = alloc_unr(ucom_unrhdr);
263 DPRINTF("unit %d is allocated\n", unit);
268 * Mark the unit number as not in use.
271 ucom_unit_free(int unit)
274 if (unit < 0 || unit >= UCOM_UNIT_MAX || ucom_unrhdr == NULL) {
275 DPRINTF("cannot free unit number\n");
278 DPRINTF("unit %d is freed\n", unit);
279 free_unr(ucom_unrhdr, unit);
283 * Setup a group of one or more serial ports.
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!
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)
299 (callback == NULL) ||
304 /* XXX Do we want our own lock here maybe */
307 /* allocate a uniq unit number */
308 ssc->sc_unit = ucom_unit_alloc();
309 if (ssc->sc_unit == -1)
312 /* generate TTY name string */
313 ksnprintf(ssc->sc_ttyname, sizeof(ssc->sc_ttyname),
314 UCOM_TTY_PREFIX "%d", ssc->sc_unit);
316 /* create USB request handling process */
317 error = usb_proc_create(&ssc->sc_tq, lock, "ucom", USB_PRI_MED);
319 ucom_unit_free(ssc->sc_unit);
322 ssc->sc_subunits = subunits;
323 ssc->sc_flag = UCOM_FLAG_ATTACHED |
326 if (callback->ucom_free == NULL)
327 ssc->sc_flag |= UCOM_FLAG_WAIT_REFS;
329 /* increment reference count */
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;
339 error = ucom_attach_tty(ssc, &sc[subunit]);
341 ucom_detach(ssc, &sc[0]);
344 /* increment reference count */
347 /* set subunit attached */
348 sc[subunit].sc_flag |= UCOM_FLAG_ATTACHED;
351 DPRINTF("tp = %p, unit = %d, subunits = %d\n",
352 sc->sc_tty, ssc->sc_unit, ssc->sc_subunits);
358 * The following function will do nothing if the structure pointed to
359 * by "ssc" and "sc" is zero or has already been detached.
362 ucom_detach(struct ucom_super_softc *ssc, struct ucom_softc *sc)
366 if (!(ssc->sc_flag & UCOM_FLAG_ATTACHED))
367 return; /* not initialized */
369 destroy_dev(sc->sc_cdev);
371 lwkt_gettoken(&tty_token);
373 if (ssc->sc_sysctl_ttyname != NULL) {
374 sysctl_remove_oid(ssc->sc_sysctl_ttyname, 1, 0);
375 ssc->sc_sysctl_ttyname = NULL;
378 if (ssc->sc_sysctl_ttyports != NULL) {
379 sysctl_remove_oid(ssc->sc_sysctl_ttyports, 1, 0);
380 ssc->sc_sysctl_ttyports = NULL;
383 usb_proc_drain(&ssc->sc_tq);
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]);
389 /* avoid duplicate detach */
390 sc[subunit].sc_flag &= ~UCOM_FLAG_ATTACHED;
393 usb_proc_free(&ssc->sc_tq);
397 if (ssc->sc_flag & UCOM_FLAG_WAIT_REFS)
400 /* make sure we don't detach twice */
401 ssc->sc_flag &= ~UCOM_FLAG_ATTACHED;
403 lwkt_reltoken(&tty_token);
407 ucom_drain(struct ucom_super_softc *ssc)
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);
414 lockmgr(&ucom_lock, LK_RELEASE);
418 ucom_drain_all(void *arg)
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);
426 lockmgr(&ucom_lock, LK_RELEASE);
430 ucom_attach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc)
433 char buf[32]; /* temporary TTY device name buffer */
436 lwkt_gettoken(&tty_token);
438 sc->sc_tty = tp = ttymalloc(sc->sc_tty);
441 lwkt_reltoken(&tty_token);
445 tp->t_sc = (void *)sc;
447 tp->t_oproc = ucom_start;
448 tp->t_param = ucom_param;
449 tp->t_stop = ucom_stop;
451 /* Check if the client has a custom TTY name */
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);
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);
465 ksnprintf(buf, sizeof(buf), UCOM_TTY_PREFIX "%u",
470 dev = make_dev(&ucom_ops, ssc->sc_unit | 0x80, // XXX UCOM_CALLOUT_MASK,
471 UID_UUCP, GID_DIALER, 0660,
478 DPRINTF("ttycreate: %s\n", buf);
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)) {
485 DPRINTF("unit %d subunit %d is console",
486 ssc->sc_unit, sc->sc_subunit);
488 ucom_cons_softc = sc;
491 tty_init_console(tp, ucom_cons_baud);
493 tp->t_termios.c_ispeed = ucom_cons_baud;
494 tp->t_termios.c_ospeed = ucom_cons_baud;
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;
503 ucom_open(ucom_cons_softc);
504 ucom_param(tp, &tp->t_termios);
505 UCOM_MTX_UNLOCK(ucom_cons_softc);
508 lwkt_reltoken(&tty_token);
513 ucom_detach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc)
515 struct tty *tp = sc->sc_tty;
517 DPRINTF("sc = %p, tp = %p\n", sc, sc->sc_tty);
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;
527 /* the config thread has been stopped when we get here */
530 sc->sc_flag |= UCOM_FLAG_GONE;
531 sc->sc_flag &= ~(UCOM_FLAG_HL_READY | UCOM_FLAG_LL_READY);
534 lwkt_gettoken(&tty_token);
539 if (tp->t_state & TS_ISOPEN) {
540 kprintf("device still open, forcing close\n");
541 (*linesw[tp->t_line].l_close)(tp, 0);
544 ucom_close(sc); /* close, if any */
547 * make sure that read and write transfers are stopped
549 if (sc->sc_callback->ucom_stop_read) {
550 (sc->sc_callback->ucom_stop_read) (sc);
552 if (sc->sc_callback->ucom_stop_write) {
553 (sc->sc_callback->ucom_stop_write) (sc);
560 dev_ops_remove_minor(&ucom_ops,ssc->sc_unit);
562 lwkt_reltoken(&tty_token);
567 ucom_set_pnpinfo_usb(struct ucom_super_softc *ssc, device_t dev)
571 struct usb_attach_arg *uaa;
573 ksnprintf(buf, sizeof(buf), "ttyname=" UCOM_TTY_PREFIX
574 "%d ttyports=%d", ssc->sc_unit, ssc->sc_subunits);
576 /* Store the PNP info in the first interface for the device */
577 uaa = device_get_ivars(dev);
578 iface_index = uaa->info.bIfaceIndex;
580 if (usbd_set_pnpinfo(uaa->device, iface_index, buf) != 0)
581 device_printf(dev, "Could not set PNP info\n");
584 * The following information is also replicated in the PNP-info
585 * string which is registered above:
587 if (ssc->sc_sysctl_ttyname == NULL) {
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");
595 if (ssc->sc_sysctl_ttyports == NULL) {
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");
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)
610 struct ucom_super_softc *ssc = sc->sc_super;
611 struct ucom_param_task *task;
613 UCOM_MTX_ASSERT(sc, MA_OWNED);
615 if (usb_proc_is_gone(&ssc->sc_tq)) {
616 DPRINTF("proc is gone\n");
617 return; /* nothing to do */
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.
624 task = (struct ucom_param_task *)
625 usb_proc_msignal(&ssc->sc_tq, t0, t1);
627 /* Setup callback and softc pointers */
628 task->hdr.pm_callback = fn;
632 * Make a copy of the termios. This field is only present if
633 * the "pt" field is not NULL.
636 task->termios_copy = *pt;
639 * Closing the device should be synchronous.
641 if (fn == ucom_cfg_close)
642 usb_proc_mwait(&ssc->sc_tq, t0, t1);
645 * In case of multiple configure requests,
646 * keep track of the last one!
648 if (fn == ucom_cfg_start_transfers)
649 sc->sc_last_start_xfer = &task->hdr;
653 ucom_shutdown(struct ucom_softc *sc)
655 struct tty *tp = sc->sc_tty;
657 UCOM_MTX_ASSERT(sc, MA_OWNED);
662 * Hang up if necessary:
664 if (tp->t_termios.c_cflag & HUPCL) {
665 ucom_modem(tp, 0, SER_DTR);
672 * else: taskqueue is draining or gone
675 ucom_cfg_is_gone(struct ucom_softc *sc)
677 struct ucom_super_softc *ssc = sc->sc_super;
679 return (usb_proc_is_gone(&ssc->sc_tq));
683 ucom_cfg_start_transfers(struct usb_proc_msg *_task)
685 struct ucom_cfg_task *task =
686 (struct ucom_cfg_task *)_task;
687 struct ucom_softc *sc = task->sc;
689 if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
692 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
693 /* TTY device closed */
697 if (_task == sc->sc_last_start_xfer)
698 sc->sc_flag |= UCOM_FLAG_GP_DATA;
700 if (sc->sc_callback->ucom_start_read) {
701 (sc->sc_callback->ucom_start_read) (sc);
703 if (sc->sc_callback->ucom_start_write) {
704 (sc->sc_callback->ucom_start_write) (sc);
709 ucom_start_transfers(struct ucom_softc *sc)
711 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
715 * Make sure that data transfers are started in both
718 if (sc->sc_callback->ucom_start_read) {
719 (sc->sc_callback->ucom_start_read) (sc);
721 if (sc->sc_callback->ucom_start_write) {
722 (sc->sc_callback->ucom_start_write) (sc);
727 ucom_cfg_open(struct usb_proc_msg *_task)
729 struct ucom_cfg_task *task =
730 (struct ucom_cfg_task *)_task;
731 struct ucom_softc *sc = task->sc;
735 if (sc->sc_flag & UCOM_FLAG_LL_READY) {
741 sc->sc_flag |= UCOM_FLAG_LL_READY;
743 if (sc->sc_callback->ucom_cfg_open) {
744 (sc->sc_callback->ucom_cfg_open) (sc);
747 usb_pause_mtx(sc->sc_lock, hz / 10);
753 ucom_dev_open(struct dev_open_args *ap)
755 cdev_t dev = ap->a_head.a_dev;
756 struct ucom_softc *sc = (struct ucom_softc *)dev->si_drv1;
760 error = ucom_open(sc);
767 ucom_open(struct ucom_softc *sc)
772 if (sc->sc_flag & UCOM_FLAG_GONE) {
775 if (sc->sc_flag & UCOM_FLAG_HL_READY) {
779 DPRINTF("tp = %p\n", sc->sc_tty);
781 if (sc->sc_callback->ucom_pre_open) {
783 * give the lower layer a chance to disallow TTY open, for
784 * example if the device is not present:
786 error = (sc->sc_callback->ucom_pre_open) (sc);
791 sc->sc_flag |= UCOM_FLAG_HL_READY;
793 lwkt_gettoken(&tty_token);
798 if (!ISSET(tp->t_state, TS_ISOPEN)) {
801 tp->t_dev = reference_dev(sc->sc_cdev);
804 t.c_ospeed = TTYDEF_SPEED;
805 t.c_cflag = TTYDEF_CFLAG;
808 tp->t_iflag = TTYDEF_IFLAG;
809 tp->t_oflag = TTYDEF_OFLAG;
810 tp->t_lflag = TTYDEF_LFLAG;
814 /* Disable transfers */
815 sc->sc_flag &= ~UCOM_FLAG_GP_DATA;
821 /* reset programmed line state */
826 /* reset jitter buffer */
827 sc->sc_jitterbuf_in = 0;
828 sc->sc_jitterbuf_out = 0;
830 ucom_queue_command(sc, ucom_cfg_open, NULL,
831 &sc->sc_open_task[0].hdr,
832 &sc->sc_open_task[1].hdr);
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);
839 ucom_modem(sc->sc_tty, SER_DTR | SER_RTS, 0);
845 ucom_status_change(sc);
847 if (ISSET(sc->sc_msr, SER_DCD)) {
848 (*linesw[tp->t_line].l_modem)(tp, 1);
853 error = ttyopen(sc->sc_cdev, tp);
855 lwkt_reltoken(&tty_token);
859 error = (*linesw[tp->t_line].l_open)(sc->sc_cdev, tp);
861 lwkt_reltoken(&tty_token);
865 disc_optim(tp, &tp->t_termios, sc);
867 lwkt_reltoken(&tty_token);
873 ucom_cfg_close(struct usb_proc_msg *_task)
875 struct ucom_cfg_task *task =
876 (struct ucom_cfg_task *)_task;
877 struct ucom_softc *sc = task->sc;
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);
891 ucom_dev_close(struct dev_close_args *ap)
893 cdev_t dev = ap->a_head.a_dev;
894 struct ucom_softc *sc = (struct ucom_softc *)dev->si_drv1;
898 error = ucom_close(sc);
905 ucom_close(struct ucom_softc *sc)
907 struct tty *tp = sc->sc_tty;
910 DPRINTF("tp=%p\n", tp);
912 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
913 DPRINTF("tp=%p already closed\n", tp);
916 if (!ISSET(tp->t_state, TS_ISOPEN)) {
921 ucom_queue_command(sc, ucom_cfg_close, NULL,
922 &sc->sc_close_task[0].hdr,
923 &sc->sc_close_task[1].hdr);
925 sc->sc_flag &= ~(UCOM_FLAG_HL_READY | UCOM_FLAG_RTS_IFLOW);
927 if (sc->sc_callback->ucom_stop_read) {
928 (sc->sc_callback->ucom_stop_read) (sc);
931 lwkt_gettoken(&tty_token);
933 (*linesw[tp->t_line].l_close)(tp, 0); /* XXX: flags */
934 disc_optim(tp, &tp->t_termios, sc);
939 release_dev(tp->t_dev);
942 /* XXX: Detach wakeup */
943 lwkt_reltoken(&tty_token);
950 ucom_inwakeup(struct tty *tp)
952 struct ucom_softc *sc = tty_softc(tp);
958 UCOM_MTX_ASSERT(sc, MA_OWNED);
960 DPRINTF("tp=%p\n", tp);
962 if (ttydisc_can_bypass(tp) != 0 ||
963 (sc->sc_flag & UCOM_FLAG_HL_READY) == 0 ||
964 (sc->sc_flag & UCOM_FLAG_INWAKEUP) != 0) {
968 /* prevent recursion */
969 sc->sc_flag |= UCOM_FLAG_INWAKEUP;
971 pos = sc->sc_jitterbuf_out;
973 while (sc->sc_jitterbuf_in != pos) {
976 c = (char)sc->sc_jitterbuf[pos];
978 if (ttydisc_rint(tp, c, 0) == -1)
981 if (pos >= UCOM_JITTERBUF_SIZE)
982 pos -= UCOM_JITTERBUF_SIZE;
985 sc->sc_jitterbuf_out = pos;
987 /* clear RTS in async fashion */
988 if ((sc->sc_jitterbuf_in == pos) &&
989 (sc->sc_flag & UCOM_FLAG_RTS_IFLOW))
992 sc->sc_flag &= ~UCOM_FLAG_INWAKEUP;
997 ucom_dev_read(struct dev_read_args *ap)
999 cdev_t dev = ap->a_head.a_dev;
1000 struct ucom_softc *sc;
1006 lwkt_gettoken(&tty_token);
1013 DPRINTF("tp = %p, flag = 0x%x\n", tp, ap->a_ioflag);
1016 error = (*linesw[tp->t_line].l_read)(tp, ap->a_uio, ap->a_ioflag);
1017 UCOM_MTX_UNLOCK(sc);
1019 DPRINTF("error = %d\n", error);
1021 lwkt_reltoken(&tty_token);
1026 ucom_dev_write(struct dev_write_args *ap)
1028 cdev_t dev = ap->a_head.a_dev;
1029 struct ucom_softc *sc;
1033 lwkt_gettoken(&tty_token);
1039 DPRINTF("tp = %p, flag = 0x%x\n", tp, ap->a_ioflag);
1042 error = (*linesw[tp->t_line].l_write)(tp, ap->a_uio, ap->a_ioflag);
1043 UCOM_MTX_UNLOCK(sc);
1045 DPRINTF("ucomwrite: error = %d\n", error);
1047 lwkt_reltoken(&tty_token);
1052 ucom_dev_ioctl(struct dev_ioctl_args *ap)
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;
1063 lwkt_gettoken(&tty_token);
1065 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1066 lwkt_reltoken(&tty_token);
1069 DPRINTF("cmd = 0x%08lx\n", cmd);
1071 error = (*linesw[tp->t_line].l_ioctl)(tp, ap->a_cmd, ap->a_data,
1072 ap->a_fflag, ap->a_cred);
1074 if (error != ENOIOCTL) {
1075 DPRINTF("ucomioctl: l_ioctl: error = %d\n", error);
1076 lwkt_reltoken(&tty_token);
1077 UCOM_MTX_UNLOCK(sc);
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) {
1087 DPRINTF("ucomioctl: ttioctl: error = %d\n", error);
1088 lwkt_reltoken(&tty_token);
1089 UCOM_MTX_UNLOCK(sc);
1122 d = *(int *)ap->a_data;
1123 DPRINTF("ucomioctl: TIOCMSET, 0x%x\n", d);
1124 ucom_modem(tp, ucom_fromtio(d), 0);
1127 d = ucom_modem(tp, 0, 0);
1128 DPRINTF("ucomioctl: TIOCMGET, 0x%x\n", d);
1129 *(int *)ap->a_data = ucom_totio(d);
1132 d = *(int *)ap->a_data;
1133 ucom_modem(tp, ucom_fromtio(d), 0);
1136 d = *(int *)ap->a_data;
1137 ucom_modem(tp, 0, ucom_fromtio(d));
1140 if (sc->sc_callback->ucom_ioctl) {
1141 error = (sc->sc_callback->ucom_ioctl)
1142 (sc, cmd, data, 0, curthread);
1146 lwkt_reltoken(&tty_token);
1147 UCOM_MTX_UNLOCK(sc);
1154 if (error == ENOIOCTL)
1155 error = pps_ioctl(cmd, data, &sc->sc_pps);
1160 lwkt_reltoken(&tty_token);
1161 UCOM_MTX_UNLOCK(sc);
1167 ucom_totio(int bits)
1171 SET(bits, TIOCM_LE);
1173 if (ISSET(bits, SER_DTR)) {
1174 SET(rbits, TIOCM_DTR);
1176 if (ISSET(bits, SER_RTS)) {
1177 SET(rbits, TIOCM_RTS);
1179 if (ISSET(bits, SER_CTS)) {
1180 SET(rbits, TIOCM_CTS);
1182 if (ISSET(bits, SER_DCD)) {
1183 SET(rbits, TIOCM_CD);
1185 if (ISSET(bits, SER_DSR)) {
1186 SET(rbits, TIOCM_DSR);
1188 if (ISSET(bits, SER_RI)) {
1189 SET(rbits, TIOCM_RI);
1196 ucom_fromtio(int bits)
1200 if (ISSET(bits, TIOCM_DTR)) {
1201 SET(rbits, SER_DTR);
1203 if (ISSET(bits, TIOCM_RTS)) {
1204 SET(rbits, SER_RTS);
1206 if (ISSET(bits, TIOCM_CTS)) {
1207 SET(rbits, SER_CTS);
1209 if (ISSET(bits, TIOCM_CD)) {
1210 SET(rbits, SER_DCD);
1212 if (ISSET(bits, TIOCM_DSR)) {
1213 SET(rbits, SER_DSR);
1215 if (ISSET(bits, TIOCM_RI)) {
1223 ucom_modem(struct tty *tp, int sigon, int sigoff)
1225 struct ucom_softc *sc = (struct ucom_softc *)tp->t_sc;
1228 UCOM_MTX_ASSERT(sc, MA_OWNED);
1230 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1233 if ((sigon == 0) && (sigoff == 0)) {
1235 if (sc->sc_mcr & SER_DTR) {
1238 if (sc->sc_mcr & SER_RTS) {
1241 if (sc->sc_msr & SER_CTS) {
1244 if (sc->sc_msr & SER_DCD) {
1247 if (sc->sc_msr & SER_DSR) {
1250 if (sc->sc_msr & SER_RI) {
1255 if (sigon & SER_DTR) {
1256 sc->sc_mcr |= SER_DTR;
1258 if (sigoff & SER_DTR) {
1259 sc->sc_mcr &= ~SER_DTR;
1261 if (sigon & SER_RTS) {
1262 sc->sc_mcr |= SER_RTS;
1264 if (sigoff & SER_RTS) {
1265 sc->sc_mcr &= ~SER_RTS;
1267 onoff = (sc->sc_mcr & SER_DTR) ? 1 : 0;
1268 ucom_dtr(sc, onoff);
1270 onoff = (sc->sc_mcr & SER_RTS) ? 1 : 0;
1271 ucom_rts(sc, onoff);
1277 ucom_cfg_line_state(struct usb_proc_msg *_task)
1279 struct ucom_cfg_task *task =
1280 (struct ucom_cfg_task *)_task;
1281 struct ucom_softc *sc = task->sc;
1288 if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
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;
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;
1309 /* reset programmed line state */
1310 sc->sc_pls_curr = 0;
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);
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);
1344 ucom_line_state(struct ucom_softc *sc,
1345 uint8_t set_bits, uint8_t clear_bits)
1347 UCOM_MTX_ASSERT(sc, MA_OWNED);
1349 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1353 DPRINTF("on=0x%02x, off=0x%02x\n", set_bits, clear_bits);
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;
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);
1368 ucom_ring(struct ucom_softc *sc, uint8_t onoff)
1370 DPRINTF("onoff = %d\n", onoff);
1373 ucom_line_state(sc, UCOM_LS_RING, 0);
1375 ucom_line_state(sc, 0, UCOM_LS_RING);
1379 ucom_break(struct ucom_softc *sc, uint8_t onoff)
1381 DPRINTF("onoff = %d\n", onoff);
1384 ucom_line_state(sc, UCOM_LS_BREAK, 0);
1386 ucom_line_state(sc, 0, UCOM_LS_BREAK);
1390 ucom_dtr(struct ucom_softc *sc, uint8_t onoff)
1392 DPRINTF("onoff = %d\n", onoff);
1395 ucom_line_state(sc, UCOM_LS_DTR, 0);
1397 ucom_line_state(sc, 0, UCOM_LS_DTR);
1401 ucom_rts(struct ucom_softc *sc, uint8_t onoff)
1403 DPRINTF("onoff = %d\n", onoff);
1406 ucom_line_state(sc, UCOM_LS_RTS, 0);
1408 ucom_line_state(sc, 0, UCOM_LS_RTS);
1412 ucom_cfg_status_change(struct usb_proc_msg *_task)
1414 struct ucom_cfg_task *task =
1415 (struct ucom_cfg_task *)_task;
1416 struct ucom_softc *sc = task->sc;
1425 UCOM_MTX_ASSERT(sc, MA_OWNED);
1427 if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
1430 if (sc->sc_callback->ucom_cfg_get_status == NULL) {
1438 (sc->sc_callback->ucom_cfg_get_status) (sc, &new_lsr, &new_msr);
1440 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1441 /* TTY device closed */
1444 msr_delta = (sc->sc_msr ^ new_msr);
1445 lsr_delta = (sc->sc_lsr ^ new_lsr);
1447 sc->sc_msr = new_msr;
1448 sc->sc_lsr = new_lsr;
1450 #if 0 /* missing pps_capture */
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
1457 switch(ucom_pps_mode) {
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);
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);
1479 if (msr_delta & SER_DCD) {
1481 int onoff = (sc->sc_msr & SER_DCD) ? 1 : 0;
1483 DPRINTF("DCD changed to %d\n", onoff);
1485 (*linesw[tp->t_line].l_modem)(tp, onoff);
1488 if ((lsr_delta & ULSR_BI) && (sc->sc_lsr & ULSR_BI)) {
1490 DPRINTF("BREAK detected\n");
1491 (*linesw[tp->t_line].l_rint)(0, tp);
1494 ttydisc_rint(tp, 0, TRE_BREAK);
1495 ttydisc_rint_done(tp);
1499 if ((lsr_delta & ULSR_FE) && (sc->sc_lsr & ULSR_FE)) {
1501 DPRINTF("Frame error detected\n");
1502 (*linesw[tp->t_line].l_rint)(0, tp);
1505 ttydisc_rint(tp, 0, TRE_FRAMING);
1506 ttydisc_rint_done(tp);
1510 if ((lsr_delta & ULSR_PE) && (sc->sc_lsr & ULSR_PE)) {
1512 DPRINTF("Parity error detected\n");
1513 (*linesw[tp->t_line].l_rint)(0, tp);
1515 ttydisc_rint(tp, 0, TRE_PARITY);
1516 ttydisc_rint_done(tp);
1522 ucom_status_change(struct ucom_softc *sc)
1524 UCOM_MTX_ASSERT(sc, MA_OWNED);
1526 if (sc->sc_flag & UCOM_FLAG_CONSOLE)
1527 return; /* not supported */
1529 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1534 ucom_queue_command(sc, ucom_cfg_status_change, NULL,
1535 &sc->sc_status_task[0].hdr,
1536 &sc->sc_status_task[1].hdr);
1540 ucom_cfg_param(struct usb_proc_msg *_task)
1542 struct ucom_param_task *task =
1543 (struct ucom_param_task *)_task;
1544 struct ucom_softc *sc = task->sc;
1546 if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
1549 if (sc->sc_callback->ucom_cfg_param == NULL) {
1553 (sc->sc_callback->ucom_cfg_param) (sc, &task->termios_copy);
1556 usb_pause_mtx(sc->sc_lock, hz / 10);
1560 ucom_param(struct tty *tp, struct termios *t)
1562 struct ucom_softc *sc = (struct ucom_softc *)tp->t_sc;
1566 lwkt_gettoken(&tty_token);
1567 UCOM_MTX_ASSERT(sc, MA_OWNED);
1572 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1574 /* XXX the TTY layer should call "open()" first! */
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().
1580 error = ucom_open(sc);
1587 DPRINTF("sc = %p\n", sc);
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");
1596 t->c_ispeed = t->c_ospeed;
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);
1602 DPRINTF("callback error = %d\n", error);
1607 /* Disable transfers */
1608 sc->sc_flag &= ~UCOM_FLAG_GP_DATA;
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);
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);
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);
1633 lwkt_reltoken(&tty_token);
1638 ucom_start(struct tty *tp)
1640 struct ucom_softc *sc = (struct ucom_softc *)tp->t_sc;
1642 UCOM_MTX_ASSERT(sc, MA_OWNED);
1644 DPRINTF("sc = %p\n", sc);
1646 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1647 /* The higher layer is not ready */
1651 lwkt_gettoken(&tty_token);
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);
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);
1669 if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) {
1671 DPRINTF("ucom_start: stopped\n");
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));
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));
1691 DPRINTF("about to start write?\n");
1692 ucom_start_transfers(sc);
1698 lwkt_reltoken(&tty_token);
1702 ucom_stop(struct tty *tp, int flag)
1704 struct ucom_softc *sc = (struct ucom_softc *)tp->t_sc;
1706 DPRINTF("sc = %p, x = 0x%x\n", sc, flag);
1708 lwkt_gettoken(&tty_token);
1711 * This is just supposed to flush pending receive data,
1712 * not stop the reception of data entirely!
1715 if (sc->sc_callback->ucom_stop_read) {
1716 (sc->sc_callback->ucom_stop_read) (sc);
1718 if (sc->sc_callback->ucom_start_read) {
1719 (sc->sc_callback->ucom_start_read) (sc);
1721 /* ucomstopread(sc);
1725 if (flag & FWRITE) {
1728 if (ISSET(tp->t_state, TS_BUSY)) {
1730 if (!ISSET(tp->t_state, TS_TTSTOP))
1731 SET(tp->t_state, TS_FLUSH);
1737 lwkt_reltoken(&tty_token);
1740 /*------------------------------------------------------------------------*
1743 * len: maximum length of data to get
1745 * Get data from the TTY layer
1748 * 0: No data is available.
1749 * Else: Data is available.
1750 *------------------------------------------------------------------------*/
1752 /* Copy data from the tty layer to usb */
1754 ucom_get_data(struct ucom_softc *sc, struct usb_page_cache *pc,
1755 uint32_t offset, uint32_t len, uint32_t *actlen)
1757 struct usb_page_search res;
1758 struct tty *tp = sc->sc_tty;
1760 uint32_t offset_orig;
1764 UCOM_MTX_ASSERT(sc, MA_OWNED);
1765 if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
1768 /* get total TX length */
1770 temp = ucom_cons_tx_high - ucom_cons_tx_low;
1771 temp %= UCOM_CONS_BUFSIZE;
1773 /* limit TX length */
1775 if (temp > (UCOM_CONS_BUFSIZE - ucom_cons_tx_low))
1776 temp = (UCOM_CONS_BUFSIZE - ucom_cons_tx_low);
1783 usbd_copy_in(pc, offset, ucom_cons_tx_buf + ucom_cons_tx_low, temp);
1785 /* update counters */
1787 ucom_cons_tx_low += temp;
1788 ucom_cons_tx_low %= UCOM_CONS_BUFSIZE;
1790 /* store actual length */
1794 return (temp ? 1 : 0);
1798 !(sc->sc_flag & UCOM_FLAG_GP_DATA)) {
1800 return (0); /* multiport device polling */
1803 offset_orig = offset;
1805 lwkt_gettoken(&tty_token);
1808 usbd_get_page(pc, offset, &res);
1810 /* Buffer bigger than max requested data */
1811 if (res.length > len) {
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);
1818 DPRINTF("ucom_get_data: cnt == 0\n");
1819 CLR(tp->t_state, TS_BUSY);
1823 CLR(tp->t_state, TS_BUSY);
1825 /* XXX mp: This breaks avrdude,
1826 does the flush need to happen
1828 if (ISSET(tp->t_state, TS_FLUSH))
1829 CLR(tp->t_state, TS_FLUSH);
1831 ndflush(&tp->t_outq,cnt);
1837 if (cnt < res.length) {
1843 lwkt_reltoken(&tty_token);
1845 actlen[0] = offset - offset_orig;
1847 DPRINTF("cnt=%d\n", actlen[0]);
1849 if (actlen[0] == 0) {
1856 * Write data to the tty layer
1860 ucom_put_data(struct ucom_softc *sc, struct usb_page_cache *pc,
1861 uint32_t offset, uint32_t len)
1863 struct usb_page_search res;
1864 struct tty *tp = sc->sc_tty;
1871 UCOM_MTX_ASSERT(sc, MA_OWNED);
1872 lwkt_gettoken(&tty_token);
1874 if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
1877 /* get maximum RX length */
1879 temp = (UCOM_CONS_BUFSIZE - 1) - ucom_cons_rx_high + ucom_cons_rx_low;
1880 temp %= UCOM_CONS_BUFSIZE;
1882 /* limit RX length */
1884 if (temp > (UCOM_CONS_BUFSIZE - ucom_cons_rx_high))
1885 temp = (UCOM_CONS_BUFSIZE - ucom_cons_rx_high);
1892 usbd_copy_out(pc, offset, ucom_cons_rx_buf + ucom_cons_rx_high, temp);
1894 /* update counters */
1896 ucom_cons_rx_high += temp;
1897 ucom_cons_rx_high %= UCOM_CONS_BUFSIZE;
1899 lwkt_reltoken(&tty_token);
1904 lwkt_reltoken(&tty_token);
1905 return; /* multiport device polling */
1908 lwkt_reltoken(&tty_token);
1909 return; /* no data */
1912 /* set a flag to prevent recursation ? */
1916 usbd_get_page(pc, offset, &res);
1918 if (res.length > len) {
1922 offset += res.length;
1924 /* pass characters to tty layer */
1929 /* first check if we can pass the buffer directly */
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;
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))
1941 lostcc = b_to_q((char *)buf, cnt, &tp->t_rawq);
1945 if (*buf == sc->hotchar)
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;
1962 kprintf("lost %d chars\n", lostcc);
1965 if (ttydisc_rint_bypass(tp, buf, cnt) != cnt) {
1966 DPRINTF("tp=%p, data lost\n", tp);
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) {
1978 pos = sc->sc_jitterbuf_in;
1979 end = sc->sc_jitterbuf_out +
1980 UCOM_JITTERBUF_SIZE - 1;
1982 if (end >= UCOM_JITTERBUF_SIZE)
1983 end -= UCOM_JITTERBUF_SIZE;
1985 for (; cnt != res.length; cnt++) {
1988 sc->sc_jitterbuf[pos] = buf[cnt];
1990 if (pos >= UCOM_JITTERBUF_SIZE)
1991 pos -= UCOM_JITTERBUF_SIZE;
1994 sc->sc_jitterbuf_in = pos;
1996 /* set RTS in async fashion */
1997 if (sc->sc_flag & UCOM_FLAG_RTS_IFLOW)
2000 DPRINTF("tp=%p, lost %d "
2001 "chars\n", tp, res.length - cnt);
2008 lwkt_reltoken(&tty_token);
2010 ttydisc_rint_done(tp);
2016 ucom_free(void *xsc)
2018 struct ucom_softc *sc = xsc;
2020 if (sc->sc_callback->ucom_free != NULL)
2021 sc->sc_callback->ucom_free(sc);
2023 /*ucom_unref(sc->sc_super) XXX hack, see end of ucom_detach_tty() */;
2025 lockmgr(&ucom_lock, LK_EXCLUSIVE);
2027 lockmgr(&ucom_lock, LK_RELEASE);
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;
2037 static cn_grab_t ucom_cngrab;
2038 static cn_ungrab_t ucom_cnungrab;
2039 CONSOLE_DRIVER(ucom);
2043 ucom_cnprobe(struct consdev *cp)
2045 if (ucom_cons_unit != -1)
2046 cp->cn_pri = CN_NORMAL;
2048 cp->cn_pri = CN_DEAD;
2051 strlcpy(cp->cn_name, "ucom", sizeof(cp->cn_name));
2056 ucom_cninit(struct consdev *cp)
2061 ucom_cnterm(struct consdev *cp)
2066 ucom_cngrab(struct consdev *cp)
2071 ucom_cnungrab(struct consdev *cp)
2076 ucom_cngetc(struct consdev *cd)
2078 struct ucom_softc *sc = ucom_cons_softc;
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;
2094 /* start USB transfers */
2095 ucom_outwakeup(sc->sc_tty);
2097 UCOM_MTX_UNLOCK(sc);
2099 /* poll if necessary */
2101 if (kdb_active && sc->sc_callback->ucom_poll)
2102 (sc->sc_callback->ucom_poll) (sc);
2108 ucom_cnputc(void *cd, int c)
2110 ucom_cnputc(struct consdev *cd, int c)
2114 struct ucom_softc *sc = ucom_cons_softc;
2124 /* compute maximum TX length */
2126 temp = (UCOM_CONS_BUFSIZE - 1) - ucom_cons_tx_high + ucom_cons_tx_low;
2127 temp %= UCOM_CONS_BUFSIZE;
2130 ucom_cons_tx_buf[ucom_cons_tx_high] = c;
2131 ucom_cons_tx_high ++;
2132 ucom_cons_tx_high %= UCOM_CONS_BUFSIZE;
2135 /* start USB transfers */
2136 ucom_outwakeup(sc->sc_tty);
2138 UCOM_MTX_UNLOCK(sc);
2140 /* poll if necessary */
2142 if (kdb_active && sc->sc_callback->ucom_poll) {
2143 (sc->sc_callback->ucom_poll) (sc);
2144 /* simple flow control */
2151 /*------------------------------------------------------------------------*
2154 * This function will increment the super UCOM reference count.
2155 *------------------------------------------------------------------------*/
2157 ucom_ref(struct ucom_super_softc *ssc)
2159 lockmgr(&ucom_lock, LK_EXCLUSIVE);
2161 lockmgr(&ucom_lock, LK_RELEASE);
2164 /*------------------------------------------------------------------------*
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 *------------------------------------------------------------------------*/
2172 ucom_free_unit(struct ucom_super_softc *ssc)
2174 if (!(ssc->sc_flag & UCOM_FLAG_FREE_UNIT))
2177 ucom_unit_free(ssc->sc_unit);
2179 ssc->sc_flag &= ~UCOM_FLAG_FREE_UNIT;
2182 /*------------------------------------------------------------------------*
2185 * This function will decrement the super UCOM reference count.
2188 * 0: UCOM structures are still referenced.
2189 * Else: UCOM structures are no longer referenced.
2190 *------------------------------------------------------------------------*/
2192 ucom_unref(struct ucom_super_softc *ssc)
2196 lockmgr(&ucom_lock, LK_EXCLUSIVE);
2197 retval = (ssc->sc_refs < 2);
2199 lockmgr(&ucom_lock, LK_RELEASE);
2202 ucom_free_unit(ssc);
2208 * NOTE: Must be called with tty_token held.
2211 disc_optim(struct tty *tp, struct termios *t, struct ucom_softc *sc)
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;
2223 DPRINTF("disc_optim: can't bypass l_rint\n");
2224 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
2226 sc->hotchar = linesw[tp->t_line].l_hotchar;
2231 #include <gdb/gdb.h>
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;
2239 GDB_DBGPORT(sio, ucom_gdbprobe, ucom_gdbinit, ucom_gdbterm, ucom_gdbgetc, ucom_gdbputc);
2244 return ((ucom_cons_softc != NULL) ? 0 : -1);
2260 ucom_cnputc(NULL, c);
2266 return (ucom_cngetc(NULL));