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