当前位置: 首页 > 编程日记 > 正文

(转载)Linux usbtouchscreen驱动分析

在Linux内核中自带USB触摸屏驱动,以linux-2.6.33.3\drivers\input\touchscreen.c为例,进行解析:

1.驱动加载:

static int __init usbtouch_init(void)
{
return usb_register(&usbtouch_driver);   //驱动注册
}

其中usbtouch_driver定义为:

static struct usb_driver usbtouch_driver = {
.name   = "usbtouchscreen", //驱动名称
.probe   = usbtouch_probe,   //probe 函数
.disconnect = usbtouch_disconnect,   //disconnect时调用的函数
.id_table = usbtouch_devices,    //usbtouch 支持的设备列表
};

static struct usb_device_id usbtouch_devices[] = {
#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
/* ignore the HID capable devices, handled by usbhid */
{USB_DEVICE_HID_CLASS(0x0eef, 0x0001), .driver_info = DEVTYPE_IGNORE},
{USB_DEVICE_HID_CLASS(0x0eef, 0x0002), .driver_info = DEVTYPE_IGNORE},

/* normal device IDs */
{USB_DEVICE(0x3823, 0x0001), .driver_info = DEVTYPE_EGALAX},
{USB_DEVICE(0x3823, 0x0002), .driver_info = DEVTYPE_EGALAX},
{USB_DEVICE(0x0123, 0x0001), .driver_info = DEVTYPE_EGALAX},

....

0x0123, 0x0001分别为VID和PID,driver_info 包含驱动信息,其类型为usbtouch_device_info。

例如DEVTYPE_EGALAX]定义为:

static struct usbtouch_device_info usbtouch_dev_info[] = {
#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
[DEVTYPE_EGALAX] = {
.min_xc   = 0x0,                 //X轴最小坐标
.max_xc   = 0x07ff,            //X轴最大坐标
.min_yc   = 0x0,                //Y轴最小坐标
.max_yc   = 0x07ff,           //Y轴最大坐标
.rept_size = 16,               //
.process_pkt = usbtouch_process_multi,    //用于中断回调函数,用于上传数据
.get_pkt_len = egalax_get_pkt_len,
.read_data = egalax_read_data,                //用于中断回调函数,用于读取数据
},
#endif

所以在注册的时候,就注入了设备的信息,如果注册成功(usb_device_id中包含对应的硬件),就会调用usbtouch_probe方法。

2.probe方法:

static int usbtouch_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usbtouch_usb *usbtouch; //a usbtouch device
struct input_dev *input_dev;    //a input device
struct usb_host_interface *interface;
/* usb 设备有一个configuration 的概念,表示配置,一个设备可以有多个配置,
但只能同时激活一个,如:一些设备可以下载固件,或可以设置不同的全局模式,
cur_altsetting 就是表示的当前的这个setting,或者说设置。可以查看原码中
usb_interface 结构定义的说明部分。从说明中可以看到一个接口可以有多种setting*/
struct usb_endpoint_descriptor *endpoint;
struct usb_device *udev = interface_to_usbdev(intf); //获取接口对应的设备

/*struct usb_device 中有一个成员struct usb_device_descriptor,而struct usb_device_descriptor 中的成员__u16 bcdDevice,表示的是制造商指定的产品的版本号,制造商id 和产品id 来标志一个设备.bcdDevice 一共16 位,是以bcd码的方式保存的信息,也就是说,每4 位代表一个十进制的数,比如0011 0110 1001 0111 就代表的3697.*/


struct usbtouch_device_info *type;
int err = -ENOMEM;

/* some devices are ignored */
if (id->driver_info == DEVTYPE_IGNORE)
return -ENODEV;

interface = intf->cur_altsetting;
endpoint = &interface->endpoint[0].desc;
//端点0描述符,此处的0表示控制端点

usbtouch = kzalloc(sizeof(struct usbtouch_usb), GFP_KERNEL); //为设备分配内存
input_dev = input_allocate_device();      //申请input_dev结构
if (!usbtouch || !input_dev)
goto out_free;

type = &usbtouch_dev_info[id->driver_info]; //提取设备对应的Info
usbtouch->type = type;
if (!type->process_pkt)
type->process_pkt = usbtouch_process_pkt; //用于中断回调函数,上传数据到应用层

usbtouch->data = usb_buffer_alloc(udev, type->rept_size,
GFP_KERNEL, &usbtouch->data_dma);

/*usbtouch->data:记录了用于普通传输用的内存指针*/

/*usb_buffer_alloc(),这个函数是usbcore提供的,我们只管调用即可.从名字上就能知道它是用来申请内存的,第一个参数就是struct usb_device结构体的指针,所以我们要传递一个udev,第三个参数,GFP_KERNEL,是一个内存申请的flag,通常内存申请都用这个flag,除非是中断上下文,不能睡眠,那就得用GPF_ATOMIC,这里没那么多要求.第二个参数申请的buffer的大小,第四个参数,这个数据类型是Linux内核中专门为dma传输而准备的.为了支持dma传输,usb_buffer_alloc不仅仅是申请了地址,并且建立了dma映射.usb_buffer_alloc申请的内存空间需要用它的搭档usb_buffer_free()来释放.*/
if (!usbtouch->data)
goto out_free;

if (type->get_pkt_len) {
usbtouch->buffer = kmalloc(type->rept_size, GFP_KERNEL);

/*usbtouch->buffer:记录了用于存储读取到的数据的内存指针*/


if (!usbtouch->buffer)
goto out_free_buffers;
}

usbtouch->irq = usb_alloc_urb(0, GFP_KERNEL);
if (!usbtouch->irq) {
dbg("%s - usb_alloc_urb failed: usbtouch->irq", __func__);
goto out_free_buffers;
}

usbtouch->udev = udev;
usbtouch->input = input_dev;

if (udev->manufacturer)
strlcpy(usbtouch->name, udev->manufacturer, sizeof(usbtouch->name));

if (udev->product) {
if (udev->manufacturer)
strlcat(usbtouch->name, " ", sizeof(usbtouch->name));
strlcat(usbtouch->name, udev->product, sizeof(usbtouch->name));
}

if (!strlen(usbtouch->name))
snprintf(usbtouch->name, sizeof(usbtouch->name),
"USB Touchscreen %04x:%04x",
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));

usb_make_path(udev, usbtouch->phys, sizeof(usbtouch->phys));

/*填充设备结构体中的节点名。用来获取 USB 设备在 Sysfs 中的路径,格式为:usb-usb 总线号-路径名。*/
strlcat(usbtouch->phys, "/input0", sizeof(usbtouch->phys));

/* 将设备的名称赋给设备内嵌的输入子系统结构体 */

input_dev->name = usbtouch->name;

/* 将设备的设备节点名赋给设备内嵌的输入子系统结构体 */
input_dev->phys = usbtouch->phys;

/*
* input_dev 中的 input_id 结构体,用来存储厂商、设备类型和设备的编号,这个函数是将设备描述符
* 中的编号赋给内嵌的输入子系统结构体
*/
usb_to_input_id(udev, &input_dev->id);


input_dev->dev.parent = &intf->dev;

input_set_drvdata(input_dev, usbtouch);

/* 填充输入设备打开函数指针 */

input_dev->open = usbtouch_open;

/* 填充输入设备关闭函数指针 */
input_dev->close = usbtouch_close;

/* evbit 用来描述事件,EV_KEY 是按键事件,EV_ABS是绝对坐标事件,EV_REL 是相对坐标事件 */
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);

/* keybit 表示键值 */
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(input_dev, ABS_X, type->min_xc, type->max_xc, 0, 0);
input_set_abs_params(input_dev, ABS_Y, type->min_yc, type->max_yc, 0, 0);
if (type->max_press)
input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press,
type->max_press, 0, 0);

/*
* 填充构建 urb,将刚才填充好的input_dev结构体的数据填充进urb 结构体中,在 open 中递交urb。
* 当 urb 包含一个即将传输的 DMA 缓冲区时应该设置 URB_NO_TRANSFER_DMA_MAP。USB核心使用
* transfer_dma变量所指向的缓冲区,而不是transfer_buffer变量所指向的。
* URB_NO_SETUP_DMA_MAP 用于 Setup 包,URB_NO_TRANSFER_DMA_MAP 用于所有 Data 包。
*/

usb_fill_int_urb(usbtouch->irq, usbtouch->udev,
usb_rcvintpipe(usbtouch->udev, endpoint->bEndpointAddress),
usbtouch->data, type->rept_size,
usbtouch_irq, usbtouch, endpoint->bInterval);

