USB设备驱动之鼠标
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设备驱动之鼠标相关推荐
- USB设备(移动硬盘、鼠标)掉电掉驱动的两种解决方案
USB设备(移动硬盘.鼠标)掉电掉驱动的两种解决方案 参考文章: (1)USB设备(移动硬盘.鼠标)掉电掉驱动的两种解决方案 (2)https://www.cnblogs.com/VAllen/p/4 ...
- Linux USB设备驱动程序设计 和 USB下载线驱动设计
Linux USB设备驱动程序设计 和 USB下载线驱动设计 USB设备驱动模型 USB设备包括配置(configuration).接口(interface)和端点(endpoint),一个USB设备 ...
- 浅谈Linux USB设备驱动
1.USB基础介绍 1-1.USB硬件接口介绍 USB接口在硬件上总共有四根线组成VCC.D+.D-.GND,通过计算D+和D-的差值来确定数据.USB设备在传输速率上可以分为低速(1.5Mbps). ...
- WDF开发USB设备驱动教程(1)
PDF下载地址(1.2版):链接地址 CY001开发板讨论帖:链接地址 注:本文档新版本已出,请在博客中查找,或下载PDF全文文档. 链接地址WDF开发USB设备驱动教程 by 张佩 文档说明 作者写 ...
- USB总线驱动及鼠标驱动实例
转自:https://blog.csdn.net/liangzc1124/article/details/119333357.https://www.cnblogs.com/lifexy/p/7631 ...
- Linux设备驱动之usb设备驱动详解
原文地址:http://blog.csdn.net/chenjin_zhong/article/details/6329316 1.Linux usb设备驱动框架 USB是通用串行总线的总称,Linu ...
- 第八章 USB 设备驱动移植
8.1 USB协议 USB协议系统主要组成,总线拓扑结构,内部层次关系,数据流模式,USB调度等等 8.1.1 主要组成部分 USB的连接部分,USB的 ...
- 71 linux usb设备驱动
usb接口有大,小口之分 usb有主机(host,大口)/设备(otg, 小口)工作模式 usb主机可以主动去操作设备, 主机接口由4根线(vcc, gnd, d+, d-) usb设备被主机操作, ...
- USB设备驱动之驱动
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/huangweiqing80/article/details/83014292 上一篇文章USB设备驱 ...
最新文章
- 前端中会用到的设计模式之单一职责原则
- webpack与babel的深奥,渣渣的我只能做个小笔记(持续更新)
- 光伏发展路线图将发布 促产业优胜劣汰
- linux qt yuv,c – 如何使用Qt中的RGBA32数据将带有YUV数据...
- 混合app用百分比还是rem_[笔记]em, rem最佳实践
- linux操作系统分区图解,图解磁盘分区介绍(超经典)
- oracle只能在指定目录下访问,只安装PLSQL怎么访问远程数据库
- mysql查找有小数点的数据_MySQL中查询中位数?
- 一、SCVMM2008R2安装部署
- Head First 设计模式 —— 装饰器模式与门面模式
- 开发中遇到的Mac使用问题
- 请大家帮忙,帮我看一下.net的这个问题
- 非线性系统的理论和方法,神经网络的非线性
- 学习单片机开发——浅尝点灯的快乐
- SpringBoot2.1.9 多MongoDB配置template
- 【Servlet】2:认识一下Web服务器——Tomcat
- 学习OpenCV3 面阵相机标定方法
- Arduino 光敏电阻
- 临界区 互斥 事件 信标的区别
- “最不合格”的SAP应聘者: 从大学生到SAP成都研究院开发工程师
热门文章
- 8、【STM32】定时器(TIM)——中断、PWM、输入捕获实验(一文精通定时器)
- 21 RBM(Restricted Boltzmann Machine)——受限玻尔兹曼机
- 数据分析师,未来的出路在哪里?
- Mac如何设置手写输入?
- 大华服务器装系统,大华车载监控系统工程安装指导书(完整版).pdf
- 怎么把计算机中更改你的视图,如何修改电脑中文件或文件夹显示的详细信息选项...
- 《Shazam It! Music Recognition Algorithms, Fingerprinting, and Processing》译文
- 垃圾回收你懂,Java垃圾回收你懂吗?
- 为什么要学HTML5
- 持续学习(continual learning/ life-long learning)