diff --git a/IMX6ULL/doc_pic/12_USB/09_编写USB鼠标驱动程序.md b/IMX6ULL/doc_pic/12_USB/09_编写USB鼠标驱动程序.md new file mode 100644 index 0000000..913e41a --- /dev/null +++ b/IMX6ULL/doc_pic/12_USB/09_编写USB鼠标驱动程序.md @@ -0,0 +1,131 @@ +# 编写USB鼠标驱动程序 # + +参考资料: + +* Linux内核源码:`include\linux\usb.h` + +* Linux内核源码:`drivers\hid\usbhid\usbmouse.c` + +* 本视频源码在GIT仓库如下位置: + + ```c + doc_and_source_for_drivers\IMX6ULL\source\12_USB\04_usbmouse_as_key + ``` + + + + +## 1. 目标 + +使用鼠标模拟按键:左键相当于"L"、右键相当于"S"、"中键"相当于 "回车"。 + + + +## 2. 编程 + +### 2.1 驱动框架 + +![image-20221011095909341](pic/66_usb_input_frame.png) + + + +对于GPIO按键,是直接构造、注册一个input_dev结构体,在GPIO中断函数里获得数据。 + +现在数据来源发生了变化,数据来自USB设备,需要做的事情是: + +* 构造、注意usb_driver +* usb_driver发现能支持是设备后,它的probe函数被调用: + * 构造、注册input_dev结构体 +* 获得数据: + * 构造、提交URB + * 在URB的回调函数里,向Input系统上报数据 + + + +### 2.2 实现usb_driver + +仿照usbmouse.c如下代码构造一个usb_driver结构体: + +![image-20221011091940453](pic/64_usb_driver_example.png) + +核心是: + +* id_table:这个驱动能支持哪些设备 +* probe函数:发现能支持的设备后,probe函数记录设备信息、注册输入设备等等 + + + +#### 2.2.1 id_table + +id_table是一个usb_device_id数组,示例如下: + +![image-20221011092207138](pic/65_usb_id_table.png) + +usb_device_id结构体定义如下: + +* match_flags:表示要比较哪些信息,可以比较设备ID、DeviceClass、InterfaceClass等等 +* 根据match_flags提供其他信息:比如设备ID、DeviceClass、InterfaceClass等等 +* driver_info:驱动程序可能用到的一些信息 + +```c +struct usb_device_id { + /* which fields to match against? */ + __u16 match_flags; + + /* Used for product specific matches; range is inclusive */ + __u16 idVendor; + __u16 idProduct; + __u16 bcdDevice_lo; + __u16 bcdDevice_hi; + + /* Used for device class matches */ + __u8 bDeviceClass; + __u8 bDeviceSubClass; + __u8 bDeviceProtocol; + + /* Used for interface class matches */ + __u8 bInterfaceClass; + __u8 bInterfaceSubClass; + __u8 bInterfaceProtocol; + + /* Used for vendor-specific interface matches */ + __u8 bInterfaceNumber; + + /* not matched against */ + kernel_ulong_t driver_info + __attribute__((aligned(sizeof(kernel_ulong_t)))); +}; +``` + + + +#### 2.2.2 probe函数 + +probe函数原型如下: + +```c +int (*probe) (struct usb_interface *intf, + const struct usb_device_id *id); +``` + +第1个参数是"struct usb_interface *"类型,表示匹配到的"USB逻辑设备"。 + +第2个参数是"struct usb_device_id *"类型,它是usb_driver的id_table中的某项,表示第1个参数就是跟这个usb_device_id匹配的。有必要的话,probe函数里可以从id->driver_info得到驱动相关的一些信息。 + +在probe函数,一般要记录intf信息,以后发起USB传输时会用到intf信息。 + + + +### 2.3 实现输入设备 + +核心是:分配、设置、注册一个input_device结构体。 + + + +### 2.4 实现数据传输 + +分配、填充、提交URB,在URB的回调函数里上报"input_event"。 + + + +## 3. 上机实验 \ No newline at end of file diff --git a/IMX6ULL/doc_pic/12_USB/09_编写USB鼠标驱动程序.tif b/IMX6ULL/doc_pic/12_USB/09_编写USB鼠标驱动程序.tif new file mode 100644 index 0000000..b7d393c Binary files /dev/null and b/IMX6ULL/doc_pic/12_USB/09_编写USB鼠标驱动程序.tif differ diff --git a/IMX6ULL/doc_pic/12_USB/pic/64_usb_driver_example.png b/IMX6ULL/doc_pic/12_USB/pic/64_usb_driver_example.png new file mode 100644 index 0000000..932bb4b Binary files /dev/null and b/IMX6ULL/doc_pic/12_USB/pic/64_usb_driver_example.png differ diff --git a/IMX6ULL/doc_pic/12_USB/pic/65_usb_id_table.png b/IMX6ULL/doc_pic/12_USB/pic/65_usb_id_table.png new file mode 100644 index 0000000..4d67ceb Binary files /dev/null and b/IMX6ULL/doc_pic/12_USB/pic/65_usb_id_table.png differ diff --git a/IMX6ULL/doc_pic/12_USB/pic/66_usb_input_frame.png b/IMX6ULL/doc_pic/12_USB/pic/66_usb_input_frame.png new file mode 100644 index 0000000..b667e70 Binary files /dev/null and b/IMX6ULL/doc_pic/12_USB/pic/66_usb_input_frame.png differ diff --git a/IMX6ULL/source/12_USB/04_usbmouse_as_key/usbmouse_as_key.c b/IMX6ULL/source/12_USB/04_usbmouse_as_key/usbmouse_as_key.c new file mode 100644 index 0000000..1203f4f --- /dev/null +++ b/IMX6ULL/source/12_USB/04_usbmouse_as_key/usbmouse_as_key.c @@ -0,0 +1,67 @@ + +/* 参考: drivers\hid\usbhid\usbmouse.c */ +#include +#include +#include +#include +#include + +/* 1. 构造usb_driver + * 1.1 id_table : 能支持哪些设备 + * 1.2 probe : 记录某些信息, 分配/设置/注册input_dev, 也许"分配/填充/提交URB" + */ + +static struct usb_device_id usb_mouse_as_key_id_table [] = { + { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, + USB_INTERFACE_PROTOCOL_MOUSE), .driver_info = (kernel_ulong_t)"it is a mouse", }, + { } /* Terminating entry */ +}; + + +static int usb_mouse_as_key_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + /* 1. 记录设备信息: intf */ + /* 2. 分配/设置/注册input_dev + * 2.1 能产生哪类事件 + * 2.2 能产生这类事件里哪些些事件: L/S/ENTER + * 2.3 设置函数, 比如open + * 2.4 在open函数里: 分配/填充/提交 URB + * 2.5 URB的回调函数: 解析数据, 上报input_event + */ + + return 0; +} + +static void usb_mouse_as_key_disconnect(struct usb_interface *intf) +{ +} + + +static struct usb_driver usb_mouse_as_key_driver = { + .name = "usbmouse_as_key", + .probe = usb_mouse_as_key_probe, + .disconnect = usb_mouse_as_key_disconnect, + .id_table = usb_mouse_as_key_id_table, +}; + +/* 入口函数 / 出口函数 */ +// module_usb_driver(usb_mouse_as_key_driver); +static int __init usb_mouse_as_key__init(void) +{ + return usb_register(&usb_mouse_as_key_driver); +} + +static void __exit usb_mouse_as_key__init_exit(void) +{ + usb_deregister(&usb_mouse_as_key_driver); +} + +module_init(usb_mouse_as_key__init); +module_exit(usb_mouse_as_key__init_exit); + + +/* 2. 注册usb_driver */ + +MODULE_LICENSE("GPL"); + + diff --git a/README.md b/README.md index 3fbceb5..0e617ad 100644 --- a/README.md +++ b/README.md @@ -688,6 +688,12 @@ git clone https://e.coding.net/weidongshan/linux/doc_and_source_for_drivers.git 08_USB设备驱动模型 ``` +* 2022.10.11 发布"USB子系统" + + ```shell + 09_编写USB鼠标驱动程序 + ``` + diff --git a/STM32MP157/doc_pic/12_USB/09_编写USB鼠标驱动程序.md b/STM32MP157/doc_pic/12_USB/09_编写USB鼠标驱动程序.md new file mode 100644 index 0000000..913e41a --- /dev/null +++ b/STM32MP157/doc_pic/12_USB/09_编写USB鼠标驱动程序.md @@ -0,0 +1,131 @@ +# 编写USB鼠标驱动程序 # + +参考资料: + +* Linux内核源码:`include\linux\usb.h` + +* Linux内核源码:`drivers\hid\usbhid\usbmouse.c` + +* 本视频源码在GIT仓库如下位置: + + ```c + doc_and_source_for_drivers\IMX6ULL\source\12_USB\04_usbmouse_as_key + ``` + + + + +## 1. 目标 + +使用鼠标模拟按键:左键相当于"L"、右键相当于"S"、"中键"相当于 "回车"。 + + + +## 2. 编程 + +### 2.1 驱动框架 + +![image-20221011095909341](pic/66_usb_input_frame.png) + + + +对于GPIO按键,是直接构造、注册一个input_dev结构体,在GPIO中断函数里获得数据。 + +现在数据来源发生了变化,数据来自USB设备,需要做的事情是: + +* 构造、注意usb_driver +* usb_driver发现能支持是设备后,它的probe函数被调用: + * 构造、注册input_dev结构体 +* 获得数据: + * 构造、提交URB + * 在URB的回调函数里,向Input系统上报数据 + + + +### 2.2 实现usb_driver + +仿照usbmouse.c如下代码构造一个usb_driver结构体: + +![image-20221011091940453](pic/64_usb_driver_example.png) + +核心是: + +* id_table:这个驱动能支持哪些设备 +* probe函数:发现能支持的设备后,probe函数记录设备信息、注册输入设备等等 + + + +#### 2.2.1 id_table + +id_table是一个usb_device_id数组,示例如下: + +![image-20221011092207138](pic/65_usb_id_table.png) + +usb_device_id结构体定义如下: + +* match_flags:表示要比较哪些信息,可以比较设备ID、DeviceClass、InterfaceClass等等 +* 根据match_flags提供其他信息:比如设备ID、DeviceClass、InterfaceClass等等 +* driver_info:驱动程序可能用到的一些信息 + +```c +struct usb_device_id { + /* which fields to match against? */ + __u16 match_flags; + + /* Used for product specific matches; range is inclusive */ + __u16 idVendor; + __u16 idProduct; + __u16 bcdDevice_lo; + __u16 bcdDevice_hi; + + /* Used for device class matches */ + __u8 bDeviceClass; + __u8 bDeviceSubClass; + __u8 bDeviceProtocol; + + /* Used for interface class matches */ + __u8 bInterfaceClass; + __u8 bInterfaceSubClass; + __u8 bInterfaceProtocol; + + /* Used for vendor-specific interface matches */ + __u8 bInterfaceNumber; + + /* not matched against */ + kernel_ulong_t driver_info + __attribute__((aligned(sizeof(kernel_ulong_t)))); +}; +``` + + + +#### 2.2.2 probe函数 + +probe函数原型如下: + +```c +int (*probe) (struct usb_interface *intf, + const struct usb_device_id *id); +``` + +第1个参数是"struct usb_interface *"类型,表示匹配到的"USB逻辑设备"。 + +第2个参数是"struct usb_device_id *"类型,它是usb_driver的id_table中的某项,表示第1个参数就是跟这个usb_device_id匹配的。有必要的话,probe函数里可以从id->driver_info得到驱动相关的一些信息。 + +在probe函数,一般要记录intf信息,以后发起USB传输时会用到intf信息。 + + + +### 2.3 实现输入设备 + +核心是:分配、设置、注册一个input_device结构体。 + + + +### 2.4 实现数据传输 + +分配、填充、提交URB,在URB的回调函数里上报"input_event"。 + + + +## 3. 上机实验 \ No newline at end of file diff --git a/STM32MP157/doc_pic/12_USB/09_编写USB鼠标驱动程序.tif b/STM32MP157/doc_pic/12_USB/09_编写USB鼠标驱动程序.tif new file mode 100644 index 0000000..b7d393c Binary files /dev/null and b/STM32MP157/doc_pic/12_USB/09_编写USB鼠标驱动程序.tif differ diff --git a/STM32MP157/doc_pic/12_USB/pic/64_usb_driver_example.png b/STM32MP157/doc_pic/12_USB/pic/64_usb_driver_example.png new file mode 100644 index 0000000..932bb4b Binary files /dev/null and b/STM32MP157/doc_pic/12_USB/pic/64_usb_driver_example.png differ diff --git a/STM32MP157/doc_pic/12_USB/pic/65_usb_id_table.png b/STM32MP157/doc_pic/12_USB/pic/65_usb_id_table.png new file mode 100644 index 0000000..4d67ceb Binary files /dev/null and b/STM32MP157/doc_pic/12_USB/pic/65_usb_id_table.png differ diff --git a/STM32MP157/doc_pic/12_USB/pic/66_usb_input_frame.png b/STM32MP157/doc_pic/12_USB/pic/66_usb_input_frame.png new file mode 100644 index 0000000..b667e70 Binary files /dev/null and b/STM32MP157/doc_pic/12_USB/pic/66_usb_input_frame.png differ