歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> USB設備主機側驅動

USB設備主機側驅動

日期:2017/3/1 11:14:53   编辑:Linux編程

從主機側的觀點去看,在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()。

Copyright © Linux教程網 All Rights Reserved