Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * EETI Egalax serial touchscreen driver
0004  *
0005  * Copyright (c) 2015 Zoltán Böszörményi <zboszor@pr.hu>
0006  *
0007  * based on the
0008  *
0009  * Hampshire serial touchscreen driver (Copyright (c) 2010 Adam Bennett)
0010  */
0011 
0012 
0013 #include <linux/errno.h>
0014 #include <linux/kernel.h>
0015 #include <linux/module.h>
0016 #include <linux/slab.h>
0017 #include <linux/input.h>
0018 #include <linux/serio.h>
0019 
0020 #define DRIVER_DESC "EETI Egalax serial touchscreen driver"
0021 
0022 /*
0023  * Definitions & global arrays.
0024  */
0025 
0026 #define EGALAX_FORMAT_MAX_LENGTH    6
0027 #define EGALAX_FORMAT_START_BIT     BIT(7)
0028 #define EGALAX_FORMAT_PRESSURE_BIT  BIT(6)
0029 #define EGALAX_FORMAT_TOUCH_BIT     BIT(0)
0030 #define EGALAX_FORMAT_RESOLUTION_MASK   0x06
0031 
0032 #define EGALAX_MIN_XC           0
0033 #define EGALAX_MAX_XC           0x4000
0034 #define EGALAX_MIN_YC           0
0035 #define EGALAX_MAX_YC           0x4000
0036 
0037 /*
0038  * Per-touchscreen data.
0039  */
0040 struct egalax {
0041     struct input_dev *input;
0042     struct serio *serio;
0043     int idx;
0044     u8 data[EGALAX_FORMAT_MAX_LENGTH];
0045     char phys[32];
0046 };
0047 
0048 static void egalax_process_data(struct egalax *egalax)
0049 {
0050     struct input_dev *dev = egalax->input;
0051     u8 *data = egalax->data;
0052     u16 x, y;
0053     u8 shift;
0054     u8 mask;
0055 
0056     shift = 3 - ((data[0] & EGALAX_FORMAT_RESOLUTION_MASK) >> 1);
0057     mask = 0xff >> (shift + 1);
0058 
0059     x = (((u16)(data[1] & mask) << 7) | (data[2] & 0x7f)) << shift;
0060     y = (((u16)(data[3] & mask) << 7) | (data[4] & 0x7f)) << shift;
0061 
0062     input_report_key(dev, BTN_TOUCH, data[0] & EGALAX_FORMAT_TOUCH_BIT);
0063     input_report_abs(dev, ABS_X, x);
0064     input_report_abs(dev, ABS_Y, y);
0065     input_sync(dev);
0066 }
0067 
0068 static irqreturn_t egalax_interrupt(struct serio *serio,
0069                     unsigned char data, unsigned int flags)
0070 {
0071     struct egalax *egalax = serio_get_drvdata(serio);
0072     int pkt_len;
0073 
0074     egalax->data[egalax->idx++] = data;
0075 
0076     if (likely(egalax->data[0] & EGALAX_FORMAT_START_BIT)) {
0077         pkt_len = egalax->data[0] & EGALAX_FORMAT_PRESSURE_BIT ? 6 : 5;
0078         if (pkt_len == egalax->idx) {
0079             egalax_process_data(egalax);
0080             egalax->idx = 0;
0081         }
0082     } else {
0083         dev_dbg(&serio->dev, "unknown/unsynchronized data: %x\n",
0084             egalax->data[0]);
0085         egalax->idx = 0;
0086     }
0087 
0088     return IRQ_HANDLED;
0089 }
0090 
0091 /*
0092  * egalax_connect() is the routine that is called when someone adds a
0093  * new serio device that supports egalax protocol and registers it as
0094  * an input device. This is usually accomplished using inputattach.
0095  */
0096 static int egalax_connect(struct serio *serio, struct serio_driver *drv)
0097 {
0098     struct egalax *egalax;
0099     struct input_dev *input_dev;
0100     int error;
0101 
0102     egalax = kzalloc(sizeof(struct egalax), GFP_KERNEL);
0103     input_dev = input_allocate_device();
0104     if (!egalax || !input_dev) {
0105         error = -ENOMEM;
0106         goto err_free_mem;
0107     }
0108 
0109     egalax->serio = serio;
0110     egalax->input = input_dev;
0111     snprintf(egalax->phys, sizeof(egalax->phys),
0112          "%s/input0", serio->phys);
0113 
0114     input_dev->name = "EETI eGalaxTouch Serial TouchScreen";
0115     input_dev->phys = egalax->phys;
0116     input_dev->id.bustype = BUS_RS232;
0117     input_dev->id.vendor = SERIO_EGALAX;
0118     input_dev->id.product = 0;
0119     input_dev->id.version = 0x0001;
0120     input_dev->dev.parent = &serio->dev;
0121 
0122     input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
0123     input_set_abs_params(input_dev, ABS_X,
0124                  EGALAX_MIN_XC, EGALAX_MAX_XC, 0, 0);
0125     input_set_abs_params(input_dev, ABS_Y,
0126                  EGALAX_MIN_YC, EGALAX_MAX_YC, 0, 0);
0127 
0128     serio_set_drvdata(serio, egalax);
0129 
0130     error = serio_open(serio, drv);
0131     if (error)
0132         goto err_reset_drvdata;
0133 
0134     error = input_register_device(input_dev);
0135     if (error)
0136         goto err_close_serio;
0137 
0138     return 0;
0139 
0140 err_close_serio:
0141     serio_close(serio);
0142 err_reset_drvdata:
0143     serio_set_drvdata(serio, NULL);
0144 err_free_mem:
0145     input_free_device(input_dev);
0146     kfree(egalax);
0147     return error;
0148 }
0149 
0150 static void egalax_disconnect(struct serio *serio)
0151 {
0152     struct egalax *egalax = serio_get_drvdata(serio);
0153 
0154     serio_close(serio);
0155     serio_set_drvdata(serio, NULL);
0156     input_unregister_device(egalax->input);
0157     kfree(egalax);
0158 }
0159 
0160 /*
0161  * The serio driver structure.
0162  */
0163 
0164 static const struct serio_device_id egalax_serio_ids[] = {
0165     {
0166         .type   = SERIO_RS232,
0167         .proto  = SERIO_EGALAX,
0168         .id = SERIO_ANY,
0169         .extra  = SERIO_ANY,
0170     },
0171     { 0 }
0172 };
0173 
0174 MODULE_DEVICE_TABLE(serio, egalax_serio_ids);
0175 
0176 static struct serio_driver egalax_drv = {
0177     .driver     = {
0178         .name   = "egalax",
0179     },
0180     .description    = DRIVER_DESC,
0181     .id_table   = egalax_serio_ids,
0182     .interrupt  = egalax_interrupt,
0183     .connect    = egalax_connect,
0184     .disconnect = egalax_disconnect,
0185 };
0186 module_serio_driver(egalax_drv);
0187 
0188 MODULE_AUTHOR("Zoltán Böszörményi <zboszor@pr.hu>");
0189 MODULE_DESCRIPTION(DRIVER_DESC);
0190 MODULE_LICENSE("GPL v2");