当前位置: 首页 > news >正文

USB设备驱动代码分析(鼠标)

定义鼠标ID表

static struct usb_device_id usbmouse_as_key_id_table [] = {{USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,USB_INTERFACE_PROTOCOL_MOUSE)}, {}
};

这段代码是用于定义一个 USB 鼠标设备的 ID 表。它使用了 Linux 内核中的 usb_device_id 结构,其中包含了 USB 设备的类、子类和协议信息。

这个ID表定义了USB接口,其类别为HID(Human Interface Device),子类别为BOOT(表示鼠标设备),协议为MOUSE(表示鼠标协议)。这个表示在Linux内核的USB驱动中使用,可以匹配对应类型的USB设备,并进行相应的操作。在最后添加一个空结构表示结束符。

中断处理函数

static void usbmouse_as_key_irq(struct urb* urb) {static unsigned char pre_val;if ((pre_val & (1 << 0)) != (usb_buf[0] & (1 << 0))) {input_event(uk_dev, EV_KEY, KEY_L, (usb_buf[0] & (1 << 0)) ? 1 : 0);input_sync(uk_dev);}if ((pre_val & (1 << 1)) != (usb_buf[0] & (1 << 1))) {input_event(uk_dev, EV_KEY, KEY_S, (usb_buf[0] & (1 << 1)) ? 1 : 0);input_sync(uk_dev);}if ((pre_val & (1 << 2)) != (usb_buf[0] & (1 << 2))) {input_event(uk_dev, EV_KEY, KEY_ENTER, (usb_buf[0] & (1 << 2)) ? 1 : 0);input_sync(uk_dev);}pre_val = usb_buf[0];usb_submit_urb(uk_urb, GFP_KERNEL);
}
  1. pre_val是一个静态变量,用于保存上一次读取到的鼠标事件。

  2. 函数首先通过比较pre_valusb_buf[0]的位状态,检测左键、右键和中建是否发生了变化。

  3. 如果左键发生了变化,则使用input_event()函数向输入设备发送相应的事件(EV_KEY)和按键(KEY_L),如果该位为1,则表示按下;如果该位为0,则表示松开。然后通过input_sync()同步输入事件。

  4. 同样的,如果右键或中键发生了变化,也会发送相应的事件给输入设备。

  5. 最后,将当前的usb_buf[0]赋值给pre_val,以便在下一次中断时比较。

  6. 在函数最后,重新提交urb(USB Request Block)

检测设备

static int usbmouse_as_key_probe(struct usb_interface* intf, const struct usb_device_id* id) {struct usb_device* dev = interface_to_usbdev(intf);struct usb_host_interface* interface;struct usb_endpoint_descriptor* endpoint;int pipe;interface = intf->cur_altsetting;endpoint = &interface->endpoint[0].desc;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_alloc_coherent(dev, len, GFP_ATOMIC, &usb_buf_phys);uk_urb = usb_alloc_urb(0, GFP_KERNEL);usb_fill_int_urb(uk_urb, dev, pipe, usb_buf, len, usbmouse_as_key_irq, NULL, endpoint->bInterval);uk_urb->transfer_dma = usb_buf_phys;uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;usb_submit_urb(uk_urb, GFP_KERNEL);return 0;
}
  1. 通过传入的usb_interfaceusb_device_id参数获取USB设备对象dev

  2. 获取当前配置的接信息interface,并获得第一个端点的描述符endpoint

  3. 创建一个用于输入设备的input_dev结构体对象,并分配内存空间,保存在uk_dev变量中。

  4. 设置该input_dev对象支持产生按键时间(EV_KEY)和重复时间(EV_REP)。

  5. 设置该input_dev对象支持产生左键(KEY_L)、右键(KEY_S)和回车键(KEY_ENTER)事件。

  6. 注册该input_dev对象,使其可以被系统识别和使用。

  7. 进行硬件相关操作前,需要确定数据传输的三个要素:源、目的和长度。其中,源是USB设备的某个端点,通过函数usb_rcvintpipt()获取相应管道号存储在pipe变量中;长度通过端点描述符中的最大包长度字段wMaxPacketSize获取存储在变量len中。

  8. 使用函数usb_alloc_coherent()分配一块连续的内存作为目的缓冲区,并将物理地址保存在变量usb_buf_phys中,虚拟地址保存在变量usb_buf中。

  9. 分配一个USB Request Block(URB)作为数据传输的控制块,使用函数usb_alloc_urb()进行分配,并将URB相关信息填充:设备对象、管道号、缓冲区指针、缓冲区长度、中断处理函数usbmouse_as_key_irq等。

  10. 设备URB的传输物理地址和标志位,确保不进行DMA映射。

  11. 使用函数usb_submit_urb()提交URB,驱动数据传输过程。

断开释放

static void usbmouse_as_key_disconnect(struct usb_interface *intf) {struct usb_device *dev = interface_to_usbdev(intf);usb_kill_urb(uk_urb);usb_free_urb(uk_urb);usb_free_coherent(dev, len, usb_buf, usb_buf_phys);input_unregister_device(uk_dev);input_free_device(uk_dev);
}
  1. usb_kill_urb(uk_urb): 停止和取消正在进行的URB(USB请求块)。

  2. usb_free_urb(uk_urb): 释放之前分配的URB资源。

  3. usb_free_coherent(dev, len, usb_buf, usb_buf_phys): 释放通过usb_alloc_coherent()分配的一段连续内存区域。

  4. input_unregister_device(uk_dev): 注销输入设备,将其从系统中移除。

  5. input_free_device(uk_dev): 释放输入设备占用的资源。

插入和退出内核

static int usbmouse_as_key_init(void) {/* 2. 注册 */usb_register(&usbmouse_as_key_driver);return 0;
}static void usbmouse_as_key_exit(void) {usb_deregister(&usbmouse_as_key_driver);	
}

http://www.mrgr.cn/news/11772.html

相关文章:

  • 【yarn publish : 报错 passed folder/tarball doesn‘t exist 】
  • 【SQL】连续出现的数字
  • LabVIEW高速数据采集关键问题
  • 网络基础知识:理解核心概念与技术
  • 通过css,js html结合实现第一个页面
  • Java常用API(Math,System,Runtime)
  • 上ERP就能数字化转型吗?数字化转型到底转什么?
  • 【C#】【EXCEL】Bumblebee/Classes/ExGraphic.cs
  • Ubuntu下部署Hadoop集群+Hive(三)
  • 【从问题中去学习k8s】k8s中的常见面试题(夯实理论基础)(十四)
  • 【dotnet】Ubuntu 24.04安装dotnet 8.0报错
  • Java笔试面试题AI答之线程(4)
  • Qt的事件循环
  • 新160个crackme - 041-genocide1
  • Servlet
  • linux 安装kafaka单体服务
  • 每日一问:GET请求和POST请求的区别
  • 仓颉语言:静态类型与垃圾收集,让编程更安全高效
  • 《JavaEE进阶》----2.<Spring前传:Maven项目管理工具>
  • 深入解析 Tomcat 的六大核心组件