Linux usbtouchscreen驱动分析
2012-11-14 17:09
316 查看
原文链接地址:http://hi.baidu.com/chris_zheng/item/a95473e3962f3b236cabb851博主的文章不错:http://hi.baidu.com/new/chris_zheng?page=3 在Linux内核中自带USB触摸屏驱动,以linux-2.6.33.3\drivers\input\touchscreen.c为例,进行解析: 1.驱动加载: static int __init usbtouch_init(void) { return usb_register(&usbtouch_driver); //驱动注册 } 其中usbtouch_driver定义为: static struct usb_driver usbtouch_driver = { .name = "usbtouchscreen", //驱动名称 .probe = usbtouch_probe, //probe 函数 .disconnect = usbtouch_disconnect, //disconnect时调用的函数 .id_table = usbtouch_devices, //usbtouch 支持的设备列表 }; static struct usb_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}, /* normal device IDs */ {USB_DEVICE(0x3823, 0x0001), .driver_info = DEVTYPE_EGALAX}, {USB_DEVICE(0x3823, 0x0002), .driver_info = DEVTYPE_EGALAX}, {USB_DEVICE(0x0123, 0x0001), .driver_info = DEVTYPE_EGALAX}, .... 0x0123, 0x0001分别为VID和PID,driver_info 包含驱动信息,其类型为usbtouch_device_info。 例如DEVTYPE_EGALAX]定义为: static struct usbtouch_device_info usbtouch_dev_info[] = { #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX [DEVTYPE_EGALAX] = { .min_xc = 0x0, //X轴最小坐标 .max_xc = 0x07ff, //X轴最大坐标 .min_yc = 0x0, //Y轴最小坐标 .max_yc = 0x07ff, //Y轴最大坐标 .rept_size = 16, // .process_pkt = usbtouch_process_multi, //用于中断回调函数,用于上传数据 .get_pkt_len = egalax_get_pkt_len, .read_data = egalax_read_data, //用于中断回调函数,用于读取数据 }, #endif 所以在注册的时候,就注入了设备的信息,如果注册成功(usb_device_id中包含对应的硬件),就会调用usbtouch_probe方法。 2.probe方法: static int usbtouch_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usbtouch_usb *usbtouch; //a usbtouch device struct input_dev *input_dev; //a input device struct usb_host_interface *interface; /* usb 设备有一个configuration 的概念,表示配置,一个设备可以有多个配置, 但只能同时激活一个,如:一些设备可以下载固件,或可以设置不同的全局模式, cur_altsetting 就是表示的当前的这个setting,或者说设置。可以查看原码中 usb_interface 结构定义的说明部分。从说明中可以看到一个接口可以有多种setting*/ 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; interface = intf->cur_altsetting; endpoint = &interface->endpoint[0].desc; //端点0描述符,此处的0表示控制端点 usbtouch = kzalloc(sizeof(struct usbtouch_usb), GFP_KERNEL); //为设备分配内存 input_dev = input_allocate_device(); //申请input_dev结构 if (!usbtouch || !input_dev) goto out_free; type = &usbtouch_dev_info[id->driver_info]; //提取设备对应的Info usbtouch->type = type; if (!type->process_pkt) type->process_pkt = usbtouch_process_pkt; //用于中断回调函数,上传数据到应用层 usbtouch->data = usb_buffer_alloc(udev, type->rept_size, GFP_KERNEL, &usbtouch->data_dma); /*:记录了用于普通传输用的内存指针*/ /*usb_buffer_alloc(),这个函数是usbcore提供的,我们只管调用即可.从名字上就能知道它是用来申请内存的,第一个参数就是struct usb_device结构体的指针,所以我们要传递一个,第三个参数,GFP_KERNEL,是一个内存申请的flag,通常内存申请都用这个flag,除非是中断上下文,不能睡眠,那就得用GPF_ATOMIC,这里没那么多要求.第二个参数申请的buffer的大小,第四个参数,这个数据类型是Linux内核中专门为dma传输而准备的.为了支持dma传输,usb_buffer_alloc不仅仅是申请了地址,并且建立了dma映射.usb_buffer_alloc申请的内存空间需要用它的搭档usb_buffer_free()来释放.*/ if (!usbtouch->data) goto out_free; if (type->get_pkt_len) { usbtouch->buffer = kmalloc(type->rept_size, GFP_KERNEL); if (!usbtouch->buffer) goto out_free_buffers; } usbtouch->irq = usb_alloc_urb(0, GFP_KERNEL); if (!usbtouch->irq) { dbg("%s - usb_alloc_urb failed: usbtouch->irq", __func__); goto out_free_buffers; } usbtouch->udev = udev; usbtouch->input = input_dev; 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 设备在 Sysfs 中的路径,格式为:usb-usb 总线号-路径名。*/ strlcat(usbtouch->phys, "/input0", sizeof(usbtouch->phys)); /* 将设备的名称赋给设备内嵌的输入子系统结构体 */ input_dev->name = usbtouch->name; /* 将设备的设备节点名赋给设备内嵌的输入子系统结构体 */ input_dev->phys = usbtouch->phys; /* * input_dev 中的 input_id 结构体,用来存储厂商、设备类型和设备的编号,这个函数是将设备描述符 * 中的编号赋给内嵌的输入子系统结构体 */ usb_to_input_id(udev, &input_dev->id); input_dev->dev.parent = &intf->dev; input_set_drvdata(input_dev, usbtouch); /* 填充输入设备打开函数指针 */ input_dev->open = usbtouch_open; /* 填充输入设备关闭函数指针 */ input_dev->close = usbtouch_close; /* evbit 用来描述事件,EV_KEY 是按键事件,EV_ABS是绝对坐标事件,EV_REL 是相对坐标事件 */ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); /* keybit 表示键值 */ 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 (type->max_press) input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press, type->max_press, 0, 0); /* * 填充构建 urb,将刚才填充好的input_dev结构体的数据填充进urb 结构体中,在 open 中递交urb。 * 当 urb 包含一个即将传输的 DMA 缓冲区时应该设置 URB_NO_TRANSFER_DMA_MAP。USB核心使用 * transfer_dma变量所指向的缓冲区,而不是transfer_buffer变量所指向的。 * URB_NO_SETUP_DMA_MAP 用于 Setup 包,URB_NO_TRANSFER_DMA_MAP 用于所有 Data 包。 */ usb_fill_int_urb(usbtouch->irq, usbtouch->udev, usb_rcvintpipe(usbtouch->udev, endpoint->bEndpointAddress), usbtouch->data, type->rept_size, usbtouch_irq, usbtouch, endpoint->bInterval); usbtouch->irq->dev = usbtouch->udev; usbtouch->irq->transfer_dma = usbtouch->data_dma; usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; /* device specific init */ if (type->init) { err = type->init(usbtouch); if (err) { dbg("%s - type->init() failed, err: %d", __func__, err); goto out_free_buffers; } } err = input_register_device(usbtouch->input); if (err) { dbg("%s - input_register_device failed, err: %d", __func__, err); goto out_free_buffers; } /* * 一般在 probe 函数中,都需要将设备相关信息保存在一个 usb_interface 结构体中,以便以后通过 * usb_get_intfdata 获取使用。这里设备结构体信息将保存在 intf 接口结构体内嵌的设备结构体中 * 的 driver_data 数据成员中,即 intf->dev->dirver_data = ...。 */ usb_set_intfdata(intf, usbtouch); if (usbtouch->type->irq_always) usb_submit_urb(usbtouch->irq, GFP_KERNEL); return 0; out_free_buffers: usbtouch_free_buffers(udev, usbtouch); out_free: input_free_device(input_dev); kfree(usbtouch); return err; } 3.回调函数: /* * urb 回调函数,在完成提交 urb 后,urb 回调函数将被调用。 * 此函数作为 usb_fill_int_urb 函数的形参,为构建的 urb 制定的回调函数。 */ static void usbtouch_irq(struct urb *urb) { struct usbtouch_usb *usbtouch = urb->context; int retval; switch (urb->status) { case 0: /* 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: /* 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->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length); exit: retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval) err("%s - usb_submit_urb failed with result: %d", __func__, retval); } 4. input_sync 用于事件同步,它告知事件的接收者驱动已经发出了一个完整的报告.
相关文章推荐
- linux自带的usbtouchscreen.c也有bug?你猜对了!
- Linux usbtouchscreen驱动分析
- usb_touch_screen Linux 驱动
- usbtouch的linux驱动分析
- Linux ——usb触摸屏驱动 - usbtouchscreen
- Button input interrupt under linux kernel 2.6.35.7 send message to touch screen
- linux内核usb触摸屏驱动bug调试- selected device is not a touchscreen I understand
- Linux-Touchscreen Driver for X
- Touch Screen Driver for Linux2.6.xx+ARM9
- SkyEye TouchScreen For S3C2410 & Linux 2.6.36
- linux 3.15.2 触摸屏移植之selected device is not a touchscreen I understand
- I.MX6 Linux eGTouch TouchScreen porting
- linux内核usb触摸屏驱动bug调试- selected device is not a touchscreen I understand
- Linux usb驱动程序全注释
- linux 技巧:使用 screen 管理你的远程会话[转载]
- Linux下的硬件驱动——USB设备(上)(驱动配置部分)
- linux 技巧:使用 screen 管理你的远程会话
- Linux中touch的作用
- Linux的touch命令与cat命令
- Linux USB Host 驱动开发入门