开始
首先从内核中去掉鼠标驱动:
路径:Device Drivers —> HID Devices —> USB Human Interface Device (full HID) support
编写USB鼠标驱动
首先关于匹配信息:采用协议的方式匹配,也就是不按照厂商id和产品id进行匹配,而是只要使用该协议的设备都可以匹配成功。
编写usb_demo_drv.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include <linux/init.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/hid.h>
#define DRIVER_VERSION "v1.6"
#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
#define DRIVER_DESC "USB HID Boot Protocol mouse driver"
#define DRIVER_LICENSE "GPL"
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
static int pipe,maxp,count;
static signed char *data;
static struct urb *mouse_urb;
static dma_addr_t data_dma;
//下面是usb鼠标中断执行的函数
static void check_usb_data(struct urb *urb){
printk("count is %d time!\n",count++);
//每个usb_submit_urb检测一次,故在执行函数中提交可多次检测
usb_submit_urb(mouse_urb, GFP_KERNEL);
}
static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
struct usb_endpoint_descriptor *endpoint;
printk("usb mouse probe!\n");
//[可选]打印一些描述信息(一般用于匹配的东西)
//- [可选]产品信息:厂商id、产品id、版本
printk("dev->descriptor.idVendor is 0x%4x!\n",dev->descriptor.idVendor);
printk("dev->descriptor.idProduct is 0x%4x!\n",dev->descriptor.idProduct);
printk("dev->descriptor.bcdDevice is 0x%4x!\n",dev->descriptor.bcdDevice);
//- [可选]类、子类、协议
printk("intf->cur_altsetting->desc.bInterfaceClass is %d!\n",intf->cur_altsetting->desc.bInterfaceClass);
printk("intf->cur_altsetting->desc.bInterfaceSubClass is %d!\n",intf->cur_altsetting->desc.bInterfaceSubClass);
printk("intf->cur_altsetting->desc.bInterfaceProtocol is %d!\n",intf->cur_altsetting->desc.bInterfaceProtocol);
//下面是urb的使用
//首先是填充urb信息
endpoint = &intf->cur_altsetting->endpoint[0].desc;
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
data = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &data_dma);
mouse_urb = usb_alloc_urb(0, GFP_KERNEL);//申请urb
usb_fill_int_urb(mouse_urb, dev, pipe, data,(maxp > 8 ? 8 : maxp),check_usb_data, NULL, endpoint->bInterval);//填充urb
mouse_urb->transfer_dma = data_dma;
mouse_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
//然后提交urb进行检测,检测到后执行上面填充的函数check_usb_data
usb_submit_urb(mouse_urb, GFP_KERNEL);
//下面纯属测试的打印信息
//设备描述下的配置描述个数
printk("dev->descriptor.bNumConfigurations is %d!\n",dev->descriptor.bNumConfigurations);
//配置描述[0]下的接口描述个数
printk("dev->config[0].desc.bNumInterfaces is %d!\n",dev->config[0].desc.bNumInterfaces);
//当前配置描述下的接口描述个数
printk("dev->actconfig->desc.bNumInterfaces is %d!\n",dev->actconfig->desc.bNumInterfaces);
//当前接口描述下的端点描述个数
printk("intf->cur_altsetting->desc.bNumEndpoints is %d!\n",intf->cur_altsetting->desc.bNumEndpoints);
//端点[0]地址(注意:不是指0地址端点)
printk("intf->cur_altsetting->endpoint[0].desc.bEndpointAddress is 0x%x!\n",intf->cur_altsetting->endpoint[0].desc.bEndpointAddress);
return 0;
}
static void usb_mouse_disconnect(struct usb_interface *intf)
{
printk("usb mouse disconnect!\n");
}
static struct usb_device_id usb_mouse_id_table [] = {
{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_MOUSE) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);
static struct usb_driver usb_mouse_driver = {
.name = "usbmouse",
.probe = usb_mouse_probe,
.disconnect = usb_mouse_disconnect,
.id_table = usb_mouse_id_table,
};
static int __init usb_mouse_init(void)
{
return usb_register(&usb_mouse_driver);
}
static void __exit usb_mouse_exit(void)
{
usb_deregister(&usb_mouse_driver);
}
module_init(usb_mouse_init);
module_exit(usb_mouse_exit);
编写Makefile
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash
obj-m += usb_demo_drv.o
KDIR := /home/jerry/Projects/iTop4412_Kernel_3.0/
PWD ?= $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules
clean:
rm -rf *.o
进行测试
1、加载模块后的打印
2、插入usb鼠标后的打印
主控制器的打印信息(没有驱动或者匹配不成功也会打印):
匹配成功后的打印信息:
3、移动鼠标就会执行自定义的函数,稍微移动下鼠标就会有很多的打印
具体是移动的采样(大量)、每个按键点击释放均会执行一次。
4、拔出鼠标后会执行usb_mouse_disconnect函数