linux/drivers/input/touchscreen/touchwin.c
<<
>>
Prefs
   1/*
   2 * Touchwindow serial touchscreen driver
   3 *
   4 * Copyright (c) 2006 Rick Koch <n1gp@hotmail.com>
   5 *
   6 * Based on MicroTouch driver (drivers/input/touchscreen/mtouch.c)
   7 * Copyright (c) 2004 Vojtech Pavlik
   8 * and Dan Streetman <ddstreet@ieee.org>
   9 */
  10
  11/*
  12 * This program is free software; you can redistribute it and/or modify it
  13 * under the terms of the GNU General Public License version 2 as published
  14 * by the Free Software Foundation.
  15 */
  16
  17/*
  18 * 2005/02/19 Rick Koch:
  19 *   The Touchwindow I used is made by Edmark Corp. and
  20 *   constantly outputs a stream of 0's unless it is touched.
  21 *   It then outputs 3 bytes: X, Y, and a copy of Y.
  22 */
  23
  24#include <linux/errno.h>
  25#include <linux/kernel.h>
  26#include <linux/module.h>
  27#include <linux/slab.h>
  28#include <linux/input.h>
  29#include <linux/serio.h>
  30#include <linux/init.h>
  31
  32#define DRIVER_DESC     "Touchwindow serial touchscreen driver"
  33
  34MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>");
  35MODULE_DESCRIPTION(DRIVER_DESC);
  36MODULE_LICENSE("GPL");
  37
  38/*
  39 * Definitions & global arrays.
  40 */
  41
  42#define TW_LENGTH 3
  43
  44#define TW_MIN_XC 0
  45#define TW_MAX_XC 0xff
  46#define TW_MIN_YC 0
  47#define TW_MAX_YC 0xff
  48
  49/*
  50 * Per-touchscreen data.
  51 */
  52
  53struct tw {
  54        struct input_dev *dev;
  55        struct serio *serio;
  56        int idx;
  57        int touched;
  58        unsigned char data[TW_LENGTH];
  59        char phys[32];
  60};
  61
  62static irqreturn_t tw_interrupt(struct serio *serio,
  63                unsigned char data, unsigned int flags)
  64{
  65        struct tw *tw = serio_get_drvdata(serio);
  66        struct input_dev *dev = tw->dev;
  67
  68        if (data) {             /* touch */
  69                tw->touched = 1;
  70                tw->data[tw->idx++] = data;
  71                /* verify length and that the two Y's are the same */
  72                if (tw->idx == TW_LENGTH && tw->data[1] == tw->data[2]) {
  73                        input_report_abs(dev, ABS_X, tw->data[0]);
  74                        input_report_abs(dev, ABS_Y, tw->data[1]);
  75                        input_report_key(dev, BTN_TOUCH, 1);
  76                        input_sync(dev);
  77                        tw->idx = 0;
  78                }
  79        } else if (tw->touched) {       /* untouch */
  80                input_report_key(dev, BTN_TOUCH, 0);
  81                input_sync(dev);
  82                tw->idx = 0;
  83                tw->touched = 0;
  84        }
  85
  86        return IRQ_HANDLED;
  87}
  88
  89/*
  90 * tw_disconnect() is the opposite of tw_connect()
  91 */
  92
  93static void tw_disconnect(struct serio *serio)
  94{
  95        struct tw *tw = serio_get_drvdata(serio);
  96
  97        input_get_device(tw->dev);
  98        input_unregister_device(tw->dev);
  99        serio_close(serio);
 100        serio_set_drvdata(serio, NULL);
 101        input_put_device(tw->dev);
 102        kfree(tw);
 103}
 104
 105/*
 106 * tw_connect() is the routine that is called when someone adds a
 107 * new serio device that supports the Touchwin protocol and registers it as
 108 * an input device.
 109 */
 110
 111static int tw_connect(struct serio *serio, struct serio_driver *drv)
 112{
 113        struct tw *tw;
 114        struct input_dev *input_dev;
 115        int err;
 116
 117        tw = kzalloc(sizeof(struct tw), GFP_KERNEL);
 118        input_dev = input_allocate_device();
 119        if (!tw || !input_dev) {
 120                err = -ENOMEM;
 121                goto fail1;
 122        }
 123
 124        tw->serio = serio;
 125        tw->dev = input_dev;
 126        snprintf(tw->phys, sizeof(tw->phys), "%s/input0", serio->phys);
 127
 128        input_dev->name = "Touchwindow Serial TouchScreen";
 129        input_dev->phys = tw->phys;
 130        input_dev->id.bustype = BUS_RS232;
 131        input_dev->id.vendor = SERIO_TOUCHWIN;
 132        input_dev->id.product = 0;
 133        input_dev->id.version = 0x0100;
 134        input_dev->dev.parent = &serio->dev;
 135        input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 136        input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
 137        input_set_abs_params(tw->dev, ABS_X, TW_MIN_XC, TW_MAX_XC, 0, 0);
 138        input_set_abs_params(tw->dev, ABS_Y, TW_MIN_YC, TW_MAX_YC, 0, 0);
 139
 140        serio_set_drvdata(serio, tw);
 141
 142        err = serio_open(serio, drv);
 143        if (err)
 144                goto fail2;
 145
 146        err = input_register_device(tw->dev);
 147        if (err)
 148                goto fail3;
 149
 150        return 0;
 151
 152 fail3: serio_close(serio);
 153 fail2: serio_set_drvdata(serio, NULL);
 154 fail1: input_free_device(input_dev);
 155        kfree(tw);
 156        return err;
 157}
 158
 159/*
 160 * The serio driver structure.
 161 */
 162
 163static struct serio_device_id tw_serio_ids[] = {
 164        {
 165                .type   = SERIO_RS232,
 166                .proto  = SERIO_TOUCHWIN,
 167                .id     = SERIO_ANY,
 168                .extra  = SERIO_ANY,
 169        },
 170        { 0 }
 171};
 172
 173MODULE_DEVICE_TABLE(serio, tw_serio_ids);
 174
 175static struct serio_driver tw_drv = {
 176        .driver         = {
 177                .name   = "touchwin",
 178        },
 179        .description    = DRIVER_DESC,
 180        .id_table       = tw_serio_ids,
 181        .interrupt      = tw_interrupt,
 182        .connect        = tw_connect,
 183        .disconnect     = tw_disconnect,
 184};
 185
 186/*
 187 * The functions for inserting/removing us as a module.
 188 */
 189
 190static int __init tw_init(void)
 191{
 192        return serio_register_driver(&tw_drv);
 193}
 194
 195static void __exit tw_exit(void)
 196{
 197        serio_unregister_driver(&tw_drv);
 198}
 199
 200module_init(tw_init);
 201module_exit(tw_exit);
 202