从主机侧的观点去看,在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()。
在ohci_hcd.c文件中实现了通用的ohci规格的主机控制器函数。
那么mini2440的主机控制器已经加到系统上去了,接下了就是usb设备驱动程序了。
这里所说的usb设备驱动指的是从主机角度观察的,怎么访问被插入的usb设备,而不是指usb设备内部本身运行的固件程序。linux系统实现了几类通用的usb设备驱动(也称客户驱动),划分为如下几个设备类:
音频设备类
通信设备类
HID设备类
显示设备类
海量存储设备类
电源设备类
打印设备类
集线器设备类
内核中提供了usb设备文件系统2.6为usbfs它和/pros类似。都是动态产生的。
可以输入命令 mount -t usbfs none /pros/bus/usb查看
正如tty_driver ,i2c_driver 等,linux内核中,使用usb_driver结构体描述一个usb设备驱动。
struct usb_driver {
const char *name;
int (*probe) (struct usb_interface *intf,
const struct usb_device_id *id);
void (*disconnect) (struct usb_interface *intf);
int (*ioctl) (struct usb_interface *intf, unsigned int code,
void *buf);
int (*suspend) (struct usb_interface *intf, pm_message_t message);
int (*resume) (struct usb_interface *intf);
int (*reset_resume)(struct usb_interface *intf);
int (*pre_reset)(struct usb_interface *intf);
int (*post_reset)(struct usb_interface *intf);
const struct usb_device_id *id_table;
struct usb_dynids dynids;
struct usbdrv_wrap drvwrap;
unsigned int no_dynamic_id:1;
unsigned int supports_autosuspend:1;
unsigned int soft_unbind:1;
};
在编写新的usb设备驱动程序时,主要完成的工作是probe()和disconnect()函数,即探测函数和断开函数,他们分别在设备被插入和拔出的时候被调用,用于初始化和释放软硬件资源。