11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 2000-2001 Vojtech Pavlik 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Gunze AHL-51S touchscreen driver for Linux 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version. 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details. 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Should you need to contact me, the author, you can do so either by 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/input.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serio.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "Gunze AHL-51S touchscreen driver" 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION(DRIVER_DESC); 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Definitions & global arrays. 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GUNZE_MAX_LENGTH 10 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Per-touchscreen data. 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct gunze { 53eca1ed196cd5b523c1057204cd3672555ad58dfeDmitry Torokhov struct input_dev *dev; 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct serio *serio; 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int idx; 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char data[GUNZE_MAX_LENGTH]; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char phys[32]; 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 607d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void gunze_process_packet(struct gunze* gunze) 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 62eca1ed196cd5b523c1057204cd3672555ad58dfeDmitry Torokhov struct input_dev *dev = gunze->dev; 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (gunze->idx != GUNZE_MAX_LENGTH || gunze->data[5] != ',' || 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (gunze->data[0] != 'T' && gunze->data[0] != 'R')) { 66a07461ec0cffb105c7e7b7404520ea2c74129db0Dmitry Torokhov printk(KERN_WARNING "gunze.c: bad packet: >%.*s<\n", GUNZE_MAX_LENGTH, gunze->data); 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_abs(dev, ABS_X, simple_strtoul(gunze->data + 1, NULL, 10)); 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_abs(dev, ABS_Y, 1024 - simple_strtoul(gunze->data + 6, NULL, 10)); 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_key(dev, BTN_TOUCH, gunze->data[0] == 'T'); 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_sync(dev); 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic irqreturn_t gunze_interrupt(struct serio *serio, 777d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells unsigned char data, unsigned int flags) 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct gunze* gunze = serio_get_drvdata(serio); 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data == '\r') { 827d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells gunze_process_packet(gunze); 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gunze->idx = 0; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (gunze->idx < GUNZE_MAX_LENGTH) 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gunze->data[gunze->idx++] = data; 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * gunze_disconnect() is the opposite of gunze_connect() 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void gunze_disconnect(struct serio *serio) 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 97eca1ed196cd5b523c1057204cd3672555ad58dfeDmitry Torokhov struct gunze *gunze = serio_get_drvdata(serio); 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 99eca1ed196cd5b523c1057204cd3672555ad58dfeDmitry Torokhov input_get_device(gunze->dev); 100eca1ed196cd5b523c1057204cd3672555ad58dfeDmitry Torokhov input_unregister_device(gunze->dev); 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio_close(serio); 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio_set_drvdata(serio, NULL); 103eca1ed196cd5b523c1057204cd3672555ad58dfeDmitry Torokhov input_put_device(gunze->dev); 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(gunze); 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * gunze_connect() is the routine that is called when someone adds a 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * new serio device that supports Gunze protocol and registers it as 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * an input device. 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int gunze_connect(struct serio *serio, struct serio_driver *drv) 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct gunze *gunze; 116eca1ed196cd5b523c1057204cd3672555ad58dfeDmitry Torokhov struct input_dev *input_dev; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 119eca1ed196cd5b523c1057204cd3672555ad58dfeDmitry Torokhov gunze = kzalloc(sizeof(struct gunze), GFP_KERNEL); 120eca1ed196cd5b523c1057204cd3672555ad58dfeDmitry Torokhov input_dev = input_allocate_device(); 121eca1ed196cd5b523c1057204cd3672555ad58dfeDmitry Torokhov if (!gunze || !input_dev) { 122eca1ed196cd5b523c1057204cd3672555ad58dfeDmitry Torokhov err = -ENOMEM; 12352c1f5704d7555a16641429b2e7af5d26d7b119aDmitry Torokhov goto fail1; 124eca1ed196cd5b523c1057204cd3672555ad58dfeDmitry Torokhov } 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gunze->serio = serio; 127eca1ed196cd5b523c1057204cd3672555ad58dfeDmitry Torokhov gunze->dev = input_dev; 128a21466cc77b25dc2afd1292c79c7fc8fd454a1a7Dmitry Torokhov snprintf(gunze->phys, sizeof(serio->phys), "%s/input0", serio->phys); 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 130eca1ed196cd5b523c1057204cd3672555ad58dfeDmitry Torokhov input_dev->name = "Gunze AHL-51S TouchScreen"; 131eca1ed196cd5b523c1057204cd3672555ad58dfeDmitry Torokhov input_dev->phys = gunze->phys; 132eca1ed196cd5b523c1057204cd3672555ad58dfeDmitry Torokhov input_dev->id.bustype = BUS_RS232; 133eca1ed196cd5b523c1057204cd3672555ad58dfeDmitry Torokhov input_dev->id.vendor = SERIO_GUNZE; 134eca1ed196cd5b523c1057204cd3672555ad58dfeDmitry Torokhov input_dev->id.product = 0x0051; 135eca1ed196cd5b523c1057204cd3672555ad58dfeDmitry Torokhov input_dev->id.version = 0x0100; 136a5394fb075a80212765ee3cd4a7842bdccf5fc0aDmitry Torokhov input_dev->dev.parent = &serio->dev; 1377b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 1387b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); 139eca1ed196cd5b523c1057204cd3672555ad58dfeDmitry Torokhov input_set_abs_params(input_dev, ABS_X, 24, 1000, 0, 0); 140eca1ed196cd5b523c1057204cd3672555ad58dfeDmitry Torokhov input_set_abs_params(input_dev, ABS_Y, 24, 1000, 0, 0); 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio_set_drvdata(serio, gunze); 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = serio_open(serio, drv); 145eca1ed196cd5b523c1057204cd3672555ad58dfeDmitry Torokhov if (err) 14652c1f5704d7555a16641429b2e7af5d26d7b119aDmitry Torokhov goto fail2; 14752c1f5704d7555a16641429b2e7af5d26d7b119aDmitry Torokhov 14852c1f5704d7555a16641429b2e7af5d26d7b119aDmitry Torokhov err = input_register_device(gunze->dev); 14952c1f5704d7555a16641429b2e7af5d26d7b119aDmitry Torokhov if (err) 15052c1f5704d7555a16641429b2e7af5d26d7b119aDmitry Torokhov goto fail3; 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 153eca1ed196cd5b523c1057204cd3672555ad58dfeDmitry Torokhov 15452c1f5704d7555a16641429b2e7af5d26d7b119aDmitry Torokhov fail3: serio_close(serio); 15552c1f5704d7555a16641429b2e7af5d26d7b119aDmitry Torokhov fail2: serio_set_drvdata(serio, NULL); 15652c1f5704d7555a16641429b2e7af5d26d7b119aDmitry Torokhov fail1: input_free_device(input_dev); 157eca1ed196cd5b523c1057204cd3672555ad58dfeDmitry Torokhov kfree(gunze); 158eca1ed196cd5b523c1057204cd3672555ad58dfeDmitry Torokhov return err; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The serio driver structure. 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct serio_device_id gunze_serio_ids[] = { 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .type = SERIO_RS232, 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .proto = SERIO_GUNZE, 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id = SERIO_ANY, 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .extra = SERIO_ANY, 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 0 } 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(serio, gunze_serio_ids); 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct serio_driver gunze_drv = { 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver = { 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "gunze", 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .description = DRIVER_DESC, 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = gunze_serio_ids, 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .interrupt = gunze_interrupt, 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .connect = gunze_connect, 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disconnect = gunze_disconnect, 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18865ac9f7a23c934ee8c40dc20955e75db4924bfeaAxel Linmodule_serio_driver(gunze_drv); 189