usbtouch->irq->dev = usbtouch->udev;
usbtouch->irq->transfer_dma = usbtouch->data_dma;
usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

/* device specific init */
if (type->init) {
err = type->init(usbtouch);
if (err) {
dbg("%s - type->init() failed, err: %d", __func__, err);
goto out_free_buffers;
}
}

err = input_register_device(usbtouch->input);
if (err) {
dbg("%s - input_register_device failed, err: %d", __func__, err);
goto out_free_buffers;
}

/*
* 一般在 probe 函数中,都需要将设备相关信息保存在一个 usb_interface 结构体中,以便以后通过
* usb_get_intfdata 获取使用。这里设备结构体信息将保存在 intf 接口结构体内嵌的设备结构体中
* 的 driver_data 数据成员中,即 intf->dev->dirver_data = ...。
*/
usb_set_intfdata(intf, usbtouch);

if (usbtouch->type->irq_always)
usb_submit_urb(usbtouch->irq, GFP_KERNEL);

return 0;

out_free_buffers:
usbtouch_free_buffers(udev, usbtouch);
out_free:
input_free_device(input_dev);
kfree(usbtouch);
return err;
}

3.回调函数:

/*
* urb 回调函数,在完成提交 urb 后,urb 回调函数将被调用。
* 此函数作为 usb_fill_int_urb 函数的形参,为构建的 urb 制定的回调函数。
*/
static void usbtouch_irq(struct urb *urb)
{
struct usbtouch_usb *usbtouch = urb->context;
int retval;

switch (urb->status) {
case 0:
/* success */
break;
case -ETIME:
/* this urb is timing out */
dbg("%s - urb timed out - was the device unplugged?",
__func__);
return;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d",
__func__, urb->status);
return;
default:
dbg("%s - nonzero urb status received: %d",
__func__, urb->status);
goto exit;
}

usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length);

exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
err("%s - usb_submit_urb failed with result: %d",
__func__, retval);
}

4. input_sync

用于事件同步,它告知事件的接收者驱动已经发出了一个完整的报告

转载于:https://www.cnblogs.com/hello2mhb/articles/3366372.html

相关文章:

关于事务隔离级别

2019独角兽企业重金招聘Python工程师标准>>> 第一种 read uncommitted 此状态下脏读,不可重复读,虚读都有可能发生。此状态下两个人同时操作一个数据库表一边开启事务没有提交,另一边也开启事物开始更改数据但是也没有提交&#x…

Datawhale组队学习周报(第047周)

本周报总结了从 2021年01月03日至2022年01月09日,Datawhale组队学习的运行情况,我们一直秉承“与学习者一起成长的理念”,希望这个活动能够让更多的学习者受益。 第 32 期组队学习一共 11 门开源课程,共组建了 11 个学习群&#…

讲座记录:从码农到架构师(精简版)

1.框架学习 不要过于在乎细节 学封装思想 不追新 否则太累 每个框架的设计理念不同 spring 比structs 优秀在哪? 关注增量而非全量 2.如何快速学习一门新技术 “新框架的产生速度远大于个人的学习速度” 先快速学习:了解模板,套路-重复出现的代码 类似做…

Enterprise Library 4 数据访问应用程序块

Enterprise Library 数据访问应用程序块简化了实现常规数据访问功能的开发任务。应用程序可以在各种场景中使用此应用程序块,例如为显示而读取数据、传递数据穿过应用程序层( application layers)、以及将修改的数据提交回数据库系统。应用程序块包含对存储过程和内…

虚拟货币市值回调到4100亿整数关口,EOS逆势站上100关口

虚拟货币虚拟货币市值在过去24小时中,虚拟货币整体回调,市值为4100亿美元。只有EOS逆势上扬,已经站上了100元(17.5美元)上方。虚拟货币市场距离12月份最高点几乎只有一步之遥。EOS走势EOS这种疯狂的势头是很多人预料未…

【NCEPU】韩绘锦:图信号处理与图卷积神经网络

韩绘锦是华北电力大学数理系大四的学生,LSGO软件技术团队(Dreamtech算法组)/Datawhale成员,也在天池比赛中取得了不错的成绩,现保送大连理工大学软件工程学院深造。 希望参与我们线下组队学习的同学,可以在…

什么是python第三方库

