From: giwoong.kim Date: Thu, 16 Feb 2012 05:30:41 +0000 (+0900) Subject: [Title] add maru_touchscreen file X-Git-Tag: 2.2.1_release^2~182^2^2~5 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=da03f33aee4711fad00ae1837841f75fc4d3e718;p=sdk%2Femulator%2Femulator-kernel.git [Title] add maru_touchscreen file [Type] feature [Module] emulator / touch [Priority] major [Jira#] [Redmine#] [Problem] [Cause] [Solution] [TestCase] Change-Id: I9fde4c5635163ba76c5ae162ec54ee50abf5ec10 --- diff --git a/drivers/maru/maru_touchscreen.c b/drivers/maru/maru_touchscreen.c new file mode 100755 index 000000000000..d3a4eed8807c --- /dev/null +++ b/drivers/maru/maru_touchscreen.c @@ -0,0 +1,307 @@ +/* + * Virtual USB Touchscreen device driver + * Based on drivers/input/tablet/wacom_sys.c: + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * GiWoong Kim + * Hyunjun Son + * DongKyun Yun + * YeongKyoon Lee + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("s-core"); +MODULE_DESCRIPTION("Emulator Touchscreen driver for x86"); + +/* touchscreen device features */ +#define USB_VENDOR_ID_SAMSUNG 0x0419 +#define EMUL_TOUCHSCREEN_PACKET_LEN 7 +#define TOUCHSCREEN_RESOLUTION_X 5040 +#define TOUCHSCREEN_RESOLUTION_Y 3780 +#define ABS_PRESSURE_MAX 255 + +struct emul_touchscreen { + dma_addr_t data_dma; + struct input_dev *emuldev; + struct usb_device *usbdev; + struct usb_interface *intf; + struct urb *irq; + unsigned char *data; + struct mutex lock; + unsigned int open:1; + char phys[32]; +}; + +/* These structure must match the qemu definitions */ +typedef struct USBEmulTouchscreenPacket { + uint16_t x, y, z; + uint8_t state; +} USBEmulTouchscreenPacket; + + +static void emul_touchscreen_sys_irq(struct urb *urb) +{ + struct emul_touchscreen *usb_ts = urb->context; + struct input_dev *input_dev = usb_ts->emuldev; + USBEmulTouchscreenPacket *packet = (USBEmulTouchscreenPacket *)usb_ts->data; + int retval; + + switch (urb->status) { + case 0: + /* success */ + break; + 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; + } + + if (packet->state != 0) { //pressed + input_report_abs(input_dev, ABS_MT_TRACKING_ID, packet->z); + input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, 5); + input_report_abs(input_dev, ABS_MT_POSITION_X, packet->x); + input_report_abs(input_dev, ABS_MT_POSITION_Y, packet->y); + input_mt_sync(input_dev); + } else { //release + if (packet->z == 1) { + input_report_abs(input_dev, ABS_MT_TRACKING_ID, 1); + input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, 0); + input_mt_sync(input_dev); + } + input_report_abs(input_dev, ABS_MT_TRACKING_ID, 0); + input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, 0); + input_mt_sync(input_dev); + } + + input_sync(input_dev); + + exit: + usb_mark_last_busy(usb_ts->usbdev); + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) { + err("%s - usb_submit_urb failed with result %d", __func__, retval); + } +} + +static int emul_touchscreen_open(struct input_dev *dev) +{ + struct emul_touchscreen *usb_ts = input_get_drvdata(dev); + + mutex_lock(&usb_ts->lock); + usb_ts->irq->dev = usb_ts->usbdev; + + if (usb_autopm_get_interface(usb_ts->intf) < 0) { + mutex_unlock(&usb_ts->lock); + return -EIO; + } + + if (usb_submit_urb(usb_ts->irq, GFP_KERNEL)) { + usb_autopm_put_interface(usb_ts->intf); + mutex_unlock(&usb_ts->lock); + return -EIO; + } + + usb_ts->open = 1; + usb_ts->intf->needs_remote_wakeup = 1; + + mutex_unlock(&usb_ts->lock); + return 0; +} + +static void emul_touchscreen_close(struct input_dev *dev) +{ + struct emul_touchscreen *usb_ts = input_get_drvdata(dev); + + mutex_lock(&usb_ts->lock); + usb_kill_urb(usb_ts->irq); + usb_ts->open = 0; + usb_ts->intf->needs_remote_wakeup = 0; + mutex_unlock(&usb_ts->lock); +} + +static int emul_touchscreen_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct usb_endpoint_descriptor *endpoint; + struct emul_touchscreen *usb_ts; + int error = -ENOMEM; + + usb_ts = kzalloc(sizeof(struct emul_touchscreen), GFP_KERNEL); + if (!usb_ts) { + goto fail1; + } + + usb_ts->usbdev = interface_to_usbdev(intf); + usb_ts->data = usb_buffer_alloc(usb_ts->usbdev, 10, GFP_KERNEL, &usb_ts->data_dma); + if (!usb_ts->data) { + goto fail1; + } + + usb_ts->irq = usb_alloc_urb(0, GFP_KERNEL); + if (!usb_ts->irq) { + goto fail2; + } + + usb_ts->emuldev = input_allocate_device(); + if (!usb_ts->emuldev) { + goto fail1; + } + + usb_ts->intf = intf; + + mutex_init(&usb_ts->lock); + usb_make_path(usb_ts->usbdev, usb_ts->phys, sizeof(usb_ts->phys)); + strlcat(usb_ts->phys, "/input0", sizeof(usb_ts->phys)); + + usb_ts->emuldev->name = "Tizen Touchscreen"; + usb_to_input_id(usb_ts->usbdev, &usb_ts->emuldev->id); + + usb_ts->emuldev->dev.parent = &intf->dev; + + input_set_drvdata(usb_ts->emuldev, usb_ts); + + usb_ts->emuldev->open = emul_touchscreen_open; + usb_ts->emuldev->close = emul_touchscreen_close; + + endpoint = &intf->cur_altsetting->endpoint[0].desc; + + usb_ts->emuldev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + usb_ts->emuldev->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC); + usb_ts->emuldev->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(BTN_TOUCH); + + input_set_abs_params(usb_ts->emuldev, ABS_X, 0, TOUCHSCREEN_RESOLUTION_X, 4, 0); + input_set_abs_params(usb_ts->emuldev, ABS_Y, 0, TOUCHSCREEN_RESOLUTION_Y, 4, 0); + + /* for multitouch */ + input_set_abs_params(usb_ts->emuldev, ABS_MT_TRACKING_ID, 0, 1, 0, 0); + input_set_abs_params(usb_ts->emuldev, ABS_MT_TOUCH_MAJOR, 0, ABS_PRESSURE_MAX, 0, 0); + input_set_abs_params(usb_ts->emuldev, ABS_MT_POSITION_X, 0, TOUCHSCREEN_RESOLUTION_X, 0, 0); + input_set_abs_params(usb_ts->emuldev, ABS_MT_POSITION_Y, 0, TOUCHSCREEN_RESOLUTION_Y, 0, 0); + + usb_fill_int_urb(usb_ts->irq, usb_ts->usbdev, + usb_rcvintpipe(usb_ts->usbdev, endpoint->bEndpointAddress), + usb_ts->data, EMUL_TOUCHSCREEN_PACKET_LEN, + emul_touchscreen_sys_irq, usb_ts, endpoint->bInterval); + usb_ts->irq->transfer_dma = usb_ts->data_dma; + usb_ts->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + error = input_register_device(usb_ts->emuldev); + if (error) { + goto fail3; + } + + usb_set_intfdata(intf, usb_ts); + return 0; + + fail3: usb_free_urb(usb_ts->irq); + fail2: usb_buffer_free(usb_ts->usbdev, 10, usb_ts->data, usb_ts->data_dma); + fail1: input_free_device(usb_ts->emuldev); + kfree(usb_ts); + return error; +} + +static void emul_touchscreen_disconnect(struct usb_interface *intf) +{ + struct emul_touchscreen *usb_ts = usb_get_intfdata(intf); + + usb_set_intfdata(intf, NULL); + if (usb_ts) { + usb_kill_urb(usb_ts->irq); + input_unregister_device(usb_ts->emuldev); + usb_free_urb(usb_ts->irq); + usb_buffer_free(interface_to_usbdev(intf), 10, usb_ts->data, usb_ts->data_dma); + kfree(usb_ts); + } +} + +static int emul_touchscreen_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct emul_touchscreen *usb_ts = usb_get_intfdata(intf); + + mutex_lock(&usb_ts->lock); + usb_kill_urb(usb_ts->irq); + mutex_unlock(&usb_ts->lock); + + return 0; +} + +static int emul_touchscreen_resume(struct usb_interface *intf) +{ + struct emul_touchscreen *usb_ts = usb_get_intfdata(intf); + int rv; + + mutex_lock(&usb_ts->lock); + if (usb_ts->open) { + rv = usb_submit_urb(usb_ts->irq, GFP_NOIO); + } else { + rv = 0; + } + mutex_unlock(&usb_ts->lock); + + return rv; +} + +static struct usb_device_id emul_usb_touchscreen_table[] = { + { USB_DEVICE(USB_VENDOR_ID_SAMSUNG, 0x00) }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, emul_usb_touchscreen_table); + +static struct usb_driver emul_touchscreen_driver = { + .name = "usb_emul_touchscreen", + .id_table = emul_usb_touchscreen_table, + .probe = emul_touchscreen_probe, + .disconnect = emul_touchscreen_disconnect, + .suspend = emul_touchscreen_suspend, + .resume = emul_touchscreen_resume, + .reset_resume = emul_touchscreen_resume, + .supports_autosuspend = 1, +}; + +static int __init emul_touchscreen_init(void) +{ + int result = usb_register(&emul_touchscreen_driver); + if (result == 0) { + printk(KERN_ERR "emul_touchscreen_init: usb_register=%d\n", result); + } + + return result; +} + +static void __exit emul_touchscreen_exit(void) +{ + usb_deregister(&emul_touchscreen_driver); +} + +module_init(emul_touchscreen_init); +module_exit(emul_touchscreen_exit);