1 /* 2 * $Id: pc110pad.c,v 1.12 2001/09/25 10:12:07 vojtech Exp $ 3 * 4 * Copyright (c) 2000-2001 Vojtech Pavlik 5 * 6 * Based on the work of: 7 * Alan Cox Robin O'Leary 8 */ 9 10 /* 11 * IBM PC110 touchpad driver for Linux 12 */ 13 14 /* 15 * This program is free software; you can redistribute it and/or modify 16 * it under the terms of the GNU General Public License as published by 17 * the Free Software Foundation; either version 2 of the License, or 18 * (at your option) any later version. 19 * 20 * This program is distributed in the hope that it will be useful, 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * GNU General Public License for more details. 24 * 25 * You should have received a copy of the GNU General Public License 26 * along with this program; if not, write to the Free Software 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 * 29 * Should you need to contact me, the author, you can do so either by 30 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: 31 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic 32 */ 33 34 #include <linux/module.h> 35 #include <linux/kernel.h> 36 #include <linux/errno.h> 37 #include <linux/ioport.h> 38 #include <linux/input.h> 39 #include <linux/init.h> 40 #include <linux/interrupt.h> 41 #include <linux/pci.h> 42 43 #include <asm/io.h> 44 #include <asm/irq.h> 45 46 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); 47 MODULE_DESCRIPTION("IBM PC110 touchpad driver"); 48 MODULE_LICENSE("GPL"); 49 50 #define PC110PAD_OFF 0x30 51 #define PC110PAD_ON 0x38 52 53 static int pc110pad_irq = 10; 54 static int pc110pad_io = 0x15e0; 55 56 static struct input_dev pc110pad_dev; 57 static int pc110pad_data[3]; 58 static int pc110pad_count; 59 60 static char *pc110pad_name = "IBM PC110 TouchPad"; 61 static char *pc110pad_phys = "isa15e0/input0"; 62 63 static irqreturn_t pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs) 64 { 65 int value = inb_p(pc110pad_io); 66 int handshake = inb_p(pc110pad_io + 2); 67 68 outb_p(handshake | 1, pc110pad_io + 2); 69 outb_p(handshake & ~1, pc110pad_io + 2); 70 inb_p(0x64); 71 72 pc110pad_data[pc110pad_count++] = value; 73 74 if (pc110pad_count < 3) 75 return IRQ_HANDLED; 76 77 input_regs(&pc110pad_dev, regs); 78 input_report_key(&pc110pad_dev, BTN_TOUCH, 79 pc110pad_data[0] & 0x01); 80 input_report_abs(&pc110pad_dev, ABS_X, 81 pc110pad_data[1] | ((pc110pad_data[0] << 3) & 0x80) | ((pc110pad_data[0] << 1) & 0x100)); 82 input_report_abs(&pc110pad_dev, ABS_Y, 83 pc110pad_data[2] | ((pc110pad_data[0] << 4) & 0x80)); 84 input_sync(&pc110pad_dev); 85 86 pc110pad_count = 0; 87 return IRQ_HANDLED; 88 } 89 90 static void pc110pad_close(struct input_dev *dev) 91 { 92 outb(PC110PAD_OFF, pc110pad_io + 2); 93 } 94 95 static int pc110pad_open(struct input_dev *dev) 96 { 97 pc110pad_interrupt(0,NULL,NULL); 98 pc110pad_interrupt(0,NULL,NULL); 99 pc110pad_interrupt(0,NULL,NULL); 100 outb(PC110PAD_ON, pc110pad_io + 2); 101 pc110pad_count = 0; 102 103 return 0; 104 } 105 106 /* 107 * We try to avoid enabling the hardware if it's not 108 * there, but we don't know how to test. But we do know 109 * that the PC110 is not a PCI system. So if we find any 110 * PCI devices in the machine, we don't have a PC110. 111 */ 112 static int __init pc110pad_init(void) 113 { 114 struct pci_dev *dev; 115 116 dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL); 117 if (dev) { 118 pci_dev_put(dev); 119 return -ENOENT; 120 } 121 122 if (!request_region(pc110pad_io, 4, "pc110pad")) { 123 printk(KERN_ERR "pc110pad: I/O area %#x-%#x in use.\n", 124 pc110pad_io, pc110pad_io + 4); 125 return -EBUSY; 126 } 127 128 outb(PC110PAD_OFF, pc110pad_io + 2); 129 130 if (request_irq(pc110pad_irq, pc110pad_interrupt, 0, "pc110pad", NULL)) 131 { 132 release_region(pc110pad_io, 4); 133 printk(KERN_ERR "pc110pad: Unable to get irq %d.\n", pc110pad_irq); 134 return -EBUSY; 135 } 136 137 pc110pad_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); 138 pc110pad_dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); 139 pc110pad_dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); 140 141 pc110pad_dev.absmax[ABS_X] = 0x1ff; 142 pc110pad_dev.absmax[ABS_Y] = 0x0ff; 143 144 pc110pad_dev.open = pc110pad_open; 145 pc110pad_dev.close = pc110pad_close; 146 147 pc110pad_dev.name = pc110pad_name; 148 pc110pad_dev.phys = pc110pad_phys; 149 pc110pad_dev.id.bustype = BUS_ISA; 150 pc110pad_dev.id.vendor = 0x0003; 151 pc110pad_dev.id.product = 0x0001; 152 pc110pad_dev.id.version = 0x0100; 153 154 input_register_device(&pc110pad_dev); 155 156 printk(KERN_INFO "input: %s at %#x irq %d\n", 157 pc110pad_name, pc110pad_io, pc110pad_irq); 158 159 return 0; 160 } 161 162 static void __exit pc110pad_exit(void) 163 { 164 input_unregister_device(&pc110pad_dev); 165 166 outb(PC110PAD_OFF, pc110pad_io + 2); 167 168 free_irq(pc110pad_irq, NULL); 169 release_region(pc110pad_io, 4); 170 } 171 172 module_init(pc110pad_init); 173 module_exit(pc110pad_exit); 174