diff options
author | Aaron Campbell <aaron@cvs.openbsd.org> | 2000-04-14 22:50:30 +0000 |
---|---|---|
committer | Aaron Campbell <aaron@cvs.openbsd.org> | 2000-04-14 22:50:30 +0000 |
commit | 991040652a68096f72fa44929e5d73800c044538 (patch) | |
tree | 952b80839b97ddc3e3a64e5e2fa4d0a5fe7a8a50 /sys/dev/usb/ucom.c | |
parent | 765944befb7871794d0edd9124f922f86d9324bc (diff) |
Sync with NetBSD.
Diffstat (limited to 'sys/dev/usb/ucom.c')
-rw-r--r-- | sys/dev/usb/ucom.c | 158 |
1 files changed, 113 insertions, 45 deletions
diff --git a/sys/dev/usb/ucom.c b/sys/dev/usb/ucom.c index a79b2bf4668..df1b17926d4 100644 --- a/sys/dev/usb/ucom.c +++ b/sys/dev/usb/ucom.c @@ -1,8 +1,8 @@ -/* $OpenBSD: ucom.c,v 1.2 2000/04/08 20:03:33 aaron Exp $ */ -/* $NetBSD: ucom.c,v 1.16 2000/03/27 12:33:55 augustss Exp $ */ +/* $OpenBSD: ucom.c,v 1.3 2000/04/14 22:50:25 aaron Exp $ */ +/* $NetBSD: ucom.c,v 1.22 2000/04/14 14:21:55 augustss Exp $ */ /* - * Copyright (c) 1998 The NetBSD Foundation, Inc. + * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation @@ -37,6 +37,9 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ +/* + * This code is very heavily based on the 16550 driver, com.c. + */ #include <sys/param.h> #include <sys/systm.h> @@ -80,14 +83,6 @@ int ucomdebug = 0; #define UCOMDIALOUT(x) (minor(x) & UCOMDIALOUT_MASK) #define UCOMCALLUNIT(x) (minor(x) & UCOMCALLUNIT_MASK) -/* - * These are the maximum number of bytes transferred per frame. - * If some really high speed devices should use this driver they - * may need to be increased, but this is good enough for modems. - */ -#define UCOMIBUFSIZE 64 -#define UCOMOBUFSIZE 256 - struct ucom_softc { USBBASEDEVICE sc_dev; /* base device */ @@ -99,11 +94,15 @@ struct ucom_softc { usbd_pipe_handle sc_bulkin_pipe; /* bulk in pipe */ usbd_xfer_handle sc_ixfer; /* read request */ u_char *sc_ibuf; /* read buffer */ + u_int sc_ibufsize; /* read buffer size */ + u_int sc_ibufsizepad; /* read buffer size padded */ int sc_bulkout_no; /* bulk out endpoint address */ usbd_pipe_handle sc_bulkout_pipe;/* bulk out pipe */ usbd_xfer_handle sc_oxfer; /* write request */ u_char *sc_obuf; /* write buffer */ + u_int sc_obufsize; /* write buffer size */ + u_int sc_obufsizepad; /* write buffer size padded */ struct ucom_methods *sc_methods; void *sc_parent; @@ -117,6 +116,7 @@ struct ucom_softc { int sc_swflags; u_char sc_opening; /* lock during open */ + int sc_refcnt; u_char sc_dying; /* disconnecting */ }; @@ -127,6 +127,8 @@ Static void ucom_hwiflow __P((struct ucom_softc *)); Static int ucomparam __P((struct tty *, struct termios *)); Static void ucomstart __P((struct tty *)); Static void ucom_shutdown __P((struct ucom_softc *)); +Static int ucom_do_ioctl __P((struct ucom_softc *, u_long, caddr_t, + int, struct proc *)); Static void ucom_dtr __P((struct ucom_softc *, int)); Static void ucom_rts __P((struct ucom_softc *, int)); Static void ucom_break __P((struct ucom_softc *, int)); @@ -159,6 +161,10 @@ USB_ATTACH(ucom) sc->sc_iface = uca->iface; sc->sc_bulkout_no = uca->bulkout; sc->sc_bulkin_no = uca->bulkin; + sc->sc_ibufsize = uca->ibufsize; + sc->sc_ibufsizepad = uca->ibufsizepad; + sc->sc_obufsize = uca->obufsize; + sc->sc_obufsizepad = uca->obufsizepad; sc->sc_methods = uca->methods; sc->sc_parent = uca->arg; sc->sc_portno = uca->portno; @@ -178,6 +184,7 @@ USB_DETACH(ucom) { struct ucom_softc *sc = (struct ucom_softc *)self; int maj, mn; + int s; DPRINTF(("ucom_detach: sc=%p flags=%d tp=%p\n", sc, flags, sc->sc_tty)); @@ -191,7 +198,13 @@ USB_DETACH(ucom) } #endif - /* XXX Use reference count? */ + s = splusb(); + if (--sc->sc_refcnt >= 0) { + /* Wake everyone.. how? */ + /* Wait for processes to go away. */ + usb_detach_wait(USBDEV(sc->sc_dev)); + } + splx(s); /* locate the major number */ for (maj = 0; maj < nchrdev; maj++) @@ -200,9 +213,10 @@ USB_DETACH(ucom) /* Nuke the vnodes for any open instances. */ mn = self->dv_unit; + DPRINTF(("ucom_detach: maj=%d mn=%d\n", maj, mn)); vdevgone(maj, mn, mn, VCHR); - vdevgone(maj, mn, mn | UCOMDIALOUT_MASK, VCHR); - vdevgone(maj, mn, mn | UCOMCALLUNIT_MASK, VCHR); + vdevgone(maj, mn | UCOMDIALOUT_MASK, mn | UCOMDIALOUT_MASK, VCHR); + vdevgone(maj, mn | UCOMCALLUNIT_MASK, mn | UCOMCALLUNIT_MASK, VCHR); /* Detach and free the tty. */ tty_detach(sc->sc_tty); @@ -291,6 +305,11 @@ ucomopen(dev, flag, mode, p) */ while (sc->sc_opening) tsleep(&sc->sc_opening, PRIBIO, "ucomop", 0); + + if (sc->sc_dying) { + splx(s); + return (EIO); + } sc->sc_opening = 1; #if defined(__NetBSD__) @@ -302,6 +321,15 @@ ucomopen(dev, flag, mode, p) tp->t_dev = dev; + if (sc->sc_methods->ucom_open != NULL) { + error = sc->sc_methods->ucom_open(sc->sc_parent, + sc->sc_portno); + if (error) { + ucom_cleanup(sc); + return (error); + } + } + ucom_status_change(sc); /* @@ -367,7 +395,8 @@ ucomopen(dev, flag, mode, p) usbd_close_pipe(sc->sc_bulkout_pipe); return (ENOMEM); } - sc->sc_ibuf = usbd_alloc_buffer(sc->sc_ixfer, UCOMIBUFSIZE); + sc->sc_ibuf = usbd_alloc_buffer(sc->sc_ixfer, + sc->sc_ibufsizepad); if (sc->sc_ibuf == NULL) { usbd_free_xfer(sc->sc_ixfer); usbd_close_pipe(sc->sc_bulkin_pipe); @@ -382,7 +411,8 @@ ucomopen(dev, flag, mode, p) usbd_close_pipe(sc->sc_bulkout_pipe); return (ENOMEM); } - sc->sc_obuf = usbd_alloc_buffer(sc->sc_oxfer, UCOMOBUFSIZE); + sc->sc_obuf = usbd_alloc_buffer(sc->sc_oxfer, + sc->sc_obufsizepad); if (sc->sc_obuf == NULL) { usbd_free_xfer(sc->sc_oxfer); usbd_free_xfer(sc->sc_ixfer); @@ -391,9 +421,6 @@ ucomopen(dev, flag, mode, p) return (ENOMEM); } - if (sc->sc_methods->ucom_open != NULL) - sc->sc_methods->ucom_open(sc->sc_parent, sc->sc_portno); - ucomstartread(sc); } sc->sc_opening = 0; @@ -443,12 +470,11 @@ ucomclose(dev, flag, mode, p) if (!ISSET(tp->t_state, TS_ISOPEN)) return (0); + sc->sc_refcnt++; + (*linesw[tp->t_line].l_close)(tp, flag); ttyclose(tp); - if (sc->sc_dying) - return (0); - #if defined(__NetBSD__) if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { #else @@ -465,6 +491,9 @@ ucomclose(dev, flag, mode, p) if (sc->sc_methods->ucom_close != NULL) sc->sc_methods->ucom_close(sc->sc_parent, sc->sc_portno); + if (--sc->sc_refcnt < 0) + usb_detach_wakeup(USBDEV(sc->sc_dev)); + return (0); } @@ -476,11 +505,16 @@ ucomread(dev, uio, flag) { struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)]; struct tty *tp = sc->sc_tty; + int error; if (sc->sc_dying) return (EIO); - return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); + sc->sc_refcnt++; + error = ((*linesw[tp->t_line].l_read)(tp, uio, flag)); + if (--sc->sc_refcnt < 0) + usb_detach_wakeup(USBDEV(sc->sc_dev)); + return (error); } int @@ -491,11 +525,16 @@ ucomwrite(dev, uio, flag) { struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)]; struct tty *tp = sc->sc_tty; + int error; if (sc->sc_dying) return (EIO); - return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); + sc->sc_refcnt++; + error = ((*linesw[tp->t_line].l_write)(tp, uio, flag)); + if (--sc->sc_refcnt < 0) + usb_detach_wakeup(USBDEV(sc->sc_dev)); + return (error); } struct tty * @@ -517,6 +556,23 @@ ucomioctl(dev, cmd, data, flag, p) struct proc *p; { struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)]; + int error; + + sc->sc_refcnt++; + error = ucom_do_ioctl(sc, cmd, data, flag, p); + if (--sc->sc_refcnt < 0) + usb_detach_wakeup(USBDEV(sc->sc_dev)); + return (error); +} + +Static int +ucom_do_ioctl(sc, cmd, data, flag, p) + struct ucom_softc *sc; + u_long cmd; + caddr_t data; + int flag; + struct proc *p; +{ struct tty *tp = sc->sc_tty; int error; int s; @@ -594,7 +650,7 @@ ucomioctl(dev, cmd, data, flag, p) return (error); } -void +Static void tiocm_to_ucom(sc, how, ttybits) struct ucom_softc *sc; int how, ttybits; @@ -626,7 +682,7 @@ tiocm_to_ucom(sc, how, ttybits) ucom_rts(sc, (sc->sc_mcr & UMCR_RTS) != 0); } -int +Static int ucom_to_tiocm(sc) struct ucom_softc *sc; { @@ -658,7 +714,7 @@ XXX; return (ttybits); } -void +Static void ucom_break(sc, onoff) struct ucom_softc *sc; int onoff; @@ -670,7 +726,7 @@ ucom_break(sc, onoff) UCOM_SET_BREAK, onoff); } -void +Static void ucom_dtr(sc, onoff) struct ucom_softc *sc; int onoff; @@ -682,7 +738,7 @@ ucom_dtr(sc, onoff) UCOM_SET_DTR, onoff); } -void +Static void ucom_rts(sc, onoff) struct ucom_softc *sc; int onoff; @@ -707,7 +763,7 @@ ucom_status_change(sc) } } -int +Static int ucomparam(tp, t) struct tty *tp; struct termios *t; @@ -780,10 +836,11 @@ XXX what if the hardware is not open /* * (un)block input via hw flowcontrol */ -void +Static void ucom_hwiflow(sc) struct ucom_softc *sc; { + DPRINTF(("ucom_hwiflow:\n")); #if 0 XXX bus_space_tag_t iot = sc->sc_iot; @@ -803,7 +860,7 @@ XXX #endif } -void +Static void ucomstart(tp) struct tty *tp; { @@ -818,7 +875,7 @@ ucomstart(tp) s = spltty(); if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) { - DPRINTFN(4,("ucomstart: stopped\n")); + DPRINTFN(4,("ucomstart: no go, state=0x%x\n", tp->t_state)); goto out; } if (sc->sc_tx_stopped) @@ -845,11 +902,15 @@ ucomstart(tp) SET(tp->t_state, TS_BUSY); - if (cnt > UCOMOBUFSIZE) { + if (cnt > sc->sc_obufsize) { DPRINTF(("ucomstart: big buffer %d chars\n", cnt)); - cnt = UCOMOBUFSIZE; + cnt = sc->sc_obufsize; } - memcpy(sc->sc_obuf, data, cnt); + if (sc->sc_methods->ucom_write != NULL) + sc->sc_methods->ucom_write(sc->sc_parent, sc->sc_portno, + sc->sc_obuf, data, &cnt); + else + memcpy(sc->sc_obuf, data, cnt); DPRINTFN(4,("ucomstart: %d chars\n", cnt)); usbd_setup_xfer(sc->sc_oxfer, sc->sc_bulkout_pipe, @@ -875,25 +936,26 @@ ucomstop(tp, flag) struct tty *tp; int flag; { - struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(tp->t_dev)]; + DPRINTF(("ucomstop: flag=%d\n", flag)); +#if 0 + /*struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(tp->t_dev)];*/ int s; - DPRINTF(("ucomstop: %d\n", flag)); s = spltty(); if (ISSET(tp->t_state, TS_BUSY)) { DPRINTF(("ucomstop: XXX\n")); - sc->sc_tx_stopped = 1; + /* sc->sc_tx_stopped = 1; */ if (!ISSET(tp->t_state, TS_TTSTOP)) SET(tp->t_state, TS_FLUSH); } splx(s); - +#endif #if !defined(__NetBSD__) return 0; #endif } -void +Static void ucomwritecb(xfer, p, status) usbd_xfer_handle xfer; usbd_private_handle p; @@ -929,7 +991,7 @@ ucomwritecb(xfer, p, status) splx(s); } -usbd_status +Static usbd_status ucomstartread(sc) struct ucom_softc *sc; { @@ -938,7 +1000,7 @@ ucomstartread(sc) DPRINTFN(5,("ucomstartread: start\n")); usbd_setup_xfer(sc->sc_ixfer, sc->sc_bulkin_pipe, (usbd_private_handle)sc, - sc->sc_ibuf, UCOMIBUFSIZE, + sc->sc_ibuf, sc->sc_ibufsize, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT, ucomreadcb); err = usbd_transfer(sc->sc_ixfer); @@ -949,7 +1011,7 @@ ucomstartread(sc) return (USBD_NORMAL_COMPLETION); } -void +Static void ucomreadcb(xfer, p, status) usbd_xfer_handle xfer; usbd_private_handle p; @@ -975,12 +1037,18 @@ ucomreadcb(xfer, p, status) usbd_get_xfer_status(xfer, NULL, (void **)&cp, &cc, NULL); DPRINTFN(5,("ucomreadcb: got %d chars, tp=%p\n", cc, tp)); + if (sc->sc_methods->ucom_read != NULL) + sc->sc_methods->ucom_read(sc->sc_parent, sc->sc_portno, + &cp, &cc); + s = spltty(); /* Give characters to tty layer. */ while (cc-- > 0) { DPRINTFN(7,("ucomreadcb: char=0x%02x\n", *cp)); if ((*rint)(*cp++, tp) == -1) { /* XXX what should we do? */ + printf("%s: lost %d chars\n", USBDEVNAME(sc->sc_dev), + cc); break; } } @@ -993,7 +1061,7 @@ ucomreadcb(xfer, p, status) } } -void +Static void ucom_cleanup(sc) struct ucom_softc *sc; { |