char * usbd_devinfo_alloc(struct usbd_device *dev, int showclass) { char *devinfop; devinfop = kmem_alloc(DEVINFOSIZE, KM_SLEEP); usbd_devinfo(dev, showclass, devinfop, DEVINFOSIZE); return devinfop; }
static int atausb_attach(device_t dev) { struct atausb_softc *sc = device_get_softc(dev); struct usb_attach_arg *uaa = device_get_ivars(dev); usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; usbd_device_handle udev; usb_device_request_t request; char devinfo[1024], *proto, *subclass; u_int8_t maxlun; int err, i; sc->dev = dev; usbd_devinfo(uaa->device, 0, devinfo); device_set_desc_copy(dev, devinfo); sc->bulkin = sc->bulkout = sc->bulkirq = -1; sc->bulkin_pipe = sc->bulkout_pipe= sc->bulkirq_pipe = NULL; sc->iface = uaa->iface; sc->ifaceno = uaa->ifaceno; sc->maxlun = 0; sc->timeout = 5000; sc->locked_ch = NULL; sc->restart_ch = NULL; spin_init(&sc->locked_mtx); id = usbd_get_interface_descriptor(sc->iface); switch (id->bInterfaceProtocol) { case UIPROTO_MASS_BBB: case UIPROTO_MASS_BBB_OLD: proto = "Bulk-Only"; break; case UIPROTO_MASS_CBI: proto = "CBI"; break; case UIPROTO_MASS_CBI_I: proto = "CBI with CCI"; break; default: proto = "Unknown"; } switch (id->bInterfaceSubClass) { case UISUBCLASS_RBC: subclass = "RBC"; break; case UISUBCLASS_QIC157: case UISUBCLASS_SFF8020I: case UISUBCLASS_SFF8070I: subclass = "ATAPI"; break; case UISUBCLASS_SCSI: subclass = "SCSI"; break; case UISUBCLASS_UFI: subclass = "UFI"; break; default: subclass = "Unknown"; } device_printf(dev, "using %s over %s\n", subclass, proto); if (strcmp(proto, "Bulk-Only") || (strcmp(subclass, "ATAPI") && strcmp(subclass, "SCSI"))) return ENXIO; for (i = 0 ; i < id->bNumEndpoints ; i++) { if (!(ed = usbd_interface2endpoint_descriptor(sc->iface, i))) { device_printf(sc->dev, "could not read endpoint descriptor\n"); return ENXIO; } if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) { sc->bulkin = ed->bEndpointAddress; } if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) { sc->bulkout = ed->bEndpointAddress; } if (id->bInterfaceProtocol == UIPROTO_MASS_CBI_I && UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) { sc->bulkirq = ed->bEndpointAddress; } } /* check whether we found at least the endpoints we need */ if (!sc->bulkin || !sc->bulkout) { device_printf(sc->dev, "needed endpoints not found (%d,%d)\n", sc->bulkin, sc->bulkout); atausb_detach(dev); return ENXIO; } /* open the pipes */ if (usbd_open_pipe(sc->iface, sc->bulkout, USBD_EXCLUSIVE_USE, &sc->bulkout_pipe)) { device_printf(sc->dev, "cannot open bulkout pipe (%d)\n", sc->bulkout); atausb_detach(dev); return ENXIO; } if (usbd_open_pipe(sc->iface, sc->bulkin, USBD_EXCLUSIVE_USE, &sc->bulkin_pipe)) { device_printf(sc->dev, "cannot open bulkin pipe (%d)\n", sc->bulkin); atausb_detach(dev); return ENXIO; } if (id->bInterfaceProtocol == UIPROTO_MASS_CBI_I) { if (usbd_open_pipe(sc->iface, sc->bulkirq, USBD_EXCLUSIVE_USE, &sc->bulkirq_pipe)) { device_printf(sc->dev, "cannot open bulkirq pipe (%d)\n", sc->bulkirq); atausb_detach(dev); return ENXIO; } } sc->state = ATAUSB_S_ATTACH; /* alloc needed number of transfer handles */ for (i = 0; i < ATAUSB_T_MAX; i++) { sc->transfer[i] = usbd_alloc_xfer(uaa->device); if (!sc->transfer[i]) { device_printf(sc->dev, "out of memory\n"); atausb_detach(dev); return ENXIO; } } /* driver is ready to process requests here */ sc->state = ATAUSB_S_IDLE; /* get number of devices so we can add matching channels */ usbd_interface2device_handle(sc->iface, &udev); request.bmRequestType = UT_READ_CLASS_INTERFACE; request.bRequest = 0xfe; /* GET_MAX_LUN; */ USETW(request.wValue, 0); USETW(request.wIndex, sc->ifaceno); USETW(request.wLength, sizeof(maxlun)); switch ((err = usbd_do_request(udev, &request, &maxlun))) { case USBD_NORMAL_COMPLETION: if (bootverbose) device_printf(sc->dev, "maxlun=%d\n", maxlun); sc->maxlun = maxlun; break; default: if (bootverbose) device_printf(sc->dev, "get maxlun not supported %s\n", usbd_errstr(err)); } /* ata channels are children to this USB control device */ for (i = 0; i <= sc->maxlun; i++) { /* XXX TGEN devclass_find_free_unit() implementation */ int freeunit = 2; while (freeunit < devclass_get_maxunit(ata_devclass) && devclass_get_device(ata_devclass, freeunit) != NULL) freeunit++; if (!device_add_child(sc->dev, "ata", freeunit)) { device_printf(sc->dev, "failed to attach ata child device\n"); atausb_detach(dev); return ENXIO; } } bus_generic_attach(sc->dev); return 0; }
/* **************************************************************** * Função de "attach" * **************************************************************** */ int uhub_attach (struct device *dev) { struct uhub_softc *sc; struct usb_attach_arg *uaa = dev->ivars; struct usbd_device *udev = uaa->device; struct usbd_hub *hub = NULL; struct usb_device_request req; struct usb_hub_descriptor *hubdesc = NULL; struct usbd_interface *iface; struct usb_endpoint_descriptor *ed; int p, port, nports, nremov, pwrdly, err; /* * Aloca e zera a estrutura "softc" */ if ((sc = dev->softc = malloc_byte (sizeof (struct uhub_softc))) == NULL) return (-1); memclr (sc, sizeof (struct uhub_softc)); #if (0) /*******************************************************/ { char *devinfo; if ((devinfo = malloc_byte (1024)) == NULL) goto bad; memclr (devinfo, 1024); usbd_devinfo (udev, USBD_SHOW_INTERFACE_CLASS, devinfo); device_set_desc_copy (dev, devinfo); free_byte (devinfo); } #endif /*******************************************************/ sc->sc_hub = udev; sc->sc_dev = dev; if (err = usbd_set_config_index (udev, 0, 1)) { printf ("uhub_attach (%s): erro na configuração (%s)\n", dev->nameunit, usbd_errstr (err)); goto bad; } if (udev->depth > USB_HUB_MAX_DEPTH) { printf ( "uhub_attach (%s): profundidade máxima excedida (%d > %d), \"hub\" ignorado\n", dev->nameunit, udev->depth, USB_HUB_MAX_DEPTH ); goto bad; } /* Get hub descriptor */ if ((hubdesc = malloc_byte (sizeof (struct usb_hub_descriptor))) == NULL) { err = USBD_NOMEM; goto bad; } req.bmRequestType = UT_READ_CLASS_DEVICE; req.bRequest = UR_GET_DESCRIPTOR; USETW2 (req.wValue, (udev->address > 1 ? UDESC_HUB : 0), 0); USETW (req.wIndex, 0); USETW (req.wLength, USB_HUB_DESCRIPTOR_SIZE); err = usbd_do_request (udev, &req, hubdesc); nports = hubdesc->bNbrPorts; if (err == 0 && nports > 7) { USETW (req.wLength, USB_HUB_DESCRIPTOR_SIZE + (nports + 1) / 8); err = usbd_do_request (udev, &req, hubdesc); } if (err) { printf ( "uhub_attach (%s): erro ao ler descritor do hub (%s)\n", dev->nameunit, usbd_errstr (err) ); goto bad; } for (nremov = 0, port = 1; port <= nports; port++) { if (!UHD_NOT_REMOV (hubdesc, port)) nremov++; } if (nports == 0) { printf ("%s: hub sem portas ignorado\n", dev->nameunit); goto bad; } printf ( "%s: %d porta%s, %d removíve%s, %s energizadas\n", dev->nameunit, nports, nports != 1 ? "s" : "", nremov, nremov != 1 ? "is" : "l", udev->self_powered ? "auto" : "bus" ); if ((hub = malloc_byte (sizeof (*hub) + (nports - 1) * sizeof (struct usbd_port))) == NULL) goto bad; memclr (hub, (sizeof (*hub) + (nports - 1) * sizeof (struct usbd_port))); udev->hub = hub; udev->hub->hubsoftc = sc; hub->explore = uhub_explore; hub->hubdesc = *hubdesc; free_byte (hubdesc); hubdesc = NULL; #ifdef USB_MSG printf ( "uhub_attach: selfpowered=%d, parent=%p, parent->selfpowered=%d\n", dev->self_powered, dev->powersrc->parent, dev->powersrc->parent ? dev->powersrc->parent->self_powered : 0 ); #endif USB_MSG if (!udev->self_powered && udev->powersrc->parent != NULL && !udev->powersrc->parent->self_powered) { printf ( "uhub_attach (%s): bus powered hub connected to bus powered hub, ignored\n", dev->nameunit ); goto bad; } /* Set up interrupt pipe */ if (usbd_device2interface_handle (udev, 0, &iface)) { printf ("uhub_attach (%s): no interface handle\n", dev->nameunit); goto bad; } if ((ed = usbd_interface2endpoint_descriptor (iface, 0)) == NULL) { printf ("uhub_attach (%s): no endpoint descriptor\n", dev->nameunit); goto bad; } if ((ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) { printf ("uhub_attach (%s): bad interrupt endpoint\n", dev->nameunit); goto bad; } if ( usbd_open_pipe_intr ( iface, ed->bEndpointAddress, USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_status, sizeof (sc->sc_status), uhub_intr, UHUB_INTR_INTERVAL ) ) { printf ("uhub_attach (%s): cannot open interrupt pipe\n", dev->nameunit); goto bad; } /* Wait with power off for a while */ usbd_delay_ms (udev, USB_POWER_DOWN_TIME); /* * To have the best chance of success we do things in the exact same * order as Windoze98. This should not be necessary, but some * devices do not follow the USB specs to the letter. * * These are the events on the bus when a hub is attached: * Get device and config descriptors (see attach code) * Get hub descriptor (see above) * For all ports * turn on power * wait for power to become stable * (all below happens in explore code) * For all ports * clear C_PORT_CONNECTION * For all ports * get port status * if device connected * wait 100 ms * turn on reset * wait * clear C_PORT_RESET * get port status * proceed with device attachment */ /* Set up data structures */ for (p = 0; p < nports; p++) { struct usbd_port *up = &hub->ports[p]; up->device = NULL; up->parent = udev; up->portno = p+1; if (udev->self_powered) /* Self powered hub, give ports maximum current */ up->power = USB_MAX_POWER; else up->power = USB_MIN_POWER; up->restartcnt = 0; } /* XXX should check for none, individual, or ganged power? */ pwrdly = udev->hub->hubdesc.bPwrOn2PwrGood * UHD_PWRON_FACTOR + USB_EXTRA_POWER_UP_TIME; for (port = 1; port <= nports; port++) { /* Turn the power on */ if (err = usbd_set_port_feature (udev, port, UHF_PORT_POWER)) { printf ( "uhub_attach (%s): port %d power on failed, %s\n", dev->nameunit, port, usbd_errstr (err) ); } #ifdef USB_MSG printf ("uhub_attach: turn on port %d power\n", port); #endif USB_MSG /* Wait for stable power */ usbd_delay_ms (udev, pwrdly); } /* The usual exploration will finish the setup */ sc->sc_running = 1; return (0); /* * Em caso de erro, ... */ bad: if (hubdesc != NULL) free_byte (hubdesc); if (hub != NULL) free_byte (hub); udev->hub = NULL; free_byte (sc); dev->softc = NULL; return (-1); } /* end uhub_attach */
usbd_status usbd_probe_and_attach(device_t parent, usbd_device_handle dev, int port, int addr) { struct usb_attach_arg uaa; usb_device_descriptor_t *dd = &dev->ddesc; int found, i, confi, nifaces; usbd_status err; device_t *tmpdv; usbd_interface_handle ifaces[256]; /* 256 is the absolute max */ char *devinfo; /* XXX FreeBSD may leak resources on failure cases -- fixme */ device_t bdev; struct usb_attach_arg *uaap; devinfo = kmalloc(1024, M_USB, M_NOWAIT); if (devinfo == NULL) { device_printf(parent, "Can't allocate memory for probe string\n"); return (USBD_NOMEM); } bdev = device_add_child(parent, NULL, -1); if (!bdev) { kfree(devinfo, M_USB); device_printf(parent, "Device creation failed\n"); return (USBD_INVAL); } uaap = kmalloc(sizeof(uaa), M_USB, M_WAITOK); device_set_ivars(bdev, uaap); uaa.device = dev; uaa.iface = NULL; uaa.ifaces = NULL; uaa.nifaces = 0; uaa.usegeneric = 0; uaa.port = port; uaa.configno = UHUB_UNK_CONFIGURATION; uaa.ifaceno = UHUB_UNK_INTERFACE; uaa.vendor = UGETW(dd->idVendor); uaa.product = UGETW(dd->idProduct); uaa.release = UGETW(dd->bcdDevice); uaa.matchlvl = 0; /* First try with device specific drivers. */ DPRINTF(("usbd_probe_and_attach: trying device specific drivers\n")); dev->ifacenums = NULL; dev->subdevs = kmalloc(2 * sizeof(device_t), M_USB, M_WAITOK); dev->subdevs[0] = bdev; dev->subdevs[1] = 0; *uaap = uaa; usbd_devinfo(dev, 1, devinfo); device_set_desc_copy(bdev, devinfo); if (device_probe_and_attach(bdev) == 0) { kfree(devinfo, M_USB); return (USBD_NORMAL_COMPLETION); } /* * Free subdevs so we can reallocate it larger for the number of * interfaces */ tmpdv = dev->subdevs; dev->subdevs = NULL; kfree(tmpdv, M_USB); DPRINTF(("usbd_probe_and_attach: no device specific driver found\n")); DPRINTF(("usbd_probe_and_attach: looping over %d configurations\n", dd->bNumConfigurations)); /* Next try with interface drivers. */ for (confi = 0; confi < dd->bNumConfigurations; confi++) { DPRINTFN(1,("usbd_probe_and_attach: trying config idx=%d\n", confi)); err = usbd_set_config_index(dev, confi, 1); if (err) { #ifdef USB_DEBUG DPRINTF(("%s: port %d, set config at addr %d failed, " "error=%s\n", device_get_nameunit(parent), port, addr, usbd_errstr(err))); #else kprintf("%s: port %d, set config at addr %d failed\n", device_get_nameunit(parent), port, addr); #endif kfree(devinfo, M_USB); return (err); } nifaces = dev->cdesc->bNumInterface; uaa.configno = dev->cdesc->bConfigurationValue; for (i = 0; i < nifaces; i++) ifaces[i] = &dev->ifaces[i]; uaa.ifaces = ifaces; uaa.nifaces = nifaces; dev->subdevs = kmalloc((nifaces+1) * sizeof(device_t), M_USB, M_WAITOK); dev->ifacenums = kmalloc((nifaces) * sizeof(*dev->ifacenums), M_USB, M_WAITOK); found = 0; for (i = 0; i < nifaces; i++) { if (ifaces[i] == NULL) continue; /* interface already claimed */ uaa.iface = ifaces[i]; uaa.ifaceno = ifaces[i]->idesc->bInterfaceNumber; dev->subdevs[found] = bdev; dev->subdevs[found + 1] = 0; dev->ifacenums[found] = i; *uaap = uaa; usbd_devinfo(dev, 1, devinfo); device_set_desc_copy(bdev, devinfo); if (device_probe_and_attach(bdev) == 0) { ifaces[i] = 0; /* consumed */ found++; /* create another child for the next iface */ bdev = device_add_child(parent, NULL, -1); if (!bdev) { device_printf(parent, "Device add failed\n"); kfree(devinfo, M_USB); return (USBD_NORMAL_COMPLETION); } uaap = kmalloc(sizeof(uaa), M_USB, M_WAITOK); device_set_ivars(bdev, uaap); } else { dev->subdevs[found] = 0; } } if (found != 0) { /* remove the last created child. It is unused */ kfree(uaap, M_USB); kfree(devinfo, M_USB); device_delete_child(parent, bdev); /* kfree(uaap, M_USB); */ /* May be needed? xxx */ return (USBD_NORMAL_COMPLETION); } tmpdv = dev->subdevs; dev->subdevs = NULL; kfree(tmpdv, M_USB); kfree(dev->ifacenums, M_USB); dev->ifacenums = NULL; } /* No interfaces were attached in any of the configurations. */ if (dd->bNumConfigurations > 1) /* don't change if only 1 config */ usbd_set_config_index(dev, 0, 0); DPRINTF(("usbd_probe_and_attach: no interface drivers found\n")); /* Finally try the generic driver. */ uaa.iface = NULL; uaa.usegeneric = 1; uaa.configno = UHUB_UNK_CONFIGURATION; uaa.ifaceno = UHUB_UNK_INTERFACE; dev->subdevs = kmalloc(2 * sizeof(device_t), M_USB, M_WAITOK); dev->subdevs[0] = bdev; dev->subdevs[1] = 0; *uaap = uaa; usbd_devinfo(dev, 1, devinfo); device_set_desc_copy(bdev, devinfo); kfree(devinfo, M_USB); if (device_probe_and_attach(bdev) == 0) return (USBD_NORMAL_COMPLETION); /* * The generic attach failed, but leave the device as it is. * We just did not find any drivers, that's all. The device is * fully operational and not harming anyone. */ DPRINTF(("usbd_probe_and_attach: generic attach failed\n")); return (USBD_NORMAL_COMPLETION); }