工作一直在使用Vxworks7。现在有时间,学习一下Linux的UsbHost框架。
Linux内核版本:linux-4.8-rc3
ohci作为platform_driver注册
static int __init ohci_s3c2410_init(void)
{
if (usb_disabled())
return -ENODEV;
pr_info("%s: " DRIVER_DESC "\n", hcd_name);
ohci_init_driver(&ohci_s3c2410_hc_driver, NULL);
/*
* The Samsung HW has some unusual quirks, which require
* Sumsung-specific workarounds. We override certain hc_driver
* functions here to achieve that. We explicitly do not enhance
* ohci_driver_overrides to allow this more easily, since this
* is an unusual case, and we don't want to encourage others to
* override these functions by making it too easy.
*/
ohci_s3c2410_hc_driver.hub_status_data = ohci_s3c2410_hub_status_data;
ohci_s3c2410_hc_driver.hub_control = ohci_s3c2410_hub_control;
return platform_driver_register(&ohci_hcd_s3c2410_driver);
ohci_hcd_s3c2410_driver作为platform_driver实例,指定当与bus上相应的platform_device匹配后需要执行的probe函数。
ohci的platform_device在arch/arm/plat-samsumg/devs.c中定义
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 = {
.name = "s3c2410-ohci",
.pm = &ohci_hcd_s3c2410_pm_ops,
},
};
struct platform_device s3c_device_ohci = {
.name = "s3c2410-ohci",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_usb_resource),
.resource = s3c_usb_resource,
.dev = {
.dma_mask = &samsung_device_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
}
};
bus_match成功后,执行ohci_hcd_s3c2410_drv_probe函数进行驱动的加载。(这里使用了提前准备好的ohci_s3c2410_hc_driver实例,保存了用来创建usb_hcd实例时需要的各种资源)。
ohci_hcd_s3c2410_drv_probe->usb_hcd_s3c2410_probe
static int usb_hcd_s3c2410_probe(const struct hc_driver *driver,
struct platform_device *dev)
{
struct usb_hcd *hcd = NULL;
struct s3c2410_hcd_info *info = dev_get_platdata(&dev->dev);
int retval;
s3c2410_usb_set_power(info, 1, 1);
s3c2410_usb_set_power(info, 2, 1);
hcd = usb_create_hcd(driver, &dev->dev, "s3c24xx");
if (hcd == NULL)
return -ENOMEM;
hcd->rsrc_start = dev->resource[0].start; // 指向hc 的寄存器首地址0x49000000
hcd->rsrc_len = resource_size(&dev->resource[0]);
hcd->regs = devm_ioremap_resource(&dev->dev, &dev->resource[0]); // 转换为虚拟地址
if (IS_ERR(hcd->regs)) {
retval = PTR_ERR(hcd->regs);
goto err_put;
}
clk = devm_clk_get(&dev->dev, "usb-host");
if (IS_ERR(clk)) {
dev_err(&dev->dev, "cannot get usb-host clock\n");
retval = PTR_ERR(clk);
goto err_put;
}
usb_clk = devm_clk_get(&dev->dev, "usb-bus-host");
if (IS_ERR(usb_clk)) {
dev_err(&dev->dev, "cannot get usb-bus-host clock\n");
retval = PTR_ERR(usb_clk);
goto err_put;
}
s3c2410_start_hc(dev, hcd);
retval = usb_add_hcd(hcd, dev->resource[1].start, 0); //中断号26
if (retval != 0)
goto err_ioremap;
device_wakeup_enable(hcd->self.controller);
return 0;
err_ioremap:
s3c2410_stop_hc(dev);
err_put:
usb_put_hcd(hcd);
return retval;
}