驱动编译:

目前的kernel中都是自带了usbtouchscreen驱动的,我的版本3.1.10

源码位于:/kernel/drivers/input/touchscreen/usbtouchscreen.c

从这个路径可以看出所属驱动分支,我这边平台本身是没放开的,并没有编译进kernel,谁会想到触摸电视呢~

可以在make menuconfig之后,通过Device Drivers——>Input device support——>Touchscreens——>USB Touchscreen Driver 然后选取需要的touchscreen类型

通过查看相关目录下的的Kconfig Makefile,可参考:Kernel 编译配置机制

注册usb驱动:

熟悉linux驱动的都知道模块入口:module_init(usbtouch_init) ,这里看下这个init:

static int __init usbtouch_init(void)
{return usb_register(&usbtouch_driver);  //调用了usb 核心的注册函数,传入的是一个usb_driver结构体指针
} int __init usbtouch_init(void)
{return usb_register(&usbtouch_driver);  //调用了usb 核心的注册函数,传入的是一个usb_driver结构体指针
}

usb_register实现在/kernel/include/linux/usb.h中:

static inline int usb_register(struct usb_driver *driver)
{return usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);//这里再往后就是usb核心驱动的事,注册这个module驱动到usb总线上
} inline int usb_register(struct usb_driver *driver)
{return usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);//这里再往后就是usb核心驱动的事,注册这个module驱动到usb总线上
}

这里必须是要先注册的总线,当一个USB设备被插入的时候,USB设备驱动,也就是usb_generic_driver会跟USB设备交互,得到其所有的各种描述符,并为每个接口都定义成为一个device,之后再加载到usb_bus上,让其去匹配其对应的接口驱动程序,有兴趣可以去看下/kernel/drivers/base/bus.c中的 bus_for_each_drv

函数。

这里注册到总线的接口驱动就是 usbtouch_driver

usbtouch_driver:

这个usb_driver类型的变量 usbtouch_driver就是整个usbtouchscreen的灵魂核心,可以在上面说到的usb.h中查看usb_driver结构原型,

这里usbtouch_driver使用了部分接口:

static struct usb_driver usbtouch_driver = {.name       = "usbtouchscreen", //driver name.probe      = usbtouch_probe,  //probe接口,用于总线上匹配检测到这个驱动对应的设备之后,/kernel/drivers/usb/core/driver.c中的usb_probe_interface调用到我们这个驱动的接口.disconnect = usbtouch_disconnect,  //与probe相反,断开的时候调用.suspend  = usbtouch_suspend, //usb 设备挂起.resume      = usbtouch_resume,  // 和上面挂起相反,唤醒.reset_resume  = usbtouch_reset_resume,  // 重置唤醒.id_table = usbtouch_devices, //支持的设备ID表.supports_autosuspend = 1,
};
 struct usb_driver usbtouch_driver = {.name     = "usbtouchscreen", //driver name.probe      = usbtouch_probe,  //probe接口,用于总线上匹配检测到这个驱动对应的设备之后,/kernel/drivers/usb/core/driver.c中的usb_probe_interface调用到我们这个驱动的接口.disconnect = usbtouch_disconnect,  //与probe相反,断开的时候调用.suspend  = usbtouch_suspend, //usb 设备挂起.resume      = usbtouch_resume,  // 和上面挂起相反,唤醒.reset_resume  = usbtouch_reset_resume,  // 重置唤醒.id_table = usbtouch_devices, //支持的设备ID表.supports_autosuspend = 1,
};

id_table:

首先可以关注一下 id_table 这个变量,代表支持的设备id列表,数据类型为:

struct usb_device_id {/* which fields to match against? */__u16      match_flags;/* Used for product specific matches; range is inclusive */__u16        idVendor;__u16      idProduct;__u16     bcdDevice_lo;__u16      bcdDevice_hi;/* Used for device class matches */__u8        bDeviceClass;__u8       bDeviceSubClass;__u8        bDeviceProtocol;/* Used for interface class matches */__u8      bInterfaceClass;__u8        bInterfaceSubClass;__u8     bInterfaceProtocol;/* not matched against */kernel_ulong_t  driver_info;
}; usb_device_id {/* which fields to match against? */__u16      match_flags;/* Used for product specific matches; range is inclusive */__u16        idVendor;__u16      idProduct;__u16     bcdDevice_lo;__u16      bcdDevice_hi;/* Used for device class matches */__u8        bDeviceClass;__u8       bDeviceSubClass;__u8        bDeviceProtocol;/* Used for interface class matches */__u8      bInterfaceClass;__u8        bInterfaceSubClass;__u8     bInterfaceProtocol;/* not matched against */kernel_ulong_t  driver_info;
};

