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