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