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

📄 hub.c

📁 有关于USB的一些主机端驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * USB hub driver.
 *
 * (C) Copyright 1999 Linus Torvalds
 * (C) Copyright 1999 Johannes Erdfelt
 * (C) Copyright 1999 Gregory P. Smith
 */
/*
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/completion.h>
#include <linux/sched.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#ifdef CONFIG_USB_DEBUG
	#define DEBUG
#else
	#undef DEBUG
#endif
*/
//#include "usb.h"
/*
#include <linux/usbdevice_fs.h>

#include <asm/semaphore.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
*/
#include "hub.h"
//#include "usb-ohci.h"
//extern void hc_register_info(ohci_t *ohci);
/* Wakes up khubd */
//static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED;
//static DECLARE_MUTEX(usb_address0_sem);
extern int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,__u16 value, __u16 index, void *data, __u16 size, int timeout);
extern int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,void *data, int len, int *actual_length, int timeout);
extern int list_empty(struct list_head *head);
void usb_hub_events();
extern void usb_scan_devices();
extern void atomic_inc(atomic_t *v);
extern void clear_bit(int nr, volatile void * addr);
extern unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint);
extern void list_del(struct list_head *entry);
extern int atomic_dec_and_test(atomic_t *v);
extern void wait_ms(unsigned int ms);

static LIST_HEAD(hub_event_list);	/* List of hubs needing servicing */
static LIST_HEAD(hub_list);		/* List containing all of the hubs (for cleanup) */

//static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
//static int khubd_pid = 0;			/* PID of khubd */
//static DECLARE_COMPLETION(khubd_exited);


char *portspeed (int portstatus)
{
	if (portstatus & (1 << USB_PORT_FEAT_HIGHSPEED))
    		return "480 Mb/s";
	else if (portstatus & (1 << USB_PORT_FEAT_LOWSPEED))
		return "1.5 Mb/s";
	else
		return "12 Mb/s";
}


static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
{
	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
		USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
		USB_DT_HUB << 8, 0, data, size, HZ);
}

static int usb_clear_hub_feature(struct usb_device *dev, int feature)
{
	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
		USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0, NULL, 0, HZ);
}

static int usb_clear_port_feature(struct usb_device *dev, int port, int feature)
{
	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
		USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ);
}

static int usb_set_port_feature(struct usb_device *dev, int port, int feature)
{
	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
		USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ);
}

static int usb_get_hub_status(struct usb_device *dev, void *data)
{
	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
		USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0,
		data, sizeof(struct usb_hub_status), HZ);
}

static int usb_get_port_status(struct usb_device *dev, int port, void *data)
{
	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
		USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port,
		data, sizeof(struct usb_hub_status), HZ);
}

static void hub_irq(struct urb *urb)
{
	struct usb_hub *hub = (struct usb_hub *)urb->context;
	unsigned long flags;

	/* Cause a hub reset after 10 consecutive errors */
	if (urb->status) {
		if (urb->status == -ENOENT)
			return;

		printf("nonzero status in irq %d", urb->status);

		if ((++hub->nerrors < 10) || hub->error)
			return;

		hub->error = urb->status;
	}

	hub->nerrors = 0;

	/* Something happened, let khubd figure it out */
//	spin_lock_irqsave(&hub_event_lock, flags);
	if (list_empty(&hub->event_list)) {
		list_add(&hub->event_list, &hub_event_list);
//		wake_up(&khubd_wait);
		usb_hub_events();
	}
//	spin_unlock_irqrestore(&hub_event_lock, flags);

}

static void usb_hub_power_on(struct usb_hub *hub)
{
	int i;

	/* Enable power to the ports */
	printf("enabling power on all ports \n");
	for (i = 0; i < hub->descriptor->bNbrPorts; i++)
		usb_set_port_feature(hub->dev, i + 1, USB_PORT_FEAT_POWER);

	/* Wait for power to be enabled */
	wait_ms(hub->descriptor->bPwrOn2PwrGood * 2);
}

static int usb_hub_configure(struct usb_hub *hub, struct usb_endpoint_descriptor *endpoint)
{
	struct usb_device *dev = hub->dev;
	struct usb_hub_status hubstatus;
	char portstr[USB_MAXCHILDREN + 1];
	unsigned int pipe;
	int i, maxp, ret;

	hub->descriptor = (struct usb_hub_descriptor *)malloc(sizeof(*hub->descriptor));
	if (!hub->descriptor) {
		err("Unable to kmalloc %Zd bytes for hub descriptor", sizeof(*hub->descriptor));
		return -1;
	}

	/* Request the entire hub descriptor. */
	ret = usb_get_hub_descriptor(dev, hub->descriptor, sizeof(*hub->descriptor));
		/* <hub->descriptor> is large enough for a hub with 127 ports;
		 * the hub can/will return fewer bytes here. */
	if (ret < 0) {
		err("Unable to get hub descriptor (err = %d)", ret);
		free(hub->descriptor);
		return -1;
	}

	dev->maxchild = hub->descriptor->bNbrPorts;
//	info("%d port%s detected", hub->descriptor->bNbrPorts, (hub->descriptor->bNbrPorts == 1) ? "" : "s");

	le16_to_cpus(&hub->descriptor->wHubCharacteristics);

	if (hub->descriptor->wHubCharacteristics & HUB_CHAR_COMPOUND)
		printf("part of a compound device\n");
	else
		printf("standalone hub\n");

	switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) {
		case 0x00:
			printf("ganged power switching\n");
			break;
		case 0x01:
			printf("individual port power switching\n");
			break;
		case 0x02:
		case 0x03:
			printf("unknown reserved power switching mode\n");
			break;
	}

	switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_OCPM) {
		case 0x00:
			printf("global over-current protection\n");
			break;
		case 0x08:
			printf("individual port over-current protection\n");
			break;
		case 0x10:
		case 0x18:
			printf("no over-current protection\n");
                        break;
	}

	switch (dev->descriptor.bDeviceProtocol) {
		case 0:
			break;
		case 1:
			printf("Single TT\n");
			break;
		case 2:
			printf("Multiple TT\n");
			break;
		default:
			printf("Unrecognized hub protocol %d\n",
				dev->descriptor.bDeviceProtocol);
			break;
	}

	switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_TTTT) {
		case 0x00:
			if (dev->descriptor.bDeviceProtocol != 0)
				printf("TT requires at most 8 FS bit times\n");
			break;
		case 0x20:
			printf("TT requires at most 16 FS bit times\n");
			break;
		case 0x40:
			printf("TT requires at most 24 FS bit times\n");
			break;
		case 0x60:
			printf("TT requires at most 32 FS bit times\n");
			break;
	}

	printf("Port indicators are %s supported\n", 
	    (hub->descriptor->wHubCharacteristics & HUB_CHAR_PORTIND) ? "" : "not");

	printf("power on to power good time: %d ms\n", hub->descriptor->bPwrOn2PwrGood * 2);
	printf("hub controller current requirement: %d mA\n", hub->descriptor->bHubContrCurrent);

	for (i = 0; i < dev->maxchild; i++)
		portstr[i] = hub->descriptor->bitmap[((i + 1) / 8)] & (1 << ((i + 1) % 8)) ? 'F' : 'R';
	portstr[dev->maxchild] = 0;

	printf("port removable status: %s\n", portstr);

	ret = usb_get_hub_status(dev, &hubstatus);
	if (ret < 0) {
		err("Unable to get hub status (err = %d)\n", ret);
		free(hub->descriptor);
		return -1;
	}

	le16_to_cpus(&hubstatus.wHubStatus);

	printf("local power source is %s\n",
		(hubstatus.wHubStatus & HUB_STATUS_LOCAL_POWER) ? "lost (inactive)" : "good");

	printf("%s over-current condition exists\n",
		(hubstatus.wHubStatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");

	/* Start the interrupt endpoint */
	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));

	if (maxp > sizeof(hub->buffer))
		maxp = sizeof(hub->buffer);

	hub->urb = (struct urb *)usb_alloc_urb(0);
	if (!hub->urb) {
		err("couldn't allocate interrupt urb\n");
		free(hub->descriptor);
		return -1;
	}

	FILL_INT_URB(hub->urb, dev, pipe, hub->buffer, maxp, hub_irq,
		hub, endpoint->bInterval);
	ret = usb_submit_urb(hub->urb);
	if (ret) {
		err("usb_submit_urb failed (%d)\n", ret);
		free(hub->descriptor);
		return -1;
	}
		
	/* Wake up khubd */
//	wake_up(&khubd_wait);

	usb_hub_power_on(hub);

	return 0;
}

//static int hub_probe(struct usb_device *dev, unsigned int i,struct usb_device_id *id)
void * hub_probe(struct usb_device *dev, unsigned int i)
{
	struct usb_interface_descriptor *interface;
	struct usb_endpoint_descriptor *endpoint;
	struct usb_hub *hub;
	unsigned long flags;

	interface = &dev->actconfig->interface[i].altsetting[0];

	/* Some hubs have a subclass of 1, which AFAICT according to the */
	/*  specs is not defined, but it works */
	if ((interface->bInterfaceSubClass != 0) &&
	    (interface->bInterfaceSubClass != 1)) {
//		printf("invalid subclass (%d) for USB hub device #%d\n",	interface->bInterfaceSubClass, dev->devnum);
		return NULL;
	}

	/* Multiple endpoints? What kind of mutant ninja-hub is this? */
	if (interface->bNumEndpoints != 1) {
		printf("invalid bNumEndpoints (%d) for USB hub device #%d\n",interface->bNumEndpoints, dev->devnum);
		return NULL;
	}

	endpoint = &interface->endpoint[0];

	/* Output endpoint? Curiousier and curiousier.. */
	if (!(endpoint->bEndpointAddress & USB_DIR_IN)) {
		printf("Device #%d is hub class, but has output endpoint?\n",dev->devnum);
		return NULL;
	}

	/* If it's not an interrupt endpoint, we'd better punt! */
	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) {
		err("Device #%d is hub class, but has endpoint other than interrupt?\n",
			dev->devnum);
		return NULL;
	}

	/* We found a hub */
	printf("USB hub found\n");

	hub = (struct usb_hub *)malloc(sizeof(*hub));
	if (!hub) {
		printf("couldn't kmalloc hub struct\n");
		return NULL;
//		return 0;
	}

	memset(hub, 0, sizeof(*hub));

	INIT_LIST_HEAD(&hub->event_list);
	hub->dev = dev;
	atomic_set(&hub->refcnt, 1);

	/* Record the new hub's existence */
//	spin_lock_irqsave(&hub_event_lock, flags);
	INIT_LIST_HEAD(&hub->hub_list);
	list_add(&hub->hub_list, &hub_list);
//	spin_unlock_irqrestore(&hub_event_lock, flags);

	if (usb_hub_configure(hub, endpoint) >= 0){
//		printf("Complete hub configuration\n");
		return hub;
	}

	printf("hub configuration failed for device #%d\n", dev->devnum);

	/* free hub, but first clean up its list. */
//	spin_lock_irqsave(&hub_event_lock, flags);

	/* Delete it and then reset it */
	list_del(&hub->event_list);
	INIT_LIST_HEAD(&hub->event_list);
	list_del(&hub->hub_list);
	INIT_LIST_HEAD(&hub->hub_list);

//	spin_unlock_irqrestore(&hub_event_lock, flags);

	free(hub);
//	return NULL;
	return 0;
}

static void hub_get(struct usb_hub *hub)
{
	atomic_inc(&hub->refcnt);
}

static void hub_put(struct usb_hub *hub)
{
	if (atomic_dec_and_test(&hub->refcnt)) {
		if (hub->descriptor) {
			free(hub->descriptor);
			hub->descriptor = NULL;
		}

		free(hub);
	}
}

static void hub_disconnect(struct usb_device *dev, void *ptr)
{
	struct usb_hub *hub = (struct usb_hub *)ptr;
	unsigned long flags;

	if (hub->urb) {
		usb_unlink_urb(hub->urb);
		usb_free_urb(hub->urb);
		hub->urb = NULL;
	}

//	spin_lock_irqsave(&hub_event_lock, flags);

	/* Delete it and then reset it */
	list_del(&hub->event_list);
	INIT_LIST_HEAD(&hub->event_list);
	list_del(&hub->hub_list);
	INIT_LIST_HEAD(&hub->hub_list);

//	spin_unlock_irqrestore(&hub_event_lock, flags);

	hub_put(hub);
}
#if 0
static int hub_ioctl(struct usb_device *hub, unsigned int code, void *user_data)
{
	/* assert ifno == 0 (part of hub spec) */
	switch (code) {
	case USBDEVFS_HUB_PORTINFO: {
		struct usbdevfs_hub_portinfo *info = user_data;
		unsigned long flags;
		int i;

		spin_lock_irqsave(&hub_event_lock, flags);
		if (hub->devnum <= 0)
			info->nports = 0;
		else {
			info->nports = hub->maxchild;
			for (i = 0; i < info->nports; i++) {
				if (hub->children[i] == NULL)
					info->port[i] = 0;
				else
					info->port[i] = hub->children[i]->devnum;
			}
		}
		spin_unlock_irqrestore(&hub_event_lock, flags);

		return info->nports + 1;
		}

	default:
		return -ENOSYS;
	}
}
#endif
static int usb_hub_reset(struct usb_hub *hub)
{
	struct usb_device *dev = hub->dev;
	int i;

	/* Disconnect any attached devices */
	for (i = 0; i < hub->descriptor->bNbrPorts; i++) {
		if (dev->children[i])
			usb_disconnect(&dev->children[i]);
	}

	/* Attempt to reset the hub */
	if (hub->urb)
		usb_unlink_urb(hub->urb);
	else
		return -1;

	if (usb_reset_device(dev))
		return -1;

	hub->urb->dev = dev;                                                    
	if (usb_submit_urb(hub->urb))
		return -1;

	usb_hub_power_on(hub);

	return 0;
}

static void usb_hub_disconnect(struct usb_device *dev)
{
	struct usb_device *parent = dev->parent;
	int i;

	/* Find the device pointer to disconnect */
	if (parent) {
		for (i = 0; i < parent->maxchild; i++) {
			if (parent->children[i] == dev) {
				usb_disconnect(&parent->children[i]);
				return;
			}
		}
	}

	err("cannot disconnect hub %d\n", dev->devnum);
}

#define HUB_RESET_TRIES		5
#define HUB_PROBE_TRIES		2
#define HUB_SHORT_RESET_TIME	10
#define HUB_LONG_RESET_TIME	200
#define HUB_RESET_TIMEOUT	500

/* return: -1 on error, 0 on success, 1 on disconnect.  */
static int usb_hub_port_wait_reset(struct usb_device *hub, int port,
				struct usb_device *dev, unsigned int delay)
{
	int delay_time, ret;
	struct usb_port_status portsts;
	unsigned short portchange, portstatus;

	for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT; delay_time += delay) {
		/* wait to give the device a chance to reset */
		wait_ms(delay);

		/* read and decode port status */
		ret = usb_get_port_status(hub, port + 1, &portsts);
		if (ret < 0) {
			err("get_port_status(%d) failed (err = %d)\n", port + 1, ret);
			return -1;
		}

		portstatus = le16_to_cpu(portsts.wPortStatus);
		portchange = le16_to_cpu(portsts.wPortChange);

//		printf("Portstatus :%x\n",portstatus);//added by changming HUANG
//		printf("PortChange :%x\n",portchange);
		
		printf("port %d, portstatus %d, change %d %s\n", port + 1,
			portstatus, portchange, portspeed (portstatus));

		/* Device went away? */
		if (!(portstatus & USB_PORT_STAT_CONNECTION))
			return 1;

⌨️ 快捷键说明

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