Linux ——usb觸摸屏驅動 - usbtouchscreen

https://blog.csdn.net/hanglinux/article/details/45576117

驅動編譯:

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

  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中:

  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使用了部分接口:

  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列表,數據類型爲:

  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:

  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 設置爲枚舉值:

  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.

  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, 00);  
  36.     input_set_abs_params(input_dev, ABS_Y, type->min_yc, type->max_yc, 00);  
  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 數組的第幾元素.

  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 數組:

  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中初始化,看下函數主要實現:


  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的驅動部分就分析到這裏。

出處:http://blog.csdn.net/jscese/article/details/41827495

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章