hcd.c
来自「omap3 linux 2.6 用nocc去除了冗余代码」· C语言 代码 · 共 1,743 行 · 第 1/4 页
C
1,743 行
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; // always USB_DIR_IN, toward host memcpy (ubuf, bufp, len); /* report whether RH hardware supports remote wakeup */ if (patch_wakeup && len > offsetof (struct usb_config_descriptor, bmAttributes)) ((struct usb_config_descriptor *)ubuf)->bmAttributes |= USB_CONFIG_ATT_WAKEUP; } /* any errors get returned through the urb completion */ local_irq_save (flags); spin_lock (&urb->lock); if (urb->status == -EINPROGRESS) urb->status = status; spin_unlock (&urb->lock); usb_hcd_giveback_urb (hcd, urb); local_irq_restore (flags); return 0;}/*-------------------------------------------------------------------------*//* * Root Hub interrupt transfers are polled using a timer if the * driver requests it; otherwise the driver is responsible for * calling usb_hcd_poll_rh_status() when an event occurs. * * Completions are called in_interrupt(), but they may or may not * be in_irq(). */void usb_hcd_poll_rh_status(struct usb_hcd *hcd){ struct urb *urb; int length; unsigned long flags; char buffer[4]; /* Any root hubs with > 31 ports? */ if (unlikely(!hcd->rh_registered)) return; if (!hcd->uses_new_polling && !hcd->status_urb) return; length = hcd->driver->hub_status_data(hcd, buffer); if (length > 0) { /* try to complete the status urb */ local_irq_save (flags); spin_lock(&hcd_root_hub_lock); urb = hcd->status_urb; if (urb) { spin_lock(&urb->lock); if (urb->status == -EINPROGRESS) { hcd->poll_pending = 0; hcd->status_urb = NULL; urb->status = 0; urb->hcpriv = NULL; urb->actual_length = length; memcpy(urb->transfer_buffer, buffer, length); } else /* urb has been unlinked */ length = 0; spin_unlock(&urb->lock); } else length = 0; spin_unlock(&hcd_root_hub_lock); /* local irqs are always blocked in completions */ if (length > 0) usb_hcd_giveback_urb (hcd, urb); else hcd->poll_pending = 1; local_irq_restore (flags); } /* The USB 2.0 spec says 256 ms. This is close enough and won't * exceed that limit if HZ is 100. */ if (hcd->uses_new_polling ? hcd->poll_rh : (length == 0 && hcd->status_urb != NULL)) mod_timer (&hcd->rh_timer, jiffies + msecs_to_jiffies(250));}EXPORT_SYMBOL_GPL(usb_hcd_poll_rh_status);/* timer callback */static void rh_timer_func (unsigned long _hcd){ usb_hcd_poll_rh_status((struct usb_hcd *) _hcd);}/*-------------------------------------------------------------------------*/static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb){ int retval; unsigned long flags; int len = 1 + (urb->dev->maxchild / 8); spin_lock_irqsave (&hcd_root_hub_lock, flags); if (urb->status != -EINPROGRESS) /* already unlinked */ retval = urb->status; else if (hcd->status_urb || urb->transfer_buffer_length < len) { dev_dbg (hcd->self.controller, "not queuing rh status urb\n"); retval = -EINVAL; } else { hcd->status_urb = urb; urb->hcpriv = hcd; /* indicate it's queued */ if (!hcd->uses_new_polling) mod_timer (&hcd->rh_timer, jiffies + msecs_to_jiffies(250)); /* If a status change has already occurred, report it ASAP */ else if (hcd->poll_pending) mod_timer (&hcd->rh_timer, jiffies); retval = 0; } spin_unlock_irqrestore (&hcd_root_hub_lock, flags); return retval;}static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb){ if (usb_pipeint (urb->pipe)) return rh_queue_status (hcd, urb); if (usb_pipecontrol (urb->pipe)) return rh_call_control (hcd, urb); return -EINVAL;}/*-------------------------------------------------------------------------*//* Unlinks of root-hub control URBs are legal, but they don't do anything * since these URBs always execute synchronously. */static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb){ unsigned long flags; if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */ ; /* Do nothing */ } else { /* Status URB */ if (!hcd->uses_new_polling) del_timer (&hcd->rh_timer); local_irq_save (flags); spin_lock (&hcd_root_hub_lock); if (urb == hcd->status_urb) { hcd->status_urb = NULL; urb->hcpriv = NULL; } else urb = NULL; /* wasn't fully queued */ spin_unlock (&hcd_root_hub_lock); if (urb) usb_hcd_giveback_urb (hcd, urb); local_irq_restore (flags); } return 0;}/*-------------------------------------------------------------------------*/static struct class *usb_host_class;int usb_host_init(void){ int retval = 0; usb_host_class = class_create(THIS_MODULE, "usb_host"); if (IS_ERR(usb_host_class)) retval = PTR_ERR(usb_host_class); return retval;}void usb_host_cleanup(void){ class_destroy(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. */static 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->busnum = -1; bus->bandwidth_allocated = 0; bus->bandwidth_int_reqs = 0; bus->bandwidth_isoc_reqs = 0; INIT_LIST_HEAD (&bus->bus_list);}/*-------------------------------------------------------------------------*//** * 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. */static int usb_register_bus(struct usb_bus *bus){ int busnum; mutex_lock(&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); mutex_unlock(&usb_bus_list_lock); return -E2BIG; } bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0), bus->controller, "usb_host%d", busnum); if (IS_ERR(bus->class_dev)) { clear_bit(busnum, busmap.busmap); mutex_unlock(&usb_bus_list_lock); return PTR_ERR(bus->class_dev); } class_set_devdata(bus->class_dev, bus); /* Add it to the local list of buses */ list_add (&bus->bus_list, &usb_bus_list); mutex_unlock(&usb_bus_list_lock); usb_notify_add_bus(bus); dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum); return 0;}/** * 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. */static 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 */ mutex_lock(&usb_bus_list_lock); list_del (&bus->bus_list); mutex_unlock(&usb_bus_list_lock); usb_notify_remove_bus(bus); clear_bit (bus->busnum, busmap.busmap); class_device_unregister(bus->class_dev);}/** * register_root_hub - called by usb_add_hcd() to register a root hub * @hcd: host controller for this root hub * * This function registers the root hub with the USB subsystem. It sets up * the device properly in the device tree and then calls usb_new_device() * to register the usb device. It also assigns the root hub's USB address * (always 1). */static int register_root_hub(struct usb_hcd *hcd){ struct device *parent_dev = hcd->self.controller; struct usb_device *usb_dev = hcd->self.root_hub; 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); mutex_lock(&usb_bus_list_lock); usb_dev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64); retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE); if (retval != sizeof usb_dev->descriptor) { mutex_unlock(&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; } retval = usb_new_device (usb_dev); if (retval) { dev_err (parent_dev, "can't register root hub for %s, %d\n", usb_dev->dev.bus_id, retval); } mutex_unlock(&usb_bus_list_lock); if (retval == 0) { spin_lock_irq (&hcd_root_hub_lock); hcd->rh_registered = 1; spin_unlock_irq (&hcd_root_hub_lock); /* Did the HC die before the root hub was registered? */ if (hcd->state == HC_STATE_HALT) usb_hc_died (hcd); /* This time clean up */ } return retval;}void usb_enable_root_hub_irq (struct usb_bus *bus){ struct usb_hcd *hcd; hcd = container_of (bus, struct usb_hcd, self); if (hcd->driver->hub_irq_enable && hcd->state != HC_STATE_HALT) hcd->driver->hub_irq_enable (hcd);}/*-------------------------------------------------------------------------*//** * usb_calc_bus_time - approximate periodic transaction time in nanoseconds * @speed: from dev->speed; USB_SPEED_{LOW,FULL,HIGH} * @is_input: true iff the transaction sends data to the host * @isoc: true for isochronous transactions, false for interrupt ones * @bytecount: how many bytes in the transaction. * * Returns approximate bus time in nanoseconds for a periodic transaction. * See USB 2.0 spec section 5.11.3; only periodic transfers need to be * scheduled in software, this function is only used for such scheduling. */long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount){ unsigned long tmp; switch (speed) { case USB_SPEED_LOW: /* INTR only */ if (is_input) { tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L; return (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); } else { tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L; return (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?