📄 usb.c
字号:
/*
* drivers/usb/usb.c
*
* (C) Copyright Linus Torvalds 1999
* (C) Copyright Johannes Erdfelt 1999-2001
* (C) Copyright Andreas Gal 1999
* (C) Copyright Gregory P. Smith 1999
* (C) Copyright Deti Fliegl 1999 (new USB architecture)
* (C) Copyright Randy Dunlap 2000
* (C) Copyright David Brownell 2000-2001 (kernel hotplug, usb_device_id,
more docs, etc)
* (C) Copyright Yggdrasil Computing, Inc. 2000
* (usb_device_id matching changes by Adam J. Richter)
* (C) Copyright Greg Kroah-Hartman 2002
*
* NOTE! This is not actually a driver at all, rather this is
* just a collection of helper routines that implement the
* generic USB things that the real drivers can use..
*
* Think of this as a "USB library" rather than anything else.
* It should be considered a slave, with no callbacks. Callbacks
* are evil.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/bitops.h>
#include <linux/slab.h>
#include <linux/interrupt.h> /* for in_interrupt() */
#include <linux/kmod.h>
#include <linux/init.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <asm/byteorder.h>
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
#include <linux/usb.h>
#include "hcd.h"
extern int usb_hub_init(void);
extern void usb_hub_cleanup(void);
/*
* Prototypes for the device driver probing/loading functions
*/
static void usb_find_drivers(struct usb_device *);
static int usb_find_interface_driver(struct usb_device *, unsigned int);
static void usb_check_support(struct usb_device *);
/*
* We have a per-interface "registered driver" list.
*/
LIST_HEAD(usb_driver_list);
devfs_handle_t usb_devfs_handle; /* /dev/usb dir. */
#define MAX_USB_MINORS 256
static struct usb_driver *usb_minors[MAX_USB_MINORS];
static spinlock_t minor_lock = SPIN_LOCK_UNLOCKED;
static int usb_register_minors (struct usb_driver *driver, int num_minors, int start_minor)
{
int i;
dbg("registering %d minors, starting at %d", num_minors, start_minor);
if (start_minor + num_minors >= MAX_USB_MINORS)
return -EINVAL;
spin_lock (&minor_lock);
for (i = start_minor; i < (start_minor + num_minors); ++i)
if (usb_minors[i]) {
spin_unlock (&minor_lock);
err("minor %d is already in use, error registering %s driver",
i, driver->name);
return -EINVAL;
}
for (i = start_minor; i < (start_minor + num_minors); ++i)
usb_minors[i] = driver;
spin_unlock (&minor_lock);
return 0;
}
static void usb_deregister_minors (struct usb_driver *driver, int num_minors, int start_minor)
{
int i;
dbg ("%s is removing %d minors starting at %d", driver->name,
num_minors, start_minor);
spin_lock (&minor_lock);
for (i = start_minor; i < (start_minor + num_minors); ++i)
usb_minors[i] = NULL;
spin_unlock (&minor_lock);
}
/**
* usb_register - register a USB driver
* @new_driver: USB operations for the driver
*
* Registers a USB driver with the USB core. The list of unattached
* interfaces will be rescanned whenever a new driver is added, allowing
* the new driver to attach to any recognized devices.
* Returns a negative error code on failure and 0 on success.
*/
int usb_register(struct usb_driver *new_driver)
{
int retval = 0;
if ((new_driver->fops) && (new_driver->num_minors == 0)) {
err ("%s driver must specify num_minors", new_driver->name);
return -EINVAL;
}
#ifndef CONFIG_USB_DYNAMIC_MINORS
if (new_driver->fops != NULL) {
retval = usb_register_minors (new_driver, new_driver->num_minors, new_driver->minor);
if (retval)
return retval;
}
#endif
info("registered new driver %s", new_driver->name);
init_MUTEX(&new_driver->serialize);
/* Add it to the list of known drivers */
list_add_tail(&new_driver->driver_list, &usb_driver_list);
usb_scan_devices();
usbfs_update_special();
return retval;
}
/**
* usb_register_dev - register a USB device, and ask for a minor number
* @new_driver: USB operations for the driver
* @num_minors: number of minor numbers requested for this device
* @start_minor: place to put the new starting minor number
*
* Used to ask the USB core for a new minor number for a device that has
* just showed up. This is used to dynamically allocate minor numbers
* from the pool of USB reserved minor numbers.
*
* This should be called by all drivers that use the USB major number.
* This only returns a good value of CONFIG_USB_DYNAMIC_MINORS is
* selected by the user.
*
* usb_deregister_dev() should be called when the driver is done with
* the minor numbers given out by this function.
*
* Returns -ENODEV if CONFIG_USB_DYNAMIC_MINORS is not enabled in this
* kernel, -EINVAL if something bad happens with trying to register a
* device, and 0 on success, alone with a value that the driver should
* use in start_minor.
*/
#ifdef CONFIG_USB_DYNAMIC_MINORS
int usb_register_dev (struct usb_driver *new_driver, int num_minors, int *start_minor)
{
int i;
int j;
int good_spot;
int retval = -EINVAL;
dbg ("%s is asking for %d minors", new_driver->name, num_minors);
if (new_driver->fops == NULL)
goto exit;
*start_minor = 0;
spin_lock (&minor_lock);
for (i = 0; i < MAX_USB_MINORS; ++i) {
if (usb_minors[i])
continue;
good_spot = 1;
for (j = 1; j <= num_minors-1; ++j)
if (usb_minors[i+j]) {
good_spot = 0;
break;
}
if (good_spot == 0)
continue;
*start_minor = i;
spin_unlock (&minor_lock);
retval = usb_register_minors (new_driver, num_minors, *start_minor);
if (retval) {
/* someone snuck in here, so let's start looking all over again */
spin_lock (&minor_lock);
i = 0;
continue;
}
goto exit;
}
spin_unlock (&minor_lock);
exit:
return retval;
}
/**
* usb_deregister_dev - deregister a USB device's dynamic minor.
* @driver: USB operations for the driver
* @num_minors: number of minor numbers to put back.
* @start_minor: the starting minor number
*
* Used in conjunction with usb_register_dev(). This function is called
* when the USB driver is finished with the minor numbers gotten from a
* call to usb_register_dev() (usually when the device is disconnected
* from the system.)
*
* This should be called by all drivers that use the USB major number.
*/
void usb_deregister_dev (struct usb_driver *driver, int num_minors, int start_minor)
{
usb_deregister_minors (driver, num_minors, start_minor);
}
#endif /* CONFIG_USB_DYNAMIC_MINORS */
/**
* usb_scan_devices - scans all unclaimed USB interfaces
* Context: !in_interrupt ()
*
* Goes through all unclaimed USB interfaces, and offers them to all
* registered USB drivers through the 'probe' function.
* This will automatically be called after usb_register is called.
* It is called by some of the subsystems layered over USB
* after one of their subdrivers are registered.
*/
void usb_scan_devices(void)
{
struct list_head *tmp;
down (&usb_bus_list_lock);
tmp = usb_bus_list.next;
while (tmp != &usb_bus_list) {
struct usb_bus *bus = list_entry(tmp,struct usb_bus, bus_list);
tmp = tmp->next;
usb_check_support(bus->root_hub);
}
up (&usb_bus_list_lock);
}
/*
* This function is part of a depth-first search down the device tree,
* removing any instances of a device driver.
*/
static void usb_drivers_purge(struct usb_driver *driver,struct usb_device *dev)
{
int i;
if (!dev) {
err("null device being purged!!!");
return;
}
for (i=0; i<USB_MAXCHILDREN; i++)
if (dev->children[i])
usb_drivers_purge(driver, dev->children[i]);
if (!dev->actconfig)
return;
for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
struct usb_interface *interface = &dev->actconfig->interface[i];
if (interface->driver == driver) {
if (driver->owner)
__MOD_INC_USE_COUNT(driver->owner);
down(&driver->serialize);
driver->disconnect(dev, interface->private_data);
up(&driver->serialize);
if (driver->owner)
__MOD_DEC_USE_COUNT(driver->owner);
/* if driver->disconnect didn't release the interface */
if (interface->driver)
usb_driver_release_interface(driver, interface);
/*
* This will go through the list looking for another
* driver that can handle the device
*/
usb_find_interface_driver(dev, i);
}
}
}
/**
* usb_deregister - unregister a USB driver
* @driver: USB operations of the driver to unregister
* Context: !in_interrupt ()
*
* Unlinks the specified driver from the internal USB driver list.
*/
void usb_deregister(struct usb_driver *driver)
{
struct list_head *tmp;
info("deregistering driver %s", driver->name);
#ifndef CONFIG_USB_DYNAMIC_MINORS
if (driver->fops != NULL)
usb_deregister_minors (driver, driver->num_minors, driver->minor);
#endif
/*
* first we remove the driver, to be sure it doesn't get used by
* another thread while we are stepping through removing entries
*/
list_del(&driver->driver_list);
down (&usb_bus_list_lock);
tmp = usb_bus_list.next;
while (tmp != &usb_bus_list) {
struct usb_bus *bus = list_entry(tmp,struct usb_bus,bus_list);
tmp = tmp->next;
usb_drivers_purge(driver, bus->root_hub);
}
up (&usb_bus_list_lock);
usbfs_update_special();
}
/**
* usb_ifnum_to_ifpos - convert the interface number to the interface position
* @dev: the device to use
* @ifnum: the interface number (bInterfaceNumber); not interface position
*
* This is used to convert the interface _number_ (as in
* interface.bInterfaceNumber) to the interface _position_ (as in
* dev->actconfig->interface + position). Note that the number is the same as
* the position for all interfaces _except_ devices with interfaces not
* sequentially numbered (e.g., 0, 2, 3, etc).
*/
int usb_ifnum_to_ifpos(struct usb_device *dev, unsigned ifnum)
{
int i;
for (i = 0; i < dev->actconfig->bNumInterfaces; i++)
if (dev->actconfig->interface[i].altsetting[0].bInterfaceNumber == ifnum)
return i;
return -EINVAL;
}
/**
* usb_ifnum_to_if - get the interface object with a given interface number
* @dev: the device whose current configuration is considered
* @ifnum: the desired interface
*
* This walks the device descriptor for the currently active configuration
* and returns a pointer to the interface with that particular interface
* number, or null.
*
* Note that configuration descriptors are not required to assign interface
* numbers sequentially, so that it would be incorrect to assume that
* the first interface in that descriptor corresponds to interface zero.
* This routine helps device drivers avoid such mistakes.
* However, you should make sure that you do the right thing with any
* alternate settings available for this interfaces.
*/
struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
{
int i;
for (i = 0; i < dev->actconfig->bNumInterfaces; i++)
if (dev->actconfig->interface[i].altsetting[0].bInterfaceNumber == ifnum)
return &dev->actconfig->interface[i];
return NULL;
}
/**
* usb_epnum_to_ep_desc - get the endpoint object with a given endpoint number
* @dev: the device whose current configuration is considered
* @epnum: the desired endpoint
*
* This walks the device descriptor for the currently active configuration,
* and returns a pointer to the endpoint with that particular endpoint
* number, or null.
*
* Note that interface descriptors are not required to assign endpont
* numbers sequentially, so that it would be incorrect to assume that
* the first endpoint in that descriptor corresponds to interface zero.
* This routine helps device drivers avoid such mistakes.
*/
struct usb_endpoint_descriptor *usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum)
{
int i, j, k;
for (i = 0; i < dev->actconfig->bNumInterfaces; i++)
for (j = 0; j < dev->actconfig->interface[i].num_altsetting; j++)
for (k = 0; k < dev->actconfig->interface[i].altsetting[j].bNumEndpoints; k++)
if (epnum == dev->actconfig->interface[i].altsetting[j].endpoint[k].bEndpointAddress)
return &dev->actconfig->interface[i].altsetting[j].endpoint[k];
return NULL;
}
/*
* This function is for doing a depth-first search for devices which
* have support, for dynamic loading of driver modules.
*/
static void usb_check_support(struct usb_device *dev)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -