Linux/Android——usb触摸屏驱动 - usbtouchscreen

我自横刀向天笑,去留肝胆两昆仑。这篇文章主要讲述Linux/Android——usb触摸屏驱动 - usbtouchscreen 相关的知识,希望能为你提供帮助。
本文转载自:http://blog.csdn.net/jscese/article/details/41827495
  最近需要往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  

  1. static  int  __init  usbtouch_init(void)   
  2. {   
  3.         return  usb_register(& usbtouch_driver);     //调用了usb  核心的注册函数,传入的是一个usb_driver结构体指针   
  4. }   
 
 
usb_register实现在/kernel/include/linux/usb.h中:
 
[objc]  view plain  copy  
  1. static  inline  int  usb_register(struct  usb_driver  *driver)   
  2. {   
  3.         return  usb_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  
  1. static  struct  usb_driver  usbtouch_driver  =  {   
  2.         .name                =  "usbtouchscreen",  //driver  name   
  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  
  1. struct  usb_device_id  {   
  2.         /*  which  fields  to  match  against?  */   
  3.         __u16              match_flags;    
  4.    
  5.         /*  Used  for  product  specific  matches;   range  is  inclusive  */   
  6.         __u16              idVendor;    
  7.         __u16              idProduct;    
  8.         __u16              bcdDevice_lo;    
  9.         __u16              bcdDevice_hi;    
  10.    
  11.         /*  Used  for  device  class  matches  */   
  12.         __u8                bDeviceClass;    
  13.         __u8                bDeviceSubClass;    
  14.         __u8                bDeviceProtocol;    
  15.    
  16.         /*  Used  for  interface  class  matches  */   
  17.         __u8                bInterfaceClass;    
  18.         __u8                bInterfaceSubClass;    
  19.         __u8                bInterfaceProtocol;    
  20.    
  21.         /*  not  matched  against  */   
  22.         kernel_ulong_t    driver_info;    
  23. };    
【Linux/Android——usb触摸屏驱动 - usbtouchscreen】
这些设备信息会被上面说到的usb bus 来匹配对应的驱动,只有这里的信息跟usb设备驱动那边收集到的设备信息匹配上,才会调用进这个驱动.
 
目前已有的id_table:
[objc]  view plain  copy  
  1. static  const  struct  usb_device_id  usbtouch_devices[]  =  {   
  2. #ifdef  CONFIG_TOUCHSCREEN_USB_EGALAX   
  3.         /*  ignore  the  HID  capable  devices,  handled  by  usbhid  */   
  4.         {USB_DEVICE_HID_CLASS(0x0eef,  0x0001),  .driver_info  =  DEVTYPE_IGNORE},   
  5.         {USB_DEVICE_HID_CLASS(0x0eef,  0x0002),  .driver_info  =  DEVTYPE_IGNORE},   
  6.    
  7. ...   
  8.    
  9. #endif   
  10.    
  11. ...   
  12.    
  13. };    
 
其中可以看到 两个字节的十六进制数字,第一个代表idVendor 厂商ID,idProduct 产品ID ,这两个一般作为设备的标识.
 
driver_info:
像上面的usbtouch_devices的数组中driver_info 设置为枚举值:
 
[objc]  view plain  copy  
  1. /*  device  types  */   
  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  
  1. static  int  usbtouch_probe(struct  usb_interface  *intf,   
  2.                             const  struct  usb_device_id  *id)   
  3. {   
  4.         struct  usbtouch_usb  *usbtouch;     //usbtouch  设备   
  5.         struct  input_dev  *input_dev;     //输入设备   
  6.         struct  usb_endpoint_descriptor  *endpoint;     //usb  的端点   
  7.         struct  usb_device  *udev  =  interface_to_usbdev(intf);     //从usb接口获取对应的设备   
  8.         struct  usbtouch_device_info  *type;       //这个就是上面说的真正的  driver  info了   
  9.    
  10.    
  11.         endpoint  =  usbtouch_get_input_endpoint(intf-> cur_altsetting);     //获取端点   
  12.         if  (!endpoint)   
  13.                 return  -ENXIO;    
  14.         usbtouch  =  kzalloc(sizeof(struct  usbtouch_usb),  GFP_KERNEL);    
  15.         input_dev  =  input_allocate_device();     //分配内存,申请input  设备结构   
  16.    
  17. ...   
  18.    
  19.         type  =  & usbtouch_dev_info[id-> driver_info];       //  这里就用到了  上面说到的枚举值了,  真正的info  是放在这个数组里面的!   
  20.    
  21. ...   
  22.    
  23.         usbtouch-> irq  =  usb_alloc_urb(0,  GFP_KERNEL);     //分配了一个urb  用于  获得触摸屏设备返回的触摸事件的数据,urb的概念可参考usb  driver   
  24.         if  (!usbtouch-> irq)  {   
  25.                 dbg("%s  -  usb_alloc_urb  failed:  usbtouch-> irq",  __func__);    
  26.                 goto  out_free_buffers;    
  27.         }   
  28.    
  29. ...   
  30.    
  31. //往下都是一些分配内存,input注册,初始化操作了   
  32.    
  33.         input_dev-> evbit[0]  =  BIT_MASK(EV_KEY)  |  BIT_MASK(EV_ABS);   //这里是就是input设备触摸坐标的初始化赋值了,为ABS  绝对坐标   
  34.         input_dev-> keybit[BIT_WORD(BTN_TOUCH)]  =  BIT_MASK(BTN_TOUCH);    
  35.         input_set_abs_params(input_dev,  ABS_X,  type-> min_xc,  type-> max_xc,  0,  0);    
  36.         input_set_abs_params(input_dev,  ABS_Y,  type-> min_yc,  type-> max_yc,  0,  0);    
  37.    
  38. ...   
  39.    
  40.         if  (usb_endpoint_type(endpoint)  ==  USB_ENDPOINT_XFER_INT)   
  41.                 usb_fill_int_urb(usbtouch-> irq,  udev,   
  42.                           usb_rcvintpipe(udev,  endpoint-> bEndpointAddress),   
  43.                           usbtouch-> data,  type-> rept_size,   
  44.                           usbtouch_irq,  usbtouch,  endpoint-> bInterval);    
  45.         else   
  46.                 usb_fill_bulk_urb(usbtouch-> irq,  udev,   
  47.                           usb_rcvbulkpipe(udev,  endpoint-> bEndpointAddress),   
  48.                           usbtouch-> data,  type-> rept_size,   
  49.                           usbtouch_irq,  usbtouch);     //初始化urb的回调函数为  usbtouch_irq   
  50.    
  51.         usbtouch-> irq-> dev  =  udev;    
  52.         usbtouch-> irq-> transfer_dma  =  usbtouch-> data_dma;    
  53.         usbtouch-> irq-> transfer_flags  |=  URB_NO_TRANSFER_DMA_MAP;    
  54.    
  55. ...   
  56.    
  57. }   



usbtouch_device_info:
  这个就是上面driver_info 以及usbtouch_probe 中抽取的驱动模块的info数组,不同的usbtouchscreen 注册的时候就是注册了一个枚举值,这个值就是usbtouch_dev_info  数组的第几元素.
 
[objc]  view plain  copy  
  1. struct  usbtouch_device_info  {   
  2.         int  min_xc,  max_xc;    
  3.         int  min_yc,  max_yc;    
  4.         int  min_press,  max_press;    
  5.         int  rept_size;    
  6.    
  7.         /* 
  8.           *  Always  service  the  USB  devices  irq  not  just  when  the  input  device  is 
  9.           *  open.  This  is  useful  when  devices  have  a  watchdog  which  prevents  us 
  10.           *  from  periodically  polling  the  device.  Leave  this  unset  unless  your 
  11.           *  touchscreen  device  requires  it,  as  it  does  consume  more  of  the  USB 
  12.           *  bandwidth. 
  13.           */   
  14.         bool  irq_always;    
  15.    
  16.         void  (*process_pkt)  (struct  usbtouch_usb  *usbtouch,  unsigned  charchar  *pkt,  int  len);     //这个函数指针是用来接收处理中断的。   
  17.    
  18.         /* 
  19.           *  used  to  get  the  packet  len.  possible  return  values: 
  20.           *  >   0:  packet  len 
  21.           *  =  0:  skip  one  byte 
  22.           *  <   0:  -return  value  more  bytes  needed 
  23.           */   
  24.         int    (*get_pkt_len)  (unsigned  charchar  *pkt,  int  len);    
  25.    
  26.         int    (*read_data)      (struct  usbtouch_usb  *usbtouch,  unsigned  charchar  *pkt);    
  27.         int    (*alloc)              (struct  usbtouch_usb  *usbtouch);    
  28.         int    (*init)                (struct  usbtouch_usb  *usbtouch);    
  29.         void  (*exit)                (struct  usbtouch_usb  *usbtouch);    
  30. };    

usbtouch_dev_info  数组:
 
[objc]  view plain  copy  
  1. static  struct  usbtouch_device_info  usbtouch_dev_info[]  =  {   
  2. #ifdef  CONFIG_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. ...   
  16.    
  17. #ifdef  CONFIG_TOUCHSCREEN_USB_IRTOUCH   
  18.         [DEVTYPE_IRTOUCH]  =  {   
  19.                 .min_xc                =  0x0,   
  20.                 .max_xc                =  0x0fff,   
  21.                 .min_yc                =  0x0,   
  22.                 .max_yc                =  0x0fff,   
  23.                 .rept_size        =  8,   
  24.                 .read_data        =  irtouch_read_data,   
  25.         },   
  26. #endif     
  27.    
  28. ...   
  29.    
  30. };    
 
可以看到这个数组的成员都是以前面说到的注册枚举值来区分的!这些x,y 参数以及回调函数,都在上面说到的 usbtouch_probe 中被抽离出来使用.
 
usbtouch_irq:
  这个函数作为中断响应函数,在上面的  usbtouch_probe中初始化,看下函数主要实现:
 
[objc]  view plain  copy  
  1. static  void  usbtouch_irq(struct  urb  *urb)   
  2. {   
  3.    
  4. ...   
  5.    
  6.         usbtouch-> type-> process_pkt(usbtouch,  usbtouch-> data,  urb-> actual_length);        
  7.    
  8. //这个type的类型就是  usbtouch_device_info,此时的process_pkt指针自然指向的是上面对应的函数,如果此时是触发的设备type为  DEVTYPE_EGALAX,那么这里调用的  usbtouch_process_multi   
  9.    
  10. //如果此时是DEVTYPE_IRTOUCH  那么就是执行  usbtouch_process_pkt函数,因为usbtouch_probe中:   
  11.    
  12. //        if  (!type-> process_pkt)   
  13. //                type-> process_pkt  =  usbtouch_process_pkt;    
  14.    
  15. ...   
  16.    
  17. }   


接下来的都会调用到usbtouch_process_pkt中,通过type-> read_data,和上面一样的指针读取,然后调用input_report_key发送,input_sync用于同步.
关于usbtouchscreen的驱动部分就分析到这里。
 

    推荐阅读