USB鼠标驱动简单示例

USB鼠标移动产生中断执行定义好的函数

Posted by Jerry Chen on September 2, 2019

开始

首先从内核中去掉鼠标驱动:

路径: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函数