version 1.152, 2008/04/05 16:35:35 |
version 1.152.4.4, 2009/09/16 13:37:58 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
|
* must display the following acknowledgement: |
|
* This product includes software developed by the NetBSD |
|
* Foundation, Inc. and its contributors. |
|
* 4. Neither the name of The NetBSD Foundation nor the names of its |
|
* contributors may be used to endorse or promote products derived |
|
* from this software without specific prior written permission. |
|
* |
* |
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
Line 48 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 41 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <sys/systm.h> |
#include <sys/systm.h> |
#include <sys/kernel.h> |
#include <sys/kernel.h> |
#include <sys/malloc.h> |
#include <sys/malloc.h> |
#if defined(__NetBSD__) || defined(__OpenBSD__) |
|
#include <sys/device.h> |
#include <sys/device.h> |
#include <sys/select.h> |
#include <sys/select.h> |
#elif defined(__FreeBSD__) |
|
#include <sys/module.h> |
|
#include <sys/bus.h> |
|
#endif |
|
#include <sys/proc.h> |
#include <sys/proc.h> |
|
|
#include <sys/bus.h> |
#include <sys/bus.h> |
Line 67 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 55 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <dev/usb/usbdevs.h> |
#include <dev/usb/usbdevs.h> |
#include <dev/usb/usb_quirks.h> |
#include <dev/usb/usb_quirks.h> |
|
|
#if defined(__FreeBSD__) |
#include "locators.h" |
#include <machine/clock.h> |
|
#define delay(d) DELAY(d) |
|
#endif |
|
|
|
#ifdef USB_DEBUG |
#ifdef USB_DEBUG |
#define DPRINTF(x) if (usbdebug) logprintf x |
#define DPRINTF(x) if (usbdebug) logprintf x |
Line 88 Static void usbd_devinfo_vp(usbd_device_ |
|
Line 73 Static void usbd_devinfo_vp(usbd_device_ |
|
char *p, int usedev, |
char *p, int usedev, |
int useencoded ); |
int useencoded ); |
Static int usbd_getnewaddr(usbd_bus_handle bus); |
Static int usbd_getnewaddr(usbd_bus_handle bus); |
#if defined(__NetBSD__) |
|
Static int usbd_print(void *, const char *); |
Static int usbd_print(void *, const char *); |
Static int usbd_ifprint(void *, const char *); |
Static int usbd_ifprint(void *, const char *); |
Static int usbd_submatch(device_ptr_t, struct cfdata *, |
|
const int *, void *); |
|
Static int usbd_ifsubmatch(device_ptr_t, struct cfdata *, |
|
const int *, void *); |
|
#elif defined(__OpenBSD__) |
|
Static int usbd_print(void *aux, const char *pnp); |
|
Static int usbd_submatch(device_ptr_t, void *, void *); |
|
#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(device_ptr_t parent, |
usbd_status usbd_attach_roothub(device_t, usbd_device_handle); |
usbd_device_handle dev, int port, int addr); |
Static usbd_status usbd_probe_and_attach(device_t parent, |
|
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 578 usbd_set_config_index(usbd_device_handle |
|
Line 555 usbd_set_config_index(usbd_device_handle |
|
DPRINTFN(5,("usbd_set_config_index: dev=%p index=%d\n", dev, index)); |
DPRINTFN(5,("usbd_set_config_index: dev=%p index=%d\n", dev, index)); |
|
|
if (index >= dev->ddesc.bNumConfigurations && |
if (index >= dev->ddesc.bNumConfigurations && |
index != USB_UNCONFIG_NO) { |
index != USB_UNCONFIG_INDEX) { |
/* panic? */ |
/* panic? */ |
printf("usbd_set_config_index: illegal index\n"); |
printf("usbd_set_config_index: illegal index\n"); |
return (USBD_INVAL); |
return (USBD_INVAL); |
Line 663 usbd_set_config_index(usbd_device_handle |
|
Line 640 usbd_set_config_index(usbd_device_handle |
|
if (msg) |
if (msg) |
printf("%s: device addr %d (config %d): " |
printf("%s: device addr %d (config %d): " |
"can't set self powered configuration\n", |
"can't set self powered configuration\n", |
USBDEVNAME(dev->bus->bdev), dev->address, |
device_xname(dev->bus->bdev), dev->address, |
cdp->bConfigurationValue); |
cdp->bConfigurationValue); |
err = USBD_NO_POWER; |
err = USBD_NO_POWER; |
goto bad; |
goto bad; |
Line 788 usbd_getnewaddr(usbd_bus_handle bus) |
|
Line 765 usbd_getnewaddr(usbd_bus_handle bus) |
|
return (-1); |
return (-1); |
} |
} |
|
|
|
|
usbd_status |
usbd_status |
usbd_probe_and_attach(device_ptr_t parent, usbd_device_handle dev, |
usbd_attach_roothub(device_t parent, usbd_device_handle dev) |
int port, int addr) |
|
{ |
{ |
struct usb_attach_arg uaa; |
struct usb_attach_arg uaa; |
struct usbif_attach_arg uiaa; |
|
usb_device_descriptor_t *dd = &dev->ddesc; |
usb_device_descriptor_t *dd = &dev->ddesc; |
int found, i, confi, nifaces; |
device_t dv; |
usbd_status err; |
|
device_ptr_t dv; |
|
usbd_interface_handle *ifaces; |
|
|
|
#if defined(__FreeBSD__) |
uaa.device = dev; |
/* |
uaa.usegeneric = 0; |
* XXX uaa is a static var. Not a problem as it _should_ be used only |
uaa.port = 0; |
* during probe and attach. Should be changed however. |
uaa.vendor = UGETW(dd->idVendor); |
*/ |
uaa.product = UGETW(dd->idProduct); |
device_t bdev; |
uaa.release = UGETW(dd->bcdDevice); |
bdev = device_add_child(parent, NULL, -1, &uaa); |
uaa.class = dd->bDeviceClass; |
if (!bdev) { |
uaa.subclass = dd->bDeviceSubClass; |
printf("%s: Device creation failed\n", USBDEVNAME(dev->bus->bdev)); |
uaa.proto = dd->bDeviceProtocol; |
return (USBD_INVAL); |
|
|
dv = config_found_ia(parent, "usbroothubif", &uaa, 0); |
|
if (dv) { |
|
dev->subdevs = malloc(sizeof dv, M_USB, M_NOWAIT); |
|
if (dev->subdevs == NULL) |
|
return (USBD_NOMEM); |
|
dev->subdevs[0] = dv; |
|
dev->subdevlen = 1; |
} |
} |
device_quiet(bdev); |
return (USBD_NORMAL_COMPLETION); |
#endif |
} |
|
|
|
static usbd_status |
|
usbd_attachwholedevice(device_t parent, usbd_device_handle dev, int port, |
|
int usegeneric) |
|
{ |
|
struct usb_attach_arg uaa; |
|
usb_device_descriptor_t *dd = &dev->ddesc; |
|
device_t dv; |
|
int dlocs[USBDEVIFCF_NLOCS]; |
|
|
uaa.device = dev; |
uaa.device = dev; |
uaa.usegeneric = 0; |
uaa.usegeneric = usegeneric; |
uaa.port = port; |
uaa.port = port; |
uaa.vendor = UGETW(dd->idVendor); |
uaa.vendor = UGETW(dd->idVendor); |
uaa.product = UGETW(dd->idProduct); |
uaa.product = UGETW(dd->idProduct); |
Line 825 usbd_probe_and_attach(device_ptr_t paren |
|
Line 812 usbd_probe_and_attach(device_ptr_t paren |
|
uaa.subclass = dd->bDeviceSubClass; |
uaa.subclass = dd->bDeviceSubClass; |
uaa.proto = dd->bDeviceProtocol; |
uaa.proto = dd->bDeviceProtocol; |
|
|
/* First try with device specific drivers. */ |
dlocs[USBDEVIFCF_PORT] = uaa.port; |
DPRINTF(("usbd_probe_and_attach: trying device specific drivers\n")); |
dlocs[USBDEVIFCF_VENDOR] = uaa.vendor; |
dv = USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print, usbd_submatch); |
dlocs[USBDEVIFCF_PRODUCT] = uaa.product; |
|
dlocs[USBDEVIFCF_RELEASE] = uaa.release; |
|
/* the rest is historical ballast */ |
|
dlocs[USBDEVIFCF_CONFIGURATION] = -1; |
|
dlocs[USBDEVIFCF_INTERFACE] = -1; |
|
|
|
dv = config_found_sm_loc(parent, "usbdevif", dlocs, &uaa, usbd_print, |
|
config_stdsubmatch); |
if (dv) { |
if (dv) { |
dev->subdevs = malloc(2 * sizeof dv, M_USB, M_NOWAIT); |
dev->subdevs = malloc(sizeof dv, M_USB, M_NOWAIT); |
if (dev->subdevs == NULL) |
if (dev->subdevs == NULL) |
return (USBD_NOMEM); |
return (USBD_NOMEM); |
dev->subdevs[0] = dv; |
dev->subdevs[0] = dv; |
dev->subdevs[1] = 0; |
dev->subdevlen = 1; |
return (USBD_NORMAL_COMPLETION); |
dev->nifaces_claimed = 1; /* XXX */ |
} |
} |
|
return (USBD_NORMAL_COMPLETION); |
|
} |
|
|
DPRINTF(("usbd_probe_and_attach: no device specific driver found\n")); |
static usbd_status |
|
usbd_attachinterfaces(device_t parent, usbd_device_handle dev, |
|
int port, const int *locators) |
|
{ |
|
struct usbif_attach_arg uiaa; |
|
int ilocs[USBIFIFCF_NLOCS]; |
|
usb_device_descriptor_t *dd = &dev->ddesc; |
|
int nifaces; |
|
usbd_interface_handle *ifaces; |
|
int i, j, loc; |
|
device_t dv; |
|
|
|
nifaces = dev->cdesc->bNumInterface; |
|
ifaces = malloc(nifaces * sizeof(*ifaces), M_USB, M_NOWAIT|M_ZERO); |
|
if (!ifaces) |
|
return (USBD_NOMEM); |
|
for (i = 0; i < nifaces; i++) |
|
if (!dev->subdevs[i]) |
|
ifaces[i] = &dev->ifaces[i]; |
|
|
uiaa.device = dev; |
uiaa.device = dev; |
uiaa.port = port; |
uiaa.port = port; |
uiaa.vendor = UGETW(dd->idVendor); |
uiaa.vendor = UGETW(dd->idVendor); |
uiaa.product = UGETW(dd->idProduct); |
uiaa.product = UGETW(dd->idProduct); |
uiaa.release = UGETW(dd->bcdDevice); |
uiaa.release = UGETW(dd->bcdDevice); |
|
uiaa.configno = dev->cdesc->bConfigurationValue; |
|
uiaa.ifaces = ifaces; |
|
uiaa.nifaces = nifaces; |
|
ilocs[USBIFIFCF_PORT] = uiaa.port; |
|
ilocs[USBIFIFCF_VENDOR] = uiaa.vendor; |
|
ilocs[USBIFIFCF_PRODUCT] = uiaa.product; |
|
ilocs[USBIFIFCF_RELEASE] = uiaa.release; |
|
ilocs[USBIFIFCF_CONFIGURATION] = uiaa.configno; |
|
|
|
for (i = 0; i < nifaces; i++) { |
|
if (!ifaces[i]) |
|
continue; /* interface already claimed */ |
|
uiaa.iface = ifaces[i]; |
|
uiaa.class = ifaces[i]->idesc->bInterfaceClass; |
|
uiaa.subclass = ifaces[i]->idesc->bInterfaceSubClass; |
|
uiaa.proto = ifaces[i]->idesc->bInterfaceProtocol; |
|
uiaa.ifaceno = ifaces[i]->idesc->bInterfaceNumber; |
|
ilocs[USBIFIFCF_INTERFACE] = uiaa.ifaceno; |
|
if (locators != NULL) { |
|
loc = locators[USBIFIFCF_CONFIGURATION]; |
|
if (loc != USBIFIFCF_CONFIGURATION_DEFAULT && |
|
loc != uiaa.configno) |
|
continue; |
|
loc = locators[USBIFIFCF_INTERFACE]; |
|
if (loc != USBIFIFCF_INTERFACE && loc != uiaa.ifaceno) |
|
continue; |
|
} |
|
dv = config_found_sm_loc(parent, "usbifif", ilocs, &uiaa, |
|
usbd_ifprint, config_stdsubmatch); |
|
if (!dv) |
|
continue; |
|
ifaces[i] = 0; /* claim */ |
|
/* account for ifaces claimed by the driver behind our back */ |
|
for (j = 0; j < nifaces; j++) { |
|
if (!ifaces[j] && !dev->subdevs[j]) { |
|
dev->subdevs[j] = dv; |
|
dev->nifaces_claimed++; |
|
} |
|
} |
|
} |
|
|
|
free(ifaces, M_USB); |
|
return (USBD_NORMAL_COMPLETION); |
|
} |
|
|
|
usbd_status |
|
usbd_probe_and_attach(device_t parent, usbd_device_handle dev, |
|
int port, int addr) |
|
{ |
|
usb_device_descriptor_t *dd = &dev->ddesc; |
|
int confi, nifaces; |
|
usbd_status err; |
|
|
|
/* First try with device specific drivers. */ |
|
DPRINTF(("usbd_probe_and_attach: trying device specific drivers\n")); |
|
err = usbd_attachwholedevice(parent, dev, port, 0); |
|
if (dev->nifaces_claimed || err) |
|
return (err); |
|
DPRINTF(("usbd_probe_and_attach: no device specific driver found\n")); |
|
|
DPRINTF(("usbd_probe_and_attach: looping over %d configurations\n", |
DPRINTF(("usbd_probe_and_attach: looping over %d configurations\n", |
dd->bNumConfigurations)); |
dd->bNumConfigurations)); |
/* Next try with interface drivers. */ |
|
for (confi = 0; confi < dd->bNumConfigurations; confi++) { |
for (confi = 0; confi < dd->bNumConfigurations; confi++) { |
DPRINTFN(1,("usbd_probe_and_attach: trying config idx=%d\n", |
DPRINTFN(1,("usbd_probe_and_attach: trying config idx=%d\n", |
confi)); |
confi)); |
Line 855 usbd_probe_and_attach(device_ptr_t paren |
|
Line 927 usbd_probe_and_attach(device_ptr_t paren |
|
if (err) { |
if (err) { |
#ifdef USB_DEBUG |
#ifdef USB_DEBUG |
DPRINTF(("%s: port %d, set config at addr %d failed, " |
DPRINTF(("%s: port %d, set config at addr %d failed, " |
"error=%s\n", USBDEVPTRNAME(parent), port, |
"error=%s\n", device_xname(parent), port, |
addr, usbd_errstr(err))); |
addr, usbd_errstr(err))); |
#else |
#else |
printf("%s: port %d, set config at addr %d failed\n", |
printf("%s: port %d, set config at addr %d failed\n", |
USBDEVPTRNAME(parent), port, addr); |
device_xname(parent), port, addr); |
#endif |
#endif |
#if defined(__FreeBSD__) |
return (err); |
device_delete_child(parent, bdev); |
|
#endif |
|
|
|
return (err); |
|
} |
} |
nifaces = dev->cdesc->bNumInterface; |
nifaces = dev->cdesc->bNumInterface; |
uiaa.configno = dev->cdesc->bConfigurationValue; |
dev->subdevs = malloc(nifaces * sizeof(device_t), M_USB, |
ifaces = malloc(nifaces * sizeof(*ifaces), M_USB, M_NOWAIT); |
M_NOWAIT|M_ZERO); |
if (ifaces == NULL) |
if (dev->subdevs == NULL) |
goto nomem; |
|
for (i = 0; i < nifaces; i++) |
|
ifaces[i] = &dev->ifaces[i]; |
|
uiaa.ifaces = ifaces; |
|
uiaa.nifaces = nifaces; |
|
dev->subdevs = malloc((nifaces+1) * sizeof dv, M_USB,M_NOWAIT); |
|
if (dev->subdevs == NULL) { |
|
free(ifaces, M_USB); |
|
nomem: |
|
#if defined(__FreeBSD__) |
|
device_delete_child(parent, bdev); |
|
#endif |
|
return (USBD_NOMEM); |
return (USBD_NOMEM); |
} |
dev->subdevlen = nifaces; |
|
|
found = 0; |
err = usbd_attachinterfaces(parent, dev, port, NULL); |
for (i = 0; i < nifaces; i++) { |
|
if (ifaces[i] == NULL) |
if (!dev->nifaces_claimed) { |
continue; /* interface already claimed */ |
free(dev->subdevs, M_USB); |
uiaa.iface = ifaces[i]; |
dev->subdevs = 0; |
uiaa.class = ifaces[i]->idesc->bInterfaceClass; |
dev->subdevlen = 0; |
uiaa.subclass = ifaces[i]->idesc->bInterfaceSubClass; |
|
uiaa.proto = ifaces[i]->idesc->bInterfaceProtocol; |
|
uiaa.ifaceno = ifaces[i]->idesc->bInterfaceNumber; |
|
dv = USB_DO_IFATTACH(dev, bdev, parent, &uiaa, usbd_ifprint, |
|
usbd_ifsubmatch); |
|
if (dv != NULL) { |
|
dev->subdevs[found++] = dv; |
|
dev->subdevs[found] = 0; |
|
ifaces[i] = 0; /* consumed */ |
|
|
|
#if defined(__FreeBSD__) |
|
/* create another child for the next iface */ |
|
bdev = device_add_child(parent, NULL, -1,&uaa); |
|
if (!bdev) { |
|
printf("%s: Device creation failed\n", |
|
USBDEVNAME(dev->bus->bdev)); |
|
free(ifaces, M_USB); |
|
return (USBD_NORMAL_COMPLETION); |
|
} |
|
device_quiet(bdev); |
|
#endif |
|
} |
|
} |
|
if (found != 0) { |
|
#if defined(__FreeBSD__) |
|
/* remove the last created child again; it is unused */ |
|
device_delete_child(parent, bdev); |
|
#endif |
|
free(ifaces, M_USB); |
|
return (USBD_NORMAL_COMPLETION); |
|
} |
} |
free(ifaces, M_USB); |
if (dev->nifaces_claimed || err) |
free(dev->subdevs, M_USB); |
return (err); |
dev->subdevs = 0; |
|
} |
} |
/* No interfaces were attached in any of the configurations. */ |
/* No interfaces were attached in any of the configurations. */ |
|
|
|
|
DPRINTF(("usbd_probe_and_attach: no interface drivers found\n")); |
DPRINTF(("usbd_probe_and_attach: no interface drivers found\n")); |
|
|
/* Finally try the generic driver. */ |
/* Finally try the generic driver. */ |
uaa.usegeneric = 1; |
err = usbd_attachwholedevice(parent, dev, port, 1); |
dv = USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print, usbd_submatch); |
|
if (dv != NULL) { |
|
dev->subdevs = malloc(2 * sizeof dv, M_USB, M_NOWAIT); |
|
if (dev->subdevs == 0) |
|
return (USBD_NOMEM); |
|
dev->subdevs[0] = dv; |
|
dev->subdevs[1] = 0; |
|
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. |
|
|
* fully operational and not harming anyone. |
* fully operational and not harming anyone. |
*/ |
*/ |
DPRINTF(("usbd_probe_and_attach: generic attach failed\n")); |
DPRINTF(("usbd_probe_and_attach: generic attach failed\n")); |
#if defined(__FreeBSD__) |
return (USBD_NORMAL_COMPLETION); |
device_delete_child(parent, bdev); |
|
#endif |
|
return (USBD_NORMAL_COMPLETION); |
|
} |
} |
|
|
|
/** |
|
* Called from uhub_rescan(). usbd_new_device() for the target dev must be |
|
* called before calling this. |
|
*/ |
|
usbd_status |
|
usbd_reattach_device(device_t parent, usbd_device_handle dev, |
|
int port, const int *locators) |
|
{ |
|
int i, loc; |
|
|
|
if (locators != NULL) { |
|
loc = locators[USBIFIFCF_PORT]; |
|
if (loc != USBIFIFCF_PORT_DEFAULT && loc != port) |
|
return USBD_NORMAL_COMPLETION; |
|
loc = locators[USBIFIFCF_VENDOR]; |
|
if (loc != USBIFIFCF_VENDOR_DEFAULT && |
|
loc != UGETW(dev->ddesc.idVendor)) |
|
return USBD_NORMAL_COMPLETION; |
|
loc = locators[USBIFIFCF_PRODUCT]; |
|
if (loc != USBIFIFCF_PRODUCT_DEFAULT && |
|
loc != UGETW(dev->ddesc.idProduct)) |
|
return USBD_NORMAL_COMPLETION; |
|
loc = locators[USBIFIFCF_RELEASE]; |
|
if (loc != USBIFIFCF_RELEASE_DEFAULT && |
|
loc != UGETW(dev->ddesc.bcdDevice)) |
|
return USBD_NORMAL_COMPLETION; |
|
} |
|
if (dev->subdevlen == 0) { |
|
/* XXX: check USBIFIFCF_CONFIGURATION and |
|
* USBIFIFCF_INTERFACE too */ |
|
return usbd_probe_and_attach(parent, dev, port, dev->address); |
|
} else if (dev->subdevlen != dev->cdesc->bNumInterface) { |
|
/* device-specific or generic driver is already attached. */ |
|
return USBD_NORMAL_COMPLETION; |
|
} |
|
/* Does the device have unconfigured interfaces? */ |
|
for (i = 0; i < dev->subdevlen; i++) { |
|
if (dev->subdevs[i] == NULL) { |
|
break; |
|
} |
|
} |
|
if (i >= dev->subdevlen) |
|
return USBD_NORMAL_COMPLETION; |
|
return usbd_attachinterfaces(parent, dev, port, locators); |
|
} |
|
|
/* |
/* |
* Called when a new device has been put in the powered state, |
* Called when a new device has been put in the powered state, |
|
|
* and attach a driver. |
* and attach a driver. |
*/ |
*/ |
usbd_status |
usbd_status |
usbd_new_device(device_ptr_t parent, usbd_bus_handle bus, int depth, |
usbd_new_device(device_t parent, usbd_bus_handle bus, int depth, |
int speed, int port, struct usbd_port *up) |
int speed, int port, struct usbd_port *up) |
{ |
{ |
usbd_device_handle dev, adev; |
usbd_device_handle dev, adev; |
struct usbd_device *hub; |
struct usbd_device *hub; |
Line 1001 usbd_new_device(device_ptr_t parent, usb |
|
Line 1059 usbd_new_device(device_ptr_t parent, usb |
|
dev->def_ep_desc.bDescriptorType = UDESC_ENDPOINT; |
dev->def_ep_desc.bDescriptorType = UDESC_ENDPOINT; |
dev->def_ep_desc.bEndpointAddress = USB_CONTROL_ENDPOINT; |
dev->def_ep_desc.bEndpointAddress = USB_CONTROL_ENDPOINT; |
dev->def_ep_desc.bmAttributes = UE_CONTROL; |
dev->def_ep_desc.bmAttributes = UE_CONTROL; |
USETW(dev->def_ep_desc.wMaxPacketSize, USB_MAX_IPACKET); |
if (speed == USB_SPEED_HIGH) |
|
USETW(dev->def_ep_desc.wMaxPacketSize, 64); |
|
else |
|
USETW(dev->def_ep_desc.wMaxPacketSize, USB_MAX_IPACKET); |
dev->def_ep_desc.bInterval = 0; |
dev->def_ep_desc.bInterval = 0; |
|
|
dev->quirks = &usbd_no_quirk; |
dev->quirks = &usbd_no_quirk; |
Line 1043 usbd_new_device(device_ptr_t parent, usb |
|
Line 1104 usbd_new_device(device_ptr_t parent, usb |
|
return (err); |
return (err); |
} |
} |
|
|
/* Set the address. Do this early; some devices need that. */ |
|
/* Try a few times in case the device is slow (i.e. outside specs) */ |
|
DPRINTFN(5,("usbd_new_device: setting device address=%d\n", addr)); |
|
for (i = 0; i < 15; i++) { |
|
err = usbd_set_address(dev, addr); |
|
if (!err) |
|
break; |
|
usbd_delay_ms(dev, 200); |
|
if ((i & 3) == 3) { |
|
DPRINTFN(-1,("usbd_new_device: set address %d " |
|
"failed - trying a port reset\n", addr)); |
|
usbd_reset_port(up->parent, port, &ps); |
|
} |
|
} |
|
if (err) { |
|
DPRINTFN(-1,("usb_new_device: set address %d failed\n", addr)); |
|
err = USBD_SET_ADDR_FAILED; |
|
usbd_remove_device(dev, up); |
|
return (err); |
|
} |
|
/* Allow device time to set new address */ |
|
usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE); |
|
dev->address = addr; /* New device address now */ |
|
bus->devices[addr] = 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 < 10; i++) { |
for (i = 0; i < 10; 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, |
|
(speed == USB_SPEED_HIGH) ? USB_DEVICE_DESCRIPTOR_SIZE |
|
: USB_MAX_IPACKET, |
|
dd); |
|
|
if (!err) |
if (!err) |
break; |
break; |
usbd_delay_ms(dev, 200); |
usbd_delay_ms(dev, 200); |
Line 1127 usbd_new_device(device_ptr_t parent, usb |
|
Line 1167 usbd_new_device(device_ptr_t parent, usb |
|
return (err); |
return (err); |
} |
} |
|
|
|
/* Set the address */ |
|
DPRINTFN(5, ("usbd_new_device: setting device address=%d\n", addr)); |
|
err = usbd_set_address(dev, addr); |
|
if (err) { |
|
DPRINTFN(-1, ("usbd_new_device: set address %d failed\n", addr)); |
|
err = USBD_SET_ADDR_FAILED; |
|
usbd_remove_device(dev, up); |
|
return err; |
|
} |
|
|
|
/* Allow device time to set new address */ |
|
usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE); |
|
dev->address = addr; /* new device address now */ |
|
bus->devices[addr] = dev; |
|
|
|
/* Re-establish the default pipe with the new address. */ |
|
usbd_kill_pipe(dev->default_pipe); |
|
err = usbd_setup_pipe(dev, 0, &dev->def_ep, USBD_DEFAULT_INTERVAL, |
|
&dev->default_pipe); |
|
if (err) { |
|
DPRINTFN(-1, ("usbd_new_device: setup default pipe failed\n")); |
|
usbd_remove_device(dev, up); |
|
return err; |
|
} |
|
|
/* Assume 100mA bus powered for now. Changed when configured. */ |
/* Assume 100mA bus powered for now. Changed when configured. */ |
dev->power = USB_MIN_POWER; |
dev->power = USB_MIN_POWER; |
dev->self_powered = 0; |
dev->self_powered = 0; |
Line 1136 usbd_new_device(device_ptr_t parent, usb |
|
Line 1201 usbd_new_device(device_ptr_t parent, usb |
|
|
|
usbd_add_dev_event(USB_EVENT_DEVICE_ATTACH, dev); |
usbd_add_dev_event(USB_EVENT_DEVICE_ATTACH, dev); |
|
|
|
if (port == 0) { /* root hub */ |
|
KASSERT(addr == 1); |
|
usbd_attach_roothub(parent, dev); |
|
return (USBD_NORMAL_COMPLETION); |
|
} |
|
|
err = usbd_probe_and_attach(parent, dev, port, addr); |
err = usbd_probe_and_attach(parent, dev, port, addr); |
if (err) { |
if (err) { |
usbd_remove_device(dev, up); |
usbd_remove_device(dev, up); |
return (err); |
return (err); |
} |
} |
|
|
return (USBD_NORMAL_COMPLETION); |
return (USBD_NORMAL_COMPLETION); |
} |
} |
|
|
usbd_status |
usbd_status |
Line 1174 usbd_remove_device(usbd_device_handle de |
|
Line 1245 usbd_remove_device(usbd_device_handle de |
|
free(dev, M_USB); |
free(dev, M_USB); |
} |
} |
|
|
#if defined(__NetBSD__) || defined(__OpenBSD__) |
|
int |
int |
usbd_print(void *aux, const char *pnp) |
usbd_print(void *aux, const char *pnp) |
{ |
{ |
Line 1191 usbd_print(void *aux, const char *pnp) |
|
Line 1261 usbd_print(void *aux, const char *pnp) |
|
aprint_normal("%s, %s", devinfo, pnp); |
aprint_normal("%s, %s", devinfo, pnp); |
free(devinfo, M_TEMP); |
free(devinfo, M_TEMP); |
} |
} |
if (uaa->port != 0) |
aprint_normal(" port %d", uaa->port); |
aprint_normal(" port %d", uaa->port); |
|
#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. |
Line 1217 usbd_ifprint(void *aux, const char *pnp) |
|
Line 1286 usbd_ifprint(void *aux, const char *pnp) |
|
DPRINTFN(15, ("usbd_print dev=%p\n", uaa->device)); |
DPRINTFN(15, ("usbd_print dev=%p\n", uaa->device)); |
if (pnp) |
if (pnp) |
return (QUIET); |
return (QUIET); |
if (uaa->port != 0) |
aprint_normal(" port %d", uaa->port); |
aprint_normal(" port %d", uaa->port); |
aprint_normal(" configuration %d", uaa->configno); |
if (uaa->configno != UHUB_UNK_CONFIGURATION) |
aprint_normal(" interface %d", uaa->ifaceno); |
aprint_normal(" configuration %d", uaa->configno); |
|
if (uaa->ifaceno != UHUB_UNK_INTERFACE) |
|
aprint_normal(" 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. |
Line 1239 usbd_ifprint(void *aux, const char *pnp) |
|
Line 1305 usbd_ifprint(void *aux, const char *pnp) |
|
return (UNCONF); |
return (UNCONF); |
} |
} |
|
|
#if defined(__NetBSD__) |
|
int |
|
usbd_submatch(struct device *parent, struct cfdata *cf, |
|
const int *ldesc, void *aux) |
|
{ |
|
#elif defined(__OpenBSD__) |
|
int |
|
usbd_submatch(struct device *parent, void *match, void *aux) |
|
{ |
|
struct cfdata *cf = match; |
|
#endif |
|
struct usb_attach_arg *uaa = aux; |
|
|
|
DPRINTFN(5,("usbd_submatch port=%d,%d " |
|
"vendor=%d,%d product=%d,%d release=%d,%d\n", |
|
uaa->port, cf->uhubcf_port, |
|
uaa->vendor, cf->uhubcf_vendor, |
|
uaa->product, cf->uhubcf_product, |
|
uaa->release, cf->uhubcf_release)); |
|
if (uaa->port != 0 && /* root hub has port 0, it should match */ |
|
((cf->uhubcf_port != UHUB_UNK_PORT && |
|
cf->uhubcf_port != uaa->port) || |
|
(uaa->vendor != UHUB_UNK_VENDOR && |
|
cf->uhubcf_vendor != UHUB_UNK_VENDOR && |
|
cf->uhubcf_vendor != uaa->vendor) || |
|
(uaa->product != UHUB_UNK_PRODUCT && |
|
cf->uhubcf_product != UHUB_UNK_PRODUCT && |
|
cf->uhubcf_product != uaa->product) || |
|
(uaa->release != UHUB_UNK_RELEASE && |
|
cf->uhubcf_release != UHUB_UNK_RELEASE && |
|
cf->uhubcf_release != uaa->release) |
|
) |
|
) |
|
return 0; |
|
return (config_match(parent, cf, aux)); |
|
} |
|
|
|
int |
|
usbd_ifsubmatch(struct device *parent, struct cfdata *cf, |
|
const int *ldesc, void *aux) |
|
{ |
|
struct usbif_attach_arg *uaa = aux; |
|
|
|
DPRINTFN(5,("usbd_submatch port=%d,%d configno=%d,%d " |
|
"ifaceno=%d,%d vendor=%d,%d product=%d,%d release=%d,%d\n", |
|
uaa->port, cf->uhubcf_port, |
|
uaa->configno, cf->uhubcf_configuration, |
|
uaa->ifaceno, cf->uhubcf_interface, |
|
uaa->vendor, cf->uhubcf_vendor, |
|
uaa->product, cf->uhubcf_product, |
|
uaa->release, cf->uhubcf_release)); |
|
if (uaa->port != 0 && /* root hub has port 0, it should match */ |
|
((cf->uhubcf_port != UHUB_UNK_PORT && |
|
cf->uhubcf_port != uaa->port) || |
|
(uaa->configno != UHUB_UNK_CONFIGURATION && |
|
cf->uhubcf_configuration != UHUB_UNK_CONFIGURATION && |
|
cf->uhubcf_configuration != uaa->configno) || |
|
(uaa->ifaceno != UHUB_UNK_INTERFACE && |
|
cf->uhubcf_interface != UHUB_UNK_INTERFACE && |
|
cf->uhubcf_interface != uaa->ifaceno) || |
|
(uaa->vendor != UHUB_UNK_VENDOR && |
|
cf->uhubcf_vendor != UHUB_UNK_VENDOR && |
|
cf->uhubcf_vendor != uaa->vendor) || |
|
(uaa->product != UHUB_UNK_PRODUCT && |
|
cf->uhubcf_product != UHUB_UNK_PRODUCT && |
|
cf->uhubcf_product != uaa->product) || |
|
(uaa->release != UHUB_UNK_RELEASE && |
|
cf->uhubcf_release != UHUB_UNK_RELEASE && |
|
cf->uhubcf_release != uaa->release) |
|
) |
|
) |
|
return 0; |
|
return (config_match(parent, cf, aux)); |
|
} |
|
|
|
#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) |
int usedev) |
{ |
{ |
struct usbd_port *p; |
struct usbd_port *p; |
int i, err, s; |
int i, j, err, s; |
|
|
di->udi_bus = device_unit(dev->bus->usbctl); |
di->udi_bus = device_unit(dev->bus->usbctl); |
di->udi_addr = dev->address; |
di->udi_addr = dev->address; |
Line 1343 usbd_fill_deviceinfo(usbd_device_handle |
|
Line 1332 usbd_fill_deviceinfo(usbd_device_handle |
|
di->udi_power = dev->self_powered ? 0 : dev->power; |
di->udi_power = dev->self_powered ? 0 : dev->power; |
di->udi_speed = dev->speed; |
di->udi_speed = dev->speed; |
|
|
if (dev->subdevs != NULL) { |
if (dev->subdevlen > 0) { |
for (i = 0; dev->subdevs[i] && |
for (i = 0, j = 0; i < dev->subdevlen && |
i < USB_MAX_DEVNAMES; i++) { |
j < USB_MAX_DEVNAMES; i++) { |
strncpy(di->udi_devnames[i], USBDEVPTRNAME(dev->subdevs[i]), |
if (!dev->subdevs[i]) |
USB_MAX_DEVNAMELEN); |
continue; |
di->udi_devnames[i][USB_MAX_DEVNAMELEN-1] = '\0'; |
strncpy(di->udi_devnames[j], |
} |
device_xname(dev->subdevs[i]), USB_MAX_DEVNAMELEN); |
} else { |
di->udi_devnames[j][USB_MAX_DEVNAMELEN-1] = '\0'; |
i = 0; |
j++; |
} |
} |
for (/*i is set */; i < USB_MAX_DEVNAMES; i++) |
} else { |
di->udi_devnames[i][0] = 0; /* empty */ |
j = 0; |
|
} |
|
for (/* j is set */; j < USB_MAX_DEVNAMES; j++) |
|
di->udi_devnames[j][0] = 0; /* empty */ |
|
|
if (dev->hub) { |
if (dev->hub) { |
for (i = 0; |
for (i = 0; |
Line 1388 usbd_fill_deviceinfo_old(usbd_device_han |
|
Line 1380 usbd_fill_deviceinfo_old(usbd_device_han |
|
int usedev) |
int usedev) |
{ |
{ |
struct usbd_port *p; |
struct usbd_port *p; |
int i, err, s; |
int i, j, err, s; |
|
|
di->udi_bus = device_unit(dev->bus->usbctl); |
di->udi_bus = device_unit(dev->bus->usbctl); |
di->udi_addr = dev->address; |
di->udi_addr = dev->address; |
Line 1406 usbd_fill_deviceinfo_old(usbd_device_han |
|
Line 1398 usbd_fill_deviceinfo_old(usbd_device_han |
|
di->udi_power = dev->self_powered ? 0 : dev->power; |
di->udi_power = dev->self_powered ? 0 : dev->power; |
di->udi_speed = dev->speed; |
di->udi_speed = dev->speed; |
|
|
if (dev->subdevs != NULL) { |
if (dev->subdevlen > 0) { |
for (i = 0; dev->subdevs[i] && |
for (i = 0, j = 0; i < dev->subdevlen && |
i < USB_MAX_DEVNAMES; i++) { |
j < USB_MAX_DEVNAMES; i++) { |
strncpy(di->udi_devnames[i], USBDEVPTRNAME(dev->subdevs[i]), |
if (!dev->subdevs[i]) |
USB_MAX_DEVNAMELEN); |
continue; |
di->udi_devnames[i][USB_MAX_DEVNAMELEN-1] = '\0'; |
strncpy(di->udi_devnames[j], |
|
device_xname(dev->subdevs[i]), USB_MAX_DEVNAMELEN); |
|
di->udi_devnames[j][USB_MAX_DEVNAMELEN-1] = '\0'; |
|
j++; |
} |
} |
} else { |
} else { |
i = 0; |
j = 0; |
} |
} |
for (/*i is set */; i < USB_MAX_DEVNAMES; i++) |
for (/* j is set */; j < USB_MAX_DEVNAMES; j++) |
di->udi_devnames[i][0] = 0; /* empty */ |
di->udi_devnames[j][0] = 0; /* empty */ |
|
|
if (dev->hub) { |
if (dev->hub) { |
for (i = 0; |
for (i = 0; |
Line 1462 usb_free_device(usbd_device_handle dev) |
|
Line 1457 usb_free_device(usbd_device_handle dev) |
|
} |
} |
if (dev->cdesc != NULL) |
if (dev->cdesc != NULL) |
free(dev->cdesc, M_USB); |
free(dev->cdesc, M_USB); |
if (dev->subdevs != NULL) |
if (dev->subdevlen > 0) { |
free(dev->subdevs, M_USB); |
free(dev->subdevs, M_USB); |
|
dev->subdevlen = 0; |
|
} |
free(dev, M_USB); |
free(dev, M_USB); |
} |
} |
|
|
Line 1485 usb_free_device(usbd_device_handle dev) |
|
Line 1482 usb_free_device(usbd_device_handle dev) |
|
* been disconnected. |
* been disconnected. |
*/ |
*/ |
void |
void |
usb_disconnect_port(struct usbd_port *up, device_ptr_t parent) |
usb_disconnect_port(struct usbd_port *up, device_t parent) |
{ |
{ |
usbd_device_handle dev = up->device; |
usbd_device_handle dev = up->device; |
const char *hubname = USBDEVPTRNAME(parent); |
const char *hubname = device_xname(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", |
Line 1501 usb_disconnect_port(struct usbd_port *up |
|
Line 1498 usb_disconnect_port(struct usbd_port *up |
|
} |
} |
#endif |
#endif |
|
|
if (dev->subdevs != NULL) { |
if (dev->subdevlen > 0) { |
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; i < dev->subdevlen; i++) { |
printf("%s: at %s", USBDEVPTRNAME(dev->subdevs[i]), |
if (!dev->subdevs[i]) |
|
continue; |
|
printf("%s: at %s", device_xname(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); |
config_detach(dev->subdevs[i], DETACH_FORCE); |
config_detach(dev->subdevs[i], DETACH_FORCE); |
} |
} |
|
KASSERT(!dev->nifaces_claimed); |
} |
} |
|
|
usbd_add_dev_event(USB_EVENT_DEVICE_DETACH, dev); |
usbd_add_dev_event(USB_EVENT_DEVICE_DETACH, dev); |
Line 1518 usb_disconnect_port(struct usbd_port *up |
|
Line 1518 usb_disconnect_port(struct usbd_port *up |
|
up->device = NULL; |
up->device = NULL; |
usb_free_device(dev); |
usb_free_device(dev); |
} |
} |
|
|
#ifdef __OpenBSD__ |
|
void *usb_realloc(void *p, u_int size, int pool, int flags) |
|
{ |
|
void *q; |
|
|
|
q = malloc(size, pool, flags); |
|
if (q == NULL) |
|
return (NULL); |
|
bcopy(p, q, size); |
|
free(p, pool); |
|
return (q); |
|
} |
|
#endif |
|