这些设备信息会被上面说到的usb bus 来匹配对应的驱动,只有这里的信息跟usb设备驱动那边收集到的设备信息匹配上,才会调用进这个驱动.

目前已有的 id_table:

static const 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},
...
#endif
...
};
 const 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},
...
#endif
...
};

其中可以看到 两个字节的十六进制数字,第一个代表idVendor 厂商ID,idProduct 产品ID ,这两个一般作为设备的标识.

driver_info:

像上面的 usbtouch_devices的数组中driver_info 设置为枚举值:

/* device types */
enum {DEVTYPE_IGNORE = -1,DEVTYPE_EGALAX,DEVTYPE_PANJIT,DEVTYPE_3M,DEVTYPE_ITM,DEVTYPE_ETURBO,DEVTYPE_GUNZE,DEVTYPE_DMC_TSC10,DEVTYPE_IRTOUCH,DEVTYPE_IDEALTEK,DEVTYPE_GENERAL_TOUCH,DEVTYPE_GOTOP,DEVTYPE_JASTEC,DEVTYPE_E2I,DEVTYPE_ZYTRONIC,DEVTYPE_TC45USB,DEVTYPE_NEXIO,
};
enum {DEVTYPE_IGNORE = -1,DEVTYPE_EGALAX,DEVTYPE_PANJIT,DEVTYPE_3M,DEVTYPE_ITM,DEVTYPE_ETURBO,DEVTYPE_GUNZE,DEVTYPE_DMC_TSC10,DEVTYPE_IRTOUCH,DEVTYPE_IDEALTEK,DEVTYPE_GENERAL_TOUCH,DEVTYPE_GOTOP,DEVTYPE_JASTEC,DEVTYPE_E2I,DEVTYPE_ZYTRONIC,DEVTYPE_TC45USB,DEVTYPE_NEXIO,
};

那么这些driver 的真正的info保存在哪里呢? 在注册的时候,现在只是注册上去一个枚举数字而已,

真正有设备识别到的时候这些个枚举值就起到作用了! 在下面的 usbtouch_probe会介绍!

usbtouch_probe:

在前面有稍微提到,usbtouchscreen驱动是怎么被映射到的,这个过程暂时不做深入,作为这个驱动中的第一个接入点就是usbtouch_probe.

static int usbtouch_probe(struct usb_interface *intf,const struct usb_device_id *id)
{struct usbtouch_usb *usbtouch;  //usbtouch 设备struct input_dev *input_dev;  //输入设备struct usb_endpoint_descriptor *endpoint;  //usb 的端点struct usb_device *udev = interface_to_usbdev(intf);  //从usb接口获取对应的设备struct usbtouch_device_info *type;   //这个就是上面说的真正的 driver info了endpoint = usbtouch_get_input_endpoint(intf->cur_altsetting);  //获取端点if (!endpoint)return -ENXIO;usbtouch = kzalloc(sizeof(struct usbtouch_usb), GFP_KERNEL);input_dev = input_allocate_device();  //分配内存,申请input 设备结构
...type = &usbtouch_dev_info[id->driver_info];   // 这里就用到了 上面说到的枚举值了, 真正的info 是放在这个数组里面的!
...usbtouch->irq = usb_alloc_urb(0, GFP_KERNEL);  //分配了一个urb 用于 获得触摸屏设备返回的触摸事件的数据,urb的概念可参考usb driverif (!usbtouch->irq) {dbg("%s - usb_alloc_urb failed: usbtouch->irq", __func__);goto out_free_buffers;}
...
//往下都是一些分配内存,input注册,初始化操作了input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); //这里是就是input设备触摸坐标的初始化赋值了,为ABS 绝对坐标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 (usb_endpoint_type(endpoint) == USB_ENDPOINT_XFER_INT)usb_fill_int_urb(usbtouch->irq, udev,usb_rcvintpipe(udev, endpoint->bEndpointAddress),usbtouch->data, type->rept_size,usbtouch_irq, usbtouch, endpoint->bInterval);elseusb_fill_bulk_urb(usbtouch->irq, udev,usb_rcvbulkpipe(udev, endpoint->bEndpointAddress),usbtouch->data, type->rept_size,usbtouch_irq, usbtouch);  //初始化urb的回调函数为 usbtouch_irqusbtouch->irq->dev = udev;usbtouch->irq->transfer_dma = usbtouch->data_dma;usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
...
}
int usbtouch_probe(struct usb_interface *intf,const struct usb_device_id *id)
{struct usbtouch_usb *usbtouch;  //usbtouch 设备struct input_dev *input_dev;  //输入设备struct usb_endpoint_descriptor *endpoint;  //usb 的端点struct usb_device *udev = interface_to_usbdev(intf);  //从usb接口获取对应的设备struct usbtouch_device_info *type;   //这个就是上面说的真正的 driver info了endpoint = usbtouch_get_input_endpoint(intf->cur_altsetting);  //获取端点if (!endpoint)return -ENXIO;usbtouch = kzalloc(sizeof(struct usbtouch_usb), GFP_KERNEL);input_dev = input_allocate_device();  //分配内存,申请input 设备结构
...type = &usbtouch_dev_info[id->driver_info];   // 这里就用到了 上面说到的枚举值了, 真正的info 是放在这个数组里面的!
...usbtouch->irq = usb_alloc_urb(0, GFP_KERNEL);  //分配了一个urb 用于 获得触摸屏设备返回的触摸事件的数据,urb的概念可参考usb driverif (!usbtouch->irq) {dbg("%s - usb_alloc_urb failed: usbtouch->irq", __func__);goto out_free_buffers;}
...
//往下都是一些分配内存,input注册,初始化操作了input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); //这里是就是input设备触摸坐标的初始化赋值了,为ABS 绝对坐标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 (usb_endpoint_type(endpoint) == USB_ENDPOINT_XFER_INT)usb_fill_int_urb(usbtouch->irq, udev,usb_rcvintpipe(udev, endpoint->bEndpointAddress),usbtouch->data, type->rept_size,usbtouch_irq, usbtouch, endpoint->bInterval);elseusb_fill_bulk_urb(usbtouch->irq, udev,usb_rcvbulkpipe(udev, endpoint->bEndpointAddress),usbtouch->data, type->rept_size,usbtouch_irq, usbtouch);  //初始化urb的回调函数为 usbtouch_irqusbtouch->irq->dev = udev;usbtouch->irq->transfer_dma = usbtouch->data_dma;usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
...
}

usbtouch_device_info:

这个就是上面driver_info 以及usbtouch_probe 中抽取的驱动模块的info数组,不同的usbtouchscreen 注册的时候就是注册了一个枚举值,这个值就是 usbtouch_dev_info数组的第几元素.

struct usbtouch_device_info {int min_xc, max_xc;int min_yc, max_yc;int min_press, max_press;int rept_size;/** Always service the USB devices irq not just when the input device is* open. This is useful when devices have a watchdog which prevents us* from periodically polling the device. Leave this unset unless your* touchscreen device requires it, as it does consume more of the USB* bandwidth.*/bool irq_always;void (*process_pkt) (struct usbtouch_usb *usbtouch, unsigned char *pkt, int len);  //这个函数指针是用来接收处理中断的。/** used to get the packet len. possible return values:* > 0: packet len* = 0: skip one byte* < 0: -return value more bytes needed*/int  (*get_pkt_len) (unsigned char *pkt, int len);int  (*read_data)   (struct usbtouch_usb *usbtouch, unsigned char *pkt);int  (*alloc)       (struct usbtouch_usb *usbtouch);int  (*init)     (struct usbtouch_usb *usbtouch);void (*exit)        (struct usbtouch_usb *usbtouch);
};
  int min_xc, max_xc;int min_yc, max_yc;int min_press, max_press;int rept_size;/** Always service the USB devices irq not just when the input device is* open. This is useful when devices have a watchdog which prevents us* from periodically polling the device. Leave this unset unless your* touchscreen device requires it, as it does consume more of the USB* bandwidth.*/bool irq_always;void (*process_pkt) (struct usbtouch_usb *usbtouch, unsigned char *pkt, int len);  //这个函数指针是用来接收处理中断的。/** used to get the packet len. possible return values:* > 0: packet len* = 0: skip one byte* < 0: -return value more bytes needed*/int  (*get_pkt_len) (unsigned char *pkt, int len);int  (*read_data)   (struct usbtouch_usb *usbtouch, unsigned char *pkt);int  (*alloc)      (struct usbtouch_usb *usbtouch);int  (*init)     (struct usbtouch_usb *usbtouch);void (*exit)        (struct usbtouch_usb *usbtouch);
};

