linux/drivers/input/touchscreen/mtouch.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * MicroTouch (3M) serial touchscreen driver
   4 *
   5 * Copyright (c) 2004 Vojtech Pavlik
   6 */
   7
   8
   9/*
  10 * 2005/02/19 Dan Streetman <ddstreet@ieee.org>
  11 *   Copied elo.c and edited for MicroTouch protocol
  12 */
  13
  14#include <linux/errno.h>
  15#include <linux/kernel.h>
  16#include <linux/module.h>
  17#include <linux/slab.h>
  18#include <linux/input.h>
  19#include <linux/serio.h>
  20
  21#define DRIVER_DESC     "MicroTouch serial touchscreen driver"
  22
  23MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
  24MODULE_DESCRIPTION(DRIVER_DESC);
  25MODULE_LICENSE("GPL");
  26
  27/*
  28 * Definitions & global arrays.
  29 */
  30
  31#define MTOUCH_FORMAT_TABLET_STATUS_BIT 0x80
  32#define MTOUCH_FORMAT_TABLET_TOUCH_BIT 0x40
  33#define MTOUCH_FORMAT_TABLET_LENGTH 5
  34#define MTOUCH_RESPONSE_BEGIN_BYTE 0x01
  35#define MTOUCH_RESPONSE_END_BYTE 0x0d
  36
  37/* todo: check specs for max length of all responses */
  38#define MTOUCH_MAX_LENGTH 16
  39
  40#define MTOUCH_MIN_XC 0
  41#define MTOUCH_MAX_XC 0x3fff
  42#define MTOUCH_MIN_YC 0
  43#define MTOUCH_MAX_YC 0x3fff
  44
  45#define MTOUCH_GET_XC(data) (((data[2])<<7) | data[1])
  46#define MTOUCH_GET_YC(data) (((data[4])<<7) | data[3])
  47#define MTOUCH_GET_TOUCHED(data) (MTOUCH_FORMAT_TABLET_TOUCH_BIT & data[0])
  48
  49/*
  50 * Per-touchscreen data.
  51 */
  52
  53struct mtouch {
  54        struct input_dev *dev;
  55        struct serio *serio;
  56        int idx;
  57        unsigned char data[MTOUCH_MAX_LENGTH];
  58        char phys[32];
  59};
  60
  61static void mtouch_process_format_tablet(struct mtouch *mtouch)
  62{
  63        struct input_dev *dev = mtouch->dev;
  64
  65        if (MTOUCH_FORMAT_TABLET_LENGTH == ++mtouch->idx) {
  66                input_report_abs(dev, ABS_X, MTOUCH_GET_XC(mtouch->data));
  67                input_report_abs(dev, ABS_Y, MTOUCH_MAX_YC - MTOUCH_GET_YC(mtouch->data));
  68                input_report_key(dev, BTN_TOUCH, MTOUCH_GET_TOUCHED(mtouch->data));
  69                input_sync(dev);
  70
  71                mtouch->idx = 0;
  72        }
  73}
  74
  75static void mtouch_process_response(struct mtouch *mtouch)
  76{
  77        if (MTOUCH_RESPONSE_END_BYTE == mtouch->data[mtouch->idx++]) {
  78                /* FIXME - process response */
  79                mtouch->idx = 0;
  80        } else if (MTOUCH_MAX_LENGTH == mtouch->idx) {
  81                printk(KERN_ERR "mtouch.c: too many response bytes\n");
  82                mtouch->idx = 0;
  83        }
  84}
  85
  86static irqreturn_t mtouch_interrupt(struct serio *serio,
  87                unsigned char data, unsigned int flags)
  88{
  89        struct mtouch *mtouch = serio_get_drvdata(serio);
  90
  91        mtouch->data[mtouch->idx] = data;
  92
  93        if (MTOUCH_FORMAT_TABLET_STATUS_BIT & mtouch->data[0])
  94                mtouch_process_format_tablet(mtouch);
  95        else if (MTOUCH_RESPONSE_BEGIN_BYTE == mtouch->data[0])
  96                mtouch_process_response(mtouch);
  97        else
  98                printk(KERN_DEBUG "mtouch.c: unknown/unsynchronized data from device, byte %x\n",mtouch->data[0]);
  99
 100        return IRQ_HANDLED;
 101}
 102
 103/*
 104 * mtouch_disconnect() is the opposite of mtouch_connect()
 105 */
 106
 107static void mtouch_disconnect(struct serio *serio)
 108{
 109        struct mtouch *mtouch = serio_get_drvdata(serio);
 110
 111        input_get_device(mtouch->dev);
 112        input_unregister_device(mtouch->dev);
 113        serio_close(serio);
 114        serio_set_drvdata(serio, NULL);
 115        input_put_device(mtouch->dev);
 116        kfree(mtouch);
 117}
 118
 119/*
 120 * mtouch_connect() is the routine that is called when someone adds a
 121 * new serio device that supports MicroTouch (Format Tablet) protocol and registers it as
 122 * an input device.
 123 */
 124
 125static int mtouch_connect(struct serio *serio, struct serio_driver *drv)
 126{
 127        struct mtouch *mtouch;
 128        struct input_dev *input_dev;
 129        int err;
 130
 131        mtouch = kzalloc(sizeof(struct mtouch), GFP_KERNEL);
 132        input_dev = input_allocate_device();
 133        if (!mtouch || !input_dev) {
 134                err = -ENOMEM;
 135                goto fail1;
 136        }
 137
 138        mtouch->serio = serio;
 139        mtouch->dev = input_dev;
 140        snprintf(mtouch->phys, sizeof(mtouch->phys), "%s/input0", serio->phys);
 141
 142        input_dev->name = "MicroTouch Serial TouchScreen";
 143        input_dev->phys = mtouch->phys;
 144        input_dev->id.bustype = BUS_RS232;
 145        input_dev->id.vendor = SERIO_MICROTOUCH;
 146        input_dev->id.product = 0;
 147        input_dev->id.version = 0x0100;
 148        input_dev->dev.parent = &serio->dev;
 149        input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 150        input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
 151        input_set_abs_params(mtouch->dev, ABS_X, MTOUCH_MIN_XC, MTOUCH_MAX_XC, 0, 0);
 152        input_set_abs_params(mtouch->dev, ABS_Y, MTOUCH_MIN_YC, MTOUCH_MAX_YC, 0, 0);
 153
 154        serio_set_drvdata(serio, mtouch);
 155
 156        err = serio_open(serio, drv);
 157        if (err)
 158                goto fail2;
 159
 160        err = input_register_device(mtouch->dev);
 161        if (err)
 162                goto fail3;
 163
 164        return 0;
 165
 166 fail3: serio_close(serio);
 167 fail2: serio_set_drvdata(serio, NULL);
 168 fail1: input_free_device(input_dev);
 169        kfree(mtouch);
 170        return err;
 171}
 172
 173/*
 174 * The serio driver structure.
 175 */
 176
 177static const struct serio_device_id mtouch_serio_ids[] = {
 178        {
 179                .type   = SERIO_RS232,
 180                .proto  = SERIO_MICROTOUCH,
 181                .id     = SERIO_ANY,
 182                .extra  = SERIO_ANY,
 183        },
 184        { 0 }
 185};
 186
 187MODULE_DEVICE_TABLE(serio, mtouch_serio_ids);
 188
 189static struct serio_driver mtouch_drv = {
 190        .driver         = {
 191                .name   = "mtouch",
 192        },
 193        .description    = DRIVER_DESC,
 194        .id_table       = mtouch_serio_ids,
 195        .interrupt      = mtouch_interrupt,
 196        .connect        = mtouch_connect,
 197        .disconnect     = mtouch_disconnect,
 198};
 199
 200module_serio_driver(mtouch_drv);
 201