📄 usb.c
字号:
static void usb_check_support(struct usb_device *dev){ int i; if (!dev) { err("null device being checked!!!"); return; } for (i=0; i<USB_MAXCHILDREN; i++) if (dev->children[i]) usb_check_support(dev->children[i]); if (!dev->actconfig) return; /* now we check this device */ if (dev->devnum > 0) for (i = 0; i < dev->actconfig->bNumInterfaces; i++) usb_find_interface_driver(dev, i);}/* * This is intended to be used by usb device drivers that need to * claim more than one interface on a device at once when probing * (audio and acm are good examples). No device driver should have * to mess with the internal usb_interface or usb_device structure * members. */void usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv){ if (!iface || !driver) return; dbg("%s driver claimed interface %p", driver->name, iface); iface->driver = driver; iface->private_data = priv;} /* usb_driver_claim_interface() *//* * This should be used by drivers to check other interfaces to see if * they are available or not. */int usb_interface_claimed(struct usb_interface *iface){ if (!iface) return 0; return (iface->driver != NULL);} /* usb_interface_claimed() *//* * This should be used by drivers to release their claimed interfaces */void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface){ /* this should never happen, don't release something that's not ours */ if (!iface || iface->driver != driver) return; iface->driver = NULL; iface->private_data = NULL;}/** * usb_match_id - find first usb_device_id matching device or interface * @dev: the device whose descriptors are considered when matching * @interface: the interface of interest * @id: array of usb_device_id structures, terminated by zero entry * * usb_match_id searches an array of usb_device_id's and returns * the first one matching the device or interface, or null. * This is used when binding (or rebinding) a driver to an interface. * Most USB device drivers will use this indirectly, through the usb core, * but some layered driver frameworks use it directly. * These device tables are exported with MODULE_DEVICE_TABLE, through * modutils and "modules.usbmap", to support the driver loading * functionality of USB hotplugging. * * What Matches: * * The "match_flags" element in a usb_device_id controls which * members are used. If the corresponding bit is set, the * value in the device_id must match its corresponding member * in the device or interface descriptor, or else the device_id * does not match. * * "driver_info" is normally used only by device drivers, * but you can create a wildcard "matches anything" usb_device_id * as a driver's "modules.usbmap" entry if you provide an id with * only a nonzero "driver_info" field. If you do this, the USB device * driver's probe() routine should use additional intelligence to * decide whether to bind to the specified interface. * * What Makes Good usb_device_id Tables: * * The match algorithm is very simple, so that intelligence in * driver selection must come from smart driver id records. * Unless you have good reasons to use another selection policy, * provide match elements only in related groups, and order match * specifiers from specific to general. Use the macros provided * for that purpose if you can. * * The most specific match specifiers use device descriptor * data. These are commonly used with product-specific matches; * 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; 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); } /* 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;}#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 usbdevfs; 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++) { /* if this interface hasn't already been claimed */ if (!usb_interface_claimed(dev->actconfig->interface + ifnum)) { 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 }}/* * Only HC's should call usb_alloc_dev and usb_free_dev directly * Anybody may use usb_inc_dev_use or usb_dec_dev_use */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); dev->bus = bus; dev->parent = parent; atomic_set(&dev->refcnt, 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -