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驱动分析的更多相关文章

  1. 八、USB驱动分析

    学习目标:分析USB驱动源码结构. 一.Windows下USB驱动理论问题 1. 当usb设备接入PC时,右下角弹出"发现AAA",并弹出对话框,提示安装驱动程序.没有驱动程序,W ...

  2. usb键鼠标驱动分析

    一.鼠标 linux下的usb鼠标驱动在/drivers/hid/usbhid/usbmouse.c中实现 1.加载初始化过程 1.1模块入口 module_init(usb_mouse_init); ...

  3. Linux 串口、usb转串口驱动分析(2-2) 【转】

    转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=26807463&id=4186852 Linux 串口.usb转 ...

  4. Linux 串口、usb转串口驱动分析(2-1) 【转】

    转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=26807463&id=4186851 Linux 串口.usb转 ...

  5. linux下usb转串口驱动分析【转】

    转自:http://blog.csdn.net/txxm520/article/details/8934706 首先说一下linux的风格,个人理解 1. linux大小结构体其实是面向对象的方法,( ...

  6. linux设备驱动之USB主机控制器驱动分析 【转】

    转自:http://blog.chinaunix.net/uid-20543183-id-1930831.html   ---------------------------------------- ...

  7. Linux USB驱动框架分析 【转】

    转自:http://blog.chinaunix.net/uid-11848011-id-96188.html 初次接触与OS相关的设备驱动编写,感觉还挺有意思的,为了不至于忘掉看过的东西,笔记跟总结 ...

  8. linux驱动基础系列--Linux 串口、usb转串口驱动分析

    前言 主要是想对Linux 串口.usb转串口驱动框架有一个整体的把控,因此会忽略某些细节,同时里面涉及到的一些驱动基础,比如字符设备驱动.平台驱动等也不进行详细说明原理.如果有任何错误地方,请指出, ...

  9. Linux下USB驱动框架分析【转】

    转自:http://blog.csdn.net/brucexu1978/article/details/17583407 版权声明:本文为博主原创文章,未经博主允许不得转载. http://www.c ...

随机推荐

  1. 【Redis】CacheCloud介绍及快速开始

    CacheCloud是做什么的 CacheCloud提供一个Redis云管理平台:实现多种类型(Redis Standalone.Redis Sentinel.Redis Cluster)自动部署.解 ...

  2. linux记录-安装elk记录(参考博文)

    什么是ELK? 通俗来讲,ELK是由Elasticsearch.Logstash.Kibana .filebeat三个开源软件的组成的一个组合体,这三个软件当中,每个软件用于完成不同的功能,ELK 又 ...

  3. hppts的理解

    参考: https://www.ruanyifeng.com/blog/2014/02/ssl_tls.html

  4. c# 在静态方法里,怎么能得到调用者的类名?

    System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace(); string name = st.GetFrame(1) ...

  5. netty WEBSOKET 客户端 JAVA

    https://blog.csdn.net/mafei6827/article/details/80657405 https://blog.csdn.net/u010939285/article/de ...

  6. HDU 2089 不要62 数位DP模板题

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2089 参考博客:https://www.cnblogs.com/HDUjackyan/p/914215 ...

  7. require.js的基本用法

    一.为什么要用require.js? 最早的时候,所有Javascript代码都写在一个文件里面,只要加载这一个文件就够了.后来,代码越来越多,一个文件不够了,必须分成多个文件,依次加载.下面的网页代 ...

  8. 【Leetcode_easy】836. Rectangle Overlap

    problem 836. Rectangle Overlap solution: class Solution { public: bool isRectangleOverlap(vector< ...

  9. jstat介绍

    命令可用选项 ➜ ~ jstat -options -class -compiler -gc -gccapacity -gccause -gcmetacapacity -gcnew -gcnewcap ...

  10. poj1056(字符串判断是否存在一个字符串是另一个字符串的前缀)

    题目链接:https://vjudge.net/problem/POJ-1056 题意:给定一个字符串集,判断是否存在一个字符串是另一个字符串的前缀. 思路:和hdoj1671一样,有两种情况: 当前 ...