📄 hcd.c
字号:
dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n", "resume", status); usb_hc_died(hcd); } return status;}/* * usb_hcd_suspend_root_hub - HCD autosuspends downstream ports * @hcd: host controller for this root hub * * This call arranges that usb_hcd_resume_root_hub() is safe to call later; * that the HCD's root hub polling is deactivated; and that the root's hub * driver is suspended. HCDs may call this to autosuspend when their root * hub's downstream ports are all inactive: unpowered, disconnected, * disabled, or suspended. * * The HCD will autoresume on device connect change detection (using SRP * or a D+/D- pullup). The HCD also autoresumes on remote wakeup signaling * from any ports that are suspended (if that is enabled). In most cases, * overcurrent signaling (on powered ports) will also start autoresume. * * Always called with IRQs blocked. */void usb_hcd_suspend_root_hub (struct usb_hcd *hcd){ struct urb *urb; spin_lock (&hcd_root_hub_lock); usb_suspend_root_hub (hcd->self.root_hub); /* force status urb to complete/unlink while suspended */ if (hcd->status_urb) { urb = hcd->status_urb; urb->status = -ECONNRESET; urb->hcpriv = NULL; urb->actual_length = 0; del_timer (&hcd->rh_timer); hcd->poll_pending = 0; hcd->status_urb = NULL; } else urb = NULL; spin_unlock (&hcd_root_hub_lock); hcd->state = HC_STATE_SUSPENDED; if (urb) usb_hcd_giveback_urb (hcd, urb, NULL);}EXPORT_SYMBOL_GPL(usb_hcd_suspend_root_hub);/** * usb_hcd_resume_root_hub - called by HCD to resume its root hub * @hcd: host controller for this root hub * * The USB host controller calls this function when its root hub is * suspended (with the remote wakeup feature enabled) and a remote * wakeup request is received. It queues a request for khubd to * resume the root hub (that is, manage its downstream ports again). */void usb_hcd_resume_root_hub (struct usb_hcd *hcd){ unsigned long flags; spin_lock_irqsave (&hcd_root_hub_lock, flags); if (hcd->rh_registered) usb_resume_root_hub (hcd->self.root_hub); spin_unlock_irqrestore (&hcd_root_hub_lock, flags);}EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);#endif/*-------------------------------------------------------------------------*/#ifdef CONFIG_USB_OTG/** * usb_bus_start_enum - start immediate enumeration (for OTG) * @bus: the bus (must use hcd framework) * @port_num: 1-based number of port; usually bus->otg_port * Context: in_interrupt() * * Starts enumeration, with an immediate reset followed later by * khubd identifying and possibly configuring the device. * This is needed by OTG controller drivers, where it helps meet * HNP protocol timing requirements for starting a port reset. */int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num){ struct usb_hcd *hcd; int status = -EOPNOTSUPP; /* NOTE: since HNP can't start by grabbing the bus's address0_sem, * boards with root hubs hooked up to internal devices (instead of * just the OTG port) may need more attention to resetting... */ hcd = container_of (bus, struct usb_hcd, self); if (port_num && hcd->driver->start_port_reset) status = hcd->driver->start_port_reset(hcd, port_num); /* run khubd shortly after (first) root port reset finishes; * it may issue others, until at least 50 msecs have passed. */ if (status == 0) mod_timer(&hcd->rh_timer, jiffies + msecs_to_jiffies(10)); return status;}EXPORT_SYMBOL (usb_bus_start_enum);#endif/*-------------------------------------------------------------------------*//* * usb_hcd_operations - adapts usb_bus framework to HCD framework (bus glue) */static struct usb_operations usb_hcd_operations = { .get_frame_number = hcd_get_frame_number, .submit_urb = hcd_submit_urb, .unlink_urb = hcd_unlink_urb, .buffer_alloc = hcd_buffer_alloc, .buffer_free = hcd_buffer_free, .disable = hcd_endpoint_disable,};/*-------------------------------------------------------------------------*//** * usb_hcd_giveback_urb - return URB from HCD to device driver * @hcd: host controller returning the URB * @urb: urb being returned to the USB device driver. * @regs: pt_regs, passed down to the URB completion handler * Context: in_interrupt() * * This hands the URB from HCD to its USB device driver, using its * completion function. The HCD has freed all per-urb resources * (and is done using urb->hcpriv). It also released all HCD locks; * the device driver won't cause problems if it frees, modifies, * or resubmits this URB. */void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs){ int at_root_hub; at_root_hub = (urb->dev == hcd->self.root_hub); urb_unlink (urb); /* lower level hcd code should use *_dma exclusively */ if (hcd->self.controller->dma_mask && !at_root_hub) { if (usb_pipecontrol (urb->pipe) && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) dma_unmap_single (hcd->self.controller, urb->setup_dma, sizeof (struct usb_ctrlrequest), DMA_TO_DEVICE); if (urb->transfer_buffer_length != 0 && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) dma_unmap_single (hcd->self.controller, urb->transfer_dma, urb->transfer_buffer_length, usb_pipein (urb->pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } usbmon_urb_complete (&hcd->self, urb); /* pass ownership to the completion handler */ urb->complete (urb, regs); atomic_dec (&urb->use_count); if (unlikely (urb->reject)) wake_up (&usb_kill_urb_queue); usb_put_urb (urb);}EXPORT_SYMBOL (usb_hcd_giveback_urb);/*-------------------------------------------------------------------------*//** * usb_hcd_irq - hook IRQs to HCD framework (bus glue) * @irq: the IRQ being raised * @__hcd: pointer to the HCD whose IRQ is being signaled * @r: saved hardware registers * * If the controller isn't HALTed, calls the driver's irq handler. * Checks whether the controller is now dead. */irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r){ struct usb_hcd *hcd = __hcd; int start = hcd->state; if (unlikely(start == HC_STATE_HALT || !test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) return IRQ_NONE; if (hcd->driver->irq (hcd, r) == IRQ_NONE) return IRQ_NONE; set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); if (unlikely(hcd->state == HC_STATE_HALT)) usb_hc_died (hcd); return IRQ_HANDLED;}/*-------------------------------------------------------------------------*//** * usb_hc_died - report abnormal shutdown of a host controller (bus glue) * @hcd: pointer to the HCD representing the controller * * This is called by bus glue to report a USB host controller that died * while operations may still have been pending. It's called automatically * by the PCI glue, so only glue for non-PCI busses should need to call it. */void usb_hc_died (struct usb_hcd *hcd){ unsigned long flags; dev_err (hcd->self.controller, "HC died; cleaning up\n"); spin_lock_irqsave (&hcd_root_hub_lock, flags); if (hcd->rh_registered) { hcd->poll_rh = 0; /* make khubd clean up old urbs and devices */ usb_set_device_state (hcd->self.root_hub, USB_STATE_NOTATTACHED); usb_kick_khubd (hcd->self.root_hub); } spin_unlock_irqrestore (&hcd_root_hub_lock, flags);}EXPORT_SYMBOL_GPL (usb_hc_died);/*-------------------------------------------------------------------------*/static void hcd_release (struct usb_bus *bus){ struct usb_hcd *hcd; hcd = container_of(bus, struct usb_hcd, self); kfree(hcd);}/** * usb_create_hcd - create and initialize an HCD structure * @driver: HC driver that will use this hcd * @dev: device for this HC, stored in hcd->self.controller * @bus_name: value to store in hcd->self.bus_name * Context: !in_interrupt() * * Allocate a struct usb_hcd, with extra space at the end for the * HC driver's private data. Initialize the generic members of the * hcd structure. * * If memory is unavailable, returns NULL. */struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, struct device *dev, char *bus_name){ struct usb_hcd *hcd; hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL); if (!hcd) { dev_dbg (dev, "hcd alloc failed\n"); return NULL; } dev_set_drvdata(dev, hcd); usb_bus_init(&hcd->self); hcd->self.op = &usb_hcd_operations; hcd->self.hcpriv = hcd; hcd->self.release = &hcd_release; hcd->self.controller = dev; hcd->self.bus_name = bus_name; init_timer(&hcd->rh_timer); hcd->rh_timer.function = rh_timer_func; hcd->rh_timer.data = (unsigned long) hcd; hcd->driver = driver; hcd->product_desc = (driver->product_desc) ? driver->product_desc : "USB Host Controller"; return hcd;}EXPORT_SYMBOL (usb_create_hcd);void usb_put_hcd (struct usb_hcd *hcd){ dev_set_drvdata(hcd->self.controller, NULL); usb_bus_put(&hcd->self);}EXPORT_SYMBOL (usb_put_hcd);/** * usb_add_hcd - finish generic HCD structure initialization and register * @hcd: the usb_hcd structure to initialize * @irqnum: Interrupt line to allocate * @irqflags: Interrupt type flags * * Finish the remaining parts of generic HCD initialization: allocate the * buffers of consistent memory, register the bus, request the IRQ line, * and call the driver's reset() and start() routines. */int usb_add_hcd(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags){ int retval; struct usb_device *rhdev; dev_info(hcd->self.controller, "%s\n", hcd->product_desc); set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); /* till now HC has been in an indeterminate state ... */ if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) { dev_err(hcd->self.controller, "can't reset\n"); return retval; } if ((retval = hcd_buffer_create(hcd)) != 0) { dev_dbg(hcd->self.controller, "pool alloc failed\n"); return retval; } if ((retval = usb_register_bus(&hcd->self)) < 0) goto err_register_bus; if (hcd->driver->irq) { char buf[8], *bufp = buf;#ifdef __sparc__ bufp = __irq_itoa(irqnum);#else sprintf(buf, "%d", irqnum);#endif snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d", hcd->driver->description, hcd->self.busnum); if ((retval = request_irq(irqnum, &usb_hcd_irq, irqflags, hcd->irq_descr, hcd)) != 0) { dev_err(hcd->self.controller, "request interrupt %s failed\n", bufp); goto err_request_irq; } hcd->irq = irqnum; dev_info(hcd->self.controller, "irq %s, %s 0x%08llx\n", bufp, (hcd->driver->flags & HCD_MEMORY) ? "io mem" : "io base", (unsigned long long)hcd->rsrc_start); } else { hcd->irq = -1; if (hcd->rsrc_start) dev_info(hcd->self.controller, "%s 0x%08llx\n", (hcd->driver->flags & HCD_MEMORY) ? "io mem" : "io base", (unsigned long long)hcd->rsrc_start); } /* Allocate the root hub before calling hcd->driver->start(), * but don't register it until afterward so that the hardware * is running. */ if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) { dev_err(hcd->self.controller, "unable to allocate root hub\n"); retval = -ENOMEM; goto err_allocate_root_hub; } rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH : USB_SPEED_FULL; /* Although in principle hcd->driver->start() might need to use rhdev, * none of the current drivers do. */ if ((retval = hcd->driver->start(hcd)) < 0) { dev_err(hcd->self.controller, "startup error %d\n", retval); goto err_hcd_driver_start; } /* hcd->driver->start() reported can_wakeup, probably with * assistance from board's boot firmware. * NOTE: normal devices won't enable wakeup by default. */ if (hcd->can_wakeup) dev_dbg(hcd->self.controller, "supports USB remote wakeup\n"); hcd->remote_wakeup = hcd->can_wakeup; if ((retval = register_root_hub(rhdev, hcd)) != 0) goto err_register_root_hub; if (hcd->uses_new_polling && hcd->poll_rh) usb_hcd_poll_rh_status(hcd); return retval; err_register_root_hub: hcd->driver->stop(hcd); err_hcd_driver_start: usb_put_dev(rhdev); err_allocate_root_hub: if (hcd->irq >= 0) free_irq(irqnum, hcd); err_request_irq: usb_deregister_bus(&hcd->self); err_register_bus: hcd_buffer_destroy(hcd); return retval;} EXPORT_SYMBOL (usb_add_hcd);/** * usb_remove_hcd - shutdown processing for generic HCDs * @hcd: the usb_hcd structure to remove * Context: !in_interrupt() * * Disconnects the root hub, then reverses the effects of usb_add_hcd(), * invoking the HCD's stop() method. */void usb_remove_hcd(struct usb_hcd *hcd){ dev_info(hcd->self.controller, "remove, state %x\n", hcd->state); if (HC_IS_RUNNING (hcd->state)) hcd->state = HC_STATE_QUIESCING; dev_dbg(hcd->self.controller, "roothub graceful disconnect\n"); spin_lock_irq (&hcd_root_hub_lock); hcd->rh_registered = 0; spin_unlock_irq (&hcd_root_hub_lock); usb_disconnect(&hcd->self.root_hub); hcd->poll_rh = 0; del_timer_sync(&hcd->rh_timer); hcd->driver->stop(hcd); hcd->state = HC_STATE_HALT; if (hcd->irq >= 0) free_irq(hcd->irq, hcd); usb_deregister_bus(&hcd->self); hcd_buffer_destroy(hcd);}EXPORT_SYMBOL (usb_remove_hcd);/*-------------------------------------------------------------------------*/#if defined(CONFIG_USB_MON)struct usb_mon_operations *mon_ops;/* * The registration is unlocked. * We do it this way because we do not want to lock in hot paths. * * Notice that the code is minimally error-proof. Because usbmon needs * symbols from usbcore, usbcore gets referenced and cannot be unloaded first. */ int usb_mon_register (struct usb_mon_operations *ops){ if (mon_ops) return -EBUSY; mon_ops = ops; mb(); return 0;}EXPORT_SYMBOL_GPL (usb_mon_register);void usb_mon_deregister (void){ if (mon_ops == NULL) { printk(KERN_ERR "USB: monitor was not registered\n"); return; } mon_ops = NULL; mb();}EXPORT_SYMBOL_GPL (usb_mon_deregister);#endif /* CONFIG_USB_MON */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -