Nuke USB_GET_SC and USB_GET_SC_OPEN macros.
[dragonfly.git] / sys / dev / usbmisc / ucom / ucom.c
1 /*
2  * $NetBSD: ucom.c,v 1.39 2001/08/16 22:31:24 augustss Exp $
3  * $NetBSD: ucom.c,v 1.40 2001/11/13 06:24:54 lukem Exp $
4  * $FreeBSD: src/sys/dev/usb/ucom.c,v 1.35 2003/11/16 11:58:21 akiyama Exp $
5  * $DragonFly: src/sys/dev/usbmisc/ucom/ucom.c,v 1.27 2007/07/02 06:43:31 hasso Exp $
6  */
7 /*-
8  * Copyright (c) 2001-2002, Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 /*
34  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
35  * All rights reserved.
36  *
37  * This code is derived from software contributed to The NetBSD Foundation
38  * by Lennart Augustsson (lennart@augustsson.net) at
39  * Carlstedt Research & Technology.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. All advertising materials mentioning features or use of this software
50  *    must display the following acknowledgement:
51  *        This product includes software developed by the NetBSD
52  *        Foundation, Inc. and its contributors.
53  * 4. Neither the name of The NetBSD Foundation nor the names of its
54  *    contributors may be used to endorse or promote products derived
55  *    from this software without specific prior written permission.
56  *
57  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
58  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
59  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
60  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
61  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
62  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
63  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
64  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
65  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
66  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
67  * POSSIBILITY OF SUCH DAMAGE.
68  */
69
70 #include <sys/param.h>
71 #include <sys/systm.h>
72 #include <sys/kernel.h>
73 #include <sys/malloc.h>
74 #include <sys/bus.h>
75 #include <sys/ioccom.h>
76 #include <sys/fcntl.h>
77 #include <sys/conf.h>
78 #include <sys/tty.h>
79 #include <sys/clist.h>
80 #include <sys/file.h>
81 #include <sys/select.h>
82 #include <sys/proc.h>
83 #include <sys/vnode.h>
84 #include <sys/poll.h>
85 #include <sys/sysctl.h>
86 #include <sys/thread2.h>
87
88 #include <bus/usb/usb.h>
89 #include <bus/usb/usbcdc.h>
90
91 #include <bus/usb/usbdi.h>
92 #include <bus/usb/usbdi_util.h>
93 #include <bus/usb/usbdevs.h>
94 #include <bus/usb/usb_quirks.h>
95
96 #include "ucomvar.h"
97
98 #ifdef USB_DEBUG
99 static int      ucomdebug = 0;
100 SYSCTL_NODE(_hw_usb, OID_AUTO, ucom, CTLFLAG_RW, 0, "USB ucom");
101 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, debug, CTLFLAG_RW,
102            &ucomdebug, 0, "ucom debug level");
103 #define DPRINTF(x)      do { \
104                                 if (ucomdebug) \
105                                         kprintf x; \
106                         } while (0)
107
108 #define DPRINTFN(n, x)  do { \
109                                 if (ucomdebug > (n)) \
110                                         kprintf x; \
111                         } while (0)
112 #else
113 #define DPRINTF(x)
114 #define DPRINTFN(n, x)
115 #endif
116
117 static d_open_t  ucomopen;
118 static d_close_t ucomclose;
119 static d_read_t  ucomread;
120 static d_write_t ucomwrite;
121 static d_ioctl_t ucomioctl;
122
123 #define UCOM_CDEV_MAJOR  138
124
125 static struct dev_ops ucom_ops = {
126         { "ucom", UCOM_CDEV_MAJOR, D_TTY | D_KQFILTER },
127         .d_open =       ucomopen,
128         .d_close =      ucomclose,
129         .d_read =       ucomread,
130         .d_write =      ucomwrite,
131         .d_ioctl =      ucomioctl,
132         .d_poll =       ttypoll,
133         .d_kqfilter =   ttykqfilter
134 };
135
136 static void ucom_cleanup(struct ucom_softc *);
137 static int ucomctl(struct ucom_softc *, int, int);
138 static int ucomparam(struct tty *, struct termios *);
139 static void ucomstart(struct tty *);
140 static void ucomstop(struct tty *, int);
141 static void ucom_shutdown(struct ucom_softc *);
142 static void ucom_dtr(struct ucom_softc *, int);
143 static void ucom_rts(struct ucom_softc *, int);
144 static void ucom_break(struct ucom_softc *, int);
145 static usbd_status ucomstartread(struct ucom_softc *);
146 static void ucomreadcb(usbd_xfer_handle, usbd_private_handle, usbd_status);
147 static void ucomwritecb(usbd_xfer_handle, usbd_private_handle, usbd_status);
148 static void ucomstopread(struct ucom_softc *);
149 static void disc_optim(struct tty *, struct termios *, struct ucom_softc *);
150
151 devclass_t ucom_devclass;
152
153 static moduledata_t ucom_mod = {
154         "ucom",
155         NULL,
156         NULL
157 };
158
159 DECLARE_MODULE(ucom, ucom_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
160 MODULE_DEPEND(ucom, usb, 1, 1, 1);
161 MODULE_VERSION(ucom, UCOM_MODVER);
162
163 int
164 ucom_attach(struct ucom_softc *sc)
165 {
166         struct tty *tp;
167         int unit;
168         cdev_t dev;
169
170         unit = device_get_unit(sc->sc_dev);
171
172         sc->sc_tty = tp = ttymalloc(sc->sc_tty);
173         tp->t_oproc = ucomstart;
174         tp->t_param = ucomparam;
175         tp->t_stop = ucomstop;
176
177         DPRINTF(("ucom_attach: tty_attach tp = %p\n", tp));
178
179         DPRINTF(("ucom_attach: make_dev: ucom%d\n", unit));
180
181         dev_ops_add(&ucom_ops, UCOMUNIT_MASK, unit);
182         dev = make_dev(&ucom_ops, unit | UCOM_CALLOUT_MASK,
183                         UID_UUCP, GID_DIALER, 0660,
184                         "ucom%d", unit);
185         dev->si_tty = tp;
186
187         return (0);
188 }
189
190 int
191 ucom_detach(struct ucom_softc *sc)
192 {
193         struct tty *tp = sc->sc_tty;
194         int unit;
195
196         DPRINTF(("ucom_detach: sc = %p, tp = %p\n", sc, sc->sc_tty));
197
198         sc->sc_dying = 1;
199
200         if (sc->sc_bulkin_pipe != NULL)
201                 usbd_abort_pipe(sc->sc_bulkin_pipe);
202         if (sc->sc_bulkout_pipe != NULL)
203                 usbd_abort_pipe(sc->sc_bulkout_pipe);
204
205         if (tp != NULL) {
206                 if (tp->t_state & TS_ISOPEN) {
207                         device_printf(sc->sc_dev,
208                                       "still open, forcing close\n");
209                         (*linesw[tp->t_line].l_close)(tp, 0);
210                         tp->t_gen++;
211                         ttyclose(tp);
212                         ttwakeup(tp);
213                         ttwwakeup(tp);
214                 }
215         } else {
216                 DPRINTF(("ucom_detach: no tty\n"));
217                 return (0);
218         }
219
220         crit_enter();
221         if (--sc->sc_refcnt >= 0) {
222                 /* Wait for processes to go away. */
223                 usb_detach_wait(sc->sc_dev);
224         }
225         crit_exit();
226
227         unit = device_get_unit(sc->sc_dev);
228         dev_ops_remove(&ucom_ops, UCOMUNIT_MASK, unit);
229
230         return (0);
231 }
232
233 static void
234 ucom_shutdown(struct ucom_softc *sc)
235 {
236         struct tty *tp = sc->sc_tty;
237
238         DPRINTF(("ucom_shutdown\n"));
239         /*
240          * Hang up if necessary.  Wait a bit, so the other side has time to
241          * notice even if we immediately open the port again.
242          */
243         if (ISSET(tp->t_cflag, HUPCL)) {
244                 (void)ucomctl(sc, TIOCM_DTR, DMBIC);
245                 (void)tsleep(sc, 0, "ucomsd", hz);
246         }
247 }
248
249 static int
250 ucomopen(struct dev_open_args *ap)
251 {
252         cdev_t dev = ap->a_head.a_dev;
253         int unit = UCOMUNIT(dev);
254         struct ucom_softc *sc;
255         usbd_status err;
256         struct tty *tp;
257         int error;
258
259         sc = devclass_get_softc(ucom_devclass, unit);
260         if (sc == NULL)
261                 return (ENXIO);
262
263         if (sc->sc_dying)
264                 return (ENXIO);
265
266         tp = sc->sc_tty;
267
268         DPRINTF(("%s: ucomopen: tp = %p\n", device_get_nameunit(sc->sc_dev), tp));
269
270         if (ISSET(tp->t_state, TS_ISOPEN) &&
271             ISSET(tp->t_state, TS_XCLUDE) &&
272             suser_cred(ap->a_cred, 0)
273         ) {
274                 return (EBUSY);
275         }
276
277         /*
278          * Do the following iff this is a first open.
279          */
280         crit_enter();
281         while (sc->sc_opening)
282                 tsleep(&sc->sc_opening, 0, "ucomop", 0);
283         sc->sc_opening = 1;
284
285         if (!ISSET(tp->t_state, TS_ISOPEN)) {
286                 struct termios t;
287
288                 sc->sc_poll = 0;
289                 sc->sc_lsr = sc->sc_msr = sc->sc_mcr = 0;
290
291                 tp->t_dev = reference_dev(dev);
292
293                 /*
294                  * Initialize the termios status to the defaults.  Add in the
295                  * sticky bits from TIOCSFLAGS.
296                  */
297                 t.c_ispeed = 0;
298                 t.c_ospeed = TTYDEF_SPEED;
299                 t.c_cflag = TTYDEF_CFLAG;
300                 /* Make sure ucomparam() will do something. */
301                 tp->t_ospeed = 0;
302                 (void)ucomparam(tp, &t);
303                 tp->t_iflag = TTYDEF_IFLAG;
304                 tp->t_oflag = TTYDEF_OFLAG;
305                 tp->t_lflag = TTYDEF_LFLAG;
306                 ttychars(tp);
307                 ttsetwater(tp);
308
309                 /*
310                  * Turn on DTR.  We must always do this, even if carrier is not
311                  * present, because otherwise we'd have to use TIOCSDTR
312                  * immediately after setting CLOCAL, which applications do not
313                  * expect.  We always assert DTR while the device is open
314                  * unless explicitly requested to deassert it.
315                  */
316                 (void)ucomctl(sc, TIOCM_DTR | TIOCM_RTS, DMBIS);
317
318                 /* Device specific open */
319                 if (sc->sc_callback->ucom_open != NULL) {
320                         error = sc->sc_callback->ucom_open(sc->sc_parent,
321                                                            sc->sc_portno);
322                         if (error) {
323                                 ucom_cleanup(sc);
324                                 sc->sc_opening = 0;
325                                 wakeup(&sc->sc_opening);
326                                 crit_exit();
327                                 return (error);
328                         }
329                 }
330
331                 DPRINTF(("ucomopen: open pipes in = %d out = %d\n",
332                          sc->sc_bulkin_no, sc->sc_bulkout_no));
333
334                 /* Open the bulk pipes */
335                 /* Bulk-in pipe */
336                 err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no, 0,
337                                      &sc->sc_bulkin_pipe);
338                 if (err) {
339                         kprintf("%s: open bulk in error (addr %d): %s\n",
340                                device_get_nameunit(sc->sc_dev), sc->sc_bulkin_no,
341                                usbd_errstr(err));
342                         error = EIO;
343                         goto fail_0;
344                 }
345                 /* Bulk-out pipe */
346                 err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no,
347                                      USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
348                 if (err) {
349                         kprintf("%s: open bulk out error (addr %d): %s\n",
350                                device_get_nameunit(sc->sc_dev), sc->sc_bulkout_no,
351                                usbd_errstr(err));
352                         error = EIO;
353                         goto fail_1;
354                 }
355
356                 /* Allocate a request and an input buffer and start reading. */
357                 sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev);
358                 if (sc->sc_ixfer == NULL) {
359                         error = ENOMEM;
360                         goto fail_2;
361                 }
362
363                 sc->sc_ibuf = usbd_alloc_buffer(sc->sc_ixfer,
364                                                 sc->sc_ibufsizepad);
365                 if (sc->sc_ibuf == NULL) {
366                         error = ENOMEM;
367                         goto fail_3;
368                 }
369
370                 sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev);
371                 if (sc->sc_oxfer == NULL) {
372                         error = ENOMEM;
373                         goto fail_3;
374                 }
375
376                 sc->sc_obuf = usbd_alloc_buffer(sc->sc_oxfer,
377                                                 sc->sc_obufsize +
378                                                 sc->sc_opkthdrlen);
379                 if (sc->sc_obuf == NULL) {
380                         error = ENOMEM;
381                         goto fail_4;
382                 }
383
384                 /*
385                  * Handle initial DCD.
386                  */
387                 if (ISSET(sc->sc_msr, UMSR_DCD) ||
388                     (minor(dev) & UCOM_CALLOUT_MASK))
389                         (*linesw[tp->t_line].l_modem)(tp, 1);
390
391                 ucomstartread(sc);
392         }
393
394         sc->sc_opening = 0;
395         wakeup(&sc->sc_opening);
396         crit_exit();
397
398         error = ttyopen(dev, tp);
399         if (error)
400                 goto bad;
401
402         error = (*linesw[tp->t_line].l_open)(dev, tp);
403         if (error)
404                 goto bad;
405
406         disc_optim(tp, &tp->t_termios, sc);
407
408         DPRINTF(("%s: ucomopen: success\n", device_get_nameunit(sc->sc_dev)));
409
410         sc->sc_poll = 1;
411         sc->sc_refcnt++;
412
413         return (0);
414
415 fail_4:
416         usbd_free_xfer(sc->sc_oxfer);
417         sc->sc_oxfer = NULL;
418 fail_3:
419         usbd_free_xfer(sc->sc_ixfer);
420         sc->sc_ixfer = NULL;
421 fail_2:
422         usbd_close_pipe(sc->sc_bulkout_pipe);
423         sc->sc_bulkout_pipe = NULL;
424 fail_1:
425         usbd_close_pipe(sc->sc_bulkin_pipe);
426         sc->sc_bulkin_pipe = NULL;
427 fail_0:
428         sc->sc_opening = 0;
429         wakeup(&sc->sc_opening);
430         crit_exit();
431         return (error);
432
433 bad:
434         if (!ISSET(tp->t_state, TS_ISOPEN)) {
435                 /*
436                  * We failed to open the device, and nobody else had it opened.
437                  * Clean up the state as appropriate.
438                  */
439                 ucom_cleanup(sc);
440         }
441
442         DPRINTF(("%s: ucomopen: failed\n", device_get_nameunit(sc->sc_dev)));
443
444         return (error);
445 }
446
447 static int
448 ucomclose(struct dev_close_args *ap)
449 {
450         cdev_t dev = ap->a_head.a_dev;
451         struct ucom_softc *sc;
452         struct tty *tp;
453
454         sc = devclass_get_softc(ucom_devclass, UCOMUNIT(dev));
455
456         tp = sc->sc_tty;
457
458         DPRINTF(("%s: ucomclose: unit = %d\n",
459                 device_get_nameunit(sc->sc_dev), UCOMUNIT(dev)));
460
461         if (!ISSET(tp->t_state, TS_ISOPEN))
462                 goto quit;
463
464         crit_enter();
465         (*linesw[tp->t_line].l_close)(tp, ap->a_fflag);
466         disc_optim(tp, &tp->t_termios, sc);
467         ttyclose(tp);
468         crit_exit();
469
470         if (sc->sc_dying)
471                 goto quit;
472
473         if (!ISSET(tp->t_state, TS_ISOPEN)) {
474                 /*
475                  * Although we got a last close, the device may still be in
476                  * use; e.g. if this was the dialout node, and there are still
477                  * processes waiting for carrier on the non-dialout node.
478                  */
479                 ucom_cleanup(sc);
480         }
481
482         if (sc->sc_callback->ucom_close != NULL)
483                 sc->sc_callback->ucom_close(sc->sc_parent, sc->sc_portno);
484
485 quit:
486         if (tp->t_dev) {
487                 release_dev(tp->t_dev);
488                 tp->t_dev = NULL;
489         }
490
491         if (--sc->sc_refcnt < 0)
492                 usb_detach_wakeup(sc->sc_dev);
493
494         return (0);
495 }
496
497 static int
498 ucomread(struct dev_read_args *ap)
499 {
500         cdev_t dev = ap->a_head.a_dev;
501         struct ucom_softc *sc;
502         struct tty *tp;
503         int error;
504
505         sc = devclass_get_softc(ucom_devclass, UCOMUNIT(dev));
506         tp = sc->sc_tty;
507
508         DPRINTF(("ucomread: tp = %p, flag = 0x%x\n", tp, ap->a_ioflag));
509
510         if (sc->sc_dying)
511                 return (EIO);
512
513         error = (*linesw[tp->t_line].l_read)(tp, ap->a_uio, ap->a_ioflag);
514
515         DPRINTF(("ucomread: error = %d\n", error));
516
517         return (error);
518 }
519
520 static int
521 ucomwrite(struct dev_write_args *ap)
522 {
523         cdev_t dev = ap->a_head.a_dev;
524         struct ucom_softc *sc;
525         struct tty *tp;
526         int error;
527
528         sc = devclass_get_softc(ucom_devclass, UCOMUNIT(dev));
529         tp = sc->sc_tty;
530
531         DPRINTF(("ucomwrite: tp = %p, flag = 0x%x\n", tp, ap->a_ioflag));
532
533         if (sc->sc_dying)
534                 return (EIO);
535
536         error = (*linesw[tp->t_line].l_write)(tp, ap->a_uio, ap->a_ioflag);
537
538         DPRINTF(("ucomwrite: error = %d\n", error));
539
540         return (error);
541 }
542
543 static int
544 ucomioctl(struct dev_ioctl_args *ap)
545 {
546         cdev_t dev = ap->a_head.a_dev;
547         struct ucom_softc *sc;
548         struct tty *tp;
549         int error;
550         int d;
551
552         sc = devclass_get_softc(ucom_devclass, UCOMUNIT(dev));
553         tp = sc->sc_tty;
554
555         if (sc->sc_dying)
556                 return (EIO);
557
558         DPRINTF(("ucomioctl: cmd = 0x%08lx\n", ap->a_cmd));
559
560         error = (*linesw[tp->t_line].l_ioctl)(tp, ap->a_cmd, ap->a_data,
561                                               ap->a_fflag, ap->a_cred);
562         if (error != ENOIOCTL) {
563                 DPRINTF(("ucomioctl: l_ioctl: error = %d\n", error));
564                 return (error);
565         }
566
567         crit_enter();
568
569         error = ttioctl(tp, ap->a_cmd, ap->a_data, ap->a_fflag);
570         disc_optim(tp, &tp->t_termios, sc);
571         if (error != ENOIOCTL) {
572                 crit_exit();
573                 DPRINTF(("ucomioctl: ttioctl: error = %d\n", error));
574                 return (error);
575         }
576
577         if (sc->sc_callback->ucom_ioctl != NULL) {
578                 error = sc->sc_callback->ucom_ioctl(sc->sc_parent,
579                                                     sc->sc_portno,
580                                                     ap->a_cmd, ap->a_data,
581                                                     ap->a_fflag, curthread);
582                 if (error >= 0) {
583                         crit_exit();
584                         return (error);
585                 }
586         }
587
588         error = 0;
589
590         DPRINTF(("ucomioctl: our cmd = 0x%08lx\n", ap->a_cmd));
591
592         switch (ap->a_cmd) {
593         case TIOCSBRK:
594                 DPRINTF(("ucomioctl: TIOCSBRK\n"));
595                 ucom_break(sc, 1);
596                 break;
597         case TIOCCBRK:
598                 DPRINTF(("ucomioctl: TIOCCBRK\n"));
599                 ucom_break(sc, 0);
600                 break;
601
602         case TIOCSDTR:
603                 DPRINTF(("ucomioctl: TIOCSDTR\n"));
604                 (void)ucomctl(sc, TIOCM_DTR, DMBIS);
605                 break;
606         case TIOCCDTR:
607                 DPRINTF(("ucomioctl: TIOCCDTR\n"));
608                 (void)ucomctl(sc, TIOCM_DTR, DMBIC);
609                 break;
610
611         case TIOCMSET:
612                 d = *(int *)ap->a_data;
613                 DPRINTF(("ucomioctl: TIOCMSET, 0x%x\n", d));
614                 (void)ucomctl(sc, d, DMSET);
615                 break;
616         case TIOCMBIS:
617                 d = *(int *)ap->a_data;
618                 DPRINTF(("ucomioctl: TIOCMBIS, 0x%x\n", d));
619                 (void)ucomctl(sc, d, DMBIS);
620                 break;
621         case TIOCMBIC:
622                 d = *(int *)ap->a_data;
623                 DPRINTF(("ucomioctl: TIOCMBIC, 0x%x\n", d));
624                 (void)ucomctl(sc, d, DMBIC);
625                 break;
626         case TIOCMGET:
627                 d = ucomctl(sc, 0, DMGET);
628                 DPRINTF(("ucomioctl: TIOCMGET, 0x%x\n", d));
629                 *(int *)ap->a_data = d;
630                 break;
631
632         default:
633                 DPRINTF(("ucomioctl: error: our cmd = 0x%08lx\n", ap->a_cmd));
634                 error = ENOTTY;
635                 break;
636         }
637
638         crit_exit();
639
640         return (error);
641 }
642
643 static int
644 ucomctl(struct ucom_softc *sc, int bits, int how)
645 {
646         int     mcr;
647         int     msr;
648         int     onoff;
649
650         DPRINTF(("ucomctl: bits = 0x%x, how = %d\n", bits, how));
651
652         if (how == DMGET) {
653                 SET(bits, TIOCM_LE);            /* always set TIOCM_LE bit */
654                 DPRINTF(("ucomctl: DMGET: LE"));
655
656                 mcr = sc->sc_mcr;
657                 if (ISSET(mcr, UMCR_DTR)) {
658                         SET(bits, TIOCM_DTR);
659                         DPRINTF((" DTR"));
660                 }
661                 if (ISSET(mcr, UMCR_RTS)) {
662                         SET(bits, TIOCM_RTS);
663                         DPRINTF((" RTS"));
664                 }
665
666                 msr = sc->sc_msr;
667                 if (ISSET(msr, UMSR_CTS)) {
668                         SET(bits, TIOCM_CTS);
669                         DPRINTF((" CTS"));
670                 }
671                 if (ISSET(msr, UMSR_DCD)) {
672                         SET(bits, TIOCM_CD);
673                         DPRINTF((" CD"));
674                 }
675                 if (ISSET(msr, UMSR_DSR)) {
676                         SET(bits, TIOCM_DSR);
677                         DPRINTF((" DSR"));
678                 }
679                 if (ISSET(msr, UMSR_RI)) {
680                         SET(bits, TIOCM_RI);
681                         DPRINTF((" RI"));
682                 }
683
684                 DPRINTF(("\n"));
685
686                 return (bits);
687         }
688
689         mcr = 0;
690         if (ISSET(bits, TIOCM_DTR))
691                 SET(mcr, UMCR_DTR);
692         if (ISSET(bits, TIOCM_RTS))
693                 SET(mcr, UMCR_RTS);
694
695         switch (how) {
696         case DMSET:
697                 sc->sc_mcr = mcr;
698                 break;
699         case DMBIS:
700                 sc->sc_mcr |= mcr;
701                 break;
702         case DMBIC:
703                 sc->sc_mcr &= ~mcr;
704                 break;
705         }
706
707         onoff = ISSET(sc->sc_mcr, UMCR_DTR) ? 1 : 0;
708         ucom_dtr(sc, onoff);
709
710         onoff = ISSET(sc->sc_mcr, UMCR_RTS) ? 1 : 0;
711         ucom_rts(sc, onoff);
712
713         return (0);
714 }
715
716 static void
717 ucom_break(struct ucom_softc *sc, int onoff)
718 {
719         DPRINTF(("ucom_break: onoff = %d\n", onoff));
720
721         if (sc->sc_callback->ucom_set == NULL)
722                 return;
723         sc->sc_callback->ucom_set(sc->sc_parent, sc->sc_portno,
724                                   UCOM_SET_BREAK, onoff);
725 }
726
727 static void
728 ucom_dtr(struct ucom_softc *sc, int onoff)
729 {
730         DPRINTF(("ucom_dtr: onoff = %d\n", onoff));
731
732         if (sc->sc_callback->ucom_set == NULL)
733                 return;
734         sc->sc_callback->ucom_set(sc->sc_parent, sc->sc_portno,
735                                   UCOM_SET_DTR, onoff);
736 }
737
738 static void
739 ucom_rts(struct ucom_softc *sc, int onoff)
740 {
741         DPRINTF(("ucom_rts: onoff = %d\n", onoff));
742
743         if (sc->sc_callback->ucom_set == NULL)
744                 return;
745         sc->sc_callback->ucom_set(sc->sc_parent, sc->sc_portno,
746                                   UCOM_SET_RTS, onoff);
747 }
748
749 void
750 ucom_status_change(struct ucom_softc *sc)
751 {
752         struct tty *tp = sc->sc_tty;
753         u_char old_msr;
754         int onoff;
755
756         if (sc->sc_callback->ucom_get_status == NULL) {
757                 sc->sc_lsr = 0;
758                 sc->sc_msr = 0;
759                 return;
760         }
761
762         old_msr = sc->sc_msr;
763         sc->sc_callback->ucom_get_status(sc->sc_parent, sc->sc_portno,
764                                          &sc->sc_lsr, &sc->sc_msr);
765         if (ISSET((sc->sc_msr ^ old_msr), UMSR_DCD)) {
766                 if (sc->sc_poll == 0)
767                         return;
768                 onoff = ISSET(sc->sc_msr, UMSR_DCD) ? 1 : 0;
769                 DPRINTF(("ucom_status_change: DCD changed to %d\n", onoff));
770                 (*linesw[tp->t_line].l_modem)(tp, onoff);
771         }
772 }
773
774 static int
775 ucomparam(struct tty *tp, struct termios *t)
776 {
777         struct ucom_softc *sc;
778         int error;
779         usbd_status uerr;
780
781         sc = devclass_get_softc(ucom_devclass, UCOMUNIT(tp->t_dev));
782
783         if (sc->sc_dying)
784                 return (EIO);
785
786         DPRINTF(("ucomparam: sc = %p\n", sc));
787
788         /* Check requested parameters. */
789         if (t->c_ospeed < 0) {
790                 DPRINTF(("ucomparam: negative ospeed\n"));
791                 return (EINVAL);
792         }
793         if (t->c_ispeed && t->c_ispeed != t->c_ospeed) {
794                 DPRINTF(("ucomparam: mismatch ispeed and ospeed\n"));
795                 return (EINVAL);
796         }
797
798         /*
799          * If there were no changes, don't do anything.  This avoids dropping
800          * input and improves performance when all we did was frob things like
801          * VMIN and VTIME.
802          */
803         if (tp->t_ospeed == t->c_ospeed &&
804             tp->t_cflag == t->c_cflag)
805                 return (0);
806
807         /* And copy to tty. */
808         tp->t_ispeed = 0;
809         tp->t_ospeed = t->c_ospeed;
810         tp->t_cflag = t->c_cflag;
811
812         if (sc->sc_callback->ucom_param == NULL)
813                 return (0);
814
815         ucomstopread(sc);
816
817         error = sc->sc_callback->ucom_param(sc->sc_parent, sc->sc_portno, t);
818         if (error) {
819                 DPRINTF(("ucomparam: callback: error = %d\n", error));
820                 return (error);
821         }
822
823         ttsetwater(tp);
824
825         if (t->c_cflag & CRTS_IFLOW) {
826                 sc->sc_state |= UCS_RTS_IFLOW;
827         } else if (sc->sc_state & UCS_RTS_IFLOW) {
828                 sc->sc_state &= ~UCS_RTS_IFLOW;
829                 (void)ucomctl(sc, UMCR_RTS, DMBIS);
830         }
831
832         disc_optim(tp, t, sc);
833
834         uerr = ucomstartread(sc);
835         if (uerr != USBD_NORMAL_COMPLETION)
836                 return (EIO);
837
838         return (0);
839 }
840
841 static void
842 ucomstart(struct tty *tp)
843 {
844         struct ucom_softc *sc;
845         struct cblock *cbp;
846         usbd_status err;
847         u_char *data;
848         int cnt;
849
850         sc = devclass_get_softc(ucom_devclass, UCOMUNIT(tp->t_dev));
851         DPRINTF(("ucomstart: sc = %p\n", sc));
852
853         if (sc->sc_dying)
854                 return;
855
856         crit_enter();
857
858         if (tp->t_state & TS_TBLOCK) {
859                 if (ISSET(sc->sc_mcr, UMCR_RTS) &&
860                     ISSET(sc->sc_state, UCS_RTS_IFLOW)) {
861                         DPRINTF(("ucomstart: clear RTS\n"));
862                         (void)ucomctl(sc, UMCR_RTS, DMBIC);
863                 }
864         } else {
865                 if (!ISSET(sc->sc_mcr, UMCR_RTS) &&
866                     tp->t_rawq.c_cc <= tp->t_ilowat &&
867                     ISSET(sc->sc_state, UCS_RTS_IFLOW)) {
868                         DPRINTF(("ucomstart: set RTS\n"));
869                         (void)ucomctl(sc, UMCR_RTS, DMBIS);
870                 }
871         }
872
873         if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) {
874                 ttwwakeup(tp);
875                 DPRINTF(("ucomstart: stopped\n"));
876                 goto out;
877         }
878
879         if (tp->t_outq.c_cc <= tp->t_olowat) {
880                 if (ISSET(tp->t_state, TS_SO_OLOWAT)) {
881                         CLR(tp->t_state, TS_SO_OLOWAT);
882                         wakeup(TSA_OLOWAT(tp));
883                 }
884                 selwakeuppri(&tp->t_wsel, TTIPRI);
885                 if (tp->t_outq.c_cc == 0) {
886                         if (ISSET(tp->t_state, TS_BUSY | TS_SO_OCOMPLETE) ==
887                             TS_SO_OCOMPLETE && tp->t_outq.c_cc == 0) {
888                                 CLR(tp->t_state, TS_SO_OCOMPLETE);
889                                 wakeup(TSA_OCOMPLETE(tp));
890                         }
891                         goto out;
892                 }
893         }
894
895         /* Grab the first contiguous region of buffer space. */
896         data = tp->t_outq.c_cf;
897         cbp = (struct cblock *) ((intptr_t) tp->t_outq.c_cf & ~CROUND);
898         cnt = min((char *) (cbp+1) - tp->t_outq.c_cf, tp->t_outq.c_cc);
899
900         if (cnt == 0) {
901                 DPRINTF(("ucomstart: cnt == 0\n"));
902                 goto out;
903         }
904
905         SET(tp->t_state, TS_BUSY);
906
907         if (cnt > sc->sc_obufsize) {
908                 DPRINTF(("ucomstart: big buffer %d chars\n", cnt));
909                 cnt = sc->sc_obufsize;
910         }
911         if (sc->sc_callback->ucom_write != NULL)
912                 sc->sc_callback->ucom_write(sc->sc_parent, sc->sc_portno,
913                                             sc->sc_obuf, data, &cnt);
914         else
915                 memcpy(sc->sc_obuf, data, cnt);
916
917         DPRINTF(("ucomstart: %d chars\n", cnt));
918         usbd_setup_xfer(sc->sc_oxfer, sc->sc_bulkout_pipe,
919                         (usbd_private_handle)sc, sc->sc_obuf, cnt,
920                         USBD_NO_COPY, USBD_NO_TIMEOUT, ucomwritecb);
921         /* What can we do on error? */
922         err = usbd_transfer(sc->sc_oxfer);
923         if (err != USBD_IN_PROGRESS)
924                 kprintf("ucomstart: err=%s\n", usbd_errstr(err));
925
926         ttwwakeup(tp);
927
928     out:
929         crit_exit();
930 }
931
932 static void
933 ucomstop(struct tty *tp, int flag)
934 {
935         struct ucom_softc *sc;
936
937         sc = devclass_get_softc(ucom_devclass, UCOMUNIT(tp->t_dev));
938
939         DPRINTF(("ucomstop: %d\n", flag));
940
941         if (flag & FREAD) {
942                 /*
943                  * This is just supposed to flush pending receive data,
944                  * not stop the reception of data entirely!
945                  */
946                 DPRINTF(("ucomstop: read\n"));
947                 ucomstopread(sc);
948                 ucomstartread(sc);
949         }
950
951         if (flag & FWRITE) {
952                 DPRINTF(("ucomstop: write\n"));
953                 crit_enter();
954                 if (ISSET(tp->t_state, TS_BUSY)) {
955                         /* XXX do what? */
956                         if (!ISSET(tp->t_state, TS_TTSTOP))
957                                 SET(tp->t_state, TS_FLUSH);
958                 }
959                 crit_exit();
960         }
961
962         DPRINTF(("ucomstop: done\n"));
963 }
964
965 static void
966 ucomwritecb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
967 {
968         struct ucom_softc *sc = (struct ucom_softc *)p;
969         struct tty *tp = sc->sc_tty;
970         u_int32_t cc;
971
972         DPRINTF(("ucomwritecb: status = %d\n", status));
973
974         if (status == USBD_CANCELLED || sc->sc_dying)
975                 goto error;
976
977         if (status != USBD_NORMAL_COMPLETION) {
978                 kprintf("%s: ucomwritecb: %s\n",
979                        device_get_nameunit(sc->sc_dev), usbd_errstr(status));
980                 if (status == USBD_STALLED)
981                         usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
982                 /*
983                  * XXX.  We may need a flag to sequence ucomstopread() and
984                  * ucomstartread() to handle the case where ucomstartread()
985                  * is called after ucomstopread() but before the request has
986                  * been properly canceled?
987                  */
988                 goto error;
989         }
990
991         usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);
992         DPRINTF(("ucomwritecb: cc = %d\n", cc));
993         if (cc <= sc->sc_opkthdrlen) {
994                 kprintf("%s: sent size too small, cc = %d\n",
995                         device_get_nameunit(sc->sc_dev), cc);
996                 goto error;
997         }
998
999         /* convert from USB bytes to tty bytes */
1000         cc -= sc->sc_opkthdrlen;
1001
1002         crit_enter();
1003         CLR(tp->t_state, TS_BUSY);
1004         if (ISSET(tp->t_state, TS_FLUSH))
1005                 CLR(tp->t_state, TS_FLUSH);
1006         else
1007                 ndflush(&tp->t_outq, cc);
1008         (*linesw[tp->t_line].l_start)(tp);
1009         crit_exit();
1010
1011         return;
1012
1013   error:
1014         crit_enter();
1015         CLR(tp->t_state, TS_BUSY);
1016         crit_exit();
1017         return;
1018 }
1019
1020 static usbd_status
1021 ucomstartread(struct ucom_softc *sc)
1022 {
1023         usbd_status err;
1024
1025         DPRINTF(("ucomstartread: start\n"));
1026
1027         sc->sc_state &= ~UCS_RXSTOP;
1028
1029         if (sc->sc_bulkin_pipe == NULL)
1030                 return (USBD_NORMAL_COMPLETION);
1031
1032         usbd_setup_xfer(sc->sc_ixfer, sc->sc_bulkin_pipe,
1033                         (usbd_private_handle)sc,
1034                         sc->sc_ibuf, sc->sc_ibufsize,
1035                         USBD_SHORT_XFER_OK | USBD_NO_COPY,
1036                         USBD_NO_TIMEOUT, ucomreadcb);
1037
1038         err = usbd_transfer(sc->sc_ixfer);
1039         if (err != USBD_IN_PROGRESS) {
1040                 DPRINTF(("ucomstartread: err = %s\n", usbd_errstr(err)));
1041                 return (err);
1042         }
1043
1044         return (USBD_NORMAL_COMPLETION);
1045 }
1046
1047 static void
1048 ucomreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
1049 {
1050         struct ucom_softc *sc = (struct ucom_softc *)p;
1051         struct tty *tp = sc->sc_tty;
1052         int (*rint) (int c, struct tty *tp) = linesw[tp->t_line].l_rint;
1053         usbd_status err;
1054         u_int32_t cc;
1055         u_char *cp;
1056         int lostcc;
1057
1058         DPRINTF(("ucomreadcb: status = %d\n", status));
1059
1060         if (status != USBD_NORMAL_COMPLETION) {
1061                 if (!(sc->sc_state & UCS_RXSTOP))
1062                         kprintf("%s: ucomreadcb: %s\n",
1063                                device_get_nameunit(sc->sc_dev), usbd_errstr(status));
1064                 if (status == USBD_STALLED)
1065                         usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
1066                 /* XXX we should restart after some delay. */
1067                 return;
1068         }
1069
1070         usbd_get_xfer_status(xfer, NULL, (void **)&cp, &cc, NULL);
1071         DPRINTF(("ucomreadcb: got %d chars, tp = %p\n", cc, tp));
1072         if (cc == 0)
1073                 goto resubmit;
1074
1075         if (sc->sc_callback->ucom_read != NULL) {
1076                 sc->sc_callback->ucom_read(sc->sc_parent, sc->sc_portno,
1077                                            &cp, &cc);
1078         }
1079
1080         if (cc > sc->sc_ibufsize) {
1081                 kprintf("%s: invalid receive data size, %d chars\n",
1082                         device_get_nameunit(sc->sc_dev), cc);
1083                 goto resubmit;
1084         }
1085         if (cc < 1)
1086                 goto resubmit;
1087
1088         crit_enter();
1089         if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1090                 if (tp->t_rawq.c_cc + cc > tp->t_ihiwat
1091                     && (sc->sc_state & UCS_RTS_IFLOW
1092                         || tp->t_iflag & IXOFF)
1093                     && !(tp->t_state & TS_TBLOCK))
1094                         ttyblock(tp);
1095                 lostcc = b_to_q((char *)cp, cc, &tp->t_rawq);
1096                 tp->t_rawcc += cc;
1097                 if (sc->hotchar) {
1098                         while (cc) {
1099                                 if (*cp == sc->hotchar)
1100                                         break;
1101                                 --cc;
1102                                 ++cp;
1103                         }
1104                         if (cc)
1105                                 setsofttty();
1106                 }
1107                 ttwakeup(tp);
1108                 if (tp->t_state & TS_TTSTOP
1109                     && (tp->t_iflag & IXANY
1110                         || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
1111                         tp->t_state &= ~TS_TTSTOP;
1112                         tp->t_lflag &= ~FLUSHO;
1113                         ucomstart(tp);
1114                 }
1115                 if (lostcc > 0)
1116                         kprintf("%s: lost %d chars\n", device_get_nameunit(sc->sc_dev),
1117                                lostcc);
1118         } else {
1119                 /* Give characters to tty layer. */
1120                 while (cc > 0) {
1121                         DPRINTFN(7, ("ucomreadcb: char = 0x%02x\n", *cp));
1122                         if ((*rint)(*cp, tp) == -1) {
1123                                 /* XXX what should we do? */
1124                                 kprintf("%s: lost %d chars\n",
1125                                        device_get_nameunit(sc->sc_dev), cc);
1126                                 break;
1127                         }
1128                         cc--;
1129                         cp++;
1130                 }
1131         }
1132         crit_exit();
1133
1134 resubmit:
1135         err = ucomstartread(sc);
1136         if (err) {
1137                 kprintf("%s: read start failed\n", device_get_nameunit(sc->sc_dev));
1138                 /* XXX what should we dow now? */
1139         }
1140
1141         if ((sc->sc_state & UCS_RTS_IFLOW) && !ISSET(sc->sc_mcr, UMCR_RTS)
1142             && !(tp->t_state & TS_TBLOCK))
1143                 ucomctl(sc, UMCR_RTS, DMBIS);
1144 }
1145
1146 static void
1147 ucom_cleanup(struct ucom_softc *sc)
1148 {
1149         DPRINTF(("ucom_cleanup: closing pipes\n"));
1150
1151         ucom_shutdown(sc);
1152         if (sc->sc_bulkin_pipe != NULL) {
1153                 usbd_abort_pipe(sc->sc_bulkin_pipe);
1154                 usbd_close_pipe(sc->sc_bulkin_pipe);
1155                 sc->sc_bulkin_pipe = NULL;
1156         }
1157         if (sc->sc_bulkout_pipe != NULL) {
1158                 usbd_abort_pipe(sc->sc_bulkout_pipe);
1159                 usbd_close_pipe(sc->sc_bulkout_pipe);
1160                 sc->sc_bulkout_pipe = NULL;
1161         }
1162         if (sc->sc_ixfer != NULL) {
1163                 usbd_free_xfer(sc->sc_ixfer);
1164                 sc->sc_ixfer = NULL;
1165         }
1166         if (sc->sc_oxfer != NULL) {
1167                 usbd_free_xfer(sc->sc_oxfer);
1168                 sc->sc_oxfer = NULL;
1169         }
1170 }
1171
1172 static void
1173 ucomstopread(struct ucom_softc *sc)
1174 {
1175         usbd_status err;
1176
1177         DPRINTF(("ucomstopread: enter\n"));
1178
1179         if (!(sc->sc_state & UCS_RXSTOP)) {
1180                 sc->sc_state |= UCS_RXSTOP;
1181                 if (sc->sc_bulkin_pipe == NULL) {
1182                         DPRINTF(("ucomstopread: bulkin pipe NULL\n"));
1183                         return;
1184                 }
1185                 err = usbd_abort_pipe(sc->sc_bulkin_pipe);
1186                 if (err) {
1187                         DPRINTF(("ucomstopread: err = %s\n",
1188                                  usbd_errstr(err)));
1189                 }
1190         }
1191
1192         DPRINTF(("ucomstopread: leave\n"));
1193 }
1194
1195 static void
1196 disc_optim(struct tty *tp, struct termios *t, struct ucom_softc *sc)
1197 {
1198         if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
1199             && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
1200             && (!(t->c_iflag & PARMRK)
1201                 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
1202             && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
1203             && linesw[tp->t_line].l_rint == ttyinput) {
1204                 DPRINTF(("disc_optim: bypass l_rint\n"));
1205                 tp->t_state |= TS_CAN_BYPASS_L_RINT;
1206         } else {
1207                 DPRINTF(("disc_optim: can't bypass l_rint\n"));
1208                 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
1209         }
1210         sc->hotchar = linesw[tp->t_line].l_hotchar;
1211 }