linux系统usb触摸驱动,Linux ——usb触摸屏驱动 - usbtouchscreen

驱动编译:

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

staticint__init usbtouch_init(void)

{

returnusb_register(&usbtouch_driver);//调用了usb 核心的注册函数,传入的是一个usb_driver结构体指针

}

usb_register实现在/kernel/include/linux/usb.h中:

staticinlineintusb_register(structusb_driver*driver)

{

returnusb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);//这里再往后就是usb核心驱动的事,注册这个module驱动到usb总线上

}

这里必须是要先注册的总线,当一个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使用了部分接口:

staticstructusb_driver usbtouch_driver = {

.name="usbtouchscreen",//driver name

.probe= usbtouch_probe,//probe接口,用于总线上匹配检测到这个驱动对应的设备之后,/kernel/drivers/usb/core/driver.c中的usb_probe_interface调用到我们这个驱动的接口

.disconnect= usbtouch_disconnect,//与probe相反,断开的时候调用

.suspend= usbtouch_suspend,//usb 设备挂起

.resume= usbtouch_resume,// 和上面挂起相反,唤醒

.reset_resume= usbtouch_reset_resume,// 重置唤醒

.id_table= usbtouch_devices,//支持的设备ID表

.supports_autosuspend=1,

};

id_table:

首先可以关注一下 id_table 这个变量,代表支持的设备id列表,数据类型为:

structusb_device_id {

/* which fields to match against? */

__u16match_flags;

/* Used for product specific matches; range is inclusive */

__u16idVendor;

__u16idProduct;

__u16bcdDevice_lo;

__u16bcdDevice_hi;

/* Used for device class matches */

__u8bDeviceClass;

__u8bDeviceSubClass;

__u8bDeviceProtocol;

/* Used for interface class matches */

__u8bInterfaceClass;

__u8bInterfaceSubClass;

__u8bInterfaceProtocol;

/* not matched against */

kernel_ulong_t  driver_info;

};

这些设备信息会被上面说到的usb bus 来匹配对应的驱动,只有这里的信息跟usb设备驱动那边收集到的设备信息匹配上,才会调用进这个驱动.

目前已有的id_table:

staticconststructusb_device_id usbtouch_devices[] = {

#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX

/* ignore the HID capable devices, handled by usbhid */

{USB_DEVICE_HID_CLASS(0x0eef,0x0001),.driver_info= DEVTYPE_IGNORE},

{USB_DEVICE_HID_CLASS(0x0eef,0x0002),.driver_info= DEVTYPE_IGNORE},

...

#endif

...

};

其中可以看到 两个字节的十六进制数字,第一个代表idVendor 厂商ID,idProduct 产品ID ,这两个一般作为设备的标识.

driver_info:

像上面的usbtouch_devices的数组中driver_info 设置为枚举值:

/* device types */

enum{

DEVTYPE_IGNORE = -1,

DEVTYPE_EGALAX,

DEVTYPE_PANJIT,

DEVTYPE_3M,

DEVTYPE_ITM,

DEVTYPE_ETURBO,

DEVTYPE_GUNZE,

DEVTYPE_DMC_TSC10,

DEVTYPE_IRTOUCH,

DEVTYPE_IDEALTEK,

DEVTYPE_GENERAL_TOUCH,

DEVTYPE_GOTOP,

DEVTYPE_JASTEC,

DEVTYPE_E2I,

DEVTYPE_ZYTRONIC,

DEVTYPE_TC45USB,

DEVTYPE_NEXIO,

};

那么这些driver 的真正的info保存在哪里呢? 在注册的时候,现在只是注册上去一个枚举数字而已,

真正有设备识别到的时候这些个枚举值就起到作用了! 在下面的 usbtouch_probe 会介绍!

usbtouch_probe:

在前面有稍微提到,usbtouchscreen驱动是怎么被映射到的,这个过程暂时不做深入,作为这个驱动中的第一个接入点就是usbtouch_probe.

staticintusbtouch_probe(structusb_interface*intf,

conststructusb_device_id*id)

{

structusbtouch_usb*usbtouch;//usbtouch 设备

structinput_dev*input_dev;//输入设备

structusb_endpoint_descriptor*endpoint;//usb 的端点

structusb_device*udev = interface_to_usbdev(intf);//从usb接口获取对应的设备

structusbtouch_device_info*type;//这个就是上面说的真正的 driver info了

endpoint = usbtouch_get_input_endpoint(intf->cur_altsetting);  //获取端点

if(!endpoint)

return-ENXIO;

usbtouch = kzalloc(sizeof(structusbtouch_usb), GFP_KERNEL);

input_dev = input_allocate_device();  //分配内存,申请input 设备结构

...

type = &usbtouch_dev_info[id->driver_info];// 这里就用到了 上面说到的枚举值了, 真正的info 是放在这个数组里面的!

...

usbtouch->irq = usb_alloc_urb(0, GFP_KERNEL);//分配了一个urb 用于 获得触摸屏设备返回的触摸事件的数据,urb的概念可参考usb driver

if(!usbtouch->irq) {

dbg("%s - usb_alloc_urb failed: usbtouch->irq", __func__);

gotoout_free_buffers;

}

...

//往下都是一些分配内存,input注册,初始化操作了

input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);//这里是就是input设备触摸坐标的初始化赋值了,为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);

