📄 usb.c
字号:
/* proc_connectinfo in devio.c may call us with id == NULL. */
if (id == NULL)
return NULL;
intf = &interface->altsetting [interface->act_altsetting];
dev = interface_to_usbdev(interface);
/* It is important to check that id->driver_info is nonzero,
since an entry that is all zeroes except for a nonzero
id->driver_info is the way to create an entry that
indicates that the driver want to examine every
device and interface. */
for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass ||
id->driver_info; id++) {
if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
id->idVendor != dev->descriptor.idVendor)
continue;
if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
id->idProduct != dev->descriptor.idProduct)
continue;
/* No need to test id->bcdDevice_lo != 0, since 0 is never
greater than any unsigned number. */
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
(id->bcdDevice_lo > dev->descriptor.bcdDevice))
continue;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
(id->bcdDevice_hi < dev->descriptor.bcdDevice))
continue;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
(id->bDeviceClass != dev->descriptor.bDeviceClass))
continue;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
(id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass))
continue;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
(id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
continue;
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
(id->bInterfaceClass != intf->desc.bInterfaceClass))
continue;
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&
(id->bInterfaceSubClass != intf->desc.bInterfaceSubClass))
continue;
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&
(id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))
continue;
return id;
}
return NULL;
}
/**
* usb_find_interface - find usb_interface pointer for driver and device
* @drv: the driver whose current configuration is considered
* @minor: the minor number of the desired device
*
* This walks the driver device list and returns a pointer to the interface
* with the matching minor. Note, this only works for devices that share the
* USB major number.
*/
struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
{
struct list_head *entry;
struct device *dev;
struct usb_interface *intf;
list_for_each(entry, &drv->driver.devices) {
dev = container_of(entry, struct device, driver_list);
/* can't look at usb devices, only interfaces */
if (dev->driver == &usb_generic_driver)
continue;
intf = to_usb_interface(dev);
if (intf->minor == -1)
continue;
if (intf->minor == minor)
return intf;
}
/* no device found that matches */
return NULL;
}
static int usb_device_match (struct device *dev, struct device_driver *drv)
{
struct usb_interface *intf;
struct usb_driver *usb_drv;
const struct usb_device_id *id;
/* check for generic driver, which we don't match any device with */
if (drv == &usb_generic_driver)
return 0;
intf = to_usb_interface(dev);
usb_drv = to_usb_driver(drv);
id = usb_drv->id_table;
id = usb_match_id (intf, usb_drv->id_table);
if (id)
return 1;
return 0;
}
#ifdef CONFIG_HOTPLUG
/*
* USB hotplugging invokes what /proc/sys/kernel/hotplug says
* (normally /sbin/hotplug) when USB devices get added or removed.
*
* This invokes a user mode policy agent, typically helping to load driver
* or other modules, configure the device, and more. Drivers can provide
* a MODULE_DEVICE_TABLE to help with module loading subtasks.
*
* We're called either from khubd (the typical case) or from root hub
* (init, kapmd, modprobe, rmmod, etc), but the agents need to handle
* delays in event delivery. Use sysfs (and DEVPATH) to make sure the
* device (and this configuration!) are still present.
*/
static int usb_hotplug (struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
{
struct usb_interface *intf;
struct usb_device *usb_dev;
char *scratch;
int i = 0;
int length = 0;
dbg ("%s", __FUNCTION__);
if (!dev)
return -ENODEV;
/* Must check driver_data here, as on remove driver is always NULL */
if ((dev->driver == &usb_generic_driver) ||
(dev->driver_data == &usb_generic_driver_data))
return 0;
intf = to_usb_interface(dev);
usb_dev = interface_to_usbdev (intf);
if (usb_dev->devnum < 0) {
dbg ("device already deleted ??");
return -ENODEV;
}
if (!usb_dev->bus) {
dbg ("bus already removed?");
return -ENODEV;
}
scratch = buffer;
#ifdef CONFIG_USB_DEVICEFS
/* If this is available, userspace programs can directly read
* all the device descriptors we don't tell them about. Or
* even act as usermode drivers.
*
* FIXME reduce hardwired intelligence here
*/
envp [i++] = scratch;
length += snprintf (scratch, buffer_size - length,
"DEVICE=/proc/bus/usb/%03d/%03d",
usb_dev->bus->busnum, usb_dev->devnum);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
#endif
/* per-device configurations are common */
envp [i++] = scratch;
length += snprintf (scratch, buffer_size - length, "PRODUCT=%x/%x/%x",
usb_dev->descriptor.idVendor,
usb_dev->descriptor.idProduct,
usb_dev->descriptor.bcdDevice);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
/* class-based driver binding models */
envp [i++] = scratch;
length += snprintf (scratch, buffer_size - length, "TYPE=%d/%d/%d",
usb_dev->descriptor.bDeviceClass,
usb_dev->descriptor.bDeviceSubClass,
usb_dev->descriptor.bDeviceProtocol);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
if (usb_dev->descriptor.bDeviceClass == 0) {
int alt = intf->act_altsetting;
/* 2.4 only exposed interface zero. in 2.5, hotplug
* agents are called for all interfaces, and can use
* $DEVPATH/bInterfaceNumber if necessary.
*/
envp [i++] = scratch;
length += snprintf (scratch, buffer_size - length,
"INTERFACE=%d/%d/%d",
intf->altsetting[alt].desc.bInterfaceClass,
intf->altsetting[alt].desc.bInterfaceSubClass,
intf->altsetting[alt].desc.bInterfaceProtocol);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
}
envp [i++] = 0;
return 0;
}
#else
static int usb_hotplug (struct device *dev, char **envp,
int num_envp, char *buffer, int buffer_size)
{
return -ENODEV;
}
#endif /* CONFIG_HOTPLUG */
/**
* usb_alloc_dev - allocate a usb device structure (usbcore-internal)
* @parent: hub to which device is connected
* @bus: bus used to access the device
* Context: !in_interrupt ()
*
* Only hub drivers (including virtual root hub drivers for host
* controllers) should ever call this.
*
* This call is synchronous, and may not be used in an interrupt context.
*/
struct usb_device STDCALL *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus)
{
struct usb_device *dev;
dev = kmalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return NULL;
memset(dev, 0, sizeof(*dev));
device_initialize(&dev->dev);
dev->state = USB_STATE_ATTACHED;
usb_bus_get(bus);
if (!parent)
dev->devpath [0] = '0';
dev->bus = bus;
dev->parent = parent;
INIT_LIST_HEAD(&dev->filelist);
init_MUTEX(&dev->serialize);
if (dev->bus->op->allocate)
dev->bus->op->allocate(dev);
return dev;
}
/**
* usb_get_dev - increments the reference count of the usb device structure
* @dev: the device being referenced
*
* Each live reference to a device should be refcounted.
*
* Drivers for USB interfaces should normally record such references in
* their probe() methods, when they bind to an interface, and release
* them by calling usb_put_dev(), in their disconnect() methods.
*
* A pointer to the device with the incremented reference counter is returned.
*/
struct usb_device STDCALL *usb_get_dev (struct usb_device *dev)
{
struct device *tmp;
if (!dev)
return NULL;
tmp = get_device(&dev->dev);
if (tmp)
return to_usb_device(tmp);
else
return NULL;
}
/**
* usb_put_dev - release a use of the usb device structure
* @dev: device that's been disconnected
*
* Must be called when a user of a device is finished with it. When the last
* user of the device calls this function, the memory of the device is freed.
*/
void STDCALL usb_put_dev(struct usb_device *dev)
{
if (dev)
put_device(&dev->dev);
}
/**
* usb_release_dev - free a usb device structure when all users of it are finished.
* @dev: device that's been disconnected
*
* Will be called only by the device core when all users of this usb device are
* done.
*/
static void usb_release_dev(struct device *dev)
{
struct usb_device *udev;
udev = to_usb_device(dev);
if (udev->bus && udev->bus->op && udev->bus->op->deallocate)
udev->bus->op->deallocate(udev);
usb_destroy_configuration (udev);
usb_bus_put (udev->bus);
kfree (udev);
}
static struct usb_device *match_device(struct usb_device *dev,
u16 vendor_id, u16 product_id)
{
struct usb_device *ret_dev = NULL;
int child;
dbg("looking at vendor %d, product %d",
dev->descriptor.idVendor,
dev->descriptor.idProduct);
/* see if this device matches */
if ((dev->descriptor.idVendor == vendor_id) &&
(dev->descriptor.idProduct == product_id)) {
dbg ("found the device!");
ret_dev = usb_get_dev(dev);
goto exit;
}
/* look through all of the children of this device */
for (child = 0; child < dev->maxchild; ++child) {
if (dev->children[child]) {
ret_dev = match_device(dev->children[child],
vendor_id, product_id);
if (ret_dev)
goto exit;
}
}
exit:
return ret_dev;
}
/**
* usb_find_device - find a specific usb device in the system
* @vendor_id: the vendor id of the device to find
* @product_id: the product id of the device to find
*
* Returns a pointer to a struct usb_device if such a specified usb
* device is present in the system currently. The usage count of the
* device will be incremented if a device is found. Make sure to call
* usb_put_dev() when the caller is finished with the device.
*
* If a device with the specified vendor and product id is not found,
* NULL is returned.
*/
struct usb_device *usb_find_device(u16 vendor_id, u16 product_id)
{
struct list_head *buslist;
struct usb_bus *bus;
struct usb_device *dev = NULL;
down(&usb_bus_list_lock);
for (buslist = usb_bus_list.next;
buslist != &usb_bus_list;
buslist = buslist->next) {
bus = container_of(buslist, struct usb_bus, bus_list);
dev = match_device(bus->root_hub, vendor_id, product_id);
if (dev)
goto exit;
}
exit:
up(&usb_bus_list_lock);
return dev;
}
/**
* usb_get_current_frame_number - return current bus frame number
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -