USB设备主机侧驱动

从主机侧的观点去看,在linux驱动中,USB驱动处于最底层的是USB主机控制器硬件,在其上运行的是USB主机控制器驱动,主机控制器之上为usb核心层,再上层为usb设备驱动层。因此在主机侧的层次结构中,要实现的usb驱动包括两类:usb主机控制器驱动和usb设备驱动。前者控制插入其中的usb设备,后者控制usb设备如何与主机通信。

下面看看Linux下mini2440的主机侧的主机控制器驱动。mini2440的主机控制器是OHCI规格的。

通过虚拟平台的方式注册

platform_driver ohci_hcd_s3c2410_driver

static struct platform_driver ohci_hcd_s3c2410_driver = {
 .probe  = ohci_hcd_s3c2410_drv_probe,
 .remove  = ohci_hcd_s3c2410_drv_remove,
 .shutdown = usb_hcd_platform_shutdown,
 
 
 .driver  = {
  .owner = THIS_MODULE,
  .name = "s3c2410-ohci",
 },
};

探测函数:

其中struct hc_driver ohci_s3c2410_hc_driver 会作为探测函数的第一个参数传递给它。

static const struct hc_driver ohci_s3c2410_hc_driver = {
 .description =  hcd_name,
 .product_desc =  "S3C24XX OHCI",
 .hcd_priv_size = sizeof(struct ohci_hcd),


 .irq =   ohci_irq,
 .flags =  HCD_USB11 | HCD_MEMORY,


 .start =  ohci_s3c2410_start,
 .stop =   ohci_stop,
 .shutdown =  ohci_shutdown,


 .urb_enqueue =  ohci_urb_enqueue,
 .urb_dequeue =  ohci_urb_dequeue,
 .endpoint_disable = ohci_endpoint_disable,


 .get_frame_number = ohci_get_frame,


 .hub_status_data = ohci_s3c2410_hub_status_data,
 .hub_control =  ohci_s3c2410_hub_control,
#ifdef CONFIG_PM
 .bus_suspend =  ohci_bus_suspend,
 .bus_resume =  ohci_bus_resume,
#endif
 .start_port_reset = ohci_start_port_reset,
};

static int usb_hcd_s3c2410_probe (const struct hc_driver *driver,
      struct platform_device *dev)
{
 struct usb_hcd *hcd = NULL;
 int retval;

s3c2410_usb_set_power(dev->dev.platform_data, 1, 1);
 s3c2410_usb_set_power(dev->dev.platform_data, 2, 1);

hcd = usb_create_hcd(driver, &dev->dev, "s3c24xx");
 if (hcd == NULL)
  return -ENOMEM;

hcd->rsrc_start = dev->resource[0].start;
 hcd->rsrc_len   = dev->resource[0].end - dev->resource[0].start + 1;

if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
  dev_err(&dev->dev, "request_mem_region failed\n");
  retval = -EBUSY;
  goto err_put;
 }

clk = clk_get(&dev->dev, "usb-host");
 if (IS_ERR(clk)) {
  dev_err(&dev->dev, "cannot get usb-host clock\n");
  retval = -ENOENT;
  goto err_mem;
 }

usb_clk = clk_get(&dev->dev, "usb-bus-host");
 if (IS_ERR(usb_clk)) {
  dev_err(&dev->dev, "cannot get usb-bus-host clock\n");
  retval = -ENOENT;
  goto err_clk;
 }

s3c2410_start_hc(dev, hcd);

hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
 if (!hcd->regs) {
  dev_err(&dev->dev, "ioremap failed\n");
  retval = -ENOMEM;
  goto err_ioremap;
 }

ohci_hcd_init(hcd_to_ohci(hcd));

retval = usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED);
 if (retval != 0)
  goto err_ioremap;

return 0;

err_ioremap:
 s3c2410_stop_hc(dev);
 iounmap(hcd->regs);
 clk_put(usb_clk);

err_clk:
 clk_put(clk);

err_mem:
 release_mem_region(hcd->rsrc_start, hcd->rsrc_len);

err_put:
 usb_put_hcd(hcd);
 return retval;
}

在hc_driver中最重要的是红色字体的部分。上层通过usb_submit_urb()提交一个usb请求后,该函数调用usb_hcd_submit_urb(),并最终调用至usb_hcd的driver成员(hc_driver类型)的ubr_enqueue()。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwyxzx.html