hcd.c
来自「linux 内核源代码」· C语言 代码 · 共 1,882 行 · 第 1/4 页
C
1,882 行
/* 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 */ spin_lock_irq(&hcd_root_hub_lock); usb_hcd_unlink_urb_from_ep(hcd, urb); /* This peculiar use of spinlocks echoes what real HC drivers do. * Avoiding calls to local_irq_disable/enable makes the code * RT-friendly. */ spin_unlock(&hcd_root_hub_lock); usb_hcd_giveback_urb(hcd, urb, status); spin_lock(&hcd_root_hub_lock); spin_unlock_irq(&hcd_root_hub_lock); 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 */ spin_lock_irqsave(&hcd_root_hub_lock, flags); urb = hcd->status_urb; if (urb) { hcd->poll_pending = 0; hcd->status_urb = NULL; urb->actual_length = length; memcpy(urb->transfer_buffer, buffer, length); usb_hcd_unlink_urb_from_ep(hcd, urb); spin_unlock(&hcd_root_hub_lock); usb_hcd_giveback_urb(hcd, urb, 0); spin_lock(&hcd_root_hub_lock); } else { length = 0; hcd->poll_pending = 1; } spin_unlock_irqrestore(&hcd_root_hub_lock, flags); } /* The USB 2.0 spec says 256 ms. This is close enough and won't * exceed that limit if HZ is 100. The math is more clunky than * maybe expected, this is to make sure that all timers for USB devices * fire at the same time to give the CPU a break inbetween */ if (hcd->uses_new_polling ? hcd->poll_rh : (length == 0 && hcd->status_urb != NULL)) mod_timer (&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));}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 (hcd->status_urb || urb->transfer_buffer_length < len) { dev_dbg (hcd->self.controller, "not queuing rh status urb\n"); retval = -EINVAL; goto done; } retval = usb_hcd_link_urb_to_ep(hcd, urb); if (retval) goto done; hcd->status_urb = urb; urb->hcpriv = hcd; /* indicate it's queued */ if (!hcd->uses_new_polling) mod_timer(&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4)); /* If a status change has already occurred, report it ASAP */ else if (hcd->poll_pending) mod_timer(&hcd->rh_timer, jiffies); retval = 0; done: spin_unlock_irqrestore (&hcd_root_hub_lock, flags); return retval;}static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb){ if (usb_endpoint_xfer_int(&urb->ep->desc)) return rh_queue_status (hcd, urb); if (usb_endpoint_xfer_control(&urb->ep->desc)) 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, int status){ unsigned long flags; int rc; spin_lock_irqsave(&hcd_root_hub_lock, flags); rc = usb_hcd_check_unlink_urb(hcd, urb, status); if (rc) goto done; if (usb_endpoint_num(&urb->ep->desc) == 0) { /* Control URB */ ; /* Do nothing */ } else { /* Status URB */ if (!hcd->uses_new_polling) del_timer (&hcd->rh_timer); if (urb == hcd->status_urb) { hcd->status_urb = NULL; usb_hcd_unlink_urb_from_ep(hcd, urb); spin_unlock(&hcd_root_hub_lock); usb_hcd_giveback_urb(hcd, urb, status); spin_lock(&hcd_root_hub_lock); } } done: spin_unlock_irqrestore(&hcd_root_hub_lock, flags); return rc;}/* * Show & store the current value of authorized_default */static ssize_t usb_host_authorized_default_show(struct device *dev, struct device_attribute *attr, char *buf){ struct usb_device *rh_usb_dev = to_usb_device(dev); struct usb_bus *usb_bus = rh_usb_dev->bus; struct usb_hcd *usb_hcd; if (usb_bus == NULL) /* FIXME: not sure if this case is possible */ return -ENODEV; usb_hcd = bus_to_hcd(usb_bus); return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default);}static ssize_t usb_host_authorized_default_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size){ ssize_t result; unsigned val; struct usb_device *rh_usb_dev = to_usb_device(dev); struct usb_bus *usb_bus = rh_usb_dev->bus; struct usb_hcd *usb_hcd; if (usb_bus == NULL) /* FIXME: not sure if this case is possible */ return -ENODEV; usb_hcd = bus_to_hcd(usb_bus); result = sscanf(buf, "%u\n", &val); if (result == 1) { usb_hcd->authorized_default = val? 1 : 0; result = size; } else result = -EINVAL; return result;}static DEVICE_ATTR(authorized_default, 0644, usb_host_authorized_default_show, usb_host_authorized_default_store);/* Group all the USB bus attributes */static struct attribute *usb_bus_attrs[] = { &dev_attr_authorized_default.attr, NULL,};static struct attribute_group usb_bus_attr_group = { .name = NULL, /* we want them in the same directory */ .attrs = usb_bus_attrs,};/*-------------------------------------------------------------------------*/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 result = -E2BIG; int busnum; mutex_lock(&usb_bus_list_lock); busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1); if (busnum >= USB_MAXBUS) { printk (KERN_ERR "%s: too many buses\n", usbcore_name); goto error_find_busnum; } set_bit (busnum, busmap.busmap); bus->busnum = busnum; bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0), bus->controller, "usb_host%d", busnum); result = PTR_ERR(bus->class_dev); if (IS_ERR(bus->class_dev)) goto error_create_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;error_create_class_dev: clear_bit(busnum, busmap.busmap);error_find_busnum: mutex_unlock(&usb_bus_list_lock); return result;}/** * 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;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?