[BACK]Return to ucom.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / usb

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/sys/dev/usb/ucom.c between version 1.81 and 1.82

version 1.81, 2009/12/06 21:40:31 version 1.82, 2010/01/06 20:37:56
Line 48  __KERNEL_RCSID(0, "$NetBSD$");
Line 48  __KERNEL_RCSID(0, "$NetBSD$");
 #include <sys/vnode.h>  #include <sys/vnode.h>
 #include <sys/device.h>  #include <sys/device.h>
 #include <sys/poll.h>  #include <sys/poll.h>
   #include <sys/queue.h>
 #include <sys/kauth.h>  #include <sys/kauth.h>
 #if defined(__NetBSD__)  #if defined(__NetBSD__)
 #include "rnd.h"  #include "rnd.h"
Line 87  int ucomdebug = 0;
Line 88  int ucomdebug = 0;
 #define UCOMDIALOUT(x)          (minor(x) & UCOMDIALOUT_MASK)  #define UCOMDIALOUT(x)          (minor(x) & UCOMDIALOUT_MASK)
 #define UCOMCALLUNIT(x)         (minor(x) & UCOMCALLUNIT_MASK)  #define UCOMCALLUNIT(x)         (minor(x) & UCOMCALLUNIT_MASK)
   
   /*
    * XXX: We can submit multiple input/output buffers to the usb stack
    * to improve throughput, but the usb stack is too lame to deal with this
    * in a number of places.
    */
   #define UCOM_IN_BUFFS   1
   #define UCOM_OUT_BUFFS  1
   
   struct ucom_buffer {
           SIMPLEQ_ENTRY(ucom_buffer) ub_link;
           usbd_xfer_handle ub_xfer;
           u_char *ub_data;
           u_int ub_len;
           u_int ub_index;
   };
   
 struct ucom_softc {  struct ucom_softc {
         USBBASEDEVICE           sc_dev;         /* base device */          USBBASEDEVICE           sc_dev;         /* base device */
   
Line 96  struct ucom_softc {
Line 113  struct ucom_softc {
   
         int                     sc_bulkin_no;   /* bulk in endpoint address */          int                     sc_bulkin_no;   /* bulk in endpoint address */
         usbd_pipe_handle        sc_bulkin_pipe; /* bulk in pipe */          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_ibufsize;    /* read buffer size */
         u_int                   sc_ibufsizepad; /* read buffer size padded */          u_int                   sc_ibufsizepad; /* read buffer size padded */
           struct ucom_buffer      sc_ibuff[UCOM_IN_BUFFS];
           SIMPLEQ_HEAD(, ucom_buffer) sc_ibuff_empty;
           SIMPLEQ_HEAD(, ucom_buffer) sc_ibuff_full;
   
         int                     sc_bulkout_no;  /* bulk out endpoint address */          int                     sc_bulkout_no;  /* bulk out endpoint address */
         usbd_pipe_handle        sc_bulkout_pipe;/* bulk out pipe */          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_obufsize;    /* write buffer size */
         u_int                   sc_opkthdrlen;  /* header length of          u_int                   sc_opkthdrlen;  /* header length of */
                                                  * output packet */          struct ucom_buffer      sc_obuff[UCOM_OUT_BUFFS];
           SIMPLEQ_HEAD(, ucom_buffer) sc_obuff_free;
           SIMPLEQ_HEAD(, ucom_buffer) sc_obuff_full;
   
           void                    *sc_si;
   
         struct ucom_methods     *sc_methods;          struct ucom_methods     *sc_methods;
         void                    *sc_parent;          void                    *sc_parent;
Line 117  struct ucom_softc {
Line 137  struct ucom_softc {
         u_char                  sc_lsr;          u_char                  sc_lsr;
         u_char                  sc_msr;          u_char                  sc_msr;
         u_char                  sc_mcr;          u_char                  sc_mcr;
           volatile u_char         sc_rx_stopped;
           u_char                  sc_rx_unblock;
         u_char                  sc_tx_stopped;          u_char                  sc_tx_stopped;
         int                     sc_swflags;          int                     sc_swflags;
   
Line 143  const struct cdevsw ucom_cdevsw = {
Line 165  const struct cdevsw ucom_cdevsw = {
         ucomstop, ucomtty, ucompoll, nommap, ttykqfilter, D_TTY          ucomstop, ucomtty, ucompoll, nommap, ttykqfilter, D_TTY
 };  };
   
 Static void     ucom_cleanup(struct ucom_softc *);  static void     ucom_cleanup(struct ucom_softc *);
 Static void     ucom_hwiflow(struct ucom_softc *);  static int      ucomparam(struct tty *, struct termios *);
 Static int      ucomparam(struct tty *, struct termios *);  static int      ucomhwiflow(struct tty *, int);
 Static void     ucomstart(struct tty *);  static void     ucomstart(struct tty *);
 Static void     ucom_shutdown(struct ucom_softc *);  static void     ucom_shutdown(struct ucom_softc *);
 Static int      ucom_do_ioctl(struct ucom_softc *, u_long, void *,  static int      ucom_do_ioctl(struct ucom_softc *, u_long, void *,
                               int, struct lwp *);                                int, struct lwp *);
 Static void     ucom_dtr(struct ucom_softc *, int);  static void     ucom_dtr(struct ucom_softc *, int);
 Static void     ucom_rts(struct ucom_softc *, int);  static void     ucom_rts(struct ucom_softc *, int);
 Static void     ucom_break(struct ucom_softc *, int);  static void     ucom_break(struct ucom_softc *, int);
 Static usbd_status ucomstartread(struct ucom_softc *);  static void     tiocm_to_ucom(struct ucom_softc *, u_long, int);
 Static void     ucomreadcb(usbd_xfer_handle, usbd_private_handle, usbd_status);  static int      ucom_to_tiocm(struct ucom_softc *);
 Static void     ucomwritecb(usbd_xfer_handle, usbd_private_handle, usbd_status);  
 Static void     tiocm_to_ucom(struct ucom_softc *, u_long, int);  static void     ucomreadcb(usbd_xfer_handle, usbd_private_handle, usbd_status);
 Static int      ucom_to_tiocm(struct ucom_softc *);  static void     ucom_submit_write(struct ucom_softc *, struct ucom_buffer *);
   static void     ucom_write_status(struct ucom_softc *, struct ucom_buffer *,
                           usbd_status);
   
   static void     ucomwritecb(usbd_xfer_handle, usbd_private_handle, usbd_status);
   static void     ucom_read_complete(struct ucom_softc *);
   static usbd_status ucomsubmitread(struct ucom_softc *, struct ucom_buffer *);
   static void     ucom_softintr(void *);
   
 USB_DECLARE_DRIVER(ucom);  USB_DECLARE_DRIVER(ucom);
   
Line 189  USB_ATTACH(ucom)
Line 218  USB_ATTACH(ucom)
         sc->sc_parent = uca->arg;          sc->sc_parent = uca->arg;
         sc->sc_portno = uca->portno;          sc->sc_portno = uca->portno;
   
           sc->sc_lsr = 0;
           sc->sc_msr = 0;
           sc->sc_mcr = 0;
           sc->sc_tx_stopped = 0;
           sc->sc_swflags = 0;
           sc->sc_opening = 0;
           sc->sc_refcnt = 0;
           sc->sc_dying = 0;
   
           sc->sc_si = softint_establish(SOFTINT_NET, ucom_softintr, sc);
   
         tp = ttymalloc();          tp = ttymalloc();
         tp->t_oproc = ucomstart;          tp->t_oproc = ucomstart;
         tp->t_param = ucomparam;          tp->t_param = ucomparam;
           tp->t_hwiflow = ucomhwiflow;
         sc->sc_tty = tp;          sc->sc_tty = tp;
   
         DPRINTF(("ucom_attach: tty_attach %p\n", tp));          DPRINTF(("ucom_attach: tty_attach %p\n", tp));
Line 212  USB_DETACH(ucom)
Line 253  USB_DETACH(ucom)
         struct ucom_softc *sc = device_private(self);          struct ucom_softc *sc = device_private(self);
         struct tty *tp = sc->sc_tty;          struct tty *tp = sc->sc_tty;
         int maj, mn;          int maj, mn;
         int s;          int s, i;
   
         DPRINTF(("ucom_detach: sc=%p flags=%d tp=%p, pipe=%d,%d\n",          DPRINTF(("ucom_detach: sc=%p flags=%d tp=%p, pipe=%d,%d\n",
                  sc, flags, tp, sc->sc_bulkin_no, sc->sc_bulkout_no));                   sc, flags, tp, sc->sc_bulkin_no, sc->sc_bulkout_no));
Line 238  USB_DETACH(ucom)
Line 279  USB_DETACH(ucom)
                 /* Wait for processes to go away. */                  /* Wait for processes to go away. */
                 usb_detach_wait(USBDEV(sc->sc_dev));                  usb_detach_wait(USBDEV(sc->sc_dev));
         }          }
   
           softint_disestablish(sc->sc_si);
         splx(s);          splx(s);
   
         /* locate the major number */          /* locate the major number */
Line 257  USB_DETACH(ucom)
Line 300  USB_DETACH(ucom)
                 sc->sc_tty = NULL;                  sc->sc_tty = NULL;
         }          }
   
           for (i = 0; i < UCOM_IN_BUFFS; i++) {
                   if (sc->sc_ibuff[i].ub_xfer != NULL)
                           usbd_free_xfer(sc->sc_ibuff[i].ub_xfer);
           }
   
           for (i = 0; i < UCOM_OUT_BUFFS; i++) {
                   if (sc->sc_obuff[i].ub_xfer != NULL)
                           usbd_free_xfer(sc->sc_obuff[i].ub_xfer);
           }
   
         /* Detach the random source */          /* Detach the random source */
 #if defined(__NetBSD__) && NRND > 0  #if defined(__NetBSD__) && NRND > 0
         rnd_detach_source(&sc->sc_rndsource);          rnd_detach_source(&sc->sc_rndsource);
Line 303  ucomopen(dev_t dev, int flag, int mode, 
Line 356  ucomopen(dev_t dev, int flag, int mode, 
         int unit = UCOMUNIT(dev);          int unit = UCOMUNIT(dev);
         usbd_status err;          usbd_status err;
         struct ucom_softc *sc = device_lookup_private(&ucom_cd, unit);          struct ucom_softc *sc = device_lookup_private(&ucom_cd, unit);
           struct ucom_buffer *ub;
         struct tty *tp;          struct tty *tp;
         int s;          int s, i;
         int error;          int error;
   
         if (sc == NULL)          if (sc == NULL)
Line 388  ucomopen(dev_t dev, int flag, int mode, 
Line 442  ucomopen(dev_t dev, int flag, int mode, 
                 ucom_dtr(sc, 1);                  ucom_dtr(sc, 1);
                 ucom_rts(sc, 1);                  ucom_rts(sc, 1);
   
                 /* XXX CLR(sc->sc_rx_flags, RX_ANY_BLOCK);*/  
                 ucom_hwiflow(sc);  
   
                 DPRINTF(("ucomopen: open pipes in=%d out=%d\n",                  DPRINTF(("ucomopen: open pipes in=%d out=%d\n",
                          sc->sc_bulkin_no, sc->sc_bulkout_no));                           sc->sc_bulkin_no, sc->sc_bulkout_no));
   
                 /* Open the bulk pipes */                  /* Open the bulk pipes */
                 err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no, 0,                  err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no,
                                      &sc->sc_bulkin_pipe);                                       USBD_EXCLUSIVE_USE, &sc->sc_bulkin_pipe);
                 if (err) {                  if (err) {
                         DPRINTF(("%s: open bulk in error (addr %d), err=%s\n",                          DPRINTF(("%s: open bulk in error (addr %d), err=%s\n",
                                  USBDEVNAME(sc->sc_dev), sc->sc_bulkin_no,                                   USBDEVNAME(sc->sc_dev), sc->sc_bulkin_no,
Line 414  ucomopen(dev_t dev, int flag, int mode, 
Line 465  ucomopen(dev_t dev, int flag, int mode, 
                         goto fail_1;                          goto fail_1;
                 }                  }
   
                 /* Allocate a request and an input buffer and start reading. */                  sc->sc_rx_unblock = 0;
                 sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev);                  sc->sc_rx_stopped = 0;
                 if (sc->sc_ixfer == NULL) {                  sc->sc_tx_stopped = 0;
                         error = ENOMEM;  
                         goto fail_2;                  memset(sc->sc_ibuff, 0, sizeof(sc->sc_ibuff));
                 }                  memset(sc->sc_obuff, 0, sizeof(sc->sc_obuff));
   
                   SIMPLEQ_INIT(&sc->sc_ibuff_empty);
                   SIMPLEQ_INIT(&sc->sc_ibuff_full);
                   SIMPLEQ_INIT(&sc->sc_obuff_free);
                   SIMPLEQ_INIT(&sc->sc_obuff_full);
   
                   /* Allocate input buffers */
                   for (ub = &sc->sc_ibuff[0]; ub != &sc->sc_ibuff[UCOM_IN_BUFFS];
                       ub++) {
                           ub->ub_xfer = usbd_alloc_xfer(sc->sc_udev);
                           if (ub->ub_xfer == NULL) {
                                   error = ENOMEM;
                                   goto fail_2;
                           }
                           ub->ub_data = usbd_alloc_buffer(ub->ub_xfer,
                               sc->sc_ibufsizepad);
                           if (ub->ub_data == NULL) {
                                   error = ENOMEM;
                                   goto fail_2;
                           }
   
                 sc->sc_ibuf = usbd_alloc_buffer(sc->sc_ixfer,                          if (ucomsubmitread(sc, ub) != USBD_NORMAL_COMPLETION) {
                                                 sc->sc_ibufsizepad);                                  error = EIO;
                 if (sc->sc_ibuf == NULL) {                                  goto fail_2;
                         error = ENOMEM;                          }
                         goto fail_3;  
                 }                  }
   
                 sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev);                  for (ub = &sc->sc_obuff[0]; ub != &sc->sc_obuff[UCOM_OUT_BUFFS];
                 if (sc->sc_oxfer == NULL) {                      ub++) {
                         error = ENOMEM;                          ub->ub_xfer = usbd_alloc_xfer(sc->sc_udev);
                         goto fail_3;                          if (ub->ub_xfer == NULL) {
                 }                                  error = ENOMEM;
                                   goto fail_2;
                           }
                           ub->ub_data = usbd_alloc_buffer(ub->ub_xfer,
                               sc->sc_obufsize);
                           if (ub->ub_data == NULL) {
                                   error = ENOMEM;
                                   goto fail_2;
                           }
   
                 sc->sc_obuf = usbd_alloc_buffer(sc->sc_oxfer,                          SIMPLEQ_INSERT_TAIL(&sc->sc_obuff_free, ub, ub_link);
                                                 sc->sc_obufsize +  
                                                 sc->sc_opkthdrlen);  
                 if (sc->sc_obuf == NULL) {  
                         error = ENOMEM;  
                         goto fail_4;  
                 }                  }
   
                 ucomstartread(sc);  
         }          }
         sc->sc_opening = 0;          sc->sc_opening = 0;
         wakeup(&sc->sc_opening);          wakeup(&sc->sc_opening);
Line 458  ucomopen(dev_t dev, int flag, int mode, 
Line 530  ucomopen(dev_t dev, int flag, int mode, 
   
         return (0);          return (0);
   
 fail_4:  
         usbd_free_xfer(sc->sc_oxfer);  
         sc->sc_oxfer = NULL;  
 fail_3:  
         usbd_free_xfer(sc->sc_ixfer);  
         sc->sc_ixfer = NULL;  
 fail_2:  fail_2:
           usbd_abort_pipe(sc->sc_bulkin_pipe);
           for (i = 0; i < UCOM_IN_BUFFS; i++) {
                   if (sc->sc_ibuff[i].ub_xfer != NULL) {
                           usbd_free_xfer(sc->sc_ibuff[i].ub_xfer);
                           sc->sc_ibuff[i].ub_xfer = NULL;
                           sc->sc_ibuff[i].ub_data = NULL;
                   }
           }
           usbd_abort_pipe(sc->sc_bulkout_pipe);
           for (i = 0; i < UCOM_OUT_BUFFS; i++) {
                   if (sc->sc_obuff[i].ub_xfer != NULL) {
                           usbd_free_xfer(sc->sc_obuff[i].ub_xfer);
                           sc->sc_obuff[i].ub_xfer = NULL;
                           sc->sc_obuff[i].ub_data = NULL;
                   }
           }
   
         usbd_close_pipe(sc->sc_bulkout_pipe);          usbd_close_pipe(sc->sc_bulkout_pipe);
         sc->sc_bulkout_pipe = NULL;          sc->sc_bulkout_pipe = NULL;
 fail_1:  fail_1:
Line 477  fail_0:
Line 560  fail_0:
         return (error);          return (error);
   
 bad:  bad:
           s = spltty();
           CLR(tp->t_state, TS_BUSY);
         if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {          if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
                 /*                  /*
                  * We failed to open the device, and nobody else had it opened.                   * We failed to open the device, and nobody else had it opened.
Line 484  bad:
Line 569  bad:
                  */                   */
                 ucom_cleanup(sc);                  ucom_cleanup(sc);
         }          }
           splx(s);
   
         return (error);          return (error);
 }  }
Line 493  ucomclose(dev_t dev, int flag, int mode,
Line 579  ucomclose(dev_t dev, int flag, int mode,
 {  {
         struct ucom_softc *sc = device_lookup_private(&ucom_cd, UCOMUNIT(dev));          struct ucom_softc *sc = device_lookup_private(&ucom_cd, UCOMUNIT(dev));
         struct tty *tp = sc->sc_tty;          struct tty *tp = sc->sc_tty;
           int s;
   
         DPRINTF(("ucomclose: unit=%d\n", UCOMUNIT(dev)));          DPRINTF(("ucomclose: unit=%d\n", UCOMUNIT(dev)));
         if (!ISSET(tp->t_state, TS_ISOPEN))          if (!ISSET(tp->t_state, TS_ISOPEN))
                 return (0);                  return (0);
   
           s = spltty();
         sc->sc_refcnt++;          sc->sc_refcnt++;
           CLR(tp->t_state, TS_BUSY);
   
         (*tp->t_linesw->l_close)(tp, flag);          (*tp->t_linesw->l_close)(tp, flag);
         ttyclose(tp);          ttyclose(tp);
Line 517  ucomclose(dev_t dev, int flag, int mode,
Line 606  ucomclose(dev_t dev, int flag, int mode,
   
         if (--sc->sc_refcnt < 0)          if (--sc->sc_refcnt < 0)
                 usb_detach_wakeup(USBDEV(sc->sc_dev));                  usb_detach_wakeup(USBDEV(sc->sc_dev));
           splx(s);
   
         return (0);          return (0);
 }  }
Line 594  ucomioctl(dev_t dev, u_long cmd, void *d
Line 684  ucomioctl(dev_t dev, u_long cmd, void *d
         return (error);          return (error);
 }  }
   
 Static int  static int
 ucom_do_ioctl(struct ucom_softc *sc, u_long cmd, void *data,  ucom_do_ioctl(struct ucom_softc *sc, u_long cmd, void *data,
               int flag, struct lwp *l)                int flag, struct lwp *l)
 {  {
Line 676  ucom_do_ioctl(struct ucom_softc *sc, u_l
Line 766  ucom_do_ioctl(struct ucom_softc *sc, u_l
         return (error);          return (error);
 }  }
   
 Static void  static void
 tiocm_to_ucom(struct ucom_softc *sc, u_long how, int ttybits)  tiocm_to_ucom(struct ucom_softc *sc, u_long how, int ttybits)
 {  {
         u_char combits;          u_char combits;
Line 708  tiocm_to_ucom(struct ucom_softc *sc, u_l
Line 798  tiocm_to_ucom(struct ucom_softc *sc, u_l
                 ucom_rts(sc, (sc->sc_mcr & UMCR_RTS) != 0);                  ucom_rts(sc, (sc->sc_mcr & UMCR_RTS) != 0);
 }  }
   
 Static int  static int
 ucom_to_tiocm(struct ucom_softc *sc)  ucom_to_tiocm(struct ucom_softc *sc)
 {  {
         u_char combits;          u_char combits;
Line 739  XXX;
Line 829  XXX;
         return (ttybits);          return (ttybits);
 }  }
   
 Static void  static void
 ucom_break(struct ucom_softc *sc, int onoff)  ucom_break(struct ucom_softc *sc, int onoff)
 {  {
         DPRINTF(("ucom_break: onoff=%d\n", onoff));          DPRINTF(("ucom_break: onoff=%d\n", onoff));
Line 749  ucom_break(struct ucom_softc *sc, int on
Line 839  ucom_break(struct ucom_softc *sc, int on
                     UCOM_SET_BREAK, onoff);                      UCOM_SET_BREAK, onoff);
 }  }
   
 Static void  static void
 ucom_dtr(struct ucom_softc *sc, int onoff)  ucom_dtr(struct ucom_softc *sc, int onoff)
 {  {
         DPRINTF(("ucom_dtr: onoff=%d\n", onoff));          DPRINTF(("ucom_dtr: onoff=%d\n", onoff));
Line 759  ucom_dtr(struct ucom_softc *sc, int onof
Line 849  ucom_dtr(struct ucom_softc *sc, int onof
                     UCOM_SET_DTR, onoff);                      UCOM_SET_DTR, onoff);
 }  }
   
 Static void  static void
 ucom_rts(struct ucom_softc *sc, int onoff)  ucom_rts(struct ucom_softc *sc, int onoff)
 {  {
         DPRINTF(("ucom_rts: onoff=%d\n", onoff));          DPRINTF(("ucom_rts: onoff=%d\n", onoff));
Line 789  ucom_status_change(struct ucom_softc *sc
Line 879  ucom_status_change(struct ucom_softc *sc
         }          }
 }  }
   
 Static int  static int
 ucomparam(struct tty *tp, struct termios *t)  ucomparam(struct tty *tp, struct termios *t)
 {  {
         struct ucom_softc *sc = device_lookup_private(&ucom_cd,          struct ucom_softc *sc = device_lookup_private(&ucom_cd,
Line 858  XXX what if the hardware is not open
Line 948  XXX what if the hardware is not open
         return (0);          return (0);
 }  }
   
 /*  static int
  * (un)block input via hw flowcontrol  ucomhwiflow(struct tty *tp, int block)
  */  
 Static void  
 ucom_hwiflow(struct ucom_softc *sc)  
 {  {
         DPRINTF(("ucom_hwiflow:\n"));          struct ucom_softc *sc = device_lookup_private(&ucom_cd,
 #if 0              UCOMUNIT(tp->t_dev));
 XXX          int old;
         bus_space_tag_t iot = sc->sc_iot;  
         bus_space_handle_t ioh = sc->sc_ioh;  
   
         if (sc->sc_mcr_rts == 0)          old = sc->sc_rx_stopped;
                 return;          sc->sc_rx_stopped = (u_char)block;
   
         if (ISSET(sc->sc_rx_flags, RX_ANY_BLOCK)) {          if (old && !block) {
                 CLR(sc->sc_mcr, sc->sc_mcr_rts);                  int s = splusb();
                 CLR(sc->sc_mcr_active, sc->sc_mcr_rts);                  sc->sc_rx_unblock = 1;
         } else {                  softint_schedule(sc->sc_si);
                 SET(sc->sc_mcr, sc->sc_mcr_rts);                  splx(s);
                 SET(sc->sc_mcr_active, sc->sc_mcr_rts);  
         }          }
         bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr_active);  
 #endif          return (1);
 }  }
   
 Static void  static void
 ucomstart(struct tty *tp)  ucomstart(struct tty *tp)
 {  {
         struct ucom_softc *sc = device_lookup_private(&ucom_cd,          struct ucom_softc *sc = device_lookup_private(&ucom_cd,
             UCOMUNIT(tp->t_dev));              UCOMUNIT(tp->t_dev));
         usbd_status err;          struct ucom_buffer *ub;
         int s;          int s;
         u_char *data;          u_char *data;
         int cnt;          int cnt;
Line 905  ucomstart(struct tty *tp)
Line 989  ucomstart(struct tty *tp)
         if (sc->sc_tx_stopped)          if (sc->sc_tx_stopped)
                 goto out;                  goto out;
   
         if (!ttypull(tp))          if (!ttypull(tp))
                 goto out;                  goto out;
   
         /* Grab the first contiguous region of buffer space. */          /* Grab the first contiguous region of buffer space. */
Line 917  ucomstart(struct tty *tp)
Line 1001  ucomstart(struct tty *tp)
                 goto out;                  goto out;
         }          }
   
         SET(tp->t_state, TS_BUSY);          ub = SIMPLEQ_FIRST(&sc->sc_obuff_free);
           KASSERT(ub != NULL);
           SIMPLEQ_REMOVE_HEAD(&sc->sc_obuff_free, ub_link);
   
         if (cnt > sc->sc_obufsize) {          if (SIMPLEQ_FIRST(&sc->sc_obuff_free) == NULL)
                 DPRINTF(("ucomstart: big buffer %d chars\n", cnt));                  SET(tp->t_state, TS_BUSY);
   
           if (cnt > sc->sc_obufsize)
                 cnt = sc->sc_obufsize;                  cnt = sc->sc_obufsize;
         }  
         if (sc->sc_methods->ucom_write != NULL)          if (sc->sc_methods->ucom_write != NULL)
                 sc->sc_methods->ucom_write(sc->sc_parent, sc->sc_portno,                  sc->sc_methods->ucom_write(sc->sc_parent, sc->sc_portno,
                                            sc->sc_obuf, data, &cnt);                                             ub->ub_data, data, &cnt);
         else          else
                 memcpy(sc->sc_obuf, data, cnt);                  memcpy(ub->ub_data, data, cnt);
   
         DPRINTFN(4,("ucomstart: %d chars\n", cnt));          ub->ub_len = cnt;
         usbd_setup_xfer(sc->sc_oxfer, sc->sc_bulkout_pipe,          ub->ub_index = 0;
                         (usbd_private_handle)sc, sc->sc_obuf, cnt,  
                         USBD_NO_COPY, USBD_NO_TIMEOUT, ucomwritecb);          SIMPLEQ_INSERT_TAIL(&sc->sc_obuff_full, ub, ub_link);
         /* What can we do on error? */  
         err = usbd_transfer(sc->sc_oxfer);          softint_schedule(sc->sc_si);
 #ifdef DIAGNOSTIC  
         if (err != USBD_IN_PROGRESS)  
                 printf("ucomstart: err=%s\n", usbd_errstr(err));  
 #endif  
   
 out:   out:
         splx(s);          splx(s);
 }  }
   
Line 964  ucomstop(struct tty *tp, int flag)
Line 1048  ucomstop(struct tty *tp, int flag)
 #endif  #endif
 }  }
   
 Static void  static void
 ucomwritecb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)  ucom_write_status(struct ucom_softc *sc, struct ucom_buffer *ub,
       usbd_status err)
 {  {
         struct ucom_softc *sc = (struct ucom_softc *)p;  
         struct tty *tp = sc->sc_tty;          struct tty *tp = sc->sc_tty;
         u_int32_t cc;          uint32_t cc = ub->ub_len;
         int s;  
   
         DPRINTFN(5,("ucomwritecb: status=%d\n", status));  
   
         if (status == USBD_CANCELLED || sc->sc_dying)          switch (err) {
                 goto error;          case USBD_IN_PROGRESS:
                   ub->ub_index = ub->ub_len;
                   break;
           case USBD_STALLED:
                   ub->ub_index = 0;
                   softint_schedule(sc->sc_si);
                   break;
           case USBD_NORMAL_COMPLETION:
                   usbd_get_xfer_status(ub->ub_xfer, NULL, NULL, &cc, NULL);
   #if defined(__NetBSD__) && NRND > 0
                   rnd_add_uint32(&sc->sc_rndsource, cc);
   #endif
                   /*FALLTHROUGH*/
           default:
                   SIMPLEQ_REMOVE_HEAD(&sc->sc_obuff_full, ub_link);
                   SIMPLEQ_INSERT_TAIL(&sc->sc_obuff_free, ub, ub_link);
                   cc -= sc->sc_opkthdrlen;
   
                   CLR(tp->t_state, TS_BUSY);
                   if (ISSET(tp->t_state, TS_FLUSH))
                           CLR(tp->t_state, TS_FLUSH);
                   else
                           ndflush(&tp->t_outq, cc);
   
                   if (err != USBD_CANCELLED && err != USBD_IOERROR &&
                       !sc->sc_dying) {
                           if ((ub = SIMPLEQ_FIRST(&sc->sc_obuff_full)) != NULL)
                                   ucom_submit_write(sc, ub);
   
         if (status) {                          (*tp->t_linesw->l_start)(tp);
                 DPRINTF(("ucomwritecb: status=%d\n", status));                  }
                 usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);                  break;
                 /* XXX we should restart after some delay. */  
                 goto error;  
         }          }
   }
   
         usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);  /* Call at spltty() */
 #if defined(__NetBSD__) && NRND > 0  static void
         rnd_add_uint32(&sc->sc_rndsource, cc);  ucom_submit_write(struct ucom_softc *sc, struct ucom_buffer *ub)
 #endif  {
         DPRINTFN(5,("ucomwritecb: cc=%d\n", cc));  
         /* convert from USB bytes to tty bytes */          usbd_setup_xfer(ub->ub_xfer, sc->sc_bulkout_pipe,
         cc -= sc->sc_opkthdrlen;              (usbd_private_handle)sc, ub->ub_data, ub->ub_len,
               USBD_NO_COPY, USBD_NO_TIMEOUT, ucomwritecb);
   
           ucom_write_status(sc, ub, usbd_transfer(ub->ub_xfer));
   }
   
   static void
   ucomwritecb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
   {
           struct ucom_softc *sc = (struct ucom_softc *)p;
           int s;
   
         s = spltty();          s = spltty();
         CLR(tp->t_state, TS_BUSY);  
         if (ISSET(tp->t_state, TS_FLUSH))          ucom_write_status(sc, SIMPLEQ_FIRST(&sc->sc_obuff_full), status);
                 CLR(tp->t_state, TS_FLUSH);  
         else  
                 ndflush(&tp->t_outq, cc);  
         (*tp->t_linesw->l_start)(tp);  
         splx(s);          splx(s);
         return;  }
   
   static void
   ucom_softintr(void *arg)
   {
           struct ucom_softc *sc = arg;
           struct tty *tp = sc->sc_tty;
           struct ucom_buffer *ub;
           int s;
   
           if (!ISSET(tp->t_state, TS_ISOPEN))
                   return;
   
 error:  
         s = spltty();          s = spltty();
         CLR(tp->t_state, TS_BUSY);  
           ub = SIMPLEQ_FIRST(&sc->sc_obuff_full);
   
           if (ub != NULL && ub->ub_index == 0)
                   ucom_submit_write(sc, ub);
   
           if (sc->sc_rx_unblock)
                   ucom_read_complete(sc);
   
         splx(s);          splx(s);
 }  }
   
 Static usbd_status  static void
 ucomstartread(struct ucom_softc *sc)  ucom_read_complete(struct ucom_softc *sc)
   {
           int (*rint)(int, struct tty *);
           struct ucom_buffer *ub;
           struct tty *tp;
           int s;
   
           tp = sc->sc_tty;
           rint = tp->t_linesw->l_rint;
           ub = SIMPLEQ_FIRST(&sc->sc_ibuff_full);
   
           while (ub != NULL && !sc->sc_rx_stopped) {
   
                   s = spltty();
   
                   while (ub->ub_index < ub->ub_len && !sc->sc_rx_stopped) {
                           /* Give characters to tty layer. */
                           if ((*rint)(ub->ub_data[ub->ub_index], tp) == -1) {
                                   /* Overflow: drop remainder */
                                   ub->ub_index = ub->ub_len;
                           } else
                                   ub->ub_index++;
                   }
   
                   splx(s);
   
                   if (ub->ub_index == ub->ub_len) {
                           SIMPLEQ_REMOVE_HEAD(&sc->sc_ibuff_full, ub_link);
   
                           ucomsubmitread(sc, ub);
   
                           ub = SIMPLEQ_FIRST(&sc->sc_ibuff_full);
                   }
           }
   
           sc->sc_rx_unblock = (ub != NULL);
   }
   
   static usbd_status
   ucomsubmitread(struct ucom_softc *sc, struct ucom_buffer *ub)
 {  {
         usbd_status err;          usbd_status err;
   
         DPRINTFN(5,("ucomstartread: start\n"));          usbd_setup_xfer(ub->ub_xfer, sc->sc_bulkin_pipe,
         usbd_setup_xfer(sc->sc_ixfer, sc->sc_bulkin_pipe,              (usbd_private_handle)sc, ub->ub_data, sc->sc_ibufsize,
                         (usbd_private_handle)sc,              USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT, ucomreadcb);
                         sc->sc_ibuf, sc->sc_ibufsize,  
                         USBD_SHORT_XFER_OK | USBD_NO_COPY,          if ((err = usbd_transfer(ub->ub_xfer)) != USBD_IN_PROGRESS) {
                         USBD_NO_TIMEOUT, ucomreadcb);                  /* XXX: Recover from this, please! */
         err = usbd_transfer(sc->sc_ixfer);                  printf("ucomsubmitread: err=%s\n", usbd_errstr(err));
         if (err != USBD_IN_PROGRESS) {  
                 DPRINTF(("ucomstartread: err=%s\n", usbd_errstr(err)));  
                 return (err);                  return (err);
         }          }
   
           SIMPLEQ_INSERT_TAIL(&sc->sc_ibuff_empty, ub, ub_link);
   
         return (USBD_NORMAL_COMPLETION);          return (USBD_NORMAL_COMPLETION);
 }  }
   
 Static void  static void
 ucomreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)  ucomreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
 {  {
         struct ucom_softc *sc = (struct ucom_softc *)p;          struct ucom_softc *sc = (struct ucom_softc *)p;
         struct tty *tp = sc->sc_tty;          struct tty *tp = sc->sc_tty;
         int (*rint)(int, struct tty *) = tp->t_linesw->l_rint;          struct ucom_buffer *ub;
         usbd_status err;  
         u_int32_t cc;          u_int32_t cc;
         u_char *cp;          u_char *cp;
         int s;          int s;
   
         DPRINTFN(5,("ucomreadcb: status=%d\n", status));          ub = SIMPLEQ_FIRST(&sc->sc_ibuff_empty);
           SIMPLEQ_REMOVE_HEAD(&sc->sc_ibuff_empty, ub_link);
   
         if (status == USBD_CANCELLED || status == USBD_IOERROR ||          if (status == USBD_CANCELLED || status == USBD_IOERROR ||
             sc->sc_dying) {              sc->sc_dying) {
                 DPRINTF(("ucomreadcb: dying\n"));                  DPRINTF(("ucomreadcb: dying\n"));
                   ub->ub_index = ub->ub_len = 0;
                 /* Send something to wake upper layer */                  /* Send something to wake upper layer */
                 s = spltty();                  s = spltty();
                 (*rint)('\n', tp);                  if (status != USBD_CANCELLED) {
                 mutex_spin_enter(&tty_lock);    /* XXX */                          (tp->t_linesw->l_rint)('\n', tp);
                 ttwakeup(tp);                          mutex_spin_enter(&tty_lock);    /* XXX */
                 mutex_spin_exit(&tty_lock);     /* XXX */                          ttwakeup(tp);
                           mutex_spin_exit(&tty_lock);     /* XXX */
                   }
                 splx(s);                  splx(s);
                 return;                  return;
         }          }
   
         if (status) {          if (status == USBD_STALLED) {
                 usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);                  usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
                 /* XXX we should restart after some delay. */                  ucomsubmitread(sc, ub);
                   return;
           }
   
           if (status != USBD_NORMAL_COMPLETION) {
                   printf("ucomreadcb: wonky status=%s\n", usbd_errstr(status));
                 return;                  return;
         }          }
   
         usbd_get_xfer_status(xfer, NULL, (void *)&cp, &cc, NULL);          usbd_get_xfer_status(xfer, NULL, (void *)&cp, &cc, NULL);
   
           if (cc == 0) {
                   aprint_normal_dev(sc->sc_dev,
                       "ucomreadcb: zero length xfer!\n");
           }
   
           KDASSERT(cp == ub->ub_data);
   
 #if defined(__NetBSD__) && NRND > 0  #if defined(__NetBSD__) && NRND > 0
         rnd_add_uint32(&sc->sc_rndsource, cc);          rnd_add_uint32(&sc->sc_rndsource, cc);
 #endif  #endif
         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();          if (sc->sc_opening) {
         /* Give characters to tty layer. */                  ucomsubmitread(sc, ub);
         while (cc-- > 0) {                  return;
                 DPRINTFN(7,("ucomreadcb: char=0x%02x\n", *cp));  
                 if ((*rint)(*cp++, tp) == -1) {  
                         /* XXX what should we do? */  
                         aprint_error_dev(sc->sc_dev, "lost %d chars\n",  
                                cc);  
                         break;  
                 }  
         }          }
         splx(s);  
   
         err = ucomstartread(sc);          if (sc->sc_methods->ucom_read != NULL) {
         if (err) {                  sc->sc_methods->ucom_read(sc->sc_parent, sc->sc_portno,
                 aprint_error_dev(sc->sc_dev, "read start failed\n");                      &cp, &cc);
                 /* XXX what should we do now? */                  ub->ub_index = (u_int)(cp - ub->ub_data);
         }          } else
                   ub->ub_index = 0;
   
           ub->ub_len = cc;
   
           SIMPLEQ_INSERT_TAIL(&sc->sc_ibuff_full, ub, ub_link);
   
           ucom_read_complete(sc);
 }  }
   
 Static void  static void
 ucom_cleanup(struct ucom_softc *sc)  ucom_cleanup(struct ucom_softc *sc)
 {  {
           struct ucom_buffer *ub;
   
         DPRINTF(("ucom_cleanup: closing pipes\n"));          DPRINTF(("ucom_cleanup: closing pipes\n"));
   
         ucom_shutdown(sc);          ucom_shutdown(sc);
Line 1104  ucom_cleanup(struct ucom_softc *sc)
Line 1289  ucom_cleanup(struct ucom_softc *sc)
                 usbd_close_pipe(sc->sc_bulkout_pipe);                  usbd_close_pipe(sc->sc_bulkout_pipe);
                 sc->sc_bulkout_pipe = NULL;                  sc->sc_bulkout_pipe = NULL;
         }          }
         if (sc->sc_ixfer != NULL) {          for (ub = &sc->sc_ibuff[0]; ub != &sc->sc_ibuff[UCOM_IN_BUFFS]; ub++) {
                 usbd_free_xfer(sc->sc_ixfer);                  if (ub->ub_xfer != NULL) {
                 sc->sc_ixfer = NULL;                          usbd_free_xfer(ub->ub_xfer);
         }                          ub->ub_xfer = NULL;
         if (sc->sc_oxfer != NULL) {                          ub->ub_data = NULL;
                 usbd_free_xfer(sc->sc_oxfer);                  }
                 sc->sc_oxfer = NULL;          }
           for (ub = &sc->sc_obuff[0]; ub != &sc->sc_obuff[UCOM_OUT_BUFFS]; ub++){
                   if (ub->ub_xfer != NULL) {
                           usbd_free_xfer(ub->ub_xfer);
                           ub->ub_xfer = NULL;
                           ub->ub_data = NULL;
                   }
         }          }
 }  }
   

Legend:
Removed from v.1.81  
changed lines
  Added in v.1.82

CVSweb <webmaster@jp.NetBSD.org>