mirror of
https://e.coding.net/weidongshan/linux/doc_and_source_for_drivers.git
synced 2025-11-28 19:11:03 +08:00
发布: 09_编写USB鼠标驱动程序
This commit is contained in:
131
IMX6ULL/doc_pic/12_USB/09_编写USB鼠标驱动程序.md
Normal file
131
IMX6ULL/doc_pic/12_USB/09_编写USB鼠标驱动程序.md
Normal file
@@ -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 驱动框架
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
对于GPIO按键,是直接构造、注册一个input_dev结构体,在GPIO中断函数里获得数据。
|
||||
|
||||
现在数据来源发生了变化,数据来自USB设备,需要做的事情是:
|
||||
|
||||
* 构造、注意usb_driver
|
||||
* usb_driver发现能支持是设备后,它的probe函数被调用:
|
||||
* 构造、注册input_dev结构体
|
||||
* 获得数据:
|
||||
* 构造、提交URB
|
||||
* 在URB的回调函数里,向Input系统上报数据
|
||||
|
||||
|
||||
|
||||
### 2.2 实现usb_driver
|
||||
|
||||
仿照usbmouse.c如下代码构造一个usb_driver结构体:
|
||||
|
||||

|
||||
|
||||
核心是:
|
||||
|
||||
* id_table:这个驱动能支持哪些设备
|
||||
* probe函数:发现能支持的设备后,probe函数记录设备信息、注册输入设备等等
|
||||
|
||||
|
||||
|
||||
#### 2.2.1 id_table
|
||||
|
||||
id_table是一个usb_device_id数组,示例如下:
|
||||
|
||||

|
||||
|
||||
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. 上机实验
|
||||
BIN
IMX6ULL/doc_pic/12_USB/09_编写USB鼠标驱动程序.tif
Normal file
BIN
IMX6ULL/doc_pic/12_USB/09_编写USB鼠标驱动程序.tif
Normal file
Binary file not shown.
BIN
IMX6ULL/doc_pic/12_USB/pic/64_usb_driver_example.png
Normal file
BIN
IMX6ULL/doc_pic/12_USB/pic/64_usb_driver_example.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.4 KiB |
BIN
IMX6ULL/doc_pic/12_USB/pic/65_usb_id_table.png
Normal file
BIN
IMX6ULL/doc_pic/12_USB/pic/65_usb_id_table.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.8 KiB |
BIN
IMX6ULL/doc_pic/12_USB/pic/66_usb_input_frame.png
Normal file
BIN
IMX6ULL/doc_pic/12_USB/pic/66_usb_input_frame.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 133 KiB |
67
IMX6ULL/source/12_USB/04_usbmouse_as_key/usbmouse_as_key.c
Normal file
67
IMX6ULL/source/12_USB/04_usbmouse_as_key/usbmouse_as_key.c
Normal file
@@ -0,0 +1,67 @@
|
||||
|
||||
/* 参考: drivers\hid\usbhid\usbmouse.c */
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
/* 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");
|
||||
|
||||
|
||||
@@ -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鼠标驱动程序
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
131
STM32MP157/doc_pic/12_USB/09_编写USB鼠标驱动程序.md
Normal file
131
STM32MP157/doc_pic/12_USB/09_编写USB鼠标驱动程序.md
Normal file
@@ -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 驱动框架
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
对于GPIO按键,是直接构造、注册一个input_dev结构体,在GPIO中断函数里获得数据。
|
||||
|
||||
现在数据来源发生了变化,数据来自USB设备,需要做的事情是:
|
||||
|
||||
* 构造、注意usb_driver
|
||||
* usb_driver发现能支持是设备后,它的probe函数被调用:
|
||||
* 构造、注册input_dev结构体
|
||||
* 获得数据:
|
||||
* 构造、提交URB
|
||||
* 在URB的回调函数里,向Input系统上报数据
|
||||
|
||||
|
||||
|
||||
### 2.2 实现usb_driver
|
||||
|
||||
仿照usbmouse.c如下代码构造一个usb_driver结构体:
|
||||
|
||||

|
||||
|
||||
核心是:
|
||||
|
||||
* id_table:这个驱动能支持哪些设备
|
||||
* probe函数:发现能支持的设备后,probe函数记录设备信息、注册输入设备等等
|
||||
|
||||
|
||||
|
||||
#### 2.2.1 id_table
|
||||
|
||||
id_table是一个usb_device_id数组,示例如下:
|
||||
|
||||

|
||||
|
||||
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. 上机实验
|
||||
BIN
STM32MP157/doc_pic/12_USB/09_编写USB鼠标驱动程序.tif
Normal file
BIN
STM32MP157/doc_pic/12_USB/09_编写USB鼠标驱动程序.tif
Normal file
Binary file not shown.
BIN
STM32MP157/doc_pic/12_USB/pic/64_usb_driver_example.png
Normal file
BIN
STM32MP157/doc_pic/12_USB/pic/64_usb_driver_example.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.4 KiB |
BIN
STM32MP157/doc_pic/12_USB/pic/65_usb_id_table.png
Normal file
BIN
STM32MP157/doc_pic/12_USB/pic/65_usb_id_table.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.8 KiB |
BIN
STM32MP157/doc_pic/12_USB/pic/66_usb_input_frame.png
Normal file
BIN
STM32MP157/doc_pic/12_USB/pic/66_usb_input_frame.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 133 KiB |
Reference in New Issue
Block a user