185f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov/* 285f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov * Fujitsu serial touchscreen driver 385f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov * 485f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov * Copyright (c) Dmitry Torokhov <dtor@mail.ru> 585f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov */ 685f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 785f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov/* 885f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov * This program is free software; you can redistribute it and/or modify it 985f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov * under the terms of the GNU General Public License version 2 as published 1085f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov * by the Free Software Foundation. 1185f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov */ 1285f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 1385f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov#include <linux/errno.h> 1485f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov#include <linux/kernel.h> 1585f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov#include <linux/module.h> 1685f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov#include <linux/slab.h> 1785f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov#include <linux/input.h> 1885f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov#include <linux/serio.h> 1985f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov#include <linux/init.h> 2085f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 2185f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov#define DRIVER_DESC "Fujitsu serial touchscreen driver" 2285f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 2385f202d5df877f8adcda342b74ab11fbdfea753dDmitry TorokhovMODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>"); 2485f202d5df877f8adcda342b74ab11fbdfea753dDmitry TorokhovMODULE_DESCRIPTION(DRIVER_DESC); 2585f202d5df877f8adcda342b74ab11fbdfea753dDmitry TorokhovMODULE_LICENSE("GPL"); 2685f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 2785f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov#define FUJITSU_LENGTH 5 2885f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 2985f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov/* 3085f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov * Per-touchscreen data. 3185f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov */ 3285f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhovstruct fujitsu { 3385f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov struct input_dev *dev; 3485f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov struct serio *serio; 3585f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov int idx; 3685f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov unsigned char data[FUJITSU_LENGTH]; 3785f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov char phys[32]; 3885f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov}; 3985f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 4085f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov/* 4185f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov * Decode serial data (5 bytes per packet) 4285f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov * First byte 4385f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov * 1 C 0 0 R S S S 4485f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov * Where C is 1 while in calibration mode (which we don't use) 4585f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov * R is 1 when no coordinate corection was done. 4685f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov * S are button state 4785f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov */ 4885f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhovstatic irqreturn_t fujitsu_interrupt(struct serio *serio, 4985f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov unsigned char data, unsigned int flags) 5085f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov{ 5185f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov struct fujitsu *fujitsu = serio_get_drvdata(serio); 5285f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov struct input_dev *dev = fujitsu->dev; 5385f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 5485f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov if (fujitsu->idx == 0) { 5585f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov /* resync skip until start of frame */ 5685f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov if ((data & 0xf0) != 0x80) 5785f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov return IRQ_HANDLED; 5885f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov } else { 5985f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov /* resync skip garbage */ 6085f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov if (data & 0x80) { 6185f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov fujitsu->idx = 0; 6285f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov return IRQ_HANDLED; 6385f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov } 6485f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov } 6585f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 6685f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov fujitsu->data[fujitsu->idx++] = data; 6785f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov if (fujitsu->idx == FUJITSU_LENGTH) { 6885f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov input_report_abs(dev, ABS_X, 6985f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov (fujitsu->data[2] << 7) | fujitsu->data[1]); 7085f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov input_report_abs(dev, ABS_Y, 7185f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov (fujitsu->data[4] << 7) | fujitsu->data[3]); 7285f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov input_report_key(dev, BTN_TOUCH, 7385f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov (fujitsu->data[0] & 0x03) != 2); 7485f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov input_sync(dev); 7585f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov fujitsu->idx = 0; 7685f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov } 7785f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 7885f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov return IRQ_HANDLED; 7985f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov} 8085f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 8185f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov/* 8285f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov * fujitsu_disconnect() is the opposite of fujitsu_connect() 8385f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov */ 8485f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhovstatic void fujitsu_disconnect(struct serio *serio) 8585f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov{ 8685f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov struct fujitsu *fujitsu = serio_get_drvdata(serio); 8785f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 8885f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov input_get_device(fujitsu->dev); 8985f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov input_unregister_device(fujitsu->dev); 9085f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov serio_close(serio); 9185f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov serio_set_drvdata(serio, NULL); 9285f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov input_put_device(fujitsu->dev); 9385f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov kfree(fujitsu); 9485f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov} 9585f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 9685f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov/* 9785f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov * fujitsu_connect() is the routine that is called when someone adds a 9885f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov * new serio device that supports the Fujitsu protocol and registers it 9985f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov * as input device. 10085f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov */ 10185f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhovstatic int fujitsu_connect(struct serio *serio, struct serio_driver *drv) 10285f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov{ 10385f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov struct fujitsu *fujitsu; 10485f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov struct input_dev *input_dev; 10585f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov int err; 10685f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 10785f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov fujitsu = kzalloc(sizeof(struct fujitsu), GFP_KERNEL); 10885f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov input_dev = input_allocate_device(); 10985f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov if (!fujitsu || !input_dev) { 11085f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov err = -ENOMEM; 11185f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov goto fail1; 11285f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov } 11385f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 11485f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov fujitsu->serio = serio; 11585f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov fujitsu->dev = input_dev; 11685f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov snprintf(fujitsu->phys, sizeof(fujitsu->phys), 11785f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov "%s/input0", serio->phys); 11885f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 11985f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov input_dev->name = "Fujitsu Serial Touchscreen"; 12085f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov input_dev->phys = fujitsu->phys; 12185f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov input_dev->id.bustype = BUS_RS232; 12285f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov input_dev->id.vendor = SERIO_FUJITSU; 12385f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov input_dev->id.product = 0; 12485f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov input_dev->id.version = 0x0100; 1257b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 1267b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); 12785f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 12885f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov input_set_abs_params(input_dev, ABS_X, 0, 4096, 0, 0); 12985f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov input_set_abs_params(input_dev, ABS_Y, 0, 4096, 0, 0); 13085f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov serio_set_drvdata(serio, fujitsu); 13185f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 13285f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov err = serio_open(serio, drv); 13385f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov if (err) 13485f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov goto fail2; 13585f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 13685f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov err = input_register_device(fujitsu->dev); 13785f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov if (err) 13885f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov goto fail3; 13985f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 14085f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov return 0; 14185f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 14285f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov fail3: 14385f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov serio_close(serio); 14485f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov fail2: 14585f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov serio_set_drvdata(serio, NULL); 14685f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov fail1: 14785f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov input_free_device(input_dev); 14885f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov kfree(fujitsu); 14985f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov return err; 15085f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov} 15185f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 15285f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov/* 15385f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov * The serio driver structure. 15485f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov */ 15585f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhovstatic struct serio_device_id fujitsu_serio_ids[] = { 15685f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov { 15785f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov .type = SERIO_RS232, 15885f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov .proto = SERIO_FUJITSU, 15985f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov .id = SERIO_ANY, 16085f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov .extra = SERIO_ANY, 16185f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov }, 16285f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov { 0 } 16385f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov}; 16485f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 16585f202d5df877f8adcda342b74ab11fbdfea753dDmitry TorokhovMODULE_DEVICE_TABLE(serio, fujitsu_serio_ids); 16685f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 16785f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhovstatic struct serio_driver fujitsu_drv = { 16885f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov .driver = { 16985f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov .name = "fujitsu_ts", 17085f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov }, 17185f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov .description = DRIVER_DESC, 17285f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov .id_table = fujitsu_serio_ids, 17385f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov .interrupt = fujitsu_interrupt, 17485f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov .connect = fujitsu_connect, 17585f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov .disconnect = fujitsu_disconnect, 17685f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov}; 17785f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 17885f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhovstatic int __init fujitsu_init(void) 17985f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov{ 18085f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov return serio_register_driver(&fujitsu_drv); 18185f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov} 18285f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 18385f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhovstatic void __exit fujitsu_exit(void) 18485f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov{ 18585f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov serio_unregister_driver(&fujitsu_drv); 18685f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov} 18785f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhov 18885f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhovmodule_init(fujitsu_init); 18985f202d5df877f8adcda342b74ab11fbdfea753dDmitry Torokhovmodule_exit(fujitsu_exit); 190