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

📄 usb.c

📁 基于S3CEB2410平台LINUX操作系统下 USB驱动源代码
💻 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 (kernel hotplug, usb_device_id) * (C) Copyright Yggdrasil Computing, Inc. 2000 *     (usb_device_id matching changes by Adam J. Richter) * * 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>#ifdef CONFIG_USB_DEBUG	#define DEBUG#else	#undef DEBUG#endif#include <linux/usb.h>static const int usb_bandwidth_option =#ifdef CONFIG_USB_BANDWIDTH				1;#else				0;#endifextern 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);LIST_HEAD(usb_bus_list);struct semaphore usb_bus_list_lock;devfs_handle_t usb_devfs_handle;	/* /dev/usb dir. */static struct usb_busmap busmap;static struct usb_driver *usb_minors[16];/** *	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){	if (new_driver->fops != NULL) {		if (usb_minors[new_driver->minor/16]) {			 err("error registering %s driver", new_driver->name);			return -EINVAL;		}		usb_minors[new_driver->minor/16] = new_driver;	}	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();	return 0;}/** *	usb_scan_devices - scans all unclaimed USB interfaces * *	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 USB subsystems 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) {			down(&driver->serialize);			driver->disconnect(dev, interface->private_data);			up(&driver->serialize);			/* 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 * *	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);	if (driver->fops != NULL)		usb_minors[driver->minor/16] = NULL;	/*	 * 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);}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;}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;}/* * usb_calc_bus_time: * * returns (approximate) USB bus time in nanoseconds for a USB transaction. */static long usb_calc_bus_time (int low_speed, int input_dir, int isoc, int bytecount){	unsigned long	tmp;	if (low_speed)		/* no isoc. here */	{		if (input_dir)		{			tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L;			return (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);		}		else		{			tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L;			return (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);		}	}	/* for full-speed: */	if (!isoc)		/* Input or Output */	{		tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;		return (9107L + BW_HOST_DELAY + tmp);	} /* end not Isoc */	/* for isoc: */	tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;	return (((input_dir) ? 7268L : 6265L) + BW_HOST_DELAY + tmp);}/* * usb_check_bandwidth(): * * old_alloc is from host_controller->bandwidth_allocated in microseconds; * bustime is from calc_bus_time(), but converted to microseconds. * * returns <bustime in us> if successful, * or USB_ST_BANDWIDTH_ERROR if bandwidth request fails. * * FIXME: * This initial implementation does not use Endpoint.bInterval * in managing bandwidth allocation. * It probably needs to be expanded to use Endpoint.bInterval. * This can be done as a later enhancement (correction). * This will also probably require some kind of * frame allocation tracking...meaning, for example, * that if multiple drivers request interrupts every 10 USB frames, * they don't all have to be allocated at * frame numbers N, N+10, N+20, etc.  Some of them could be at * N+11, N+21, N+31, etc., and others at * N+12, N+22, N+32, etc. * However, this first cut at USB bandwidth allocation does not * contain any frame allocation tracking. */int usb_check_bandwidth (struct usb_device *dev, struct urb *urb){	int		new_alloc;	int		old_alloc = dev->bus->bandwidth_allocated;	unsigned int	pipe = urb->pipe;	long		bustime;	bustime = usb_calc_bus_time (usb_pipeslow(pipe), usb_pipein(pipe),			usb_pipeisoc(pipe), usb_maxpacket(dev, pipe, usb_pipeout(pipe)));	if (usb_pipeisoc(pipe))		bustime = NS_TO_US(bustime) / urb->number_of_packets;	else		bustime = NS_TO_US(bustime);	new_alloc = old_alloc + (int)bustime;		/* what new total allocated bus time would be */	if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC)		dbg("usb-check-bandwidth %sFAILED: was %u, would be %u, bustime = %ld us",			usb_bandwidth_option ? "" : "would have ",			old_alloc, new_alloc, bustime);	if (!usb_bandwidth_option)	/* don't enforce it */		return (bustime);	return (new_alloc <= FRAME_TIME_MAX_USECS_ALLOC) ? bustime : USB_ST_BANDWIDTH_ERROR;}void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc){	dev->bus->bandwidth_allocated += bustime;	if (isoc)		dev->bus->bandwidth_isoc_reqs++;	else		dev->bus->bandwidth_int_reqs++;	urb->bandwidth = bustime;#ifdef USB_BANDWIDTH_MESSAGES	dbg("bandwidth alloc increased by %d to %d for %d requesters",		bustime,		dev->bus->bandwidth_allocated,		dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);#endif}/* * usb_release_bandwidth(): * * called to release a pipe's bandwidth (in microseconds) */void usb_release_bandwidth(struct usb_device *dev, struct urb *urb, int isoc){	dev->bus->bandwidth_allocated -= urb->bandwidth;	if (isoc)		dev->bus->bandwidth_isoc_reqs--;	else		dev->bus->bandwidth_int_reqs--;#ifdef USB_BANDWIDTH_MESSAGES	dbg("bandwidth alloc reduced by %d to %d for %d requesters",		urb->bandwidth,		dev->bus->bandwidth_allocated,		dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);#endif	urb->bandwidth = 0;}static void usb_bus_get(struct usb_bus *bus){	atomic_inc(&bus->refcnt);}static void usb_bus_put(struct usb_bus *bus){	if (atomic_dec_and_test(&bus->refcnt))		kfree(bus);}/** *	usb_alloc_bus - creates a new USB host controller structure *	@op: pointer to a struct usb_operations that this bus structure should use * *	Creates a USB host controller bus structure with the specified  *	usb_operations and initializes all the necessary internal objects. *	(For use only by USB Host Controller Drivers.) * *	If no memory is available, NULL is returned. * *	The caller should call usb_free_bus() when it is finished with the structure. */struct usb_bus *usb_alloc_bus(struct usb_operations *op){	struct usb_bus *bus;	bus = kmalloc(sizeof(*bus), GFP_KERNEL);	if (!bus)		return NULL;	memset(&bus->devmap, 0, sizeof(struct usb_devmap));#ifdef DEVNUM_ROUND_ROBIN	bus->devnum_next = 1;#endif /* DEVNUM_ROUND_ROBIN */	bus->op = op;	bus->root_hub = NULL;	bus->hcpriv = NULL;	bus->busnum = -1;	bus->bandwidth_allocated = 0;	bus->bandwidth_int_reqs  = 0;	bus->bandwidth_isoc_reqs = 0;	INIT_LIST_HEAD(&bus->bus_list);	INIT_LIST_HEAD(&bus->inodes);	atomic_set(&bus->refcnt, 1);	return bus;}/** *	usb_free_bus - frees the memory used by a bus structure *	@bus: pointer to the bus to free * *	(For use only by USB Host Controller Drivers.) */void usb_free_bus(struct usb_bus *bus){	if (!bus)		return;	usb_bus_put(bus);}/** *	usb_register_bus - registers the USB host controller with the usb core *	@bus: pointer to the bus to register * *	(For use only by USB Host Controller Drivers.) */void usb_register_bus(struct usb_bus *bus){	int busnum;	down (&usb_bus_list_lock);	busnum = find_next_zero_bit(busmap.busmap, USB_MAXBUS, 1);	if (busnum < USB_MAXBUS) {		set_bit(busnum, busmap.busmap);		bus->busnum = busnum;	} else		warn("too many buses");	usb_bus_get(bus);	/* Add it to the list of buses */	list_add(&bus->bus_list, &usb_bus_list);	up (&usb_bus_list_lock);	usbdevfs_add_bus(bus);	info("new USB bus registered, assigned bus number %d", bus->busnum);}/** *	usb_deregister_bus - deregisters the USB host controller *	@bus: pointer to the bus to deregister * *	(For use only by USB Host Controller Drivers.) */void usb_deregister_bus(struct usb_bus *bus){	info("USB bus %d deregistered", bus->busnum);	/*	 * NOTE: make sure that all the devices are removed by the	 * controller code, as well as having it call this when cleaning	 * itself up	 */	down (&usb_bus_list_lock);	list_del(&bus->bus_list);	up (&usb_bus_list_lock);	usbdevfs_remove_bus(bus);	clear_bit(bus->busnum, busmap.busmap);	usb_bus_put(bus);}/* * This function is for doing a depth-first search for devices which * have support, for dynamic loading of driver modules. */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -