USB触摸屏的驱动

  我们都知道410c没有配套的触摸屏,如果有屏的话,在调试或者其他方面就方便多了,所以我们自己买了一个usb触摸屏,现在让我们看看usb触摸屏的驱动。

  驱动路经:drivers/input/touchscreen/usbtouchscreen.c


  (1)设备匹配

    module_usb_driver(usbtouch_driver);

   static struct usb_driver usbtouch_driver = {
          .name       = "usbtouchscreen",
   ..............
          .id_table   = usbtouch_devices,
            .............
     };


static const struct usb_device_id usbtouch_devices[] = {
    12 #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
    13     /* ignore the HID capable devices, handled by usbhid */
    14     {USB_DEVICE_HID_CLASS(0x0eef, 0x0001), .driver_info = DEVTYPE_IGNORE},
    15     {USB_DEVICE_HID_CLASS(0x0eef, 0x0002), .driver_info = DEVTYPE_IGNORE},
    16
    17     /* normal device IDs */
    18     {USB_DEVICE(0x3823, 0x0001), .driver_info = DEVTYPE_EGALAX},
    19     {USB_DEVICE(0x3823, 0x0002), .driver_info = DEVTYPE_EGALAX},
    20     {USB_DEVICE(0x0123, 0x0001), .driver_info = DEVTYPE_EGALAX},
    21     {USB_DEVICE(0x0eef, 0x0001), .driver_info = DEVTYPE_EGALAX},
    22     {USB_DEVICE(0x0eef, 0x0002), .driver_info = DEVTYPE_EGALAX},
    23     {USB_DEVICE(0x1234, 0x0001), .driver_info = DEVTYPE_EGALAX},
    24     {USB_DEVICE(0x1234, 0x0002), .driver_info = DEVTYPE_EGALAX},
    25 #endif
    26
    27 #ifdef CONFIG_TOUCHSCREEN_USB_PANJIT
    28     {USB_DEVICE(0x134c, 0x0001), .driver_info = DEVTYPE_PANJIT},
    29     {USB_DEVICE(0x134c, 0x0002), .driver_info = DEVTYPE_PANJIT},
    30     {USB_DEVICE(0x134c, 0x0003), .driver_info = DEVTYPE_PANJIT},
    31     {USB_DEVICE(0x134c, 0x0004), .driver_info = DEVTYPE_PANJIT},
    32 #endif
    33
 ......................

 }

 添加的支持的设备,其中(0x3823, 0x0001)分别为usb设备的厂商id(vid)和产品id(pid),DEVTYPE_EGALAX则在下面定义

    24 enum {
    25     DEVTYPE_IGNORE = -1,
    26     DEVTYPE_EGALAX,
    27     DEVTYPE_PANJIT,
    28     DEVTYPE_3M,
    29     DEVTYPE_ITM,
    30     DEVTYPE_ETURBO,
    31     DEVTYPE_GUNZE,
    32     DEVTYPE_DMC_TSC10,
    33     DEVTYPE_IRTOUCH,
    34     DEVTYPE_IDEALTEK,
    35     DEVTYPE_GENERAL_TOUCH,
    36     DEVTYPE_GOTOP,
    37     DEVTYPE_JASTEC,
    38     DEVTYPE_E2I,
    39     DEVTYPE_ZYTRONIC,
    40     DEVTYPE_TC45USB,
    41     DEVTYPE_NEXIO,
    42     DEVTYPE_ELO,
    43     DEVTYPE_ETOUCH,
    44 };

一旦这些都有了,设备匹配成功就会执行probe函数


  (2)

USB触摸屏的驱动_第1张图片


struct usb_device *udev = interface_to_usbdev(intf):获取接口对应的设备

usbtouch_get_input_endpoint:获取端点描述符指针。

input_allocate_device:申请输入设备对象内存

type = &usbtouch_dev_info[id->driver_info]:根据driver_info获取全局usbtouch_dev_info的数组项。

usbtouch_process_pkt用于中断回调函数,上传数据到应用层

usb_alloc_coherent:分配内存

usb_alloc_urb申请用于urb用于数据传输的内存,注意:这里将返回“usbtouch->data”

usbtouch->data记录了用于普通传输用的内存指针
usbtouch->buffer记录了用于存储读取到的数据的内存指针

usb_make_path填充设备结构体中的节点名。用来获取 USB 设备在 Sysfs 中的路径

usb_autopm_get_interface:电源唤醒

usb_submit_urb:提交urb

usb_autopm_put_interface:关闭电源

 

 主要来看一下usbtouch_dev_info

 1074 static struct usbtouch_device_info usbtouch_dev_info[] = {                                                                                                                                            
     1 #ifdef CONFIG_TOUCHSCREEN_USB_ELO
     2     [DEVTYPE_ELO] = {
     3         .min_xc     = 0x0,
     4         .max_xc     = 0x0fff,
     5         .min_yc     = 0x0,
     6         .max_yc     = 0x0fff,
     7         .max_press  = 0xff,
     8         .rept_size  = 8,
     9         .read_data  = elo_read_data,
    10     },
    11 #endif
    12
    13 #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
    14     [DEVTYPE_EGALAX] = {
    15         .min_xc     = 0x0,
    16         .max_xc     = 0x07ff,
    17         .min_yc     = 0x0,
    18         .max_yc     = 0x07ff,
    19         .rept_size  = 16,
    20         .process_pkt    = usbtouch_process_multi,
    21         .get_pkt_len    = egalax_get_pkt_len,
    22         .read_data  = egalax_read_data,
    23         .init       = egalax_init,
    24     },
    25 #endif

 ............................

 }

   

以DEVTYPE_EGALAX为例:

egalax_init:初始化设备

  48 static int egalax_init(struct usbtouch_usb *usbtouch)
    47 {
    46     int ret, i;
    45     unsigned char *buf;
    44     struct usb_device *udev = interface_to_usbdev(usbtouch->interface);

   //interface_to_usbdev:根据usb_interface指针intf获取usb_device的地址。
    
    32     buf[0] = EGALAX_PKT_TYPE_DIAG;
    31     buf[1] = 1; /* length */
    30     buf[2] = 'A';   /* command - check active */
    29
    28     for (i = 0; i < 3; i++) {
    27         ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
    26                       0,
    25                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
    24                       0, 0, buf, 3,
    23                       USB_CTRL_SET_TIMEOUT);
 

  //usb_control_msg:是没有用到urb的在USB中简单进行发送和接收的一种机制,用于少量的数据通信。

    11 }


egalax_get_pkt_len:获取包的长度

 357  static int egalax_get_pkt_len(unsigned char *buf, int len)                                                                                                                                            
     1 {
     2     switch (buf[0] & EGALAX_PKT_TYPE_MASK) {
     3     case EGALAX_PKT_TYPE_REPT:
     4         return 5;
     5
     6     case EGALAX_PKT_TYPE_DIAG:
     7         if (len < 2)
     8             return -1;
     9
    10         return buf[1] + 2;
    11     }
    12
    13     return 0;
    14 }


egalax_read_data:用于中断回调函数,用于读取数据

  345  static int egalax_read_data(struct usbtouch_usb *dev, unsigned char *pkt)                                                                                                                             
     1 {
     2     if ((pkt[0] & EGALAX_PKT_TYPE_MASK) != EGALAX_PKT_TYPE_REPT)
     3         return 0;
     4
     5     dev->x = ((pkt[3] & 0x0F) << 7) | (pkt[4] & 0x7F);
     6     dev->y = ((pkt[1] & 0x0F) << 7) | (pkt[2] & 0x7F);
     7     dev->touch = pkt[0] & 0x01;
     8
     9     return 1;
    10 }


usbtouch_process_multi:用于中断回调函数,用于上传数据

   12 static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
    13                                    unsigned char *pkt, int len)
    14 {

  ...............

   34         tmp = pkt_len - usbtouch->buf_len;
    33         if (usbtouch->buf_len + tmp >= usbtouch->type->rept_size)
    32             goto out_flush_buf;
    31         memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, tmp);
    30         usbtouch_process_pkt(usbtouch, usbtouch->buffer, pkt_len);

  ................

    25         if (likely((pkt_len > 0) && (pkt_len <= buf_len - pos))) {
    24             usbtouch_process_pkt(usbtouch, buffer + pos, pkt_len);
    23         } else {
    22             /* incomplete packet: save in buffer */
    21             memcpy(usbtouch->buffer, buffer + pos, buf_len - pos);
    20             usbtouch->buf_len = buf_len - pos;
    19             return;
    18         }

  ................



  1292 static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,                                                                                                                                       
  1                                  unsigned char *pkt, int len)
     2 {
  ............
   8     input_report_key(usbtouch->input, BTN_TOUCH, usbtouch->touch);
   
    14         input_report_abs(usbtouch->input, ABS_X, usbtouch->x);
    15         input_report_abs(usbtouch->input, ABS_Y, usbtouch->y);
 
    17     if (type->max_press)
    18         input_report_abs(usbtouch->input, ABS_PRESSURE, usbtouch->press);
  19     input_sync(usbtouch->input);
    20 }



最后,简单说一下urb,urb全称:USB request block,可以看作数据运输的工具,主要流程如下:

1.usb设备驱动程序创建并初始化一个访问特定usb设备端点的urb,并提交给usb core。

2.usb core提交该urb到usb主控制器驱动程序

3.usb主控制器驱动程序根据urb描述的信息来访问usb设备

具体流程:

(1)创建urb

struct urb* usb_alloc_urb(int isoc_packets, int mem_flags);

iso_packets:urb 所包含的等时数据包的个数,若不是等时传输则为0。

mem_flags:内存分配标志(如GFP_KERNEL)

(2)中断urb的初始化

void usb_fill_int_urb(struct urb* urb,

struct usb_device* dev,

unsigned int pipe,

void* transfer_buffer,

int buffer_length,

usb_complete_t complete,

void* context,

int interval

);

struct urb* urb:要初始化的urb指针

struct usb_device* dev:要访问的设备

transfer_buffer:收/发数据的缓冲区

buffer_length:缓冲区长度

complete:当完成urb所请求的操作后调用此函数。

context:complete函数所需的上下文,通常值为dev

interval:urb被调度的时间间隔。

pipe:要访问的端点所对应的管道,使用usb_sndintpipe()或usb_rcvintpipe()创建,如下:

pipe是一个管道号,该管道记录了目标设备的端点以及管道的类型。每个管道只有一种类型和一个方向,与他的目标设备的端点相对应,可以通过一下几个函数来获得管道号并设置管道类型:

 unsigned int usb_sndctrlpipe(struct usb_device* dev, unsigned int endpoint):把指定usb设备的指定端点设置为一个控制out端点。

 unsigned int usb_rcvctrlpipe(struct usb_device* dev, unsigned int endpoint):把指定usb设备的指定端点设置为一个控制in端点。

 unsigned int usb_sndbulkpipe(struct usb_device* dev, unsigned int endpoint):把指定usb设备的指定端点设置为一个批量out端点。

 unsigned int usb_rcvbulkpipe(struct usb_device* dev, unsigned int endpoint):把指定usb设备的指定端点设置为一个批量in端点。

 unsigned int usb_sndintpipe(struct usb_device* dev, unsigned int endpoint):把指定usb设备的指定端点设置为一个中断out端点。

 unsigned int usb_rcvintpipe(struct usb_device* dev, unsigned int endpoint):把指定usb设备的指定端点设置为一个中断in端点。

 unsigned int usb_sndisocpipe(struct usb_device* dev, unsigned int endpoint):把指定usb设备的指定端点设置为一个等时out端点。

 unsigned int usb_rcvisocpipe(struct usb_device* dev, unsigned int endpoint):把指定usb设备的指定端点设置为一个等时in端点。


对于批量urb和控制urb,用下面函数:

void usb_fill_bulk_urb(struct urb* urb, struct usb_device* dev, unsigned int pipe, void* transfer_buffer, int buffer_length, usb_complete_t complete, void* context);

void usb_fill_bulk_urb(struct urb* urb, struct usb_device* dev, unsigned int pipe, unsigned char* setup_packet, void* transfer_buffer, int buffer_length, usb_complete_t complete, void* context);


(3)创建和初始化完成后,urb便可以通过usb_submit_urb函数提交到usb核心:

int usb_submit_urb(struct urb* urb, gfp_t mem_flags)

urb:指向urb的指针

mem_flags:内存分配标志,用于告诉usb核心如何分配内存缓冲区。

mem_flags的几种标志:GFP_ATOMIC、GFP_NOIO、GFP_KERNEL,一般在中断上下文环境中我们会用GFP_ATOMIC

(4)提交后,urb会调用回调函数,回调函数主要检查status字段(当一个urb把数据送到设备时,这个urb会由系统返回给驱动程序,并调用驱动程序的urb完成回调函数处理,这是status记录了这次数据传输的有关状态,如是否成功,成功则返回0),以确定数据是否传输成功.


usb中的endpoint和传输模式可以参考一下:http://blog.chinaunix.net/uid-25314474-id-3040231.html






















  

你可能感兴趣的:(USB触摸屏的驱动)