blob: a0ba93ccac7255433e6dd3e46fd30c6d71a6aa88 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * $Id: grip_mp.c,v 1.9 2002/07/20 19:28:45 bonnland Exp $
3 *
4 * Driver for the Gravis Grip Multiport, a gamepad "hub" that
5 * connects up to four 9-pin digital gamepads/joysticks.
6 * Driver tested on SMP and UP kernel versions 2.4.18-4 and 2.4.18-5.
7 *
8 * Thanks to Chris Gassib for helpful advice.
9 *
10 * Copyright (c) 2002 Brian Bonnlander, Bill Soudan
11 * Copyright (c) 1998-2000 Vojtech Pavlik
12 */
13
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/init.h>
17#include <linux/slab.h>
18#include <linux/gameport.h>
19#include <linux/input.h>
20#include <linux/delay.h>
21#include <linux/proc_fs.h>
22
23#define DRIVER_DESC "Gravis Grip Multiport driver"
24
25MODULE_AUTHOR("Brian Bonnlander");
26MODULE_DESCRIPTION(DRIVER_DESC);
27MODULE_LICENSE("GPL");
28
29#ifdef GRIP_DEBUG
30#define dbg(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg)
31#else
32#define dbg(format, arg...) do {} while (0)
33#endif
34
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -050035#define GRIP_MAX_PORTS 4
Linus Torvalds1da177e2005-04-16 15:20:36 -070036/*
37 * Grip multiport state
38 */
39
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -050040struct grip_port {
41 struct input_dev *dev;
42 int mode;
43 int registered;
44
45 /* individual gamepad states */
46 int buttons;
47 int xaxes;
48 int yaxes;
49 int dirty; /* has the state been updated? */
50};
51
Linus Torvalds1da177e2005-04-16 15:20:36 -070052struct grip_mp {
53 struct gameport *gameport;
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -050054 struct grip_port *port[GRIP_MAX_PORTS];
55// struct input_dev *dev[4];
56// int mode[4];
57// int registered[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 int reads;
59 int bads;
60
61 /* individual gamepad states */
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -050062// int buttons[4];
63// int xaxes[4];
64// int yaxes[4];
65// int dirty[4]; /* has the state been updated? */
Linus Torvalds1da177e2005-04-16 15:20:36 -070066};
67
68/*
69 * Multiport packet interpretation
70 */
71
72#define PACKET_FULL 0x80000000 /* packet is full */
73#define PACKET_IO_FAST 0x40000000 /* 3 bits per gameport read */
74#define PACKET_IO_SLOW 0x20000000 /* 1 bit per gameport read */
75#define PACKET_MP_MORE 0x04000000 /* multiport wants to send more */
76#define PACKET_MP_DONE 0x02000000 /* multiport done sending */
77
78/*
79 * Packet status code interpretation
80 */
81
82#define IO_GOT_PACKET 0x0100 /* Got a packet */
83#define IO_MODE_FAST 0x0200 /* Used 3 data bits per gameport read */
84#define IO_SLOT_CHANGE 0x0800 /* Multiport physical slot status changed */
85#define IO_DONE 0x1000 /* Multiport is done sending packets */
86#define IO_RETRY 0x4000 /* Try again later to get packet */
87#define IO_RESET 0x8000 /* Force multiport to resend all packets */
88
89/*
90 * Gamepad configuration data. Other 9-pin digital joystick devices
91 * may work with the multiport, so this may not be an exhaustive list!
92 * Commodore 64 joystick remains untested.
93 */
94
95#define GRIP_INIT_DELAY 2000 /* 2 ms */
96
97#define GRIP_MODE_NONE 0
98#define GRIP_MODE_RESET 1
99#define GRIP_MODE_GP 2
100#define GRIP_MODE_C64 3
101
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500102static const int grip_btn_gp[] = { BTN_TR, BTN_TL, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, -1 };
103static const int grip_btn_c64[] = { BTN_JOYSTICK, -1 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500105static const int grip_abs_gp[] = { ABS_X, ABS_Y, -1 };
106static const int grip_abs_c64[] = { ABS_X, ABS_Y, -1 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500108static const int *grip_abs[] = { NULL, NULL, grip_abs_gp, grip_abs_c64 };
109static const int *grip_btn[] = { NULL, NULL, grip_btn_gp, grip_btn_c64 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500111static const char *grip_name[] = { NULL, NULL, "Gravis Grip Pad", "Commodore 64 Joystick" };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112
113static const int init_seq[] = {
114 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,
115 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,
116 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,
117 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1 };
118
119/* Maps multiport directional values to X,Y axis values (each axis encoded in 3 bits) */
120
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500121static const int axis_map[] = { 5, 9, 1, 5, 6, 10, 2, 6, 4, 8, 0, 4, 5, 9, 1, 5 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500123static int register_slot(int i, struct grip_mp *grip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
125/*
126 * Returns whether an odd or even number of bits are on in pkt.
127 */
128
129static int bit_parity(u32 pkt)
130{
131 int x = pkt ^ (pkt >> 16);
132 x ^= x >> 8;
133 x ^= x >> 4;
134 x ^= x >> 2;
135 x ^= x >> 1;
136 return x & 1;
137}
138
139/*
140 * Poll gameport; return true if all bits set in 'onbits' are on and
141 * all bits set in 'offbits' are off.
142 */
143
144static inline int poll_until(u8 onbits, u8 offbits, int u_sec, struct gameport* gp, u8 *data)
145{
146 int i, nloops;
147
148 nloops = gameport_time(gp, u_sec);
149 for (i = 0; i < nloops; i++) {
150 *data = gameport_read(gp);
151 if ((*data & onbits) == onbits &&
152 (~(*data) & offbits) == offbits)
153 return 1;
154 }
155 dbg("gameport timed out after %d microseconds.\n", u_sec);
156 return 0;
157}
158
159/*
160 * Gets a 28-bit packet from the multiport.
161 *
162 * After getting a packet successfully, commands encoded by sendcode may
163 * be sent to the multiport.
164 *
165 * The multiport clock value is reflected in gameport bit B4.
166 *
167 * Returns a packet status code indicating whether packet is valid, the transfer
168 * mode, and any error conditions.
169 *
170 * sendflags: current I/O status
171 * sendcode: data to send to the multiport if sendflags is nonzero
172 */
173
174static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet)
175{
176 u8 raw_data; /* raw data from gameport */
177 u8 data_mask; /* packet data bits from raw_data */
178 u32 pkt; /* packet temporary storage */
179 int bits_per_read; /* num packet bits per gameport read */
180 int portvals = 0; /* used for port value sanity check */
181 int i;
182
183 /* Gameport bits B0, B4, B5 should first be off, then B4 should come on. */
184
185 *packet = 0;
186 raw_data = gameport_read(gameport);
187 if (raw_data & 1)
Dmitry Torokhovab0c3442005-05-29 02:28:55 -0500188 return IO_RETRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
190 for (i = 0; i < 64; i++) {
191 raw_data = gameport_read(gameport);
192 portvals |= 1 << ((raw_data >> 4) & 3); /* Demux B4, B5 */
193 }
194
195 if (portvals == 1) { /* B4, B5 off */
196 raw_data = gameport_read(gameport);
197 portvals = raw_data & 0xf0;
198
199 if (raw_data & 0x31)
200 return IO_RESET;
201 gameport_trigger(gameport);
202
203 if (!poll_until(0x10, 0, 308, gameport, &raw_data))
204 return IO_RESET;
205 } else
206 return IO_RETRY;
207
208 /* Determine packet transfer mode and prepare for packet construction. */
209
210 if (raw_data & 0x20) { /* 3 data bits/read */
211 portvals |= raw_data >> 4; /* Compare B4-B7 before & after trigger */
212
213 if (portvals != 0xb)
214 return 0;
215 data_mask = 7;
216 bits_per_read = 3;
217 pkt = (PACKET_FULL | PACKET_IO_FAST) >> 28;
218 } else { /* 1 data bit/read */
219 data_mask = 1;
220 bits_per_read = 1;
221 pkt = (PACKET_FULL | PACKET_IO_SLOW) >> 28;
222 }
223
224 /* Construct a packet. Final data bits must be zero. */
225
226 while (1) {
227 if (!poll_until(0, 0x10, 77, gameport, &raw_data))
228 return IO_RESET;
229 raw_data = (raw_data >> 5) & data_mask;
230
231 if (pkt & PACKET_FULL)
232 break;
233 pkt = (pkt << bits_per_read) | raw_data;
234
235 if (!poll_until(0x10, 0, 77, gameport, &raw_data))
236 return IO_RESET;
237 }
238
239 if (raw_data)
240 return IO_RESET;
241
242 /* If 3 bits/read used, drop from 30 bits to 28. */
243
244 if (bits_per_read == 3) {
245 pkt = (pkt & 0xffff0000) | ((pkt << 1) & 0xffff);
246 pkt = (pkt >> 2) | 0xf0000000;
247 }
248
249 if (bit_parity(pkt) == 1)
250 return IO_RESET;
251
252 /* Acknowledge packet receipt */
253
254 if (!poll_until(0x30, 0, 77, gameport, &raw_data))
255 return IO_RESET;
256
257 raw_data = gameport_read(gameport);
258
259 if (raw_data & 1)
260 return IO_RESET;
261
262 gameport_trigger(gameport);
263
264 if (!poll_until(0, 0x20, 77, gameport, &raw_data))
265 return IO_RESET;
266
267 /* Return if we just wanted the packet or multiport wants to send more */
268
269 *packet = pkt;
270 if ((sendflags == 0) || ((sendflags & IO_RETRY) && !(pkt & PACKET_MP_DONE)))
271 return IO_GOT_PACKET;
272
273 if (pkt & PACKET_MP_MORE)
274 return IO_GOT_PACKET | IO_RETRY;
275
276 /* Multiport is done sending packets and is ready to receive data */
277
278 if (!poll_until(0x20, 0, 77, gameport, &raw_data))
279 return IO_GOT_PACKET | IO_RESET;
280
281 raw_data = gameport_read(gameport);
282 if (raw_data & 1)
283 return IO_GOT_PACKET | IO_RESET;
284
285 /* Trigger gameport based on bits in sendcode */
286
287 gameport_trigger(gameport);
288 do {
289 if (!poll_until(0x20, 0x10, 116, gameport, &raw_data))
290 return IO_GOT_PACKET | IO_RESET;
291
292 if (!poll_until(0x30, 0, 193, gameport, &raw_data))
293 return IO_GOT_PACKET | IO_RESET;
294
295 if (raw_data & 1)
296 return IO_GOT_PACKET | IO_RESET;
297
298 if (sendcode & 1)
299 gameport_trigger(gameport);
300
301 sendcode >>= 1;
302 } while (sendcode);
303
304 return IO_GOT_PACKET | IO_MODE_FAST;
305}
306
307/*
308 * Disables and restores interrupts for mp_io(), which does the actual I/O.
309 */
310
311static int multiport_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet)
312{
313 int status;
314 unsigned long flags;
315
316 local_irq_save(flags);
317 status = mp_io(gameport, sendflags, sendcode, packet);
318 local_irq_restore(flags);
319
320 return status;
321}
322
323/*
324 * Puts multiport into digital mode. Multiport LED turns green.
325 *
326 * Returns true if a valid digital packet was received, false otherwise.
327 */
328
329static int dig_mode_start(struct gameport *gameport, u32 *packet)
330{
331 int i, seq_len = sizeof(init_seq)/sizeof(int);
332 int flags, tries = 0, bads = 0;
333
334 for (i = 0; i < seq_len; i++) { /* Send magic sequence */
335 if (init_seq[i])
336 gameport_trigger(gameport);
337 udelay(GRIP_INIT_DELAY);
338 }
339
340 for (i = 0; i < 16; i++) /* Wait for multiport to settle */
341 udelay(GRIP_INIT_DELAY);
342
343 while (tries < 64 && bads < 8) { /* Reset multiport and try getting a packet */
344
345 flags = multiport_io(gameport, IO_RESET, 0x27, packet);
346
347 if (flags & IO_MODE_FAST)
348 return 1;
349
350 if (flags & IO_RETRY)
351 tries++;
352 else
353 bads++;
354 }
355 return 0;
356}
357
358/*
359 * Packet structure: B0-B15 => gamepad state
360 * B16-B20 => gamepad device type
361 * B21-B24 => multiport slot index (1-4)
362 *
363 * Known device types: 0x1f (grip pad), 0x0 (no device). Others may exist.
364 *
365 * Returns the packet status.
366 */
367
368static int get_and_decode_packet(struct grip_mp *grip, int flags)
369{
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500370 struct grip_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 u32 packet;
372 int joytype = 0;
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500373 int slot;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374
375 /* Get a packet and check for validity */
376
377 flags &= IO_RESET | IO_RETRY;
378 flags = multiport_io(grip->gameport, flags, 0, &packet);
379 grip->reads++;
380
381 if (packet & PACKET_MP_DONE)
382 flags |= IO_DONE;
383
384 if (flags && !(flags & IO_GOT_PACKET)) {
385 grip->bads++;
386 return flags;
387 }
388
389 /* Ignore non-gamepad packets, e.g. multiport hardware version */
390
391 slot = ((packet >> 21) & 0xf) - 1;
392 if ((slot < 0) || (slot > 3))
393 return flags;
394
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500395 port = grip->port[slot];
396
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 /*
398 * Handle "reset" packets, which occur at startup, and when gamepads
399 * are removed or plugged in. May contain configuration of a new gamepad.
400 */
401
402 joytype = (packet >> 16) & 0x1f;
403 if (!joytype) {
404
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500405 if (port->registered) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 printk(KERN_INFO "grip_mp: removing %s, slot %d\n",
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500407 grip_name[port->mode], slot);
408 input_unregister_device(port->dev);
409 port->registered = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 }
411 dbg("Reset: grip multiport slot %d\n", slot);
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500412 port->mode = GRIP_MODE_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 flags |= IO_SLOT_CHANGE;
414 return flags;
415 }
416
417 /* Interpret a grip pad packet */
418
419 if (joytype == 0x1f) {
420
421 int dir = (packet >> 8) & 0xf; /* eight way directional value */
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500422 port->buttons = (~packet) & 0xff;
423 port->yaxes = ((axis_map[dir] >> 2) & 3) - 1;
424 port->xaxes = (axis_map[dir] & 3) - 1;
425 port->dirty = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500427 if (port->mode == GRIP_MODE_RESET)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 flags |= IO_SLOT_CHANGE;
429
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500430 port->mode = GRIP_MODE_GP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500432 if (!port->registered) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 dbg("New Grip pad in multiport slot %d.\n", slot);
434 register_slot(slot, grip);
435 }
436 return flags;
437 }
438
439 /* Handle non-grip device codes. For now, just print diagnostics. */
440
441 {
442 static int strange_code = 0;
443 if (strange_code != joytype) {
444 printk(KERN_INFO "Possible non-grip pad/joystick detected.\n");
445 printk(KERN_INFO "Got joy type 0x%x and packet 0x%x.\n", joytype, packet);
446 strange_code = joytype;
447 }
448 }
449 return flags;
450}
451
452/*
453 * Returns true if all multiport slot states appear valid.
454 */
455
456static int slots_valid(struct grip_mp *grip)
457{
458 int flags, slot, invalid = 0, active = 0;
459
460 flags = get_and_decode_packet(grip, 0);
461 if (!(flags & IO_GOT_PACKET))
462 return 0;
463
464 for (slot = 0; slot < 4; slot++) {
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500465 if (grip->port[slot]->mode == GRIP_MODE_RESET)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 invalid = 1;
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500467 if (grip->port[slot]->mode != GRIP_MODE_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 active = 1;
469 }
470
471 /* Return true if no active slot but multiport sent all its data */
472 if (!active)
473 return (flags & IO_DONE) ? 1 : 0;
474
475 /* Return false if invalid device code received */
476 return invalid ? 0 : 1;
477}
478
479/*
480 * Returns whether the multiport was placed into digital mode and
481 * able to communicate its state successfully.
482 */
483
484static int multiport_init(struct grip_mp *grip)
485{
486 int dig_mode, initialized = 0, tries = 0;
487 u32 packet;
488
489 dig_mode = dig_mode_start(grip->gameport, &packet);
490 while (!dig_mode && tries < 4) {
491 dig_mode = dig_mode_start(grip->gameport, &packet);
492 tries++;
493 }
494
495 if (dig_mode)
496 dbg("multiport_init(): digital mode activated.\n");
497 else {
498 dbg("multiport_init(): unable to activate digital mode.\n");
499 return 0;
500 }
501
502 /* Get packets, store multiport state, and check state's validity */
503 for (tries = 0; tries < 4096; tries++) {
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500504 if (slots_valid(grip)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 initialized = 1;
506 break;
507 }
508 }
509 dbg("multiport_init(): initialized == %d\n", initialized);
510 return initialized;
511}
512
513/*
514 * Reports joystick state to the linux input layer.
515 */
516
517static void report_slot(struct grip_mp *grip, int slot)
518{
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500519 struct grip_port *port = grip->port[slot];
520 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
522 /* Store button states with linux input driver */
523
524 for (i = 0; i < 8; i++)
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500525 input_report_key(port->dev, grip_btn_gp[i], (port->buttons >> i) & 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
527 /* Store axis states with linux driver */
528
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500529 input_report_abs(port->dev, ABS_X, port->xaxes);
530 input_report_abs(port->dev, ABS_Y, port->yaxes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
532 /* Tell the receiver of the events to process them */
533
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500534 input_sync(port->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500536 port->dirty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537}
538
539/*
540 * Get the multiport state.
541 */
542
543static void grip_poll(struct gameport *gameport)
544{
545 struct grip_mp *grip = gameport_get_drvdata(gameport);
546 int i, npkts, flags;
547
548 for (npkts = 0; npkts < 4; npkts++) {
549 flags = IO_RETRY;
550 for (i = 0; i < 32; i++) {
551 flags = get_and_decode_packet(grip, flags);
552 if ((flags & IO_GOT_PACKET) || !(flags & IO_RETRY))
553 break;
554 }
555 if (flags & IO_DONE)
556 break;
557 }
558
559 for (i = 0; i < 4; i++)
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500560 if (grip->port[i]->dirty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 report_slot(grip, i);
562}
563
564/*
565 * Called when a joystick device file is opened
566 */
567
568static int grip_open(struct input_dev *dev)
569{
570 struct grip_mp *grip = dev->private;
571
572 gameport_start_polling(grip->gameport);
573 return 0;
574}
575
576/*
577 * Called when a joystick device file is closed
578 */
579
580static void grip_close(struct input_dev *dev)
581{
582 struct grip_mp *grip = dev->private;
583
584 gameport_start_polling(grip->gameport);
585}
586
587/*
588 * Tell the linux input layer about a newly plugged-in gamepad.
589 */
590
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500591static int register_slot(int slot, struct grip_mp *grip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592{
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500593 struct grip_port *port = grip->port[slot];
594 struct input_dev *input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 int j, t;
596
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500597 port->dev = input_dev = input_allocate_device();
598 if (!input_dev)
599 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500601 input_dev->name = grip_name[port->mode];
602 input_dev->id.bustype = BUS_GAMEPORT;
603 input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS;
604 input_dev->id.product = 0x0100 + port->mode;
605 input_dev->id.version = 0x0100;
606 input_dev->cdev.dev = &grip->gameport->dev;
607 input_dev->private = grip;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500609 input_dev->open = grip_open;
610 input_dev->close = grip_close;
611
612 input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
613
614 for (j = 0; (t = grip_abs[port->mode][j]) >= 0; j++)
615 input_set_abs_params(input_dev, t, -1, 1, 0, 0);
616
617 for (j = 0; (t = grip_btn[port->mode][j]) >= 0; j++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 if (t > 0)
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500619 set_bit(t, input_dev->keybit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500621 input_register_device(port->dev);
622 port->registered = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500624 if (port->dirty) /* report initial state, if any */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 report_slot(grip, slot);
626
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500627 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628}
629
630static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
631{
632 struct grip_mp *grip;
633 int err;
634
Pekka Enberga97e1482005-09-06 15:18:33 -0700635 if (!(grip = kzalloc(sizeof(struct grip_mp), GFP_KERNEL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 return -ENOMEM;
637
638 grip->gameport = gameport;
639
640 gameport_set_drvdata(gameport, grip);
641
642 err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
643 if (err)
644 goto fail1;
645
646 gameport_set_poll_handler(gameport, grip_poll);
647 gameport_set_poll_interval(gameport, 20);
648
649 if (!multiport_init(grip)) {
650 err = -ENODEV;
651 goto fail2;
652 }
653
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500654 if (!grip->port[0]->mode && !grip->port[1]->mode && !grip->port[2]->mode && !grip->port[3]->mode) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 /* nothing plugged in */
656 err = -ENODEV;
657 goto fail2;
658 }
659
660 return 0;
661
662fail2: gameport_close(gameport);
663fail1: gameport_set_drvdata(gameport, NULL);
664 kfree(grip);
665 return err;
666}
667
668static void grip_disconnect(struct gameport *gameport)
669{
670 struct grip_mp *grip = gameport_get_drvdata(gameport);
671 int i;
672
673 for (i = 0; i < 4; i++)
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500674 if (grip->port[i]->registered)
675 input_unregister_device(grip->port[i]->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 gameport_close(gameport);
677 gameport_set_drvdata(gameport, NULL);
678 kfree(grip);
679}
680
681static struct gameport_driver grip_drv = {
682 .driver = {
683 .name = "grip_mp",
684 },
685 .description = DRIVER_DESC,
686 .connect = grip_connect,
687 .disconnect = grip_disconnect,
688};
689
690static int __init grip_init(void)
691{
692 gameport_register_driver(&grip_drv);
693 return 0;
694}
695
696static void __exit grip_exit(void)
697{
698 gameport_unregister_driver(&grip_drv);
699}
700
701module_init(grip_init);
702module_exit(grip_exit);