usbtouch_dev_info

数组:

static struct usbtouch_device_info usbtouch_dev_info[] = {
#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX[DEVTYPE_EGALAX] = {.min_xc        = 0x0,.max_xc      = 0x07ff,.min_yc       = 0x0,.max_yc      = 0x07ff,.rept_size    = 16,.process_pkt  = usbtouch_process_multi,//用于中断回调函数,用于处理中断,得到input的event,上传数据.get_pkt_len = egalax_get_pkt_len,.read_data    = egalax_read_data, //用于中断回调函数,用于读取数据},
#endif
...
#ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH[DEVTYPE_IRTOUCH] = {.min_xc      = 0x0,.max_xc      = 0x0fff,.min_yc       = 0x0,.max_yc      = 0x0fff,.rept_size    = 8,.read_data = irtouch_read_data,},
#endif
...
};
 struct usbtouch_device_info usbtouch_dev_info[] = {
#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX[DEVTYPE_EGALAX] = {.min_xc        = 0x0,.max_xc      = 0x07ff,.min_yc       = 0x0,.max_yc      = 0x07ff,.rept_size    = 16,.process_pkt  = usbtouch_process_multi,//用于中断回调函数,用于处理中断,得到input的event,上传数据.get_pkt_len = egalax_get_pkt_len,.read_data    = egalax_read_data, //用于中断回调函数,用于读取数据},
#endif
...
#ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH[DEVTYPE_IRTOUCH] = {.min_xc      = 0x0,.max_xc      = 0x0fff,.min_yc       = 0x0,.max_yc      = 0x0fff,.rept_size    = 8,.read_data = irtouch_read_data,},
#endif
...
};

可以看到这个数组的成员都是以前面说到的注册枚举值来区分的!这些x,y 参数以及回调函数,都在上面说到的 usbtouch_probe 中被抽离出来使用.

usbtouch_irq:

这个函数作为中断响应函数,在上面的 usbtouch_probe中初始化,看下函数主要实现:

static void usbtouch_irq(struct urb *urb)
{
...usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length);
//这个type的类型就是 usbtouch_device_info,此时的process_pkt指针自然指向的是上面对应的函数,如果此时是触发的设备type为 DEVTYPE_EGALAX,那么这里调用的 usbtouch_process_multi
//如果此时是DEVTYPE_IRTOUCH 那么就是执行 usbtouch_process_pkt函数,因为usbtouch_probe中:
//  if (!type->process_pkt)
//      type->process_pkt = usbtouch_process_pkt;
...
}
q(struct urb *urb)
{
...usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length);
//这个type的类型就是 usbtouch_device_info,此时的process_pkt指针自然指向的是上面对应的函数,如果此时是触发的设备type为 DEVTYPE_EGALAX,那么这里调用的 usbtouch_process_multi
//如果此时是DEVTYPE_IRTOUCH 那么就是执行 usbtouch_process_pkt函数,因为usbtouch_probe中:
//  if (!type->process_pkt)
//      type->process_pkt = usbtouch_process_pkt;
...
}

接下来的都会调用到usbtouch_process_pkt中,通过type->read_data,和上面一样的指针读取,然后调用input_report_key发送,input_sync用于同步.

关于usbtouchscreen的驱动部分就分析到这里。

