hcd.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,625 行 · 第 1/4 页

C
1,625
字号
		ubuf [0] = 0;			/* 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		ubuf [0] = 0;		ubuf [1] = 0;			/* 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 */		if (HCD_IS_SUSPENDED (hcd->state))			urb->status = -EAGAIN;		else if (!HCD_IS_RUNNING (hcd->state))			urb->status = -ENODEV;		else			urb->status = hcd->driver->hub_control (hcd,				typeReq, wValue, wIndex,				ubuf, wLength);		break;error:		/* "protocol stall" on error */		urb->status = -EPIPE;		dev_dbg (hcd->self.controller, "unsupported hub control message (maxchild %d)\n",				urb->dev->maxchild);	}	if (urb->status) {		urb->actual_length = 0;		dev_dbg (hcd->self.controller, "CTRL: TypeReq=0x%x val=0x%x idx=0x%x len=%d ==> %d\n",			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);		/* report whether RH hardware supports remote wakeup */		if (patch_wakeup)			((struct usb_config_descriptor *)ubuf)->bmAttributes				|= USB_CONFIG_ATT_WAKEUP;	}	/* any errors get returned through the urb completion */	local_irq_save (flags);	usb_hcd_giveback_urb (hcd, urb, NULL);	local_irq_restore (flags);	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 (hcd->rh_timer.data			|| urb->status != -EINPROGRESS			|| urb->transfer_buffer_length < len			|| !HCD_IS_RUNNING (hcd->state)) {		dev_dbg (hcd->self.controller,				"not queuing rh status urb, stat %d\n",				urb->status);		return -EINVAL;	}	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);	urb->hcpriv = hcd;	/* nonzero to indicate it's queued */	return 0;}/* timer callback */static void rh_report_status (unsigned long ptr){	struct urb	*urb;	struct usb_hcd	*hcd;	int		length = 0;	unsigned long	flags;	urb = (struct urb *) ptr;	local_irq_save (flags);	spin_lock (&urb->lock);	/* do nothing if the urb's been unlinked */	if (!urb->dev			|| urb->status != -EINPROGRESS			|| (hcd = urb->dev->bus->hcpriv) == 0) {		spin_unlock (&urb->lock);		local_irq_restore (flags);		return;	}	if (!HCD_IS_SUSPENDED (hcd->state))		length = hcd->driver->hub_status_data (					hcd, urb->transfer_buffer);	/* complete the status urb, or retrigger the timer */	spin_lock (&hcd_data_lock);	if (length > 0) {		hcd->rh_timer.data = 0;		urb->actual_length = length;		urb->status = 0;		urb->hcpriv = NULL;	} else		mod_timer (&hcd->rh_timer, jiffies + HZ/4);	spin_unlock (&hcd_data_lock);	spin_unlock (&urb->lock);	/* local irqs are always blocked in completions */	if (length > 0)		usb_hcd_giveback_urb (hcd, urb, NULL);	local_irq_restore (flags);}/*-------------------------------------------------------------------------*/static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb){	if (usb_pipeint (urb->pipe)) {		int		retval;		unsigned long	flags;		spin_lock_irqsave (&hcd_data_lock, flags);		retval = rh_status_urb (hcd, urb);		spin_unlock_irqrestore (&hcd_data_lock, flags);		return retval;	}	if (usb_pipecontrol (urb->pipe))		return rh_call_control (hcd, urb);	else		return -EINVAL;}/*-------------------------------------------------------------------------*/int usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb){	unsigned long	flags;	/* note:  always a synchronous unlink */	del_timer_sync (&hcd->rh_timer);	hcd->rh_timer.data = 0;	local_irq_save (flags);	urb->hcpriv = NULL;	usb_hcd_giveback_urb (hcd, urb, NULL);	local_irq_restore (flags);	return 0;}/*-------------------------------------------------------------------------*//* exported only within usbcore */struct usb_bus *usb_bus_get (struct usb_bus *bus){	struct class_device *tmp;	if (!bus)		return NULL;	tmp = class_device_get(&bus->class_dev);	if (tmp)        		return to_usb_bus(tmp);	else		return NULL;}/* exported only within usbcore */void usb_bus_put (struct usb_bus *bus){	if (bus)		class_device_put(&bus->class_dev);}/*-------------------------------------------------------------------------*/static void usb_host_release(struct class_device *class_dev){	struct usb_bus *bus = to_usb_bus(class_dev);	if (bus->release)		bus->release(bus);}static struct class usb_host_class = {	.name		= "usb_host",	.release	= &usb_host_release,};int usb_host_init(void){	return class_register(&usb_host_class);}void usb_host_cleanup(void){	class_unregister(&usb_host_class);}/** * usb_bus_init - shared initialization code * @bus: the bus structure being initialized * * This code is used to initialize a usb_bus structure, memory for which is * separately managed. */void usb_bus_init (struct usb_bus *bus){	memset (&bus->devmap, 0, sizeof(struct usb_devmap));	bus->devnum_next = 1;	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);}EXPORT_SYMBOL (usb_bus_init);/** * usb_alloc_bus - creates a new USB host controller structure * @op: pointer to a struct usb_operations that this bus structure should use * Context: !in_interrupt() * * Creates a USB host controller bus structure with the specified  * usb_operations and initializes all the necessary internal objects. * * If no memory is available, NULL is returned. * * The caller should call usb_put_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, 0, sizeof(struct usb_bus));	usb_bus_init (bus);	bus->op = op;	return bus;}EXPORT_SYMBOL (usb_alloc_bus);/*-------------------------------------------------------------------------*//** * usb_register_bus - registers the USB host controller with the usb core * @bus: pointer to the bus to register * Context: !in_interrupt() * * Assigns a bus number, and links the controller into usbcore data * structures so that it can be seen by scanning the bus list. */int usb_register_bus(struct usb_bus *bus){	int busnum;	int retval;	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 {		printk (KERN_ERR "%s: too many buses\n", usbcore_name);		up(&usb_bus_list_lock);		return -E2BIG;	}	snprintf(bus->class_dev.class_id, BUS_ID_SIZE, "usb%d", busnum);	bus->class_dev.class = &usb_host_class;	bus->class_dev.dev = bus->controller;	retval = class_device_register(&bus->class_dev);	if (retval) {		clear_bit(busnum, busmap.busmap);		up(&usb_bus_list_lock);		return retval;	}	/* Add it to the local list of buses */	list_add (&bus->bus_list, &usb_bus_list);	up (&usb_bus_list_lock);	usbfs_add_bus (bus);	dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum);	return 0;}EXPORT_SYMBOL (usb_register_bus);/** * usb_deregister_bus - deregisters the USB host controller * @bus: pointer to the bus to deregister * Context: !in_interrupt() * * Recycles the bus number, and unlinks the controller from usbcore data * structures so that it won't be seen by scanning the bus list. */void usb_deregister_bus (struct usb_bus *bus){	dev_info (bus->controller, "USB bus %d deregistered\n", 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);	usbfs_remove_bus (bus);	clear_bit (bus->busnum, busmap.busmap);	class_device_unregister(&bus->class_dev);}EXPORT_SYMBOL (usb_deregister_bus);/** * usb_register_root_hub - called by HCD to register its root hub  * @usb_dev: the usb root hub device to be registered. * @parent_dev: the parent device of this root hub. * * The USB host controller calls this function to register the root hub * properly with the USB subsystem.  It sets up the device properly in * the device tree and stores the root_hub pointer in the bus structure, * then calls usb_new_device() to register the usb device.  It also * assigns the root hub's USB address (always 1). */int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev){	const int devnum = 1;	int retval;	usb_dev->devnum = devnum;	usb_dev->bus->devnum_next = devnum + 1;	memset (&usb_dev->bus->devmap.devicemap, 0,			sizeof usb_dev->bus->devmap.devicemap);	set_bit (devnum, usb_dev->bus->devmap.devicemap);	usb_set_device_state(usb_dev, USB_STATE_ADDRESS);	down (&usb_bus_list_lock);	usb_dev->bus->root_hub = usb_dev;	usb_dev->epmaxpacketin[0] = usb_dev->epmaxpacketout[0] = 64;	retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);	if (retval != sizeof usb_dev->descriptor) {		usb_dev->bus->root_hub = NULL;		up (&usb_bus_list_lock);		dev_dbg (parent_dev, "can't read %s device descriptor %d\n",				usb_dev->dev.bus_id, retval);		return (retval < 0) ? retval : -EMSGSIZE;	}	down (&usb_dev->serialize);	retval = usb_new_device (usb_dev);	up (&usb_dev->serialize);	if (retval) {		usb_dev->bus->root_hub = NULL;		dev_err (parent_dev, "can't register root hub for %s, %d\n",				usb_dev->dev.bus_id, retval);	}	up (&usb_bus_list_lock);	return retval;}EXPORT_SYMBOL (usb_register_root_hub);

⌨️ 快捷键说明

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