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