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