linux/drivers/input/touchscreen/penmount.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Penmount serial touchscreen driver
   4 *
   5 * Copyright (c) 2006 Rick Koch <n1gp@hotmail.com>
   6 * Copyright (c) 2011 John Sung <penmount.touch@gmail.com>
   7 *
   8 * Based on ELO driver (drivers/input/touchscreen/elo.c)
   9 * Copyright (c) 2004 Vojtech Pavlik
  10 */
  11
  12
  13#include <linux/errno.h>
  14#include <linux/kernel.h>
  15#include <linux/module.h>
  16#include <linux/slab.h>
  17#include <linux/input.h>
  18#include <linux/input/mt.h>
  19#include <linux/serio.h>
  20
  21#define DRIVER_DESC     "PenMount serial touchscreen driver"
  22
  23MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>");
  24MODULE_AUTHOR("John Sung <penmount.touch@gmail.com>");
  25MODULE_DESCRIPTION(DRIVER_DESC);
  26MODULE_LICENSE("GPL");
  27
  28/*
  29 * Definitions & global arrays.
  30 */
  31
  32#define PM_MAX_LENGTH   6
  33#define PM_MAX_MTSLOT   16
  34#define PM_3000_MTSLOT  2
  35#define PM_6250_MTSLOT  12
  36
  37/*
  38 * Multi-touch slot
  39 */
  40
  41struct mt_slot {
  42        unsigned short x, y;
  43        bool active; /* is the touch valid? */
  44};
  45
  46/*
  47 * Per-touchscreen data.
  48 */
  49
  50struct pm {
  51        struct input_dev *dev;
  52        struct serio *serio;
  53        int idx;
  54        unsigned char data[PM_MAX_LENGTH];
  55        char phys[32];
  56        unsigned char packetsize;
  57        unsigned char maxcontacts;
  58        struct mt_slot slots[PM_MAX_MTSLOT];
  59        void (*parse_packet)(struct pm *);
  60};
  61
  62/*
  63 * pm_mtevent() sends mt events and also emulates pointer movement
  64 */
  65
  66static void pm_mtevent(struct pm *pm, struct input_dev *input)
  67{
  68        int i;
  69
  70        for (i = 0; i < pm->maxcontacts; ++i) {
  71                input_mt_slot(input, i);
  72                input_mt_report_slot_state(input, MT_TOOL_FINGER,
  73                                pm->slots[i].active);
  74                if (pm->slots[i].active) {
  75                        input_event(input, EV_ABS, ABS_MT_POSITION_X, pm->slots[i].x);
  76                        input_event(input, EV_ABS, ABS_MT_POSITION_Y, pm->slots[i].y);
  77                }
  78        }
  79
  80        input_mt_report_pointer_emulation(input, true);
  81        input_sync(input);
  82}
  83
  84/*
  85 * pm_checkpacket() checks if data packet is valid
  86 */
  87
  88static bool pm_checkpacket(unsigned char *packet)
  89{
  90        int total = 0;
  91        int i;
  92
  93        for (i = 0; i < 5; i++)
  94                total += packet[i];
  95
  96        return packet[5] == (unsigned char)~(total & 0xff);
  97}
  98
  99static void pm_parse_9000(struct pm *pm)
 100{
 101        struct input_dev *dev = pm->dev;
 102
 103        if ((pm->data[0] & 0x80) && pm->packetsize == ++pm->idx) {
 104                input_report_abs(dev, ABS_X, pm->data[1] * 128 + pm->data[2]);
 105                input_report_abs(dev, ABS_Y, pm->data[3] * 128 + pm->data[4]);
 106                input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40));
 107                input_sync(dev);
 108                pm->idx = 0;
 109        }
 110}
 111
 112static void pm_parse_6000(struct pm *pm)
 113{
 114        struct input_dev *dev = pm->dev;
 115
 116        if ((pm->data[0] & 0xbf) == 0x30 && pm->packetsize == ++pm->idx) {
 117                if (pm_checkpacket(pm->data)) {
 118                        input_report_abs(dev, ABS_X,
 119                                        pm->data[2] * 256 + pm->data[1]);
 120                        input_report_abs(dev, ABS_Y,
 121                                        pm->data[4] * 256 + pm->data[3]);
 122                        input_report_key(dev, BTN_TOUCH, pm->data[0] & 0x40);
 123                        input_sync(dev);
 124                }
 125                pm->idx = 0;
 126        }
 127}
 128
 129static void pm_parse_3000(struct pm *pm)
 130{
 131        struct input_dev *dev = pm->dev;
 132
 133        if ((pm->data[0] & 0xce) == 0x40 && pm->packetsize == ++pm->idx) {
 134                if (pm_checkpacket(pm->data)) {
 135                        int slotnum = pm->data[0] & 0x0f;
 136                        pm->slots[slotnum].active = pm->data[0] & 0x30;
 137                        pm->slots[slotnum].x = pm->data[2] * 256 + pm->data[1];
 138                        pm->slots[slotnum].y = pm->data[4] * 256 + pm->data[3];
 139                        pm_mtevent(pm, dev);
 140                }
 141                pm->idx = 0;
 142        }
 143}
 144
 145static void pm_parse_6250(struct pm *pm)
 146{
 147        struct input_dev *dev = pm->dev;
 148
 149        if ((pm->data[0] & 0xb0) == 0x30 && pm->packetsize == ++pm->idx) {
 150                if (pm_checkpacket(pm->data)) {
 151                        int slotnum = pm->data[0] & 0x0f;
 152                        pm->slots[slotnum].active = pm->data[0] & 0x40;
 153                        pm->slots[slotnum].x = pm->data[2] * 256 + pm->data[1];
 154                        pm->slots[slotnum].y = pm->data[4] * 256 + pm->data[3];
 155                        pm_mtevent(pm, dev);
 156                }
 157                pm->idx = 0;
 158        }
 159}
 160
 161static irqreturn_t pm_interrupt(struct serio *serio,
 162                unsigned char data, unsigned int flags)
 163{
 164        struct pm *pm = serio_get_drvdata(serio);
 165
 166        pm->data[pm->idx] = data;
 167
 168        pm->parse_packet(pm);
 169
 170        return IRQ_HANDLED;
 171}
 172
 173/*
 174 * pm_disconnect() is the opposite of pm_connect()
 175 */
 176
 177static void pm_disconnect(struct serio *serio)
 178{
 179        struct pm *pm = serio_get_drvdata(serio);
 180
 181        serio_close(serio);
 182
 183        input_unregister_device(pm->dev);
 184        kfree(pm);
 185
 186        serio_set_drvdata(serio, NULL);
 187}
 188
 189/*
 190 * pm_connect() is the routine that is called when someone adds a
 191 * new serio device that supports PenMount protocol and registers it as
 192 * an input device.
 193 */
 194
 195static int pm_connect(struct serio *serio, struct serio_driver *drv)
 196{
 197        struct pm *pm;
 198        struct input_dev *input_dev;
 199        int max_x, max_y;
 200        int err;
 201
 202        pm = kzalloc(sizeof(struct pm), GFP_KERNEL);
 203        input_dev = input_allocate_device();
 204        if (!pm || !input_dev) {
 205                err = -ENOMEM;
 206                goto fail1;
 207        }
 208
 209        pm->serio = serio;
 210        pm->dev = input_dev;
 211        snprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys);
 212        pm->maxcontacts = 1;
 213
 214        input_dev->name = "PenMount Serial TouchScreen";
 215        input_dev->phys = pm->phys;
 216        input_dev->id.bustype = BUS_RS232;
 217        input_dev->id.vendor = SERIO_PENMOUNT;
 218        input_dev->id.product = 0;
 219        input_dev->id.version = 0x0100;
 220        input_dev->dev.parent = &serio->dev;
 221
 222        input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 223        input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
 224
 225        switch (serio->id.id) {
 226        default:
 227        case 0:
 228                pm->packetsize = 5;
 229                pm->parse_packet = pm_parse_9000;
 230                input_dev->id.product = 0x9000;
 231                max_x = max_y = 0x3ff;
 232                break;
 233
 234        case 1:
 235                pm->packetsize = 6;
 236                pm->parse_packet = pm_parse_6000;
 237                input_dev->id.product = 0x6000;
 238                max_x = max_y = 0x3ff;
 239                break;
 240
 241        case 2:
 242                pm->packetsize = 6;
 243                pm->parse_packet = pm_parse_3000;
 244                input_dev->id.product = 0x3000;
 245                max_x = max_y = 0x7ff;
 246                pm->maxcontacts = PM_3000_MTSLOT;
 247                break;
 248
 249        case 3:
 250                pm->packetsize = 6;
 251                pm->parse_packet = pm_parse_6250;
 252                input_dev->id.product = 0x6250;
 253                max_x = max_y = 0x3ff;
 254                pm->maxcontacts = PM_6250_MTSLOT;
 255                break;
 256        }
 257
 258        input_set_abs_params(pm->dev, ABS_X, 0, max_x, 0, 0);
 259        input_set_abs_params(pm->dev, ABS_Y, 0, max_y, 0, 0);
 260
 261        if (pm->maxcontacts > 1) {
 262                input_mt_init_slots(pm->dev, pm->maxcontacts, 0);
 263                input_set_abs_params(pm->dev,
 264                                     ABS_MT_POSITION_X, 0, max_x, 0, 0);
 265                input_set_abs_params(pm->dev,
 266                                     ABS_MT_POSITION_Y, 0, max_y, 0, 0);
 267        }
 268
 269        serio_set_drvdata(serio, pm);
 270
 271        err = serio_open(serio, drv);
 272        if (err)
 273                goto fail2;
 274
 275        err = input_register_device(pm->dev);
 276        if (err)
 277                goto fail3;
 278
 279        return 0;
 280
 281 fail3: serio_close(serio);
 282 fail2: serio_set_drvdata(serio, NULL);
 283 fail1: input_free_device(input_dev);
 284        kfree(pm);
 285        return err;
 286}
 287
 288/*
 289 * The serio driver structure.
 290 */
 291
 292static const struct serio_device_id pm_serio_ids[] = {
 293        {
 294                .type   = SERIO_RS232,
 295                .proto  = SERIO_PENMOUNT,
 296                .id     = SERIO_ANY,
 297                .extra  = SERIO_ANY,
 298        },
 299        { 0 }
 300};
 301
 302MODULE_DEVICE_TABLE(serio, pm_serio_ids);
 303
 304static struct serio_driver pm_drv = {
 305        .driver         = {
 306                .name   = "serio-penmount",
 307        },
 308        .description    = DRIVER_DESC,
 309        .id_table       = pm_serio_ids,
 310        .interrupt      = pm_interrupt,
 311        .connect        = pm_connect,
 312        .disconnect     = pm_disconnect,
 313};
 314
 315module_serio_driver(pm_drv);
 316