zoukankan      html  css  js  c++  java
  • Linux USB 鼠标输入驱动具体解释

    平台:mini2440

    内核:linux 2.6.32.2

    USB设备插入时。内核会读取设备信息,接着就把id_table里的信息与读取到的信息做比較。看是否匹配,假设匹配。就调用probe函数。

    USB设备拔出时会调用disconnect函数。URB在USB设备驱动程序中用来描写叙述与USB设备通信时用到的基本载体和核心数据结构。

    URB(usb request block)处理流程:

        ①USB设备驱动程序创建并初始化一个訪问特定USB设备特定端点的urb并提交给USB core。

        ②USB core把这个urb提交到USB主控制器驱动程序。

        ③USB主控制器驱动程序依据该urb描写叙述的信息来訪问usb设备。

        ④当设备訪问结束后,USB主控制器驱动程序通知USB设备驱动程序。

    USB鼠标数据格式:

        ①bit0 ->左键,1->按下。0->松开

        ②bit1 ->右键,1->按下。0->松开

        ③bit2 ->中键,1->按下,0->松开

    驱动代码清单:

    usb_mouse_input_test.c:

    #include <linux/kernel.h>
    #include <linux/slab.h>
    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/usb/input.h>
    #include <linux/hid.h>
    
    static struct urb *uk_urb;
    static char       *usb_buf;
    static int        len;
    static struct     input_dev *uk_dev;
    static dma_addr_t usb_buf_phys;
    
    static struct usb_device_id usb_mouse_input_test_id_table [] = 
    {
    	{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, 
    			             USB_INTERFACE_SUBCLASS_BOOT,
    		                 USB_INTERFACE_PROTOCOL_MOUSE) 
    	}
    };
    
    static void usb_mouse_input_test_irq(struct urb *urb)
    {
    	static unsigned char pre_val;//USB鼠标将它的数据写到驱动缓冲区usb_buf
    	if ((pre_val & (1<<0)) != (usb_buf[0] & (1<<0)))
    	{
    		//状态变化
    		printk("left !
    ");
    	}
    
    	if ((pre_val & (1<<1)) != (usb_buf[0] & (1<<1)))
    	{
    		//状态变化
    		printk("right !
    ");
    	}
    
    	if ((pre_val & (1<<2)) != (usb_buf[0] & (1<<2)))
    	{
    		//状态变化
    		printk("middle !
    ");
    	}
    	
    	pre_val = usb_buf[0];
    	usb_submit_urb(uk_urb, GFP_KERNEL);
    }
    
    static int usb_mouse_input_test_probe(struct usb_interface *intf, const struct usb_device_id *id)
    {
    	struct usb_device *dev = interface_to_usbdev(intf);//获取usb接口结构体中的usb设备结构体
    	struct usb_host_interface *interface;
    	struct usb_endpoint_descriptor *endpoint;
    	int pipe;
    	
    	interface = intf->cur_altsetting; //获取usb接口结构体中的usb host接口结构体
    	endpoint = &interface->endpoint[0].desc;//获取usb host接口结构体中的端点描写叙述结构体
    	uk_dev = input_allocate_device();
    
    	set_bit(EV_KEY, uk_dev->evbit);//设置
    	set_bit(EV_REP, uk_dev->evbit);
    	set_bit(KEY_L, uk_dev->keybit);
    	set_bit(KEY_S, uk_dev->keybit);
    	set_bit(KEY_ENTER, uk_dev->keybit);
    	
    	input_register_device(uk_dev);//注冊
    	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
    	len = endpoint->wMaxPacketSize;
    	usb_buf = usb_buffer_alloc(dev, len, GFP_ATOMIC, &usb_buf_phys);
    	uk_urb = usb_alloc_urb(0, GFP_KERNEL);//分配usb request block
    	usb_fill_int_urb(uk_urb, dev, pipe, usb_buf, len, usb_mouse_input_test_irq, NULL, endpoint->bInterval);
    	uk_urb->transfer_dma = usb_buf_phys;  //源,目的。长度。设置URB
    	uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
    	usb_submit_urb(uk_urb, GFP_KERNEL);//把URB提交到USB主控制器驱动
    	
    	return 0;
    }
    
    static void usb_mouse_input_test_disconnect(struct usb_interface *intf)
    {
    	struct usb_device *dev = interface_to_usbdev(intf);
    	printk("disconnect mouse!
    ");
    	usb_kill_urb(uk_urb);
    	usb_free_urb(uk_urb);
    	usb_buffer_free(dev, len, usb_buf, usb_buf_phys);
    	input_unregister_device(uk_dev);
    	input_free_device(uk_dev);
    }
    
    static struct usb_driver usb_mouse_input_test_driver = {
    	.name		= "usb_mouse_input_test_",
    	.probe		= usb_mouse_input_test_probe,
    	.disconnect	= usb_mouse_input_test_disconnect,
    	.id_table	= usb_mouse_input_test_id_table,
    };
    
    static int usb_mouse_input_test_init(void)
    {
    	usb_register(&usb_mouse_input_test_driver);
    	return 0;
    }
    
    static void usb_mouse_input_test_exit(void)
    {
    	usb_deregister(&usb_mouse_input_test_driver);	
    }
    
    MODULE_LICENSE("GPL");
    module_init(usb_mouse_input_test_init);
    module_exit(usb_mouse_input_test_exit);
    

    Makefile:

    obj-m	+= usb_mouse_input_test.o
    
    KERN_DIR = /home/***/linux-2.6.32.2
    
    all:
    	make -C $(KERN_DIR) M=`pwd` modules 
    clean:
    	make -C $(KERN_DIR) M=`pwd` modules clean
    	rm -rf modules.order

    測试前去掉linux内核中鼠标功能:



    insmod usb_mouse_input_test.ko

    插入USB鼠标

    点击鼠标三个按键

    终端可见信息打印:

    left !

    right !

    middle !

  • 相关阅读:
    「模拟赛20180306」回忆树 memory LCA+KMP+AC自动机+树状数组
    python写一个通讯录
    Git学习笔记
    交换排序
    用Windows自带的方法创建WiFi
    MySQL之触发器
    插入排序
    range和arange的区别
    Spring前后端跨域请求设置
    三、图的定义及遍历
  • 原文地址:https://www.cnblogs.com/wzzkaifa/p/7289204.html
Copyright © 2011-2022 走看看