Python计算生态 标准库 第三方库 标准库:随解释器直接安装到操作系统中的功能模块 第三方库:需要经过安装才能使用的功能模块 模块的概念:库Library、包Package、模块Module 出处:北理工Python慕课

Task01:青少年软件编程(Scratch)等级考试模拟卷(二级)

试题来源 青少年软件编程(Scratch)等级考试试卷(二级)【2019.09】青少年软件编程(Scratch)等级考试试卷(二级)【2019.12】青少年软件编程(Scratch)等级考试试…

App功能测试的注意点

好几个月没有写博客记录学习心得了,这次回老家深夜闲来无事写一篇记录下这段时间的面试心得,这次面试过程很多面试官都问APP的有关测试,下面我就自己的认识和工作中的经验来谈谈自己对APP测试的认识: 1.push消息推送测试 检查push…

编程以外积累: 如何给项目生成类似VS2008的说明文档

1:【下载】 目前微软提供的官方开源工具 Sandcastle 结果跑到项目中一看,抬头就来了这么一段: The Sandcastle CodePlex project is no longer under active development by Microsoft and as such, there will be no future releases to t…

python的turtle绘图体系入门必看(一)

1 设置窗体 turtle.setup(width,height,startx,starty) 说明: setup()函数不是必须的前两个参数代表窗体的横向宽与纵向长后两个参数可选,表示窗体距离屏幕的横向距离和纵向距离(也可以理解为窗体左上角距离屏幕左上角的横向和纵向距离&…

交换两个变量的值不使用第三个变量(Java)

关于这个问题网上有好多答案,最近有人说这是个奇葩问题 个人测试了一把,如果是普通的数字的话,基本上没有问题 public static void main(String[] args) {int a 2147483647;int b 2147483646;// aab;// ba-b;// aa-b;// b a (a b) * 0; …

Task02:青少年软件编程(Scratch)等级考试模拟卷(二级)

电子学会 软件编程(图形化)二级训练营 试题来源 青少年软件编程(Scratch)等级考试试卷(二级)【2019.09】青少年软件编程(Scratch)等级考试试卷(二级)【2019…

Visual Studio 15.7预览版4改进Git、C++支持

\看新闻很累?看技术新闻更累?试试下载InfoQ手机客户端,每天上下班路上听新闻,有趣还有料!\\\对于即将到来的Visual Studio 2017 15.7,微软已经发布了多个新的预览版本。这些版本的变更很有限,似…

python库引用的3种方式比较

方法一 import 库名 使用方式&#xff1a; <库名>.<函数名>(<函数参数>) 方法二 from 库名 import 函数名/* 使用方式&#xff1a; <函数名>(<函数参数>) 第一种方法可以避免第三方库函数和自定义函数重名 第二种更简洁&#xff0c;适用于引用…

使用livereload实现自动刷新

livereload是一个web开发辅助工具&#xff0c;当我们修改完html、css和js的时候会自动刷新浏览器&#xff0c;解放码农的双手。这样在双屏切图、写js代码的时候会提高很多效率。livereload有很多版本&#xff0c;比如基于ruby的版本&#xff0c;我们今天介绍的是nodegruntchrom…

Task03:青少年软件编程(Scratch)等级考试模拟卷(二级)

电子学会 软件编程&#xff08;图形化&#xff09;二级训练营 试题来源 青少年软件编程&#xff08;Scratch&#xff09;等级考试试卷&#xff08;二级&#xff09;【2019.09】青少年软件编程&#xff08;Scratch&#xff09;等级考试试卷&#xff08;二级&#xff09;【2019…

java静态代理与动态代理

2019独角兽企业重金招聘Python工程师标准>>> 代理模式是java常见的设计模式。其目的是为其他对象提供一个代理以控制对某个真实对象的访问。通过代理类这一中间层&#xff0c;有效控制对真实委托类的对象的直接访问&#xff0c;同时可以实现自定义的控制策略。 根据…

python的turtle绘图体系入门必看(二)

1 turtle画笔控制函数 画笔操作后一直有效&#xff0c;一般成对出现 turtle.penup() 别名 turtle.pu() 画笔抬起&#xff0c;海龟在飞行(不在画布上留下图案) turtle.pendown() 别名 turtle.pd() 画笔落下&#xff0c;海龟在爬行 turtle.pensize(width) 别名 turtle.width(wi…

MSSQL2005外网IP的1433端口开启方法

打开SQL Server Configuration Manager&#xff0c;在SQL server配置管理器展开SQL server 2005网络配置-->SQLEXPRESS 的协议-->双击TCP/IP协议-->ip地址将1433端口启用&#xff0c;重启下MSSQL服务才能生效&#xff0c;示例图&#xff1a; 重启下MSSQL服务才能生效转…

Rokid webhook 指南 手把手教你做个懒人

若琪用户 Amadeus 在社区里分享过很多视频。当你进门10秒后还未关闭房门&#xff0c;若琪会一直报警提醒&#xff1b;当你走进门后将门反锁的那一刻&#xff0c;若琪会为你播报今天的天气、为你播放设定的轻音乐。 看到这些视频中对传感器、智能情景的熟练运用&#xff0c;你很…

Task04:青少年软件编程(Scratch)等级考试模拟卷(二级)

电子学会 软件编程&#xff08;图形化&#xff09;二级训练营 试题来源 青少年软件编程&#xff08;Scratch&#xff09;等级考试试卷&#xff08;二级&#xff09;【2019.09】青少年软件编程&#xff08;Scratch&#xff09;等级考试试卷&#xff08;二级&#xff09;【2019…

Python数字类型及操作汇总(入门级)

1. 整数类型 2. 浮点数类型 带有小数点及小数的数字 取值范围和精度都有限制&#xff0c;但常规计算可忽略不计(基本无限制) 注意&#xff1a;浮点数运算存在不确定尾数&#xff08;不是bug&#xff0c;一般发生在10-16左右&#xff0c;因为计算机内部用二进制表示&#xff0c…

FCKeditor如何升级CKEditor及使用方法

之前编辑器用的是FCKeditor&#xff0c;因为项目原因需要升级为最新版本4.2.2&#xff0c;发现是已经更名为CKEditor。 百度了一下&#xff0c;据官方的解释&#xff0c;CK是对FCK的代码的完全重写。 项目环境是asp.net的&#xff0c;之前用的FCKeditor版本是2.6。 在aspx文件头…

【新周报(045)】青少年编程竞赛交流群周报

「青少年编程竞赛交流群」已成立&#xff08;适合6至18周岁的青少年&#xff09;&#xff0c;公众号后台回复【Scratch】或【Python】&#xff0c;即可进入。如果加入了之前的社群不需要重复加入。 为了完成二月份青少年编程公益训练营的活动&#xff0c;本周整理了以往收集的电…

Xshell5中常用linux服务器命令集合

简易版&#xff1a;http://www.zhimengzhe.com/linux/84546.html 详细版&#xff1a;http://www.cnblogs.com/peida/tag/%E6%AF%8F%E6%97%A5%E4%B8%80linux%E5%91%BD%E4%BB%A4/default.html?page4转载于:https://www.cnblogs.com/keye/p/8982440.html

C++设置每屏显示的行数简易办法

定义计数变量counter if ((counter) % 22 0) { //每屏显示22行 cout << "请按回车键继续";cin.get(); }效果

挖坑挖到cnblogs.com来...

这几年一直在cppblog.com上敲字, 因为开帖时满脑袋都是C, 所以选了它~ 懒懒散散竟然也敲了四年多, 真是难得的有毅力啊&#xff5e; 回头看看这一年越来越不务正业了,C越来越少, 到是当年看着不爽的Java越来越多~唉, 语言只是工具而已, 当年为何如此偏执~ 本来就想在cppblog.co…

vue项目踩坑

由于上一个小项目写的很次&#xff0c;这一次打算好好地写一个博客系统&#xff0c;最近刚刚结束了管理员的管理端的编写。其中遇到了很多小坑。 其实只能说自己vue用的不是特别熟练吧。很多问题都有些想当然了&#xff0c;实现起来发现了很多的问题。简单的记录几个我自己认为…

【NCEPU】王子朝:神经网络、支持向量机原理

王子朝 是华北电力大学计算机系大四的学生&#xff0c;LSGO软件技术团队&#xff08;Dreamtech算法组&#xff09;成员&#xff0c;参加了多期Datawhale的组队学习活动&#xff0c;现保送西安电子科技大学深造。 希望参与我们线下组队学习的同学&#xff0c;可以在微信公众号后…