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.30 2007/08/07 11:30:03 hasso Exp $
8 * Copyright (c) 2001-2002, Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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
34 * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
35 * All rights reserved.
37 * This code is derived from software contributed to The NetBSD Foundation
38 * by Lennart Augustsson (lennart@augustsson.net) at
39 * Carlstedt Research & Technology.
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
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.
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.
70 #include <sys/param.h>
71 #include <sys/systm.h>
72 #include <sys/kernel.h>
73 #include <sys/malloc.h>
75 #include <sys/ioccom.h>
76 #include <sys/fcntl.h>
79 #include <sys/clist.h>
81 #include <sys/select.h>
84 #include <sys/sysctl.h>
85 #include <sys/thread2.h>
87 #include <bus/usb/usb.h>
88 #include <bus/usb/usbcdc.h>
90 #include <bus/usb/usbdi.h>
91 #include <bus/usb/usbdi_util.h>
92 #include <bus/usb/usbdevs.h>
93 #include <bus/usb/usb_quirks.h>
98 static int ucomdebug
= 0;
99 SYSCTL_NODE(_hw_usb
, OID_AUTO
, ucom
, CTLFLAG_RW
, 0, "USB ucom");
100 SYSCTL_INT(_hw_usb_ucom
, OID_AUTO
, debug
, CTLFLAG_RW
,
101 &ucomdebug
, 0, "ucom debug level");
102 #define DPRINTF(x) do { \
107 #define DPRINTFN(n, x) do { \
108 if (ucomdebug > (n)) \
113 #define DPRINTFN(n, x)
116 static d_open_t ucomopen
;
117 static d_close_t ucomclose
;
118 static d_read_t ucomread
;
119 static d_write_t ucomwrite
;
120 static d_ioctl_t ucomioctl
;
122 #define UCOM_CDEV_MAJOR 138
124 static struct dev_ops ucom_ops
= {
125 { "ucom", UCOM_CDEV_MAJOR
, D_TTY
| D_KQFILTER
},
127 .d_close
= ucomclose
,
129 .d_write
= ucomwrite
,
130 .d_ioctl
= ucomioctl
,
132 .d_kqfilter
= ttykqfilter
135 static void ucom_cleanup(struct ucom_softc
*);
136 static int ucomctl(struct ucom_softc
*, int, int);
137 static int ucomparam(struct tty
*, struct termios
*);
138 static void ucomstart(struct tty
*);
139 static void ucomstop(struct tty
*, int);
140 static void ucom_shutdown(struct ucom_softc
*);
141 static void ucom_dtr(struct ucom_softc
*, int);
142 static void ucom_rts(struct ucom_softc
*, int);
143 static void ucom_break(struct ucom_softc
*, int);
144 static usbd_status
ucomstartread(struct ucom_softc
*);
145 static void ucomreadcb(usbd_xfer_handle
, usbd_private_handle
, usbd_status
);
146 static void ucomwritecb(usbd_xfer_handle
, usbd_private_handle
, usbd_status
);
147 static void ucomstopread(struct ucom_softc
*);
148 static void disc_optim(struct tty
*, struct termios
*, struct ucom_softc
*);
150 devclass_t ucom_devclass
;
152 static moduledata_t ucom_mod
= {
158 DECLARE_MODULE(ucom
, ucom_mod
, SI_SUB_DRIVERS
, SI_ORDER_MIDDLE
);
159 MODULE_DEPEND(ucom
, usb
, 1, 1, 1);
160 MODULE_VERSION(ucom
, UCOM_MODVER
);
163 ucom_attach(struct ucom_softc
*sc
)
169 unit
= device_get_unit(sc
->sc_dev
);
171 sc
->sc_tty
= tp
= ttymalloc(sc
->sc_tty
);
172 tp
->t_oproc
= ucomstart
;
173 tp
->t_param
= ucomparam
;
174 tp
->t_stop
= ucomstop
;
176 DPRINTF(("ucom_attach: tty_attach tp = %p\n", tp
));
178 DPRINTF(("ucom_attach: make_dev: ucom%d\n", unit
));
180 dev_ops_add(&ucom_ops
, UCOMUNIT_MASK
, unit
);
181 dev
= make_dev(&ucom_ops
, unit
| UCOM_CALLOUT_MASK
,
182 UID_UUCP
, GID_DIALER
, 0660,
190 ucom_detach(struct ucom_softc
*sc
)
192 struct tty
*tp
= sc
->sc_tty
;
195 DPRINTF(("ucom_detach: sc = %p, tp = %p\n", sc
, sc
->sc_tty
));
199 if (sc
->sc_bulkin_pipe
!= NULL
)
200 usbd_abort_pipe(sc
->sc_bulkin_pipe
);
201 if (sc
->sc_bulkout_pipe
!= NULL
)
202 usbd_abort_pipe(sc
->sc_bulkout_pipe
);
205 if (tp
->t_state
& TS_ISOPEN
) {
206 device_printf(sc
->sc_dev
,
207 "still open, forcing close\n");
208 (*linesw
[tp
->t_line
].l_close
)(tp
, 0);
214 DPRINTF(("ucom_detach: no tty\n"));
219 if (--sc
->sc_refcnt
>= 0) {
220 /* Wait for processes to go away. */
221 usb_detach_wait(sc
->sc_dev
);
225 unit
= device_get_unit(sc
->sc_dev
);
226 dev_ops_remove(&ucom_ops
, UCOMUNIT_MASK
, unit
);
232 ucom_shutdown(struct ucom_softc
*sc
)
234 struct tty
*tp
= sc
->sc_tty
;
236 DPRINTF(("ucom_shutdown\n"));
238 * Hang up if necessary. Wait a bit, so the other side has time to
239 * notice even if we immediately open the port again.
241 if (ISSET(tp
->t_cflag
, HUPCL
)) {
242 (void)ucomctl(sc
, TIOCM_DTR
, DMBIC
);
243 (void)tsleep(sc
, 0, "ucomsd", hz
);
248 ucomopen(struct dev_open_args
*ap
)
250 cdev_t dev
= ap
->a_head
.a_dev
;
251 int unit
= UCOMUNIT(dev
);
252 struct ucom_softc
*sc
;
257 sc
= devclass_get_softc(ucom_devclass
, unit
);
266 DPRINTF(("%s: ucomopen: tp = %p\n", device_get_nameunit(sc
->sc_dev
), tp
));
268 if (ISSET(tp
->t_state
, TS_ISOPEN
) &&
269 ISSET(tp
->t_state
, TS_XCLUDE
) &&
270 suser_cred(ap
->a_cred
, 0)
276 * Do the following iff this is a first open.
279 while (sc
->sc_opening
)
280 tsleep(&sc
->sc_opening
, 0, "ucomop", 0);
283 if (!ISSET(tp
->t_state
, TS_ISOPEN
)) {
287 sc
->sc_lsr
= sc
->sc_msr
= sc
->sc_mcr
= 0;
289 tp
->t_dev
= reference_dev(dev
);
292 * Initialize the termios status to the defaults. Add in the
293 * sticky bits from TIOCSFLAGS.
296 t
.c_ospeed
= TTYDEF_SPEED
;
297 t
.c_cflag
= TTYDEF_CFLAG
;
298 /* Make sure ucomparam() will do something. */
300 (void)ucomparam(tp
, &t
);
301 tp
->t_iflag
= TTYDEF_IFLAG
;
302 tp
->t_oflag
= TTYDEF_OFLAG
;
303 tp
->t_lflag
= TTYDEF_LFLAG
;
308 * Turn on DTR. We must always do this, even if carrier is not
309 * present, because otherwise we'd have to use TIOCSDTR
310 * immediately after setting CLOCAL, which applications do not
311 * expect. We always assert DTR while the device is open
312 * unless explicitly requested to deassert it.
314 (void)ucomctl(sc
, TIOCM_DTR
| TIOCM_RTS
, DMBIS
);
316 /* Device specific open */
317 if (sc
->sc_callback
->ucom_open
!= NULL
) {
318 error
= sc
->sc_callback
->ucom_open(sc
->sc_parent
,
323 wakeup(&sc
->sc_opening
);
329 DPRINTF(("ucomopen: open pipes in = %d out = %d\n",
330 sc
->sc_bulkin_no
, sc
->sc_bulkout_no
));
332 /* Open the bulk pipes */
334 err
= usbd_open_pipe(sc
->sc_iface
, sc
->sc_bulkin_no
, 0,
335 &sc
->sc_bulkin_pipe
);
337 kprintf("%s: open bulk in error (addr %d): %s\n",
338 device_get_nameunit(sc
->sc_dev
), sc
->sc_bulkin_no
,
344 err
= usbd_open_pipe(sc
->sc_iface
, sc
->sc_bulkout_no
,
345 USBD_EXCLUSIVE_USE
, &sc
->sc_bulkout_pipe
);
347 kprintf("%s: open bulk out error (addr %d): %s\n",
348 device_get_nameunit(sc
->sc_dev
), sc
->sc_bulkout_no
,
354 /* Allocate a request and an input buffer and start reading. */
355 sc
->sc_ixfer
= usbd_alloc_xfer(sc
->sc_udev
);
356 if (sc
->sc_ixfer
== NULL
) {
361 sc
->sc_ibuf
= usbd_alloc_buffer(sc
->sc_ixfer
,
363 if (sc
->sc_ibuf
== NULL
) {
368 sc
->sc_oxfer
= usbd_alloc_xfer(sc
->sc_udev
);
369 if (sc
->sc_oxfer
== NULL
) {
374 sc
->sc_obuf
= usbd_alloc_buffer(sc
->sc_oxfer
,
377 if (sc
->sc_obuf
== NULL
) {
383 * Handle initial DCD.
385 if (ISSET(sc
->sc_msr
, UMSR_DCD
) ||
386 (minor(dev
) & UCOM_CALLOUT_MASK
))
387 (*linesw
[tp
->t_line
].l_modem
)(tp
, 1);
393 wakeup(&sc
->sc_opening
);
396 error
= ttyopen(dev
, tp
);
400 error
= (*linesw
[tp
->t_line
].l_open
)(dev
, tp
);
404 disc_optim(tp
, &tp
->t_termios
, sc
);
406 DPRINTF(("%s: ucomopen: success\n", device_get_nameunit(sc
->sc_dev
)));
414 usbd_free_xfer(sc
->sc_oxfer
);
417 usbd_free_xfer(sc
->sc_ixfer
);
420 usbd_close_pipe(sc
->sc_bulkout_pipe
);
421 sc
->sc_bulkout_pipe
= NULL
;
423 usbd_close_pipe(sc
->sc_bulkin_pipe
);
424 sc
->sc_bulkin_pipe
= NULL
;
427 wakeup(&sc
->sc_opening
);
432 if (!ISSET(tp
->t_state
, TS_ISOPEN
)) {
434 * We failed to open the device, and nobody else had it opened.
435 * Clean up the state as appropriate.
440 DPRINTF(("%s: ucomopen: failed\n", device_get_nameunit(sc
->sc_dev
)));
446 ucomclose(struct dev_close_args
*ap
)
448 cdev_t dev
= ap
->a_head
.a_dev
;
449 struct ucom_softc
*sc
;
452 sc
= devclass_get_softc(ucom_devclass
, UCOMUNIT(dev
));
456 DPRINTF(("%s: ucomclose: unit = %d\n",
457 device_get_nameunit(sc
->sc_dev
), UCOMUNIT(dev
)));
459 if (!ISSET(tp
->t_state
, TS_ISOPEN
))
463 (*linesw
[tp
->t_line
].l_close
)(tp
, ap
->a_fflag
);
464 disc_optim(tp
, &tp
->t_termios
, sc
);
471 if (!ISSET(tp
->t_state
, TS_ISOPEN
)) {
473 * Although we got a last close, the device may still be in
474 * use; e.g. if this was the dialout node, and there are still
475 * processes waiting for carrier on the non-dialout node.
480 if (sc
->sc_callback
->ucom_close
!= NULL
)
481 sc
->sc_callback
->ucom_close(sc
->sc_parent
, sc
->sc_portno
);
485 release_dev(tp
->t_dev
);
489 if (--sc
->sc_refcnt
< 0)
490 usb_detach_wakeup(sc
->sc_dev
);
496 ucomread(struct dev_read_args
*ap
)
498 cdev_t dev
= ap
->a_head
.a_dev
;
499 struct ucom_softc
*sc
;
503 sc
= devclass_get_softc(ucom_devclass
, UCOMUNIT(dev
));
506 DPRINTF(("ucomread: tp = %p, flag = 0x%x\n", tp
, ap
->a_ioflag
));
511 error
= (*linesw
[tp
->t_line
].l_read
)(tp
, ap
->a_uio
, ap
->a_ioflag
);
513 DPRINTF(("ucomread: error = %d\n", error
));
519 ucomwrite(struct dev_write_args
*ap
)
521 cdev_t dev
= ap
->a_head
.a_dev
;
522 struct ucom_softc
*sc
;
526 sc
= devclass_get_softc(ucom_devclass
, UCOMUNIT(dev
));
529 DPRINTF(("ucomwrite: tp = %p, flag = 0x%x\n", tp
, ap
->a_ioflag
));
534 error
= (*linesw
[tp
->t_line
].l_write
)(tp
, ap
->a_uio
, ap
->a_ioflag
);
536 DPRINTF(("ucomwrite: error = %d\n", error
));
542 ucomioctl(struct dev_ioctl_args
*ap
)
544 cdev_t dev
= ap
->a_head
.a_dev
;
545 struct ucom_softc
*sc
;
550 sc
= devclass_get_softc(ucom_devclass
, UCOMUNIT(dev
));
556 DPRINTF(("ucomioctl: cmd = 0x%08lx\n", ap
->a_cmd
));
558 error
= (*linesw
[tp
->t_line
].l_ioctl
)(tp
, ap
->a_cmd
, ap
->a_data
,
559 ap
->a_fflag
, ap
->a_cred
);
560 if (error
!= ENOIOCTL
) {
561 DPRINTF(("ucomioctl: l_ioctl: error = %d\n", error
));
567 error
= ttioctl(tp
, ap
->a_cmd
, ap
->a_data
, ap
->a_fflag
);
568 disc_optim(tp
, &tp
->t_termios
, sc
);
569 if (error
!= ENOIOCTL
) {
571 DPRINTF(("ucomioctl: ttioctl: error = %d\n", error
));
575 if (sc
->sc_callback
->ucom_ioctl
!= NULL
) {
576 error
= sc
->sc_callback
->ucom_ioctl(sc
->sc_parent
,
578 ap
->a_cmd
, ap
->a_data
,
579 ap
->a_fflag
, curthread
);
588 DPRINTF(("ucomioctl: our cmd = 0x%08lx\n", ap
->a_cmd
));
592 DPRINTF(("ucomioctl: TIOCSBRK\n"));
596 DPRINTF(("ucomioctl: TIOCCBRK\n"));
601 DPRINTF(("ucomioctl: TIOCSDTR\n"));
602 (void)ucomctl(sc
, TIOCM_DTR
, DMBIS
);
605 DPRINTF(("ucomioctl: TIOCCDTR\n"));
606 (void)ucomctl(sc
, TIOCM_DTR
, DMBIC
);
610 d
= *(int *)ap
->a_data
;
611 DPRINTF(("ucomioctl: TIOCMSET, 0x%x\n", d
));
612 (void)ucomctl(sc
, d
, DMSET
);
615 d
= *(int *)ap
->a_data
;
616 DPRINTF(("ucomioctl: TIOCMBIS, 0x%x\n", d
));
617 (void)ucomctl(sc
, d
, DMBIS
);
620 d
= *(int *)ap
->a_data
;
621 DPRINTF(("ucomioctl: TIOCMBIC, 0x%x\n", d
));
622 (void)ucomctl(sc
, d
, DMBIC
);
625 d
= ucomctl(sc
, 0, DMGET
);
626 DPRINTF(("ucomioctl: TIOCMGET, 0x%x\n", d
));
627 *(int *)ap
->a_data
= d
;
631 DPRINTF(("ucomioctl: error: our cmd = 0x%08lx\n", ap
->a_cmd
));
642 ucomctl(struct ucom_softc
*sc
, int bits
, int how
)
648 DPRINTF(("ucomctl: bits = 0x%x, how = %d\n", bits
, how
));
651 SET(bits
, TIOCM_LE
); /* always set TIOCM_LE bit */
652 DPRINTF(("ucomctl: DMGET: LE"));
655 if (ISSET(mcr
, UMCR_DTR
)) {
656 SET(bits
, TIOCM_DTR
);
659 if (ISSET(mcr
, UMCR_RTS
)) {
660 SET(bits
, TIOCM_RTS
);
665 if (ISSET(msr
, UMSR_CTS
)) {
666 SET(bits
, TIOCM_CTS
);
669 if (ISSET(msr
, UMSR_DCD
)) {
673 if (ISSET(msr
, UMSR_DSR
)) {
674 SET(bits
, TIOCM_DSR
);
677 if (ISSET(msr
, UMSR_RI
)) {
688 if (ISSET(bits
, TIOCM_DTR
))
690 if (ISSET(bits
, TIOCM_RTS
))
705 onoff
= ISSET(sc
->sc_mcr
, UMCR_DTR
) ? 1 : 0;
708 onoff
= ISSET(sc
->sc_mcr
, UMCR_RTS
) ? 1 : 0;
715 ucom_break(struct ucom_softc
*sc
, int onoff
)
717 DPRINTF(("ucom_break: onoff = %d\n", onoff
));
719 if (sc
->sc_callback
->ucom_set
== NULL
)
721 sc
->sc_callback
->ucom_set(sc
->sc_parent
, sc
->sc_portno
,
722 UCOM_SET_BREAK
, onoff
);
726 ucom_dtr(struct ucom_softc
*sc
, int onoff
)
728 DPRINTF(("ucom_dtr: onoff = %d\n", onoff
));
730 if (sc
->sc_callback
->ucom_set
== NULL
)
732 sc
->sc_callback
->ucom_set(sc
->sc_parent
, sc
->sc_portno
,
733 UCOM_SET_DTR
, onoff
);
737 ucom_rts(struct ucom_softc
*sc
, int onoff
)
739 DPRINTF(("ucom_rts: onoff = %d\n", onoff
));
741 if (sc
->sc_callback
->ucom_set
== NULL
)
743 sc
->sc_callback
->ucom_set(sc
->sc_parent
, sc
->sc_portno
,
744 UCOM_SET_RTS
, onoff
);
748 ucom_status_change(struct ucom_softc
*sc
)
750 struct tty
*tp
= sc
->sc_tty
;
754 if (sc
->sc_callback
->ucom_get_status
== NULL
) {
760 old_msr
= sc
->sc_msr
;
761 sc
->sc_callback
->ucom_get_status(sc
->sc_parent
, sc
->sc_portno
,
762 &sc
->sc_lsr
, &sc
->sc_msr
);
763 if (ISSET((sc
->sc_msr
^ old_msr
), UMSR_DCD
)) {
764 if (sc
->sc_poll
== 0)
766 onoff
= ISSET(sc
->sc_msr
, UMSR_DCD
) ? 1 : 0;
767 DPRINTF(("ucom_status_change: DCD changed to %d\n", onoff
));
768 (*linesw
[tp
->t_line
].l_modem
)(tp
, onoff
);
773 ucomparam(struct tty
*tp
, struct termios
*t
)
775 struct ucom_softc
*sc
;
779 sc
= devclass_get_softc(ucom_devclass
, UCOMUNIT(tp
->t_dev
));
784 DPRINTF(("ucomparam: sc = %p\n", sc
));
786 /* Check requested parameters. */
787 if (t
->c_ospeed
< 0) {
788 DPRINTF(("ucomparam: negative ospeed\n"));
791 if (t
->c_ispeed
&& t
->c_ispeed
!= t
->c_ospeed
) {
792 DPRINTF(("ucomparam: mismatch ispeed and ospeed\n"));
797 * If there were no changes, don't do anything. This avoids dropping
798 * input and improves performance when all we did was frob things like
801 if (tp
->t_ospeed
== t
->c_ospeed
&&
802 tp
->t_cflag
== t
->c_cflag
)
805 /* And copy to tty. */
807 tp
->t_ospeed
= t
->c_ospeed
;
808 tp
->t_cflag
= t
->c_cflag
;
810 if (sc
->sc_callback
->ucom_param
== NULL
)
815 error
= sc
->sc_callback
->ucom_param(sc
->sc_parent
, sc
->sc_portno
, t
);
817 DPRINTF(("ucomparam: callback: error = %d\n", error
));
823 if (t
->c_cflag
& CRTS_IFLOW
) {
824 sc
->sc_state
|= UCS_RTS_IFLOW
;
825 } else if (sc
->sc_state
& UCS_RTS_IFLOW
) {
826 sc
->sc_state
&= ~UCS_RTS_IFLOW
;
827 (void)ucomctl(sc
, UMCR_RTS
, DMBIS
);
830 disc_optim(tp
, t
, sc
);
832 uerr
= ucomstartread(sc
);
833 if (uerr
!= USBD_NORMAL_COMPLETION
)
840 ucomstart(struct tty
*tp
)
842 struct ucom_softc
*sc
;
848 sc
= devclass_get_softc(ucom_devclass
, UCOMUNIT(tp
->t_dev
));
849 DPRINTF(("ucomstart: sc = %p\n", sc
));
856 if (tp
->t_state
& TS_TBLOCK
) {
857 if (ISSET(sc
->sc_mcr
, UMCR_RTS
) &&
858 ISSET(sc
->sc_state
, UCS_RTS_IFLOW
)) {
859 DPRINTF(("ucomstart: clear RTS\n"));
860 (void)ucomctl(sc
, UMCR_RTS
, DMBIC
);
863 if (!ISSET(sc
->sc_mcr
, UMCR_RTS
) &&
864 tp
->t_rawq
.c_cc
<= tp
->t_ilowat
&&
865 ISSET(sc
->sc_state
, UCS_RTS_IFLOW
)) {
866 DPRINTF(("ucomstart: set RTS\n"));
867 (void)ucomctl(sc
, UMCR_RTS
, DMBIS
);
871 if (ISSET(tp
->t_state
, TS_BUSY
| TS_TIMEOUT
| TS_TTSTOP
)) {
873 DPRINTF(("ucomstart: stopped\n"));
877 if (tp
->t_outq
.c_cc
<= tp
->t_olowat
) {
878 if (ISSET(tp
->t_state
, TS_SO_OLOWAT
)) {
879 CLR(tp
->t_state
, TS_SO_OLOWAT
);
880 wakeup(TSA_OLOWAT(tp
));
882 selwakeup(&tp
->t_wsel
);
883 if (tp
->t_outq
.c_cc
== 0) {
884 if (ISSET(tp
->t_state
, TS_BUSY
| TS_SO_OCOMPLETE
) ==
885 TS_SO_OCOMPLETE
&& tp
->t_outq
.c_cc
== 0) {
886 CLR(tp
->t_state
, TS_SO_OCOMPLETE
);
887 wakeup(TSA_OCOMPLETE(tp
));
893 /* Grab the first contiguous region of buffer space. */
894 data
= tp
->t_outq
.c_cf
;
895 cbp
= (struct cblock
*) ((intptr_t) tp
->t_outq
.c_cf
& ~CROUND
);
896 cnt
= min((char *) (cbp
+1) - tp
->t_outq
.c_cf
, tp
->t_outq
.c_cc
);
899 DPRINTF(("ucomstart: cnt == 0\n"));
903 SET(tp
->t_state
, TS_BUSY
);
905 if (cnt
> sc
->sc_obufsize
) {
906 DPRINTF(("ucomstart: big buffer %d chars\n", cnt
));
907 cnt
= sc
->sc_obufsize
;
909 if (sc
->sc_callback
->ucom_write
!= NULL
)
910 sc
->sc_callback
->ucom_write(sc
->sc_parent
, sc
->sc_portno
,
911 sc
->sc_obuf
, data
, &cnt
);
913 memcpy(sc
->sc_obuf
, data
, cnt
);
915 DPRINTF(("ucomstart: %d chars\n", cnt
));
916 usbd_setup_xfer(sc
->sc_oxfer
, sc
->sc_bulkout_pipe
,
917 (usbd_private_handle
)sc
, sc
->sc_obuf
, cnt
,
918 USBD_NO_COPY
, USBD_NO_TIMEOUT
, ucomwritecb
);
919 /* What can we do on error? */
920 err
= usbd_transfer(sc
->sc_oxfer
);
921 if (err
!= USBD_IN_PROGRESS
)
922 kprintf("ucomstart: err=%s\n", usbd_errstr(err
));
931 ucomstop(struct tty
*tp
, int flag
)
933 struct ucom_softc
*sc
;
935 sc
= devclass_get_softc(ucom_devclass
, UCOMUNIT(tp
->t_dev
));
937 DPRINTF(("ucomstop: %d\n", flag
));
941 * This is just supposed to flush pending receive data,
942 * not stop the reception of data entirely!
944 DPRINTF(("ucomstop: read\n"));
950 DPRINTF(("ucomstop: write\n"));
952 if (ISSET(tp
->t_state
, TS_BUSY
)) {
954 if (!ISSET(tp
->t_state
, TS_TTSTOP
))
955 SET(tp
->t_state
, TS_FLUSH
);
960 DPRINTF(("ucomstop: done\n"));
964 ucomwritecb(usbd_xfer_handle xfer
, usbd_private_handle p
, usbd_status status
)
966 struct ucom_softc
*sc
= (struct ucom_softc
*)p
;
967 struct tty
*tp
= sc
->sc_tty
;
970 DPRINTF(("ucomwritecb: status = %d\n", status
));
972 if (status
== USBD_CANCELLED
|| sc
->sc_dying
)
975 if (status
!= USBD_NORMAL_COMPLETION
) {
976 kprintf("%s: ucomwritecb: %s\n",
977 device_get_nameunit(sc
->sc_dev
), usbd_errstr(status
));
978 if (status
== USBD_STALLED
)
979 usbd_clear_endpoint_stall_async(sc
->sc_bulkin_pipe
);
981 * XXX. We may need a flag to sequence ucomstopread() and
982 * ucomstartread() to handle the case where ucomstartread()
983 * is called after ucomstopread() but before the request has
984 * been properly canceled?
989 usbd_get_xfer_status(xfer
, NULL
, NULL
, &cc
, NULL
);
990 DPRINTF(("ucomwritecb: cc = %d\n", cc
));
991 if (cc
<= sc
->sc_opkthdrlen
) {
992 kprintf("%s: sent size too small, cc = %d\n",
993 device_get_nameunit(sc
->sc_dev
), cc
);
997 /* convert from USB bytes to tty bytes */
998 cc
-= sc
->sc_opkthdrlen
;
1001 CLR(tp
->t_state
, TS_BUSY
);
1002 if (ISSET(tp
->t_state
, TS_FLUSH
))
1003 CLR(tp
->t_state
, TS_FLUSH
);
1005 ndflush(&tp
->t_outq
, cc
);
1006 (*linesw
[tp
->t_line
].l_start
)(tp
);
1013 CLR(tp
->t_state
, TS_BUSY
);
1019 ucomstartread(struct ucom_softc
*sc
)
1023 DPRINTF(("ucomstartread: start\n"));
1025 sc
->sc_state
&= ~UCS_RXSTOP
;
1027 if (sc
->sc_bulkin_pipe
== NULL
)
1028 return (USBD_NORMAL_COMPLETION
);
1030 usbd_setup_xfer(sc
->sc_ixfer
, sc
->sc_bulkin_pipe
,
1031 (usbd_private_handle
)sc
,
1032 sc
->sc_ibuf
, sc
->sc_ibufsize
,
1033 USBD_SHORT_XFER_OK
| USBD_NO_COPY
,
1034 USBD_NO_TIMEOUT
, ucomreadcb
);
1036 err
= usbd_transfer(sc
->sc_ixfer
);
1037 if (err
!= USBD_IN_PROGRESS
) {
1038 DPRINTF(("ucomstartread: err = %s\n", usbd_errstr(err
)));
1042 return (USBD_NORMAL_COMPLETION
);
1046 ucomreadcb(usbd_xfer_handle xfer
, usbd_private_handle p
, usbd_status status
)
1048 struct ucom_softc
*sc
= (struct ucom_softc
*)p
;
1049 struct tty
*tp
= sc
->sc_tty
;
1050 int (*rint
) (int c
, struct tty
*tp
) = linesw
[tp
->t_line
].l_rint
;
1056 DPRINTF(("ucomreadcb: status = %d\n", status
));
1058 if (status
!= USBD_NORMAL_COMPLETION
) {
1059 if (!(sc
->sc_state
& UCS_RXSTOP
))
1060 kprintf("%s: ucomreadcb: %s\n",
1061 device_get_nameunit(sc
->sc_dev
), usbd_errstr(status
));
1062 if (status
== USBD_STALLED
)
1063 usbd_clear_endpoint_stall_async(sc
->sc_bulkin_pipe
);
1064 /* XXX we should restart after some delay. */
1068 usbd_get_xfer_status(xfer
, NULL
, (void **)&cp
, &cc
, NULL
);
1069 DPRINTF(("ucomreadcb: got %d chars, tp = %p\n", cc
, tp
));
1073 if (sc
->sc_callback
->ucom_read
!= NULL
) {
1074 sc
->sc_callback
->ucom_read(sc
->sc_parent
, sc
->sc_portno
,
1078 if (cc
> sc
->sc_ibufsize
) {
1079 kprintf("%s: invalid receive data size, %d chars\n",
1080 device_get_nameunit(sc
->sc_dev
), cc
);
1087 if (tp
->t_state
& TS_CAN_BYPASS_L_RINT
) {
1088 if (tp
->t_rawq
.c_cc
+ cc
> tp
->t_ihiwat
1089 && (sc
->sc_state
& UCS_RTS_IFLOW
1090 || tp
->t_iflag
& IXOFF
)
1091 && !(tp
->t_state
& TS_TBLOCK
))
1093 lostcc
= b_to_q((char *)cp
, cc
, &tp
->t_rawq
);
1097 if (*cp
== sc
->hotchar
)
1106 if (tp
->t_state
& TS_TTSTOP
1107 && (tp
->t_iflag
& IXANY
1108 || tp
->t_cc
[VSTART
] == tp
->t_cc
[VSTOP
])) {
1109 tp
->t_state
&= ~TS_TTSTOP
;
1110 tp
->t_lflag
&= ~FLUSHO
;
1114 kprintf("%s: lost %d chars\n", device_get_nameunit(sc
->sc_dev
),
1117 /* Give characters to tty layer. */
1119 DPRINTFN(7, ("ucomreadcb: char = 0x%02x\n", *cp
));
1120 if ((*rint
)(*cp
, tp
) == -1) {
1121 /* XXX what should we do? */
1122 kprintf("%s: lost %d chars\n",
1123 device_get_nameunit(sc
->sc_dev
), cc
);
1133 err
= ucomstartread(sc
);
1135 kprintf("%s: read start failed\n", device_get_nameunit(sc
->sc_dev
));
1136 /* XXX what should we dow now? */
1139 if ((sc
->sc_state
& UCS_RTS_IFLOW
) && !ISSET(sc
->sc_mcr
, UMCR_RTS
)
1140 && !(tp
->t_state
& TS_TBLOCK
))
1141 ucomctl(sc
, UMCR_RTS
, DMBIS
);
1145 ucom_cleanup(struct ucom_softc
*sc
)
1147 DPRINTF(("ucom_cleanup: closing pipes\n"));
1150 if (sc
->sc_bulkin_pipe
!= NULL
) {
1151 usbd_abort_pipe(sc
->sc_bulkin_pipe
);
1152 usbd_close_pipe(sc
->sc_bulkin_pipe
);
1153 sc
->sc_bulkin_pipe
= NULL
;
1155 if (sc
->sc_bulkout_pipe
!= NULL
) {
1156 usbd_abort_pipe(sc
->sc_bulkout_pipe
);
1157 usbd_close_pipe(sc
->sc_bulkout_pipe
);
1158 sc
->sc_bulkout_pipe
= NULL
;
1160 if (sc
->sc_ixfer
!= NULL
) {
1161 usbd_free_xfer(sc
->sc_ixfer
);
1162 sc
->sc_ixfer
= NULL
;
1164 if (sc
->sc_oxfer
!= NULL
) {
1165 usbd_free_xfer(sc
->sc_oxfer
);
1166 sc
->sc_oxfer
= NULL
;
1171 ucomstopread(struct ucom_softc
*sc
)
1175 DPRINTF(("ucomstopread: enter\n"));
1177 if (!(sc
->sc_state
& UCS_RXSTOP
)) {
1178 sc
->sc_state
|= UCS_RXSTOP
;
1179 if (sc
->sc_bulkin_pipe
== NULL
) {
1180 DPRINTF(("ucomstopread: bulkin pipe NULL\n"));
1183 err
= usbd_abort_pipe(sc
->sc_bulkin_pipe
);
1185 DPRINTF(("ucomstopread: err = %s\n",
1190 DPRINTF(("ucomstopread: leave\n"));
1194 disc_optim(struct tty
*tp
, struct termios
*t
, struct ucom_softc
*sc
)
1196 if (!(t
->c_iflag
& (ICRNL
| IGNCR
| IMAXBEL
| INLCR
| ISTRIP
| IXON
))
1197 && (!(t
->c_iflag
& BRKINT
) || (t
->c_iflag
& IGNBRK
))
1198 && (!(t
->c_iflag
& PARMRK
)
1199 || (t
->c_iflag
& (IGNPAR
| IGNBRK
)) == (IGNPAR
| IGNBRK
))
1200 && !(t
->c_lflag
& (ECHO
| ICANON
| IEXTEN
| ISIG
| PENDIN
))
1201 && linesw
[tp
->t_line
].l_rint
== ttyinput
) {
1202 DPRINTF(("disc_optim: bypass l_rint\n"));
1203 tp
->t_state
|= TS_CAN_BYPASS_L_RINT
;
1205 DPRINTF(("disc_optim: can't bypass l_rint\n"));
1206 tp
->t_state
&= ~TS_CAN_BYPASS_L_RINT
;
1208 sc
->hotchar
= linesw
[tp
->t_line
].l_hotchar
;