1 /* $NetBSD: ucom.c,v 1.81 2009/12/06 21:40:31 dyoung Exp $ */
4 * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (lennart@augustsson.net) at
9 * Carlstedt Research & Technology.
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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
33 * This code is very heavily based on the 16550 driver, com.c.
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: ucom.c,v 1.81 2009/12/06 21:40:31 dyoung Exp $");
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/ioctl.h>
46 #include <sys/select.h>
48 #include <sys/vnode.h>
49 #include <sys/device.h>
51 #include <sys/queue.h>
52 #include <sys/kauth.h>
53 #if defined(__NetBSD__)
60 #include <dev/usb/usb.h>
62 #include <dev/usb/usbdi.h>
63 #include <dev/usb/usbdi_util.h>
64 #include <dev/usb/usbdevs.h>
65 #include <dev/usb/usb_quirks.h>
67 #include <dev/usb/ucomvar.h>
76 #define DPRINTFN(n, x) if (ucomdebug > (n)) logprintf x
79 #define DPRINTFN(n, x)
81 #define DPRINTF(x) DPRINTFN(0, x)
83 #define UCOMUNIT_MASK 0x3ffff
84 #define UCOMDIALOUT_MASK 0x80000
85 #define UCOMCALLUNIT_MASK 0x40000
87 #define UCOMUNIT(x) (minor(x) & UCOMUNIT_MASK)
88 #define UCOMDIALOUT(x) (minor(x) & UCOMDIALOUT_MASK)
89 #define UCOMCALLUNIT(x) (minor(x) & UCOMCALLUNIT_MASK)
92 * XXX: We can submit multiple input/output buffers to the usb stack
93 * to improve throughput, but the usb stack is too lame to deal with this
94 * in a number of places.
96 #define UCOM_IN_BUFFS 1
97 #define UCOM_OUT_BUFFS 1
100 SIMPLEQ_ENTRY(ucom_buffer
) ub_link
;
101 usbd_xfer_handle ub_xfer
;
108 USBBASEDEVICE sc_dev
; /* base device */
110 usbd_device_handle sc_udev
; /* USB device */
112 usbd_interface_handle sc_iface
; /* data interface */
114 int sc_bulkin_no
; /* bulk in endpoint address */
115 usbd_pipe_handle sc_bulkin_pipe
; /* bulk in pipe */
116 u_int sc_ibufsize
; /* read buffer size */
117 u_int sc_ibufsizepad
; /* read buffer size padded */
118 struct ucom_buffer sc_ibuff
[UCOM_IN_BUFFS
];
119 SIMPLEQ_HEAD(, ucom_buffer
) sc_ibuff_empty
;
120 SIMPLEQ_HEAD(, ucom_buffer
) sc_ibuff_full
;
122 int sc_bulkout_no
; /* bulk out endpoint address */
123 usbd_pipe_handle sc_bulkout_pipe
;/* bulk out pipe */
124 u_int sc_obufsize
; /* write buffer size */
125 u_int sc_opkthdrlen
; /* header length of */
126 struct ucom_buffer sc_obuff
[UCOM_OUT_BUFFS
];
127 SIMPLEQ_HEAD(, ucom_buffer
) sc_obuff_free
;
128 SIMPLEQ_HEAD(, ucom_buffer
) sc_obuff_full
;
132 struct ucom_methods
*sc_methods
;
136 struct tty
*sc_tty
; /* our tty */
140 volatile u_char sc_rx_stopped
;
141 u_char sc_rx_unblock
;
142 u_char sc_tx_stopped
;
145 u_char sc_opening
; /* lock during open */
147 u_char sc_dying
; /* disconnecting */
149 #if defined(__NetBSD__) && NRND > 0
150 rndsource_element_t sc_rndsource
; /* random source */
154 dev_type_open(ucomopen
);
155 dev_type_close(ucomclose
);
156 dev_type_read(ucomread
);
157 dev_type_write(ucomwrite
);
158 dev_type_ioctl(ucomioctl
);
159 dev_type_stop(ucomstop
);
160 dev_type_tty(ucomtty
);
161 dev_type_poll(ucompoll
);
163 const struct cdevsw ucom_cdevsw
= {
164 ucomopen
, ucomclose
, ucomread
, ucomwrite
, ucomioctl
,
165 ucomstop
, ucomtty
, ucompoll
, nommap
, ttykqfilter
, D_TTY
168 static void ucom_cleanup(struct ucom_softc
*);
169 static int ucomparam(struct tty
*, struct termios
*);
170 static int ucomhwiflow(struct tty
*, int);
171 static void ucomstart(struct tty
*);
172 static void ucom_shutdown(struct ucom_softc
*);
173 static int ucom_do_ioctl(struct ucom_softc
*, u_long
, void *,
175 static void ucom_dtr(struct ucom_softc
*, int);
176 static void ucom_rts(struct ucom_softc
*, int);
177 static void ucom_break(struct ucom_softc
*, int);
178 static void tiocm_to_ucom(struct ucom_softc
*, u_long
, int);
179 static int ucom_to_tiocm(struct ucom_softc
*);
181 static void ucomreadcb(usbd_xfer_handle
, usbd_private_handle
, usbd_status
);
182 static void ucom_submit_write(struct ucom_softc
*, struct ucom_buffer
*);
183 static void ucom_write_status(struct ucom_softc
*, struct ucom_buffer
*,
186 static void ucomwritecb(usbd_xfer_handle
, usbd_private_handle
, usbd_status
);
187 static void ucom_read_complete(struct ucom_softc
*);
188 static usbd_status
ucomsubmitread(struct ucom_softc
*, struct ucom_buffer
*);
189 static void ucom_softintr(void *);
191 USB_DECLARE_DRIVER(ucom
);
200 struct ucom_softc
*sc
= device_private(self
);
201 struct ucom_attach_args
*uca
= aux
;
204 if (uca
->info
!= NULL
)
205 printf(": %s", uca
->info
);
209 sc
->sc_udev
= uca
->device
;
210 sc
->sc_iface
= uca
->iface
;
211 sc
->sc_bulkout_no
= uca
->bulkout
;
212 sc
->sc_bulkin_no
= uca
->bulkin
;
213 sc
->sc_ibufsize
= uca
->ibufsize
;
214 sc
->sc_ibufsizepad
= uca
->ibufsizepad
;
215 sc
->sc_obufsize
= uca
->obufsize
;
216 sc
->sc_opkthdrlen
= uca
->opkthdrlen
;
217 sc
->sc_methods
= uca
->methods
;
218 sc
->sc_parent
= uca
->arg
;
219 sc
->sc_portno
= uca
->portno
;
224 sc
->sc_tx_stopped
= 0;
230 sc
->sc_si
= softint_establish(SOFTINT_NET
, ucom_softintr
, sc
);
233 tp
->t_oproc
= ucomstart
;
234 tp
->t_param
= ucomparam
;
235 tp
->t_hwiflow
= ucomhwiflow
;
238 DPRINTF(("ucom_attach: tty_attach %p\n", tp
));
241 #if defined(__NetBSD__) && NRND > 0
242 rnd_attach_source(&sc
->sc_rndsource
, USBDEVNAME(sc
->sc_dev
),
246 if (!pmf_device_register(self
, NULL
, NULL
))
247 aprint_error_dev(self
, "couldn't establish power handler\n");
248 USB_ATTACH_SUCCESS_RETURN
;
253 struct ucom_softc
*sc
= device_private(self
);
254 struct tty
*tp
= sc
->sc_tty
;
258 DPRINTF(("ucom_detach: sc=%p flags=%d tp=%p, pipe=%d,%d\n",
259 sc
, flags
, tp
, sc
->sc_bulkin_no
, sc
->sc_bulkout_no
));
262 pmf_device_deregister(self
);
264 if (sc
->sc_bulkin_pipe
!= NULL
)
265 usbd_abort_pipe(sc
->sc_bulkin_pipe
);
266 if (sc
->sc_bulkout_pipe
!= NULL
)
267 usbd_abort_pipe(sc
->sc_bulkout_pipe
);
270 if (--sc
->sc_refcnt
>= 0) {
271 /* Wake up anyone waiting */
273 mutex_spin_enter(&tty_lock
);
274 CLR(tp
->t_state
, TS_CARR_ON
);
275 CLR(tp
->t_cflag
, CLOCAL
| MDMBUF
);
276 ttyflush(tp
, FREAD
|FWRITE
);
277 mutex_spin_exit(&tty_lock
);
279 /* Wait for processes to go away. */
280 usb_detach_wait(USBDEV(sc
->sc_dev
));
283 softint_disestablish(sc
->sc_si
);
286 /* locate the major number */
287 maj
= cdevsw_lookup_major(&ucom_cdevsw
);
289 /* Nuke the vnodes for any open instances. */
290 mn
= device_unit(self
);
291 DPRINTF(("ucom_detach: maj=%d mn=%d\n", maj
, mn
));
292 vdevgone(maj
, mn
, mn
, VCHR
);
293 vdevgone(maj
, mn
| UCOMDIALOUT_MASK
, mn
| UCOMDIALOUT_MASK
, VCHR
);
294 vdevgone(maj
, mn
| UCOMCALLUNIT_MASK
, mn
| UCOMCALLUNIT_MASK
, VCHR
);
296 /* Detach and free the tty. */
303 for (i
= 0; i
< UCOM_IN_BUFFS
; i
++) {
304 if (sc
->sc_ibuff
[i
].ub_xfer
!= NULL
)
305 usbd_free_xfer(sc
->sc_ibuff
[i
].ub_xfer
);
308 for (i
= 0; i
< UCOM_OUT_BUFFS
; i
++) {
309 if (sc
->sc_obuff
[i
].ub_xfer
!= NULL
)
310 usbd_free_xfer(sc
->sc_obuff
[i
].ub_xfer
);
313 /* Detach the random source */
314 #if defined(__NetBSD__) && NRND > 0
315 rnd_detach_source(&sc
->sc_rndsource
);
322 ucom_activate(device_ptr_t self
, enum devact act
)
324 struct ucom_softc
*sc
= device_private(self
);
326 DPRINTFN(5,("ucom_activate: %d\n", act
));
329 case DVACT_DEACTIVATE
:
338 ucom_shutdown(struct ucom_softc
*sc
)
340 struct tty
*tp
= sc
->sc_tty
;
342 DPRINTF(("ucom_shutdown\n"));
344 * Hang up if necessary. Wait a bit, so the other side has time to
345 * notice even if we immediately open the port again.
347 if (ISSET(tp
->t_cflag
, HUPCL
)) {
349 (void)tsleep(sc
, TTIPRI
, ttclos
, hz
);
354 ucomopen(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
356 int unit
= UCOMUNIT(dev
);
358 struct ucom_softc
*sc
= device_lookup_private(&ucom_cd
, unit
);
359 struct ucom_buffer
*ub
;
370 if (!device_is_active(sc
->sc_dev
))
375 DPRINTF(("ucomopen: unit=%d, tp=%p\n", unit
, tp
));
377 if (kauth_authorize_device_tty(l
->l_cred
, KAUTH_DEVICE_TTY_OPEN
, tp
))
383 * Do the following iff this is a first open.
385 while (sc
->sc_opening
)
386 tsleep(&sc
->sc_opening
, PRIBIO
, "ucomop", 0);
394 if (!ISSET(tp
->t_state
, TS_ISOPEN
) && tp
->t_wopen
== 0) {
399 if (sc
->sc_methods
->ucom_open
!= NULL
) {
400 error
= sc
->sc_methods
->ucom_open(sc
->sc_parent
,
405 wakeup(&sc
->sc_opening
);
411 ucom_status_change(sc
);
414 * Initialize the termios status to the defaults. Add in the
415 * sticky bits from TIOCSFLAGS.
418 t
.c_ospeed
= TTYDEF_SPEED
;
419 t
.c_cflag
= TTYDEF_CFLAG
;
420 if (ISSET(sc
->sc_swflags
, TIOCFLAG_CLOCAL
))
421 SET(t
.c_cflag
, CLOCAL
);
422 if (ISSET(sc
->sc_swflags
, TIOCFLAG_CRTSCTS
))
423 SET(t
.c_cflag
, CRTSCTS
);
424 if (ISSET(sc
->sc_swflags
, TIOCFLAG_MDMBUF
))
425 SET(t
.c_cflag
, MDMBUF
);
426 /* Make sure ucomparam() will do something. */
428 (void) ucomparam(tp
, &t
);
429 tp
->t_iflag
= TTYDEF_IFLAG
;
430 tp
->t_oflag
= TTYDEF_OFLAG
;
431 tp
->t_lflag
= TTYDEF_LFLAG
;
436 * Turn on DTR. We must always do this, even if carrier is not
437 * present, because otherwise we'd have to use TIOCSDTR
438 * immediately after setting CLOCAL, which applications do not
439 * expect. We always assert DTR while the device is open
440 * unless explicitly requested to deassert it. Ditto RTS.
445 DPRINTF(("ucomopen: open pipes in=%d out=%d\n",
446 sc
->sc_bulkin_no
, sc
->sc_bulkout_no
));
448 /* Open the bulk pipes */
449 err
= usbd_open_pipe(sc
->sc_iface
, sc
->sc_bulkin_no
,
450 USBD_EXCLUSIVE_USE
, &sc
->sc_bulkin_pipe
);
452 DPRINTF(("%s: open bulk in error (addr %d), err=%s\n",
453 USBDEVNAME(sc
->sc_dev
), sc
->sc_bulkin_no
,
458 err
= usbd_open_pipe(sc
->sc_iface
, sc
->sc_bulkout_no
,
459 USBD_EXCLUSIVE_USE
, &sc
->sc_bulkout_pipe
);
461 DPRINTF(("%s: open bulk out error (addr %d), err=%s\n",
462 USBDEVNAME(sc
->sc_dev
), sc
->sc_bulkout_no
,
468 sc
->sc_rx_unblock
= 0;
469 sc
->sc_rx_stopped
= 0;
470 sc
->sc_tx_stopped
= 0;
472 memset(sc
->sc_ibuff
, 0, sizeof(sc
->sc_ibuff
));
473 memset(sc
->sc_obuff
, 0, sizeof(sc
->sc_obuff
));
475 SIMPLEQ_INIT(&sc
->sc_ibuff_empty
);
476 SIMPLEQ_INIT(&sc
->sc_ibuff_full
);
477 SIMPLEQ_INIT(&sc
->sc_obuff_free
);
478 SIMPLEQ_INIT(&sc
->sc_obuff_full
);
480 /* Allocate input buffers */
481 for (ub
= &sc
->sc_ibuff
[0]; ub
!= &sc
->sc_ibuff
[UCOM_IN_BUFFS
];
483 ub
->ub_xfer
= usbd_alloc_xfer(sc
->sc_udev
);
484 if (ub
->ub_xfer
== NULL
) {
488 ub
->ub_data
= usbd_alloc_buffer(ub
->ub_xfer
,
490 if (ub
->ub_data
== NULL
) {
495 if (ucomsubmitread(sc
, ub
) != USBD_NORMAL_COMPLETION
) {
501 for (ub
= &sc
->sc_obuff
[0]; ub
!= &sc
->sc_obuff
[UCOM_OUT_BUFFS
];
503 ub
->ub_xfer
= usbd_alloc_xfer(sc
->sc_udev
);
504 if (ub
->ub_xfer
== NULL
) {
508 ub
->ub_data
= usbd_alloc_buffer(ub
->ub_xfer
,
510 if (ub
->ub_data
== NULL
) {
515 SIMPLEQ_INSERT_TAIL(&sc
->sc_obuff_free
, ub
, ub_link
);
520 wakeup(&sc
->sc_opening
);
523 error
= ttyopen(tp
, UCOMDIALOUT(dev
), ISSET(flag
, O_NONBLOCK
));
527 error
= (*tp
->t_linesw
->l_open
)(dev
, tp
);
534 usbd_abort_pipe(sc
->sc_bulkin_pipe
);
535 for (i
= 0; i
< UCOM_IN_BUFFS
; i
++) {
536 if (sc
->sc_ibuff
[i
].ub_xfer
!= NULL
) {
537 usbd_free_xfer(sc
->sc_ibuff
[i
].ub_xfer
);
538 sc
->sc_ibuff
[i
].ub_xfer
= NULL
;
539 sc
->sc_ibuff
[i
].ub_data
= NULL
;
542 usbd_abort_pipe(sc
->sc_bulkout_pipe
);
543 for (i
= 0; i
< UCOM_OUT_BUFFS
; i
++) {
544 if (sc
->sc_obuff
[i
].ub_xfer
!= NULL
) {
545 usbd_free_xfer(sc
->sc_obuff
[i
].ub_xfer
);
546 sc
->sc_obuff
[i
].ub_xfer
= NULL
;
547 sc
->sc_obuff
[i
].ub_data
= NULL
;
551 usbd_close_pipe(sc
->sc_bulkout_pipe
);
552 sc
->sc_bulkout_pipe
= NULL
;
554 usbd_close_pipe(sc
->sc_bulkin_pipe
);
555 sc
->sc_bulkin_pipe
= NULL
;
558 wakeup(&sc
->sc_opening
);
564 CLR(tp
->t_state
, TS_BUSY
);
565 if (!ISSET(tp
->t_state
, TS_ISOPEN
) && tp
->t_wopen
== 0) {
567 * We failed to open the device, and nobody else had it opened.
568 * Clean up the state as appropriate.
578 ucomclose(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
580 struct ucom_softc
*sc
= device_lookup_private(&ucom_cd
, UCOMUNIT(dev
));
581 struct tty
*tp
= sc
->sc_tty
;
584 DPRINTF(("ucomclose: unit=%d\n", UCOMUNIT(dev
)));
585 if (!ISSET(tp
->t_state
, TS_ISOPEN
))
590 CLR(tp
->t_state
, TS_BUSY
);
592 (*tp
->t_linesw
->l_close
)(tp
, flag
);
595 if (!ISSET(tp
->t_state
, TS_ISOPEN
) && tp
->t_wopen
== 0) {
597 * Although we got a last close, the device may still be in
598 * use; e.g. if this was the dialout node, and there are still
599 * processes waiting for carrier on the non-dialout node.
604 if (sc
->sc_methods
->ucom_close
!= NULL
)
605 sc
->sc_methods
->ucom_close(sc
->sc_parent
, sc
->sc_portno
);
607 if (--sc
->sc_refcnt
< 0)
608 usb_detach_wakeup(USBDEV(sc
->sc_dev
));
615 ucomread(dev_t dev
, struct uio
*uio
, int flag
)
617 struct ucom_softc
*sc
= device_lookup_private(&ucom_cd
, UCOMUNIT(dev
));
618 struct tty
*tp
= sc
->sc_tty
;
625 error
= ((*tp
->t_linesw
->l_read
)(tp
, uio
, flag
));
626 if (--sc
->sc_refcnt
< 0)
627 usb_detach_wakeup(USBDEV(sc
->sc_dev
));
632 ucomwrite(dev_t dev
, struct uio
*uio
, int flag
)
634 struct ucom_softc
*sc
= device_lookup_private(&ucom_cd
, UCOMUNIT(dev
));
635 struct tty
*tp
= sc
->sc_tty
;
642 error
= ((*tp
->t_linesw
->l_write
)(tp
, uio
, flag
));
643 if (--sc
->sc_refcnt
< 0)
644 usb_detach_wakeup(USBDEV(sc
->sc_dev
));
649 ucompoll(dev_t dev
, int events
, struct lwp
*l
)
651 struct ucom_softc
*sc
= device_lookup_private(&ucom_cd
, UCOMUNIT(dev
));
652 struct tty
*tp
= sc
->sc_tty
;
659 revents
= ((*tp
->t_linesw
->l_poll
)(tp
, events
, l
));
660 if (--sc
->sc_refcnt
< 0)
661 usb_detach_wakeup(USBDEV(sc
->sc_dev
));
668 struct ucom_softc
*sc
= device_lookup_private(&ucom_cd
, UCOMUNIT(dev
));
669 struct tty
*tp
= sc
->sc_tty
;
675 ucomioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
677 struct ucom_softc
*sc
= device_lookup_private(&ucom_cd
, UCOMUNIT(dev
));
681 error
= ucom_do_ioctl(sc
, cmd
, data
, flag
, l
);
682 if (--sc
->sc_refcnt
< 0)
683 usb_detach_wakeup(USBDEV(sc
->sc_dev
));
688 ucom_do_ioctl(struct ucom_softc
*sc
, u_long cmd
, void *data
,
689 int flag
, struct lwp
*l
)
691 struct tty
*tp
= sc
->sc_tty
;
698 DPRINTF(("ucomioctl: cmd=0x%08lx\n", cmd
));
700 error
= (*tp
->t_linesw
->l_ioctl
)(tp
, cmd
, data
, flag
, l
);
701 if (error
!= EPASSTHROUGH
)
704 error
= ttioctl(tp
, cmd
, data
, flag
, l
);
705 if (error
!= EPASSTHROUGH
)
708 if (sc
->sc_methods
->ucom_ioctl
!= NULL
) {
709 error
= sc
->sc_methods
->ucom_ioctl(sc
->sc_parent
,
710 sc
->sc_portno
, cmd
, data
, flag
, l
->l_proc
);
711 if (error
!= EPASSTHROUGH
)
717 DPRINTF(("ucomioctl: our cmd=0x%08lx\n", cmd
));
738 *(int *)data
= sc
->sc_swflags
;
742 error
= kauth_authorize_device_tty(l
->l_cred
,
743 KAUTH_DEVICE_TTY_PRIVSET
, tp
);
746 sc
->sc_swflags
= *(int *)data
;
752 tiocm_to_ucom(sc
, cmd
, *(int *)data
);
756 *(int *)data
= ucom_to_tiocm(sc
);
760 error
= EPASSTHROUGH
;
770 tiocm_to_ucom(struct ucom_softc
*sc
, u_long how
, int ttybits
)
775 if (ISSET(ttybits
, TIOCM_DTR
))
776 SET(combits
, UMCR_DTR
);
777 if (ISSET(ttybits
, TIOCM_RTS
))
778 SET(combits
, UMCR_RTS
);
782 CLR(sc
->sc_mcr
, combits
);
786 SET(sc
->sc_mcr
, combits
);
790 CLR(sc
->sc_mcr
, UMCR_DTR
| UMCR_RTS
);
791 SET(sc
->sc_mcr
, combits
);
795 if (how
== TIOCMSET
|| ISSET(combits
, UMCR_DTR
))
796 ucom_dtr(sc
, (sc
->sc_mcr
& UMCR_DTR
) != 0);
797 if (how
== TIOCMSET
|| ISSET(combits
, UMCR_RTS
))
798 ucom_rts(sc
, (sc
->sc_mcr
& UMCR_RTS
) != 0);
802 ucom_to_tiocm(struct ucom_softc
*sc
)
807 combits
= sc
->sc_mcr
;
808 if (ISSET(combits
, UMCR_DTR
))
809 SET(ttybits
, TIOCM_DTR
);
810 if (ISSET(combits
, UMCR_RTS
))
811 SET(ttybits
, TIOCM_RTS
);
813 combits
= sc
->sc_msr
;
814 if (ISSET(combits
, UMSR_DCD
))
815 SET(ttybits
, TIOCM_CD
);
816 if (ISSET(combits
, UMSR_CTS
))
817 SET(ttybits
, TIOCM_CTS
);
818 if (ISSET(combits
, UMSR_DSR
))
819 SET(ttybits
, TIOCM_DSR
);
820 if (ISSET(combits
, UMSR_RI
| UMSR_TERI
))
821 SET(ttybits
, TIOCM_RI
);
826 SET(ttybits
, TIOCM_LE
);
833 ucom_break(struct ucom_softc
*sc
, int onoff
)
835 DPRINTF(("ucom_break: onoff=%d\n", onoff
));
837 if (sc
->sc_methods
->ucom_set
!= NULL
)
838 sc
->sc_methods
->ucom_set(sc
->sc_parent
, sc
->sc_portno
,
839 UCOM_SET_BREAK
, onoff
);
843 ucom_dtr(struct ucom_softc
*sc
, int onoff
)
845 DPRINTF(("ucom_dtr: onoff=%d\n", onoff
));
847 if (sc
->sc_methods
->ucom_set
!= NULL
)
848 sc
->sc_methods
->ucom_set(sc
->sc_parent
, sc
->sc_portno
,
849 UCOM_SET_DTR
, onoff
);
853 ucom_rts(struct ucom_softc
*sc
, int onoff
)
855 DPRINTF(("ucom_rts: onoff=%d\n", onoff
));
857 if (sc
->sc_methods
->ucom_set
!= NULL
)
858 sc
->sc_methods
->ucom_set(sc
->sc_parent
, sc
->sc_portno
,
859 UCOM_SET_RTS
, onoff
);
863 ucom_status_change(struct ucom_softc
*sc
)
865 struct tty
*tp
= sc
->sc_tty
;
868 if (sc
->sc_methods
->ucom_get_status
!= NULL
) {
869 old_msr
= sc
->sc_msr
;
870 sc
->sc_methods
->ucom_get_status(sc
->sc_parent
, sc
->sc_portno
,
871 &sc
->sc_lsr
, &sc
->sc_msr
);
872 if (ISSET((sc
->sc_msr
^ old_msr
), UMSR_DCD
))
873 (*tp
->t_linesw
->l_modem
)(tp
,
874 ISSET(sc
->sc_msr
, UMSR_DCD
));
877 /* Assume DCD is present, if we have no chance to check it. */
878 sc
->sc_msr
= UMSR_DCD
;
883 ucomparam(struct tty
*tp
, struct termios
*t
)
885 struct ucom_softc
*sc
= device_lookup_private(&ucom_cd
,
886 UCOMUNIT(tp
->t_dev
));
892 /* Check requested parameters. */
893 if (t
->c_ispeed
&& t
->c_ispeed
!= t
->c_ospeed
)
897 * For the console, always force CLOCAL and !HUPCL, so that the port
900 if (ISSET(sc
->sc_swflags
, TIOCFLAG_SOFTCAR
)) {
901 SET(t
->c_cflag
, CLOCAL
);
902 CLR(t
->c_cflag
, HUPCL
);
906 * If there were no changes, don't do anything. This avoids dropping
907 * input and improves performance when all we did was frob things like
910 if (tp
->t_ospeed
== t
->c_ospeed
&&
911 tp
->t_cflag
== t
->c_cflag
)
914 /* XXX lcr = ISSET(sc->sc_lcr, LCR_SBREAK) | cflag2lcr(t->c_cflag); */
916 /* And copy to tty. */
918 tp
->t_ospeed
= t
->c_ospeed
;
919 tp
->t_cflag
= t
->c_cflag
;
921 if (sc
->sc_methods
->ucom_param
!= NULL
) {
922 error
= sc
->sc_methods
->ucom_param(sc
->sc_parent
, sc
->sc_portno
,
928 /* XXX worry about CHWFLOW */
931 * Update the tty layer's idea of the carrier bit, in case we changed
932 * CLOCAL or MDMBUF. We don't hang up here; we only do that by
935 DPRINTF(("ucomparam: l_modem\n"));
936 (void) (*tp
->t_linesw
->l_modem
)(tp
, ISSET(sc
->sc_msr
, UMSR_DCD
));
939 XXX what
if the hardware is
not open
940 if (!ISSET(t
->c_cflag
, CHWFLOW
)) {
941 if (sc
->sc_tx_stopped
) {
942 sc
->sc_tx_stopped
= 0;
952 ucomhwiflow(struct tty
*tp
, int block
)
954 struct ucom_softc
*sc
= device_lookup_private(&ucom_cd
,
955 UCOMUNIT(tp
->t_dev
));
958 old
= sc
->sc_rx_stopped
;
959 sc
->sc_rx_stopped
= (u_char
)block
;
963 sc
->sc_rx_unblock
= 1;
964 softint_schedule(sc
->sc_si
);
972 ucomstart(struct tty
*tp
)
974 struct ucom_softc
*sc
= device_lookup_private(&ucom_cd
,
975 UCOMUNIT(tp
->t_dev
));
976 struct ucom_buffer
*ub
;
985 if (ISSET(tp
->t_state
, TS_BUSY
| TS_TIMEOUT
| TS_TTSTOP
)) {
986 DPRINTFN(4,("ucomstart: no go, state=0x%x\n", tp
->t_state
));
989 if (sc
->sc_tx_stopped
)
995 /* Grab the first contiguous region of buffer space. */
996 data
= tp
->t_outq
.c_cf
;
997 cnt
= ndqb(&tp
->t_outq
, 0);
1000 DPRINTF(("ucomstart: cnt==0\n"));
1004 ub
= SIMPLEQ_FIRST(&sc
->sc_obuff_free
);
1005 KASSERT(ub
!= NULL
);
1006 SIMPLEQ_REMOVE_HEAD(&sc
->sc_obuff_free
, ub_link
);
1008 if (SIMPLEQ_FIRST(&sc
->sc_obuff_free
) == NULL
)
1009 SET(tp
->t_state
, TS_BUSY
);
1011 if (cnt
> sc
->sc_obufsize
)
1012 cnt
= sc
->sc_obufsize
;
1014 if (sc
->sc_methods
->ucom_write
!= NULL
)
1015 sc
->sc_methods
->ucom_write(sc
->sc_parent
, sc
->sc_portno
,
1016 ub
->ub_data
, data
, &cnt
);
1018 memcpy(ub
->ub_data
, data
, cnt
);
1023 SIMPLEQ_INSERT_TAIL(&sc
->sc_obuff_full
, ub
, ub_link
);
1025 softint_schedule(sc
->sc_si
);
1032 ucomstop(struct tty
*tp
, int flag
)
1034 DPRINTF(("ucomstop: flag=%d\n", flag
));
1036 /*struct ucom_softc *sc =
1037 device_lookup_private(&ucom_cd, UCOMUNIT(dev));*/
1041 if (ISSET(tp
->t_state
, TS_BUSY
)) {
1042 DPRINTF(("ucomstop: XXX\n"));
1043 /* sc->sc_tx_stopped = 1; */
1044 if (!ISSET(tp
->t_state
, TS_TTSTOP
))
1045 SET(tp
->t_state
, TS_FLUSH
);
1052 ucom_write_status(struct ucom_softc
*sc
, struct ucom_buffer
*ub
,
1055 struct tty
*tp
= sc
->sc_tty
;
1056 uint32_t cc
= ub
->ub_len
;
1059 case USBD_IN_PROGRESS
:
1060 ub
->ub_index
= ub
->ub_len
;
1064 softint_schedule(sc
->sc_si
);
1066 case USBD_NORMAL_COMPLETION
:
1067 usbd_get_xfer_status(ub
->ub_xfer
, NULL
, NULL
, &cc
, NULL
);
1068 #if defined(__NetBSD__) && NRND > 0
1069 rnd_add_uint32(&sc
->sc_rndsource
, cc
);
1073 SIMPLEQ_REMOVE_HEAD(&sc
->sc_obuff_full
, ub_link
);
1074 SIMPLEQ_INSERT_TAIL(&sc
->sc_obuff_free
, ub
, ub_link
);
1075 cc
-= sc
->sc_opkthdrlen
;
1077 CLR(tp
->t_state
, TS_BUSY
);
1078 if (ISSET(tp
->t_state
, TS_FLUSH
))
1079 CLR(tp
->t_state
, TS_FLUSH
);
1081 ndflush(&tp
->t_outq
, cc
);
1083 if (err
!= USBD_CANCELLED
&& err
!= USBD_IOERROR
&&
1085 if ((ub
= SIMPLEQ_FIRST(&sc
->sc_obuff_full
)) != NULL
)
1086 ucom_submit_write(sc
, ub
);
1088 (*tp
->t_linesw
->l_start
)(tp
);
1094 /* Call at spltty() */
1096 ucom_submit_write(struct ucom_softc
*sc
, struct ucom_buffer
*ub
)
1099 usbd_setup_xfer(ub
->ub_xfer
, sc
->sc_bulkout_pipe
,
1100 (usbd_private_handle
)sc
, ub
->ub_data
, ub
->ub_len
,
1101 USBD_NO_COPY
, USBD_NO_TIMEOUT
, ucomwritecb
);
1103 ucom_write_status(sc
, ub
, usbd_transfer(ub
->ub_xfer
));
1107 ucomwritecb(usbd_xfer_handle xfer
, usbd_private_handle p
, usbd_status status
)
1109 struct ucom_softc
*sc
= (struct ucom_softc
*)p
;
1114 ucom_write_status(sc
, SIMPLEQ_FIRST(&sc
->sc_obuff_full
), status
);
1120 ucom_softintr(void *arg
)
1122 struct ucom_softc
*sc
= arg
;
1123 struct tty
*tp
= sc
->sc_tty
;
1124 struct ucom_buffer
*ub
;
1127 if (!ISSET(tp
->t_state
, TS_ISOPEN
))
1132 ub
= SIMPLEQ_FIRST(&sc
->sc_obuff_full
);
1134 if (ub
!= NULL
&& ub
->ub_index
== 0)
1135 ucom_submit_write(sc
, ub
);
1137 if (sc
->sc_rx_unblock
)
1138 ucom_read_complete(sc
);
1144 ucom_read_complete(struct ucom_softc
*sc
)
1146 int (*rint
)(int, struct tty
*);
1147 struct ucom_buffer
*ub
;
1152 rint
= tp
->t_linesw
->l_rint
;
1153 ub
= SIMPLEQ_FIRST(&sc
->sc_ibuff_full
);
1155 while (ub
!= NULL
&& !sc
->sc_rx_stopped
) {
1159 while (ub
->ub_index
< ub
->ub_len
&& !sc
->sc_rx_stopped
) {
1160 /* Give characters to tty layer. */
1161 if ((*rint
)(ub
->ub_data
[ub
->ub_index
], tp
) == -1) {
1162 /* Overflow: drop remainder */
1163 ub
->ub_index
= ub
->ub_len
;
1170 if (ub
->ub_index
== ub
->ub_len
) {
1171 SIMPLEQ_REMOVE_HEAD(&sc
->sc_ibuff_full
, ub_link
);
1173 ucomsubmitread(sc
, ub
);
1175 ub
= SIMPLEQ_FIRST(&sc
->sc_ibuff_full
);
1179 sc
->sc_rx_unblock
= (ub
!= NULL
);
1183 ucomsubmitread(struct ucom_softc
*sc
, struct ucom_buffer
*ub
)
1187 usbd_setup_xfer(ub
->ub_xfer
, sc
->sc_bulkin_pipe
,
1188 (usbd_private_handle
)sc
, ub
->ub_data
, sc
->sc_ibufsize
,
1189 USBD_SHORT_XFER_OK
| USBD_NO_COPY
, USBD_NO_TIMEOUT
, ucomreadcb
);
1191 if ((err
= usbd_transfer(ub
->ub_xfer
)) != USBD_IN_PROGRESS
) {
1192 /* XXX: Recover from this, please! */
1193 printf("ucomsubmitread: err=%s\n", usbd_errstr(err
));
1197 SIMPLEQ_INSERT_TAIL(&sc
->sc_ibuff_empty
, ub
, ub_link
);
1199 return (USBD_NORMAL_COMPLETION
);
1203 ucomreadcb(usbd_xfer_handle xfer
, usbd_private_handle p
, usbd_status status
)
1205 struct ucom_softc
*sc
= (struct ucom_softc
*)p
;
1206 struct tty
*tp
= sc
->sc_tty
;
1207 struct ucom_buffer
*ub
;
1212 ub
= SIMPLEQ_FIRST(&sc
->sc_ibuff_empty
);
1213 SIMPLEQ_REMOVE_HEAD(&sc
->sc_ibuff_empty
, ub_link
);
1215 if (status
== USBD_CANCELLED
|| status
== USBD_IOERROR
||
1217 DPRINTF(("ucomreadcb: dying\n"));
1218 ub
->ub_index
= ub
->ub_len
= 0;
1219 /* Send something to wake upper layer */
1221 if (status
!= USBD_CANCELLED
) {
1222 (tp
->t_linesw
->l_rint
)('\n', tp
);
1223 mutex_spin_enter(&tty_lock
); /* XXX */
1225 mutex_spin_exit(&tty_lock
); /* XXX */
1231 if (status
== USBD_STALLED
) {
1232 usbd_clear_endpoint_stall_async(sc
->sc_bulkin_pipe
);
1233 ucomsubmitread(sc
, ub
);
1237 if (status
!= USBD_NORMAL_COMPLETION
) {
1238 printf("ucomreadcb: wonky status=%s\n", usbd_errstr(status
));
1242 usbd_get_xfer_status(xfer
, NULL
, (void *)&cp
, &cc
, NULL
);
1245 aprint_normal_dev(sc
->sc_dev
,
1246 "ucomreadcb: zero length xfer!\n");
1249 KDASSERT(cp
== ub
->ub_data
);
1251 #if defined(__NetBSD__) && NRND > 0
1252 rnd_add_uint32(&sc
->sc_rndsource
, cc
);
1255 if (sc
->sc_opening
) {
1256 ucomsubmitread(sc
, ub
);
1260 if (sc
->sc_methods
->ucom_read
!= NULL
) {
1261 sc
->sc_methods
->ucom_read(sc
->sc_parent
, sc
->sc_portno
,
1263 ub
->ub_index
= (u_int
)(cp
- ub
->ub_data
);
1269 SIMPLEQ_INSERT_TAIL(&sc
->sc_ibuff_full
, ub
, ub_link
);
1271 ucom_read_complete(sc
);
1275 ucom_cleanup(struct ucom_softc
*sc
)
1277 struct ucom_buffer
*ub
;
1279 DPRINTF(("ucom_cleanup: closing pipes\n"));
1282 if (sc
->sc_bulkin_pipe
!= NULL
) {
1283 usbd_abort_pipe(sc
->sc_bulkin_pipe
);
1284 usbd_close_pipe(sc
->sc_bulkin_pipe
);
1285 sc
->sc_bulkin_pipe
= NULL
;
1287 if (sc
->sc_bulkout_pipe
!= NULL
) {
1288 usbd_abort_pipe(sc
->sc_bulkout_pipe
);
1289 usbd_close_pipe(sc
->sc_bulkout_pipe
);
1290 sc
->sc_bulkout_pipe
= NULL
;
1292 for (ub
= &sc
->sc_ibuff
[0]; ub
!= &sc
->sc_ibuff
[UCOM_IN_BUFFS
]; ub
++) {
1293 if (ub
->ub_xfer
!= NULL
) {
1294 usbd_free_xfer(ub
->ub_xfer
);
1299 for (ub
= &sc
->sc_obuff
[0]; ub
!= &sc
->sc_obuff
[UCOM_OUT_BUFFS
]; ub
++){
1300 if (ub
->ub_xfer
!= NULL
) {
1301 usbd_free_xfer(ub
->ub_xfer
);
1308 #endif /* NUCOM > 0 */
1311 ucomprint(void *aux
, const char *pnp
)
1313 struct ucom_attach_args
*uca
= aux
;
1316 aprint_normal("ucom at %s", pnp
);
1317 if (uca
->portno
!= UCOM_UNK_PORTNO
)
1318 aprint_normal(" portno %d", uca
->portno
);
1323 ucomsubmatch(device_t parent
, cfdata_t cf
,
1324 const int *ldesc
, void *aux
)
1326 struct ucom_attach_args
*uca
= aux
;
1328 if (uca
->portno
!= UCOM_UNK_PORTNO
&&
1329 cf
->cf_loc
[UCOMBUSCF_PORTNO
] != UCOMBUSCF_PORTNO_DEFAULT
&&
1330 cf
->cf_loc
[UCOMBUSCF_PORTNO
] != uca
->portno
)
1332 return (config_match(parent
, cf
, aux
));