usb触摸屏驱动 - usbtouchscreen相关推荐

  1. Linux/Android——usb触摸屏驱动 - usbtouchscreen (一)

    版权声明:免责声明: 本人在此发文(包括但不限于汉字.拼音.拉丁字母)均为随意敲击键盘所出,用于检验本人电脑键盘录入.屏幕显示的机械.光电性能,并不代表本人局部或全部同意.支持或者反对观点.如需要详查 ...

  2. linux内核关闭触摸屏校准,linux内核usb触摸屏驱动bug调试- selected device is not a touchscreen I understand...

    近期给客户调试一块数控板,今天客户带过来一个屏,并且有一个usb的触摸屏芯片接在屏上.屏很快就弄好正常显示. 触摸屏在内核下找到usb 触摸屏驱动,内核启动后这个usb转的触摸屏也正常找到,注册为ev ...

  3. usb触摸屏驱动移植

    最近公司产品在原有基础上增加一个触摸功能,因电路已经定型,只有usb接口引出来,所以只能选用市面上usb接口的触摸屏,联系了多家触摸屏代理商,移植时都存在问题. 公司产品用的平台是: PXA270 + ...

  4. linux usb 触摸屏驱动,请教大家一个linux下的usb触摸屏驱动的问题

    我手头有个usb红外触摸屏, 在windows下插上就可以使用,但在linux下,插上后,加载了usbhid驱动,生了/dev/input/event4及 /dev/input/mouse0两个设备文 ...

  5. android usb触摸屏驱动 win10,Win10手机居然这样兼容安卓:直接运行apk!

    摘要:"应用太少是硬伤!"这是WP粉吐槽微软简洁而有力的一句话.最新的Win10Mobile预览版中首次引入了微软的安卓子系统,这也是微软推行的ProjectAstoria的一部分 ...

  6. usb4-配置usb触摸屏

    淘了一个触摸屏,usb接口,四线电阻,usb芯片是cy7c63723c. 此芯片一端接触摸屏的四根线,对触摸动作采样然后ad转换,一端通过usb接mini2440,即将ad转换后的数据通过usb接口发 ...

  7. Zynq移植USB触摸屏

    Zynq平台移植USB触摸屏的实现(Qt5.7) 使用的环境: 1. CPU type:ARM CortexA9(Xilinx zynq7000)(使用的是黑金AX7021开发板) 2. Kernel ...

  8. usb 接口触摸屏驱动

    以前写的 USB 接口的触摸屏驱动,那段时间简单的看了下 USB 协议的一些东西,主要是 HID 相关的,代码记录: /*Created by_fire 2012.2.13 */ #include & ...

  9. win10万能触摸屏驱动_教你win10系统设置usb鼠标驱动的方法

    鼠标也有相对应的品牌,在不知道自己使用鼠标设备是什么品牌的情况下,下载安装usb鼠标万能驱动,该软件支持的usb鼠标品牌有罗技,雷蛇,多彩,微软,雷柏,双飞燕等.该驱动还能够适用于各种2.4G.蓝牙5 ...

最新文章

  1. 【 MATLAB 】impz函数介绍(数字滤波器的脉冲响应)
  2. 【Python】如何在文件夹里批量分割图片?
  3. 苹果iOS 15正式发布!一大波新功能上线,这几个被刷爆了
  4. Windows Server 2016-DHCP服务器审核日志大小调整
  5. 计算机维修英语情景对话大全,实用英语短对话:修电脑
  6. 基于Java开发的Java毕业设计实战项目
  7. 电脑系统时间服务器地址,电脑时间同步服务器ip地址
  8. 关于铁路订票系统如何改善设计的讨论
  9. matlab实现多目标测试集ZDT、DTLZ、MOP的最优理论前沿
  10. 西南民族大学第十届校赛(同步赛) 个人笔记 题解
  11. 用不可逆算法MD5进行加密后,如何进行登录验证
  12. Qt编写的项目作品7-视频监控系统
  13. 电路中的过压(OVP)过流(OCP)保护电路
  14. 【Java语言基础】1.3 Java补充知识
  15. Google 或于近期恢复对华为 GMS 服务供应
  16. python计算时间差_Python:计算时间差
  17. matlab 复频域,MATLAB信号与系统分析(四)——离散信号与系统的复频域分析及MATLAB实现...
  18. https配置经过 解决访问php变成下载问题
  19. 计算机word有关表格的考点,2017职称计算机word2003考点文本与表格的转换
  20. 最小二乘支持向量机LSSVM多输入多输出预测,最小二乘支持向量机LSSVM回归预测。

热门文章

  1. 物联网卡和流量卡相比哪个信号强
  2. 涵盖多场景区块链与政务结合 应用前景广阔
  3. ios5.1.1旧版软件下载_苹果iOS 14.1正式版推送 关闭旧版本降级通道
  4. 北京PMP考试考点在哪里?
  5. Oracle11g导入DMP文件并导出为CSV文件过程全纪录
  6. RepVGG: Making VGG-style ConvNets Great Again
  7. 会泡妞的程序员都是怎么撩妹子的?
  8. 腾讯华为签署《深圳市APP个人信息保护自律承诺书》举措新解读
  9. 仿b站的动漫视频网站
  10. 数据库上机实验三(游标)