📄 usb.c
字号:
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; if (!dev) return -ENODEV; /* driver is often null here; dev_dbg() would oops */ pr_debug ("usb %s: hotplug\n", dev->bus_id); /* 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) { pr_debug ("usb %s: already deleted?\n", dev->bus_id); return -ENODEV; } if (!usb_dev->bus) { pr_debug ("usb %s: bus removed?\n", dev->bus_id); 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) { struct usb_host_interface *alt = intf->cur_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", alt->desc.bInterfaceClass, alt->desc.bInterfaceSubClass, alt->desc.bInterfaceProtocol); if ((buffer_size - length <= 0) || (i >= num_envp)) return -ENOMEM; ++length; scratch += length; } envp[i++] = NULL; return 0;}#elsestatic int usb_hotplug (struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size){ return -ENODEV;}#endif /* CONFIG_HOTPLUG *//** * 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);}/** * usb_alloc_dev - usb device constructor (usbcore-internal) * @parent: hub to which device is connected; null to allocate a root hub * @bus: bus used to access the device * @port: zero based index of port; ignored for root hubs * Context: !in_interrupt () * * Only hub drivers (including virtual root hub drivers for host * controllers) should ever call this. * * This call may not be used in a non-sleeping context. */struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port){ struct usb_device *dev; dev = kmalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return NULL; memset(dev, 0, sizeof(*dev)); bus = usb_bus_get(bus); if (!bus) { kfree(dev); return NULL; } device_initialize(&dev->dev); dev->dev.bus = &usb_bus_type; dev->dev.dma_mask = bus->controller->dma_mask; dev->dev.driver_data = &usb_generic_driver_data; dev->dev.driver = &usb_generic_driver; dev->dev.release = usb_release_dev; dev->state = USB_STATE_ATTACHED; /* Save readable and stable topology id, distinguishing devices * by location for diagnostics, tools, driver model, etc. The * string is a path along hub ports, from the root. Each device's * dev->devpath will be stable until USB is re-cabled, and hubs * are often labeled with these port numbers. The bus_id isn't * as stable: bus->busnum changes easily from modprobe order, * cardbus or pci hotplugging, and so on. */ if (unlikely (!parent)) { dev->devpath [0] = '0'; dev->dev.parent = bus->controller; sprintf (&dev->dev.bus_id[0], "usb%d", bus->busnum); } else { /* match any labeling on the hubs; it's one-based */ if (parent->devpath [0] == '0') snprintf (dev->devpath, sizeof dev->devpath, "%d", port + 1); else snprintf (dev->devpath, sizeof dev->devpath, "%s.%d", parent->devpath, port + 1); dev->dev.parent = &parent->dev; sprintf (&dev->dev.bus_id[0], "%d-%s", bus->busnum, dev->devpath); /* hub driver sets up TT records */ } 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 *usb_get_dev(struct usb_device *dev){ if (dev) get_device(&dev->dev); return dev;}/** * 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 usb_put_dev(struct usb_device *dev){ if (dev) put_device(&dev->dev);}/** * usb_get_intf - increments the reference count of the usb interface structure * @intf: the interface being referenced * * Each live reference to a interface must 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_intf(), in their disconnect() methods. * * A pointer to the interface with the incremented reference counter is * returned. */struct usb_interface *usb_get_intf(struct usb_interface *intf){ if (intf) get_device(&intf->dev); return intf;}/** * usb_put_intf - release a use of the usb interface structure * @intf: interface that's been decremented * * Must be called when a user of an interface is finished with it. When the * last user of the interface calls this function, the memory of the interface * is freed. */void usb_put_intf(struct usb_interface *intf){ if (intf) put_device(&intf->dev);}static struct usb_device *match_device(struct usb_device *dev, u16 vendor_id, u16 product_id){ struct usb_device *ret_dev = NULL; int child; dev_dbg(&dev->dev, "check for vendor %04x, product %04x ...\n", dev->descriptor.idVendor, dev->descriptor.idProduct); /* see if this device matches */ if ((dev->descriptor.idVendor == vendor_id) && (dev->descriptor.idProduct == product_id)) { dev_dbg (&dev->dev, "matched this device!\n"); 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); if (!bus->root_hub) continue; 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 * @dev: the device whose bus is being queried * * Returns the current frame number for the USB host controller * used with the given USB device. This can be used when scheduling * isochronous requests. * * Note that different kinds of host controller have different * "scheduling horizons". While one type might support scheduling only * 32 frames into the future, others could support scheduling up to * 1024 frames into the future. */int usb_get_current_frame_number(struct usb_device *dev){ return dev->bus->op->get_frame_number (dev);}/*-------------------------------------------------------------------*//* * __usb_get_extra_descriptor() finds a descriptor of specific type in the * extra field of the interface and endpoint descriptor structs. */int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr){ struct usb_descriptor_header *header; while (size >= sizeof(struct usb_descriptor_header)) { header = (struct usb_descriptor_header *)buffer; if (header->bLength < 2) { printk(KERN_ERR "%s: bogus descriptor, type %d length %d\n", usbcore_name, header->bDescriptorType, header->bLength); return -1; } if (header->bDescriptorType == type) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -