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

📄 hcd.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * (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 * (C) Copyright Randy Dunlap 2000 * (C) Copyright David Brownell 2000-2002 *  * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include <linux/config.h>#include <linux/module.h>#include <linux/version.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/completion.h>#include <linux/utsname.h>#include <linux/mm.h>#include <asm/io.h>#include <asm/scatterlist.h>#include <linux/device.h>#include <linux/dma-mapping.h>#include <asm/irq.h>#include <asm/byteorder.h>#include <linux/usb.h>#include "usb.h"#include "hcd.h"#include "hub.h"// #define USB_BANDWIDTH_MESSAGES/*-------------------------------------------------------------------------*//* * USB Host Controller Driver framework * * Plugs into usbcore (usb_bus) and lets HCDs share code, minimizing * HCD-specific behaviors/bugs. * * This does error checks, tracks devices and urbs, and delegates to a * "hc_driver" only for code (and data) that really needs to know about * hardware differences.  That includes root hub registers, i/o queues, * and so on ... but as little else as possible. * * Shared code includes most of the "root hub" code (these are emulated, * though each HC's hardware works differently) and PCI glue, plus request * tracking overhead.  The HCD code should only block on spinlocks or on * hardware handshaking; blocking on software events (such as other kernel * threads releasing resources, or completing actions) is all generic. * * Happens the USB 2.0 spec says this would be invisible inside the "USBD", * and includes mostly a "HCDI" (HCD Interface) along with some APIs used * only by the hub driver ... and that neither should be seen or used by * usb client device drivers. * * Contributors of ideas or unattributed patches include: David Brownell, * Roman Weissgaerber, Rory Bolt, Greg Kroah-Hartman, ... * * HISTORY: * 2002-02-21	Pull in most of the usb_bus support from usb.c; some *		associated cleanup.  "usb_hcd" still != "usb_bus". * 2001-12-12	Initial patch version for Linux 2.5.1 kernel. *//*-------------------------------------------------------------------------*//* host controllers we manage */LIST_HEAD (usb_bus_list);EXPORT_SYMBOL_GPL (usb_bus_list);/* used when allocating bus numbers */#define USB_MAXBUS		64struct usb_busmap {	unsigned long busmap [USB_MAXBUS / (8*sizeof (unsigned long))];};static struct usb_busmap busmap;/* used when updating list of hcds */DECLARE_MUTEX (usb_bus_list_lock);	/* exported only for usbfs */EXPORT_SYMBOL_GPL (usb_bus_list_lock);/* used for controlling access to virtual root hubs */static DEFINE_SPINLOCK(hcd_root_hub_lock);/* used when updating hcd data */static DEFINE_SPINLOCK(hcd_data_lock);/* wait queue for synchronous unlinks */DECLARE_WAIT_QUEUE_HEAD(usb_kill_urb_queue);/*-------------------------------------------------------------------------*//* * Sharable chunks of root hub code. *//*-------------------------------------------------------------------------*/#define KERNEL_REL	((LINUX_VERSION_CODE >> 16) & 0x0ff)#define KERNEL_VER	((LINUX_VERSION_CODE >> 8) & 0x0ff)/* usb 2.0 root hub device descriptor */static const u8 usb2_rh_dev_descriptor [18] = {	0x12,       /*  __u8  bLength; */	0x01,       /*  __u8  bDescriptorType; Device */	0x00, 0x02, /*  __le16 bcdUSB; v2.0 */	0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */	0x00,	    /*  __u8  bDeviceSubClass; */	0x01,       /*  __u8  bDeviceProtocol; [ usb 2.0 single TT ]*/	0x40,       /*  __u8  bMaxPacketSize0; 64 Bytes */	0x00, 0x00, /*  __le16 idVendor; */ 	0x00, 0x00, /*  __le16 idProduct; */	KERNEL_VER, KERNEL_REL, /*  __le16 bcdDevice */	0x03,       /*  __u8  iManufacturer; */	0x02,       /*  __u8  iProduct; */	0x01,       /*  __u8  iSerialNumber; */	0x01        /*  __u8  bNumConfigurations; */};/* no usb 2.0 root hub "device qualifier" descriptor: one speed only *//* usb 1.1 root hub device descriptor */static const u8 usb11_rh_dev_descriptor [18] = {	0x12,       /*  __u8  bLength; */	0x01,       /*  __u8  bDescriptorType; Device */	0x10, 0x01, /*  __le16 bcdUSB; v1.1 */	0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */	0x00,	    /*  __u8  bDeviceSubClass; */	0x00,       /*  __u8  bDeviceProtocol; [ low/full speeds only ] */	0x40,       /*  __u8  bMaxPacketSize0; 64 Bytes */	0x00, 0x00, /*  __le16 idVendor; */ 	0x00, 0x00, /*  __le16 idProduct; */	KERNEL_VER, KERNEL_REL, /*  __le16 bcdDevice */	0x03,       /*  __u8  iManufacturer; */	0x02,       /*  __u8  iProduct; */	0x01,       /*  __u8  iSerialNumber; */	0x01        /*  __u8  bNumConfigurations; */};/*-------------------------------------------------------------------------*//* Configuration descriptors for our root hubs */static const u8 fs_rh_config_descriptor [] = {	/* one configuration */	0x09,       /*  __u8  bLength; */	0x02,       /*  __u8  bDescriptorType; Configuration */	0x19, 0x00, /*  __le16 wTotalLength; */	0x01,       /*  __u8  bNumInterfaces; (1) */	0x01,       /*  __u8  bConfigurationValue; */	0x00,       /*  __u8  iConfiguration; */	0xc0,       /*  __u8  bmAttributes; 				 Bit 7: must be set,				     6: Self-powered,				     5: Remote wakeup,				     4..0: resvd */	0x00,       /*  __u8  MaxPower; */      	/* USB 1.1:	 * USB 2.0, single TT organization (mandatory):	 *	one interface, protocol 0	 *	 * USB 2.0, multiple TT organization (optional):	 *	two interfaces, protocols 1 (like single TT)	 *	and 2 (multiple TT mode) ... config is	 *	sometimes settable	 *	NOT IMPLEMENTED	 */	/* one interface */	0x09,       /*  __u8  if_bLength; */	0x04,       /*  __u8  if_bDescriptorType; Interface */	0x00,       /*  __u8  if_bInterfaceNumber; */	0x00,       /*  __u8  if_bAlternateSetting; */	0x01,       /*  __u8  if_bNumEndpoints; */	0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */	0x00,       /*  __u8  if_bInterfaceSubClass; */	0x00,       /*  __u8  if_bInterfaceProtocol; [usb1.1 or single tt] */	0x00,       /*  __u8  if_iInterface; */     	/* one endpoint (status change endpoint) */	0x07,       /*  __u8  ep_bLength; */	0x05,       /*  __u8  ep_bDescriptorType; Endpoint */	0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */ 	0x03,       /*  __u8  ep_bmAttributes; Interrupt */ 	0x02, 0x00, /*  __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */	0xff        /*  __u8  ep_bInterval; (255ms -- usb 2.0 spec) */};static const u8 hs_rh_config_descriptor [] = {	/* one configuration */	0x09,       /*  __u8  bLength; */	0x02,       /*  __u8  bDescriptorType; Configuration */	0x19, 0x00, /*  __le16 wTotalLength; */	0x01,       /*  __u8  bNumInterfaces; (1) */	0x01,       /*  __u8  bConfigurationValue; */	0x00,       /*  __u8  iConfiguration; */	0xc0,       /*  __u8  bmAttributes; 				 Bit 7: must be set,				     6: Self-powered,				     5: Remote wakeup,				     4..0: resvd */	0x00,       /*  __u8  MaxPower; */      	/* USB 1.1:	 * USB 2.0, single TT organization (mandatory):	 *	one interface, protocol 0	 *	 * USB 2.0, multiple TT organization (optional):	 *	two interfaces, protocols 1 (like single TT)	 *	and 2 (multiple TT mode) ... config is	 *	sometimes settable	 *	NOT IMPLEMENTED	 */	/* one interface */	0x09,       /*  __u8  if_bLength; */	0x04,       /*  __u8  if_bDescriptorType; Interface */	0x00,       /*  __u8  if_bInterfaceNumber; */	0x00,       /*  __u8  if_bAlternateSetting; */	0x01,       /*  __u8  if_bNumEndpoints; */	0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */	0x00,       /*  __u8  if_bInterfaceSubClass; */	0x00,       /*  __u8  if_bInterfaceProtocol; [usb1.1 or single tt] */	0x00,       /*  __u8  if_iInterface; */     	/* one endpoint (status change endpoint) */	0x07,       /*  __u8  ep_bLength; */	0x05,       /*  __u8  ep_bDescriptorType; Endpoint */	0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */ 	0x03,       /*  __u8  ep_bmAttributes; Interrupt */ 	0x02, 0x00, /*  __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */	0x0c        /*  __u8  ep_bInterval; (256ms -- usb 2.0 spec) */};/*-------------------------------------------------------------------------*//* * helper routine for returning string descriptors in UTF-16LE * input can actually be ISO-8859-1; ASCII is its 7-bit subset */static int ascii2utf (char *s, u8 *utf, int utfmax){	int retval;	for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) {		*utf++ = *s++;		*utf++ = 0;	}	if (utfmax > 0) {		*utf = *s;		++retval;	}	return retval;}/* * rh_string - provides manufacturer, product and serial strings for root hub * @id: the string ID number (1: serial number, 2: product, 3: vendor) * @hcd: the host controller for this root hub * @type: string describing our driver  * @data: return packet in UTF-16 LE * @len: length of the return packet * * Produces either a manufacturer, product or serial number string for the * virtual root hub device. */static int rh_string (	int		id,	struct usb_hcd	*hcd,	u8		*data,	int		len) {	char buf [100];	// language ids	if (id == 0) {		buf[0] = 4;    buf[1] = 3;	/* 4 bytes string data */		buf[2] = 0x09; buf[3] = 0x04;	/* MSFT-speak for "en-us" */		len = min (len, 4);		memcpy (data, buf, len);		return len;	// serial number	} else if (id == 1) {		strlcpy (buf, hcd->self.bus_name, sizeof buf);	// product description	} else if (id == 2) {		strlcpy (buf, hcd->product_desc, sizeof buf); 	// id 3 == vendor description	} else if (id == 3) {		snprintf (buf, sizeof buf, "%s %s %s", system_utsname.sysname,			system_utsname.release, hcd->driver->description);	// unsupported IDs --> "protocol stall"	} else		return -EPIPE;	switch (len) {		/* All cases fall through */	default:		len = 2 + ascii2utf (buf, data + 2, len - 2);	case 2:		data [1] = 3;	/* type == string */	case 1:		data [0] = 2 * (strlen (buf) + 1);	case 0:		;		/* Compiler wants a statement here */	}	return len;}/* Root hub control transfers execute synchronously */static int rh_call_control (struct usb_hcd *hcd, struct urb *urb){	struct usb_ctrlrequest *cmd; 	u16		typeReq, wValue, wIndex, wLength;	u8		*ubuf = urb->transfer_buffer;	u8		tbuf [sizeof (struct usb_hub_descriptor)];	const u8	*bufp = tbuf;	int		len = 0;	int		patch_wakeup = 0;	unsigned long	flags;	int		status = 0;	int		n;	cmd = (struct usb_ctrlrequest *) urb->setup_packet;	typeReq  = (cmd->bRequestType << 8) | cmd->bRequest;	wValue   = le16_to_cpu (cmd->wValue);	wIndex   = le16_to_cpu (cmd->wIndex);	wLength  = le16_to_cpu (cmd->wLength);	if (wLength > urb->transfer_buffer_length)		goto error;	urb->actual_length = 0;	switch (typeReq) {	/* DEVICE REQUESTS */	case DeviceRequest | USB_REQ_GET_STATUS:		tbuf [0] = (hcd->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP)				| (1 << USB_DEVICE_SELF_POWERED);		tbuf [1] = 0;		len = 2;		break;	case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:		if (wValue == USB_DEVICE_REMOTE_WAKEUP)			hcd->remote_wakeup = 0;		else			goto error;		break;	case DeviceOutRequest | USB_REQ_SET_FEATURE:		if (hcd->can_wakeup && wValue == USB_DEVICE_REMOTE_WAKEUP)			hcd->remote_wakeup = 1;		else			goto error;		break;	case DeviceRequest | USB_REQ_GET_CONFIGURATION:		tbuf [0] = 1;		len = 1;			/* FALLTHROUGH */	case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:		break;	case DeviceRequest | USB_REQ_GET_DESCRIPTOR:		switch (wValue & 0xff00) {		case USB_DT_DEVICE << 8:			if (hcd->driver->flags & HCD_USB2)				bufp = usb2_rh_dev_descriptor;			else if (hcd->driver->flags & HCD_USB11)				bufp = usb11_rh_dev_descriptor;			else				goto error;			len = 18;			break;		case USB_DT_CONFIG << 8:			if (hcd->driver->flags & HCD_USB2) {				bufp = hs_rh_config_descriptor;				len = sizeof hs_rh_config_descriptor;			} else {				bufp = fs_rh_config_descriptor;				len = sizeof fs_rh_config_descriptor;			}			if (hcd->can_wakeup)				patch_wakeup = 1;			break;		case USB_DT_STRING << 8:			n = rh_string (wValue & 0xff, hcd, ubuf, wLength);			if (n < 0)				goto error;			urb->actual_length = n;			break;		default:			goto error;		}		break;	case DeviceRequest | USB_REQ_GET_INTERFACE:		tbuf [0] = 0;		len = 1;			/* FALLTHROUGH */	case DeviceOutRequest | USB_REQ_SET_INTERFACE:		break;	case DeviceOutRequest | USB_REQ_SET_ADDRESS:		// wValue == urb->dev->devaddr		dev_dbg (hcd->self.controller, "root hub device address %d\n",			wValue);		break;	/* INTERFACE REQUESTS (no defined feature/status flags) */	/* ENDPOINT REQUESTS */	case EndpointRequest | USB_REQ_GET_STATUS:		// ENDPOINT_HALT flag		tbuf [0] = 0;		tbuf [1] = 0;		len = 2;			/* FALLTHROUGH */	case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:	case EndpointOutRequest | USB_REQ_SET_FEATURE:		dev_dbg (hcd->self.controller, "no endpoint features yet\n");		break;	/* CLASS REQUESTS (and errors) */	default:		/* non-generic request */		switch (typeReq) {		case GetHubStatus:		case GetPortStatus:			len = 4;			break;		case GetHubDescriptor:			len = sizeof (struct usb_hub_descriptor);			break;		}		status = hcd->driver->hub_control (hcd,			typeReq, wValue, wIndex,			tbuf, wLength);		break;error:		/* "protocol stall" on error */		status = -EPIPE;	}	if (status) {		len = 0;		if (status != -EPIPE) {			dev_dbg (hcd->self.controller,				"CTRL: TypeReq=0x%x val=0x%x "				"idx=0x%x len=%d ==> %d\n",				typeReq, wValue, wIndex,				wLength, status);		}	}	if (len) {		if (urb->transfer_buffer_length < len)			len = urb->transfer_buffer_length;		urb->actual_length = len;

⌨️ 快捷键说明

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