Diff for /src/sys/bus/usb/usb_subr.c between versions 1.5 and 1.6

version 1.5, 2003/08/07 21:16:47 version 1.6, 2003/12/30 01:01:44
Line 1 Line 1
/*        $NetBSD: usb_subr.c,v 1.76 2000/04/27 15:26:50 augustss Exp $ *//*
/*        $FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.23.2.8 2003/01/17 17:46:24 joe Exp $  */ * $NetBSD: usb_subr.c,v 1.99 2002/07/11 21:14:34 augustss Exp $
/*        $DragonFly$     */ * $FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.58 2003/09/01 07:47:42 ticso Exp $
  * $DragonFly$
  */
 
 /* Also already have from NetBSD:
  *      $NetBSD: usb_subr.c,v 1.102 2003/01/01 16:21:50 augustss Exp $
  *      $NetBSD: usb_subr.c,v 1.103 2003/01/10 11:19:13 augustss Exp $
  */
   
 /*  /*
  * Copyright (c) 1998 The NetBSD Foundation, Inc.   * Copyright (c) 1998 The NetBSD Foundation, Inc.
Line 76  extern int usbdebug; Line 83  extern int usbdebug;
 #define DPRINTFN(n,x)  #define DPRINTFN(n,x)
 #endif  #endif
   
Static usbd_status      usbd_set_config(usbd_device_handle, int);Static usbd_status usbd_set_config(usbd_device_handle, int);
 Static void usbd_devinfo_vp(usbd_device_handle, char *, char *, int);
 Static char *usbd_get_string(usbd_device_handle, int, char *);  Static char *usbd_get_string(usbd_device_handle, int, char *);
 Static int usbd_getnewaddr(usbd_bus_handle bus);  Static int usbd_getnewaddr(usbd_bus_handle bus);
 #if defined(__NetBSD__)  #if defined(__NetBSD__)
 Static int usbd_print(void *aux, const char *pnp);  Static int usbd_print(void *aux, const char *pnp);
 Static int usbd_submatch(device_ptr_t, struct cfdata *cf, void *);  Static int usbd_submatch(device_ptr_t, struct cfdata *cf, void *);
 #elif defined(__OpenBSD__)  #elif defined(__OpenBSD__)
   Static int usbd_print(void *aux, const char *pnp);
 Static int usbd_submatch(device_ptr_t, void *, void *);  Static int usbd_submatch(device_ptr_t, void *, void *);
 #endif  #endif
 Static void usbd_free_iface_data(usbd_device_handle dev, int ifcno);  Static void usbd_free_iface_data(usbd_device_handle dev, int ifcno);
 Static void usbd_kill_pipe(usbd_pipe_handle);  Static void usbd_kill_pipe(usbd_pipe_handle);
Static usbd_status usbd_probe_and_attach Static usbd_status usbd_probe_and_attach(device_ptr_t parent,
        (device_ptr_t parent, usbd_device_handle dev, int port, int addr);                                 usbd_device_handle dev, int port, int addr);
   
 Static u_int32_t usb_cookie_no = 0;  Static u_int32_t usb_cookie_no = 0;
   
Line 110  struct usb_knowndev { Line 119  struct usb_knowndev {
 #include "usbdevs_data.h"  #include "usbdevs_data.h"
 #endif /* USBVERBOSE */  #endif /* USBVERBOSE */
   
Static const char *usbd_error_strs[] = {Static const char * const usbd_error_strs[] = {
         "NORMAL_COMPLETION",          "NORMAL_COMPLETION",
         "IN_PROGRESS",          "IN_PROGRESS",
         "PENDING_REQUESTS",          "PENDING_REQUESTS",
Line 160  usbd_get_string_desc(usbd_device_handle Line 169  usbd_get_string_desc(usbd_device_handle
         USETW(req.wIndex, langid);          USETW(req.wIndex, langid);
         USETW(req.wLength, 2);  /* only size byte first */          USETW(req.wLength, 2);  /* only size byte first */
         err = usbd_do_request_flags(dev, &req, sdesc, USBD_SHORT_XFER_OK,          err = usbd_do_request_flags(dev, &req, sdesc, USBD_SHORT_XFER_OK,
                &actlen);                &actlen, USBD_DEFAULT_TIMEOUT);
         if (err)          if (err)
                 return (err);                  return (err);
   
Line 189  usbd_get_string(usbd_device_handle dev, Line 198  usbd_get_string(usbd_device_handle dev,
                 /* Set up default language */                  /* Set up default language */
                 err = usbd_get_string_desc(dev, USB_LANGUAGE_TABLE, 0, &us);                  err = usbd_get_string_desc(dev, USB_LANGUAGE_TABLE, 0, &us);
                 if (err || us.bLength < 4) {                  if (err || us.bLength < 4) {
                        dev->langid = 0; /* Well, just pick English then */                        dev->langid = 0; /* Well, just pick something then */
                 } else {                  } else {
                         /* Pick the first language as the default. */                          /* Pick the first language as the default. */
                         dev->langid = UGETW(us.bString[0]);                          dev->langid = UGETW(us.bString[0]);
Line 207  usbd_get_string(usbd_device_handle dev, Line 216  usbd_get_string(usbd_device_handle dev,
                         *s++ = c;                          *s++ = c;
                 else if ((c & 0x00ff) == 0 && swap)                  else if ((c & 0x00ff) == 0 && swap)
                         *s++ = c >> 8;                          *s++ = c >> 8;
                else                 else
                         *s++ = '?';                          *s++ = '?';
         }          }
         *s++ = 0;          *s++ = 0;
         return (buf);          return (buf);
 }  }
   
voidStatic void
usbd_devinfo_vp(usbd_device_handle dev, char *v, char *p)usbd_trim_spaces(char *p)
 {
         char *q, *e;
 
         if (p == NULL)
                 return;
         q = e = p;
         while (*q == ' ')       /* skip leading spaces */
                 q++;
         while ((*p = *q++))     /* copy string */
                 if (*p++ != ' ') /* remember last non-space */
                         e = p;
         *e = 0;                 /* kill trailing spaces */
 }
 
 Static void
 usbd_devinfo_vp(usbd_device_handle dev, char *v, char *p, int usedev)
 {  {
         usb_device_descriptor_t *udd = &dev->ddesc;          usb_device_descriptor_t *udd = &dev->ddesc;
         char *vendor = 0, *product = 0;          char *vendor = 0, *product = 0;
 #ifdef USBVERBOSE  #ifdef USBVERBOSE
        struct usb_knowndev *kdp;        const struct usb_knowndev *kdp;
 #endif  #endif
   
         if (dev == NULL) {          if (dev == NULL) {
Line 228  usbd_devinfo_vp(usbd_device_handle dev, Line 253  usbd_devinfo_vp(usbd_device_handle dev,
                 return;                  return;
         }          }
   
        vendor = usbd_get_string(dev, udd->iManufacturer, v);        if (usedev) {
        product = usbd_get_string(dev, udd->iProduct, p);                vendor = usbd_get_string(dev, udd->iManufacturer, v);
                 usbd_trim_spaces(vendor);
                 product = usbd_get_string(dev, udd->iProduct, p);
                 usbd_trim_spaces(product);
         } else {
                 vendor = NULL;
                 product = NULL;
         }
 #ifdef USBVERBOSE  #ifdef USBVERBOSE
         if (vendor == NULL || product == NULL) {          if (vendor == NULL || product == NULL) {
                 for(kdp = usb_knowndevs;                  for(kdp = usb_knowndevs;
                     kdp->vendorname != NULL;                      kdp->vendorname != NULL;
                     kdp++) {                      kdp++) {
                        if (kdp->vendor == UGETW(udd->idVendor) &&                         if (kdp->vendor == UGETW(udd->idVendor) &&
                             (kdp->product == UGETW(udd->idProduct) ||                              (kdp->product == UGETW(udd->idProduct) ||
                              (kdp->flags & USB_KNOWNDEV_NOPROD) != 0))                               (kdp->flags & USB_KNOWNDEV_NOPROD) != 0))
                                 break;                                  break;
                 }                  }
                 if (kdp->vendorname != NULL) {                  if (kdp->vendorname != NULL) {
                        if (!vendor)                        if (vendor == NULL)
                        vendor = kdp->vendorname;                            vendor = kdp->vendorname;
                        if (!product)                        if (product == NULL)
                        product = (kdp->flags & USB_KNOWNDEV_NOPROD) == 0 ?                            product = (kdp->flags & USB_KNOWNDEV_NOPROD) == 0 ?
                                 kdp->productname : NULL;                                  kdp->productname : NULL;
                 }                  }
         }          }
 #endif  #endif
        if (vendor != NULL)        if (vendor != NULL && *vendor)
                 strcpy(v, vendor);                  strcpy(v, vendor);
         else          else
                 sprintf(v, "vendor 0x%04x", UGETW(udd->idVendor));                  sprintf(v, "vendor 0x%04x", UGETW(udd->idVendor));
        if (product != NULL)        if (product != NULL && *product)
                 strcpy(p, product);                  strcpy(p, product);
         else          else
                 sprintf(p, "product 0x%04x", UGETW(udd->idProduct));                  sprintf(p, "product 0x%04x", UGETW(udd->idProduct));
Line 273  usbd_devinfo(usbd_device_handle dev, int Line 305  usbd_devinfo(usbd_device_handle dev, int
         char product[USB_MAX_STRING_LEN];          char product[USB_MAX_STRING_LEN];
         int bcdDevice, bcdUSB;          int bcdDevice, bcdUSB;
   
        usbd_devinfo_vp(dev, vendor, product);        usbd_devinfo_vp(dev, vendor, product, 1);
         cp += sprintf(cp, "%s %s", vendor, product);          cp += sprintf(cp, "%s %s", vendor, product);
         if (showclass)          if (showclass)
                 cp += sprintf(cp, ", class %d/%d",                  cp += sprintf(cp, ", class %d/%d",
Line 312  usbd_reset_port(usbd_device_handle dev, Line 344  usbd_reset_port(usbd_device_handle dev,
         usb_device_request_t req;          usb_device_request_t req;
         usbd_status err;          usbd_status err;
         int n;          int n;
        
         req.bmRequestType = UT_WRITE_CLASS_OTHER;          req.bmRequestType = UT_WRITE_CLASS_OTHER;
         req.bRequest = UR_SET_FEATURE;          req.bRequest = UR_SET_FEATURE;
         USETW(req.wValue, UHF_PORT_RESET);          USETW(req.wValue, UHF_PORT_RESET);
Line 333  usbd_reset_port(usbd_device_handle dev, Line 365  usbd_reset_port(usbd_device_handle dev,
                                  err));                                   err));
                         return (err);                          return (err);
                 }                  }
                   /* If the device disappeared, just give up. */
                   if (!(UGETW(ps->wPortStatus) & UPS_CURRENT_CONNECT_STATUS))
                           return (USBD_NORMAL_COMPLETION);
         } while ((UGETW(ps->wPortChange) & UPS_C_PORT_RESET) == 0 && --n > 0);          } while ((UGETW(ps->wPortChange) & UPS_C_PORT_RESET) == 0 && --n > 0);
         if (n == 0)          if (n == 0)
                 return (USBD_TIMEOUT);                  return (USBD_TIMEOUT);
Line 359  usbd_find_idesc(usb_config_descriptor_t Line 394  usbd_find_idesc(usb_config_descriptor_t
         for (curidx = lastidx = -1; p < end; ) {          for (curidx = lastidx = -1; p < end; ) {
                 d = (usb_interface_descriptor_t *)p;                  d = (usb_interface_descriptor_t *)p;
                 DPRINTFN(4,("usbd_find_idesc: idx=%d(%d) altidx=%d(%d) len=%d "                  DPRINTFN(4,("usbd_find_idesc: idx=%d(%d) altidx=%d(%d) len=%d "
                            "type=%d\n",                             "type=%d\n",
                             ifaceidx, curidx, altidx, curaidx,                              ifaceidx, curidx, altidx, curaidx,
                             d->bLength, d->bDescriptorType));                              d->bLength, d->bDescriptorType));
                 if (d->bLength == 0) /* bad descriptor */                  if (d->bLength == 0) /* bad descriptor */
Line 380  usbd_find_idesc(usb_config_descriptor_t Line 415  usbd_find_idesc(usb_config_descriptor_t
 }  }
   
 usb_endpoint_descriptor_t *  usb_endpoint_descriptor_t *
usbd_find_edesc(usb_config_descriptor_t *cd, int ifaceidx, int altidx, usbd_find_edesc(usb_config_descriptor_t *cd, int ifaceidx, int altidx,
                 int endptidx)                  int endptidx)
 {  {
         char *p = (char *)cd;          char *p = (char *)cd;
Line 416  usbd_status Line 451  usbd_status
 usbd_fill_iface_data(usbd_device_handle dev, int ifaceidx, int altidx)  usbd_fill_iface_data(usbd_device_handle dev, int ifaceidx, int altidx)
 {  {
         usbd_interface_handle ifc = &dev->ifaces[ifaceidx];          usbd_interface_handle ifc = &dev->ifaces[ifaceidx];
           usb_interface_descriptor_t *idesc;
         char *p, *end;          char *p, *end;
         int endpt, nendpt;          int endpt, nendpt;
   
         DPRINTFN(4,("usbd_fill_iface_data: ifaceidx=%d altidx=%d\n",          DPRINTFN(4,("usbd_fill_iface_data: ifaceidx=%d altidx=%d\n",
                     ifaceidx, altidx));                      ifaceidx, altidx));
        ifc->device = dev;        idesc = usbd_find_idesc(dev->cdesc, ifaceidx, altidx);
        ifc->idesc = usbd_find_idesc(dev->cdesc, ifaceidx, altidx);        if (idesc == NULL)
        if (ifc->idesc == 0) 
                 return (USBD_INVAL);                  return (USBD_INVAL);
           ifc->device = dev;
           ifc->idesc = idesc;
         ifc->index = ifaceidx;          ifc->index = ifaceidx;
         ifc->altindex = altidx;          ifc->altindex = altidx;
         nendpt = ifc->idesc->bNumEndpoints;          nendpt = ifc->idesc->bNumEndpoints;
Line 443  usbd_fill_iface_data(usbd_device_handle Line 480  usbd_fill_iface_data(usbd_device_handle
         for (endpt = 0; endpt < nendpt; endpt++) {          for (endpt = 0; endpt < nendpt; endpt++) {
                 DPRINTFN(10,("usbd_fill_iface_data: endpt=%d\n", endpt));                  DPRINTFN(10,("usbd_fill_iface_data: endpt=%d\n", endpt));
                 for (; p < end; p += ed->bLength) {                  for (; p < end; p += ed->bLength) {
                         ed = (usb_endpoint_descriptor_t *)p;  
                         DPRINTFN(10,("usbd_fill_iface_data: p=%p end=%p "                          DPRINTFN(10,("usbd_fill_iface_data: p=%p end=%p "
                                      "len=%d type=%d\n",                                       "len=%d type=%d\n",
                                  p, end, ed->bLength, ed->bDescriptorType));                                   p, end, ed->bLength, ed->bDescriptorType));
Line 455  usbd_fill_iface_data(usbd_device_handle Line 491  usbd_fill_iface_data(usbd_device_handle
                                 break;                                  break;
                 }                  }
                 /* passed end, or bad desc */                  /* passed end, or bad desc */
                DPRINTF(("usbd_fill_iface_data: bad descriptor(s): %s\n",                printf("usbd_fill_iface_data: bad descriptor(s): %s\n",
                         ed->bLength == 0 ? "0 length" :                       ed->bLength == 0 ? "0 length" :
                         ed->bDescriptorType == UDESC_INTERFACE ? "iface desc":                       ed->bDescriptorType == UDESC_INTERFACE ? "iface desc":
                         "out of data"));                       "out of data");
                 goto bad;                  goto bad;
         found:          found:
                 ifc->endpoints[endpt].edesc = ed;                  ifc->endpoints[endpt].edesc = ed;
                   if (dev->speed == USB_SPEED_HIGH) {
                           u_int mps;
                           /* Control and bulk endpoints have max packet limits. */
                           switch (UE_GET_XFERTYPE(ed->bmAttributes)) {
                           case UE_CONTROL:
                                   mps = USB_2_MAX_CTRL_PACKET;
                                   goto check;
                           case UE_BULK:
                                   mps = USB_2_MAX_BULK_PACKET;
                           check:
                                   if (UGETW(ed->wMaxPacketSize) != mps) {
                                           USETW(ed->wMaxPacketSize, mps);
   #ifdef DIAGNOSTIC
                                           printf("usbd_fill_iface_data: bad max "
                                                  "packet size\n");
   #endif
                                   }
                                   break;
                           default:
                                   break;
                           }
                   }
                 ifc->endpoints[endpt].refcnt = 0;                  ifc->endpoints[endpt].refcnt = 0;
                 p += ed->bLength;                  p += ed->bLength;
         }          }
Line 470  usbd_fill_iface_data(usbd_device_handle Line 528  usbd_fill_iface_data(usbd_device_handle
         return (USBD_NORMAL_COMPLETION);          return (USBD_NORMAL_COMPLETION);
   
  bad:   bad:
        if (ifc->endpoints != NULL)        if (ifc->endpoints != NULL) {
                 free(ifc->endpoints, M_USB);                  free(ifc->endpoints, M_USB);
                   ifc->endpoints = NULL;
           }
         return (USBD_INVAL);          return (USBD_INVAL);
 }  }
   
Line 578  usbd_set_config_index(usbd_device_handle Line 638  usbd_set_config_index(usbd_device_handle
                 /* May be self powered. */                  /* May be self powered. */
                 if (cdp->bmAttributes & UC_BUS_POWERED) {                  if (cdp->bmAttributes & UC_BUS_POWERED) {
                         /* Must ask device. */                          /* Must ask device. */
                        err = usbd_get_device_status(dev, &ds);                        if (dev->quirks->uq_flags & UQ_POWER_CLAIM) {
                        if (!err && (UGETW(ds.wStatus) & UDS_SELF_POWERED))                                /*
                                selfpowered = 1;                                 * Hub claims to be self powered, but isn't.
                        DPRINTF(("usbd_set_config_index: status=0x%04x, "                                 * It seems that the power status can be
                                 "error=%s\n",                                 * determined by the hub characteristics.
                                 UGETW(ds.wStatus), usbd_errstr(err)));                                 */
                                 usb_hub_descriptor_t hd;
                                 usb_device_request_t req;
                                 req.bmRequestType = UT_READ_CLASS_DEVICE;
                                 req.bRequest = UR_GET_DESCRIPTOR;
                                 USETW(req.wValue, 0);
                                 USETW(req.wIndex, 0);
                                 USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE);
                                 err = usbd_do_request(dev, &req, &hd);
                                 if (!err &&
                                     (UGETW(hd.wHubCharacteristics) &
                                      UHD_PWR_INDIVIDUAL))
                                         selfpowered = 1;
                                 DPRINTF(("usbd_set_config_index: charac=0x%04x"
                                     ", error=%s\n",
                                     UGETW(hd.wHubCharacteristics),
                                     usbd_errstr(err)));
                         } else {
                                 err = usbd_get_device_status(dev, &ds);
                                 if (!err &&
                                     (UGETW(ds.wStatus) & UDS_SELF_POWERED))
                                         selfpowered = 1;
                                 DPRINTF(("usbd_set_config_index: status=0x%04x"
                                     ", error=%s\n",
                                     UGETW(ds.wStatus), usbd_errstr(err)));
                         }
                 } else                  } else
                         selfpowered = 1;                          selfpowered = 1;
         }          }
        DPRINTF(("usbd_set_config_index: (addr %d) attr=0x%02x, "        DPRINTF(("usbd_set_config_index: (addr %d) cno=%d attr=0x%02x, "
                 "selfpowered=%d, power=%d\n",                  "selfpowered=%d, power=%d\n",
                 dev->address, cdp->bmAttributes,                  cdp->bConfigurationValue, dev->address, cdp->bmAttributes,
                  selfpowered, cdp->bMaxPower * 2));                   selfpowered, cdp->bMaxPower * 2));
   
         /* Check if we have enough power. */          /* Check if we have enough power. */
Line 601  usbd_set_config_index(usbd_device_handle Line 686  usbd_set_config_index(usbd_device_handle
 #endif  #endif
         power = cdp->bMaxPower * 2;          power = cdp->bMaxPower * 2;
         if (power > dev->powersrc->power) {          if (power > dev->powersrc->power) {
                   DPRINTF(("power exceeded %d %d\n", power,dev->powersrc->power));
                 /* XXX print nicer message. */                  /* XXX print nicer message. */
                 if (msg)                  if (msg)
                         printf("%s: device addr %d (config %d) exceeds power "                          printf("%s: device addr %d (config %d) exceeds power "
                                  "budget, %d mA > %d mA\n",                                   "budget, %d mA > %d mA\n",
                               USBDEVNAME(dev->bus->bdev), dev->address,                                USBDEVNAME(dev->bus->bdev), dev->address,
                               cdp->bConfigurationValue,                                cdp->bConfigurationValue,
                                power, dev->powersrc->power);                                 power, dev->powersrc->power);
                 err = USBD_NO_POWER;                  err = USBD_NO_POWER;
                 goto bad;                  goto bad;
Line 627  usbd_set_config_index(usbd_device_handle Line 713  usbd_set_config_index(usbd_device_handle
   
         /* Allocate and fill interface data. */          /* Allocate and fill interface data. */
         nifc = cdp->bNumInterface;          nifc = cdp->bNumInterface;
        dev->ifaces = malloc(nifc * sizeof(struct usbd_interface),         dev->ifaces = malloc(nifc * sizeof(struct usbd_interface),
                              M_USB, M_NOWAIT);                               M_USB, M_NOWAIT);
         if (dev->ifaces == NULL) {          if (dev->ifaces == NULL) {
                 err = USBD_NOMEM;                  err = USBD_NOMEM;
Line 673  usbd_setup_pipe(usbd_device_handle dev, Line 759  usbd_setup_pipe(usbd_device_handle dev,
         p->refcnt = 1;          p->refcnt = 1;
         p->intrxfer = 0;          p->intrxfer = 0;
         p->running = 0;          p->running = 0;
           p->aborting = 0;
         p->repeat = 0;          p->repeat = 0;
         p->interval = ival;          p->interval = ival;
         SIMPLEQ_INIT(&p->queue);          SIMPLEQ_INIT(&p->queue);
Line 695  usbd_setup_pipe(usbd_device_handle dev, Line 782  usbd_setup_pipe(usbd_device_handle dev,
 void  void
 usbd_kill_pipe(usbd_pipe_handle pipe)  usbd_kill_pipe(usbd_pipe_handle pipe)
 {  {
           usbd_abort_pipe(pipe);
         pipe->methods->close(pipe);          pipe->methods->close(pipe);
         pipe->endpoint->refcnt--;          pipe->endpoint->refcnt--;
         free(pipe, M_USB);          free(pipe, M_USB);
Line 724  usbd_probe_and_attach(device_ptr_t paren Line 812  usbd_probe_and_attach(device_ptr_t paren
         usbd_interface_handle ifaces[256]; /* 256 is the absolute max */          usbd_interface_handle ifaces[256]; /* 256 is the absolute max */
   
 #if defined(__FreeBSD__)  #if defined(__FreeBSD__)
        /*         /*
          * XXX uaa is a static var. Not a problem as it _should_ be used only           * XXX uaa is a static var. Not a problem as it _should_ be used only
          * during probe and attach. Should be changed however.           * during probe and attach. Should be changed however.
          */           */
         device_t bdev;          device_t bdev;
         bdev = device_add_child(parent, NULL, -1);          bdev = device_add_child(parent, NULL, -1);
         device_set_ivars(bdev, &uaa);  
         if (!bdev) {          if (!bdev) {
             printf("%s: Device creation failed\n", USBDEVNAME(dev->bus->bdev));              printf("%s: Device creation failed\n", USBDEVNAME(dev->bus->bdev));
             return (USBD_INVAL);              return (USBD_INVAL);
         }          }
           device_set_ivars(bdev, &uaa);
         device_quiet(bdev);          device_quiet(bdev);
 #endif  #endif
   
Line 816  usbd_probe_and_attach(device_ptr_t paren Line 904  usbd_probe_and_attach(device_ptr_t paren
 #if defined(__FreeBSD__)  #if defined(__FreeBSD__)
                                 /* create another child for the next iface */                                  /* create another child for the next iface */
                                 bdev = device_add_child(parent, NULL, -1);                                  bdev = device_add_child(parent, NULL, -1);
                                 device_set_ivars(bdev, &uaa);  
                                 if (!bdev) {                                  if (!bdev) {
                                         printf("%s: Device creation failed\n",                                          printf("%s: Device creation failed\n",
                                         USBDEVNAME(dev->bus->bdev));                                          USBDEVNAME(dev->bus->bdev));
                                         return (USBD_NORMAL_COMPLETION);                                          return (USBD_NORMAL_COMPLETION);
                                 }                                  }
                                   device_set_ivars(bdev, &uaa);
                                 device_quiet(bdev);                                  device_quiet(bdev);
 #endif  #endif
                         }                          }
Line 848  usbd_probe_and_attach(device_ptr_t paren Line 936  usbd_probe_and_attach(device_ptr_t paren
         uaa.usegeneric = 1;          uaa.usegeneric = 1;
         uaa.configno = UHUB_UNK_CONFIGURATION;          uaa.configno = UHUB_UNK_CONFIGURATION;
         uaa.ifaceno = UHUB_UNK_INTERFACE;          uaa.ifaceno = UHUB_UNK_INTERFACE;
         uaa.vendor = UHUB_UNK_VENDOR;  
         uaa.product = UHUB_UNK_PRODUCT;  
         uaa.release = UHUB_UNK_RELEASE;  
         dv = USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print, usbd_submatch);          dv = USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print, usbd_submatch);
         if (dv != NULL) {          if (dv != NULL) {
                 dev->subdevs = malloc(2 * sizeof dv, M_USB, M_NOWAIT);                  dev->subdevs = malloc(2 * sizeof dv, M_USB, M_NOWAIT);
Line 861  usbd_probe_and_attach(device_ptr_t paren Line 946  usbd_probe_and_attach(device_ptr_t paren
                 return (USBD_NORMAL_COMPLETION);                  return (USBD_NORMAL_COMPLETION);
         }          }
   
        /*         /*
          * The generic attach failed, but leave the device as it is.           * The generic attach failed, but leave the device as it is.
          * We just did not find any drivers, that's all.  The device is           * We just did not find any drivers, that's all.  The device is
          * fully operational and not harming anyone.           * fully operational and not harming anyone.
Line 882  usbd_probe_and_attach(device_ptr_t paren Line 967  usbd_probe_and_attach(device_ptr_t paren
  */   */
 usbd_status  usbd_status
 usbd_new_device(device_ptr_t parent, usbd_bus_handle bus, int depth,  usbd_new_device(device_ptr_t parent, usbd_bus_handle bus, int depth,
                int lowspeed, int port, struct usbd_port *up)                int speed, int port, struct usbd_port *up)
 {  {
         usbd_device_handle dev;          usbd_device_handle dev;
           struct usbd_device *hub;
         usb_device_descriptor_t *dd;          usb_device_descriptor_t *dd;
           usb_port_status_t ps;
         usbd_status err;          usbd_status err;
         int addr;          int addr;
         int i;          int i;
   
        DPRINTF(("usbd_new_device bus=%p port=%d depth=%d lowspeed=%d\n",        DPRINTF(("usbd_new_device bus=%p port=%d depth=%d speed=%d\n",
                 bus, port, depth, lowspeed));                 bus, port, depth, speed));
         addr = usbd_getnewaddr(bus);          addr = usbd_getnewaddr(bus);
         if (addr < 0) {          if (addr < 0) {
                printf("%s: No free USB addresses, new device ignored.\n",                 printf("%s: No free USB addresses, new device ignored.\n",
                        USBDEVNAME(bus->bdev));                         USBDEVNAME(bus->bdev));
                 return (USBD_NO_ADDR);                  return (USBD_NO_ADDR);
         }          }
   
        dev = malloc(sizeof *dev, M_USB, M_NOWAIT);        dev = malloc(sizeof *dev, M_USB, M_NOWAIT|M_ZERO);
         if (dev == NULL)          if (dev == NULL)
                 return (USBD_NOMEM);                  return (USBD_NOMEM);
         memset(dev, 0, sizeof(*dev));  
   
         dev->bus = bus;          dev->bus = bus;
   
Line 920  usbd_new_device(device_ptr_t parent, usb Line 1006  usbd_new_device(device_ptr_t parent, usb
         dev->quirks = &usbd_no_quirk;          dev->quirks = &usbd_no_quirk;
         dev->address = USB_START_ADDR;          dev->address = USB_START_ADDR;
         dev->ddesc.bMaxPacketSize = 0;          dev->ddesc.bMaxPacketSize = 0;
         dev->lowspeed = lowspeed != 0;  
         dev->depth = depth;          dev->depth = depth;
         dev->powersrc = up;          dev->powersrc = up;
           dev->myhub = up->parent;
           for (hub = up->parent;
                hub != NULL && hub->speed != USB_SPEED_HIGH;
                hub = hub->myhub)
                   ;
           dev->myhighhub = hub;
           dev->speed = speed;
         dev->langid = USBD_NOLANG;          dev->langid = USBD_NOLANG;
         dev->cookie.cookie = ++usb_cookie_no;          dev->cookie.cookie = ++usb_cookie_no;
   
Line 937  usbd_new_device(device_ptr_t parent, usb Line 1029  usbd_new_device(device_ptr_t parent, usb
         up->device = dev;          up->device = dev;
         dd = &dev->ddesc;          dd = &dev->ddesc;
         /* Try a few times in case the device is slow (i.e. outside specs.) */          /* Try a few times in case the device is slow (i.e. outside specs.) */
        for (i = 0; i < 3; i++) {        for (i = 0; i < 15; i++) {
                 /* Get the first 8 bytes of the device descriptor. */                  /* Get the first 8 bytes of the device descriptor. */
                 err = usbd_get_desc(dev, UDESC_DEVICE, 0, USB_MAX_IPACKET, dd);                  err = usbd_get_desc(dev, UDESC_DEVICE, 0, USB_MAX_IPACKET, dd);
                 if (!err)                  if (!err)
                         break;                          break;
                 usbd_delay_ms(dev, 200);                  usbd_delay_ms(dev, 200);
                   if ((i & 3) == 3)
                           usbd_reset_port(up->parent, port, &ps);
         }          }
         if (err) {          if (err) {
                 DPRINTFN(-1, ("usbd_new_device: addr=%d, getting first desc "                  DPRINTFN(-1, ("usbd_new_device: addr=%d, getting first desc "
Line 951  usbd_new_device(device_ptr_t parent, usb Line 1045  usbd_new_device(device_ptr_t parent, usb
                 return (err);                  return (err);
         }          }
   
           if (speed == USB_SPEED_HIGH) {
                   /* Max packet size must be 64 (sec 5.5.3). */
                   if (dd->bMaxPacketSize != USB_2_MAX_CTRL_PACKET) {
   #ifdef DIAGNOSTIC
                           printf("usbd_new_device: addr=%d bad max packet size\n",
                                  addr);
   #endif
                           dd->bMaxPacketSize = USB_2_MAX_CTRL_PACKET;
                   }
           }
   
         DPRINTF(("usbd_new_device: adding unit addr=%d, rev=%02x, class=%d, "          DPRINTF(("usbd_new_device: adding unit addr=%d, rev=%02x, class=%d, "
                 "subclass=%d, protocol=%d, maxpacket=%d, len=%d, ls=%d\n",                  "subclass=%d, protocol=%d, maxpacket=%d, len=%d, speed=%d\n",
                  addr,UGETW(dd->bcdUSB), dd->bDeviceClass, dd->bDeviceSubClass,                   addr,UGETW(dd->bcdUSB), dd->bDeviceClass, dd->bDeviceSubClass,
                 dd->bDeviceProtocol, dd->bMaxPacketSize, dd->bLength,                  dd->bDeviceProtocol, dd->bMaxPacketSize, dd->bLength,
                 dev->lowspeed));                 dev->speed));
   
         if (dd->bDescriptorType != UDESC_DEVICE) {          if (dd->bDescriptorType != UDESC_DEVICE) {
                 /* Illegal device descriptor */                  /* Illegal device descriptor */
Line 1000  usbd_new_device(device_ptr_t parent, usb Line 1105  usbd_new_device(device_ptr_t parent, usb
         dev->power = USB_MIN_POWER;          dev->power = USB_MIN_POWER;
         dev->self_powered = 0;          dev->self_powered = 0;
   
        DPRINTF(("usbd_new_device: new dev (addr %d), dev=%p, parent=%p\n",         DPRINTF(("usbd_new_device: new dev (addr %d), dev=%p, parent=%p\n",
                  addr, dev, parent));                   addr, dev, parent));
   
         err = usbd_probe_and_attach(parent, dev, port, addr);          err = usbd_probe_and_attach(parent, dev, port, addr);
Line 1008  usbd_new_device(device_ptr_t parent, usb Line 1113  usbd_new_device(device_ptr_t parent, usb
                 usbd_remove_device(dev, up);                  usbd_remove_device(dev, up);
                 return (err);                  return (err);
         }          }
  
        usbd_add_event(USB_EVENT_DEVICE_ATTACH, dev);        usbd_add_dev_event(USB_EVENT_DEVICE_ATTACH, dev);
 
         return (USBD_NORMAL_COMPLETION);          return (USBD_NORMAL_COMPLETION);
 }  }
   
Line 1039  void Line 1145  void
 usbd_remove_device(usbd_device_handle dev, struct usbd_port *up)  usbd_remove_device(usbd_device_handle dev, struct usbd_port *up)
 {  {
         DPRINTF(("usbd_remove_device: %p\n", dev));          DPRINTF(("usbd_remove_device: %p\n", dev));
  
         if (dev->default_pipe != NULL)          if (dev->default_pipe != NULL)
                 usbd_kill_pipe(dev->default_pipe);                  usbd_kill_pipe(dev->default_pipe);
         up->device = 0;          up->device = 0;
Line 1069  usbd_print(void *aux, const char *pnp) Line 1175  usbd_print(void *aux, const char *pnp)
         if (uaa->ifaceno != UHUB_UNK_INTERFACE)          if (uaa->ifaceno != UHUB_UNK_INTERFACE)
                 printf(" interface %d", uaa->ifaceno);                  printf(" interface %d", uaa->ifaceno);
 #if 0  #if 0
        /*         /*
          * It gets very crowded with these locators on the attach line.           * It gets very crowded with these locators on the attach line.
          * They are not really needed since they are printed in the clear           * They are not really needed since they are printed in the clear
          * by each driver.           * by each driver.
Line 1106  usbd_submatch(struct device *parent, voi Line 1212  usbd_submatch(struct device *parent, voi
             uaa->release, cf->uhubcf_release));              uaa->release, cf->uhubcf_release));
         if (uaa->port != 0 &&   /* root hub has port 0, it should match */          if (uaa->port != 0 &&   /* root hub has port 0, it should match */
             ((uaa->port != 0 &&              ((uaa->port != 0 &&
             cf->uhubcf_port != UHUB_UNK_PORT &&              cf->uhubcf_port != UHUB_UNK_PORT &&
             cf->uhubcf_port != uaa->port) ||              cf->uhubcf_port != uaa->port) ||
            (uaa->configno != UHUB_UNK_CONFIGURATION &&             (uaa->configno != UHUB_UNK_CONFIGURATION &&
             cf->uhubcf_configuration != UHUB_UNK_CONFIGURATION &&              cf->uhubcf_configuration != UHUB_UNK_CONFIGURATION &&
             cf->uhubcf_configuration != uaa->configno) ||              cf->uhubcf_configuration != uaa->configno) ||
            (uaa->ifaceno != UHUB_UNK_INTERFACE &&             (uaa->ifaceno != UHUB_UNK_INTERFACE &&
             cf->uhubcf_interface != UHUB_UNK_INTERFACE &&              cf->uhubcf_interface != UHUB_UNK_INTERFACE &&
             cf->uhubcf_interface != uaa->ifaceno) ||              cf->uhubcf_interface != uaa->ifaceno) ||
            (uaa->vendor != UHUB_UNK_VENDOR &&             (uaa->vendor != UHUB_UNK_VENDOR &&
             cf->uhubcf_vendor != UHUB_UNK_VENDOR &&              cf->uhubcf_vendor != UHUB_UNK_VENDOR &&
             cf->uhubcf_vendor != uaa->vendor) ||              cf->uhubcf_vendor != uaa->vendor) ||
            (uaa->product != UHUB_UNK_PRODUCT &&             (uaa->product != UHUB_UNK_PRODUCT &&
             cf->uhubcf_product != UHUB_UNK_PRODUCT &&              cf->uhubcf_product != UHUB_UNK_PRODUCT &&
             cf->uhubcf_product != uaa->product) ||              cf->uhubcf_product != uaa->product) ||
            (uaa->release != UHUB_UNK_RELEASE &&             (uaa->release != UHUB_UNK_RELEASE &&
             cf->uhubcf_release != UHUB_UNK_RELEASE &&              cf->uhubcf_release != UHUB_UNK_RELEASE &&
             cf->uhubcf_release != uaa->release)              cf->uhubcf_release != uaa->release)
           )             )
            )             )
                 return 0;                  return 0;
           if (cf->uhubcf_vendor != UHUB_UNK_VENDOR &&
               cf->uhubcf_vendor == uaa->vendor &&
               cf->uhubcf_product != UHUB_UNK_PRODUCT &&
               cf->uhubcf_product == uaa->product) {
                   /* We have a vendor&product locator match */
                   if (cf->uhubcf_release != UHUB_UNK_RELEASE &&
                       cf->uhubcf_release == uaa->release)
                           uaa->matchlvl = UMATCH_VENDOR_PRODUCT_REV;
                   else
                           uaa->matchlvl = UMATCH_VENDOR_PRODUCT;
           } else
                   uaa->matchlvl = 0;
         return ((*cf->cf_attach->ca_match)(parent, cf, aux));          return ((*cf->cf_attach->ca_match)(parent, cf, aux));
 }  }
   
 #endif  #endif
   
 void  void
usbd_fill_deviceinfo(usbd_device_handle dev, struct usb_device_info *di)usbd_fill_deviceinfo(usbd_device_handle dev, struct usb_device_info *di,
                      int usedev)
 {  {
         struct usbd_port *p;          struct usbd_port *p;
         int i, err, s;          int i, err, s;
   
         di->udi_bus = USBDEVUNIT(dev->bus->bdev);          di->udi_bus = USBDEVUNIT(dev->bus->bdev);
         di->udi_addr = dev->address;          di->udi_addr = dev->address;
        di->udi_cookie = dev->cookie;
        if (dev->subdevs) {        usbd_devinfo_vp(dev, di->udi_vendor, di->udi_product, usedev);
                for (i = 0; dev->subdevs[i] && 
                            i < USB_MAX_DEVNAMES; i++) { 
                        strncpy(di->udi_devnames[i], USBDEVPTRNAME(dev->subdevs[i]), 
                                USB_MAX_DEVNAMELEN); 
                        di->udi_devnames[i][USB_MAX_DEVNAMELEN-1] = '\0'; /* terminate */ 
                } 
        } else { 
                i = 0; 
        } 
        for (/*i is set */; i < USB_MAX_DEVNAMES; i++) 
                di->udi_devnames[i][0] = 0;                     /* empty */ 
 
        usbd_devinfo_vp(dev, di->udi_vendor, di->udi_product); 
         usbd_printBCD(di->udi_release, UGETW(dev->ddesc.bcdDevice));          usbd_printBCD(di->udi_release, UGETW(dev->ddesc.bcdDevice));
         di->udi_vendorNo = UGETW(dev->ddesc.idVendor);          di->udi_vendorNo = UGETW(dev->ddesc.idVendor);
         di->udi_productNo = UGETW(dev->ddesc.idProduct);          di->udi_productNo = UGETW(dev->ddesc.idProduct);
Line 1163  usbd_fill_deviceinfo(usbd_device_handle Line 1269  usbd_fill_deviceinfo(usbd_device_handle
         di->udi_protocol = dev->ddesc.bDeviceProtocol;          di->udi_protocol = dev->ddesc.bDeviceProtocol;
         di->udi_config = dev->config;          di->udi_config = dev->config;
         di->udi_power = dev->self_powered ? 0 : dev->power;          di->udi_power = dev->self_powered ? 0 : dev->power;
        di->udi_lowspeed = dev->lowspeed;        di->udi_speed = dev->speed;
 
         if (dev->subdevs != NULL) {
                 for (i = 0; dev->subdevs[i] &&
                              i < USB_MAX_DEVNAMES; i++) {
                         strncpy(di->udi_devnames[i], USBDEVPTRNAME(dev->subdevs[i]),
                                 USB_MAX_DEVNAMELEN);
                         di->udi_devnames[i][USB_MAX_DEVNAMELEN-1] = '\0';
                 }
         } else {
                 i = 0;
         }
         for (/*i is set */; i < USB_MAX_DEVNAMES; i++)
                 di->udi_devnames[i][0] = 0;                 /* empty */
   
         if (dev->hub) {          if (dev->hub) {
                for (i = 0;                 for (i = 0;
                      i < sizeof(di->udi_ports) / sizeof(di->udi_ports[0]) &&                       i < sizeof(di->udi_ports) / sizeof(di->udi_ports[0]) &&
                              i < dev->hub->hubdesc.bNbrPorts;                               i < dev->hub->hubdesc.bNbrPorts;
                      i++) {                       i++) {
Line 1235  usb_disconnect_port(struct usbd_port *up Line 1354  usb_disconnect_port(struct usbd_port *up
         const char *hubname = USBDEVPTRNAME(parent);          const char *hubname = USBDEVPTRNAME(parent);
         int i;          int i;
   
        DPRINTFN(3,("uhub_disconnect: up=%p dev=%p port=%d\n",         DPRINTFN(3,("uhub_disconnect: up=%p dev=%p port=%d\n",
                     up, dev, up->portno));                      up, dev, up->portno));
   
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
Line 1245  usb_disconnect_port(struct usbd_port *up Line 1364  usb_disconnect_port(struct usbd_port *up
         }          }
 #endif  #endif
   
         if (dev->cdesc == NULL) {  
                 /* Partially attached device, just drop it. */  
                 dev->bus->devices[dev->address] = 0;  
                 up->device = 0;  
                 return;  
         }  
   
         usbd_add_event(USB_EVENT_DEVICE_DETACH, dev);  
   
         if (dev->subdevs != NULL) {          if (dev->subdevs != NULL) {
                 DPRINTFN(3,("usb_disconnect_port: disconnect subdevs\n"));                  DPRINTFN(3,("usb_disconnect_port: disconnect subdevs\n"));
                 for (i = 0; dev->subdevs[i]; i++) {                  for (i = 0; dev->subdevs[i]; i++) {
                        printf("%s: at %s", USBDEVPTRNAME(dev->subdevs[i]),                         printf("%s: at %s", USBDEVPTRNAME(dev->subdevs[i]),
                                hubname);                                 hubname);
                         if (up->portno != 0)                          if (up->portno != 0)
                                 printf(" port %d", up->portno);                                  printf(" port %d", up->portno);
                         printf(" (addr %d) disconnected\n", dev->address);                          printf(" (addr %d) disconnected\n", dev->address);
 #if defined(__NetBSD__) || defined(__OpenBSD__)  
                         config_detach(dev->subdevs[i], DETACH_FORCE);                          config_detach(dev->subdevs[i], DETACH_FORCE);
 #elif defined(__FreeBSD__)  
                         device_delete_child(device_get_parent(dev->subdevs[i]),  
                                             dev->subdevs[i]);  
 #endif  
   
                 }                  }
         }          }
   
        /*usbd_add_event(USB_EVENT_DEVICE_DETACH, dev);*/        /*usbd_add_dev_event(USB_EVENT_DEVICE_DETACH, dev);*/
         dev->bus->devices[dev->address] = NULL;          dev->bus->devices[dev->address] = NULL;
         up->device = NULL;          up->device = NULL;
         usb_free_device(dev);          usb_free_device(dev);

Removed from v.1.5  
changed lines
  Added in v.1.6