📄 usb.c
字号:
*/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 searches an array of usb_device_id's and returns the first one that matches the device and interface. Parameters: "id" is an array of usb_device_id's is terminated by an entry containing all zeroes. "dev" and "interface" are the device and interface for which a match is sought. If no match is found or if the "id" pointer is NULL, then usb_match_id returns NULL. What constitutes a match: A zero in any element of a usb_device_id entry is a wildcard (i.e., that field always matches). For there to be a match, *every* nonzero element of the usb_device_id must match the provided device and interface in. The comparison is for equality, except for one pair of fields: usb_match_id.bcdDevice_{lo,hi} define an inclusive range that dev->descriptor.bcdDevice must be in. If interface->altsettings does not exist (i.e., there are no interfaces defined), then bInterface{Class,SubClass,Protocol} only match if they are all zeroes. What constitutes a good "usb_device_id"? 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: * device specifiers (vendor and product IDs; and maybe a revision range for that product); * generic device specs (class/subclass/protocol); * interface specs (class/subclass/protocol). Within those groups, work from least specific to most specific. For example, don't give a product version range without vendor and product IDs. "driver_info" is not considered by the kernel matching algorithm, but you can create a wildcard "matches anything" usb_device_id as your driver's "modules.usbmap" entry if you provide only an id with a nonzero "driver_info" field.*/ 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; } interface = dev->actconfig->interface + ifnum; if (usb_interface_claimed(interface)) return -1; private = NULL; for (tmp = usb_driver_list.next; tmp != &usb_driver_list;) { driver = list_entry(tmp, struct usb_driver, driver_list); tmp = tmp->next; down(&driver->serialize); 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) { private = driver->probe(dev,ifnum,id); if (private != NULL) break; } } /* if driver not bound, leave defaults unchanged */ if (private == NULL) interface->act_altsetting = 0; } else /* "old style" driver */ private = driver->probe(dev, ifnum, NULL); up(&driver->serialize); if (private) { usb_driver_claim_interface(driver, interface, private); return 0; } } 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 /* KMOD *//* * 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)); dev->bus = bus; dev->parent = parent; atomic_set(&dev->refcnt, 1); INIT_LIST_HEAD(&dev->inodes); INIT_LIST_HEAD(&dev->filelist); dev->bus->op->allocate(dev); return dev;}void usb_free_dev(struct usb_device *dev){ if (atomic_dec_and_test(&dev->refcnt)) { dev->bus->op->deallocate(dev); usb_destroy_configuration(dev); kfree(dev); }}void usb_inc_dev_use(struct usb_device *dev){ atomic_inc(&dev->refcnt);}/* ------------------------------------------------------------------------------------- * New USB Core Functions * -------------------------------------------------------------------------------------*//** * usb_alloc_urb - creates a new urb for a USB driver to use * @iso_packets: number of iso packets for this urb * * Creates an urb for the USB driver to use and returns a pointer to it. * If no memory is available, NULL is returned. * * If the driver want to use this urb for interrupt, control, or bulk * endpoints, pass '0' as the number of iso packets. * * The driver should call usb_free_urb() when it is finished with the urb. */urb_t *usb_alloc_urb(int iso_packets){ urb_t *urb; urb = (urb_t *)kmalloc(sizeof(urb_t) + iso_packets * sizeof(iso_packet_descriptor_t), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); if (!urb) { err("alloc_urb: kmalloc failed"); return NULL; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -