📄 hcd.c
字号:
// 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, NULL); 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 (!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, NULL); 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;}/*-------------------------------------------------------------------------*//* Asynchronous unlinks of root-hub control URBs are legal, but they * don't do anything. Status URB unlinks must be made in process context * with interrupts enabled. */static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb){ if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */ if (in_interrupt()) return 0; /* nothing to do */ 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 { /* Status URB */ if (!hcd->uses_new_polling) del_timer_sync (&hcd->rh_timer); local_irq_disable (); 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, NULL); local_irq_enable (); } return 0;}/*-------------------------------------------------------------------------*//* exported only within usbcore */struct usb_bus *usb_bus_get(struct usb_bus *bus){ if (bus) kref_get(&bus->kref); return bus;}static void usb_host_release(struct kref *kref){ struct usb_bus *bus = container_of(kref, struct usb_bus, kref); if (bus->release) bus->release(bus);}/* exported only within usbcore */void usb_bus_put(struct usb_bus *bus){ if (bus) kref_put(&bus->kref, usb_host_release);}/*-------------------------------------------------------------------------*/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->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); kref_init(&bus->kref);}/** * 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 = kzalloc (sizeof *bus, GFP_KERNEL); if (!bus) return NULL; usb_bus_init (bus); bus->op = op; return 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. */static int usb_register_bus(struct usb_bus *bus){ int busnum; 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; } 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); up(&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); up (&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 */ down (&usb_bus_list_lock); list_del (&bus->bus_list); up (&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 * @usb_dev: the usb root hub device to be registered. * @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 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). */static int register_root_hub (struct usb_device *usb_dev, struct usb_hcd *hcd){ struct device *parent_dev = hcd->self.controller; 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->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) { 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; } usb_lock_device (usb_dev); retval = usb_new_device (usb_dev); usb_unlock_device (usb_dev); 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); 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->poll_rh && 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); } case USB_SPEED_FULL: /* ISOC or INTR */ if (isoc) { tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; return (((is_input) ? 7268L : 6265L) + BW_HOST_DELAY + tmp); } else { tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; return (9107L + BW_HOST_DELAY + tmp); } case USB_SPEED_HIGH: /* ISOC or INTR */ // FIXME adjust for input vs output if (isoc) tmp = HS_NSECS_ISO (bytecount); else tmp = HS_NSECS (bytecount); return tmp; default: pr_debug ("%s: bogus device speed!\n", usbcore_name); return -1; }}EXPORT_SYMBOL (usb_calc_bus_time);/* * usb_check_bandwidth(): * * old_alloc is from host_controller->bandwidth_allocated in microseconds; * bustime is from calc_bus_time(), but converted to microseconds. * * returns <bustime in us> if successful, * or -ENOSPC if bandwidth request fails. * * FIXME: * This initial implementation does not use Endpoint.bInterval * in managing bandwidth allocation. * It probably needs to be expanded to use Endpoint.bInterval. * This can be done as a later enhancement (correction). * * This will also probably require some kind of * frame allocation tracking...meaning, for example, * that if multiple drivers request interrupts every 10 USB frames, * they don't all have to be allocated at * frame numbers N, N+10, N+20, etc. Some of them could be at * N+11, N+21, N+31, etc., and others at * N+12, N+22, N+32, etc. * * Similarly for isochronous transfers... * * Individual HCDs can schedule more directly ... this logic * is not correct for high speed transfers. */int usb_check_bandwidth (struct usb_device *dev, struct urb *urb){ unsigned int pipe = urb->pipe; long bustime; int is_in = usb_pipein (pipe);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -