Linux usb system(driver)
USB的应用用来用广泛了,键盘、鼠标、打印机、摄像头、网卡...而且传输的速度也越来越快,USB2.0的480MB/s,到USB3.0已经是USB2.0的十倍了。Linux中USB的内容实在是太多了,有兴趣的可以查看《Linux那些事兒之我是USB》这本书,这边对USB的驱动进行简要的说明和总结。
还是先看一下框架图,如下:
由图可知USB驱动的各个层次:
- USB主机控制器,位于/drivers/usb/host/下面,USB主机控制器接口标准有OHCI/UHCI/EHCI/XHCI等,对于嵌入式设备一般使用OHCI和XHCI。
- USB Core位于/drivers/usb/core/下,该层由内核实现,里面包含了最主要的功能,为设备驱动和主机控制器提供编程接口,各种功能组件的描述操作,设备热拔插、总线数据传输等。
- 设备驱动是按USB接口来实现,一个interface对应一个driver,一般通用的USB设备,如U盘、USB鼠标等都不需要再进行驱动编写,需要编写的是特定厂商、特定芯片的驱动。
- 在设备驱动的上面还有一层,用来对应特定的功能驱动,该部分在设备驱动probe的时候实现。如USB网卡,则需要Net层的驱动;USB视频接口,则需要video层的驱动;USB键盘接口,则需要 input_dev层的驱动。
1.控制器驱动
控制器驱动使用的还是platform总线进行的,platform_device
位于arch或dts里,如下:
static struct resource comcerto_usb3_resource[] = {
[0] = {
.start = COMCERTO_AXI_USB3P0_BASE,
.end = COMCERTO_AXI_USB3P0_BASE + SZ_8M - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_USB3,
.end = IRQ_USB3,
.flags = IORESOURCE_IRQ,
},
};
static u64 comcerto_usb3_dmamask = 0xfffff000;
struct platform_device comcerto_device_usb3 = {
.name = "xhci-hcd",
.id = -1,
.resource = comcerto_usb3_resource,
.num_resources = ARRAY_SIZE(comcerto_usb3_resource),
.dev = {
.dma_mask = &comcerto_usb3_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
};
#endif
platform_driver
位于/drivers/usb/host/里面,但是要看使用的是哪一种接口OHCI/XHCI,然后在对应的接口平台里面进行platform_driver
的注册,如下:
static struct platform_driver usb_xhci_driver = {
.probe = xhci_plat_probe,
.remove = xhci_plat_remove,
.driver = {
.name = "xhci-hcd",
},
};
MODULE_ALIAS("platform:xhci-hcd");
int xhci_register_plat(void)
{
return platform_driver_register(&usb_xhci_driver);
}
void xhci_unregister_plat(void)
{
platform_driver_unregister(&usb_xhci_driver);
}
probe函数会有很多关于hcd的操作,如usb_create_hcd()
、usb_add_hcd()
、usb_remove_hcd()
等,hcd是主机控制器的驱动程序,它位于USB主机控制器与USB系统软件之间。内核使用usb_hcd结构体描述USB主机控制器驱动,一个USB控制器的实现者必须提供一个支持它自己的控制器的主机控制器驱动器(HCD)实现。
2.设备器驱动
USB设备驱动的注册和卸载使用usb_register
和usb_deregister
,如下是键盘的设备驱动:
static struct usb_driver usb_kbd_driver = {
.name = "usbkbd",
.probe = usb_kbd_probe,
.disconnect = usb_kbd_disconnect,
.id_table = usb_kbd_id_table,
};
static int __init usb_kbd_init(void)
{
int result = usb_register(&usb_kbd_driver);
if (result == 0)
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
DRIVER_DESC "\n");
return result;
}
static void __exit usb_kbd_exit(void)
{
usb_deregister(&usb_kbd_driver);
}
module_init(usb_kbd_init);
module_exit(usb_kbd_exit);
usb_driver
最主要的就是probe()
和disconnect()
两个函数。
disconnect()
里面的处理比较简单,就是对应设备的卸载,这边说下probe()
函数:
上面说过一个接口对应一个驱动,USB数据的传输是通过端点endpoint实现的,连接端点需要pipe通道,所以probe()
函数的入口一定是usb_interface
,函数里面需要对interface、endpoint、usb_rcvintpipe进行处理;
USB接口的上层也要有对应的接口设备,这边是键盘,输入input设备,所以需要input_dev
设备的处理,使用input_register_device()
进行注册,使用input_unregister_device()
进行卸载。
这边大概看下usb_interface
结构体,位于/include/linux/usb.h
struct usb_interface {
/* array of alternate settings for this interface,
* stored in no particular order */
struct usb_host_interface *altsetting;
struct usb_host_interface *cur_altsetting; /* the currently
* active alternate setting */
unsigned num_altsetting; /* number of alternate settings */
...
struct device dev; /* interface specific device info */
struct device *usb_dev;
atomic_t pm_usage_cnt; /* usage counter for autosuspend */
struct work_struct reset_ws; /* for resets in atomic context */
}
里面包含usb_host_interface
结构体,位于/include/linux/usb.h
struct usb_host_interface {
struct usb_interface_descriptor desc;
/* array of desc.bNumEndpoint endpoints associated with this
* interface setting. these will be in no particular order.
*/
struct usb_host_endpoint *endpoint;
char *string; /* iInterface string, if present */
unsigned char *extra; /* Extra descriptors */
int extralen;
};
里面包含usb_interface_descriptor
和usb_host_endpoint
结构体,位于/include/linux/usb.h
struct usb_host_endpoint {
struct usb_endpoint_descriptor desc;
struct usb_ss_ep_comp_descriptor ss_ep_comp;
struct list_head urb_list;
void *hcpriv;
struct ep_device *ep_dev; /* For sysfs info */
unsigned char *extra; /* Extra descriptors */
int extralen;
int enabled;
};
里面包含usb_endpoint_descriptor
结构体,所以一个设备驱动下面会包含interface和endpoint的所有信息。
在usb_host_endpoint
下面有一个成员urb_list,这边就又引入了urb一个知识点,这边先不做介绍,后期进行学习整理后在进行介绍。
几个常用USB设备的驱动所在位置:
- U盘的驱动位于/drivers/usb/storage/下;
- USB键盘和鼠标的驱动位于/drivers/hid/usbhid/下;
- USB打印机的驱动位于/drivers/usb/class/usblp.c下;
Linux usb system(driver)的分析就到这边,有感悟时会持续会更新。
注:以上内容都是本人在学习过程积累的一些心得,难免会有参考到其他文章的一些知识,如有侵权,请及时通知我,我将及时删除或标注内容出处,如有错误之处也请指出,进行探讨学习。文章只是起一个引导作用,详细的数据解析内容还请查看Linux相关教程,感谢您的查阅。