zoukankan      html  css  js  c++  java
  • Linux/Android——usb触摸屏驱动

    本文转载自: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. };  


    这些设备信息会被上面说到的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的驱动部分就分析到这里。

  • 相关阅读:
    [前端插件]Bootstrap Table服务器分页与在线编辑应用总结
    Accord.NET_Naive Bayes Classifier
    Accord.NET入门
    [C++]STL容器Vector的内存释放
    [设计模式]适配器模式与外观模式
    [设计模式]工厂模式
    Linux下spi驱动开发
    Qt移植对USB鼠标键盘、触摸屏的支持
    linux设备模型详解 http://blog.csdn.net/linux_xiaomugua/article/details/6989386
    LGPL协议的理解
  • 原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/7806209.html
Copyright © 2011-2022 走看看