ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / input / mouse / 98busmouse.c
1 /*
2  *
3  *  Copyright (c) 2002 Osamu Tomita
4  *
5  *  Based on the work of:
6  *      James Banks             Matthew Dillon
7  *      David Giller            Nathan Laredo
8  *      Linus Torvalds          Johan Myreen
9  *      Cliff Matthews          Philip Blundell
10  *      Russell King            Vojtech Pavlik
11  */
12
13 /*
14  * NEC PC-9801 Bus Mouse Driver for Linux
15  */
16
17 /*
18  * This program is free software; you can redistribute it and/or modify
19  * it under the terms of the GNU General Public License as published by
20  * the Free Software Foundation; either version 2 of the License, or 
21  * (at your option) any later version.
22  * 
23  * This program is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  * GNU General Public License for more details.
27  * 
28  * You should have received a copy of the GNU General Public License
29  * along with this program; if not, write to the Free Software
30  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31  * 
32  */
33
34 #include <linux/config.h>
35 #include <linux/module.h>
36 #include <linux/moduleparam.h>
37 #include <linux/delay.h>
38 #include <linux/ioport.h>
39 #include <linux/init.h>
40 #include <linux/input.h>
41 #include <linux/interrupt.h>
42
43 #include <asm/io.h>
44 #include <asm/irq.h>
45
46 MODULE_AUTHOR("Osamu Tomita <tomita@cinet.co.jp>");
47 MODULE_DESCRIPTION("PC-9801 busmouse driver");
48 MODULE_LICENSE("GPL");
49
50 #define PC98BM_BASE             0x7fd9
51 #define PC98BM_DATA_PORT        PC98BM_BASE + 0
52 /*      PC98BM_SIGNATURE_PORT   does not exist */
53 #define PC98BM_CONTROL_PORT     PC98BM_BASE + 4
54 /*      PC98BM_INTERRUPT_PORT   does not exist */
55 #define PC98BM_CONFIG_PORT      PC98BM_BASE + 6
56
57 #define PC98BM_ENABLE_IRQ       0x00
58 #define PC98BM_DISABLE_IRQ      0x10
59 #define PC98BM_READ_X_LOW       0x80
60 #define PC98BM_READ_X_HIGH      0xa0
61 #define PC98BM_READ_Y_LOW       0xc0
62 #define PC98BM_READ_Y_HIGH      0xe0
63
64 #define PC98BM_DEFAULT_MODE     0x93
65 /*      PC98BM_CONFIG_BYTE      is not used */
66 /*      PC98BM_SIGNATURE_BYTE   is not used */
67
68 #define PC98BM_TIMER_PORT       0xbfdb
69 #define PC98BM_DEFAULT_TIMER_VAL        0x00
70
71 #define PC98BM_IRQ              13
72
73 static int pc98bm_irq = PC98BM_IRQ;
74 module_param_named(irq, pc98bm_irq, uint, 0);
75 MODULE_PARM_DESC(irq, "IRQ number (13=default)");
76
77 __obsolete_setup("pc98bm_irq=");
78
79 static int pc98bm_used = 0;
80
81 static irqreturn_t pc98bm_interrupt(int irq, void *dev_id, struct pt_regs *regs);
82
83 static int pc98bm_open(struct input_dev *dev)
84 {
85         if (pc98bm_used++)
86                 return 0;
87         if (request_irq(pc98bm_irq, pc98bm_interrupt, 0, "98busmouse", NULL)) {
88                 pc98bm_used--;
89                 printk(KERN_ERR "98busmouse.c: Can't allocate irq %d\n", pc98bm_irq);
90                 return -EBUSY;
91         }
92         outb(PC98BM_ENABLE_IRQ, PC98BM_CONTROL_PORT);
93         return 0;
94 }
95
96 static void pc98bm_close(struct input_dev *dev)
97 {
98         if (--pc98bm_used)
99                 return;
100         outb(PC98BM_DISABLE_IRQ, PC98BM_CONTROL_PORT);
101         free_irq(pc98bm_irq, NULL);
102 }
103
104 static struct input_dev pc98bm_dev = {
105         .evbit  = { BIT(EV_KEY) | BIT(EV_REL) },
106         .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) },
107         .relbit = { BIT(REL_X) | BIT(REL_Y) },
108         .open   = pc98bm_open,
109         .close  = pc98bm_close,
110         .name   = "PC-9801 bus mouse",
111         .phys   = "isa7fd9/input0",
112         .id     = {
113                 .bustype = BUS_ISA,
114                 .vendor  = 0x0004,
115                 .product = 0x0001,
116                 .version = 0x0100,
117         },
118 };
119
120 static irqreturn_t pc98bm_interrupt(int irq, void *dev_id, struct pt_regs *regs)
121 {
122         char dx, dy;
123         unsigned char buttons;
124
125         outb(PC98BM_READ_X_LOW, PC98BM_CONTROL_PORT);
126         dx = (inb(PC98BM_DATA_PORT) & 0xf);
127         outb(PC98BM_READ_X_HIGH, PC98BM_CONTROL_PORT);
128         dx |= (inb(PC98BM_DATA_PORT) & 0xf) << 4;
129         outb(PC98BM_READ_Y_LOW, PC98BM_CONTROL_PORT);
130         dy = (inb(PC98BM_DATA_PORT) & 0xf);
131         outb(PC98BM_READ_Y_HIGH, PC98BM_CONTROL_PORT);
132         buttons = inb(PC98BM_DATA_PORT);
133         dy |= (buttons & 0xf) << 4;
134         buttons = ~buttons >> 5;
135
136         input_report_rel(&pc98bm_dev, REL_X, dx);
137         input_report_rel(&pc98bm_dev, REL_Y, dy);
138         input_report_key(&pc98bm_dev, BTN_RIGHT,  buttons & 1);
139         input_report_key(&pc98bm_dev, BTN_MIDDLE, buttons & 2);
140         input_report_key(&pc98bm_dev, BTN_LEFT,   buttons & 4);
141         input_sync(&pc98bm_dev);
142
143         outb(PC98BM_ENABLE_IRQ, PC98BM_CONTROL_PORT);
144
145         return IRQ_HANDLED;
146 }
147
148 static int __init pc98bm_init(void)
149 {
150         int i;
151
152         for (i = 0; i <= 6; i += 2) {
153                 if (!request_region(PC98BM_BASE + i, 1, "98busmouse")) {
154                         printk(KERN_ERR "98busmouse.c: Can't allocate ports at %#x\n", PC98BM_BASE + i);
155                         while (i > 0) {
156                                 i -= 2;
157                                 release_region(PC98BM_BASE + i, 1);
158                         }
159
160                         return -EBUSY;
161                 }
162
163         }
164
165         if (!request_region(PC98BM_TIMER_PORT, 1, "98busmouse")) {
166                 printk(KERN_ERR "98busmouse.c: Can't allocate ports at %#x\n", PC98BM_TIMER_PORT);
167                 for (i = 0; i <= 6; i += 2)
168                         release_region(PC98BM_BASE + i, 1);
169
170                 return -EBUSY;
171         }
172
173         outb(PC98BM_DEFAULT_MODE, PC98BM_CONFIG_PORT);
174         outb(PC98BM_DISABLE_IRQ, PC98BM_CONTROL_PORT);
175
176         outb(PC98BM_DEFAULT_TIMER_VAL, PC98BM_TIMER_PORT);
177
178         input_register_device(&pc98bm_dev);
179         
180         printk(KERN_INFO "input: PC-9801 bus mouse at %#x irq %d\n", PC98BM_BASE, pc98bm_irq);
181
182         return 0;
183 }
184
185 static void __exit pc98bm_exit(void)
186 {
187         int i;
188
189         input_unregister_device(&pc98bm_dev);
190         for (i = 0; i <= 6; i += 2)
191                 release_region(PC98BM_BASE + i, 1);
192
193         release_region(PC98BM_TIMER_PORT, 1);
194 }
195
196 module_init(pc98bm_init);
197 module_exit(pc98bm_exit);