USB设备驱动之鼠标

1.  概述

USB鼠标驱动程序大致分为两大部分:USB设备驱动部分和输入设备驱动部分,USB设备驱动只起了挂接总线和传输数据的作用,而具体的设备类型的驱动仍然是工作的主体。

USB设备驱动部分:负责注册USB设备驱动,实现probe和disconnect函数,初始化驱动支持的USB鼠标设备类型表(id_table);初始化和提交URB;根据HID规范,鼠标只有一个端点(不包括端点0),且属于中断传输类型。

输入设备驱动部分:负责注册输入设备和该设备所支持的事件类型;向输入核心层上报鼠标事件。

这里有一个概念需要注意,这里的中断传输与硬件中断那个中断是不一样的,这个中断传输实际是靠USB hostcontrol轮询usb device来实现的,而USBhost control对于CPU则是基于中断的机制。拿USB鼠标为例,USB host control对USB鼠标不断请求,这个请求的间隔是很短的,端点描述符中的bInterval域中指定的,当鼠标发生过了事件之后,鼠标会发送数据回host,这时USB host control中断通知CPU,于是usb_mouse_irq被调用,在usb_mouse_irq里,就可以读取鼠标发回来的数据,当读完之后,驱动再次调用usb_submit_urb发出请求,就这么一直重复下去,一个usb鼠标的驱动也就完成了。

我们在进行硬件访问的时候,只需调用URB相关的接口,而不需要关心底层USB主机控制器的具体细节,因此,USB设备也变得与平台无关,同样的驱动可应用于不同的SOC。

2.代码分析

#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>/* for apple IDs */
#ifdef CONFIG_USB_HID_MODULE
#include "../hid-ids.h"
#endif/** Version Information*/
#define DRIVER_VERSION "v1.6"
#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
#define DRIVER_DESC "USB HID Boot Protocol mouse driver"
#define DRIVER_LICENSE "GPL"MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);/*  */
struct usb_mouse {char name[128];char phys[64];struct usb_device *usbdev;struct input_dev *dev;struct urb *irq;signed char *data;dma_addr_t data_dma;
};static void usb_mouse_irq(struct urb *urb)
{struct usb_mouse *mouse = urb->context; /* context 指向USB驱动 程序分 配 的 数据 块*/signed char *data = mouse->data;struct input_dev *dev = mouse->dev;int status;/* 判断传输是否成功 */switch (urb->status) {case 0:          /* success */break;case -ECONNRESET:    /* unlink */case -ENOENT:case -ESHUTDOWN:return;/* -EPIPE:  should clear the halt */default:        /* error */goto resubmit;}/* 上报事件 */input_report_key(dev, BTN_LEFT,   data[0] & 0x01);input_report_key(dev, BTN_RIGHT,  data[0] & 0x02);input_report_key(dev, BTN_MIDDLE, data[0] & 0x04);input_report_key(dev, BTN_SIDE,   data[0] & 0x08);input_report_key(dev, BTN_EXTRA,  data[0] & 0x10);input_report_rel(dev, REL_X,     data[1]);input_report_rel(dev, REL_Y,     data[2]);input_report_rel(dev, REL_WHEEL, data[3]);input_sync(dev);/* 提交下次传输 */
resubmit:status = usb_submit_urb (urb, GFP_ATOMIC);if (status)err ("can't resubmit intr, %s-%s/input0, status %d",mouse->usbdev->bus->bus_name,mouse->usbdev->devpath, status);
}static int usb_mouse_open(struct input_dev *dev)
{struct usb_mouse *mouse = input_get_drvdata(dev);mouse->irq->dev = mouse->usbdev;/* 向USB核心层提交URB */if (usb_submit_urb(mouse->irq, GFP_KERNEL))return -EIO;return 0;
}static void usb_mouse_close(struct input_dev *dev)
{struct usb_mouse *mouse = input_get_drvdata(dev);usb_kill_urb(mouse->irq);
}/* USB设备与驱动匹配上时调用 */
static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
{/* 设备描述 usb_device *//* 接口描述 usb_interface */struct usb_device *dev = interface_to_usbdev(intf); /* 接口设置描述 */struct usb_host_interface *interface;/* 端点描述符 */struct usb_endpoint_descriptor *endpoint;struct usb_mouse *mouse;struct input_dev *input_dev;int pipe, maxp;int error = -ENOMEM;/* 获取当前接口设置 */interface = intf->cur_altsetting;/* 根据HID规范,鼠标只有一个端点(不包含0号控制端点)*/if (interface->desc.bNumEndpoints != 1)return -ENODEV;/* 获取端点0描述符 */endpoint = &interface->endpoint[0].desc;/* 根据HID规范,鼠标唯一的端点应为中断端点 */if (!usb_endpoint_is_int_in(endpoint))return -ENODEV;/* 生成中断管道 */pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);/* 返回该端点能够传输的最大的包长度,鼠标的返回的最大数据包为4个字节。*/  maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));/* 创建input设备 */mouse = kzalloc(sizeof(struct usb_mouse), GFP_KERNEL);input_dev = input_allocate_device();if (!mouse || !input_dev)goto fail1;/* 申请内存空间用于数据传输,data 为指向该空间的地址*/mouse->data = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &mouse->data_dma);if (!mouse->data)goto fail1;/* 分配URB */mouse->irq = usb_alloc_urb(0, GFP_KERNEL);if (!mouse->irq)goto fail2;mouse->usbdev = dev;mouse->dev = input_dev;if (dev->manufacturer)strlcpy(mouse->name, dev->manufacturer, sizeof(mouse->name));if (dev->product) {if (dev->manufacturer)strlcat(mouse->name, " ", sizeof(mouse->name));strlcat(mouse->name, dev->product, sizeof(mouse->name));}if (!strlen(mouse->name))snprintf(mouse->name, sizeof(mouse->name),"USB HIDBP Mouse %04x:%04x",le16_to_cpu(dev->descriptor.idVendor),le16_to_cpu(dev->descriptor.idProduct));usb_make_path(dev, mouse->phys, sizeof(mouse->phys));strlcat(mouse->phys, "/input0", sizeof(mouse->phys));/* 设置输入设备的相关属性 */input_dev->name = mouse->name;input_dev->phys = mouse->phys;usb_to_input_id(dev, &input_dev->id);input_dev->dev.parent = &intf->dev;/* 设置输入设备支持的事件和事件代码 */input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |BIT_MASK(BTN_EXTRA);input_dev->relbit[0] |= BIT_MASK(REL_WHEEL);input_set_drvdata(input_dev, mouse);input_dev->open = usb_mouse_open;input_dev->close = usb_mouse_close;/* 初始化中断URB */usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data,(maxp > 8 ? 8 : maxp),usb_mouse_irq, mouse, endpoint->bInterval);mouse->irq->transfer_dma = mouse->data_dma;mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;/* 向输入核心层注册输入设备 */error = input_register_device(mouse->dev);if (error)goto fail3;usb_set_intfdata(intf, mouse);return 0;fail3:   usb_free_urb(mouse->irq);
fail2:  usb_buffer_free(dev, 8, mouse->data, mouse->data_dma);
fail1:  input_free_device(input_dev);kfree(mouse);return error;
}/* USB设备移除时调用 */
static void usb_mouse_disconnect(struct usb_interface *intf)
{struct usb_mouse *mouse = usb_get_intfdata (intf);usb_set_intfdata(intf, NULL);if (mouse) {usb_kill_urb(mouse->irq);input_unregister_device(mouse->dev);usb_free_urb(mouse->irq);usb_buffer_free(interface_to_usbdev(intf), 8, mouse->data, mouse->data_dma);kfree(mouse);}
}/* 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 */
};MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);static struct usb_driver usb_mouse_driver = {.name     = "usbmouse",   /* 驱动名 */.probe      = usb_mouse_probe, /* 捕获函数 */.disconnect   = usb_mouse_disconnect, /* 卸载函数 */.id_table    = usb_mouse_id_table, /* 设备列表 */
};static int __init usb_mouse_init(void)
{/* 注册鼠标驱动程序 */int retval = usb_register(&usb_mouse_driver);if (retval == 0)printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"DRIVER_DESC "\n");return retval;
}static void __exit usb_mouse_exit(void)
{usb_deregister(&usb_mouse_driver);
}module_init(usb_mouse_init);
module_exit(usb_mouse_exit);


