usb 接口触摸屏驱动

来源:互联网 发布:java web基础书籍推荐 编辑:程序博客网 时间:2024/04/30 11:23

以前写的 USB 接口的触摸屏驱动,那段时间简单的看了下 USB 协议的一些东西,主要是 HID 相关的,代码记录:

/*Created by_fire2012.2.13*/#include <linux/kernel.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/module.h>#include <linux/kref.h>#include <linux/uaccess.h>#include <linux/usb.h>#include <linux/mutex.h>#include <linux/input.h>#include <linux/usb/input.h>#define DEBUG 0#if DEBUG#define usb_ts_dbg(fmt, arg...) printk(fmt, ##arg)#else#define usb_ts_dbg(arg...) #endif/* Define these values to match your devices */#define USB_SKEL_VENDOR_ID0x0eef#define USB_SKEL_PRODUCT_ID0x0001/* table of devices that work with this driver */static const struct usb_device_id usb_ts_table[] = {{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },{ }/* Terminating entry */};MODULE_DEVICE_TABLE(usb, usb_ts_table);static int swap_xy;module_param(swap_xy, bool, 0644);MODULE_PARM_DESC(swap_xy, "If set X and Y axes are swapped.");struct usb_ts;struct usb_ts_device_info {int min_xc, max_xc;int min_yc, max_yc;int min_press, max_press;int rept_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. */bool irq_always;void (*process_pkt) (struct usb_ts *usbtouch, unsigned char *pkt, int len);/* * used to get the packet len. possible return values: * > 0: packet len * = 0: skip one byte * < 0: -return value more bytes needed */int  (*get_pkt_len) (unsigned char *pkt, int len);int  (*read_data)   (struct usb_ts *usbtouch, unsigned char *pkt);int  (*init)        (struct usb_ts *usbtouch);void (*exit)    (struct usb_ts *usbtouch);};/* a usbtouch device */struct usb_ts {unsigned char *data;dma_addr_t data_dma;unsigned char *buffer;int buf_len;struct urb *int_urb;struct usb_interface *interface;struct input_dev *input;struct usb_ts_device_info *dev_info;char name[128];char phys[64];void *priv;int x, y;int touch, press;};static int usb_ts_read_data(struct usb_ts *dev, unsigned char *pkt){usb_ts_dbg("%s\n", __func__);dev->x = ((pkt[3] & 0x0F) << 7) | (pkt[4] & 0x7F);dev->y = ((pkt[1] & 0x0F) << 7) | (pkt[2] & 0x7F);dev->touch = pkt[0] & 0x01;dev->press = 0x01;return 1;}static void usb_ts_process_pkt(struct usb_ts *usbtouch, unsigned char *pkt, int len){usb_ts_dbg("%s\n", __func__);struct usb_ts_device_info *dev_info = usbtouch->dev_info;int i;if(!(pkt[0] & 0x80)) return;#if 0for(i = 0; i < len; i++)printk("pkt[%d] = %02x ", i, pkt[i]);printk("\n");#endifif (!dev_info->read_data(usbtouch, pkt))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);input_report_abs(usbtouch->input, ABS_Y, usbtouch->y);}usb_ts_dbg("x = %d, y = %d, p = %d\n", usbtouch->x, usbtouch->y, usbtouch->touch);if (dev_info->max_press)input_report_abs(usbtouch->input, ABS_PRESSURE, usbtouch->press);input_sync(usbtouch->input);}static struct usb_ts_device_info usb_ts_dev_info[] = {[0] = {.min_xc= 50,.max_xc= 1960,.min_yc= 140,.max_yc= 1900,.min_press  = 0x0,.max_press  = 0x1,.rept_size= 16,.process_pkt= usb_ts_process_pkt,.read_data= usb_ts_read_data,},};static void usb_ts_irq(struct urb *urb){usb_ts_dbg("%s\n", __func__);struct usb_ts *usbtouch = urb->context;int retval;switch (urb->status) {case 0:/* success */break;case -ETIME:/* this urb is timing out */usb_ts_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 */usb_ts_dbg("%s - urb shutting down with status: %d", __func__, urb->status);return;default:usb_ts_dbg("%s - nonzero urb status received: %d", __func__, urb->status);goto exit;}usbtouch->dev_info->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);}static int usb_ts_open(struct input_dev *input){usb_ts_dbg("%s\n", __func__);struct usb_ts *usbtouch = input_get_drvdata(input);usbtouch->int_urb->dev = interface_to_usbdev(usbtouch->interface);if (!usbtouch->dev_info->irq_always) {if (usb_submit_urb(usbtouch->int_urb, GFP_KERNEL))  return -EIO;}return 0;}static void usb_ts_close(struct input_dev *input){usb_ts_dbg("%s\n", __func__);struct usb_ts *usbtouch = input_get_drvdata(input);if (!usbtouch->dev_info->irq_always)usb_kill_urb(usbtouch->int_urb);}static void usb_ts_free_buffers(struct usb_device *udev, struct usb_ts *usbtouch){usb_ts_dbg("%s\n", __func__);usb_free_coherent(udev, usbtouch->dev_info->rept_size, usbtouch->data, usbtouch->data_dma);kfree(usbtouch->buffer);}static struct usb_endpoint_descriptor *usb_ts_get_input_endpoint(struct usb_host_interface *interface){usb_ts_dbg("%s\n", __func__);int i;for (i = 0; i < interface->desc.bNumEndpoints; i++)if (usb_endpoint_dir_in(&interface->endpoint[i].desc))return &interface->endpoint[i].desc;return NULL;}static int usb_ts_probe(struct usb_interface *intf, const struct usb_device_id *id){struct usb_ts *usbtouch;struct input_dev *input_dev;struct usb_endpoint_descriptor *endpoint;struct usb_device *udev = interface_to_usbdev(intf);struct usb_ts_device_info *dev_info;int err = -ENOMEM;usb_ts_dbg("%s 1\n", __func__);endpoint = usb_ts_get_input_endpoint(intf->cur_altsetting);if (!endpoint)return -ENXIO;usbtouch = kzalloc(sizeof(struct usb_ts), GFP_KERNEL);input_dev = input_allocate_device();if (!usbtouch || !input_dev)goto out_free;dev_info = &usb_ts_dev_info[0];usbtouch->dev_info = dev_info;if (!dev_info->process_pkt)dev_info->process_pkt = usb_ts_process_pkt;usbtouch->data = usb_alloc_coherent(udev, dev_info->rept_size, GFP_KERNEL, &usbtouch->data_dma);if (!usbtouch->data)goto out_free;if (dev_info->get_pkt_len) {usbtouch->buffer = kmalloc(dev_info->rept_size, GFP_KERNEL);if (!usbtouch->buffer)goto out_free_buffers;}usbtouch->int_urb = usb_alloc_urb(0, GFP_KERNEL);if (!usbtouch->int_urb) {usb_ts_dbg("%s - usb_alloc_urb failed: usbtouch->irq", __func__);goto out_free_buffers;}usb_ts_dbg("%s 2\n", __func__);usbtouch->interface = intf;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));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;input_set_drvdata(input_dev, usbtouch);input_dev->open = usb_ts_open;input_dev->close = usb_ts_close;usb_ts_dbg("%s 3\n", __func__);input_dev->evbit[0] = BIT_MASK(EV_SYN) | 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, dev_info->min_xc, dev_info->max_xc, 0, 0);input_set_abs_params(input_dev, ABS_Y, dev_info->min_yc, dev_info->max_yc, 0, 0);if (dev_info->max_press)input_set_abs_params(input_dev, ABS_PRESSURE, dev_info->min_press, dev_info->max_press, 0, 0);if (usb_endpoint_type(endpoint) == USB_ENDPOINT_XFER_INT)usb_fill_int_urb(usbtouch->int_urb, udev, usb_rcvintpipe(udev, endpoint->bEndpointAddress), usbtouch->data, dev_info->rept_size, usb_ts_irq, usbtouch, endpoint->bInterval);elseusb_fill_bulk_urb(usbtouch->int_urb, udev, usb_rcvbulkpipe(udev, endpoint->bEndpointAddress), usbtouch->data, dev_info->rept_size, usb_ts_irq, usbtouch);usbtouch->int_urb->dev = udev;usbtouch->int_urb->transfer_dma = usbtouch->data_dma;usbtouch->int_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;/* device specific init */if (dev_info->init) {err = dev_info->init(usbtouch);if (err) {usb_ts_dbg("%s - type->init() failed, err: %d", __func__, err);goto out_free_urb;}}err = input_register_device(usbtouch->input);if (err) {usb_ts_dbg("%s - input_register_device failed, err: %d", __func__, err);goto out_do_exit;}usb_set_intfdata(intf, usbtouch);if (usbtouch->dev_info->irq_always) {err = usb_submit_urb(usbtouch->int_urb, GFP_KERNEL);if (err) {err("%s - usb_submit_urb failed with result: %d",    __func__, err);goto out_unregister_input;}}usb_ts_dbg("%s 4\n", __func__);return 0;out_unregister_input:input_unregister_device(input_dev);input_dev = NULL;out_do_exit:if (dev_info->exit)dev_info->exit(usbtouch);out_free_urb:usb_free_urb(usbtouch->int_urb);out_free_buffers:usb_ts_free_buffers(udev, usbtouch);out_free:input_free_device(input_dev);kfree(usbtouch);return err;}static void usb_ts_disconnect(struct usb_interface *intf){struct usb_ts *usbtouch = usb_get_intfdata(intf);usb_ts_dbg("%s - called", __func__);if (!usbtouch)return;usb_ts_dbg("%s - usbtouch is initialized, cleaning up", __func__);usb_set_intfdata(intf, NULL);/* this will stop IO via close */input_unregister_device(usbtouch->input);usb_free_urb(usbtouch->int_urb);if (usbtouch->dev_info->exit)usbtouch->dev_info->exit(usbtouch);usb_ts_free_buffers(interface_to_usbdev(intf), usbtouch);kfree(usbtouch);}static struct usb_driver usb_ts_driver = {.name= "usb_ts",.probe= usb_ts_probe,.disconnect= usb_ts_disconnect,.id_table= usb_ts_table,};static int __init usb_ts_init(void){int result;/* register this driver with the USB subsystem */result = usb_register(&usb_ts_driver);if (result)err("usb_register failed. Error number %d", result);return result;}static void __exit usb_ts_exit(void){/* deregister this driver with the USB subsystem */usb_deregister(&usb_ts_driver);}module_init(usb_ts_init);module_exit(usb_ts_exit);MODULE_AUTHOR("fire <fire@gochen.com.cn>");MODULE_DESCRIPTION("Gochen USB Touchscreen driver");MODULE_LICENSE("GPL");
原创粉丝点击