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.31 2007/08/07 13:14:11 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);
212 DPRINTF(("ucom_detach: no tty\n"));
217 if (--sc
->sc_refcnt
>= 0) {
218 /* Wait for processes to go away. */
219 usb_detach_wait(sc
->sc_dev
);
223 unit
= device_get_unit(sc
->sc_dev
);
224 dev_ops_remove(&ucom_ops
, UCOMUNIT_MASK
, unit
);
230 ucom_shutdown(struct ucom_softc
*sc
)
232 struct tty
*tp
= sc
->sc_tty
;
234 DPRINTF(("ucom_shutdown\n"));
236 * Hang up if necessary. Wait a bit, so the other side has time to
237 * notice even if we immediately open the port again.
239 if (ISSET(tp
->t_cflag
, HUPCL
)) {
240 (void)ucomctl(sc
, TIOCM_DTR
, DMBIC
);
241 (void)tsleep(sc
, 0, "ucomsd", hz
);
246 ucomopen(struct dev_open_args
*ap
)
248 cdev_t dev
= ap
->a_head
.a_dev
;
249 int unit
= UCOMUNIT(dev
);
250 struct ucom_softc
*sc
;
255 sc
= devclass_get_softc(ucom_devclass
, unit
);
264 DPRINTF(("%s: ucomopen: tp = %p\n", device_get_nameunit(sc
->sc_dev
), tp
));
266 if (ISSET(tp
->t_state
, TS_ISOPEN
) &&
267 ISSET(tp
->t_state
, TS_XCLUDE
) &&
268 suser_cred(ap
->a_cred
, 0)
274 * Do the following iff this is a first open.
277 while (sc
->sc_opening
)
278 tsleep(&sc
->sc_opening
, 0, "ucomop", 0);
281 if (!ISSET(tp
->t_state
, TS_ISOPEN
)) {
285 sc
->sc_lsr
= sc
->sc_msr
= sc
->sc_mcr
= 0;
287 tp
->t_dev
= reference_dev(dev
);
290 * Initialize the termios status to the defaults. Add in the
291 * sticky bits from TIOCSFLAGS.
294 t
.c_ospeed
= TTYDEF_SPEED
;
295 t
.c_cflag
= TTYDEF_CFLAG
;
296 /* Make sure ucomparam() will do something. */
298 (void)ucomparam(tp
, &t
);
299 tp
->t_iflag
= TTYDEF_IFLAG
;
300 tp
->t_oflag
= TTYDEF_OFLAG
;
301 tp
->t_lflag
= TTYDEF_LFLAG
;
306 * Turn on DTR. We must always do this, even if carrier is not
307 * present, because otherwise we'd have to use TIOCSDTR
308 * immediately after setting CLOCAL, which applications do not
309 * expect. We always assert DTR while the device is open
310 * unless explicitly requested to deassert it.
312 (void)ucomctl(sc
, TIOCM_DTR
| TIOCM_RTS
, DMBIS
);
314 /* Device specific open */
315 if (sc
->sc_callback
->ucom_open
!= NULL
) {
316 error
= sc
->sc_callback
->ucom_open(sc
->sc_parent
,
321 wakeup(&sc
->sc_opening
);
327 DPRINTF(("ucomopen: open pipes in = %d out = %d\n",
328 sc
->sc_bulkin_no
, sc
->sc_bulkout_no
));
330 /* Open the bulk pipes */
332 err
= usbd_open_pipe(sc
->sc_iface
, sc
->sc_bulkin_no
, 0,
333 &sc
->sc_bulkin_pipe
);
335 kprintf("%s: open bulk in error (addr %d): %s\n",
336 device_get_nameunit(sc
->sc_dev
), sc
->sc_bulkin_no
,
342 err
= usbd_open_pipe(sc
->sc_iface
, sc
->sc_bulkout_no
,
343 USBD_EXCLUSIVE_USE
, &sc
->sc_bulkout_pipe
);
345 kprintf("%s: open bulk out error (addr %d): %s\n",
346 device_get_nameunit(sc
->sc_dev
), sc
->sc_bulkout_no
,
352 /* Allocate a request and an input buffer and start reading. */
353 sc
->sc_ixfer
= usbd_alloc_xfer(sc
->sc_udev
);
354 if (sc
->sc_ixfer
== NULL
) {
359 sc
->sc_ibuf
= usbd_alloc_buffer(sc
->sc_ixfer
,
361 if (sc
->sc_ibuf
== NULL
) {
366 sc
->sc_oxfer
= usbd_alloc_xfer(sc
->sc_udev
);
367 if (sc
->sc_oxfer
== NULL
) {
372 sc
->sc_obuf
= usbd_alloc_buffer(sc
->sc_oxfer
,
375 if (sc
->sc_obuf
== NULL
) {
381 * Handle initial DCD.
383 if (ISSET(sc
->sc_msr
, UMSR_DCD
) ||
384 (minor(dev
) & UCOM_CALLOUT_MASK
))
385 (*linesw
[tp
->t_line
].l_modem
)(tp
, 1);
391 wakeup(&sc
->sc_opening
);
394 error
= ttyopen(dev
, tp
);
398 error
= (*linesw
[tp
->t_line
].l_open
)(dev
, tp
);
402 disc_optim(tp
, &tp
->t_termios
, sc
);
404 DPRINTF(("%s: ucomopen: success\n", device_get_nameunit(sc
->sc_dev
)));
412 usbd_free_xfer(sc
->sc_oxfer
);
415 usbd_free_xfer(sc
->sc_ixfer
);
418 usbd_close_pipe(sc
->sc_bulkout_pipe
);
419 sc
->sc_bulkout_pipe
= NULL
;
421 usbd_close_pipe(sc
->sc_bulkin_pipe
);
422 sc
->sc_bulkin_pipe
= NULL
;
425 wakeup(&sc
->sc_opening
);
430 if (!ISSET(tp
->t_state
, TS_ISOPEN
)) {
432 * We failed to open the device, and nobody else had it opened.
433 * Clean up the state as appropriate.
438 DPRINTF(("%s: ucomopen: failed\n", device_get_nameunit(sc
->sc_dev
)));
444 ucomclose(struct dev_close_args
*ap
)
446 cdev_t dev
= ap
->a_head
.a_dev
;
447 struct ucom_softc
*sc
;
450 sc
= devclass_get_softc(ucom_devclass
, UCOMUNIT(dev
));
454 DPRINTF(("%s: ucomclose: unit = %d\n",
455 device_get_nameunit(sc
->sc_dev
), UCOMUNIT(dev
)));
457 if (!ISSET(tp
->t_state
, TS_ISOPEN
))
461 (*linesw
[tp
->t_line
].l_close
)(tp
, ap
->a_fflag
);
462 disc_optim(tp
, &tp
->t_termios
, sc
);
469 if (!ISSET(tp
->t_state
, TS_ISOPEN
)) {
471 * Although we got a last close, the device may still be in
472 * use; e.g. if this was the dialout node, and there are still
473 * processes waiting for carrier on the non-dialout node.
478 if (sc
->sc_callback
->ucom_close
!= NULL
)
479 sc
->sc_callback
->ucom_close(sc
->sc_parent
, sc
->sc_portno
);
483 release_dev(tp
->t_dev
);
487 if (--sc
->sc_refcnt
< 0)
488 usb_detach_wakeup(sc
->sc_dev
);
494 ucomread(struct dev_read_args
*ap
)
496 cdev_t dev
= ap
->a_head
.a_dev
;
497 struct ucom_softc
*sc
;
501 sc
= devclass_get_softc(ucom_devclass
, UCOMUNIT(dev
));
504 DPRINTF(("ucomread: tp = %p, flag = 0x%x\n", tp
, ap
->a_ioflag
));
509 error
= (*linesw
[tp
->t_line
].l_read
)(tp
, ap
->a_uio
, ap
->a_ioflag
);
511 DPRINTF(("ucomread: error = %d\n", error
));
517 ucomwrite(struct dev_write_args
*ap
)
519 cdev_t dev
= ap
->a_head
.a_dev
;
520 struct ucom_softc
*sc
;
524 sc
= devclass_get_softc(ucom_devclass
, UCOMUNIT(dev
));
527 DPRINTF(("ucomwrite: tp = %p, flag = 0x%x\n", tp
, ap
->a_ioflag
));
532 error
= (*linesw
[tp
->t_line
].l_write
)(tp
, ap
->a_uio
, ap
->a_ioflag
);
534 DPRINTF(("ucomwrite: error = %d\n", error
));
540 ucomioctl(struct dev_ioctl_args
*ap
)
542 cdev_t dev
= ap
->a_head
.a_dev
;
543 struct ucom_softc
*sc
;
548 sc
= devclass_get_softc(ucom_devclass
, UCOMUNIT(dev
));
554 DPRINTF(("ucomioctl: cmd = 0x%08lx\n", ap
->a_cmd
));
556 error
= (*linesw
[tp
->t_line
].l_ioctl
)(tp
, ap
->a_cmd
, ap
->a_data
,
557 ap
->a_fflag
, ap
->a_cred
);
558 if (error
!= ENOIOCTL
) {
559 DPRINTF(("ucomioctl: l_ioctl: error = %d\n", error
));
565 error
= ttioctl(tp
, ap
->a_cmd
, ap
->a_data
, ap
->a_fflag
);
566 disc_optim(tp
, &tp
->t_termios
, sc
);
567 if (error
!= ENOIOCTL
) {
569 DPRINTF(("ucomioctl: ttioctl: error = %d\n", error
));
573 if (sc
->sc_callback
->ucom_ioctl
!= NULL
) {
574 error
= sc
->sc_callback
->ucom_ioctl(sc
->sc_parent
,
576 ap
->a_cmd
, ap
->a_data
,
577 ap
->a_fflag
, curthread
);
586 DPRINTF(("ucomioctl: our cmd = 0x%08lx\n", ap
->a_cmd
));
590 DPRINTF(("ucomioctl: TIOCSBRK\n"));
594 DPRINTF(("ucomioctl: TIOCCBRK\n"));
599 DPRINTF(("ucomioctl: TIOCSDTR\n"));
600 (void)ucomctl(sc
, TIOCM_DTR
, DMBIS
);
603 DPRINTF(("ucomioctl: TIOCCDTR\n"));
604 (void)ucomctl(sc
, TIOCM_DTR
, DMBIC
);
608 d
= *(int *)ap
->a_data
;
609 DPRINTF(("ucomioctl: TIOCMSET, 0x%x\n", d
));
610 (void)ucomctl(sc
, d
, DMSET
);
613 d
= *(int *)ap
->a_data
;
614 DPRINTF(("ucomioctl: TIOCMBIS, 0x%x\n", d
));
615 (void)ucomctl(sc
, d
, DMBIS
);
618 d
= *(int *)ap
->a_data
;
619 DPRINTF(("ucomioctl: TIOCMBIC, 0x%x\n", d
));
620 (void)ucomctl(sc
, d
, DMBIC
);
623 d
= ucomctl(sc
, 0, DMGET
);
624 DPRINTF(("ucomioctl: TIOCMGET, 0x%x\n", d
));
625 *(int *)ap
->a_data
= d
;
629 DPRINTF(("ucomioctl: error: our cmd = 0x%08lx\n", ap
->a_cmd
));
640 ucomctl(struct ucom_softc
*sc
, int bits
, int how
)
646 DPRINTF(("ucomctl: bits = 0x%x, how = %d\n", bits
, how
));
649 SET(bits
, TIOCM_LE
); /* always set TIOCM_LE bit */
650 DPRINTF(("ucomctl: DMGET: LE"));
653 if (ISSET(mcr
, UMCR_DTR
)) {
654 SET(bits
, TIOCM_DTR
);
657 if (ISSET(mcr
, UMCR_RTS
)) {
658 SET(bits
, TIOCM_RTS
);
663 if (ISSET(msr
, UMSR_CTS
)) {
664 SET(bits
, TIOCM_CTS
);
667 if (ISSET(msr
, UMSR_DCD
)) {
671 if (ISSET(msr
, UMSR_DSR
)) {
672 SET(bits
, TIOCM_DSR
);
675 if (ISSET(msr
, UMSR_RI
)) {
686 if (ISSET(bits
, TIOCM_DTR
))
688 if (ISSET(bits
, TIOCM_RTS
))
703 onoff
= ISSET(sc
->sc_mcr
, UMCR_DTR
) ? 1 : 0;
706 onoff
= ISSET(sc
->sc_mcr
, UMCR_RTS
) ? 1 : 0;
713 ucom_break(struct ucom_softc
*sc
, int onoff
)
715 DPRINTF(("ucom_break: onoff = %d\n", onoff
));
717 if (sc
->sc_callback
->ucom_set
== NULL
)
719 sc
->sc_callback
->ucom_set(sc
->sc_parent
, sc
->sc_portno
,
720 UCOM_SET_BREAK
, onoff
);
724 ucom_dtr(struct ucom_softc
*sc
, int onoff
)
726 DPRINTF(("ucom_dtr: onoff = %d\n", onoff
));
728 if (sc
->sc_callback
->ucom_set
== NULL
)
730 sc
->sc_callback
->ucom_set(sc
->sc_parent
, sc
->sc_portno
,
731 UCOM_SET_DTR
, onoff
);
735 ucom_rts(struct ucom_softc
*sc
, int onoff
)
737 DPRINTF(("ucom_rts: onoff = %d\n", onoff
));
739 if (sc
->sc_callback
->ucom_set
== NULL
)
741 sc
->sc_callback
->ucom_set(sc
->sc_parent
, sc
->sc_portno
,
742 UCOM_SET_RTS
, onoff
);
746 ucom_status_change(struct ucom_softc
*sc
)
748 struct tty
*tp
= sc
->sc_tty
;
752 if (sc
->sc_callback
->ucom_get_status
== NULL
) {
758 old_msr
= sc
->sc_msr
;
759 sc
->sc_callback
->ucom_get_status(sc
->sc_parent
, sc
->sc_portno
,
760 &sc
->sc_lsr
, &sc
->sc_msr
);
761 if (ISSET((sc
->sc_msr
^ old_msr
), UMSR_DCD
)) {
762 if (sc
->sc_poll
== 0)
764 onoff
= ISSET(sc
->sc_msr
, UMSR_DCD
) ? 1 : 0;
765 DPRINTF(("ucom_status_change: DCD changed to %d\n", onoff
));
766 (*linesw
[tp
->t_line
].l_modem
)(tp
, onoff
);
771 ucomparam(struct tty
*tp
, struct termios
*t
)
773 struct ucom_softc
*sc
;
777 sc
= devclass_get_softc(ucom_devclass
, UCOMUNIT(tp
->t_dev
));
782 DPRINTF(("ucomparam: sc = %p\n", sc
));
784 /* Check requested parameters. */
785 if (t
->c_ospeed
< 0) {
786 DPRINTF(("ucomparam: negative ospeed\n"));
789 if (t
->c_ispeed
&& t
->c_ispeed
!= t
->c_ospeed
) {
790 DPRINTF(("ucomparam: mismatch ispeed and ospeed\n"));
795 * If there were no changes, don't do anything. This avoids dropping
796 * input and improves performance when all we did was frob things like
799 if (tp
->t_ospeed
== t
->c_ospeed
&&
800 tp
->t_cflag
== t
->c_cflag
)
803 /* And copy to tty. */
805 tp
->t_ospeed
= t
->c_ospeed
;
806 tp
->t_cflag
= t
->c_cflag
;
808 if (sc
->sc_callback
->ucom_param
== NULL
)
813 error
= sc
->sc_callback
->ucom_param(sc
->sc_parent
, sc
->sc_portno
, t
);
815 DPRINTF(("ucomparam: callback: error = %d\n", error
));
821 if (t
->c_cflag
& CRTS_IFLOW
) {
822 sc
->sc_state
|= UCS_RTS_IFLOW
;
823 } else if (sc
->sc_state
& UCS_RTS_IFLOW
) {
824 sc
->sc_state
&= ~UCS_RTS_IFLOW
;
825 (void)ucomctl(sc
, UMCR_RTS
, DMBIS
);
828 disc_optim(tp
, t
, sc
);
830 uerr
= ucomstartread(sc
);
831 if (uerr
!= USBD_NORMAL_COMPLETION
)
838 ucomstart(struct tty
*tp
)
840 struct ucom_softc
*sc
;
846 sc
= devclass_get_softc(ucom_devclass
, UCOMUNIT(tp
->t_dev
));
847 DPRINTF(("ucomstart: sc = %p\n", sc
));
854 if (tp
->t_state
& TS_TBLOCK
) {
855 if (ISSET(sc
->sc_mcr
, UMCR_RTS
) &&
856 ISSET(sc
->sc_state
, UCS_RTS_IFLOW
)) {
857 DPRINTF(("ucomstart: clear RTS\n"));
858 (void)ucomctl(sc
, UMCR_RTS
, DMBIC
);
861 if (!ISSET(sc
->sc_mcr
, UMCR_RTS
) &&
862 tp
->t_rawq
.c_cc
<= tp
->t_ilowat
&&
863 ISSET(sc
->sc_state
, UCS_RTS_IFLOW
)) {
864 DPRINTF(("ucomstart: set RTS\n"));
865 (void)ucomctl(sc
, UMCR_RTS
, DMBIS
);
869 if (ISSET(tp
->t_state
, TS_BUSY
| TS_TIMEOUT
| TS_TTSTOP
)) {
871 DPRINTF(("ucomstart: stopped\n"));
875 if (tp
->t_outq
.c_cc
<= tp
->t_olowat
) {
876 if (ISSET(tp
->t_state
, TS_SO_OLOWAT
)) {
877 CLR(tp
->t_state
, TS_SO_OLOWAT
);
878 wakeup(TSA_OLOWAT(tp
));
880 selwakeup(&tp
->t_wsel
);
881 if (tp
->t_outq
.c_cc
== 0) {
882 if (ISSET(tp
->t_state
, TS_BUSY
| TS_SO_OCOMPLETE
) ==
883 TS_SO_OCOMPLETE
&& tp
->t_outq
.c_cc
== 0) {
884 CLR(tp
->t_state
, TS_SO_OCOMPLETE
);
885 wakeup(TSA_OCOMPLETE(tp
));
891 /* Grab the first contiguous region of buffer space. */
892 data
= tp
->t_outq
.c_cf
;
893 cbp
= (struct cblock
*) ((intptr_t) tp
->t_outq
.c_cf
& ~CROUND
);
894 cnt
= min((char *) (cbp
+1) - tp
->t_outq
.c_cf
, tp
->t_outq
.c_cc
);
897 DPRINTF(("ucomstart: cnt == 0\n"));
901 SET(tp
->t_state
, TS_BUSY
);
903 if (cnt
> sc
->sc_obufsize
) {
904 DPRINTF(("ucomstart: big buffer %d chars\n", cnt
));
905 cnt
= sc
->sc_obufsize
;
907 if (sc
->sc_callback
->ucom_write
!= NULL
)
908 sc
->sc_callback
->ucom_write(sc
->sc_parent
, sc
->sc_portno
,
909 sc
->sc_obuf
, data
, &cnt
);
911 memcpy(sc
->sc_obuf
, data
, cnt
);
913 DPRINTF(("ucomstart: %d chars\n", cnt
));
914 usbd_setup_xfer(sc
->sc_oxfer
, sc
->sc_bulkout_pipe
,
915 (usbd_private_handle
)sc
, sc
->sc_obuf
, cnt
,
916 USBD_NO_COPY
, USBD_NO_TIMEOUT
, ucomwritecb
);
917 /* What can we do on error? */
918 err
= usbd_transfer(sc
->sc_oxfer
);
919 if (err
!= USBD_IN_PROGRESS
)
920 kprintf("ucomstart: err=%s\n", usbd_errstr(err
));
929 ucomstop(struct tty
*tp
, int flag
)
931 struct ucom_softc
*sc
;
933 sc
= devclass_get_softc(ucom_devclass
, UCOMUNIT(tp
->t_dev
));
935 DPRINTF(("ucomstop: %d\n", flag
));
939 * This is just supposed to flush pending receive data,
940 * not stop the reception of data entirely!
942 DPRINTF(("ucomstop: read\n"));
948 DPRINTF(("ucomstop: write\n"));
950 if (ISSET(tp
->t_state
, TS_BUSY
)) {
952 if (!ISSET(tp
->t_state
, TS_TTSTOP
))
953 SET(tp
->t_state
, TS_FLUSH
);
958 DPRINTF(("ucomstop: done\n"));
962 ucomwritecb(usbd_xfer_handle xfer
, usbd_private_handle p
, usbd_status status
)
964 struct ucom_softc
*sc
= (struct ucom_softc
*)p
;
965 struct tty
*tp
= sc
->sc_tty
;
968 DPRINTF(("ucomwritecb: status = %d\n", status
));
970 if (status
== USBD_CANCELLED
|| sc
->sc_dying
)
973 if (status
!= USBD_NORMAL_COMPLETION
) {
974 kprintf("%s: ucomwritecb: %s\n",
975 device_get_nameunit(sc
->sc_dev
), usbd_errstr(status
));
976 if (status
== USBD_STALLED
)
977 usbd_clear_endpoint_stall_async(sc
->sc_bulkin_pipe
);
979 * XXX. We may need a flag to sequence ucomstopread() and
980 * ucomstartread() to handle the case where ucomstartread()
981 * is called after ucomstopread() but before the request has
982 * been properly canceled?
987 usbd_get_xfer_status(xfer
, NULL
, NULL
, &cc
, NULL
);
988 DPRINTF(("ucomwritecb: cc = %d\n", cc
));
989 if (cc
<= sc
->sc_opkthdrlen
) {
990 kprintf("%s: sent size too small, cc = %d\n",
991 device_get_nameunit(sc
->sc_dev
), cc
);
995 /* convert from USB bytes to tty bytes */
996 cc
-= sc
->sc_opkthdrlen
;
999 CLR(tp
->t_state
, TS_BUSY
);
1000 if (ISSET(tp
->t_state
, TS_FLUSH
))
1001 CLR(tp
->t_state
, TS_FLUSH
);
1003 ndflush(&tp
->t_outq
, cc
);
1004 (*linesw
[tp
->t_line
].l_start
)(tp
);
1011 CLR(tp
->t_state
, TS_BUSY
);
1017 ucomstartread(struct ucom_softc
*sc
)
1021 DPRINTF(("ucomstartread: start\n"));
1023 sc
->sc_state
&= ~UCS_RXSTOP
;
1025 if (sc
->sc_bulkin_pipe
== NULL
)
1026 return (USBD_NORMAL_COMPLETION
);
1028 usbd_setup_xfer(sc
->sc_ixfer
, sc
->sc_bulkin_pipe
,
1029 (usbd_private_handle
)sc
,
1030 sc
->sc_ibuf
, sc
->sc_ibufsize
,
1031 USBD_SHORT_XFER_OK
| USBD_NO_COPY
,
1032 USBD_NO_TIMEOUT
, ucomreadcb
);
1034 err
= usbd_transfer(sc
->sc_ixfer
);
1035 if (err
!= USBD_IN_PROGRESS
) {
1036 DPRINTF(("ucomstartread: err = %s\n", usbd_errstr(err
)));
1040 return (USBD_NORMAL_COMPLETION
);
1044 ucomreadcb(usbd_xfer_handle xfer
, usbd_private_handle p
, usbd_status status
)
1046 struct ucom_softc
*sc
= (struct ucom_softc
*)p
;
1047 struct tty
*tp
= sc
->sc_tty
;
1048 int (*rint
) (int c
, struct tty
*tp
) = linesw
[tp
->t_line
].l_rint
;
1054 DPRINTF(("ucomreadcb: status = %d\n", status
));
1056 if (status
!= USBD_NORMAL_COMPLETION
) {
1057 if (!(sc
->sc_state
& UCS_RXSTOP
))
1058 kprintf("%s: ucomreadcb: %s\n",
1059 device_get_nameunit(sc
->sc_dev
), usbd_errstr(status
));
1060 if (status
== USBD_STALLED
)
1061 usbd_clear_endpoint_stall_async(sc
->sc_bulkin_pipe
);
1062 /* XXX we should restart after some delay. */
1066 usbd_get_xfer_status(xfer
, NULL
, (void **)&cp
, &cc
, NULL
);
1067 DPRINTF(("ucomreadcb: got %d chars, tp = %p\n", cc
, tp
));
1071 if (sc
->sc_callback
->ucom_read
!= NULL
) {
1072 sc
->sc_callback
->ucom_read(sc
->sc_parent
, sc
->sc_portno
,
1076 if (cc
> sc
->sc_ibufsize
) {
1077 kprintf("%s: invalid receive data size, %d chars\n",
1078 device_get_nameunit(sc
->sc_dev
), cc
);
1085 if (tp
->t_state
& TS_CAN_BYPASS_L_RINT
) {
1086 if (tp
->t_rawq
.c_cc
+ cc
> tp
->t_ihiwat
1087 && (sc
->sc_state
& UCS_RTS_IFLOW
1088 || tp
->t_iflag
& IXOFF
)
1089 && !(tp
->t_state
& TS_TBLOCK
))
1091 lostcc
= b_to_q((char *)cp
, cc
, &tp
->t_rawq
);
1095 if (*cp
== sc
->hotchar
)
1104 if (tp
->t_state
& TS_TTSTOP
1105 && (tp
->t_iflag
& IXANY
1106 || tp
->t_cc
[VSTART
] == tp
->t_cc
[VSTOP
])) {
1107 tp
->t_state
&= ~TS_TTSTOP
;
1108 tp
->t_lflag
&= ~FLUSHO
;
1112 kprintf("%s: lost %d chars\n", device_get_nameunit(sc
->sc_dev
),
1115 /* Give characters to tty layer. */
1117 DPRINTFN(7, ("ucomreadcb: char = 0x%02x\n", *cp
));
1118 if ((*rint
)(*cp
, tp
) == -1) {
1119 /* XXX what should we do? */
1120 kprintf("%s: lost %d chars\n",
1121 device_get_nameunit(sc
->sc_dev
), cc
);
1131 err
= ucomstartread(sc
);
1133 kprintf("%s: read start failed\n", device_get_nameunit(sc
->sc_dev
));
1134 /* XXX what should we dow now? */
1137 if ((sc
->sc_state
& UCS_RTS_IFLOW
) && !ISSET(sc
->sc_mcr
, UMCR_RTS
)
1138 && !(tp
->t_state
& TS_TBLOCK
))
1139 ucomctl(sc
, UMCR_RTS
, DMBIS
);
1143 ucom_cleanup(struct ucom_softc
*sc
)
1145 DPRINTF(("ucom_cleanup: closing pipes\n"));
1148 if (sc
->sc_bulkin_pipe
!= NULL
) {
1149 usbd_abort_pipe(sc
->sc_bulkin_pipe
);
1150 usbd_close_pipe(sc
->sc_bulkin_pipe
);
1151 sc
->sc_bulkin_pipe
= NULL
;
1153 if (sc
->sc_bulkout_pipe
!= NULL
) {
1154 usbd_abort_pipe(sc
->sc_bulkout_pipe
);
1155 usbd_close_pipe(sc
->sc_bulkout_pipe
);
1156 sc
->sc_bulkout_pipe
= NULL
;
1158 if (sc
->sc_ixfer
!= NULL
) {
1159 usbd_free_xfer(sc
->sc_ixfer
);
1160 sc
->sc_ixfer
= NULL
;
1162 if (sc
->sc_oxfer
!= NULL
) {
1163 usbd_free_xfer(sc
->sc_oxfer
);
1164 sc
->sc_oxfer
= NULL
;
1169 ucomstopread(struct ucom_softc
*sc
)
1173 DPRINTF(("ucomstopread: enter\n"));
1175 if (!(sc
->sc_state
& UCS_RXSTOP
)) {
1176 sc
->sc_state
|= UCS_RXSTOP
;
1177 if (sc
->sc_bulkin_pipe
== NULL
) {
1178 DPRINTF(("ucomstopread: bulkin pipe NULL\n"));
1181 err
= usbd_abort_pipe(sc
->sc_bulkin_pipe
);
1183 DPRINTF(("ucomstopread: err = %s\n",
1188 DPRINTF(("ucomstopread: leave\n"));
1192 disc_optim(struct tty
*tp
, struct termios
*t
, struct ucom_softc
*sc
)
1194 if (!(t
->c_iflag
& (ICRNL
| IGNCR
| IMAXBEL
| INLCR
| ISTRIP
| IXON
))
1195 && (!(t
->c_iflag
& BRKINT
) || (t
->c_iflag
& IGNBRK
))
1196 && (!(t
->c_iflag
& PARMRK
)
1197 || (t
->c_iflag
& (IGNPAR
| IGNBRK
)) == (IGNPAR
| IGNBRK
))
1198 && !(t
->c_lflag
& (ECHO
| ICANON
| IEXTEN
| ISIG
| PENDIN
))
1199 && linesw
[tp
->t_line
].l_rint
== ttyinput
) {
1200 DPRINTF(("disc_optim: bypass l_rint\n"));
1201 tp
->t_state
|= TS_CAN_BYPASS_L_RINT
;
1203 DPRINTF(("disc_optim: can't bypass l_rint\n"));
1204 tp
->t_state
&= ~TS_CAN_BYPASS_L_RINT
;
1206 sc
->hotchar
= linesw
[tp
->t_line
].l_hotchar
;