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

📄 usb.c

📁 有关于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>
//#include <asm/semaphore.h>

#ifdef CONFIG_USB_DEBUG
	#define DEBUG
#else
	#undef DEBUG
#endif
*/
//#include "usb.h"
#include "usb-ohci.h"

static const int usb_bandwidth_option =
#ifdef CONFIG_USB_BANDWIDTH
				1;
#else
				0;
#endif

extern int  usb_hub_init(void);
extern void usb_hub_cleanup(void);
extern void * hub_probe(struct usb_device *dev, unsigned int i);

/*
 * 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);
//rwlock_t usb_bus_list_lock = RW_LOCK_UNLOCKED;

//devfs_handle_t usb_devfs_handle;	/* /dev/usb dir. */

static struct usb_busmap busmap;

static struct usb_driver *usb_minors[16];

void wait_ms(unsigned int ms)
{
	int i=0;
	int res =100*ms;

	for(i;i<res;i++);
}

int list_empty(struct list_head *head)
{
	return head->next == head;
}

void __list_add(struct list_head * new,
	struct list_head * prev,
	struct list_head * next)
{
	next->prev = new;
	new->next = next;
	new->prev = prev;
	prev->next = new;
}
void list_add(struct list_head *new, struct list_head *head)
{
	__list_add(new, head, head->next);
}

void list_add_tail(struct list_head *new, struct list_head *head)
{
	__list_add(new, head->prev, head);
}

 void __list_del(struct list_head * prev,
				  struct list_head * next)
{
	next->prev = prev;
	prev->next = next;
}
void list_del(struct list_head *entry)
{
	__list_del(entry->prev, entry->next);
	entry->next = entry->prev = 0;
}
void list_del_init(struct list_head *entry)
{
	__list_del(entry->prev, entry->next);
	INIT_LIST_HEAD(entry); 
}

int find_next_zero_bit (void * addr, int size, int offset){
	unsigned long *p=((unsigned long *)addr)+(offset>>5);
	unsigned int set = 0, bit = offset & 31;
	unsigned int res;

//	res=bit;
	set=*p;
	set=(set>>bit);
	while(set & 0x1){
		bit+=1;
		set=(set>>1);
		if((bit%32)==0){
			p+=1;
			set=*p;
		}
	}
	
	res =(offset>>5)*32+bit;
	return res;
}

void set_bit(int nr, volatile void * addr){
	unsigned long *p=((unsigned long *)addr)+(nr>>5);
	unsigned int res=nr & 31;

	*p |=(1<<res);
}

void clear_bit(int nr, volatile void * addr){
	unsigned long *p=((unsigned long *)addr)+(nr>>5);
	unsigned int res=nr & 31;

	*p &=(~(1<<res));
}

 int atomic_dec_and_test(atomic_t *v)
{
//	unsigned long flags;
	int result;

//	__save_flags_cli(flags);
	v->counter -= 1;
	result = (v->counter == 0);
//	__restore_flags(flags);

	return result;
}

 void atomic_inc(atomic_t *v)
{
//	unsigned long flags;

//	__save_flags_cli(flags);
	v->counter += 1;
//	__restore_flags(flags);
}
void atomic_dec(atomic_t *v)
{
//	unsigned long flags;

//	__save_flags_cli(flags);
	v->counter -= 1;
//	__restore_flags(flags);
}

unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint)
{
	return (dev->devnum << 8) | (endpoint << 15) |
		((dev->speed == USB_SPEED_LOW) << 26);
}

unsigned int __default_pipe(struct usb_device *dev)
{
	return ((dev->speed == USB_SPEED_LOW) << 26);
}

/**
 *	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()
{
	struct list_head *tmp;

//	read_lock_irq (&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);
	}
//	read_unlock_irq (&usb_bus_list_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)
{
	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;
}

/*
 * 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;
}


/*
 * 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);

//	read_lock_irq (&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);
	}
//	read_unlock_irq (&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 (9107 + 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)
		printf("usb-check-bandwidth FAILED: was %d, would be %d, 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;

#if 0
//#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
}

⌨️ 快捷键说明

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