Diff for /src/sys/dev/usbmisc/ugen/ugen.c between versions 1.7 and 1.8

version 1.7, 2003/08/07 21:17:14 version 1.8, 2003/12/30 01:01:46
Line 1 Line 1
/*        $NetBSD: ugen.c,v 1.27 1999/10/28 12:08:38 augustss Exp $       *//*
/*        $FreeBSD: src/sys/dev/usb/ugen.c,v 1.38.2.9 2002/11/06 14:41:01 joe Exp $  */ * $NetBSD: ugen.c,v 1.27 1999/10/28 12:08:38 augustss Exp $
/*        $DragonFly$     */ * $NetBSD: ugen.c,v 1.59 2002/07/11 21:14:28 augustss Exp $
  * $FreeBSD: src/sys/dev/usb/ugen.c,v 1.81 2003/11/09 09:17:22 tanimura Exp $
  * $DragonFly$
  */
 
 /* 
  * Also already merged from NetBSD:
  *      $NetBSD: ugen.c,v 1.61 2002/09/23 05:51:20 simonb Exp $
  *      $NetBSD: ugen.c,v 1.64 2003/06/28 14:21:46 darrenr Exp $
  *      $NetBSD: ugen.c,v 1.65 2003/06/29 22:30:56 fvdl Exp $
  */
   
 /*  /*
  * Copyright (c) 1998 The NetBSD Foundation, Inc.   * Copyright (c) 1998 The NetBSD Foundation, Inc.
Line 57 Line 67
 #endif  #endif
 #include <sys/tty.h>  #include <sys/tty.h>
 #include <sys/file.h>  #include <sys/file.h>
   #if __FreeBSD_version >= 500014
   #include <sys/selinfo.h>
   #else
 #include <sys/select.h>  #include <sys/select.h>
#include <sys/proc.h>#endif
 #include <sys/vnode.h>  #include <sys/vnode.h>
 #include <sys/poll.h>  #include <sys/poll.h>
 #include <sys/sysctl.h>  #include <sys/sysctl.h>
Line 89  SYSCTL_INT(_hw_usb_ugen, OID_AUTO, debug Line 102  SYSCTL_INT(_hw_usb_ugen, OID_AUTO, debug
   
 struct ugen_endpoint {  struct ugen_endpoint {
         struct ugen_softc *sc;          struct ugen_softc *sc;
   #if defined(__FreeBSD__)
           dev_t dev;
   #endif
         usb_endpoint_descriptor_t *edesc;          usb_endpoint_descriptor_t *edesc;
         usbd_interface_handle iface;          usbd_interface_handle iface;
         int state;          int state;
Line 113  struct ugen_endpoint { Line 129  struct ugen_endpoint {
 struct ugen_softc {  struct ugen_softc {
         USBBASEDEVICE sc_dev;           /* base device */          USBBASEDEVICE sc_dev;           /* base device */
         usbd_device_handle sc_udev;          usbd_device_handle sc_udev;
   #if defined(__FreeBSD__)
           dev_t dev;
   #endif
   
         char sc_is_open[USB_MAX_ENDPOINTS];          char sc_is_open[USB_MAX_ENDPOINTS];
         struct ugen_endpoint sc_endpoints[USB_MAX_ENDPOINTS][2];          struct ugen_endpoint sc_endpoints[USB_MAX_ENDPOINTS][2];
Line 155  Static struct cdevsw ugen_cdevsw = { Line 174  Static struct cdevsw ugen_cdevsw = {
 };  };
 #endif  #endif
   
Static void ugenintr(usbd_xfer_handle xfer, usbd_private_handle addr, Static void ugenintr(usbd_xfer_handle xfer, usbd_private_handle addr,
                          usbd_status status);                            usbd_status status);
 Static void ugen_isoc_rintr(usbd_xfer_handle xfer, usbd_private_handle addr,  Static void ugen_isoc_rintr(usbd_xfer_handle xfer, usbd_private_handle addr,
                             usbd_status status);                              usbd_status status);
 Static int ugen_do_read(struct ugen_softc *, int, struct uio *, int);  Static int ugen_do_read(struct ugen_softc *, int, struct uio *, int);
 Static int ugen_do_write(struct ugen_softc *, int, struct uio *, int);  Static int ugen_do_write(struct ugen_softc *, int, struct uio *, int);
Static int ugen_do_ioctl(struct ugen_softc *, int, u_long, Static int ugen_do_ioctl(struct ugen_softc *, int, u_long,
                              caddr_t, int, usb_proc_ptr);                            caddr_t, int, usb_proc_ptr);
 #if defined(__FreeBSD__)
 Static void ugen_make_devnodes(struct ugen_softc *sc);
 Static void ugen_destroy_devnodes(struct ugen_softc *sc);
 #endif
 Static int ugen_set_config(struct ugen_softc *sc, int configno);  Static int ugen_set_config(struct ugen_softc *sc, int configno);
 Static usb_config_descriptor_t *ugen_get_cdesc(struct ugen_softc *sc,  Static usb_config_descriptor_t *ugen_get_cdesc(struct ugen_softc *sc,
                                                    int index, int *lenp);                                                int index, int *lenp);
 Static usbd_status ugen_set_interface(struct ugen_softc *, int, int);  Static usbd_status ugen_set_interface(struct ugen_softc *, int, int);
 Static int ugen_get_alt_index(struct ugen_softc *sc, int ifaceidx);  Static int ugen_get_alt_index(struct ugen_softc *sc, int ifaceidx);
   
Line 179  USB_MATCH(ugen) Line 202  USB_MATCH(ugen)
 {  {
         USB_MATCH_START(ugen, uaa);          USB_MATCH_START(ugen, uaa);
   
   #if 0
           if (uaa->matchlvl)
                   return (uaa->matchlvl);
   #endif
         if (uaa->usegeneric)          if (uaa->usegeneric)
                 return (UMATCH_GENERIC);                  return (UMATCH_GENERIC);
         else          else
Line 192  USB_ATTACH(ugen) Line 219  USB_ATTACH(ugen)
         char devinfo[1024];          char devinfo[1024];
         usbd_status err;          usbd_status err;
         int conf;          int conf;
        
         usbd_devinfo(uaa->device, 0, devinfo);          usbd_devinfo(uaa->device, 0, devinfo);
         USB_ATTACH_SETUP;          USB_ATTACH_SETUP;
         printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);          printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
Line 204  USB_ATTACH(ugen) Line 231  USB_ATTACH(ugen)
         /* First set configuration index 0, the default one for ugen. */          /* First set configuration index 0, the default one for ugen. */
         err = usbd_set_config_index(udev, 0, 0);          err = usbd_set_config_index(udev, 0, 0);
         if (err) {          if (err) {
                printf("%s: setting configuration index 0 failed\n",                 printf("%s: setting configuration index 0 failed\n",
                        USBDEVNAME(sc->sc_dev));                         USBDEVNAME(sc->sc_dev));
                 sc->sc_dying = 1;                  sc->sc_dying = 1;
                 USB_ATTACH_ERROR_RETURN;                  USB_ATTACH_ERROR_RETURN;
Line 214  USB_ATTACH(ugen) Line 241  USB_ATTACH(ugen)
         /* Set up all the local state for this configuration. */          /* Set up all the local state for this configuration. */
         err = ugen_set_config(sc, conf);          err = ugen_set_config(sc, conf);
         if (err) {          if (err) {
                printf("%s: setting configuration %d failed\n",                 printf("%s: setting configuration %d failed\n",
                        USBDEVNAME(sc->sc_dev), conf);                         USBDEVNAME(sc->sc_dev), conf);
                 sc->sc_dying = 1;                  sc->sc_dying = 1;
                 USB_ATTACH_ERROR_RETURN;                  USB_ATTACH_ERROR_RETURN;
         }          }
   
   #if defined(__FreeBSD__)
           /* the main device, ctrl endpoint */
           sc->dev = make_dev(&ugen_cdevsw, UGENMINOR(USBDEVUNIT(sc->sc_dev), 0),
                   UID_ROOT, GID_OPERATOR, 0644, "%s", USBDEVNAME(sc->sc_dev));
   #endif
   
         USB_ATTACH_SUCCESS_RETURN;          USB_ATTACH_SUCCESS_RETURN;
 }  }
   
   #if defined(__FreeBSD__)
   Static void
   ugen_make_devnodes(struct ugen_softc *sc)
   {
           int endptno;
           dev_t dev;
   
           for (endptno = 1; endptno < USB_MAX_ENDPOINTS; endptno++) {
                   if (sc->sc_endpoints[endptno][IN].sc != NULL ||
                       sc->sc_endpoints[endptno][OUT].sc != NULL ) {
                           /* endpt can be 0x81 and 0x01, representing
                            * endpoint address 0x01 and IN/OUT directions.
                            * We map both endpts to the same device,
                            * IN is reading from it, OUT is writing to it.
                            *
                            * In the if clause above we check whether one
                            * of the structs is populated.
                            */
                           dev = make_dev(&ugen_cdevsw,
                                   UGENMINOR(USBDEVUNIT(sc->sc_dev), endptno),
                                   UID_ROOT, GID_OPERATOR, 0644,
                                   "%s.%d",
                                   USBDEVNAME(sc->sc_dev), endptno);
                           if (sc->sc_endpoints[endptno][IN].sc != NULL)
                                   sc->sc_endpoints[endptno][IN].dev = dev;
                           if (sc->sc_endpoints[endptno][OUT].sc != NULL)
                                   sc->sc_endpoints[endptno][OUT].dev = dev;
                   }
           }
   }
   
   Static void
   ugen_destroy_devnodes(struct ugen_softc *sc)
   {
           int endptno;
           dev_t dev;
   
           /* destroy all devices for the other (existing) endpoints as well */
           for (endptno = 1; endptno < USB_MAX_ENDPOINTS; endptno++) {
                   if (sc->sc_endpoints[endptno][IN].sc != NULL ||
                       sc->sc_endpoints[endptno][OUT].sc != NULL ) {
                           /* endpt can be 0x81 and 0x01, representing
                            * endpoint address 0x01 and IN/OUT directions.
                            * We map both endpoint addresses to the same device,
                            * IN is reading from it, OUT is writing to it.
                            *
                            * In the if clause above we check whether one
                            * of the structs is populated.
                            */
                           if (sc->sc_endpoints[endptno][IN].sc != NULL)
                                   dev = sc->sc_endpoints[endptno][IN].dev;
                           else
                                   dev = sc->sc_endpoints[endptno][OUT].dev;
                           destroy_dev(dev);
                   }
           }
   }
   #endif
   
 Static int  Static int
 ugen_set_config(struct ugen_softc *sc, int configno)  ugen_set_config(struct ugen_softc *sc, int configno)
 {  {
Line 238  ugen_set_config(struct ugen_softc *sc, i Line 330  ugen_set_config(struct ugen_softc *sc, i
         DPRINTFN(1,("ugen_set_config: %s to configno %d, sc=%p\n",          DPRINTFN(1,("ugen_set_config: %s to configno %d, sc=%p\n",
                     USBDEVNAME(sc->sc_dev), configno, sc));                      USBDEVNAME(sc->sc_dev), configno, sc));
   
   #if defined(__FreeBSD__)
           ugen_destroy_devnodes(sc);
   #endif
   
         /* We start at 1, not 0, because we don't care whether the          /* We start at 1, not 0, because we don't care whether the
          * control endpoint is open or not. It is always present.           * control endpoint is open or not. It is always present.
          */           */
Line 249  ugen_set_config(struct ugen_softc *sc, i Line 345  ugen_set_config(struct ugen_softc *sc, i
                         return (USBD_IN_USE);                          return (USBD_IN_USE);
                 }                  }
   
           /* Avoid setting the current value. */
         if (usbd_get_config_descriptor(dev)->bConfigurationValue != configno) {          if (usbd_get_config_descriptor(dev)->bConfigurationValue != configno) {
                /* Avoid setting the current value. */                err = usbd_set_config_no(dev, configno, 1);
                err = usbd_set_config_no(dev, configno, 0); 
                 if (err)                  if (err)
                         return (err);                          return (err);
         }          }
Line 270  ugen_set_config(struct ugen_softc *sc, i Line 366  ugen_set_config(struct ugen_softc *sc, i
                         return (err);                          return (err);
                 for (endptno = 0; endptno < nendpt; endptno++) {                  for (endptno = 0; endptno < nendpt; endptno++) {
                         ed = usbd_interface2endpoint_descriptor(iface,endptno);                          ed = usbd_interface2endpoint_descriptor(iface,endptno);
                        endpt = UE_GET_ADDR(ed->bEndpointAddress);                        endpt = ed->bEndpointAddress;
                        dir = UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN?                        dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
                                        IN : OUT;                        sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
 
                        sce = &sc->sc_endpoints[endpt][dir]; 
                         DPRINTFN(1,("ugen_set_config: endptno %d, endpt=0x%02x"                          DPRINTFN(1,("ugen_set_config: endptno %d, endpt=0x%02x"
                                    "(%d,%d), sce=%p\n",                                     "(%d,%d), sce=%p\n",
                                    endptno, endpt, endpt, dir, sce));                                    endptno, endpt, UE_GET_ADDR(endpt),
                                    UE_GET_DIR(endpt), sce));
                         sce->sc = sc;                          sce->sc = sc;
                         sce->edesc = ed;                          sce->edesc = ed;
                         sce->iface = iface;                          sce->iface = iface;
                 }                  }
         }          }
   
   
 #if defined(__FreeBSD__)  #if defined(__FreeBSD__)
        /* the main device, ctrl endpoint */        ugen_make_devnodes(sc);
        make_dev(&ugen_cdevsw, UGENMINOR(USBDEVUNIT(sc->sc_dev), 0), 
                UID_ROOT, GID_OPERATOR, 0644, "%s", USBDEVNAME(sc->sc_dev)); 
 
        for (endptno = 1; endptno < USB_MAX_ENDPOINTS; endptno++) { 
                if (sc->sc_endpoints[endptno][IN].sc != NULL || 
                    sc->sc_endpoints[endptno][OUT].sc != NULL ) { 
                        /* endpt can be 0x81 and 0x01, representing 
                         * endpoint address 0x01 and IN/OUT directions. 
                         * We map both endpts to the same device, 
                         * IN is reading from it, OUT is writing to it. 
                         * 
                         * In the if clause above we check whether one 
                         * of the structs is populated. 
                         */ 
                        make_dev(&ugen_cdevsw, 
                                UGENMINOR(USBDEVUNIT(sc->sc_dev), endptno), 
                                UID_ROOT, GID_OPERATOR, 0644, 
                                "%s.%d", 
                                USBDEVNAME(sc->sc_dev), endptno); 
                } 
        } 
 #endif  #endif
   
         return (USBD_NORMAL_COMPLETION);          return (USBD_NORMAL_COMPLETION);
Line 330  ugenopen(dev_t dev, int flag, int mode, Line 402  ugenopen(dev_t dev, int flag, int mode,
   
         USB_GET_SC_OPEN(ugen, unit, sc);          USB_GET_SC_OPEN(ugen, unit, sc);
   
        DPRINTFN(5, ("ugenopen: flag=%d, mode=%d, unit=%d endpt=%d\n",         DPRINTFN(5, ("ugenopen: flag=%d, mode=%d, unit=%d endpt=%d\n",
                      flag, mode, unit, endpt));                       flag, mode, unit, endpt));
   
         if (sc == NULL || sc->sc_dying)          if (sc == NULL || sc->sc_dying)
Line 361  ugenopen(dev_t dev, int flag, int mode, Line 433  ugenopen(dev_t dev, int flag, int mode,
                 sce = &sc->sc_endpoints[endpt][dir];                  sce = &sc->sc_endpoints[endpt][dir];
                 sce->state = 0;                  sce->state = 0;
                 sce->timeout = USBD_NO_TIMEOUT;                  sce->timeout = USBD_NO_TIMEOUT;
                DPRINTFN(5, ("ugenopen: sc=%p, endpt=%d, dir=%d, sce=%p\n",                 DPRINTFN(5, ("ugenopen: sc=%p, endpt=%d, dir=%d, sce=%p\n",
                              sc, endpt, dir, sce));                               sc, endpt, dir, sce));
                 edesc = sce->edesc;                  edesc = sce->edesc;
                 switch (edesc->bmAttributes & UE_XFERTYPE) {                  switch (edesc->bmAttributes & UE_XFERTYPE) {
                 case UE_INTERRUPT:                  case UE_INTERRUPT:
                           if (dir == OUT) {
                                   err = usbd_open_pipe(sce->iface,
                                       edesc->bEndpointAddress, 0, &sce->pipeh);
                                   if (err)
                                           return (EIO);
                                   break;
                           }
                         isize = UGETW(edesc->wMaxPacketSize);                          isize = UGETW(edesc->wMaxPacketSize);
                         if (isize == 0) /* shouldn't happen */                          if (isize == 0) /* shouldn't happen */
                                 return (EINVAL);                                  return (EINVAL);
                         sce->ibuf = malloc(isize, M_USBDEV, M_WAITOK);                          sce->ibuf = malloc(isize, M_USBDEV, M_WAITOK);
                        DPRINTFN(5, ("ugenopen: intr endpt=%d,isize=%d\n",                         DPRINTFN(5, ("ugenopen: intr endpt=%d,isize=%d\n",
                                      endpt, isize));                                       endpt, isize));
                         if (clalloc(&sce->q, UGEN_IBSIZE, 0) == -1)                          if (clalloc(&sce->q, UGEN_IBSIZE, 0) == -1)
                                 return (ENOMEM);                                  return (ENOMEM);
                        err = usbd_open_pipe_intr(sce->iface,                         err = usbd_open_pipe_intr(sce->iface,
                                edesc->bEndpointAddress,                                 edesc->bEndpointAddress,
                                USBD_SHORT_XFER_OK, &sce->pipeh, sce,                                 USBD_SHORT_XFER_OK, &sce->pipeh, sce,
                                 sce->ibuf, isize, ugenintr,                                  sce->ibuf, isize, ugenintr,
                                 USBD_DEFAULT_INTERVAL);                                  USBD_DEFAULT_INTERVAL);
                         if (err) {                          if (err) {
Line 387  ugenopen(dev_t dev, int flag, int mode, Line 466  ugenopen(dev_t dev, int flag, int mode,
                         DPRINTFN(5, ("ugenopen: interrupt open done\n"));                          DPRINTFN(5, ("ugenopen: interrupt open done\n"));
                         break;                          break;
                 case UE_BULK:                  case UE_BULK:
                        err = usbd_open_pipe(sce->iface,                         err = usbd_open_pipe(sce->iface,
                                   edesc->bEndpointAddress, 0, &sce->pipeh);                                    edesc->bEndpointAddress, 0, &sce->pipeh);
                         if (err)                          if (err)
                                 return (EIO);                                  return (EIO);
Line 402  ugenopen(dev_t dev, int flag, int mode, Line 481  ugenopen(dev_t dev, int flag, int mode,
                                 M_USBDEV, M_WAITOK);                                  M_USBDEV, M_WAITOK);
                         sce->cur = sce->fill = sce->ibuf;                          sce->cur = sce->fill = sce->ibuf;
                         sce->limit = sce->ibuf + isize * UGEN_NISOFRAMES;                          sce->limit = sce->ibuf + isize * UGEN_NISOFRAMES;
                        DPRINTFN(5, ("ugenopen: isoc endpt=%d, isize=%d\n",                         DPRINTFN(5, ("ugenopen: isoc endpt=%d, isize=%d\n",
                                      endpt, isize));                                       endpt, isize));
                         err = usbd_open_pipe(sce->iface,                          err = usbd_open_pipe(sce->iface,
                                   edesc->bEndpointAddress, 0, &sce->pipeh);                                    edesc->bEndpointAddress, 0, &sce->pipeh);
Line 439  ugenopen(dev_t dev, int flag, int mode, Line 518  ugenopen(dev_t dev, int flag, int mode,
                                 usbd_free_xfer(sce->isoreqs[i].xfer);                                  usbd_free_xfer(sce->isoreqs[i].xfer);
                         return (ENOMEM);                          return (ENOMEM);
                 case UE_CONTROL:                  case UE_CONTROL:
                           sce->timeout = USBD_DEFAULT_TIMEOUT;
                         return (EINVAL);                          return (EINVAL);
                 }                  }
         }          }
Line 479  ugenclose(dev_t dev, int flag, int mode, Line 559  ugenclose(dev_t dev, int flag, int mode,
                 sce = &sc->sc_endpoints[endpt][dir];                  sce = &sc->sc_endpoints[endpt][dir];
                 if (sce == NULL || sce->pipeh == NULL)                  if (sce == NULL || sce->pipeh == NULL)
                         continue;                          continue;
                DPRINTFN(5, ("ugenclose: endpt=%d dir=%d sce=%p\n",                 DPRINTFN(5, ("ugenclose: endpt=%d dir=%d sce=%p\n",
                              endpt, dir, sce));                               endpt, dir, sce));
   
                 usbd_abort_pipe(sce->pipeh);                  usbd_abort_pipe(sce->pipeh);
Line 501  ugenclose(dev_t dev, int flag, int mode, Line 581  ugenclose(dev_t dev, int flag, int mode,
                 if (sce->ibuf != NULL) {                  if (sce->ibuf != NULL) {
                         free(sce->ibuf, M_USBDEV);                          free(sce->ibuf, M_USBDEV);
                         sce->ibuf = NULL;                          sce->ibuf = NULL;
                           clfree(&sce->q);
                 }                  }
         }          }
         sc->sc_is_open[endpt] = 0;          sc->sc_is_open[endpt] = 0;
Line 528  ugen_do_read(struct ugen_softc *sc, int Line 609  ugen_do_read(struct ugen_softc *sc, int
         if (endpt == USB_CONTROL_ENDPOINT)          if (endpt == USB_CONTROL_ENDPOINT)
                 return (ENODEV);                  return (ENODEV);
   
#ifdef DIAGNOSTIC        if (sce == NULL)
                 return (EINVAL);
 
         if (sce->edesc == NULL) {          if (sce->edesc == NULL) {
                 printf("ugenread: no edesc\n");                  printf("ugenread: no edesc\n");
                 return (EIO);                  return (EIO);
Line 537  ugen_do_read(struct ugen_softc *sc, int Line 620  ugen_do_read(struct ugen_softc *sc, int
                 printf("ugenread: no pipe\n");                  printf("ugenread: no pipe\n");
                 return (EIO);                  return (EIO);
         }          }
 #endif  
   
         switch (sce->edesc->bmAttributes & UE_XFERTYPE) {          switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
         case UE_INTERRUPT:          case UE_INTERRUPT:
                /* Block until activity occured. */                /* Block until activity occurred. */
                 s = splusb();                  s = splusb();
                 while (sce->q.c_cc == 0) {                  while (sce->q.c_cc == 0) {
                         if (flag & IO_NDELAY) {                          if (flag & IO_NDELAY) {
Line 549  ugen_do_read(struct ugen_softc *sc, int Line 631  ugen_do_read(struct ugen_softc *sc, int
                                 return (EWOULDBLOCK);                                  return (EWOULDBLOCK);
                         }                          }
                         sce->state |= UGEN_ASLP;                          sce->state |= UGEN_ASLP;
                        DPRINTFN(5, ("ugenread: sleep on %p\n", sc));                        DPRINTFN(5, ("ugenread: sleep on %p\n", sce));
                         error = tsleep(sce, PCATCH, "ugenri", 0);                          error = tsleep(sce, PCATCH, "ugenri", 0);
                         DPRINTFN(5, ("ugenread: woke, error=%d\n", error));                          DPRINTFN(5, ("ugenread: woke, error=%d\n", error));
                         if (sc->sc_dying)                          if (sc->sc_dying)
Line 586  ugen_do_read(struct ugen_softc *sc, int Line 668  ugen_do_read(struct ugen_softc *sc, int
                         tn = n;                          tn = n;
                         err = usbd_bulk_transfer(                          err = usbd_bulk_transfer(
                                 xfer, sce->pipeh,                                  xfer, sce->pipeh,
                                sce->state & UGEN_SHORT_OK ?                                 sce->state & UGEN_SHORT_OK ?
                                    USBD_SHORT_XFER_OK : 0,                                     USBD_SHORT_XFER_OK : 0,
                                 sce->timeout, buf, &tn, "ugenrb");                                  sce->timeout, buf, &tn, "ugenrb");
                         if (err) {                          if (err) {
                                 if (err == USBD_INTERRUPTED)                                  if (err == USBD_INTERRUPTED)
Line 613  ugen_do_read(struct ugen_softc *sc, int Line 695  ugen_do_read(struct ugen_softc *sc, int
                                 return (EWOULDBLOCK);                                  return (EWOULDBLOCK);
                         }                          }
                         sce->state |= UGEN_ASLP;                          sce->state |= UGEN_ASLP;
                        DPRINTFN(5, ("ugenread: sleep on %p\n", sc));                        DPRINTFN(5, ("ugenread: sleep on %p\n", sce));
                         error = tsleep(sce, PCATCH, "ugenri", 0);                          error = tsleep(sce, PCATCH, "ugenri", 0);
                         DPRINTFN(5, ("ugenread: woke, error=%d\n", error));                          DPRINTFN(5, ("ugenread: woke, error=%d\n", error));
                         if (sc->sc_dying)                          if (sc->sc_dying)
Line 643  ugen_do_read(struct ugen_softc *sc, int Line 725  ugen_do_read(struct ugen_softc *sc, int
                 splx(s);                  splx(s);
                 break;                  break;
   
                
         default:          default:
                 return (ENXIO);                  return (ENXIO);
         }          }
Line 676  ugen_do_write(struct ugen_softc *sc, int Line 758  ugen_do_write(struct ugen_softc *sc, int
         usbd_xfer_handle xfer;          usbd_xfer_handle xfer;
         usbd_status err;          usbd_status err;
   
        DPRINTFN(5, ("%s: ugen_do_write: %d\n", USBDEVNAME(sc->sc_dev), endpt));        DPRINTFN(5, ("%s: ugenwrite: %d\n", USBDEVNAME(sc->sc_dev), endpt));
   
         if (sc->sc_dying)          if (sc->sc_dying)
                 return (EIO);                  return (EIO);
Line 684  ugen_do_write(struct ugen_softc *sc, int Line 766  ugen_do_write(struct ugen_softc *sc, int
         if (endpt == USB_CONTROL_ENDPOINT)          if (endpt == USB_CONTROL_ENDPOINT)
                 return (ENODEV);                  return (ENODEV);
   
#ifdef DIAGNOSTIC        if (sce == NULL)
                 return (EINVAL);
 
         if (sce->edesc == NULL) {          if (sce->edesc == NULL) {
                printf("ugen_do_write: no edesc\n");                printf("ugenwrite: no edesc\n");
                 return (EIO);                  return (EIO);
         }          }
         if (sce->pipeh == NULL) {          if (sce->pipeh == NULL) {
                printf("ugen_do_write: no pipe\n");                printf("ugenwrite: no pipe\n");
                 return (EIO);                  return (EIO);
         }          }
 #endif  
   
         switch (sce->edesc->bmAttributes & UE_XFERTYPE) {          switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
         case UE_BULK:          case UE_BULK:
Line 704  ugen_do_write(struct ugen_softc *sc, int Line 787  ugen_do_write(struct ugen_softc *sc, int
                         error = uiomove(buf, n, uio);                          error = uiomove(buf, n, uio);
                         if (error)                          if (error)
                                 break;                                  break;
                        DPRINTFN(1, ("ugen_do_write: transfer %d bytes\n", n));                        DPRINTFN(1, ("ugenwrite: transfer %d bytes\n", n));
                        err = usbd_bulk_transfer(xfer, sce->pipeh, 0,                         err = usbd_bulk_transfer(xfer, sce->pipeh, 0,
                                   sce->timeout, buf, &n,"ugenwb");                                    sce->timeout, buf, &n,"ugenwb");
                         if (err) {                          if (err) {
                                 if (err == USBD_INTERRUPTED)                                  if (err == USBD_INTERRUPTED)
                                         error = EINTR;                                          error = EINTR;
                                   else if (err == USBD_TIMEOUT)
                                           error = ETIMEDOUT;
                                   else
                                           error = EIO;
                                   break;
                           }
                   }
                   usbd_free_xfer(xfer);
                   break;
           case UE_INTERRUPT:
                   xfer = usbd_alloc_xfer(sc->sc_udev);
                   if (xfer == 0)
                           return (EIO);
                   while ((n = min(UGETW(sce->edesc->wMaxPacketSize),
                       uio->uio_resid)) != 0) {
                           error = uiomove(buf, n, uio);
                           if (error)
                                   break;
                           DPRINTFN(1, ("ugenwrite: transfer %d bytes\n", n));
                           err = usbd_intr_transfer(xfer, sce->pipeh, 0,
                                     sce->timeout, buf, &n,"ugenwi");
                           if (err) {
                                   if (err == USBD_INTERRUPTED)
                                           error = EINTR;
                                   else if (err == USBD_TIMEOUT)
                                           error = ETIMEDOUT;
                                 else                                  else
                                         error = EIO;                                          error = EIO;
                                 break;                                  break;
Line 748  ugen_activate(device_ptr_t self, enum de Line 857  ugen_activate(device_ptr_t self, enum de
         switch (act) {          switch (act) {
         case DVACT_ACTIVATE:          case DVACT_ACTIVATE:
                 return (EOPNOTSUPP);                  return (EOPNOTSUPP);
                 break;  
   
         case DVACT_DEACTIVATE:          case DVACT_DEACTIVATE:
                 sc->sc_dying = 1;                  sc->sc_dying = 1;
Line 766  USB_DETACH(ugen) Line 874  USB_DETACH(ugen)
         int s;          int s;
 #if defined(__NetBSD__) || defined(__OpenBSD__)  #if defined(__NetBSD__) || defined(__OpenBSD__)
         int maj, mn;          int maj, mn;
 #elif defined(__FreeBSD__)  
         int endptno;  
         dev_t dev;  
         struct vnode *vp;  
 #endif  #endif
   
 #if defined(__NetBSD__) || defined(__OpenBSD__)  #if defined(__NetBSD__) || defined(__OpenBSD__)
Line 809  USB_DETACH(ugen) Line 913  USB_DETACH(ugen)
         vdevgone(maj, mn, mn + USB_MAX_ENDPOINTS - 1, VCHR);          vdevgone(maj, mn, mn + USB_MAX_ENDPOINTS - 1, VCHR);
 #elif defined(__FreeBSD__)  #elif defined(__FreeBSD__)
         /* destroy the device for the control endpoint */          /* destroy the device for the control endpoint */
        dev = makedev(UGEN_CDEV_MAJOR, UGENMINOR(USBDEVUNIT(sc->sc_dev), 0));        destroy_dev(sc->dev);
        vp = SLIST_FIRST(&dev->si_hlist);        ugen_destroy_devnodes(sc);
        if (vp) 
                VOP_REVOKE(vp, REVOKEALL); 
        destroy_dev(dev); 
 
        /* destroy all devices for the other (existing) endpoints as well */ 
        for (endptno = 1; endptno < USB_MAX_ENDPOINTS; endptno++) { 
                if (sc->sc_endpoints[endptno][IN].sc != NULL || 
                    sc->sc_endpoints[endptno][OUT].sc != NULL ) { 
                        /* endpt can be 0x81 and 0x01, representing 
                         * endpoint address 0x01 and IN/OUT directions. 
                         * We map both endpoint addresses to the same device, 
                         * IN is reading from it, OUT is writing to it. 
                         * 
                         * In the if clause above we check whether one 
                         * of the structs is populated. 
                         */ 
                        dev = makedev(UGEN_CDEV_MAJOR, 
                                UGENMINOR(USBDEVUNIT(sc->sc_dev), endptno)); 
                        vp = SLIST_FIRST(&dev->si_hlist); 
                        if (vp) 
                                VOP_REVOKE(vp, REVOKEALL); 
 
                        destroy_dev(dev); 
                } 
        } 
 #endif  #endif
   
         return (0);          return (0);
Line 854  ugenintr(usbd_xfer_handle xfer, usbd_pri Line 933  ugenintr(usbd_xfer_handle xfer, usbd_pri
   
         if (status != USBD_NORMAL_COMPLETION) {          if (status != USBD_NORMAL_COMPLETION) {
                 DPRINTF(("ugenintr: status=%d\n", status));                  DPRINTF(("ugenintr: status=%d\n", status));
                usbd_clear_endpoint_stall_async(sce->pipeh);                if (status == USBD_STALLED)
                     usbd_clear_endpoint_stall_async(sce->pipeh);
                 return;                  return;
         }          }
   
         usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);          usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
         ibuf = sce->ibuf;          ibuf = sce->ibuf;
   
        DPRINTFN(5, ("ugenintr: xfer=%p status=%d count=%d\n",         DPRINTFN(5, ("ugenintr: xfer=%p status=%d count=%d\n",
                      xfer, status, count));                       xfer, status, count));
         DPRINTFN(5, ("          data = %02x %02x %02x\n",          DPRINTFN(5, ("          data = %02x %02x %02x\n",
                      ibuf[0], ibuf[1], ibuf[2]));                       ibuf[0], ibuf[1], ibuf[2]));
   
         (void)b_to_q(ibuf, count, &sce->q);          (void)b_to_q(ibuf, count, &sce->q);
                
         if (sce->state & UGEN_ASLP) {          if (sce->state & UGEN_ASLP) {
                 sce->state &= ~UGEN_ASLP;                  sce->state &= ~UGEN_ASLP;
                 DPRINTFN(5, ("ugen_intr: waking %p\n", sce));                  DPRINTFN(5, ("ugen_intr: waking %p\n", sce));
                 wakeup(sce);                  wakeup(sce);
         }          }
        selwakeup(&sce->rsel);        selwakeuppri(&sce->rsel, PZERO);
 }  }
   
 Static void  Static void
ugen_isoc_rintr(usbd_xfer_handle xfer, usbd_private_handle addr, ugen_isoc_rintr(usbd_xfer_handle xfer, usbd_private_handle addr,
                 usbd_status status)                  usbd_status status)
 {  {
         struct isoreq *req = addr;          struct isoreq *req = addr;
         struct ugen_endpoint *sce = req->sce;          struct ugen_endpoint *sce = req->sce;
         u_int32_t count, n;          u_int32_t count, n;
           int i, isize;
   
         /* Return if we are aborting. */          /* Return if we are aborting. */
         if (status == USBD_CANCELLED)          if (status == USBD_CANCELLED)
                 return;                  return;
   
         usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);          usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
        DPRINTFN(5,("ugen_isoc_rintr: xfer %d, count=%d\n", req - sce->isoreqs,        DPRINTFN(5,("ugen_isoc_rintr: xfer %d, count=%d\n",
                     (int)(req - sce->isoreqs),
                     count));                      count));
   
         /* throw away oldest input if the buffer is full */          /* throw away oldest input if the buffer is full */
Line 901  ugen_isoc_rintr(usbd_xfer_handle xfer, u Line 983  ugen_isoc_rintr(usbd_xfer_handle xfer, u
                              count));                               count));
         }          }
   
        /* copy data to buffer */        isize = UGETW(sce->edesc->wMaxPacketSize);
        while (count > 0) {        for (i = 0; i < UGEN_NISORFRMS; i++) {
                n = min(count, sce->limit - sce->fill);                u_int32_t actlen = req->sizes[i];
                memcpy(sce->fill, req->dmabuf, n);                char const *buf = (char const *)req->dmabuf + isize * i;
                count -= n;                /* copy data to buffer */
                sce->fill += n;                while (actlen > 0) {
                if(sce->fill == sce->limit)                        n = min(actlen, sce->limit - sce->fill);
                        sce->fill = sce->ibuf;                        memcpy(sce->fill, buf, n);
 
                         buf += n;
                         actlen -= n;
                         sce->fill += n;
                         if(sce->fill == sce->limit)
                                 sce->fill = sce->ibuf;
                 }
 
                 /* setup size for next transfer */
                 req->sizes[i] = isize;
         }          }
   
         usbd_setup_isoc_xfer(xfer, sce->pipeh, req, req->sizes, UGEN_NISORFRMS,          usbd_setup_isoc_xfer(xfer, sce->pipeh, req, req->sizes, UGEN_NISORFRMS,
Line 921  ugen_isoc_rintr(usbd_xfer_handle xfer, u Line 1013  ugen_isoc_rintr(usbd_xfer_handle xfer, u
                 DPRINTFN(5, ("ugen_isoc_rintr: waking %p\n", sce));                  DPRINTFN(5, ("ugen_isoc_rintr: waking %p\n", sce));
                 wakeup(sce);                  wakeup(sce);
         }          }
        selwakeup(&sce->rsel);        selwakeuppri(&sce->rsel, PZERO);
 }  }
   
 Static usbd_status  Static usbd_status
Line 941  ugen_set_interface(struct ugen_softc *sc Line 1033  ugen_set_interface(struct ugen_softc *sc
                 return (err);                  return (err);
         if (ifaceidx < 0 || ifaceidx >= niface)          if (ifaceidx < 0 || ifaceidx >= niface)
                 return (USBD_INVAL);                  return (USBD_INVAL);
        
         err = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);          err = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
         if (err)          if (err)
                 return (err);                  return (err);
         err = usbd_endpoint_count(iface, &nendpt);          err = usbd_endpoint_count(iface, &nendpt);
         if (err)          if (err)
                 return (err);                  return (err);
   
   #if defined(__FreeBSD__)
           /* destroy the existing devices, we remake the new ones in a moment */
           ugen_destroy_devnodes(sc);
   #endif
   
           /* XXX should only do this after setting new altno has succeeded */
         for (endptno = 0; endptno < nendpt; endptno++) {          for (endptno = 0; endptno < nendpt; endptno++) {
                 ed = usbd_interface2endpoint_descriptor(iface,endptno);                  ed = usbd_interface2endpoint_descriptor(iface,endptno);
                 endpt = ed->bEndpointAddress;                  endpt = ed->bEndpointAddress;
Line 975  ugen_set_interface(struct ugen_softc *sc Line 1074  ugen_set_interface(struct ugen_softc *sc
                 sce->edesc = ed;                  sce->edesc = ed;
                 sce->iface = iface;                  sce->iface = iface;
         }          }
   
   #if defined(__FreeBSD__)
           /* make the new devices */
           ugen_make_devnodes(sc);
   #endif
   
         return (0);          return (0);
 }  }
   
Line 1020  ugen_get_alt_index(struct ugen_softc *sc Line 1125  ugen_get_alt_index(struct ugen_softc *sc
   
         err = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);          err = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
         if (err)          if (err)
                        return (-1);                return (-1);
         return (usbd_get_interface_altindex(iface));          return (usbd_get_interface_altindex(iface));
 }  }
   
Line 1056  ugen_do_ioctl(struct ugen_softc *sc, int Line 1161  ugen_do_ioctl(struct ugen_softc *sc, int
                 sce = &sc->sc_endpoints[endpt][IN];                  sce = &sc->sc_endpoints[endpt][IN];
                 if (sce == NULL)                  if (sce == NULL)
                         return (EINVAL);                          return (EINVAL);
#ifdef DIAGNOSTIC
                 if (sce->pipeh == NULL) {                  if (sce->pipeh == NULL) {
                         printf("ugenioctl: USB_SET_SHORT_XFER, no pipe\n");                          printf("ugenioctl: USB_SET_SHORT_XFER, no pipe\n");
                         return (EIO);                          return (EIO);
                 }                  }
#endif
                 if (*(int *)addr)                  if (*(int *)addr)
                         sce->state |= UGEN_SHORT_OK;                          sce->state |= UGEN_SHORT_OK;
                 else                  else
Line 1071  ugen_do_ioctl(struct ugen_softc *sc, int Line 1176  ugen_do_ioctl(struct ugen_softc *sc, int
                 sce = &sc->sc_endpoints[endpt][IN];                  sce = &sc->sc_endpoints[endpt][IN];
                 if (sce == NULL)                  if (sce == NULL)
                         return (EINVAL);                          return (EINVAL);
 #ifdef DIAGNOSTIC  
                 if (sce->pipeh == NULL) {  
                         printf("ugenioctl: USB_SET_TIMEOUT, no pipe\n");  
                         return (EIO);  
                 }  
 #endif  
                 sce->timeout = *(int *)addr;                  sce->timeout = *(int *)addr;
                 return (0);                  return (0);
         default:          default:
Line 1113  ugen_do_ioctl(struct ugen_softc *sc, int Line 1212  ugen_do_ioctl(struct ugen_softc *sc, int
                 break;                  break;
         case USB_GET_ALTINTERFACE:          case USB_GET_ALTINTERFACE:
                 ai = (struct usb_alt_interface *)addr;                  ai = (struct usb_alt_interface *)addr;
                err = usbd_device2interface_handle(sc->sc_udev,                 err = usbd_device2interface_handle(sc->sc_udev,
                           ai->uai_interface_index, &iface);                            ai->uai_interface_index, &iface);
                 if (err)                  if (err)
                         return (EINVAL);                          return (EINVAL);
Line 1126  ugen_do_ioctl(struct ugen_softc *sc, int Line 1225  ugen_do_ioctl(struct ugen_softc *sc, int
                 if (!(flag & FWRITE))                  if (!(flag & FWRITE))
                         return (EPERM);                          return (EPERM);
                 ai = (struct usb_alt_interface *)addr;                  ai = (struct usb_alt_interface *)addr;
                err = usbd_device2interface_handle(sc->sc_udev,                 err = usbd_device2interface_handle(sc->sc_udev,
                           ai->uai_interface_index, &iface);                            ai->uai_interface_index, &iface);
                 if (err)                  if (err)
                         return (EINVAL);                          return (EINVAL);
Line 1187  ugen_do_ioctl(struct ugen_softc *sc, int Line 1286  ugen_do_ioctl(struct ugen_softc *sc, int
                         alt = ugen_get_alt_index(sc, ed->ued_interface_index);                          alt = ugen_get_alt_index(sc, ed->ued_interface_index);
                 else                  else
                         alt = ed->ued_alt_index;                          alt = ed->ued_alt_index;
                edesc = usbd_find_edesc(cdesc, ed->ued_interface_index,                 edesc = usbd_find_edesc(cdesc, ed->ued_interface_index,
                                         alt, ed->ued_endpoint_index);                                          alt, ed->ued_endpoint_index);
                 if (edesc == NULL) {                  if (edesc == NULL) {
                         free(cdesc, M_TEMP);                          free(cdesc, M_TEMP);
Line 1215  ugen_do_ioctl(struct ugen_softc *sc, int Line 1314  ugen_do_ioctl(struct ugen_softc *sc, int
                 uio.uio_offset = 0;                  uio.uio_offset = 0;
                 uio.uio_segflg = UIO_USERSPACE;                  uio.uio_segflg = UIO_USERSPACE;
                 uio.uio_rw = UIO_READ;                  uio.uio_rw = UIO_READ;
                uio.uio_td = p;                uio.uio_procp = p;
#if defined(__NetBSD__) || defined(__OpenBSD__) 
                error = uiomove((caddr_t)cdesc, len, &uio); 
#elif defined(__FreeBSD__) 
                 error = uiomove((void *)cdesc, len, &uio);                  error = uiomove((void *)cdesc, len, &uio);
 #endif  
                 free(cdesc, M_TEMP);                  free(cdesc, M_TEMP);
                 return (error);                  return (error);
         }          }
         case USB_GET_STRING_DESC:          case USB_GET_STRING_DESC:
                 si = (struct usb_string_desc *)addr;                  si = (struct usb_string_desc *)addr;
                err = usbd_get_string_desc(sc->sc_udev, si->usd_string_index,                 err = usbd_get_string_desc(sc->sc_udev, si->usd_string_index,
                           si->usd_language_id, &si->usd_desc);                            si->usd_language_id, &si->usd_desc);
                 if (err)                  if (err)
                         return (EINVAL);                          return (EINVAL);
Line 1263  ugen_do_ioctl(struct ugen_softc *sc, int Line 1358  ugen_do_ioctl(struct ugen_softc *sc, int
                         uio.uio_offset = 0;                          uio.uio_offset = 0;
                         uio.uio_segflg = UIO_USERSPACE;                          uio.uio_segflg = UIO_USERSPACE;
                         uio.uio_rw =                          uio.uio_rw =
                                ur->ucr_request.bmRequestType & UT_READ ?                                 ur->ucr_request.bmRequestType & UT_READ ?
                                 UIO_READ : UIO_WRITE;                                  UIO_READ : UIO_WRITE;
                         uio.uio_td = p;                          uio.uio_td = p;
                         ptr = malloc(len, M_TEMP, M_WAITOK);                          ptr = malloc(len, M_TEMP, M_WAITOK);
Line 1273  ugen_do_ioctl(struct ugen_softc *sc, int Line 1368  ugen_do_ioctl(struct ugen_softc *sc, int
                                         goto ret;                                          goto ret;
                         }                          }
                 }                  }
                err = usbd_do_request_flags(sc->sc_udev, &ur->ucr_request,                 sce = &sc->sc_endpoints[endpt][IN];
                          ptr, ur->ucr_flags, &ur->ucr_actlen);                err = usbd_do_request_flags(sc->sc_udev, &ur->ucr_request,
                           ptr, ur->ucr_flags, &ur->ucr_actlen, sce->timeout);
                 if (err) {                  if (err) {
                         error = EIO;                          error = EIO;
                         goto ret;                          goto ret;
Line 1293  ugen_do_ioctl(struct ugen_softc *sc, int Line 1389  ugen_do_ioctl(struct ugen_softc *sc, int
         }          }
         case USB_GET_DEVICEINFO:          case USB_GET_DEVICEINFO:
                 usbd_fill_deviceinfo(sc->sc_udev,                  usbd_fill_deviceinfo(sc->sc_udev,
                    (struct usb_device_info *)addr);                    (struct usb_device_info *)addr, 1);
                 break;                  break;
         default:          default:
                 return (EINVAL);                  return (EINVAL);
Line 1334  ugenpoll(dev_t dev, int events, usb_proc Line 1430  ugenpoll(dev_t dev, int events, usb_proc
         sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];          sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
         if (sce == NULL)          if (sce == NULL)
                 return (EINVAL);                  return (EINVAL);
#ifdef DIAGNOSTIC
         if (!sce->edesc) {          if (!sce->edesc) {
                 printf("ugenpoll: no edesc\n");                  printf("ugenpoll: no edesc\n");
                 return (EIO);                  return (EIO);
Line 1343  ugenpoll(dev_t dev, int events, usb_proc Line 1439  ugenpoll(dev_t dev, int events, usb_proc
                 printf("ugenpoll: no pipe\n");                  printf("ugenpoll: no pipe\n");
                 return (EIO);                  return (EIO);
         }          }
#endif
         s = splusb();          s = splusb();
         switch (sce->edesc->bmAttributes & UE_XFERTYPE) {          switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
         case UE_INTERRUPT:          case UE_INTERRUPT:
Line 1363  ugenpoll(dev_t dev, int events, usb_proc Line 1459  ugenpoll(dev_t dev, int events, usb_proc
                 }                  }
                 break;                  break;
         case UE_BULK:          case UE_BULK:
                /*                 /*
                  * We have no easy way of determining if a read will                   * We have no easy way of determining if a read will
                  * yield any data or a write will happen.                   * yield any data or a write will happen.
                  * Pretend they will.                   * Pretend they will.
                  */                   */
                revents |= events &                 revents |= events &
                            (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM);                             (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM);
                 break;                  break;
         default:          default:

Removed from v.1.7  
changed lines
  Added in v.1.8