Path: blob/master/drivers/input/touchscreen/htcpen.c
15111 views
/*1* HTC Shift touchscreen driver2*3* Copyright (C) 2008 Pau Oliva Fora <[email protected]>4*5* This program is free software; you can redistribute it and/or modify it6* under the terms of the GNU General Public License version 2 as published7* by the Free Software Foundation.8*/910#include <linux/errno.h>11#include <linux/kernel.h>12#include <linux/module.h>13#include <linux/input.h>14#include <linux/interrupt.h>15#include <linux/io.h>16#include <linux/init.h>17#include <linux/irq.h>18#include <linux/isa.h>19#include <linux/ioport.h>20#include <linux/dmi.h>2122MODULE_AUTHOR("Pau Oliva Fora <[email protected]>");23MODULE_DESCRIPTION("HTC Shift touchscreen driver");24MODULE_LICENSE("GPL");2526#define HTCPEN_PORT_IRQ_CLEAR 0x06827#define HTCPEN_PORT_INIT 0x06c28#define HTCPEN_PORT_INDEX 0x025029#define HTCPEN_PORT_DATA 0x025130#define HTCPEN_IRQ 33132#define DEVICE_ENABLE 0xa233#define DEVICE_DISABLE 0xa33435#define X_INDEX 336#define Y_INDEX 537#define TOUCH_INDEX 0xb38#define LSB_XY_INDEX 0xc39#define X_AXIS_MAX 204040#define Y_AXIS_MAX 20404142static int invert_x;43module_param(invert_x, bool, 0644);44MODULE_PARM_DESC(invert_x, "If set, X axis is inverted");45static int invert_y;46module_param(invert_y, bool, 0644);47MODULE_PARM_DESC(invert_y, "If set, Y axis is inverted");4849static struct pnp_device_id pnp_ids[] = {50{ .id = "PNP0cc0" },51{ .id = "" }52};53MODULE_DEVICE_TABLE(pnp, pnp_ids);5455static irqreturn_t htcpen_interrupt(int irq, void *handle)56{57struct input_dev *htcpen_dev = handle;58unsigned short x, y, xy;5960/* 0 = press; 1 = release */61outb_p(TOUCH_INDEX, HTCPEN_PORT_INDEX);6263if (inb_p(HTCPEN_PORT_DATA)) {64input_report_key(htcpen_dev, BTN_TOUCH, 0);65} else {66outb_p(X_INDEX, HTCPEN_PORT_INDEX);67x = inb_p(HTCPEN_PORT_DATA);6869outb_p(Y_INDEX, HTCPEN_PORT_INDEX);70y = inb_p(HTCPEN_PORT_DATA);7172outb_p(LSB_XY_INDEX, HTCPEN_PORT_INDEX);73xy = inb_p(HTCPEN_PORT_DATA);7475/* get high resolution value of X and Y using LSB */76x = X_AXIS_MAX - ((x * 8) + ((xy >> 4) & 0xf));77y = (y * 8) + (xy & 0xf);78if (invert_x)79x = X_AXIS_MAX - x;80if (invert_y)81y = Y_AXIS_MAX - y;8283if (x != X_AXIS_MAX && x != 0) {84input_report_key(htcpen_dev, BTN_TOUCH, 1);85input_report_abs(htcpen_dev, ABS_X, x);86input_report_abs(htcpen_dev, ABS_Y, y);87}88}8990input_sync(htcpen_dev);9192inb_p(HTCPEN_PORT_IRQ_CLEAR);9394return IRQ_HANDLED;95}9697static int htcpen_open(struct input_dev *dev)98{99outb_p(DEVICE_ENABLE, HTCPEN_PORT_INIT);100101return 0;102}103104static void htcpen_close(struct input_dev *dev)105{106outb_p(DEVICE_DISABLE, HTCPEN_PORT_INIT);107synchronize_irq(HTCPEN_IRQ);108}109110static int __devinit htcpen_isa_probe(struct device *dev, unsigned int id)111{112struct input_dev *htcpen_dev;113int err = -EBUSY;114115if (!request_region(HTCPEN_PORT_IRQ_CLEAR, 1, "htcpen")) {116printk(KERN_ERR "htcpen: unable to get IO region 0x%x\n",117HTCPEN_PORT_IRQ_CLEAR);118goto request_region1_failed;119}120121if (!request_region(HTCPEN_PORT_INIT, 1, "htcpen")) {122printk(KERN_ERR "htcpen: unable to get IO region 0x%x\n",123HTCPEN_PORT_INIT);124goto request_region2_failed;125}126127if (!request_region(HTCPEN_PORT_INDEX, 2, "htcpen")) {128printk(KERN_ERR "htcpen: unable to get IO region 0x%x\n",129HTCPEN_PORT_INDEX);130goto request_region3_failed;131}132133htcpen_dev = input_allocate_device();134if (!htcpen_dev) {135printk(KERN_ERR "htcpen: can't allocate device\n");136err = -ENOMEM;137goto input_alloc_failed;138}139140htcpen_dev->name = "HTC Shift EC TouchScreen";141htcpen_dev->id.bustype = BUS_ISA;142143htcpen_dev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);144htcpen_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);145input_set_abs_params(htcpen_dev, ABS_X, 0, X_AXIS_MAX, 0, 0);146input_set_abs_params(htcpen_dev, ABS_Y, 0, Y_AXIS_MAX, 0, 0);147148htcpen_dev->open = htcpen_open;149htcpen_dev->close = htcpen_close;150151err = request_irq(HTCPEN_IRQ, htcpen_interrupt, 0, "htcpen",152htcpen_dev);153if (err) {154printk(KERN_ERR "htcpen: irq busy\n");155goto request_irq_failed;156}157158inb_p(HTCPEN_PORT_IRQ_CLEAR);159160err = input_register_device(htcpen_dev);161if (err)162goto input_register_failed;163164dev_set_drvdata(dev, htcpen_dev);165166return 0;167168input_register_failed:169free_irq(HTCPEN_IRQ, htcpen_dev);170request_irq_failed:171input_free_device(htcpen_dev);172input_alloc_failed:173release_region(HTCPEN_PORT_INDEX, 2);174request_region3_failed:175release_region(HTCPEN_PORT_INIT, 1);176request_region2_failed:177release_region(HTCPEN_PORT_IRQ_CLEAR, 1);178request_region1_failed:179return err;180}181182static int __devexit htcpen_isa_remove(struct device *dev, unsigned int id)183{184struct input_dev *htcpen_dev = dev_get_drvdata(dev);185186input_unregister_device(htcpen_dev);187188free_irq(HTCPEN_IRQ, htcpen_dev);189190release_region(HTCPEN_PORT_INDEX, 2);191release_region(HTCPEN_PORT_INIT, 1);192release_region(HTCPEN_PORT_IRQ_CLEAR, 1);193194dev_set_drvdata(dev, NULL);195196return 0;197}198199#ifdef CONFIG_PM200static int htcpen_isa_suspend(struct device *dev, unsigned int n,201pm_message_t state)202{203outb_p(DEVICE_DISABLE, HTCPEN_PORT_INIT);204205return 0;206}207208static int htcpen_isa_resume(struct device *dev, unsigned int n)209{210outb_p(DEVICE_ENABLE, HTCPEN_PORT_INIT);211212return 0;213}214#endif215216static struct isa_driver htcpen_isa_driver = {217.probe = htcpen_isa_probe,218.remove = __devexit_p(htcpen_isa_remove),219#ifdef CONFIG_PM220.suspend = htcpen_isa_suspend,221.resume = htcpen_isa_resume,222#endif223.driver = {224.owner = THIS_MODULE,225.name = "htcpen",226}227};228229static struct dmi_system_id __initdata htcshift_dmi_table[] = {230{231.ident = "Shift",232.matches = {233DMI_MATCH(DMI_SYS_VENDOR, "High Tech Computer Corp"),234DMI_MATCH(DMI_PRODUCT_NAME, "Shift"),235},236},237{ }238};239240static int __init htcpen_isa_init(void)241{242if (!dmi_check_system(htcshift_dmi_table))243return -ENODEV;244245return isa_register_driver(&htcpen_isa_driver, 1);246}247248static void __exit htcpen_isa_exit(void)249{250isa_unregister_driver(&htcpen_isa_driver);251}252253module_init(htcpen_isa_init);254module_exit(htcpen_isa_exit);255256257