📄 usb.c
字号:
* the USB_DEVICE macro lets you provide vendor and product IDs, * and you can also match against ranges of product revisions. * These are widely used for devices with application or vendor * specific bDeviceClass values. * * Matches based on device class/subclass/protocol specifications * are slightly more general; use the USB_DEVICE_INFO macro, or * its siblings. These are used with single-function devices * where bDeviceClass doesn't specify that each interface has * its own class. * * Matches based on interface class/subclass/protocol are the * most general; they let drivers bind to any interface on a * multiple-function device. Use the USB_INTERFACE_INFO * macro, or its siblings, to match class-per-interface style * devices (as recorded in bDeviceClass). * * Within those groups, remember that not all combinations are * meaningful. For example, don't give a product version range * without vendor and product IDs; or specify a protocol without * its associated class and subclass. */ const struct usb_device_id *usb_match_id(struct usb_device *dev, struct usb_interface *interface, const struct usb_device_id *id){ struct usb_interface_descriptor *intf = 0; /* proc_connectinfo in devio.c may call us with id == NULL. */ if (id == NULL) return NULL; /* 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; intf = &interface->altsetting [interface->act_altsetting]; if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) && (id->bInterfaceClass != intf->bInterfaceClass)) continue; if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) && (id->bInterfaceSubClass != intf->bInterfaceSubClass)) continue; if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) && (id->bInterfaceProtocol != intf->bInterfaceProtocol)) continue; return id; } return NULL;}/* * This entrypoint gets called for each new device. * * We now walk the list of registered USB drivers, * looking for one that will accept this interface. * * "New Style" drivers use a table describing the devices and interfaces * they handle. Those tables are available to user mode tools deciding * whether to load driver modules for a new device. * * The probe return value is changed to be a private pointer. This way * the drivers don't have to dig around in our structures to set the * private pointer if they only need one interface. * * Returns: 0 if a driver accepted the interface, -1 otherwise */static int usb_find_interface_driver(struct usb_device *dev, unsigned ifnum){ struct list_head *tmp; struct usb_interface *interface; void *private; const struct usb_device_id *id; struct usb_driver *driver; int i; if ((!dev) || (ifnum >= dev->actconfig->bNumInterfaces)) { err("bad find_interface_driver params"); return -1; } down(&dev->serialize); interface = dev->actconfig->interface + ifnum; if (usb_interface_claimed(interface)) goto out_err; private = NULL; for (tmp = usb_driver_list.next; tmp != &usb_driver_list;) { driver = list_entry(tmp, struct usb_driver, driver_list); tmp = tmp->next; if (driver->owner) __MOD_INC_USE_COUNT(driver->owner); id = driver->id_table; /* new style driver? */ if (id) { for (i = 0; i < interface->num_altsetting; i++) { interface->act_altsetting = i; id = usb_match_id(dev, interface, id); if (id) { down(&driver->serialize); private = driver->probe(dev,ifnum,id); up(&driver->serialize); if (private != NULL) break; } } /* if driver not bound, leave defaults unchanged */ if (private == NULL) interface->act_altsetting = 0; } else { /* "old style" driver */ down(&driver->serialize); private = driver->probe(dev, ifnum, NULL); up(&driver->serialize); } if (driver->owner) __MOD_DEC_USE_COUNT(driver->owner); /* probe() may have changed the config on us */ interface = dev->actconfig->interface + ifnum; if (private) { usb_driver_claim_interface(driver, interface, private); up(&dev->serialize); return 0; } }out_err: up(&dev->serialize); return -1;}/** * usb_find_interface_driver_for_ifnum - finds a usb interface driver for the specified ifnum * @dev: the device to use * @ifnum: the interface number (bInterfaceNumber); not interface position! * * This converts a ifnum to ifpos via a call to usb_ifnum_to_ifpos and then * calls usb_find_interface_driver() with the found ifpos. Note * usb_find_interface_driver's ifnum parameter is actually interface position. */int usb_find_interface_driver_for_ifnum(struct usb_device *dev, unsigned ifnum){ int ifpos = usb_ifnum_to_ifpos(dev, ifnum); if (0 > ifpos) return -EINVAL; return usb_find_interface_driver(dev, ifpos);}#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. * * Some synchronization is important: removes can't start processing * before the add-device processing completes, and vice versa. That keeps * a stack of USB-related identifiers stable while they're in use. If we * know that agents won't complete after they return (such as by forking * a process that completes later), it's enough to just waitpid() for the * agent -- as is currently done. * * The reason: we know we're called either from khubd (the typical case) * or from root hub initialization (init, kapmd, modprobe, etc). In both * cases, we know no other thread can recycle our address, since we must * already have been serialized enough to prevent that. */static void call_policy (char *verb, struct usb_device *dev){ char *argv [3], **envp, *buf, *scratch; int i = 0, value; if (!hotplug_path [0]) return; if (in_interrupt ()) { dbg ("In_interrupt"); return; } if (!current->fs->root) { /* statically linked USB is initted rather early */ dbg ("call_policy %s, num %d -- no FS yet", verb, dev->devnum); return; } if (dev->devnum < 0) { dbg ("device already deleted ??"); return; } if (!(envp = (char **) kmalloc (20 * sizeof (char *), GFP_KERNEL))) { dbg ("enomem"); return; } if (!(buf = kmalloc (256, GFP_KERNEL))) { kfree (envp); dbg ("enomem2"); return; } /* only one standardized param to hotplug command: type */ argv [0] = hotplug_path; argv [1] = "usb"; argv [2] = 0; /* minimal command environment */ envp [i++] = "HOME=/"; envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";#ifdef DEBUG /* hint that policy agent should enter no-stdout debug mode */ envp [i++] = "DEBUG=kernel";#endif /* extensible set of named bus-specific parameters, * supporting multiple driver selection algorithms. */ scratch = buf; /* action: add, remove */ envp [i++] = scratch; scratch += sprintf (scratch, "ACTION=%s", verb) + 1;#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++] = "DEVFS=/proc/bus/usb"; envp [i++] = scratch; scratch += sprintf (scratch, "DEVICE=/proc/bus/usb/%03d/%03d", dev->bus->busnum, dev->devnum) + 1;#endif /* per-device configuration hacks are common */ envp [i++] = scratch; scratch += sprintf (scratch, "PRODUCT=%x/%x/%x", dev->descriptor.idVendor, dev->descriptor.idProduct, dev->descriptor.bcdDevice) + 1; /* class-based driver binding models */ envp [i++] = scratch; scratch += sprintf (scratch, "TYPE=%d/%d/%d", dev->descriptor.bDeviceClass, dev->descriptor.bDeviceSubClass, dev->descriptor.bDeviceProtocol) + 1; if (dev->descriptor.bDeviceClass == 0) { int alt = dev->actconfig->interface [0].act_altsetting; /* a simple/common case: one config, one interface, one driver * with current altsetting being a reasonable setting. * everything needs a smart agent and usbfs; or can rely on * device-specific binding policies. */ envp [i++] = scratch; scratch += sprintf (scratch, "INTERFACE=%d/%d/%d", dev->actconfig->interface [0].altsetting [alt].bInterfaceClass, dev->actconfig->interface [0].altsetting [alt].bInterfaceSubClass, dev->actconfig->interface [0].altsetting [alt].bInterfaceProtocol) + 1; /* INTERFACE-0, INTERFACE-1, ... ? */ } envp [i++] = 0; /* assert: (scratch - buf) < sizeof buf */ /* NOTE: user mode daemons can call the agents too */ dbg ("kusbd: %s %s %d", argv [0], verb, dev->devnum); value = call_usermodehelper (argv [0], argv, envp); kfree (buf); kfree (envp); if (value != 0) dbg ("kusbd policy returned 0x%x", value);}#elsestatic inline voidcall_policy (char *verb, struct usb_device *dev){ } #endif /* CONFIG_HOTPLUG *//* * This entrypoint gets called for each new device. * * All interfaces are scanned for matching drivers. */static void usb_find_drivers(struct usb_device *dev){ unsigned ifnum; unsigned rejected = 0; unsigned claimed = 0; for (ifnum = 0; ifnum < dev->actconfig->bNumInterfaces; ifnum++) { struct usb_interface *interface = &dev->actconfig->interface[ifnum]; /* register this interface with driverfs */ interface->dev.parent = &dev->dev; sprintf (&interface->dev.bus_id[0], "%03d", ifnum); sprintf (&interface->dev.name[0], "figure out some name..."); device_register (&interface->dev); /* if this interface hasn't already been claimed */ if (!usb_interface_claimed(interface)) { if (usb_find_interface_driver(dev, ifnum)) rejected++; else claimed++; } } if (rejected) dbg("unhandled interfaces on device"); if (!claimed) { warn("USB device %d (vend/prod 0x%x/0x%x) is not claimed by any active driver.", dev->devnum, dev->descriptor.idVendor, dev->descriptor.idProduct);#ifdef DEBUG usb_show_device(dev);#endif }}/** * 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 *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)); usb_bus_get(bus); if (!parent) dev->devpath [0] = '/'; dev->bus = bus; dev->parent = parent; atomic_set(&dev->refcnt, 1); INIT_LIST_HEAD(&dev->filelist); init_MUTEX(&dev->serialize); dev->bus->op->allocate(dev); return dev;}/** * usb_free_dev - free a usb device structure (usbcore-internal) * @dev: device that's been disconnected * Context: !in_interrupt () * * Used by hub and virtual root hub drivers. The device is completely * gone, everything is cleaned up, so it's time to get rid of these last * records of this device. */void usb_free_dev(struct usb_device *dev){ if (in_interrupt ()) BUG (); if (!atomic_dec_and_test (&dev->refcnt)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -