⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usb.c

📁 linux core 函数例程
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 * 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 + -