📄 dummy_hcd.c
字号:
total = transfer (dum, urb, ep, limit); break; } /* incomplete transfer? */ if (urb->status == -EINPROGRESS) continue;return_urb: urb->hcpriv = NULL; list_del (&urbp->urbp_list); kfree (urbp); if (ep) ep->already_seen = ep->setup_stage = 0; spin_unlock (&dum->lock); usb_hcd_giveback_urb (dummy_to_hcd(dum), urb, NULL); spin_lock (&dum->lock); goto restart; } if (list_empty (&dum->urbp_list)) { usb_put_dev (dum->udev); dum->udev = NULL; } else if (dum->rh_state == DUMMY_RH_RUNNING) { /* want a 1 msec delay here */ mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1)); } spin_unlock_irqrestore (&dum->lock, flags);}/*-------------------------------------------------------------------------*/#define PORT_C_MASK \ ((USB_PORT_STAT_C_CONNECTION \ | USB_PORT_STAT_C_ENABLE \ | USB_PORT_STAT_C_SUSPEND \ | USB_PORT_STAT_C_OVERCURRENT \ | USB_PORT_STAT_C_RESET) << 16)static int dummy_hub_status (struct usb_hcd *hcd, char *buf){ struct dummy *dum; unsigned long flags; int retval = 0; dum = hcd_to_dummy (hcd); spin_lock_irqsave (&dum->lock, flags); if (hcd->state != HC_STATE_RUNNING) goto done; if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) { dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); dum->port_status &= ~USB_PORT_STAT_SUSPEND; set_link_state (dum); } if ((dum->port_status & PORT_C_MASK) != 0) { *buf = (1 << 1); dev_dbg (dummy_dev(dum), "port status 0x%08x has changes\n", dum->port_status); retval = 1; if (dum->rh_state == DUMMY_RH_SUSPENDED) usb_hcd_resume_root_hub (hcd); }done: spin_unlock_irqrestore (&dum->lock, flags); return retval;}static inline voidhub_descriptor (struct usb_hub_descriptor *desc){ memset (desc, 0, sizeof *desc); desc->bDescriptorType = 0x29; desc->bDescLength = 9; desc->wHubCharacteristics = (__force __u16) (__constant_cpu_to_le16 (0x0001)); desc->bNbrPorts = 1; desc->bitmap [0] = 0xff; desc->bitmap [1] = 0xff;}static int dummy_hub_control ( struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { struct dummy *dum; int retval = 0; unsigned long flags; if (hcd->state != HC_STATE_RUNNING) return -ETIMEDOUT; dum = hcd_to_dummy (hcd); spin_lock_irqsave (&dum->lock, flags); switch (typeReq) { case ClearHubFeature: break; case ClearPortFeature: switch (wValue) { case USB_PORT_FEAT_SUSPEND: if (dum->port_status & USB_PORT_STAT_SUSPEND) { /* 20msec resume signaling */ dum->resuming = 1; dum->re_timeout = jiffies + msecs_to_jiffies(20); } break; case USB_PORT_FEAT_POWER: if (dum->port_status & USB_PORT_STAT_POWER) dev_dbg (dummy_dev(dum), "power-off\n"); /* FALLS THROUGH */ default: dum->port_status &= ~(1 << wValue); set_link_state (dum); } break; case GetHubDescriptor: hub_descriptor ((struct usb_hub_descriptor *) buf); break; case GetHubStatus: *(__le32 *) buf = __constant_cpu_to_le32 (0); break; case GetPortStatus: if (wIndex != 1) retval = -EPIPE; /* whoever resets or resumes must GetPortStatus to * complete it!! */ if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) { dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); dum->port_status &= ~USB_PORT_STAT_SUSPEND; } if ((dum->port_status & USB_PORT_STAT_RESET) != 0 && time_after_eq (jiffies, dum->re_timeout)) { dum->port_status |= (USB_PORT_STAT_C_RESET << 16); dum->port_status &= ~USB_PORT_STAT_RESET; if (dum->pullup) { dum->port_status |= USB_PORT_STAT_ENABLE; /* give it the best speed we agree on */ dum->gadget.speed = dum->driver->speed; dum->gadget.ep0->maxpacket = 64; switch (dum->gadget.speed) { case USB_SPEED_HIGH: dum->port_status |= USB_PORT_STAT_HIGH_SPEED; break; case USB_SPEED_LOW: dum->gadget.ep0->maxpacket = 8; dum->port_status |= USB_PORT_STAT_LOW_SPEED; break; default: dum->gadget.speed = USB_SPEED_FULL; break; } } } set_link_state (dum); ((__le16 *) buf)[0] = cpu_to_le16 (dum->port_status); ((__le16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16); break; case SetHubFeature: retval = -EPIPE; break; case SetPortFeature: switch (wValue) { case USB_PORT_FEAT_SUSPEND: if (dum->active) { dum->port_status |= USB_PORT_STAT_SUSPEND; /* HNP would happen here; for now we * assume b_bus_req is always true. */ set_link_state (dum); if (((1 << USB_DEVICE_B_HNP_ENABLE) & dum->devstatus) != 0) dev_dbg (dummy_dev(dum), "no HNP yet!\n"); } break; case USB_PORT_FEAT_POWER: dum->port_status |= USB_PORT_STAT_POWER; set_link_state (dum); break; case USB_PORT_FEAT_RESET: /* if it's already enabled, disable */ dum->port_status &= ~(USB_PORT_STAT_ENABLE | USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED); dum->devstatus = 0; /* 50msec reset signaling */ dum->re_timeout = jiffies + msecs_to_jiffies(50); /* FALLS THROUGH */ default: if ((dum->port_status & USB_PORT_STAT_POWER) != 0) { dum->port_status |= (1 << wValue); set_link_state (dum); } } break; default: dev_dbg (dummy_dev(dum), "hub control req%04x v%04x i%04x l%d\n", typeReq, wValue, wIndex, wLength); /* "protocol stall" on error */ retval = -EPIPE; } spin_unlock_irqrestore (&dum->lock, flags); if ((dum->port_status & PORT_C_MASK) != 0) usb_hcd_poll_rh_status (hcd); return retval;}static int dummy_bus_suspend (struct usb_hcd *hcd){ struct dummy *dum = hcd_to_dummy (hcd); spin_lock_irq (&dum->lock); dum->rh_state = DUMMY_RH_SUSPENDED; set_link_state (dum); spin_unlock_irq (&dum->lock); return 0;}static int dummy_bus_resume (struct usb_hcd *hcd){ struct dummy *dum = hcd_to_dummy (hcd); spin_lock_irq (&dum->lock); dum->rh_state = DUMMY_RH_RUNNING; set_link_state (dum); if (!list_empty(&dum->urbp_list)) mod_timer (&dum->timer, jiffies); spin_unlock_irq (&dum->lock); return 0;}/*-------------------------------------------------------------------------*/static inline ssize_tshow_urb (char *buf, size_t size, struct urb *urb){ int ep = usb_pipeendpoint (urb->pipe); return snprintf (buf, size, "urb/%p %s ep%d%s%s len %d/%d\n", urb, ({ char *s; switch (urb->dev->speed) { case USB_SPEED_LOW: s = "ls"; break; case USB_SPEED_FULL: s = "fs"; break; case USB_SPEED_HIGH: s = "hs"; break; default: s = "?"; break; }; s; }), ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "", ({ char *s; \ switch (usb_pipetype (urb->pipe)) { \ case PIPE_CONTROL: s = ""; break; \ case PIPE_BULK: s = "-bulk"; break; \ case PIPE_INTERRUPT: s = "-int"; break; \ default: s = "-iso"; break; \ }; s;}), urb->actual_length, urb->transfer_buffer_length);}static ssize_tshow_urbs (struct device *dev, struct device_attribute *attr, char *buf){ struct usb_hcd *hcd = dev_get_drvdata (dev); struct dummy *dum = hcd_to_dummy (hcd); struct urbp *urbp; size_t size = 0; unsigned long flags; spin_lock_irqsave (&dum->lock, flags); list_for_each_entry (urbp, &dum->urbp_list, urbp_list) { size_t temp; temp = show_urb (buf, PAGE_SIZE - size, urbp->urb); buf += temp; size += temp; } spin_unlock_irqrestore (&dum->lock, flags); return size;}static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL);static int dummy_start (struct usb_hcd *hcd){ struct dummy *dum; dum = hcd_to_dummy (hcd); /* * MASTER side init ... we emulate a root hub that'll only ever * talk to one device (the slave side). Also appears in sysfs, * just like more familiar pci-based HCDs. */ spin_lock_init (&dum->lock); init_timer (&dum->timer); dum->timer.function = dummy_timer; dum->timer.data = (unsigned long) dum; dum->rh_state = DUMMY_RH_RUNNING; INIT_LIST_HEAD (&dum->urbp_list); /* only show a low-power port: just 8mA */ hcd->power_budget = 8; hcd->state = HC_STATE_RUNNING; hcd->uses_new_polling = 1;#ifdef CONFIG_USB_OTG hcd->self.otg_port = 1;#endif /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */ device_create_file (dummy_dev(dum), &dev_attr_urbs); return 0;}static void dummy_stop (struct usb_hcd *hcd){ struct dummy *dum; dum = hcd_to_dummy (hcd); device_remove_file (dummy_dev(dum), &dev_attr_urbs); usb_gadget_unregister_driver (dum->driver); dev_info (dummy_dev(dum), "stopped\n");}/*-------------------------------------------------------------------------*/static int dummy_h_get_frame (struct usb_hcd *hcd){ return dummy_g_get_frame (NULL);}static const struct hc_driver dummy_hcd = { .description = (char *) driver_name, .product_desc = "Dummy host controller", .hcd_priv_size = sizeof(struct dummy), .flags = HCD_USB2, .start = dummy_start, .stop = dummy_stop, .urb_enqueue = dummy_urb_enqueue, .urb_dequeue = dummy_urb_dequeue, .get_frame_number = dummy_h_get_frame, .hub_status_data = dummy_hub_status, .hub_control = dummy_hub_control, .bus_suspend = dummy_bus_suspend, .bus_resume = dummy_bus_resume,};static int dummy_hcd_probe (struct platform_device *dev){ struct usb_hcd *hcd; int retval; dev_info(&dev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc); hcd = usb_create_hcd (&dummy_hcd, &dev->dev, dev->dev.bus_id); if (!hcd) return -ENOMEM; the_controller = hcd_to_dummy (hcd); retval = usb_add_hcd(hcd, 0, 0); if (retval != 0) { usb_put_hcd (hcd); the_controller = NULL; } return retval;}static int dummy_hcd_remove (struct platform_device *dev){ struct usb_hcd *hcd; hcd = platform_get_drvdata (dev); usb_remove_hcd (hcd); usb_put_hcd (hcd); the_controller = NULL; return 0;}static int dummy_hcd_suspend (struct platform_device *dev, pm_message_t state){ struct usb_hcd *hcd; dev_dbg (&dev->dev, "%s\n", __FUNCTION__); hcd = platform_get_drvdata (dev); hcd->state = HC_STATE_SUSPENDED; return 0;}static int dummy_hcd_resume (struct platform_device *dev){ struct usb_hcd *hcd; dev_dbg (&dev->dev, "%s\n", __FUNCTION__); hcd = platform_get_drvdata (dev); hcd->state = HC_STATE_RUNNING; usb_hcd_poll_rh_status (hcd); return 0;}static struct platform_driver dummy_hcd_driver = { .probe = dummy_hcd_probe, .remove = dummy_hcd_remove, .suspend = dummy_hcd_suspend, .resume = dummy_hcd_resume, .driver = { .name = (char *) driver_name, .owner = THIS_MODULE, },};/*-------------------------------------------------------------------------*//* These don't need to do anything because the pdev structures are * statically allocated. */static voiddummy_udc_release (struct device *dev) {}static voiddummy_hcd_release (struct device *dev) {}static struct platform_device the_udc_pdev = { .name = (char *) gadget_name, .id = -1, .dev = { .release = dummy_udc_release, },};static struct platform_device the_hcd_pdev = { .name = (char *) driver_name, .id = -1, .dev = { .release = dummy_hcd_release, },};static int __init init (void){ int retval; if (usb_disabled ()) return -ENODEV; retval = platform_driver_register (&dummy_hcd_driver); if (retval < 0) return retval; retval = platform_driver_register (&dummy_udc_driver); if (retval < 0) goto err_register_udc_driver; retval = platform_device_register (&the_hcd_pdev); if (retval < 0) goto err_register_hcd; retval = platform_device_register (&the_udc_pdev); if (retval < 0) goto err_register_udc; return retval;err_register_udc: platform_device_unregister (&the_hcd_pdev);err_register_hcd: platform_driver_unregister (&dummy_udc_driver);err_register_udc_driver: platform_driver_unregister (&dummy_hcd_driver); return retval;}module_init (init);static void __exit cleanup (void){ platform_device_unregister (&the_udc_pdev); platform_device_unregister (&the_hcd_pdev); platform_driver_unregister (&dummy_udc_driver); platform_driver_unregister (&dummy_hcd_driver);}module_exit (cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -