土木在线论坛 \ 电气工程 \ 工业自动化 \ 嵌入式Linux USB驱动开发之教你一步步编写USB驱动程序

嵌入式Linux USB驱动开发之教你一步步编写USB驱动程序

发布于:2017-11-03 10:18:03 来自:电气工程/工业自动化 [复制转发]
编写与一个USB 设备驱动程序的方法和其他总线驱动方式类似,驱动程序把驱动程序对象注册到 USB 子系统中,稍后再使用制造商和设备标识来判断是否安装了硬件。当然,这些制造商和设备标识需要我们编写进 USB 驱动程序中。
USB 驱动程序依然遵循设备模型 —— 总线、设备、驱动。和 I2C 总线设备驱动编写一样,所有的 USB 驱动程序都必须创建的主要结构体是 struct usb_driver ,它们向 USB 核心代码描述了 USB 驱动程序。但这是个外壳,只是实现设备和总线的挂接,具体的 USB 设备是什么样的,如何实现的,比如一个字符设备,我们还需填写相应的文件操作接口 ,下面我们从外到里进行剖析,学习如何搭建这样的一个 USB 驱动外壳框架:
一、注册USB 驱动程序
Linux 的设备驱动,特别是这种 hotplug USB 设备驱动,会被编译成模块,然后在需要时挂在到内核。所以 USB 驱动和注册与正常的模块注册、卸载是一样的,下面是 USB 驱动的注册与卸载:
[cpp] view plain copy
1. static int __init usb_skel_init(void)
2. {
3. int result;
4. /* register this driver with the USB subsystem */
5. result = usb_register(&skel_driver);
6. if (result)
7. err("usb_register failed. Error number %d", result);
8.
9. return result;
10. }
11.
12. static void __exit usb_skel_exit(void)
13. {
14. /* deregister this driver with the USB subsystem */
15. usb_deregister(&skel_driver);
16. }
17.
18. module_init (usb_skel_init);
19. module_exit (usb_skel_exit);
20. MODULE_LICENSE("GPL");
USB 设备驱动的模块加载函数通用的方法是在 I2C 设备驱动的模块加载函数中使用 usb_register struct *usb_driver )函数添加 usb_driver 的工作 , 而在模块卸载函数中利用 usb_deregister struct *usb_driver )做相反的工作。 对比 I2C 设备驱动中的 i2c_add_driver(&i2c_driver) i2c_del_driver(&i2c_driver)
struct usb_driver USB 设备驱动 , 我们需要实现其成员函数:
[cpp] view plain copy
1. static struct usb_driver skel_driver = {
2. .owner = THIS_MODULE,
3. .name = "skeleton",
4. .id_table = skel_table,
5. .probe = skel_probe,
6. .disconnect = skel_disconnect,
7. };
从代码看来,usb_driver 需要初始化五个字段:
模块的所有者 THIS_MODULE
模块的名字 skeleton
probe 函数 skel_probe
disconnect 函数 skel_disconnect
id_table
最重要的当然是probe 函数与 disconnect 函数 , 这个在后面详细介绍,先谈一下 id_table
id_table struct usb_device_id 类型,包含了一列该驱动程序可以支持的所有不同类型的 USB 设备。如果没有设置该变量, USB 驱动程序中的探测回调该函数将不会被调用。对比 I2C struct i2c_device_id *id_table ,一个驱动程序可以对应多个设备, i2c 示例:
[cpp] view plain copy
1. static const struct i2c_device_id mpu6050_id[] = {
2. { "mpu6050", 0},
3. {}
4. };
usb 子系统通过设备的 production ID vendor ID 的组合或者设备的 class subclass protocol 的组合来识别设备,并调用相关的驱动程序作处理。我们可以看看这个 id_table 到底是什么东西:
[cpp] view plain copy
1. static struct usb_device_id skel_table [] = {
2. { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
3. { } /* Terminating entry */
4. };
5.
6. MODULE_DEVICE_TABLE (usb, skel_table);
MODULE_DEVICE_TABLE 的第一个参数是设备的类型,如果是 USB 设备,那自然是 usb 。后面一个参数是设备表,这个设备表的最后一个元素是空的,用于标识结束。代码定义了 USB_SKEL_VENDOR_ID 0xfff0 USB_SKEL_PRODUCT_ID 0xfff0 ,也就是说,当有一个设备接到集线器时, usb 子系统就会检查这个设备的 vendor ID product ID ,如果它们的值是 0xfff0 时,那么子系统就会调用这个 skeleton 模块作为设备的驱动。
USB 设备接到 USB 控制器接口时, usb_core 就检测该设备的一些信息,例如生产厂商 ID 和产品的 ID ,或者是设备所属的 class subclass protocol ,以便确定应该调用哪一个驱动处理该设备。
我们下面所要做的就是对probe 函数与 disconnect 函数的填充了,但是在对 probe 函数与 disconnect 函数填充之前,有必要先学习三个重要的数据结构,这在我们后面 probe 函数与 disconnect 函数中有很大的作用:
二、USB 驱动程序中重要数据结构
1usb-skeleton
usb-skeleton 是一个局部结构体,用于与端点进行通信。下面先看一下 Linux 内核源码中的一个 usb-skeleton (就是 usb 驱动的骨架咯),其定义的设备结构体就叫做 usb-skel
[cpp] view plain copy
1. struct usb_skel {
2. struct usb_device *udev; /* the usb device for this device */
3. struct usb_interface *interface; /* the interface for this device */
4. struct semaphore limit_sem; /* limiting the number of writes in progress */
5. unsigned char *bulk_in_buffer; /* the buffer to receive data */
6. size_t bulk_in_size; /* the size of the receive buffer */
7. __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */
8. __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */
9. struct kref kref;
10. };


这个家伙什么也没有留下。。。

工业自动化

返回版块

17.92 万条内容 · 352 人订阅

猜你喜欢

阅读下一篇

QB系列太阳能充放电控制器的几种充放电模式介绍 

QB系列太阳能充放电控制器的几种充放电模式介绍 .pdf

回帖成功

经验值 +10