initial commit with v2.6.9
[linux-2.6.9-moxart.git] / drivers / input / joystick / guillemot.c
blobcfe8c6be1a5a064e35f785dd67d3a97bbf7f2052
1 /*
2 * $Id: guillemot.c,v 1.10 2002/01/22 20:28:12 vojtech Exp $
4 * Copyright (c) 2001 Vojtech Pavlik
5 */
7 /*
8 * Guillemot Digital Interface Protocol driver for Linux
9 */
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 * Should you need to contact me, the author, you can do so either by
27 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
28 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
31 #include <linux/kernel.h>
32 #include <linux/slab.h>
33 #include <linux/module.h>
34 #include <linux/delay.h>
35 #include <linux/init.h>
36 #include <linux/gameport.h>
37 #include <linux/input.h>
39 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
40 MODULE_DESCRIPTION("Guillemot Digital joystick driver");
41 MODULE_LICENSE("GPL");
43 #define GUILLEMOT_MAX_START 600 /* 600 us */
44 #define GUILLEMOT_MAX_STROBE 60 /* 60 us */
45 #define GUILLEMOT_MAX_LENGTH 17 /* 17 bytes */
46 #define GUILLEMOT_REFRESH_TIME HZ/50 /* 20 ms */
48 static short guillemot_abs_pad[] =
49 { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, -1 };
51 static short guillemot_btn_pad[] =
52 { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_MODE, BTN_SELECT, -1 };
54 static struct {
55 int x;
56 int y;
57 } guillemot_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
59 struct guillemot_type {
60 unsigned char id;
61 short *abs;
62 short *btn;
63 int hat;
64 char *name;
67 struct guillemot {
68 struct gameport *gameport;
69 struct input_dev dev;
70 struct timer_list timer;
71 int used;
72 int bads;
73 int reads;
74 struct guillemot_type *type;
75 unsigned char length;
76 char phys[32];
79 static struct guillemot_type guillemot_type[] = {
80 { 0x00, guillemot_abs_pad, guillemot_btn_pad, 1, "Guillemot Pad" },
81 { 0 }};
84 * guillemot_read_packet() reads Guillemot joystick data.
87 static int guillemot_read_packet(struct gameport *gameport, u8 *data)
89 unsigned long flags;
90 unsigned char u, v;
91 unsigned int t, s;
92 int i;
94 for (i = 0; i < GUILLEMOT_MAX_LENGTH; i++)
95 data[i] = 0;
97 i = 0;
98 t = gameport_time(gameport, GUILLEMOT_MAX_START);
99 s = gameport_time(gameport, GUILLEMOT_MAX_STROBE);
101 local_irq_save(flags);
102 gameport_trigger(gameport);
103 v = gameport_read(gameport);
105 while (t > 0 && i < GUILLEMOT_MAX_LENGTH * 8) {
106 t--;
107 u = v; v = gameport_read(gameport);
108 if (v & ~u & 0x10) {
109 data[i >> 3] |= ((v >> 5) & 1) << (i & 7);
110 i++;
111 t = s;
115 local_irq_restore(flags);
117 return i;
121 * guillemot_timer() reads and analyzes Guillemot joystick data.
124 static void guillemot_timer(unsigned long private)
126 struct guillemot *guillemot = (struct guillemot *) private;
127 struct input_dev *dev = &guillemot->dev;
128 u8 data[GUILLEMOT_MAX_LENGTH];
129 int i;
131 guillemot->reads++;
133 if (guillemot_read_packet(guillemot->gameport, data) != GUILLEMOT_MAX_LENGTH * 8 ||
134 data[0] != 0x55 || data[16] != 0xaa) {
135 guillemot->bads++;
136 } else {
138 for (i = 0; i < 6 && guillemot->type->abs[i] >= 0; i++)
139 input_report_abs(dev, guillemot->type->abs[i], data[i + 5]);
141 if (guillemot->type->hat) {
142 input_report_abs(dev, ABS_HAT0X, guillemot_hat_to_axis[data[4] >> 4].x);
143 input_report_abs(dev, ABS_HAT0Y, guillemot_hat_to_axis[data[4] >> 4].y);
146 for (i = 0; i < 16 && guillemot->type->btn[i] >= 0; i++)
147 input_report_key(dev, guillemot->type->btn[i], (data[2 + (i >> 3)] >> (i & 7)) & 1);
150 input_sync(dev);
152 mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME);
156 * guillemot_open() is a callback from the input open routine.
159 static int guillemot_open(struct input_dev *dev)
161 struct guillemot *guillemot = dev->private;
162 if (!guillemot->used++)
163 mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME);
164 return 0;
168 * guillemot_close() is a callback from the input close routine.
171 static void guillemot_close(struct input_dev *dev)
173 struct guillemot *guillemot = dev->private;
174 if (!--guillemot->used)
175 del_timer(&guillemot->timer);
179 * guillemot_connect() probes for Guillemot joysticks.
182 static void guillemot_connect(struct gameport *gameport, struct gameport_dev *dev)
184 struct guillemot *guillemot;
185 u8 data[GUILLEMOT_MAX_LENGTH];
186 int i, t;
188 if (!(guillemot = kmalloc(sizeof(struct guillemot), GFP_KERNEL)))
189 return;
190 memset(guillemot, 0, sizeof(struct guillemot));
192 gameport->private = guillemot;
194 guillemot->gameport = gameport;
195 init_timer(&guillemot->timer);
196 guillemot->timer.data = (long) guillemot;
197 guillemot->timer.function = guillemot_timer;
199 if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
200 goto fail1;
202 i = guillemot_read_packet(gameport, data);
204 if (i != GUILLEMOT_MAX_LENGTH * 8 || data[0] != 0x55 || data[16] != 0xaa)
205 goto fail2;
207 for (i = 0; guillemot_type[i].name; i++)
208 if (guillemot_type[i].id == data[11])
209 break;
211 if (!guillemot_type[i].name) {
212 printk(KERN_WARNING "guillemot.c: Unknown joystick on %s. [ %02x%02x:%04x, ver %d.%02d ]\n",
213 gameport->phys, data[12], data[13], data[11], data[14], data[15]);
214 goto fail2;
217 sprintf(guillemot->phys, "%s/input0", gameport->phys);
219 guillemot->type = guillemot_type + i;
221 guillemot->dev.private = guillemot;
222 guillemot->dev.open = guillemot_open;
223 guillemot->dev.close = guillemot_close;
225 guillemot->dev.name = guillemot_type[i].name;
226 guillemot->dev.phys = guillemot->phys;
227 guillemot->dev.id.bustype = BUS_GAMEPORT;
228 guillemot->dev.id.vendor = GAMEPORT_ID_VENDOR_GUILLEMOT;
229 guillemot->dev.id.product = guillemot_type[i].id;
230 guillemot->dev.id.version = (int)data[14] << 8 | data[15];
232 guillemot->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
234 for (i = 0; (t = guillemot->type->abs[i]) >= 0; i++) {
235 set_bit(t, guillemot->dev.absbit);
236 guillemot->dev.absmin[t] = 0;
237 guillemot->dev.absmax[t] = 255;
240 if (guillemot->type->hat)
241 for (i = 0; i < 2; i++) {
242 t = ABS_HAT0X + i;
243 set_bit(t, guillemot->dev.absbit);
244 guillemot->dev.absmin[t] = -1;
245 guillemot->dev.absmax[t] = 1;
248 for (i = 0; (t = guillemot->type->btn[i]) >= 0; i++)
249 set_bit(t, guillemot->dev.keybit);
251 input_register_device(&guillemot->dev);
252 printk(KERN_INFO "input: %s ver %d.%02d on %s\n",
253 guillemot->type->name, data[14], data[15], gameport->phys);
255 return;
256 fail2: gameport_close(gameport);
257 fail1: kfree(guillemot);
260 static void guillemot_disconnect(struct gameport *gameport)
262 struct guillemot *guillemot = gameport->private;
263 printk(KERN_INFO "guillemot.c: Failed %d reads out of %d on %s\n", guillemot->reads, guillemot->bads, guillemot->phys);
264 input_unregister_device(&guillemot->dev);
265 gameport_close(gameport);
266 kfree(guillemot);
269 static struct gameport_dev guillemot_dev = {
270 .connect = guillemot_connect,
271 .disconnect = guillemot_disconnect,
274 int __init guillemot_init(void)
276 gameport_register_device(&guillemot_dev);
277 return 0;
280 void __exit guillemot_exit(void)
282 gameport_unregister_device(&guillemot_dev);
285 module_init(guillemot_init);
286 module_exit(guillemot_exit);