usbtouch的linux驱动分析

    上个月写过个关于eGalax Touchkit触摸屏的东西,感觉当时只能算是贴代码,没能写的系统些。今天想试着再写点

    回头看了看那篇发表的时间,不得不小感慨下时间的飞快。也是今天终于有了点时间。好吧,不废话了

    (我也争取由eGalax Touchkit这个点展开成这一类驱动的面)


   1. eGalax Touchkit是什么

    这是款带有usb设备接口的触摸屏,电阻屏、电容屏都有。其物理尺寸能达到15.6"。我感觉比较有用的文档是 eGalaxTouch Software Programming Guide Version 2.0 - EETI这个是可以google出来的

  

    2. 模块位置和所涉及的知识(或者叫功能模块)

    其驱动的具体实现是在\drivers\input\touchscreen\usbtouchscreen.c中实现的。而在这个驱动模块中借助了usb和input两个子系统的东西来实现


    3. 具体实现过程

    整个的驱动模块是从static int __init usbtouch_init(void)函数开始的。从表面上看,他只是注册了名为usbtouch_driver的struct usb_driver 结构体,也就是由这个函数usb_register(&usbtouch_driver)所实现的。

struct usb_driver {
        const char *name;

        int (*probe) (struct usb_interface *intf,
                      const struct usb_device_id *id);

        void (*disconnect) (struct usb_interface *intf);

        int (*ioctl) (struct usb_interface *intf, unsigned int code,
                        void *buf);

        int (*suspend) (struct usb_interface *intf, pm_message_t message);
        int (*resume) (struct usb_interface *intf);
        int (*reset_resume)(struct usb_interface *intf);

        int (*pre_reset)(struct usb_interface *intf);
        int (*post_reset)(struct usb_interface *intf);

        const struct usb_device_id *id_table;

        struct usb_dynids dynids;
        struct usbdrv_wrap drvwrap;
        unsigned int no_dynamic_id:1;

        unsigned int supports_autosuspend:1;
        unsigned int soft_unbind:1;
};
在这个结构体中,我们主要用到了name,probe,disconnect,id_table四项。

name:给定driver的名字

probe:提过给usb核心,以便将来有匹配的设备插入后的驱动模块的匹配工作

disconnect:与probe功能恰恰相反,设备断开时使用

id_table:向usb核心声明本驱动都支持哪些设备


struct usb_device_id {
        /* which fields to match against? */
        __u16           match_flags;

        /* Used for product specific matches; range is inclusive */
        __u16           idVendor;
        __u16           idProduct;
        __u16           bcdDevice_lo;
        __u16           bcdDevice_hi;
        
        /* Used for device class matches */
        __u8            bDeviceClass;
        __u8            bDeviceSubClass;
        __u8            bDeviceProtocol;

        /* Used for interface class matches */
        __u8            bInterfaceClass;
        __u8            bInterfaceSubClass;
        __u8            bInterfaceProtocol;

        /* not matched against */
        kernel_ulong_t  driver_info;
};

该结构体同样不必全给出,在给出时我们可以用到一些宏定义来给出

我们可能需要做的就是要在static struct usb_device_id usbtouch_devices[]这个结构体中添加我们的设备id号进去

而我使用到的一款egalax触摸屏恰恰没有包含进来,也就有了这么一行

    {USB_DEVICE(0x0eef, 0x7241), .driver_info = DEVTYPE_EGALAX},


下面开始涉及我认为整个驱动最关键的两个函数——usbtouch_probe和usbtouch_irq

先从usbtouch_probe说 起,该函数是在usb_register(&usbtouch_driver)时传给usb核心的,当usb检测到我们在上面声明的static struct usb_device_id usbtouch_devices[]中的设备插入时会调用这个probe

在probe中所需要做的是:设备与驱动的匹配工作,相关结构体(譬如urb)、数据缓存区的申请,udev、sys的注册,input设备的注册,以及针对特殊触摸屏设备的初始化

我想在probe需要特别提出来的几点:

  a。 在从usb申请相关的内存是需要使用usb_buffer_alloc函数,而不能是其它,这个是有特殊要求的

  b。 input设备的注册,即input_register_device函数的调用必须等到前面所有的申请、初始化结束之后

  c。 这里用到了两种urb:中断urb和控制urb。中断urb是为获得触摸屏设备返回的触摸事件的数据,控制urb是为初始化触摸屏设备。

  d。触摸屏作为使用绝对坐标的设备,就有了

    input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
    input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
    input_set_abs_params(input_dev, ABS_X, type->min_xc, type->max_xc, 0, 0);
    input_set_abs_params(input_dev, ABS_Y, type->min_yc, type->max_yc, 0, 0);

这样的设置

   e。对于我所用到的两款egalax触摸屏,恰恰是少了初始化函数。具体到我的实现里,我使用了

static ssize_t egalax_send_data(struct usbtouch_usb *dev, unsigned char *buf, int len)函数,对向usb控制器提交控制urb进行了封装


     在static void usbtouch_irq(struct urb *urb)函数中,对中断进行处理

usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length);

这行则是整个中断数据的处理。使用了指针,对多款触摸屏的数据处理进行了封装(具体使用哪个处理函数就需要看你所打开的宏开关,以及具体插入的设备了)

下面就用EGALAX来讲吧,其最终指向了

static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,  unsigned char *pkt, int len) 函数

在这个函数中首先调用static int egalax_get_pkt_len(unsigned char *buf, int len)函数计算出中断返回的数据的有效长度

以及调用static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,  unsigned char *pkt, int len)对中断返回的数据进行处理,包括分析出所对应的x,y,及press值,并向input核心提交input事件

具体的分析过程是由

static int egalax_read_data(struct usbtouch_usb *dev, unsigned char *pkt) 函数完成的。它根据具体设备的中断数据格式来处理

而我所使用的到两款egalax触摸屏返回的数据格式是略有不同的



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值