最近需要往TV上装一个触摸屏设备,现在比较常见的就是使用usb接口的触摸框,适用于各种平台,这里大体记录一下在android上kernel中的usbtouchscreen驱动.



撰写不易,转载需注明出处:http://blog.csdn.net/jscese/article/details/41827495

驱动编译:

目前的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:

[objc] view plain copy print ?
  1. staticint__initusbtouch_init(void)
  2. {
  3. returnusb_register(&usbtouch_driver);//调用了usb核心的注册函数,传入的是一个usb_driver结构体指针
  4. }

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

[objc] view plain copy print ?
  1. staticinlineintusb_register(structusb_driver*driver)
  2. {
  3. returnusb_register_driver(driver,THIS_MODULE,KBUILD_MODNAME);//这里再往后就是usb核心驱动的事,注册这个module驱动到usb总线上
  4. }

这里必须是要先注册的总线,当一个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使用了部分接口:

[objc] view plain copy print ?
  1. staticstructusb_driverusbtouch_driver={
  2. .name="usbtouchscreen",//drivername
  3. .probe=usbtouch_probe,//probe接口,用于总线上匹配检测到这个驱动对应的设备之后,/kernel/drivers/usb/core/driver.c中的usb_probe_interface调用到我们这个驱动的接口
  4. .disconnect=usbtouch_disconnect,//与probe相反,断开的时候调用
  5. .suspend=usbtouch_suspend,//usb设备挂起
  6. .resume=usbtouch_resume,//和上面挂起相反,唤醒
  7. .reset_resume=usbtouch_reset_resume,//重置唤醒
  8. .id_table=usbtouch_devices,//支持的设备ID表
  9. .supports_autosuspend=1,
  10. };

id_table:

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

[objc] view plain copy print ?
  1. structusb_device_id{
  2. /*whichfieldstomatchagainst?*/
  3. __u16match_flags;
  4. /*Usedforproductspecificmatches;rangeisinclusive*/
  5. __u16idVendor;
  6. __u16idProduct;
  7. __u16bcdDevice_lo;
  8. __u16bcdDevice_hi;
  9. /*Usedfordeviceclassmatches*/
  10. __u8bDeviceClass;
  11. __u8bDeviceSubClass;
  12. __u8bDeviceProtocol;
  13. /*Usedforinterfaceclassmatches*/
  14. __u8bInterfaceClass;
  15. __u8bInterfaceSubClass;
  16. __u8bInterfaceProtocol;
  17. /*notmatchedagainst*/
  18. kernel_ulong_tdriver_info;
  19. };

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

目前已有的id_table:

[objc] view plain copy print ?
  1. staticconststructusb_device_idusbtouch_devices[]={
  2. #ifdefCONFIG_TOUCHSCREEN_USB_EGALAX
  3. /*ignoretheHIDcapabledevices,handledbyusbhid*/
  4. {USB_DEVICE_HID_CLASS(0x0eef,0x0001),.driver_info=DEVTYPE_IGNORE},
  5. {USB_DEVICE_HID_CLASS(0x0eef,0x0002),.driver_info=DEVTYPE_IGNORE},
  6. ...
  7. #endif
  8. ...
  9. };

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


driver_info:

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

[objc] view plain copy print ?
  1. /*devicetypes*/
  2. enum{
  3. DEVTYPE_IGNORE=-1,
  4. DEVTYPE_EGALAX,
  5. DEVTYPE_PANJIT,
  6. DEVTYPE_3M,
  7. DEVTYPE_ITM,
  8. DEVTYPE_ETURBO,
  9. DEVTYPE_GUNZE,
  10. DEVTYPE_DMC_TSC10,
  11. DEVTYPE_IRTOUCH,
  12. DEVTYPE_IDEALTEK,
  13. DEVTYPE_GENERAL_TOUCH,
  14. DEVTYPE_GOTOP,
  15. DEVTYPE_JASTEC,
  16. DEVTYPE_E2I,
  17. DEVTYPE_ZYTRONIC,
  18. DEVTYPE_TC45USB,
  19. DEVTYPE_NEXIO,
  20. };

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

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


usbtouch_probe

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

[objc] view plain copy print ?
  1. staticintusbtouch_probe(structusb_interface*intf,
  2. conststructusb_device_id*id)
  3. {
  4. structusbtouch_usb*usbtouch;//usbtouch设备
  5. structinput_dev*input_dev;//输入设备
  6. structusb_endpoint_descriptor*endpoint;//usb的端点
  7. structusb_device*udev=interface_to_usbdev(intf);//从usb接口获取对应的设备
  8. structusbtouch_device_info*type;//这个就是上面说的真正的driverinfo了
  9. endpoint=usbtouch_get_input_endpoint(intf->cur_altsetting);//获取端点
  10. if(!endpoint)
  11. return-ENXIO;
  12. usbtouch=kzalloc(sizeof(structusbtouch_usb),GFP_KERNEL);
  13. input_dev=input_allocate_device();//分配内存,申请input设备结构
  14. ...
  15. type=&usbtouch_dev_info[id->driver_info];//这里就用到了上面说到的枚举值了,真正的info是放在这个数组里面的!
  16. ...
  17. usbtouch->irq=usb_alloc_urb(0,GFP_KERNEL);//分配了一个urb用于获得触摸屏设备返回的触摸事件的数据,urb的概念可参考usbdriver
  18. if(!usbtouch->irq){
  19. dbg("%s-usb_alloc_urbfailed:usbtouch->irq",__func__);
  20. gotoout_free_buffers;
  21. }
  22. ...
  23. //往下都是一些分配内存,input注册,初始化操作了
  24. input_dev->evbit[0]=BIT_MASK(EV_KEY)|BIT_MASK(EV_ABS);//这里是就是input设备触摸坐标的初始化赋值了,为ABS绝对坐标
  25. input_dev->keybit[BIT_WORD(BTN_TOUCH)]=BIT_MASK(BTN_TOUCH);
  26. input_set_abs_params(input_dev,ABS_X,type->min_xc,type->max_xc,0,0);
  27. input_set_abs_params(input_dev,ABS_Y,type->min_yc,type->max_yc,0,0);
  28. ...
  29. if(usb_endpoint_type(endpoint)==USB_ENDPOINT_XFER_INT)
  30. usb_fill_int_urb(usbtouch->irq,udev,
  31. usb_rcvintpipe(udev,endpoint->bEndpointAddress),
  32. usbtouch->data,type->rept_size,
  33. usbtouch_irq,usbtouch,endpoint->bInterval);
  34. else
  35. usb_fill_bulk_urb(usbtouch->irq,udev,
  36. usb_rcvbulkpipe(udev,endpoint->bEndpointAddress),
  37. usbtouch->data,type->rept_size,
  38. usbtouch_irq,usbtouch);//初始化urb的回调函数为usbtouch_irq
  39. usbtouch->irq->dev=udev;
  40. usbtouch->irq->transfer_dma=usbtouch->data_dma;
  41. usbtouch->irq->transfer_flags|=URB_NO_TRANSFER_DMA_MAP;
  42. ...
  43. }


usbtouch_device_info:

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

