static int __init usbtouch_init(void) //入口函数 { return usb_register(&usbtouch_driver); //注册usb触摸屏驱动 } module_init(usbtouch_init);
看usbtouch_driver的定义
static struct usb_driver usbtouch_driver = { .name = "usbtouchscreen", .probe = usbtouch_probe, //usb触摸屏探测到 .disconnect = usbtouch_disconnect, .suspend = usbtouch_suspend, .resume = usbtouch_resume, .reset_resume = usbtouch_reset_resume, .id_table = usbtouch_devices, .supports_autosuspend = 1, };
当有设备匹配的时候会调用probe方法,也就是usbtouch_probe
在static const struct usb_device_id usbtouch_devices[]中定义了的usb设备插入就会匹配并触发probe
可以用宏USB_DEVICE简化设置usb设备id信息,如下:
{USB_DEVICE(0x3823, 0x0001), .driver_info = DEVTYPE_EGALAX},
driver_info是驱动类型,有一下选择
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, };
没有选择也可以自己添加一个在枚举体后面
(0x3823,0x0001)这两个分别是usb设备的厂商id和产品id
下面代码是我插拔usb触摸屏的打印信息
usb 1-1.1: new full speed USB device using musb-hdrc and address 9 usb 1-1.1: New USB device found, idVendor=0408, idProduct=3001 usb 1-1.1: New USB device strings: Mfr=1, Product=2, SerialNumber=0 usb 1-1.1: Product: HCTouch usb 1-1.1: Manufacturer: HC input: HC HCTouch as /devices/platform/omap/ti81xx-usbss/musb-hdrc.0/usb1/1-1/1-1.1/1-1.1:1.0/input/input6 input: HC HCTouch as /devices/platform/omap/ti81xx-usbss/musb-hdrc.0/usb1/1-1/1-1.1/1-1.1:1.1/input/input7
作为我的设备,我就把idVendor=0408, idProduct=3001添加进USB_DEVICE宏就行
{USB_DEVICE(0x0408, 0x3001), .driver_info = DEVTYPE_HCTOUCH},
OK!插上设备就会匹配的
input: HC HCTouch as /devices/platform/omap/ti81xx-usbss/musb-hdrc.0/usb1/1-1/1-1.1/1-1.1:1.0/input/input6 input: HC HCTouch as /devices/platform/omap/ti81xx-usbss/musb-hdrc.0/usb1/1-1/1-1.1/1-1.1:1.1/input/input7
这个就是匹配后的打印信息
接着就是probe方法了
static int usbtouch_probe(struct usb_interface *intf,const struct usb_device_id *id) { struct usbtouch_usb *usbtouch; struct input_dev *input_dev; struct usb_endpoint_descriptor *endpoint; struct usb_device *udev = interface_to_usbdev(intf); struct usbtouch_device_info *type; int err = -ENOMEM; /* some devices are ignored */ if (id->driver_info == DEVTYPE_IGNORE) //忽略的设备类型 return -ENODEV; endpoint = usbtouch_get_input_endpoint(intf->cur_altsetting); //获取端点描述符数组指针 if (!endpoint) return -ENXIO; usbtouch = kzalloc(sizeof(struct usbtouch_usb), GFP_KERNEL); //分配usbtouch_usb结构体对象内存 input_dev = input_allocate_device(); //分配输入设备对象内存 if (!usbtouch || !input_dev) //分配不成功退出 goto out_free; type = &usbtouch_dev_info[id->driver_info]; //根据id的driver_info信息获取全局usbtouch_dev_info数组项 usbtouch->type = type; //指定usbtouch_dev_info if (!type->process_pkt) //若usbtouch_dev_info不存在process_pkt方法 type->process_pkt = usbtouch_process_pkt; //则默认设置为usbtouch_process_pkt usbtouch->data = usb_alloc_coherent(udev, type->rept_size,GFP_KERNEL, &usbtouch->data_dma); //分配缓冲区 if (!usbtouch->data) goto out_free; if (type->get_pkt_len) { //若usbtouch_dev_info存在get_pkt_len方法 usbtouch->buffer = kmalloc(type->rept_size, GFP_KERNEL); //则要根据rept_size分配usb_touch_usb对象缓冲区 if (!usbtouch->buffer) goto out_free_buffers; } usbtouch->irq = usb_alloc_urb(0, GFP_KERNEL); //分配urb if (!usbtouch->irq) { dbg("%s - usb_alloc_urb failed: usbtouch->irq", __func__); goto out_free_buffers; } usbtouch->interface = intf; //设置usb_touch_usb的usb接口 usbtouch->input = input_dev;//捆绑usb_touch_usb和输入设备 if (udev->manufacturer) //存在工厂名则设置工厂名 strlcpy(usbtouch->name, udev->manufacturer, sizeof(usbtouch->name)); if (udev->product) { //存在产品名则设置产品名 if (udev->manufacturer) strlcat(usbtouch->name, " ", sizeof(usbtouch->name)); strlcat(usbtouch->name, udev->product, sizeof(usbtouch->name)); } if (!strlen(usbtouch->name)) //若不存在工厂名和产品名 snprintf(usbtouch->name, sizeof(usbtouch->name), "USB Touchscreen %04x:%04x", le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct)); usb_make_path(udev, usbtouch->phys, sizeof(usbtouch->phys)); //设置usb设备路径 strlcat(usbtouch->phys, "/input0", sizeof(usbtouch->phys)); input_dev->name = usbtouch->name; //设置输入设备名 input_dev->phys = usbtouch->phys; //设置输入设备路径 usb_to_input_id(udev, &input_dev->id); input_dev->dev.parent = &intf->dev; //设置usb设备为输入设备的父设备 input_set_drvdata(input_dev, usbtouch); input_dev->open = usbtouch_open; //设置输入设备的open方法 input_dev->close = usbtouch_close; //设置输入设备的close方法 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); //绝对x坐标位移 input_set_abs_params(input_dev, ABS_Y, type->min_yc, type->max_yc, 0, 0); //绝对y坐标位移 if (type->max_press) input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press,type->max_press, 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 //bulk传输方式 usb_fill_bulk_urb(usbtouch->irq, udev, usb_rcvbulkpipe(udev, endpoint->bEndpointAddress), usbtouch->data, type->rept_size, usbtouch_irq, usbtouch); usbtouch->irq->dev = udev; //urb和usb设备捆绑 usbtouch->irq->transfer_dma = usbtouch->data_dma; //传输数据dma地址缓冲区 usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; //传输标志物dma映射传输 /* device specific allocations */ if (type->alloc) { //usbtouch_dev_info对象存在alloc方法 err = type->alloc(usbtouch); //则调用该方法 if (err) { dbg("%s - type->alloc() failed, err: %d", __func__, err); goto out_free_urb; } } /* device specific initialisation*/ if (type->init) { //usbtouch_dev_info对象存在初始化方法 err = type->init(usbtouch); //则调用该初始化方法 if (err) { dbg("%s - type->init() failed, err: %d", __func__, err); goto out_do_exit; } } err = input_register_device(usbtouch->input); //注册输入设备 if (err) { dbg("%s - input_register_device failed, err: %d", __func__, err); goto out_do_exit; } usb_set_intfdata(intf, usbtouch); if (usbtouch->type->irq_always) { //usbtouch_dev_info对象存在irq_always方法 /* this can't fail */ usb_autopm_get_interface(intf); //电源唤醒 err = usb_submit_urb(usbtouch->irq, GFP_KERNEL); //提交urb if (err) { usb_autopm_put_interface(intf); //电源挂起 err("%s - usb_submit_urb failed with result: %d", __func__, err); goto out_unregister_input; } } return 0; out_unregister_input: input_unregister_device(input_dev); input_dev = NULL; out_do_exit: if (type->exit) type->exit(usbtouch); out_free_urb: usb_free_urb(usbtouch->irq); out_free_buffers: usbtouch_free_buffers(udev, usbtouch); out_free: input_free_device(input_dev); kfree(usbtouch); return err; }
错中复杂的关系不用管,关键是
1.type = &usbtouch_dev_info[id->driver_info]; //根据id的driver_info信息获取全局usbtouch_dev_info数组项
2.if (!type->process_pkt) //若usbtouch_dev_info不存在process_pkt方法
type->process_pkt = usbtouch_process_pkt; //则默认设置为usbtouch_process_pkt
3.申请的urb的回调函数是usbtouch_irq
4.if (type->init) { //usbtouch_dev_info对象存在初始化方法
err = type->init(usbtouch); //则调用该初始化方法
usbtouch_dev_info是全局usbtouch_device_info数组
static struct usbtouch_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, .get_pkt_len = egalax_get_pkt_len, .read_data = egalax_read_data, }, #endif #ifdef CONFIG_TOUCHSCREEN_USB_PANJIT [DEVTYPE_PANJIT] = { .min_xc = 0x0, .max_xc = 0x0fff, .min_yc = 0x0, .max_yc = 0x0fff, .rept_size = 8, .read_data = panjit_read_data, }, #endif #ifdef CONFIG_TOUCHSCREEN_USB_3M [DEVTYPE_3M] = { .min_xc = 0x0, .max_xc = 0x4000, .min_yc = 0x0, .max_yc = 0x4000, .rept_size = 11, .read_data = mtouch_read_data, .init = mtouch_init, }, #endif #ifdef CONFIG_TOUCHSCREEN_USB_ITM [DEVTYPE_ITM] = { .min_xc = 0x0, .max_xc = 0x0fff, .min_yc = 0x0, .max_yc = 0x0fff, .max_press = 0xff, .rept_size = 8, .read_data = itm_read_data, }, #endif #ifdef CONFIG_TOUCHSCREEN_USB_ETURBO [DEVTYPE_ETURBO] = { .min_xc = 0x0, .max_xc = 0x07ff, .min_yc = 0x0, .max_yc = 0x07ff, .rept_size = 8, .process_pkt = usbtouch_process_multi, .get_pkt_len = eturbo_get_pkt_len, .read_data = eturbo_read_data, }, #endif #ifdef CONFIG_TOUCHSCREEN_USB_GUNZE [DEVTYPE_GUNZE] = { .min_xc = 0x0, .max_xc = 0x0fff, .min_yc = 0x0, .max_yc = 0x0fff, .rept_size = 4, .read_data = gunze_read_data, }, #endif #ifdef CONFIG_TOUCHSCREEN_USB_DMC_TSC10 [DEVTYPE_DMC_TSC10] = { .min_xc = 0x0, .max_xc = 0x03ff, .min_yc = 0x0, .max_yc = 0x03ff, .rept_size = 5, .init = dmc_tsc10_init, .read_data = dmc_tsc10_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 #ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK [DEVTYPE_IDEALTEK] = { .min_xc = 0x0, .max_xc = 0x0fff, .min_yc = 0x0, .max_yc = 0x0fff, .rept_size = 8, .process_pkt = usbtouch_process_multi, .get_pkt_len = idealtek_get_pkt_len, .read_data = idealtek_read_data, }, #endif #ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH [DEVTYPE_GENERAL_TOUCH] = { .min_xc = 0x0, .max_xc = 0x7fff, .min_yc = 0x0, .max_yc = 0x7fff, .rept_size = 7, .read_data = general_touch_read_data, }, #endif #ifdef CONFIG_TOUCHSCREEN_USB_GOTOP [DEVTYPE_GOTOP] = { .min_xc = 0x0, .max_xc = 0x03ff, .min_yc = 0x0, .max_yc = 0x03ff, .rept_size = 4, .read_data = gotop_read_data, }, #endif #ifdef CONFIG_TOUCHSCREEN_USB_JASTEC [DEVTYPE_JASTEC] = { .min_xc = 0x0, .max_xc = 0x0fff, .min_yc = 0x0, .max_yc = 0x0fff, .rept_size = 4, .read_data = jastec_read_data, }, #endif #ifdef CONFIG_TOUCHSCREEN_USB_E2I [DEVTYPE_E2I] = { .min_xc = 0x0, .max_xc = 0x7fff, .min_yc = 0x0, .max_yc = 0x7fff, .rept_size = 6, .init = e2i_init, .read_data = e2i_read_data, }, #endif #ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC [DEVTYPE_ZYTRONIC] = { .min_xc = 0x0, .max_xc = 0x03ff, .min_yc = 0x0, .max_yc = 0x03ff, .rept_size = 5, .read_data = zytronic_read_data, .irq_always = true, }, #endif #ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC45USB [DEVTYPE_TC45USB] = { .min_xc = 0x0, .max_xc = 0x0fff, .min_yc = 0x0, .max_yc = 0x0fff, .rept_size = 5, .read_data = tc45usb_read_data, }, #endif #ifdef CONFIG_TOUCHSCREEN_USB_NEXIO [DEVTYPE_NEXIO] = { .rept_size = 1024, .irq_always = true, .read_data = nexio_read_data, .alloc = nexio_alloc, .init = nexio_init, .exit = nexio_exit, }, #endif };
由于我DIY了一个,所以后面要添加
[DEVTYPE_HCTOUCH] = { .min_xc = 0x0, //最小x坐标 .max_xc = 0x7fff, //最大x坐标 .min_yc = 0x0, //最小y坐标 .max_yc = 0x7fff, //最大y坐标 .rept_size = 7, //还不知道是干嘛用的 .read_data = hc_touch_read_data, //关键的读数据方法 },
当触摸屏幕的时候,usb会通过urb传递数据,紧接着肯定会调用usbtouch_irq啦
static void usbtouch_irq(struct urb *urb) { struct usbtouch_usb *usbtouch = urb->context; int retval; switch (urb->status) { case 0: //正常流程跳出switch语句 /* success */ break; case -ETIME: /* this urb is timing out */ dbg("%s - urb timed out - was the device unplugged?", __func__); return; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: case -EPIPE: /* this urb is terminated, clean up */ dbg("%s - urb shutting down with status: %d", __func__, urb->status); return; default: dbg("%s - nonzero urb status received: %d", __func__, urb->status); goto exit; } //执行usbtouch_device_info对象的process_pkt方法 usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length); exit: usb_mark_last_busy(interface_to_usbdev(usbtouch->interface)); retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval) err("%s - usb_submit_urb failed with result: %d", __func__, retval); }
这里的关键是会调用process_pkt方法也就是默认的usbtouch_process_pkt函数
static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,unsigned char *pkt, int len) //默认的usb触摸数据包处理函数 { struct usbtouch_device_info *type = usbtouch->type; //获取usbtouch_device_info对象 if (!type->read_data(usbtouch, pkt)) //调用usbtouch_device_info对象的read_data方法 return; input_report_key(usbtouch->input, BTN_TOUCH, usbtouch->touch); //上报触摸事件 if (swap_xy) { //竖屏模式 input_report_abs(usbtouch->input, ABS_X, usbtouch->y); input_report_abs(usbtouch->input, ABS_Y, usbtouch->x); } else { input_report_abs(usbtouch->input, ABS_X, usbtouch->x); //上报绝对坐标X事件 input_report_abs(usbtouch->input, ABS_Y, usbtouch->y); //上报绝对坐标Y事件 } if (type->max_press) input_report_abs(usbtouch->input, ABS_PRESSURE, usbtouch->press); input_sync(usbtouch->input); //同步输入事件 }
这个函数主要是调用了usbtouch_device_info对象的read_data方法也就是上面提到的数组的read_data方法(hc_touch_read_data)
数据读取完毕后上报触摸事件,绝对XY坐标事件,然后同步交由输入子系统去处理坐标等具体事项
hc_touch_read_data函数读取usb接口传递过来的数据,该数据就包含了坐标和触摸信息,函数主要是对这些信息做下运算处理
static int hc_touch_read_data(struct usbtouch_usb *dev, unsigned char *pkt) { dev->x = (pkt[2] << 8) | pkt[1]; dev->y = (pkt[4] << 8) | pkt[3]; dev->press = pkt[5] & 0xff; dev->touch = pkt[0] & 0x01; return 1; }
这些处理的细节跟具体硬件厂商或者协议有关,调试可以将dev->x和dev->y打印出来
可能你加了打印之后触摸屏幕压根就没有打印信息
那是因为要打开设备,所以应用层也要有测试软件,有界面的测试软件最好
没有也可以用下面这段代码去简单测试一下(来着网络)
#include <stdio.h> #include <linux/input.h> static int event0_fd = -1; struct input_event ev0[64]; static int handle_event0() { int button = 0, realx=0, realy=0, i, rd; rd = read(event0_fd, ev0, sizeof(struct input_event)* 64); if(rd < sizeof(struct input_event)) return 0; for(i=0;i<rd/sizeof(struct input_event); i++) { if(EV_ABS == ev0[i].type) { if(ev0[i].code == 0) { realx = ev0[i].value; } else if(ev0[i].code == 1) { realy = ev0[i].value; } } printf("realx:%3d; realy:%3d\n",realx,realy); //printf("event(%d):type:%d; code:%3d; value:%3d; realx:%3d; realy:%3d\n",i,ev0[i].type,ev0[i].code,ev0[i].value,realx,realy); } return 1; } int main(void) { int done = 1; event0_fd = open("/dev/input/event1",02); //打开设备 if(event0_fd <0) { printf("open input device error\n"); return -1; } while (done) { //printf("begin handle_event0...\n"); done = handle_event0(); //printf("end handle_event0...\n"); } if(event0_fd > 0) { close(event0_fd); event0_fd = -1; } return 0; }
这段代码打开的设备修改成你的设备路径,插拔触摸屏判断哪个是你触摸屏的设备
或者ls -l /sys/class/input看信息结合插入设备的打印信息也可以判断你的设备是哪个
lrwxrwxrwx 1 root root 0 Mar 23 17:20 event0 -> ../../devices/platform/omap/ti81xx-usbss/musb-hdrc.0/usb1/1-1/1-1.1/1-1.1:1.0/input/input6/event0 lrwxrwxrwx 1 root root 0 Mar 23 17:20 event1 -> ../../devices/platform/omap/ti81xx-usbss/musb-hdrc.0/usb1/1-1/1-1.1/1-1.1:1.1/input/input7/event1 lrwxrwxrwx 1 root root 0 Mar 23 17:20 event2 -> ../../devices/platform/omap/ti81xx-usbss/musb-hdrc.0/usb1/1-1/1-1.3/1-1.3:1.0/input/input8/event2
再或者cat /proc/bus/input/devices也可以
I: Bus=0003 Vendor=0408 Product=3001 Version=0200 N: Name="HC HCTouch " P: Phys=usb-musb-hdrc.0-1.1/input0 S: Sysfs=/devices/platform/omap/ti81xx-usbss/musb-hdrc.0/usb1/1-1/1-1.1/1-1.1:1.0/input/input6 U: Uniq= H: Handlers=mouse0 event0 B: EV=b B: KEY=400 0 0 0 0 0 0 0 0 0 0 B: ABS=3 I: Bus=0003 Vendor=0408 Product=3001 Version=0200 N: Name="HC HCTouch " P: Phys=usb-musb-hdrc.0-1.1/input0 S: Sysfs=/devices/platform/omap/ti81xx-usbss/musb-hdrc.0/usb1/1-1/1-1.1/1-1.1:1.1/input/input7 U: Uniq= H: Handlers=mouse1 event1 B: EV=b B: KEY=400 0 0 0 0 0 0 0 0 0 0 B: ABS=3
这里我的设备有两个input是因为我是2点的屏
还有一点要补充就是关于内核编译选项的
Device Drivers --->Input device support --->
[*] Touchscreens --->
<*> USB Touchscreen Driver 这个要选择
[*] HID Devices ---> <*> USB Human Interface Device (full HID) support 选中