18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Elo serial touchscreen driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2004 Vojtech Pavlik 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci/* 108c2ecf20Sopenharmony_ci * This driver can handle serial Elo touchscreens using either the Elo standard 118c2ecf20Sopenharmony_ci * 'E271-2210' 10-byte protocol, Elo legacy 'E281A-4002' 6-byte protocol, Elo 128c2ecf20Sopenharmony_ci * legacy 'E271-140' 4-byte protocol and Elo legacy 'E261-280' 3-byte protocol. 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/errno.h> 168c2ecf20Sopenharmony_ci#include <linux/kernel.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci#include <linux/input.h> 208c2ecf20Sopenharmony_ci#include <linux/serio.h> 218c2ecf20Sopenharmony_ci#include <linux/ctype.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define DRIVER_DESC "Elo serial touchscreen driver" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ciMODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); 268c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 278c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* 308c2ecf20Sopenharmony_ci * Definitions & global arrays. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define ELO_MAX_LENGTH 10 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define ELO10_PACKET_LEN 8 368c2ecf20Sopenharmony_ci#define ELO10_TOUCH 0x03 378c2ecf20Sopenharmony_ci#define ELO10_PRESSURE 0x80 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define ELO10_LEAD_BYTE 'U' 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define ELO10_ID_CMD 'i' 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define ELO10_TOUCH_PACKET 'T' 448c2ecf20Sopenharmony_ci#define ELO10_ACK_PACKET 'A' 458c2ecf20Sopenharmony_ci#define ELI10_ID_PACKET 'I' 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* 488c2ecf20Sopenharmony_ci * Per-touchscreen data. 498c2ecf20Sopenharmony_ci */ 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistruct elo { 528c2ecf20Sopenharmony_ci struct input_dev *dev; 538c2ecf20Sopenharmony_ci struct serio *serio; 548c2ecf20Sopenharmony_ci struct mutex cmd_mutex; 558c2ecf20Sopenharmony_ci struct completion cmd_done; 568c2ecf20Sopenharmony_ci int id; 578c2ecf20Sopenharmony_ci int idx; 588c2ecf20Sopenharmony_ci unsigned char expected_packet; 598c2ecf20Sopenharmony_ci unsigned char csum; 608c2ecf20Sopenharmony_ci unsigned char data[ELO_MAX_LENGTH]; 618c2ecf20Sopenharmony_ci unsigned char response[ELO10_PACKET_LEN]; 628c2ecf20Sopenharmony_ci char phys[32]; 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic void elo_process_data_10(struct elo *elo, unsigned char data) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci struct input_dev *dev = elo->dev; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci elo->data[elo->idx] = data; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci switch (elo->idx++) { 728c2ecf20Sopenharmony_ci case 0: 738c2ecf20Sopenharmony_ci elo->csum = 0xaa; 748c2ecf20Sopenharmony_ci if (data != ELO10_LEAD_BYTE) { 758c2ecf20Sopenharmony_ci dev_dbg(&elo->serio->dev, 768c2ecf20Sopenharmony_ci "unsynchronized data: 0x%02x\n", data); 778c2ecf20Sopenharmony_ci elo->idx = 0; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci break; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci case 9: 828c2ecf20Sopenharmony_ci elo->idx = 0; 838c2ecf20Sopenharmony_ci if (data != elo->csum) { 848c2ecf20Sopenharmony_ci dev_dbg(&elo->serio->dev, 858c2ecf20Sopenharmony_ci "bad checksum: 0x%02x, expected 0x%02x\n", 868c2ecf20Sopenharmony_ci data, elo->csum); 878c2ecf20Sopenharmony_ci break; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci if (elo->data[1] != elo->expected_packet) { 908c2ecf20Sopenharmony_ci if (elo->data[1] != ELO10_TOUCH_PACKET) 918c2ecf20Sopenharmony_ci dev_dbg(&elo->serio->dev, 928c2ecf20Sopenharmony_ci "unexpected packet: 0x%02x\n", 938c2ecf20Sopenharmony_ci elo->data[1]); 948c2ecf20Sopenharmony_ci break; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci if (likely(elo->data[1] == ELO10_TOUCH_PACKET)) { 978c2ecf20Sopenharmony_ci input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]); 988c2ecf20Sopenharmony_ci input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]); 998c2ecf20Sopenharmony_ci if (elo->data[2] & ELO10_PRESSURE) 1008c2ecf20Sopenharmony_ci input_report_abs(dev, ABS_PRESSURE, 1018c2ecf20Sopenharmony_ci (elo->data[8] << 8) | elo->data[7]); 1028c2ecf20Sopenharmony_ci input_report_key(dev, BTN_TOUCH, elo->data[2] & ELO10_TOUCH); 1038c2ecf20Sopenharmony_ci input_sync(dev); 1048c2ecf20Sopenharmony_ci } else if (elo->data[1] == ELO10_ACK_PACKET) { 1058c2ecf20Sopenharmony_ci if (elo->data[2] == '0') 1068c2ecf20Sopenharmony_ci elo->expected_packet = ELO10_TOUCH_PACKET; 1078c2ecf20Sopenharmony_ci complete(&elo->cmd_done); 1088c2ecf20Sopenharmony_ci } else { 1098c2ecf20Sopenharmony_ci memcpy(elo->response, &elo->data[1], ELO10_PACKET_LEN); 1108c2ecf20Sopenharmony_ci elo->expected_packet = ELO10_ACK_PACKET; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci break; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci elo->csum += data; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic void elo_process_data_6(struct elo *elo, unsigned char data) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci struct input_dev *dev = elo->dev; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci elo->data[elo->idx] = data; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci switch (elo->idx++) { 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci case 0: 1268c2ecf20Sopenharmony_ci if ((data & 0xc0) != 0xc0) 1278c2ecf20Sopenharmony_ci elo->idx = 0; 1288c2ecf20Sopenharmony_ci break; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci case 1: 1318c2ecf20Sopenharmony_ci if ((data & 0xc0) != 0x80) 1328c2ecf20Sopenharmony_ci elo->idx = 0; 1338c2ecf20Sopenharmony_ci break; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci case 2: 1368c2ecf20Sopenharmony_ci if ((data & 0xc0) != 0x40) 1378c2ecf20Sopenharmony_ci elo->idx = 0; 1388c2ecf20Sopenharmony_ci break; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci case 3: 1418c2ecf20Sopenharmony_ci if (data & 0xc0) { 1428c2ecf20Sopenharmony_ci elo->idx = 0; 1438c2ecf20Sopenharmony_ci break; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci input_report_abs(dev, ABS_X, ((elo->data[0] & 0x3f) << 6) | (elo->data[1] & 0x3f)); 1478c2ecf20Sopenharmony_ci input_report_abs(dev, ABS_Y, ((elo->data[2] & 0x3f) << 6) | (elo->data[3] & 0x3f)); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (elo->id == 2) { 1508c2ecf20Sopenharmony_ci input_report_key(dev, BTN_TOUCH, 1); 1518c2ecf20Sopenharmony_ci input_sync(dev); 1528c2ecf20Sopenharmony_ci elo->idx = 0; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci break; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci case 4: 1588c2ecf20Sopenharmony_ci if (data) { 1598c2ecf20Sopenharmony_ci input_sync(dev); 1608c2ecf20Sopenharmony_ci elo->idx = 0; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci break; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci case 5: 1658c2ecf20Sopenharmony_ci if ((data & 0xf0) == 0) { 1668c2ecf20Sopenharmony_ci input_report_abs(dev, ABS_PRESSURE, elo->data[5]); 1678c2ecf20Sopenharmony_ci input_report_key(dev, BTN_TOUCH, !!elo->data[5]); 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci input_sync(dev); 1708c2ecf20Sopenharmony_ci elo->idx = 0; 1718c2ecf20Sopenharmony_ci break; 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic void elo_process_data_3(struct elo *elo, unsigned char data) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci struct input_dev *dev = elo->dev; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci elo->data[elo->idx] = data; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci switch (elo->idx++) { 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci case 0: 1848c2ecf20Sopenharmony_ci if ((data & 0x7f) != 0x01) 1858c2ecf20Sopenharmony_ci elo->idx = 0; 1868c2ecf20Sopenharmony_ci break; 1878c2ecf20Sopenharmony_ci case 2: 1888c2ecf20Sopenharmony_ci input_report_key(dev, BTN_TOUCH, !(elo->data[1] & 0x80)); 1898c2ecf20Sopenharmony_ci input_report_abs(dev, ABS_X, elo->data[1]); 1908c2ecf20Sopenharmony_ci input_report_abs(dev, ABS_Y, elo->data[2]); 1918c2ecf20Sopenharmony_ci input_sync(dev); 1928c2ecf20Sopenharmony_ci elo->idx = 0; 1938c2ecf20Sopenharmony_ci break; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic irqreturn_t elo_interrupt(struct serio *serio, 1988c2ecf20Sopenharmony_ci unsigned char data, unsigned int flags) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci struct elo *elo = serio_get_drvdata(serio); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci switch (elo->id) { 2038c2ecf20Sopenharmony_ci case 0: 2048c2ecf20Sopenharmony_ci elo_process_data_10(elo, data); 2058c2ecf20Sopenharmony_ci break; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci case 1: 2088c2ecf20Sopenharmony_ci case 2: 2098c2ecf20Sopenharmony_ci elo_process_data_6(elo, data); 2108c2ecf20Sopenharmony_ci break; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci case 3: 2138c2ecf20Sopenharmony_ci elo_process_data_3(elo, data); 2148c2ecf20Sopenharmony_ci break; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic int elo_command_10(struct elo *elo, unsigned char *packet) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci int rc = -1; 2238c2ecf20Sopenharmony_ci int i; 2248c2ecf20Sopenharmony_ci unsigned char csum = 0xaa + ELO10_LEAD_BYTE; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci mutex_lock(&elo->cmd_mutex); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci serio_pause_rx(elo->serio); 2298c2ecf20Sopenharmony_ci elo->expected_packet = toupper(packet[0]); 2308c2ecf20Sopenharmony_ci init_completion(&elo->cmd_done); 2318c2ecf20Sopenharmony_ci serio_continue_rx(elo->serio); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci if (serio_write(elo->serio, ELO10_LEAD_BYTE)) 2348c2ecf20Sopenharmony_ci goto out; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci for (i = 0; i < ELO10_PACKET_LEN; i++) { 2378c2ecf20Sopenharmony_ci csum += packet[i]; 2388c2ecf20Sopenharmony_ci if (serio_write(elo->serio, packet[i])) 2398c2ecf20Sopenharmony_ci goto out; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (serio_write(elo->serio, csum)) 2438c2ecf20Sopenharmony_ci goto out; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci wait_for_completion_timeout(&elo->cmd_done, HZ); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (elo->expected_packet == ELO10_TOUCH_PACKET) { 2488c2ecf20Sopenharmony_ci /* We are back in reporting mode, the command was ACKed */ 2498c2ecf20Sopenharmony_ci memcpy(packet, elo->response, ELO10_PACKET_LEN); 2508c2ecf20Sopenharmony_ci rc = 0; 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci out: 2548c2ecf20Sopenharmony_ci mutex_unlock(&elo->cmd_mutex); 2558c2ecf20Sopenharmony_ci return rc; 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic int elo_setup_10(struct elo *elo) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci static const char *elo_types[] = { "Accu", "Dura", "Intelli", "Carroll" }; 2618c2ecf20Sopenharmony_ci struct input_dev *dev = elo->dev; 2628c2ecf20Sopenharmony_ci unsigned char packet[ELO10_PACKET_LEN] = { ELO10_ID_CMD }; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (elo_command_10(elo, packet)) 2658c2ecf20Sopenharmony_ci return -1; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci dev->id.version = (packet[5] << 8) | packet[4]; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci input_set_abs_params(dev, ABS_X, 96, 4000, 0, 0); 2708c2ecf20Sopenharmony_ci input_set_abs_params(dev, ABS_Y, 96, 4000, 0, 0); 2718c2ecf20Sopenharmony_ci if (packet[3] & ELO10_PRESSURE) 2728c2ecf20Sopenharmony_ci input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci dev_info(&elo->serio->dev, 2758c2ecf20Sopenharmony_ci "%sTouch touchscreen, fw: %02x.%02x, features: 0x%02x, controller: 0x%02x\n", 2768c2ecf20Sopenharmony_ci elo_types[(packet[1] -'0') & 0x03], 2778c2ecf20Sopenharmony_ci packet[5], packet[4], packet[3], packet[7]); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci return 0; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci/* 2838c2ecf20Sopenharmony_ci * elo_disconnect() is the opposite of elo_connect() 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic void elo_disconnect(struct serio *serio) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct elo *elo = serio_get_drvdata(serio); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci input_get_device(elo->dev); 2918c2ecf20Sopenharmony_ci input_unregister_device(elo->dev); 2928c2ecf20Sopenharmony_ci serio_close(serio); 2938c2ecf20Sopenharmony_ci serio_set_drvdata(serio, NULL); 2948c2ecf20Sopenharmony_ci input_put_device(elo->dev); 2958c2ecf20Sopenharmony_ci kfree(elo); 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci/* 2998c2ecf20Sopenharmony_ci * elo_connect() is the routine that is called when someone adds a 3008c2ecf20Sopenharmony_ci * new serio device that supports Gunze protocol and registers it as 3018c2ecf20Sopenharmony_ci * an input device. 3028c2ecf20Sopenharmony_ci */ 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic int elo_connect(struct serio *serio, struct serio_driver *drv) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci struct elo *elo; 3078c2ecf20Sopenharmony_ci struct input_dev *input_dev; 3088c2ecf20Sopenharmony_ci int err; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci elo = kzalloc(sizeof(struct elo), GFP_KERNEL); 3118c2ecf20Sopenharmony_ci input_dev = input_allocate_device(); 3128c2ecf20Sopenharmony_ci if (!elo || !input_dev) { 3138c2ecf20Sopenharmony_ci err = -ENOMEM; 3148c2ecf20Sopenharmony_ci goto fail1; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci elo->serio = serio; 3188c2ecf20Sopenharmony_ci elo->id = serio->id.id; 3198c2ecf20Sopenharmony_ci elo->dev = input_dev; 3208c2ecf20Sopenharmony_ci elo->expected_packet = ELO10_TOUCH_PACKET; 3218c2ecf20Sopenharmony_ci mutex_init(&elo->cmd_mutex); 3228c2ecf20Sopenharmony_ci init_completion(&elo->cmd_done); 3238c2ecf20Sopenharmony_ci snprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci input_dev->name = "Elo Serial TouchScreen"; 3268c2ecf20Sopenharmony_ci input_dev->phys = elo->phys; 3278c2ecf20Sopenharmony_ci input_dev->id.bustype = BUS_RS232; 3288c2ecf20Sopenharmony_ci input_dev->id.vendor = SERIO_ELO; 3298c2ecf20Sopenharmony_ci input_dev->id.product = elo->id; 3308c2ecf20Sopenharmony_ci input_dev->id.version = 0x0100; 3318c2ecf20Sopenharmony_ci input_dev->dev.parent = &serio->dev; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 3348c2ecf20Sopenharmony_ci input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci serio_set_drvdata(serio, elo); 3378c2ecf20Sopenharmony_ci err = serio_open(serio, drv); 3388c2ecf20Sopenharmony_ci if (err) 3398c2ecf20Sopenharmony_ci goto fail2; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci switch (elo->id) { 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci case 0: /* 10-byte protocol */ 3448c2ecf20Sopenharmony_ci if (elo_setup_10(elo)) { 3458c2ecf20Sopenharmony_ci err = -EIO; 3468c2ecf20Sopenharmony_ci goto fail3; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci break; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci case 1: /* 6-byte protocol */ 3528c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_PRESSURE, 0, 15, 0, 0); 3538c2ecf20Sopenharmony_ci fallthrough; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci case 2: /* 4-byte protocol */ 3568c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0); 3578c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_Y, 96, 4000, 0, 0); 3588c2ecf20Sopenharmony_ci break; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci case 3: /* 3-byte protocol */ 3618c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_X, 0, 255, 0, 0); 3628c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_Y, 0, 255, 0, 0); 3638c2ecf20Sopenharmony_ci break; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci err = input_register_device(elo->dev); 3678c2ecf20Sopenharmony_ci if (err) 3688c2ecf20Sopenharmony_ci goto fail3; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci return 0; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci fail3: serio_close(serio); 3738c2ecf20Sopenharmony_ci fail2: serio_set_drvdata(serio, NULL); 3748c2ecf20Sopenharmony_ci fail1: input_free_device(input_dev); 3758c2ecf20Sopenharmony_ci kfree(elo); 3768c2ecf20Sopenharmony_ci return err; 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci/* 3808c2ecf20Sopenharmony_ci * The serio driver structure. 3818c2ecf20Sopenharmony_ci */ 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic const struct serio_device_id elo_serio_ids[] = { 3848c2ecf20Sopenharmony_ci { 3858c2ecf20Sopenharmony_ci .type = SERIO_RS232, 3868c2ecf20Sopenharmony_ci .proto = SERIO_ELO, 3878c2ecf20Sopenharmony_ci .id = SERIO_ANY, 3888c2ecf20Sopenharmony_ci .extra = SERIO_ANY, 3898c2ecf20Sopenharmony_ci }, 3908c2ecf20Sopenharmony_ci { 0 } 3918c2ecf20Sopenharmony_ci}; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(serio, elo_serio_ids); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic struct serio_driver elo_drv = { 3968c2ecf20Sopenharmony_ci .driver = { 3978c2ecf20Sopenharmony_ci .name = "elo", 3988c2ecf20Sopenharmony_ci }, 3998c2ecf20Sopenharmony_ci .description = DRIVER_DESC, 4008c2ecf20Sopenharmony_ci .id_table = elo_serio_ids, 4018c2ecf20Sopenharmony_ci .interrupt = elo_interrupt, 4028c2ecf20Sopenharmony_ci .connect = elo_connect, 4038c2ecf20Sopenharmony_ci .disconnect = elo_disconnect, 4048c2ecf20Sopenharmony_ci}; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cimodule_serio_driver(elo_drv); 407