[objc] view plain copy print ?
  1. structusbtouch_device_info{
  2. intmin_xc,max_xc;
  3. intmin_yc,max_yc;
  4. intmin_press,max_press;
  5. intrept_size;
  6. /*
  7. *AlwaysservicetheUSBdevicesirqnotjustwhentheinputdeviceis
  8. *open.Thisisusefulwhendeviceshaveawatchdogwhichpreventsus
  9. *fromperiodicallypollingthedevice.Leavethisunsetunlessyour
  10. *touchscreendevicerequiresit,asitdoesconsumemoreoftheUSB
  11. *bandwidth.
  12. */
  13. boolirq_always;
  14. void(*process_pkt)(structusbtouch_usb*usbtouch,unsignedcharchar*pkt,intlen);//这个函数指针是用来接收处理中断的。
  15. /*
  16. *usedtogetthepacketlen.possiblereturnvalues:
  17. *>0:packetlen
  18. *=0:skiponebyte
  19. *<0:-returnvaluemorebytesneeded
  20. */
  21. int(*get_pkt_len)(unsignedcharchar*pkt,intlen);
  22. int(*read_data)(structusbtouch_usb*usbtouch,unsignedcharchar*pkt);
  23. int(*alloc)(structusbtouch_usb*usbtouch);
  24. int(*init)(structusbtouch_usb*usbtouch);
  25. void(*exit)(structusbtouch_usb*usbtouch);
  26. };

usbtouch_dev_info 数组: [objc] view plain copy print ?
  1. staticstructusbtouch_device_infousbtouch_dev_info[]={
  2. #ifdefCONFIG_TOUCHSCREEN_USB_EGALAX
  3. [DEVTYPE_EGALAX]={
  4. .min_xc=0x0,
  5. .max_xc=0x07ff,
  6. .min_yc=0x0,
  7. .max_yc=0x07ff,
  8. .rept_size=16,
  9. .process_pkt=usbtouch_process_multi,//用于中断回调函数,用于处理中断,得到input的event,上传数据
  10. .get_pkt_len=egalax_get_pkt_len,
  11. .read_data=egalax_read_data,//用于中断回调函数,用于读取数据
  12. },
  13. #endif
  14. ...
  15. #ifdefCONFIG_TOUCHSCREEN_USB_IRTOUCH
  16. [DEVTYPE_IRTOUCH]={
  17. .min_xc=0x0,
  18. .max_xc=0x0fff,
  19. .min_yc=0x0,
  20. .max_yc=0x0fff,
  21. .rept_size=8,
  22. .read_data=irtouch_read_data,
  23. },
  24. #endif
  25. ...
  26. };

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


usbtouch_irq:

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


[objc] view plain copy print ?
  1. staticvoidusbtouch_irq(structurb*urb)
  2. {
  3. ...
  4. usbtouch->type->process_pkt(usbtouch,usbtouch->data,urb->actual_length);
  5. //这个type的类型就是usbtouch_device_info,此时的process_pkt指针自然指向的是上面对应的函数,如果此时是触发的设备type为DEVTYPE_EGALAX,那么这里调用的usbtouch_process_multi
  6. //如果此时是DEVTYPE_IRTOUCH那么就是执行usbtouch_process_pkt函数,因为usbtouch_probe中:
  7. //if(!type->process_pkt)
  8. //type->process_pkt=usbtouch_process_pkt;
  9. ...
  10. }


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

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



更多相关文章

  1. [中英文对照]android Designing for TV(三) ------ Handling Fea
  2. android设备管理器.md
  3. Android(安卓)USB设备通信--读写操作
  4. Android(安卓)逆向学习之《Smail语法查询手册》
  5. Android(安卓)Camera2 Hal3(一)初始化
  6. Android(安卓)EventBus的简单使用
  7. Android(安卓)开源框架选择
  8. 【Android(安卓)Developers Training】 20. 创建一个Fragment
  9. Android开发者指南(7) —— App Install Location

随机推荐

  1. Android中的进程与多线程的讲解(Handler和
  2. Android(安卓)API Guides---Data Storage
  3. android 自定义圆形进度条(一)
  4. iOS中的抽屉菜单
  5. Android如何快速实现打渠道打包
  6. Android客户端与服务器端数据同步
  7. Android(安卓)显示GIF图片实例详解
  8. Android中弹窗中带有Edittext,软键盘遮挡
  9. 记一次Build.gradle引发的ClassNotFound
  10. android中的数据存储方式(二)SQLite