linux驱动之usb鼠标按键的读取

上一篇博文只是usb总线驱动程序的框架,下面来真正写一个usb驱动程序。

USB鼠标驱动,鼠标输入HID类型,其数据传输采用中断URB,鼠标端点类型为IN

目的:usb鼠标按键的驱动代码编写:

框架:

  1. 分配一个input_dev结构体
  2. 设置
  3. 注册
  4. 硬件相关的操作

思路:

1、分配/设置usb_driver结构体

static struct usb_driver usb_mouse_driver = {
	.name		= "usbmouse",
	.probe		= usb_mouse_probe,
	.disconnect	= usb_mouse_disconnect,
	.id_table	= usb_mouse_id_table,
};

a.这个结构体中有两个函数:1、dev和drv匹配之后会调用probe函数,2、usb鼠标拔出后会调用disconnect函数3、id_table 支持项

支持项中有三个匹配项:接口类,接口子类,接口协议

usb鼠标使用的支持项为:

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 */
};

b.大部分工作都在probe函数中完成,先写出usb_mouse_probe函数原型,逐渐完善它,我们truct usb_interface *intf, const struct usb_device_id *id)
static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
    return 0;
}
以上就是基本的框架,只要usb鼠标插上之后,就会调用 probe函数

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

下面完成具体的操作:

c、还是用输入子系统的套路:

  • 分配
  • 设置
  • 注册
  • 硬件的相关操作

c.1分配

static struct input_dev *um_dev;

um_dev = input_allocate_device();

这样就分配了一个input_dev结构体。

c.2设置

需要设置两方面的内容:1能产生哪些类事件,2能产生这个这些类里面的具体哪个事件。

	/*b.1能产生哪类事件*/
	set_bit(EV_KEY,um_dev->evbit);
	set_bit(EV_REP,um_dev->evbit);
	/*b.2能产生这类里面的哪些事件*/
	set_bit(KEY_L,um_dev->keybit);
	set_bit(KEY_S,um_dev->keybit);
	set_bit(KEY_ENTER,um_dev->keybit);

EV_KEY:按键事件。EV_REP:重复事件。

c.3注册

只需要注册 input_dev 结构体:

input_register_device(um_dev);

c.4硬件的相关操作

这个部分主要是设置数据的传输。数据传输围绕三个要素:源、目的、长度

源:

pipe = usb_rcvintpipe(dev,endpoint->bEndpointAddress);

根据中断端点获取源。

长度:

length = endpoint->wMaxPacketSize;
目的:

usb_buf = usb_buffer_alloc(dev,length,GFP_ATOMIC,&usb_buf_phys);

usb数据会存储在 usb_buf中。

d。使用这三个要素,完成最终的驱动程序-----》使用urb

urb处理流程:

  1. USB设备驱动程序创建并初始化一个访问特定USB设备特定端点的urb,并提交给USB core
  2. USB core提交该urb到到USB主控制器驱动程序。
  3. USB主控制器驱动程序根据该urb描述的信息,来访问usb设备
  4. 当设备访问结束后,USB的主控制器驱动程序通知USB设备驱动程序。

	um_urb = usb_alloc_urb(0,GFP_KERNEL);
	/*使用三要素设置 urb*/
	usb_fill_int_urb(um_urb, dev, pipe,usb_buf,length,
				 usb_mouse_irq, NULL, endpoint->bInterval);
	um_urb->transfer_dma = usb_buf_phys;
	um_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

	/*使用URB( 提交 urb)*/
	usb_submit_urb(um_urb,GFP_KERNEL);
说明1:

usb_alloc_urb(int iso_packets, gfp_t mem_flags);

iso_packets :是这个urb应当包含的等时数据包数目,若为0:表示不创建等时数据包。

mem_flags   :是分配内存的标志。

说明2:

对于中断urb,使用usb_fill_int_urb来初始化urb。函数定义如下:

static inline void usb_fill_int_urb(struct urb *urb,
                    struct usb_device *dev,      //指向这个urb要被发送的usb设备
                    unsigned int pipe,           //源
                    void *transfer_buffer,       //目的
                    int buffer_length,           //长度
                    usb_complete_t complete_fn,  //这个urb完成时,被调用的完成处理函数
                    void *context,               //完成处理函数的“上下文”
                    int interval)                //urb应当被调用的间隔

那么在完成处理函数中就可以完成我们想做的东西:

例如,打印 usb鼠标传回的数据

static void usb_mouse_irq(struct urb *urb)
{
	static unsigned char pre_val;

	int i;
	static int cnt =0;
	printk("data  cnt %d   ",++cnt);
	for(i=0;i<length;i++)
	{
		printk("%02x  ",usb_buf[i]);
	}
	printk("\n");
} 
这样,一个完整的驱动程序基本就写好了。完整的驱动代码,我会在后面使用csdncode 地址的形式给出

测试:

1、make menuconfig 去掉原来的usb鼠标驱动

     -> Device Drivers                                                                                                                                  
         -> HID Devices (HID_SUPPORT [=y]) 
2、make

3、使用新内核

4、加载驱动

5、可以使用 hexdump /dev/event1 查看  插入USB鼠标新生成的event

6、或者使用 cat /dev/tty1


完整驱动程序地址:csdncode 源码














發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章