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

📄 hcd.c

📁 飞利浦isp1161 arm-linux驱动源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (c) 2001-2002 by David Brownell *  * 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/pci.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/ioport.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/smp_lock.h>#include <linux/errno.h>#include <linux/kmod.h>#include <linux/init.h>#include <linux/timer.h>#include <linux/list.h>#include <linux/interrupt.h>#include <linux/completion.h>#include <linux/uts.h>			/* for UTS_SYSNAME */#ifdef CONFIG_USB_DEBUG	#define DEBUG#else	#undef DEBUG#endif#include <linux/usb.h>#include "hcd.h"#include <asm/io.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/unaligned.h>/*-------------------------------------------------------------------------*//* * 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, ... * * HISTORY: * 2001-12-12	Initial patch version for Linux 2.5.1 kernel. *//*-------------------------------------------------------------------------*//* host controllers we manage */static LIST_HEAD (hcd_list);/* used when updating list of hcds */static DECLARE_MUTEX (hcd_list_lock);/* used when updating hcd data */static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED;static struct usb_operations hcd_operations;/*-------------------------------------------------------------------------*//* * 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, /*  __u16 bcdUSB; v2.0 */	0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */	0x00,	    /*  __u8  bDeviceSubClass; */	0x01,       /*  __u8  bDeviceProtocol; [ usb 2.0 single TT ]*/	0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */	0x00, 0x00, /*  __u16 idVendor; */ 	0x00, 0x00, /*  __u16 idProduct; */	KERNEL_VER, KERNEL_REL, /*  __u16 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, /*  __u16 bcdUSB; v1.1 */	0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */	0x00,	    /*  __u8  bDeviceSubClass; */	0x00,       /*  __u8  bDeviceProtocol; [ low/full speeds only ] */	0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */	0x00, 0x00, /*  __u16 idVendor; */ 	0x00, 0x00, /*  __u16 idProduct; */	KERNEL_VER, KERNEL_REL, /*  __u16 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, /*  __u16 wTotalLength; */	0x01,       /*  __u8  bNumInterfaces; (1) */	0x01,       /*  __u8  bConfigurationValue; */	0x00,       /*  __u8  iConfiguration; */	0x40,       /*  __u8  bmAttributes; 				 Bit 7: Bus-powered,				     6: Self-powered,				     5 Remote-wakwup,				     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, /*  __u16 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, /*  __u16 wTotalLength; */	0x01,       /*  __u8  bNumInterfaces; (1) */	0x01,       /*  __u8  bConfigurationValue; */	0x00,       /*  __u8  iConfiguration; */	0x40,       /*  __u8  bmAttributes; 				 Bit 7: Bus-powered,				     6: Self-powered,				     5 Remote-wakwup,				     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, /*  __u16 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;	}	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) * @pci_desc: PCI device descriptor for the relevant HC * @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) {		*data++ = 4; *data++ = 3;	/* 4 bytes string data */		*data++ = 0; *data++ = 0;	/* some language id */		return 4;	// serial number	} else if (id == 1) {		strcpy (buf, hcd->bus_name);	// product description	} else if (id == 2) {                strcpy (buf, hcd->product_desc); 	// id 3 == vendor description	} else if (id == 3) {                sprintf (buf, "%s %s %s", UTS_SYSNAME, UTS_RELEASE,			hcd->description);	// unsupported IDs --> "protocol stall"	} else	    return 0;	data [0] = 2 + ascii2utf (buf, data + 2, len - 2);	data [1] = 3;	/* type == string */	return data [0];}/* Root hub control transfers execute synchronously */static int rh_call_control (struct usb_hcd *hcd, struct urb *urb){	devrequest	*cmd = (devrequest *) urb->setup_packet; 	u16		typeReq, wValue, wIndex, wLength;	const u8	*bufp = 0;	u8		*ubuf = urb->transfer_buffer;	int		len = 0;	typeReq  = (cmd->requesttype << 8) | cmd->request;	wValue   = le16_to_cpu (cmd->value);	wIndex   = le16_to_cpu (cmd->index);	wLength  = le16_to_cpu (cmd->length);	if (wLength > urb->transfer_buffer_length)		goto error;	/* set up for success */	urb->status = 0;	urb->actual_length = wLength;	switch (typeReq) {	/* DEVICE REQUESTS */	case DeviceRequest | USB_REQ_GET_STATUS:		// DEVICE_REMOTE_WAKEUP		ubuf [0] = 1; // selfpowered		ubuf [1] = 0;			/* FALLTHROUGH */	case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:	case DeviceOutRequest | USB_REQ_SET_FEATURE:		dbg ("no device features yet yet");		break;	case DeviceRequest | USB_REQ_GET_CONFIGURATION:		ubuf [0] = 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;			}			break;		case USB_DT_STRING << 8:			urb->actual_length = rh_string (				wValue & 0xff, hcd,				ubuf, wLength);			break;		default:			goto error;		}		break;	case DeviceRequest | USB_REQ_GET_INTERFACE:		ubuf [0] = 0;			/* FALLTHROUGH */	case DeviceOutRequest | USB_REQ_SET_INTERFACE:		break;	case DeviceOutRequest | USB_REQ_SET_ADDRESS:		// wValue == urb->dev->devaddr		dbg ("%s root hub device address %d",			hcd->bus_name, wValue);		break;	/* INTERFACE REQUESTS (no defined feature/status flags) */	/* ENDPOINT REQUESTS */	case EndpointRequest | USB_REQ_GET_STATUS:		// ENDPOINT_HALT flag		ubuf [0] = 0;		ubuf [1] = 0;			/* FALLTHROUGH */	case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:	case EndpointOutRequest | USB_REQ_SET_FEATURE:		dbg ("no endpoint features yet");		break;	/* CLASS REQUESTS (and errors) */	default:		/* non-generic request */		urb->status = hcd->driver->hub_control (hcd,			typeReq, wValue, wIndex,			ubuf, wLength);		break;error:		/* "protocol stall" on error */		urb->status = -EPIPE;		dbg ("unsupported hub control message (maxchild %d)",				urb->dev->maxchild);	}	if (urb->status) {		urb->actual_length = 0;		dbg ("CTRL: TypeReq=0x%x val=0x%x idx=0x%x len=%d ==> %d",			typeReq, wValue, wIndex, wLength, urb->status);	}	if (bufp) {		if (urb->transfer_buffer_length < len)			len = urb->transfer_buffer_length;		urb->actual_length = len;		// always USB_DIR_IN, toward host		memcpy (ubuf, bufp, len);	}	/* any errors get returned through the urb completion */	usb_hcd_giveback_urb (hcd, urb);	return 0;}/*-------------------------------------------------------------------------*//* * Root Hub interrupt transfers are synthesized with a timer. * Completions are called in_interrupt() but not in_irq(). */static void rh_report_status (unsigned long ptr);static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb) {	int	len = 1 + (urb->dev->maxchild / 8);	/* rh_timer protected by hcd_data_lock */	if (timer_pending (&hcd->rh_timer)			|| urb->status != -EINPROGRESS			|| !HCD_IS_RUNNING (hcd->state)			|| urb->transfer_buffer_length < len) {		dbg ("not queuing status urb, stat %d", urb->status);		return -EINVAL;	}	urb->hcpriv = hcd;	/* nonzero to indicate it's queued */	init_timer (&hcd->rh_timer);	hcd->rh_timer.function = rh_report_status;	hcd->rh_timer.data = (unsigned long) urb;	/* USB 2.0 spec says 256msec; this is close enough */	hcd->rh_timer.expires = jiffies + HZ/4;	add_timer (&hcd->rh_timer);	return 0;}/* timer callback */static void rh_report_status (unsigned long ptr){	struct urb	*urb;	struct usb_hcd	*hcd;	int		length;	unsigned long	flags;	urb = (struct urb *) ptr;	spin_lock_irqsave (&urb->lock, flags);	if (!urb->dev) {		spin_unlock_irqrestore (&urb->lock, flags);		return;	}	hcd = urb->dev->bus->hcpriv;	if (urb->status == -EINPROGRESS) {		if (HCD_IS_RUNNING (hcd->state)) {

⌨️ 快捷键说明

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