1*d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2a5f523bcSTias Guns /* 3a5f523bcSTias Guns * Dynapro serial touchscreen driver 4a5f523bcSTias Guns * 5a5f523bcSTias Guns * Copyright (c) 2009 Tias Guns 6a5f523bcSTias Guns * Based on the inexio driver (c) Vojtech Pavlik and Dan Streetman and 7a5f523bcSTias Guns * Richard Lemon 8a5f523bcSTias Guns */ 9a5f523bcSTias Guns 10a5f523bcSTias Guns 11a5f523bcSTias Guns /* 12a5f523bcSTias Guns * 2009/09/19 Tias Guns <tias@ulyssis.org> 13a5f523bcSTias Guns * Copied inexio.c and edited for Dynapro protocol (from retired Xorg module) 14a5f523bcSTias Guns */ 15a5f523bcSTias Guns 16a5f523bcSTias Guns #include <linux/errno.h> 17a5f523bcSTias Guns #include <linux/kernel.h> 18a5f523bcSTias Guns #include <linux/module.h> 19a5f523bcSTias Guns #include <linux/slab.h> 20a5f523bcSTias Guns #include <linux/input.h> 21a5f523bcSTias Guns #include <linux/serio.h> 22a5f523bcSTias Guns 23a5f523bcSTias Guns #define DRIVER_DESC "Dynapro serial touchscreen driver" 24a5f523bcSTias Guns 25a5f523bcSTias Guns MODULE_AUTHOR("Tias Guns <tias@ulyssis.org>"); 26a5f523bcSTias Guns MODULE_DESCRIPTION(DRIVER_DESC); 27a5f523bcSTias Guns MODULE_LICENSE("GPL"); 28a5f523bcSTias Guns 29a5f523bcSTias Guns /* 30a5f523bcSTias Guns * Definitions & global arrays. 31a5f523bcSTias Guns */ 32a5f523bcSTias Guns 33a5f523bcSTias Guns #define DYNAPRO_FORMAT_TOUCH_BIT 0x40 34a5f523bcSTias Guns #define DYNAPRO_FORMAT_LENGTH 3 35a5f523bcSTias Guns #define DYNAPRO_RESPONSE_BEGIN_BYTE 0x80 36a5f523bcSTias Guns 37a5f523bcSTias Guns #define DYNAPRO_MIN_XC 0 38a5f523bcSTias Guns #define DYNAPRO_MAX_XC 0x3ff 39a5f523bcSTias Guns #define DYNAPRO_MIN_YC 0 40a5f523bcSTias Guns #define DYNAPRO_MAX_YC 0x3ff 41a5f523bcSTias Guns 42a5f523bcSTias Guns #define DYNAPRO_GET_XC(data) (data[1] | ((data[0] & 0x38) << 4)) 43a5f523bcSTias Guns #define DYNAPRO_GET_YC(data) (data[2] | ((data[0] & 0x07) << 7)) 44a5f523bcSTias Guns #define DYNAPRO_GET_TOUCHED(data) (DYNAPRO_FORMAT_TOUCH_BIT & data[0]) 45a5f523bcSTias Guns 46a5f523bcSTias Guns /* 47a5f523bcSTias Guns * Per-touchscreen data. 48a5f523bcSTias Guns */ 49a5f523bcSTias Guns 50a5f523bcSTias Guns struct dynapro { 51a5f523bcSTias Guns struct input_dev *dev; 52a5f523bcSTias Guns struct serio *serio; 53a5f523bcSTias Guns int idx; 54a5f523bcSTias Guns unsigned char data[DYNAPRO_FORMAT_LENGTH]; 55a5f523bcSTias Guns char phys[32]; 56a5f523bcSTias Guns }; 57a5f523bcSTias Guns 58a5f523bcSTias Guns static void dynapro_process_data(struct dynapro *pdynapro) 59a5f523bcSTias Guns { 60a5f523bcSTias Guns struct input_dev *dev = pdynapro->dev; 61a5f523bcSTias Guns 62a5f523bcSTias Guns if (DYNAPRO_FORMAT_LENGTH == ++pdynapro->idx) { 63a5f523bcSTias Guns input_report_abs(dev, ABS_X, DYNAPRO_GET_XC(pdynapro->data)); 64a5f523bcSTias Guns input_report_abs(dev, ABS_Y, DYNAPRO_GET_YC(pdynapro->data)); 65a5f523bcSTias Guns input_report_key(dev, BTN_TOUCH, 66a5f523bcSTias Guns DYNAPRO_GET_TOUCHED(pdynapro->data)); 67a5f523bcSTias Guns input_sync(dev); 68a5f523bcSTias Guns 69a5f523bcSTias Guns pdynapro->idx = 0; 70a5f523bcSTias Guns } 71a5f523bcSTias Guns } 72a5f523bcSTias Guns 73a5f523bcSTias Guns static irqreturn_t dynapro_interrupt(struct serio *serio, 74a5f523bcSTias Guns unsigned char data, unsigned int flags) 75a5f523bcSTias Guns { 76a5f523bcSTias Guns struct dynapro *pdynapro = serio_get_drvdata(serio); 77a5f523bcSTias Guns 78a5f523bcSTias Guns pdynapro->data[pdynapro->idx] = data; 79a5f523bcSTias Guns 80a5f523bcSTias Guns if (DYNAPRO_RESPONSE_BEGIN_BYTE & pdynapro->data[0]) 81a5f523bcSTias Guns dynapro_process_data(pdynapro); 82a5f523bcSTias Guns else 83a5f523bcSTias Guns dev_dbg(&serio->dev, "unknown/unsynchronized data: %x\n", 84a5f523bcSTias Guns pdynapro->data[0]); 85a5f523bcSTias Guns 86a5f523bcSTias Guns return IRQ_HANDLED; 87a5f523bcSTias Guns } 88a5f523bcSTias Guns 89a5f523bcSTias Guns static void dynapro_disconnect(struct serio *serio) 90a5f523bcSTias Guns { 91a5f523bcSTias Guns struct dynapro *pdynapro = serio_get_drvdata(serio); 92a5f523bcSTias Guns 93a5f523bcSTias Guns input_get_device(pdynapro->dev); 94a5f523bcSTias Guns input_unregister_device(pdynapro->dev); 95a5f523bcSTias Guns serio_close(serio); 96a5f523bcSTias Guns serio_set_drvdata(serio, NULL); 97a5f523bcSTias Guns input_put_device(pdynapro->dev); 98a5f523bcSTias Guns kfree(pdynapro); 99a5f523bcSTias Guns } 100a5f523bcSTias Guns 101a5f523bcSTias Guns /* 102a5f523bcSTias Guns * dynapro_connect() is the routine that is called when someone adds a 103a5f523bcSTias Guns * new serio device that supports dynapro protocol and registers it as 104a5f523bcSTias Guns * an input device. This is usually accomplished using inputattach. 105a5f523bcSTias Guns */ 106a5f523bcSTias Guns 107a5f523bcSTias Guns static int dynapro_connect(struct serio *serio, struct serio_driver *drv) 108a5f523bcSTias Guns { 109a5f523bcSTias Guns struct dynapro *pdynapro; 110a5f523bcSTias Guns struct input_dev *input_dev; 111a5f523bcSTias Guns int err; 112a5f523bcSTias Guns 113a5f523bcSTias Guns pdynapro = kzalloc(sizeof(struct dynapro), GFP_KERNEL); 114a5f523bcSTias Guns input_dev = input_allocate_device(); 115a5f523bcSTias Guns if (!pdynapro || !input_dev) { 116a5f523bcSTias Guns err = -ENOMEM; 117a5f523bcSTias Guns goto fail1; 118a5f523bcSTias Guns } 119a5f523bcSTias Guns 120a5f523bcSTias Guns pdynapro->serio = serio; 121a5f523bcSTias Guns pdynapro->dev = input_dev; 122a5f523bcSTias Guns snprintf(pdynapro->phys, sizeof(pdynapro->phys), 123a5f523bcSTias Guns "%s/input0", serio->phys); 124a5f523bcSTias Guns 125a5f523bcSTias Guns input_dev->name = "Dynapro Serial TouchScreen"; 126a5f523bcSTias Guns input_dev->phys = pdynapro->phys; 127a5f523bcSTias Guns input_dev->id.bustype = BUS_RS232; 128a5f523bcSTias Guns input_dev->id.vendor = SERIO_DYNAPRO; 129a5f523bcSTias Guns input_dev->id.product = 0; 130a5f523bcSTias Guns input_dev->id.version = 0x0001; 131a5f523bcSTias Guns input_dev->dev.parent = &serio->dev; 132a5f523bcSTias Guns input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 133a5f523bcSTias Guns input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); 134a5f523bcSTias Guns input_set_abs_params(pdynapro->dev, ABS_X, 135a5f523bcSTias Guns DYNAPRO_MIN_XC, DYNAPRO_MAX_XC, 0, 0); 136a5f523bcSTias Guns input_set_abs_params(pdynapro->dev, ABS_Y, 137a5f523bcSTias Guns DYNAPRO_MIN_YC, DYNAPRO_MAX_YC, 0, 0); 138a5f523bcSTias Guns 139a5f523bcSTias Guns serio_set_drvdata(serio, pdynapro); 140a5f523bcSTias Guns 141a5f523bcSTias Guns err = serio_open(serio, drv); 142a5f523bcSTias Guns if (err) 143a5f523bcSTias Guns goto fail2; 144a5f523bcSTias Guns 145a5f523bcSTias Guns err = input_register_device(pdynapro->dev); 146a5f523bcSTias Guns if (err) 147a5f523bcSTias Guns goto fail3; 148a5f523bcSTias Guns 149a5f523bcSTias Guns return 0; 150a5f523bcSTias Guns 151a5f523bcSTias Guns fail3: serio_close(serio); 152a5f523bcSTias Guns fail2: serio_set_drvdata(serio, NULL); 153a5f523bcSTias Guns fail1: input_free_device(input_dev); 154a5f523bcSTias Guns kfree(pdynapro); 155a5f523bcSTias Guns return err; 156a5f523bcSTias Guns } 157a5f523bcSTias Guns 158a5f523bcSTias Guns /* 159a5f523bcSTias Guns * The serio driver structure. 160a5f523bcSTias Guns */ 161a5f523bcSTias Guns 162fe11d25eSArvind Yadav static const struct serio_device_id dynapro_serio_ids[] = { 163a5f523bcSTias Guns { 164a5f523bcSTias Guns .type = SERIO_RS232, 165a5f523bcSTias Guns .proto = SERIO_DYNAPRO, 166a5f523bcSTias Guns .id = SERIO_ANY, 167a5f523bcSTias Guns .extra = SERIO_ANY, 168a5f523bcSTias Guns }, 169a5f523bcSTias Guns { 0 } 170a5f523bcSTias Guns }; 171a5f523bcSTias Guns 172a5f523bcSTias Guns MODULE_DEVICE_TABLE(serio, dynapro_serio_ids); 173a5f523bcSTias Guns 174a5f523bcSTias Guns static struct serio_driver dynapro_drv = { 175a5f523bcSTias Guns .driver = { 176a5f523bcSTias Guns .name = "dynapro", 177a5f523bcSTias Guns }, 178a5f523bcSTias Guns .description = DRIVER_DESC, 179a5f523bcSTias Guns .id_table = dynapro_serio_ids, 180a5f523bcSTias Guns .interrupt = dynapro_interrupt, 181a5f523bcSTias Guns .connect = dynapro_connect, 182a5f523bcSTias Guns .disconnect = dynapro_disconnect, 183a5f523bcSTias Guns }; 184a5f523bcSTias Guns 18565ac9f7aSAxel Lin module_serio_driver(dynapro_drv); 186