linux/drivers/input/touchscreen/inexio.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * iNexio serial touchscreen driver
   4 *
   5 * Copyright (c) 2008 Richard Lemon
   6 * Based on the mtouch driver (c) Vojtech Pavlik and Dan Streetman
   7 */
   8
   9
  10/*
  11 * 2008/06/19 Richard Lemon <richard@codelemon.com>
  12 *   Copied mtouch.c and edited for iNexio protocol
  13 */
  14
  15#include <linux/errno.h>
  16#include <linux/kernel.h>
  17#include <linux/module.h>
  18#include <linux/slab.h>
  19#include <linux/input.h>
  20#include <linux/serio.h>
  21
  22#define DRIVER_DESC     "iNexio serial touchscreen driver"
  23
  24MODULE_AUTHOR("Richard Lemon <richard@codelemon.com>");
  25MODULE_DESCRIPTION(DRIVER_DESC);
  26MODULE_LICENSE("GPL");
  27
  28/*
  29 * Definitions & global arrays.
  30 */
  31
  32#define INEXIO_FORMAT_TOUCH_BIT 0x01
  33#define INEXIO_FORMAT_LENGTH 5
  34#define INEXIO_RESPONSE_BEGIN_BYTE 0x80
  35
  36/* todo: check specs for max length of all responses */
  37#define INEXIO_MAX_LENGTH 16
  38
  39#define INEXIO_MIN_XC 0
  40#define INEXIO_MAX_XC 0x3fff
  41#define INEXIO_MIN_YC 0
  42#define INEXIO_MAX_YC 0x3fff
  43
  44#define INEXIO_GET_XC(data) (((data[1])<<7) | data[2])
  45#define INEXIO_GET_YC(data) (((data[3])<<7) | data[4])
  46#define INEXIO_GET_TOUCHED(data) (INEXIO_FORMAT_TOUCH_BIT & data[0])
  47
  48/*
  49 * Per-touchscreen data.
  50 */
  51
  52struct inexio {
  53        struct input_dev *dev;
  54        struct serio *serio;
  55        int idx;
  56        unsigned char data[INEXIO_MAX_LENGTH];
  57        char phys[32];
  58};
  59
  60static void inexio_process_data(struct inexio *pinexio)
  61{
  62        struct input_dev *dev = pinexio->dev;
  63
  64        if (INEXIO_FORMAT_LENGTH == ++pinexio->idx) {
  65                input_report_abs(dev, ABS_X, INEXIO_GET_XC(pinexio->data));
  66                input_report_abs(dev, ABS_Y, INEXIO_GET_YC(pinexio->data));
  67                input_report_key(dev, BTN_TOUCH, INEXIO_GET_TOUCHED(pinexio->data));
  68                input_sync(dev);
  69
  70                pinexio->idx = 0;
  71        }
  72}
  73
  74static irqreturn_t inexio_interrupt(struct serio *serio,
  75                unsigned char data, unsigned int flags)
  76{
  77        struct inexio *pinexio = serio_get_drvdata(serio);
  78
  79        pinexio->data[pinexio->idx] = data;
  80
  81        if (INEXIO_RESPONSE_BEGIN_BYTE&pinexio->data[0])
  82                inexio_process_data(pinexio);
  83        else
  84                printk(KERN_DEBUG "inexio.c: unknown/unsynchronized data from device, byte %x\n",pinexio->data[0]);
  85
  86        return IRQ_HANDLED;
  87}
  88
  89/*
  90 * inexio_disconnect() is the opposite of inexio_connect()
  91 */
  92
  93static void inexio_disconnect(struct serio *serio)
  94{
  95        struct inexio *pinexio = serio_get_drvdata(serio);
  96
  97        input_get_device(pinexio->dev);
  98        input_unregister_device(pinexio->dev);
  99        serio_close(serio);
 100        serio_set_drvdata(serio, NULL);
 101        input_put_device(pinexio->dev);
 102        kfree(pinexio);
 103}
 104
 105/*
 106 * inexio_connect() is the routine that is called when someone adds a
 107 * new serio device that supports iNexio protocol and registers it as
 108 * an input device. This is usually accomplished using inputattach.
 109 */
 110
 111static int inexio_connect(struct serio *serio, struct serio_driver *drv)
 112{
 113        struct inexio *pinexio;
 114        struct input_dev *input_dev;
 115        int err;
 116
 117        pinexio = kzalloc(sizeof(struct inexio), GFP_KERNEL);
 118        input_dev = input_allocate_device();
 119        if (!pinexio || !input_dev) {
 120                err = -ENOMEM;
 121                goto fail1;
 122        }
 123
 124        pinexio->serio = serio;
 125        pinexio->dev = input_dev;
 126        snprintf(pinexio->phys, sizeof(pinexio->phys), "%s/input0", serio->phys);
 127
 128        input_dev->name = "iNexio Serial TouchScreen";
 129        input_dev->phys = pinexio->phys;
 130        input_dev->id.bustype = BUS_RS232;
 131        input_dev->id.vendor = SERIO_INEXIO;
 132        input_dev->id.product = 0;
 133        input_dev->id.version = 0x0001;
 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(pinexio->dev, ABS_X, INEXIO_MIN_XC, INEXIO_MAX_XC, 0, 0);
 138        input_set_abs_params(pinexio->dev, ABS_Y, INEXIO_MIN_YC, INEXIO_MAX_YC, 0, 0);
 139
 140        serio_set_drvdata(serio, pinexio);
 141
 142        err = serio_open(serio, drv);
 143        if (err)
 144                goto fail2;
 145
 146        err = input_register_device(pinexio->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(pinexio);
 156        return err;
 157}
 158
 159/*
 160 * The serio driver structure.
 161 */
 162
 163static const struct serio_device_id inexio_serio_ids[] = {
 164        {
 165                .type   = SERIO_RS232,
 166                .proto  = SERIO_INEXIO,
 167                .id     = SERIO_ANY,
 168                .extra  = SERIO_ANY,
 169        },
 170        { 0 }
 171};
 172
 173MODULE_DEVICE_TABLE(serio, inexio_serio_ids);
 174
 175static struct serio_driver inexio_drv = {
 176        .driver         = {
 177                .name   = "inexio",
 178        },
 179        .description    = DRIVER_DESC,
 180        .id_table       = inexio_serio_ids,
 181        .interrupt      = inexio_interrupt,
 182        .connect        = inexio_connect,
 183        .disconnect     = inexio_disconnect,
 184};
 185
 186module_serio_driver(inexio_drv);
 187