USB 驱动(监测鼠标左键的动作)

(基于 Linux 3.4.2 内核)

可分为以下几个步骤来完成这个驱动:

1. 分配设置一个 usb_driver 结构体
2. 注册这个 usb_driver
(如果设备的 id_table 与驱动匹配的话会调用驱动程序的 probe 函数)
3. 在 probe 函数中分配 urb
4. 配置 urb
5. 调用 usb_submit_urb 启用 urb
6. 在 urb 中断函数内处理状态
7. 重新提交 urb

usb_driver 的配置与注册

/* 驱动的 id_table */
static struct usb_device_id usb_mouse_id_table [] = {
	{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
		USB_INTERFACE_PROTOCOL_MOUSE) },
	{ }
};

/* 分配设置 usb_driver */
static struct usb_driver mouse_monitor = {
	.name		= "MouseMonitor",
	.probe		= mouse_monitor_probe,
	.disconnect	= mouse_monitor_disconnect,
	.id_table		= usb_mouse_id_table,
};

/* 注册 usb_driver */
static int mouse_monitor_init(void)
{
	usb_register(&mouse_monitor);

	return 0;
}

probe 函数

static int mouse_monitor_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
	struct usb_host_interface *interface;
	struct usb_endpoint_descriptor *endpoint;
	static struct usb_device *dev;
	dma_addr_t usb_buf_phy;
	int pipe;
	int buffer_length;

    /* 得到 usb_device */
	dev = interface_to_usbdev(intf);

    /* 得到当前的接口描述符与端点描述符 */
	interface = intf->cur_altsetting;
	endpoint = &interface->endpoint[0].desc;

    /* 获取到设备数据长度 */
	buffer_length = __le16_to_cpu(endpoint->wMaxPacketSize);

	len = buffer_length;

    /* 获取到通信的管道 */
	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);

    /* 分配一段连贯的内存 */
	usb_buf = usb_alloc_coherent(dev, buffer_length, GFP_ATOMIC, &usb_buf_phy);

    /* 分配 urb */
	MouseUrb = usb_alloc_urb(0, GFP_KERNEL);

    /* 配置 urb */
	usb_fill_int_urb(MouseUrb, dev, pipe, usb_buf,  (buffer_length > 8 ? 8 : buffer_length), usb_complete, NULL, endpoint->bInterval);
	MouseUrb->transfer_dma = usb_buf_phy;
	MouseUrb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

    /* 提交调用 urb */
	usb_submit_urb(MouseUrb,  GFP_KERNEL);

	return 0;
}

urb 传输完成函数

static void usb_complete(struct urb *urb)
{
	static unsigned char presta;

#if 0
	int i;
	
	for (i = 0; i < len; i++)
		printk("%02x ", usb_buf[i]);

	printk("
");
#endif

	if(presta != (usb_buf[1] & 0x01)){
		if(presta)
			printk("BTN_LEFT is released. 
");
		else
			printk("BTN_LEFT is pressed. 
");
	}

    /* 保存状态 */
	presta = usb_buf[1] & 0x01;

    /* 重新提交 urb */
	usb_submit_urb(MouseUrb,  GFP_KERNEL);
}

usb_complete 函数中注释掉的程序为测试使用,通过输出的数据找到鼠标左键对应的 usb_buf 与 bit 位。

测试驱动

make menuconfig 去掉原来的 USB 鼠标驱动
-> Device Drivers 
  -> HID Devices
  <> USB Human Interface Device (full HID) support 

编译当前驱动,传入开发板并安装。

按下松开鼠标左键,现象如下:

原文地址:https://www.cnblogs.com/GyForever1004/p/8563332.html