Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Dynapro serial touchscreen driver
0004  *
0005  * Copyright (c) 2009 Tias Guns
0006  * Based on the inexio driver (c) Vojtech Pavlik and Dan Streetman and
0007  * Richard Lemon
0008  */
0009 
0010 
0011 /*
0012  * 2009/09/19 Tias Guns <tias@ulyssis.org>
0013  *   Copied inexio.c and edited for Dynapro protocol (from retired Xorg module)
0014  */
0015 
0016 #include <linux/errno.h>
0017 #include <linux/kernel.h>
0018 #include <linux/module.h>
0019 #include <linux/slab.h>
0020 #include <linux/input.h>
0021 #include <linux/serio.h>
0022 
0023 #define DRIVER_DESC "Dynapro serial touchscreen driver"
0024 
0025 MODULE_AUTHOR("Tias Guns <tias@ulyssis.org>");
0026 MODULE_DESCRIPTION(DRIVER_DESC);
0027 MODULE_LICENSE("GPL");
0028 
0029 /*
0030  * Definitions & global arrays.
0031  */
0032 
0033 #define DYNAPRO_FORMAT_TOUCH_BIT 0x40
0034 #define DYNAPRO_FORMAT_LENGTH 3
0035 #define DYNAPRO_RESPONSE_BEGIN_BYTE 0x80
0036 
0037 #define DYNAPRO_MIN_XC 0
0038 #define DYNAPRO_MAX_XC 0x3ff
0039 #define DYNAPRO_MIN_YC 0
0040 #define DYNAPRO_MAX_YC 0x3ff
0041 
0042 #define DYNAPRO_GET_XC(data) (data[1] | ((data[0] & 0x38) << 4))
0043 #define DYNAPRO_GET_YC(data) (data[2] | ((data[0] & 0x07) << 7))
0044 #define DYNAPRO_GET_TOUCHED(data) (DYNAPRO_FORMAT_TOUCH_BIT & data[0])
0045 
0046 /*
0047  * Per-touchscreen data.
0048  */
0049 
0050 struct dynapro {
0051     struct input_dev *dev;
0052     struct serio *serio;
0053     int idx;
0054     unsigned char data[DYNAPRO_FORMAT_LENGTH];
0055     char phys[32];
0056 };
0057 
0058 static void dynapro_process_data(struct dynapro *pdynapro)
0059 {
0060     struct input_dev *dev = pdynapro->dev;
0061 
0062     if (DYNAPRO_FORMAT_LENGTH == ++pdynapro->idx) {
0063         input_report_abs(dev, ABS_X, DYNAPRO_GET_XC(pdynapro->data));
0064         input_report_abs(dev, ABS_Y, DYNAPRO_GET_YC(pdynapro->data));
0065         input_report_key(dev, BTN_TOUCH,
0066                  DYNAPRO_GET_TOUCHED(pdynapro->data));
0067         input_sync(dev);
0068 
0069         pdynapro->idx = 0;
0070     }
0071 }
0072 
0073 static irqreturn_t dynapro_interrupt(struct serio *serio,
0074         unsigned char data, unsigned int flags)
0075 {
0076     struct dynapro *pdynapro = serio_get_drvdata(serio);
0077 
0078     pdynapro->data[pdynapro->idx] = data;
0079 
0080     if (DYNAPRO_RESPONSE_BEGIN_BYTE & pdynapro->data[0])
0081         dynapro_process_data(pdynapro);
0082     else
0083         dev_dbg(&serio->dev, "unknown/unsynchronized data: %x\n",
0084             pdynapro->data[0]);
0085 
0086     return IRQ_HANDLED;
0087 }
0088 
0089 static void dynapro_disconnect(struct serio *serio)
0090 {
0091     struct dynapro *pdynapro = serio_get_drvdata(serio);
0092 
0093     input_get_device(pdynapro->dev);
0094     input_unregister_device(pdynapro->dev);
0095     serio_close(serio);
0096     serio_set_drvdata(serio, NULL);
0097     input_put_device(pdynapro->dev);
0098     kfree(pdynapro);
0099 }
0100 
0101 /*
0102  * dynapro_connect() is the routine that is called when someone adds a
0103  * new serio device that supports dynapro protocol and registers it as
0104  * an input device. This is usually accomplished using inputattach.
0105  */
0106 
0107 static int dynapro_connect(struct serio *serio, struct serio_driver *drv)
0108 {
0109     struct dynapro *pdynapro;
0110     struct input_dev *input_dev;
0111     int err;
0112 
0113     pdynapro = kzalloc(sizeof(struct dynapro), GFP_KERNEL);
0114     input_dev = input_allocate_device();
0115     if (!pdynapro || !input_dev) {
0116         err = -ENOMEM;
0117         goto fail1;
0118     }
0119 
0120     pdynapro->serio = serio;
0121     pdynapro->dev = input_dev;
0122     snprintf(pdynapro->phys, sizeof(pdynapro->phys),
0123          "%s/input0", serio->phys);
0124 
0125     input_dev->name = "Dynapro Serial TouchScreen";
0126     input_dev->phys = pdynapro->phys;
0127     input_dev->id.bustype = BUS_RS232;
0128     input_dev->id.vendor = SERIO_DYNAPRO;
0129     input_dev->id.product = 0;
0130     input_dev->id.version = 0x0001;
0131     input_dev->dev.parent = &serio->dev;
0132     input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
0133     input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
0134     input_set_abs_params(pdynapro->dev, ABS_X,
0135                  DYNAPRO_MIN_XC, DYNAPRO_MAX_XC, 0, 0);
0136     input_set_abs_params(pdynapro->dev, ABS_Y,
0137                  DYNAPRO_MIN_YC, DYNAPRO_MAX_YC, 0, 0);
0138 
0139     serio_set_drvdata(serio, pdynapro);
0140 
0141     err = serio_open(serio, drv);
0142     if (err)
0143         goto fail2;
0144 
0145     err = input_register_device(pdynapro->dev);
0146     if (err)
0147         goto fail3;
0148 
0149     return 0;
0150 
0151  fail3: serio_close(serio);
0152  fail2: serio_set_drvdata(serio, NULL);
0153  fail1: input_free_device(input_dev);
0154     kfree(pdynapro);
0155     return err;
0156 }
0157 
0158 /*
0159  * The serio driver structure.
0160  */
0161 
0162 static const struct serio_device_id dynapro_serio_ids[] = {
0163     {
0164         .type   = SERIO_RS232,
0165         .proto  = SERIO_DYNAPRO,
0166         .id = SERIO_ANY,
0167         .extra  = SERIO_ANY,
0168     },
0169     { 0 }
0170 };
0171 
0172 MODULE_DEVICE_TABLE(serio, dynapro_serio_ids);
0173 
0174 static struct serio_driver dynapro_drv = {
0175     .driver     = {
0176         .name   = "dynapro",
0177     },
0178     .description    = DRIVER_DESC,
0179     .id_table   = dynapro_serio_ids,
0180     .interrupt  = dynapro_interrupt,
0181     .connect    = dynapro_connect,
0182     .disconnect = dynapro_disconnect,
0183 };
0184 
0185 module_serio_driver(dynapro_drv);