USB设备驱动之鼠标相关推荐

  1. USB设备(移动硬盘、鼠标)掉电掉驱动的两种解决方案

    USB设备(移动硬盘.鼠标)掉电掉驱动的两种解决方案 参考文章: (1)USB设备(移动硬盘.鼠标)掉电掉驱动的两种解决方案 (2)https://www.cnblogs.com/VAllen/p/4 ...

  2. Linux USB设备驱动程序设计 和 USB下载线驱动设计

    Linux USB设备驱动程序设计 和 USB下载线驱动设计 USB设备驱动模型 USB设备包括配置(configuration).接口(interface)和端点(endpoint),一个USB设备 ...

  3. 浅谈Linux USB设备驱动

    1.USB基础介绍 1-1.USB硬件接口介绍 USB接口在硬件上总共有四根线组成VCC.D+.D-.GND,通过计算D+和D-的差值来确定数据.USB设备在传输速率上可以分为低速(1.5Mbps). ...

  4. WDF开发USB设备驱动教程(1)

    PDF下载地址(1.2版):链接地址 CY001开发板讨论帖:链接地址 注:本文档新版本已出,请在博客中查找,或下载PDF全文文档. 链接地址WDF开发USB设备驱动教程 by 张佩 文档说明 作者写 ...

  5. USB总线驱动及鼠标驱动实例

    转自:https://blog.csdn.net/liangzc1124/article/details/119333357.https://www.cnblogs.com/lifexy/p/7631 ...

  6. Linux设备驱动之usb设备驱动详解

    原文地址:http://blog.csdn.net/chenjin_zhong/article/details/6329316 1.Linux usb设备驱动框架 USB是通用串行总线的总称,Linu ...

  7. 第八章 USB 设备驱动移植

    8.1 USB协议     USB协议系统主要组成,总线拓扑结构,内部层次关系,数据流模式,USB调度等等         8.1.1 主要组成部分             USB的连接部分,USB的 ...

  8. 71 linux usb设备驱动

    usb接口有大,小口之分 usb有主机(host,大口)/设备(otg, 小口)工作模式 usb主机可以主动去操作设备, 主机接口由4根线(vcc, gnd, d+, d-) usb设备被主机操作, ...

  9. USB设备驱动之驱动

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/huangweiqing80/article/details/83014292 上一篇文章USB设备驱 ...

最新文章

  1. 前端中会用到的设计模式之单一职责原则
  2. webpack与babel的深奥,渣渣的我只能做个小笔记(持续更新)
  3. 光伏发展路线图将发布 促产业优胜劣汰
  4. linux qt yuv,c – 如何使用Qt中的RGBA32数据将带有YUV数据...
  5. 混合app用百分比还是rem_[笔记]em, rem最佳实践
  6. linux操作系统分区图解,图解磁盘分区介绍(超经典)
  7. oracle只能在指定目录下访问,只安装PLSQL怎么访问远程数据库
  8. mysql查找有小数点的数据_MySQL中查询中位数?
  9. 一、SCVMM2008R2安装部署
  10. Head First 设计模式 —— 装饰器模式与门面模式
  11. 开发中遇到的Mac使用问题
  12. 请大家帮忙,帮我看一下.net的这个问题
  13. 非线性系统的理论和方法,神经网络的非线性
  14. 学习单片机开发——浅尝点灯的快乐
  15. SpringBoot2.1.9 多MongoDB配置template
  16. 【Servlet】2:认识一下Web服务器——Tomcat
  17. 学习OpenCV3 面阵相机标定方法
  18. Arduino 光敏电阻
  19. 临界区 互斥 事件 信标的区别
  20. “最不合格”的SAP应聘者: 从大学生到SAP成都研究院开发工程师

热门文章

  1. 8、【STM32】定时器(TIM)——中断、PWM、输入捕获实验(一文精通定时器)
  2. 21 RBM(Restricted Boltzmann Machine)——受限玻尔兹曼机
  3. 数据分析师,未来的出路在哪里?
  4. Mac如何设置手写输入?
  5. 大华服务器装系统,大华车载监控系统工程安装指导书(完整版).pdf
  6. 怎么把计算机中更改你的视图,如何修改电脑中文件或文件夹显示的详细信息选项...
  7. 《Shazam It! Music Recognition Algorithms, Fingerprinting, and Processing》译文
  8. 垃圾回收你懂,Java垃圾回收你懂吗?
  9. 为什么要学HTML5
  10. 持续学习(continual learning/ life-long learning)