...

if(usb_endpoint_type(endpoint) == USB_ENDPOINT_XFER_INT)

usb_fill_int_urb(usbtouch->irq, udev,

usb_rcvintpipe(udev, endpoint->bEndpointAddress),

usbtouch->data, type->rept_size,

usbtouch_irq, usbtouch, endpoint->bInterval);

else

usb_fill_bulk_urb(usbtouch->irq, udev,

usb_rcvbulkpipe(udev, endpoint->bEndpointAddress),

usbtouch->data, type->rept_size,

usbtouch_irq, usbtouch);  //初始化urb的回调函数为 usbtouch_irq

usbtouch->irq->dev = udev;

usbtouch->irq->transfer_dma = usbtouch->data_dma;

usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

...

}

usbtouch_device_info:

这个就是上面driver_info 以及usbtouch_probe 中抽取的驱动模块的info数组,不同的usbtouchscreen 注册的时候就是注册了一个枚举值,这个值就是usbtouch_dev_info 数组的第几元素.

structusbtouch_device_info {

intmin_xc, max_xc;

intmin_yc, max_yc;

intmin_press, max_press;

intrept_size;

/*

* Always service the USB devices irq not just when the input device is

* open. This is useful when devices have a watchdog which prevents us

* from periodically polling the device. Leave this unset unless your

* touchscreen device requires it, as it does consume more of the USB

* bandwidth.

*/

boolirq_always;

void(*process_pkt) (structusbtouch_usb*usbtouch, unsignedcharchar*pkt,intlen);//这个函数指针是用来接收处理中断的。

/*

* used to get the packet len. possible return values:

* > 0: packet len

* = 0: skip one byte

*/

int(*get_pkt_len) (unsignedcharchar*pkt,intlen);

int(*read_data)   (structusbtouch_usb*usbtouch, unsignedcharchar*pkt);

int(*alloc)       (structusbtouch_usb*usbtouch);

int(*init)        (structusbtouch_usb*usbtouch);

void(*exit)        (structusbtouch_usb*usbtouch);

};

usbtouch_dev_info

数组:

staticstructusbtouch_device_info usbtouch_dev_info[] = {

#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX

[DEVTYPE_EGALAX] = {

.min_xc=0x0,

.max_xc=0x07ff,

.min_yc=0x0,

.max_yc=0x07ff,

.rept_size=16,

.process_pkt= usbtouch_process_multi,//用于中断回调函数,用于处理中断,得到input的event,上传数据

.get_pkt_len= egalax_get_pkt_len,

.read_data= egalax_read_data,//用于中断回调函数,用于读取数据

},

#endif

...

#ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH

[DEVTYPE_IRTOUCH] = {

.min_xc=0x0,

.max_xc=0x0fff,

.min_yc=0x0,

.max_yc=0x0fff,

.rept_size=8,

.read_data= irtouch_read_data,

},

#endif

...

};

可以看到这个数组的成员都是以前面说到的注册枚举值来区分的!这些x,y 参数以及回调函数,都在上面说到的 usbtouch_probe 中被抽离出来使用.

usbtouch_irq:

这个函数作为中断响应函数,在上面的 usbtouch_probe中初始化,看下函数主要实现:

staticvoidusbtouch_irq(structurb*urb)

{

...

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

//这个type的类型就是 usbtouch_device_info,此时的process_pkt指针自然指向的是上面对应的函数,如果此时是触发的设备type为 DEVTYPE_EGALAX,那么这里调用的 usbtouch_process_multi

//如果此时是DEVTYPE_IRTOUCH 那么就是执行 usbtouch_process_pkt函数,因为usbtouch_probe中:

//    if (!type->process_pkt)

//        type->process_pkt = usbtouch_process_pkt;

...

}

接下来的都会调用到usbtouch_process_pkt中,通过type->read_data,和上面一样的指针读取,然后调用input_report_key发送,input_sync用于同步.

关于usbtouchscreen的驱动部分就分析到这里。

参与评论 您还未登录,请先 登录 后发表或查看评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:深蓝海洋 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值