Linux 5.1.15
[linux/fpc-iii.git] / drivers / input / mouse / pc110pad.c
blobb8965e6bc89069f2862e4e77602af70a888fc577
1 /*
2 * Copyright (c) 2000-2001 Vojtech Pavlik
4 * Based on the work of:
5 * Alan Cox Robin O'Leary
6 */
8 /*
9 * IBM PC110 touchpad driver for Linux
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include <linux/module.h>
29 #include <linux/kernel.h>
30 #include <linux/errno.h>
31 #include <linux/ioport.h>
32 #include <linux/input.h>
33 #include <linux/init.h>
34 #include <linux/interrupt.h>
35 #include <linux/pci.h>
36 #include <linux/delay.h>
38 #include <asm/io.h>
39 #include <asm/irq.h>
41 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
42 MODULE_DESCRIPTION("IBM PC110 touchpad driver");
43 MODULE_LICENSE("GPL");
45 #define PC110PAD_OFF 0x30
46 #define PC110PAD_ON 0x38
48 static int pc110pad_irq = 10;
49 static int pc110pad_io = 0x15e0;
51 static struct input_dev *pc110pad_dev;
52 static int pc110pad_data[3];
53 static int pc110pad_count;
55 static irqreturn_t pc110pad_interrupt(int irq, void *ptr)
57 int value = inb_p(pc110pad_io);
58 int handshake = inb_p(pc110pad_io + 2);
60 outb(handshake | 1, pc110pad_io + 2);
61 udelay(2);
62 outb(handshake & ~1, pc110pad_io + 2);
63 udelay(2);
64 inb_p(0x64);
66 pc110pad_data[pc110pad_count++] = value;
68 if (pc110pad_count < 3)
69 return IRQ_HANDLED;
71 input_report_key(pc110pad_dev, BTN_TOUCH,
72 pc110pad_data[0] & 0x01);
73 input_report_abs(pc110pad_dev, ABS_X,
74 pc110pad_data[1] | ((pc110pad_data[0] << 3) & 0x80) | ((pc110pad_data[0] << 1) & 0x100));
75 input_report_abs(pc110pad_dev, ABS_Y,
76 pc110pad_data[2] | ((pc110pad_data[0] << 4) & 0x80));
77 input_sync(pc110pad_dev);
79 pc110pad_count = 0;
80 return IRQ_HANDLED;
83 static void pc110pad_close(struct input_dev *dev)
85 outb(PC110PAD_OFF, pc110pad_io + 2);
88 static int pc110pad_open(struct input_dev *dev)
90 pc110pad_interrupt(0, NULL);
91 pc110pad_interrupt(0, NULL);
92 pc110pad_interrupt(0, NULL);
93 outb(PC110PAD_ON, pc110pad_io + 2);
94 pc110pad_count = 0;
96 return 0;
100 * We try to avoid enabling the hardware if it's not
101 * there, but we don't know how to test. But we do know
102 * that the PC110 is not a PCI system. So if we find any
103 * PCI devices in the machine, we don't have a PC110.
105 static int __init pc110pad_init(void)
107 int err;
109 if (!no_pci_devices())
110 return -ENODEV;
112 if (!request_region(pc110pad_io, 4, "pc110pad")) {
113 printk(KERN_ERR "pc110pad: I/O area %#x-%#x in use.\n",
114 pc110pad_io, pc110pad_io + 4);
115 return -EBUSY;
118 outb(PC110PAD_OFF, pc110pad_io + 2);
120 if (request_irq(pc110pad_irq, pc110pad_interrupt, 0, "pc110pad", NULL)) {
121 printk(KERN_ERR "pc110pad: Unable to get irq %d.\n", pc110pad_irq);
122 err = -EBUSY;
123 goto err_release_region;
126 pc110pad_dev = input_allocate_device();
127 if (!pc110pad_dev) {
128 printk(KERN_ERR "pc110pad: Not enough memory.\n");
129 err = -ENOMEM;
130 goto err_free_irq;
133 pc110pad_dev->name = "IBM PC110 TouchPad";
134 pc110pad_dev->phys = "isa15e0/input0";
135 pc110pad_dev->id.bustype = BUS_ISA;
136 pc110pad_dev->id.vendor = 0x0003;
137 pc110pad_dev->id.product = 0x0001;
138 pc110pad_dev->id.version = 0x0100;
140 pc110pad_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
141 pc110pad_dev->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y);
142 pc110pad_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
144 input_abs_set_max(pc110pad_dev, ABS_X, 0x1ff);
145 input_abs_set_max(pc110pad_dev, ABS_Y, 0x0ff);
147 pc110pad_dev->open = pc110pad_open;
148 pc110pad_dev->close = pc110pad_close;
150 err = input_register_device(pc110pad_dev);
151 if (err)
152 goto err_free_dev;
154 return 0;
156 err_free_dev:
157 input_free_device(pc110pad_dev);
158 err_free_irq:
159 free_irq(pc110pad_irq, NULL);
160 err_release_region:
161 release_region(pc110pad_io, 4);
163 return err;
166 static void __exit pc110pad_exit(void)
168 outb(PC110PAD_OFF, pc110pad_io + 2);
169 free_irq(pc110pad_irq, NULL);
170 input_unregister_device(pc110pad_dev);
171 release_region(pc110pad_io, 4);
174 module_init(pc110pad_init);
175 module_exit(pc110pad_exit);