• 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 
    

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

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

  • 相关阅读:
    Swift中的可选链与内存管理(干货系列)
    Swift中的类型转换
    Swift中类与结构的初始化
    Swift3中函数的使用
    Java常用的公共方法
    Eclipse中添加文档注释快捷键
    SVN服务器的搭建(三)
    SVN服务器的搭建(二)
    SVN服务器的搭建(一)
    多线程常见的例子
  • 原文地址:https://www.cnblogs.com/GyForever1004/p/8563332.html
Copyright © 2020-2023  润新知