USB驱动分析
INIT函数:
这是内核模块的初始化函数,其所作的工作只有注册定义好的USB驱动结构体。
USB驱动结构体如下:
Usb_driver中的probe函数是驱动和设备匹配成功后调用。
Usb_driver中的disconnect函数是驱动和设备断开连接后后调用。
Id_table中是驱动能够支持的设备列表,usb_device_id中记载的就是支持的设备。其中USB_interface_info是用来定义一类USB鼠标设备。
MODULE_DEVICE_TABLE定义如下:
MODULE_DEVICE_TABLE的第一个参数是设备的类型,如果是USB设备,就是usb,后一个参数是设备表。
这条语句把支持设备数据添加到了/lib/module/内核名称/module.usbmap中,使模块装载程序知道什么模块对应什么硬件设备。
EXIT函数
唯一要做的就是注销usb_driver
Probe函数:
当设备匹配成功的时候,就需要调用prob函数:
probe的主要任务1为向输入子系统注册,需要的工作如下:(功能相关)
1.注册
2.告诉输入子系统需要支持哪些事件
probe的主要任务2为创建URB,那么他需要做好以下几点准备:(总线相关)
1.urb指针
2.要访问的设备
3.管道
4.host的数据缓冲区
5.回调函数
当然了,还有一大堆判断,比如判断是不是只有一个端点0(HID规范)等等。
static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
//USB接口描述符被当做参数传递进来
/* 设备描述 usb_device */
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个字节。*/
//初始化URB的时候会用到这个长度,缓冲区的长度要依照maxp来决定,最大不能超过8
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
//为mouse结构申请内存
//mouse结构的主要作用是赋值给usb_interface中的一个属性
//以便于触发其它函数的时候通过usb_interface中的这个属性就可以知道相关信息
//usb_interface中的这个属性是专门为了储存用户需要的数据的
mouse = kzalloc(sizeof(struct usb_mouse), GFP_KERNEL);
/* 创建input设备 */
input_dev = input_allocate_device();
if (!mouse || !input_dev)
goto fail1;
/* 申请内存空间用于数据传输,data 为指向该空间的地址*/
//初始化URB需要的缓冲区,第四个参数是DMA相关
mouse->data = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &mouse->data_dma);
if (!mouse->data)
goto fail1;
//////////////////////////////////
///////////////////////////////
//到这准备工作做完了,开始操作urb阶段
/* 分配URB */
mouse->irq = usb_alloc_urb(0, GFP_KERNEL);
if (!mouse->irq)
goto fail2;
//过程中顺便给mouse变量赋值
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));
}
//给usb_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用来获取USB设备在sysfs中的路径
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;
//从dev中获取总线类型,设备id,厂商id,版本号
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)| BIT_MASK(BTN_SIDE) |
BIT_MASK(BTN_EXTRA);
//支持的相对坐标为鼠标移动坐标和滚轮坐标
input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y) | BIT_MASK(REL_WHEEL);
//将mouse传入input_dev,因为open和close函数的传入参数就只有input_dev,而我们需要mouse
input_set_drvdata(input_dev, mouse);
//制定打开函数和关闭函数
input_dev->open = usb_mouse_open;
input_dev->close = usb_mouse_close;
/* 初始化中断URB */
//没有中断函数,因为我们都知道其实是主控制器在不断地轮询
//注意:mouse被设置到urb的上下文里,方便到时候调用。
usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data,
(maxp > 8 ? 8 : maxp),
usb_mouse_irq, mouse, endpoint->bInterval);
//mouse的irq就是urb,下面应该是设置DMA传输相关
//当flag使用URB_NO_TRANSFER_DMA_MAP的时候,优先使用transfer_dma,而不是transfer_buffer
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;
//将mouse传递给intf
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;
}
PS : mouse类型如下:
Disconnect函数
当断开匹配的时候就会调用这个函数:
static void usb_mouse_disconnect(struct usb_interface *intf)
{
//从probe函数中,我们把mouse传递进了intf
struct usb_mouse *mouse = usb_get_intfdata (intf);
usb_set_intfdata(intf, NULL);
//把mouse中的属性逐个击破
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);
}
}
Open函数
当打开设备文件,就会调用open函数:
Urb实在这里提交的,保证了只有打开设备文件才会提交urb。
Close函数:
关闭设备文件的时候调用
static void usb_mouse_close(struct input_dev *dev)
{
//在probe函数中将mouse传入input_dev
struct usb_mouse *mouse = input_get_drvdata(dev);
usb_kill_urb(mouse->irq);
}
Usb_mouse_irq回调函数
回调函数,完成URB请求的操作会调用一次这个回调函数。
static void usb_mouse_irq(struct urb *urb)
{
struct usb_mouse *mouse = urb->context;
signed char *data = mouse->data;
struct input_dev *dev = mouse->dev;
int status;
//检查urb是否传输成功
switch (urb->status) {
case 0: /* success */
break;
case -ECONNRESET: /* unlink */
case -ENOENT:
case -ESHUTDOWN:
return;
/* -EPIPE: should clear the halt */
default: /* error */
goto resubmit;
}
//按这么看,data的第一个字节应该是代表按键,按下和抬起都会触发
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);
//第二个,第三个字节代表鼠标的x,y坐标,第四个字节是滑轮的当前值
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);
}
USB驱动分析的更多相关文章
- 八、USB驱动分析
学习目标:分析USB驱动源码结构. 一.Windows下USB驱动理论问题 1. 当usb设备接入PC时,右下角弹出"发现AAA",并弹出对话框,提示安装驱动程序.没有驱动程序,W ...
- usb键鼠标驱动分析
一.鼠标 linux下的usb鼠标驱动在/drivers/hid/usbhid/usbmouse.c中实现 1.加载初始化过程 1.1模块入口 module_init(usb_mouse_init); ...
- Linux 串口、usb转串口驱动分析(2-2) 【转】
转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=26807463&id=4186852 Linux 串口.usb转 ...
- Linux 串口、usb转串口驱动分析(2-1) 【转】
转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=26807463&id=4186851 Linux 串口.usb转 ...
- linux下usb转串口驱动分析【转】
转自:http://blog.csdn.net/txxm520/article/details/8934706 首先说一下linux的风格,个人理解 1. linux大小结构体其实是面向对象的方法,( ...
- linux设备驱动之USB主机控制器驱动分析 【转】
转自:http://blog.chinaunix.net/uid-20543183-id-1930831.html ---------------------------------------- ...
- Linux USB驱动框架分析 【转】
转自:http://blog.chinaunix.net/uid-11848011-id-96188.html 初次接触与OS相关的设备驱动编写,感觉还挺有意思的,为了不至于忘掉看过的东西,笔记跟总结 ...
- linux驱动基础系列--Linux 串口、usb转串口驱动分析
前言 主要是想对Linux 串口.usb转串口驱动框架有一个整体的把控,因此会忽略某些细节,同时里面涉及到的一些驱动基础,比如字符设备驱动.平台驱动等也不进行详细说明原理.如果有任何错误地方,请指出, ...
- Linux下USB驱动框架分析【转】
转自:http://blog.csdn.net/brucexu1978/article/details/17583407 版权声明:本文为博主原创文章,未经博主允许不得转载. http://www.c ...
随机推荐
- Spring cloud微服务安全实战-4-11Zuul网关安全开发(四)
限流,有个现成的开源项目可以帮助我们来做网关上的限流 用最新的这个版本 在pom.xml加入引用. 在限流的过程中需要存一些信息,可以存在数据库里 也可以存在redis里.这里我们演示存到数据库里 比 ...
- Django Model 定义语法
简单用法 from django.db import models class Person(models.Model): first_name = models.CharField(max_leng ...
- Python - Django - ORM 自定义表名
通过 Django 建立的表 命名方式为:项目名_表名 可以将该默认命名方式进行修改 models.py: from django.db import models class Person(mode ...
- 基于TreeSoft实现异构数据同步
一.为了解决数据同步汇聚,数据分发,数据转换,数据维护等需求,TreeSoft将复杂的网状的同步链路变成了星型数据链路. TreeSoft作为中间传输载体负责连接各种数据源,为各种异构数据库之 ...
- 2019年Java面试题基础系列228道(5)
21.存在两个类,B 继承 A,C 继承 B,我们能将 B 转换为C 么?如 C = (C) B: 这属于强制类型转换,如果被转换的B实例不是C类型,会有异常 比如你的ABC分别对应动物,猫,黑猫. ...
- 查找searching
查找searching 在有序数列中查找某一个数据时候的算法设计 查找表的分类 静态查找表:只进行查找操作 动态查找表:不断的插入不存在,删除已存在 查找表的操作 查找.插入.删除 查找也叫检索,是根 ...
- flask 编码问题
在我们的flask项目中,通过表单提交对数据库进行更新的时候,数据提交不成功,提示以下内容: sqlalchemy.exc.InternalError: (pymysql.err.InternalEr ...
- QPS、TPS和系统吞吐量
QPS:Queries Per Second,每秒查询率.是一台服务器每秒能够相应的查询次数,是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准. TPS:Transactions Per ...
- Python3之字符串格式化format函数详解(下)
格式限定符 format通过丰富的的“格式限定符”(语法是 {}中带:号)对需要格式的内容完成更加详细的制定. 进制转换 我们可以再限定符中制定不同的字符对数字进行进制转换的格式化,进制对应的表格: ...
- firefox 获取xpath
在做一个爬虫是,输入内容后,会自动显示内容,而且只能选择,不能根据输入的提交,一点就失去焦点,找不到相关内容 后来发现firefox的查看元素的最左边的类似于鼠标尖头的按钮,就是确保这种情况下,去查找 ...