diff options
| author | Pau Oliva Fora <pau@eslack.org> | 2008-06-02 00:38:35 -0400 | 
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2008-06-02 00:38:35 -0400 | 
| commit | 5a18c343a6bee4b38965f14a40ccb95306641f87 (patch) | |
| tree | fd169a5bec68b762dea8a93127f430c3cc908cfd | |
| parent | c3a34f4390396a4bede3f8b7bcc5153f50b974bb (diff) | |
Input: add HTC Shift Touchscreen Driver
Signed-off-by: Pau Oliva Fora <pau@eslack.org>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
| -rw-r--r-- | MAINTAINERS | 6 | ||||
| -rw-r--r-- | drivers/input/touchscreen/Kconfig | 12 | ||||
| -rw-r--r-- | drivers/input/touchscreen/Makefile | 1 | ||||
| -rw-r--r-- | drivers/input/touchscreen/htcpen.c | 255 | 
4 files changed, 274 insertions, 0 deletions
| diff --git a/MAINTAINERS b/MAINTAINERS index bc1c0088dc49..5f12d73142a0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1928,6 +1928,12 @@ M:	mikulas@artax.karlin.mff.cuni.cz  W:	http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi  S:	Maintained +HTCPEN TOUCHSCREEN DRIVER +P:	Pau Oliva Fora +M:	pof@eslack.org +L:	linux-input@vger.kernel.org +S:	Maintained +  HUGETLB FILESYSTEM  P:	William Irwin  M:	wli@holomorphy.com diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 2cb4df0e0a7b..030a89734855 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -134,6 +134,18 @@ config TOUCHSCREEN_HP7XX  	  To compile this driver as a module, choose M here: the  	  module will be called jornada720_ts. +config TOUCHSCREEN_HTCPEN +	tristate "HTC Shift X9500 touchscreen" +	depends on ISA +	help +	  Say Y here if you have an HTC Shift UMPC also known as HTC X9500 +	  Clio / Shangrila and want to support the built-in touchscreen. + +	  If unsure, say N. + +	  To compile this driver as a module, choose M here: the +	  module will be called htcpen. +  config TOUCHSCREEN_PENMOUNT  	tristate "Penmount serial touchscreen"  	select SERIO diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 30e86816cd41..64a11f443dce 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_TOUCHSCREEN_MTOUCH)	+= mtouch.o  obj-$(CONFIG_TOUCHSCREEN_MK712)		+= mk712.o  obj-$(CONFIG_TOUCHSCREEN_HP600)		+= hp680_ts_input.o  obj-$(CONFIG_TOUCHSCREEN_HP7XX)		+= jornada720_ts.o +obj-$(CONFIG_TOUCHSCREEN_HTCPEN)	+= htcpen.o  obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE)	+= usbtouchscreen.o  obj-$(CONFIG_TOUCHSCREEN_PENMOUNT)	+= penmount.o  obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)	+= touchright.o diff --git a/drivers/input/touchscreen/htcpen.c b/drivers/input/touchscreen/htcpen.c new file mode 100644 index 000000000000..62811de6f18f --- /dev/null +++ b/drivers/input/touchscreen/htcpen.c @@ -0,0 +1,255 @@ +/* + * HTC Shift touchscreen driver + * + * Copyright (C) 2008 Pau Oliva Fora <pof@eslack.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/isa.h> +#include <linux/ioport.h> +#include <linux/dmi.h> + +MODULE_AUTHOR("Pau Oliva Fora <pau@eslack.org>"); +MODULE_DESCRIPTION("HTC Shift touchscreen driver"); +MODULE_LICENSE("GPL"); + +#define HTCPEN_PORT_IRQ_CLEAR	0x068 +#define HTCPEN_PORT_INIT	0x06c +#define HTCPEN_PORT_INDEX	0x0250 +#define HTCPEN_PORT_DATA	0x0251 +#define HTCPEN_IRQ		3 + +#define DEVICE_ENABLE		0xa2 +#define DEVICE_DISABLE		0xa3 + +#define X_INDEX			3 +#define Y_INDEX			5 +#define TOUCH_INDEX		0xb +#define LSB_XY_INDEX		0xc +#define X_AXIS_MAX		2040 +#define Y_AXIS_MAX		2040 + +static int invert_x; +module_param(invert_x, bool, 0644); +MODULE_PARM_DESC(invert_x, "If set, X axis is inverted"); +static int invert_y; +module_param(invert_y, bool, 0644); +MODULE_PARM_DESC(invert_y, "If set, Y axis is inverted"); + +static struct pnp_device_id pnp_ids[] = { +	{ .id = "PNP0cc0" }, +	{ .id = "" } +}; +MODULE_DEVICE_TABLE(pnp, pnp_ids); + +static irqreturn_t htcpen_interrupt(int irq, void *handle) +{ +	struct input_dev *htcpen_dev = handle; +	unsigned short x, y, xy; + +	/* 0 = press; 1 = release */ +	outb_p(TOUCH_INDEX, HTCPEN_PORT_INDEX); + +	if (inb_p(HTCPEN_PORT_DATA)) { +		input_report_key(htcpen_dev, BTN_TOUCH, 0); +	} else { +		outb_p(X_INDEX, HTCPEN_PORT_INDEX); +		x = inb_p(HTCPEN_PORT_DATA); + +		outb_p(Y_INDEX, HTCPEN_PORT_INDEX); +		y = inb_p(HTCPEN_PORT_DATA); + +		outb_p(LSB_XY_INDEX, HTCPEN_PORT_INDEX); +		xy = inb_p(HTCPEN_PORT_DATA); + +		/* get high resolution value of X and Y using LSB */ +		x = X_AXIS_MAX - ((x * 8) + ((xy >> 4) & 0xf)); +		y = (y * 8) + (xy & 0xf); +		if (invert_x) +			x = X_AXIS_MAX - x; +		if (invert_y) +			y = Y_AXIS_MAX - y; + +		if (x != X_AXIS_MAX && x != 0) { +			input_report_key(htcpen_dev, BTN_TOUCH, 1); +			input_report_abs(htcpen_dev, ABS_X, x); +			input_report_abs(htcpen_dev, ABS_Y, y); +		} +	} + +	input_sync(htcpen_dev); + +	inb_p(HTCPEN_PORT_IRQ_CLEAR); + +	return IRQ_HANDLED; +} + +static int htcpen_open(struct input_dev *dev) +{ +	outb_p(DEVICE_ENABLE, HTCPEN_PORT_INIT); + +	return 0; +} + +static void htcpen_close(struct input_dev *dev) +{ +	outb_p(DEVICE_DISABLE, HTCPEN_PORT_INIT); +	synchronize_irq(HTCPEN_IRQ); +} + +static int __devinit htcpen_isa_probe(struct device *dev, unsigned int id) +{ +	struct input_dev *htcpen_dev; +	int err = -EBUSY; + +	if (!request_region(HTCPEN_PORT_IRQ_CLEAR, 1, "htcpen")) { +		printk(KERN_ERR "htcpen: unable to get IO region 0x%x\n", +			HTCPEN_PORT_IRQ_CLEAR); +		goto request_region1_failed; +	} + +	if (!request_region(HTCPEN_PORT_INIT, 1, "htcpen")) { +		printk(KERN_ERR "htcpen: unable to get IO region 0x%x\n", +			HTCPEN_PORT_INIT); +		goto request_region2_failed; +	} + +	if (!request_region(HTCPEN_PORT_INDEX, 2, "htcpen")) { +		printk(KERN_ERR "htcpen: unable to get IO region 0x%x\n", +			HTCPEN_PORT_INDEX); +		goto request_region3_failed; +	} + +	htcpen_dev = input_allocate_device(); +	if (!htcpen_dev) { +		printk(KERN_ERR "htcpen: can't allocate device\n"); +		err = -ENOMEM; +		goto input_alloc_failed; +	} + +	htcpen_dev->name = "HTC Shift EC TouchScreen"; +	htcpen_dev->id.bustype = BUS_ISA; + +	htcpen_dev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY); +	htcpen_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); +	input_set_abs_params(htcpen_dev, ABS_X, 0, X_AXIS_MAX, 0, 0); +	input_set_abs_params(htcpen_dev, ABS_Y, 0, Y_AXIS_MAX, 0, 0); + +	htcpen_dev->open = htcpen_open; +	htcpen_dev->close = htcpen_close; + +	err = request_irq(HTCPEN_IRQ, htcpen_interrupt, 0, "htcpen", +			htcpen_dev); +	if (err) { +		printk(KERN_ERR "htcpen: irq busy\n"); +		goto request_irq_failed; +	} + +	inb_p(HTCPEN_PORT_IRQ_CLEAR); + +	err = input_register_device(htcpen_dev); +	if (err) +		goto input_register_failed; + +	dev_set_drvdata(dev, htcpen_dev); + +	return 0; + + input_register_failed: +	free_irq(HTCPEN_IRQ, htcpen_dev); + request_irq_failed: +	input_free_device(htcpen_dev); + input_alloc_failed: +	release_region(HTCPEN_PORT_INDEX, 2); + request_region3_failed: +	release_region(HTCPEN_PORT_INIT, 1); + request_region2_failed: +	release_region(HTCPEN_PORT_IRQ_CLEAR, 1); + request_region1_failed: +	return err; +} + +static int __devexit htcpen_isa_remove(struct device *dev, unsigned int id) +{ +	struct input_dev *htcpen_dev = dev_get_drvdata(dev); + +	input_unregister_device(htcpen_dev); + +	free_irq(HTCPEN_IRQ, htcpen_dev); + +	release_region(HTCPEN_PORT_INDEX, 2); +	release_region(HTCPEN_PORT_INIT, 1); +	release_region(HTCPEN_PORT_IRQ_CLEAR, 1); + +	dev_set_drvdata(dev, NULL); + +	return 0; +} + +#ifdef CONFIG_PM +static int htcpen_isa_suspend(struct device *dev, unsigned int n, +				pm_message_t state) +{ +	outb_p(DEVICE_DISABLE, HTCPEN_PORT_INIT); + +	return 0; +} + +static int htcpen_isa_resume(struct device *dev, unsigned int n) +{ +	outb_p(DEVICE_ENABLE, HTCPEN_PORT_INIT); + +	return 0; +} +#endif + +static struct isa_driver htcpen_isa_driver = { +	.probe		= htcpen_isa_probe, +	.remove		= __devexit_p(htcpen_isa_remove), +#ifdef CONFIG_PM +	.suspend	= htcpen_isa_suspend, +	.resume		= htcpen_isa_resume, +#endif +	.driver = { +		.owner	= THIS_MODULE, +		.name	= "htcpen", +	} +}; + +static struct dmi_system_id __initdata htcshift_dmi_table[] = { +	{ +		.ident = "Shift", +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "High Tech Computer Corp"), +			DMI_MATCH(DMI_PRODUCT_NAME, "Shift"), +		}, +	}, +	{ } +}; + +static int __init htcpen_isa_init(void) +{ +	if (!dmi_check_system(htcshift_dmi_table)) +		return -ENODEV; + +	return isa_register_driver(&htcpen_isa_driver, 1); +} + +static void __exit htcpen_isa_exit(void) +{ +	isa_unregister_driver(&htcpen_isa_driver); +} + +module_init(htcpen_isa_init); +module_exit(htcpen_isa_exit); | 
