📄 hcd.c
字号:
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 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 urb->status = hcd->driver->hub_control (hcd, typeReq, wValue, wIndex, ubuf, wLength); break;error: /* "protocol stall" on error */ urb->status = -EPIPE; } if (urb->status) { urb->actual_length = 0; if (urb->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, 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(). * * Note: some root hubs (including common UHCI based designs) can't * correctly issue port change IRQs. They're the ones that _need_ a * timer; most other root hubs don't. Some systems could save a * lot of battery power by eliminating these root hub timer IRQs. */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->transfer_buffer_length < len) { 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) == NULL) { spin_unlock (&urb->lock); local_irq_restore (flags); return; } /* complete the status urb, or retrigger the timer */ spin_lock (&hcd_data_lock); if (urb->dev->state == USB_STATE_CONFIGURED) { length = hcd->driver->hub_status_data ( hcd, urb->transfer_buffer); 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;}/*-------------------------------------------------------------------------*/static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb){ unsigned long flags; /* note: always a synchronous unlink */ if ((unsigned long) urb == hcd->rh_timer.data) { 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); } else if (usb_pipeendpoint(urb->pipe) == 0) { spin_lock_irq(&urb->lock); /* from usb_kill_urb */ ++urb->reject; spin_unlock_irq(&urb->lock); wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0); spin_lock_irq(&urb->lock); --urb->reject; spin_unlock_irq(&urb->lock); } else return -EINVAL; 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); class_device_initialize(&bus->class_dev); bus->class_dev.class = &usb_host_class;}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.dev = bus->controller; retval = class_device_add(&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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -