blob: 51a912222e85e6b93e4a6f8e4fc35b245db14341 [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>
Tim Schmielau4e57b682005-10-30 15:03:48 -080022#include <linux/jiffies.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023
24#define DRIVER_DESC "Gravis Grip Multiport driver"
25
26MODULE_AUTHOR("Brian Bonnlander");
27MODULE_DESCRIPTION(DRIVER_DESC);
28MODULE_LICENSE("GPL");
29
30#ifdef GRIP_DEBUG
31#define dbg(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg)
32#else
33#define dbg(format, arg...) do {} while (0)
34#endif
35
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -050036#define GRIP_MAX_PORTS 4
Linus Torvalds1da177e2005-04-16 15:20:36 -070037/*
38 * Grip multiport state
39 */
40
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -050041struct grip_port {
42 struct input_dev *dev;
43 int mode;
44 int registered;
45
46 /* individual gamepad states */
47 int buttons;
48 int xaxes;
49 int yaxes;
50 int dirty; /* has the state been updated? */
51};
52
Linus Torvalds1da177e2005-04-16 15:20:36 -070053struct grip_mp {
54 struct gameport *gameport;
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -050055 struct grip_port *port[GRIP_MAX_PORTS];
56// struct input_dev *dev[4];
57// int mode[4];
58// int registered[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 int reads;
60 int bads;
61
62 /* individual gamepad states */
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -050063// int buttons[4];
64// int xaxes[4];
65// int yaxes[4];
66// int dirty[4]; /* has the state been updated? */
Linus Torvalds1da177e2005-04-16 15:20:36 -070067};
68
69/*
70 * Multiport packet interpretation
71 */
72
73#define PACKET_FULL 0x80000000 /* packet is full */
74#define PACKET_IO_FAST 0x40000000 /* 3 bits per gameport read */
75#define PACKET_IO_SLOW 0x20000000 /* 1 bit per gameport read */
76#define PACKET_MP_MORE 0x04000000 /* multiport wants to send more */
77#define PACKET_MP_DONE 0x02000000 /* multiport done sending */
78
79/*
80 * Packet status code interpretation
81 */
82
83#define IO_GOT_PACKET 0x0100 /* Got a packet */
84#define IO_MODE_FAST 0x0200 /* Used 3 data bits per gameport read */
85#define IO_SLOT_CHANGE 0x0800 /* Multiport physical slot status changed */
86#define IO_DONE 0x1000 /* Multiport is done sending packets */
87#define IO_RETRY 0x4000 /* Try again later to get packet */
88#define IO_RESET 0x8000 /* Force multiport to resend all packets */
89
90/*
91 * Gamepad configuration data. Other 9-pin digital joystick devices
92 * may work with the multiport, so this may not be an exhaustive list!
93 * Commodore 64 joystick remains untested.
94 */
95
96#define GRIP_INIT_DELAY 2000 /* 2 ms */
97
98#define GRIP_MODE_NONE 0
99#define GRIP_MODE_RESET 1
100#define GRIP_MODE_GP 2
101#define GRIP_MODE_C64 3
102
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500103static const int grip_btn_gp[] = { BTN_TR, BTN_TL, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, -1 };
104static const int grip_btn_c64[] = { BTN_JOYSTICK, -1 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500106static const int grip_abs_gp[] = { ABS_X, ABS_Y, -1 };
107static const int grip_abs_c64[] = { ABS_X, ABS_Y, -1 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500109static const int *grip_abs[] = { NULL, NULL, grip_abs_gp, grip_abs_c64 };
110static const int *grip_btn[] = { NULL, NULL, grip_btn_gp, grip_btn_c64 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500112static const char *grip_name[] = { NULL, NULL, "Gravis Grip Pad", "Commodore 64 Joystick" };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113
114static const int init_seq[] = {
115 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,
116 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,
117 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,
118 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1 };
119
120/* Maps multiport directional values to X,Y axis values (each axis encoded in 3 bits) */
121
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500122static 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 -0700123
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500124static int register_slot(int i, struct grip_mp *grip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
126/*
127 * Returns whether an odd or even number of bits are on in pkt.
128 */
129
130static int bit_parity(u32 pkt)
131{
132 int x = pkt ^ (pkt >> 16);
133 x ^= x >> 8;
134 x ^= x >> 4;
135 x ^= x >> 2;
136 x ^= x >> 1;
137 return x & 1;
138}
139
140/*
141 * Poll gameport; return true if all bits set in 'onbits' are on and
142 * all bits set in 'offbits' are off.
143 */
144
145static inline int poll_until(u8 onbits, u8 offbits, int u_sec, struct gameport* gp, u8 *data)
146{
147 int i, nloops;
148
149 nloops = gameport_time(gp, u_sec);
150 for (i = 0; i < nloops; i++) {
151 *data = gameport_read(gp);
152 if ((*data & onbits) == onbits &&
153 (~(*data) & offbits) == offbits)
154 return 1;
155 }
156 dbg("gameport timed out after %d microseconds.\n", u_sec);
157 return 0;
158}
159
160/*
161 * Gets a 28-bit packet from the multiport.
162 *
163 * After getting a packet successfully, commands encoded by sendcode may
164 * be sent to the multiport.
165 *
166 * The multiport clock value is reflected in gameport bit B4.
167 *
168 * Returns a packet status code indicating whether packet is valid, the transfer
169 * mode, and any error conditions.
170 *
171 * sendflags: current I/O status
172 * sendcode: data to send to the multiport if sendflags is nonzero
173 */
174
175static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet)
176{
177 u8 raw_data; /* raw data from gameport */
178 u8 data_mask; /* packet data bits from raw_data */
179 u32 pkt; /* packet temporary storage */
180 int bits_per_read; /* num packet bits per gameport read */
181 int portvals = 0; /* used for port value sanity check */
182 int i;
183
184 /* Gameport bits B0, B4, B5 should first be off, then B4 should come on. */
185
186 *packet = 0;
187 raw_data = gameport_read(gameport);
188 if (raw_data & 1)
Dmitry Torokhovab0c3442005-05-29 02:28:55 -0500189 return IO_RETRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190
191 for (i = 0; i < 64; i++) {
192 raw_data = gameport_read(gameport);
193 portvals |= 1 << ((raw_data >> 4) & 3); /* Demux B4, B5 */
194 }
195
196 if (portvals == 1) { /* B4, B5 off */
197 raw_data = gameport_read(gameport);
198 portvals = raw_data & 0xf0;
199
200 if (raw_data & 0x31)
201 return IO_RESET;
202 gameport_trigger(gameport);
203
204 if (!poll_until(0x10, 0, 308, gameport, &raw_data))
205 return IO_RESET;
206 } else
207 return IO_RETRY;
208
209 /* Determine packet transfer mode and prepare for packet construction. */
210
211 if (raw_data & 0x20) { /* 3 data bits/read */
212 portvals |= raw_data >> 4; /* Compare B4-B7 before & after trigger */
213
214 if (portvals != 0xb)
215 return 0;
216 data_mask = 7;
217 bits_per_read = 3;
218 pkt = (PACKET_FULL | PACKET_IO_FAST) >> 28;
219 } else { /* 1 data bit/read */
220 data_mask = 1;
221 bits_per_read = 1;
222 pkt = (PACKET_FULL | PACKET_IO_SLOW) >> 28;
223 }
224
225 /* Construct a packet. Final data bits must be zero. */
226
227 while (1) {
228 if (!poll_until(0, 0x10, 77, gameport, &raw_data))
229 return IO_RESET;
230 raw_data = (raw_data >> 5) & data_mask;
231
232 if (pkt & PACKET_FULL)
233 break;
234 pkt = (pkt << bits_per_read) | raw_data;
235
236 if (!poll_until(0x10, 0, 77, gameport, &raw_data))
237 return IO_RESET;
238 }
239
240 if (raw_data)
241 return IO_RESET;
242
243 /* If 3 bits/read used, drop from 30 bits to 28. */
244
245 if (bits_per_read == 3) {
246 pkt = (pkt & 0xffff0000) | ((pkt << 1) & 0xffff);
247 pkt = (pkt >> 2) | 0xf0000000;
248 }
249
250 if (bit_parity(pkt) == 1)
251 return IO_RESET;
252
253 /* Acknowledge packet receipt */
254
255 if (!poll_until(0x30, 0, 77, gameport, &raw_data))
256 return IO_RESET;
257
258 raw_data = gameport_read(gameport);
259
260 if (raw_data & 1)
261 return IO_RESET;
262
263 gameport_trigger(gameport);
264
265 if (!poll_until(0, 0x20, 77, gameport, &raw_data))
266 return IO_RESET;
267
268 /* Return if we just wanted the packet or multiport wants to send more */
269
270 *packet = pkt;
271 if ((sendflags == 0) || ((sendflags & IO_RETRY) && !(pkt & PACKET_MP_DONE)))
272 return IO_GOT_PACKET;
273
274 if (pkt & PACKET_MP_MORE)
275 return IO_GOT_PACKET | IO_RETRY;
276
277 /* Multiport is done sending packets and is ready to receive data */
278
279 if (!poll_until(0x20, 0, 77, gameport, &raw_data))
280 return IO_GOT_PACKET | IO_RESET;
281
282 raw_data = gameport_read(gameport);
283 if (raw_data & 1)
284 return IO_GOT_PACKET | IO_RESET;
285
286 /* Trigger gameport based on bits in sendcode */
287
288 gameport_trigger(gameport);
289 do {
290 if (!poll_until(0x20, 0x10, 116, gameport, &raw_data))
291 return IO_GOT_PACKET | IO_RESET;
292
293 if (!poll_until(0x30, 0, 193, gameport, &raw_data))
294 return IO_GOT_PACKET | IO_RESET;
295
296 if (raw_data & 1)
297 return IO_GOT_PACKET | IO_RESET;
298
299 if (sendcode & 1)
300 gameport_trigger(gameport);
301
302 sendcode >>= 1;
303 } while (sendcode);
304
305 return IO_GOT_PACKET | IO_MODE_FAST;
306}
307
308/*
309 * Disables and restores interrupts for mp_io(), which does the actual I/O.
310 */
311
312static int multiport_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet)
313{
314 int status;
315 unsigned long flags;
316
317 local_irq_save(flags);
318 status = mp_io(gameport, sendflags, sendcode, packet);
319 local_irq_restore(flags);
320
321 return status;
322}
323
324/*
325 * Puts multiport into digital mode. Multiport LED turns green.
326 *
327 * Returns true if a valid digital packet was received, false otherwise.
328 */
329
330static int dig_mode_start(struct gameport *gameport, u32 *packet)
331{
332 int i, seq_len = sizeof(init_seq)/sizeof(int);
333 int flags, tries = 0, bads = 0;
334
335 for (i = 0; i < seq_len; i++) { /* Send magic sequence */
336 if (init_seq[i])
337 gameport_trigger(gameport);
338 udelay(GRIP_INIT_DELAY);
339 }
340
341 for (i = 0; i < 16; i++) /* Wait for multiport to settle */
342 udelay(GRIP_INIT_DELAY);
343
344 while (tries < 64 && bads < 8) { /* Reset multiport and try getting a packet */
345
346 flags = multiport_io(gameport, IO_RESET, 0x27, packet);
347
348 if (flags & IO_MODE_FAST)
349 return 1;
350
351 if (flags & IO_RETRY)
352 tries++;
353 else
354 bads++;
355 }
356 return 0;
357}
358
359/*
360 * Packet structure: B0-B15 => gamepad state
361 * B16-B20 => gamepad device type
362 * B21-B24 => multiport slot index (1-4)
363 *
364 * Known device types: 0x1f (grip pad), 0x0 (no device). Others may exist.
365 *
366 * Returns the packet status.
367 */
368
369static int get_and_decode_packet(struct grip_mp *grip, int flags)
370{
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500371 struct grip_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 u32 packet;
373 int joytype = 0;
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500374 int slot;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
376 /* Get a packet and check for validity */
377
378 flags &= IO_RESET | IO_RETRY;
379 flags = multiport_io(grip->gameport, flags, 0, &packet);
380 grip->reads++;
381
382 if (packet & PACKET_MP_DONE)
383 flags |= IO_DONE;
384
385 if (flags && !(flags & IO_GOT_PACKET)) {
386 grip->bads++;
387 return flags;
388 }
389
390 /* Ignore non-gamepad packets, e.g. multiport hardware version */
391
392 slot = ((packet >> 21) & 0xf) - 1;
393 if ((slot < 0) || (slot > 3))
394 return flags;
395
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500396 port = grip->port[slot];
397
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 /*
399 * Handle "reset" packets, which occur at startup, and when gamepads
400 * are removed or plugged in. May contain configuration of a new gamepad.
401 */
402
403 joytype = (packet >> 16) & 0x1f;
404 if (!joytype) {
405
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500406 if (port->registered) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 printk(KERN_INFO "grip_mp: removing %s, slot %d\n",
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500408 grip_name[port->mode], slot);
409 input_unregister_device(port->dev);
410 port->registered = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 }
412 dbg("Reset: grip multiport slot %d\n", slot);
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500413 port->mode = GRIP_MODE_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 flags |= IO_SLOT_CHANGE;
415 return flags;
416 }
417
418 /* Interpret a grip pad packet */
419
420 if (joytype == 0x1f) {
421
422 int dir = (packet >> 8) & 0xf; /* eight way directional value */
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500423 port->buttons = (~packet) & 0xff;
424 port->yaxes = ((axis_map[dir] >> 2) & 3) - 1;
425 port->xaxes = (axis_map[dir] & 3) - 1;
426 port->dirty = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500428 if (port->mode == GRIP_MODE_RESET)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 flags |= IO_SLOT_CHANGE;
430
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500431 port->mode = GRIP_MODE_GP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500433 if (!port->registered) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 dbg("New Grip pad in multiport slot %d.\n", slot);
435 register_slot(slot, grip);
436 }
437 return flags;
438 }
439
440 /* Handle non-grip device codes. For now, just print diagnostics. */
441
442 {
443 static int strange_code = 0;
444 if (strange_code != joytype) {
445 printk(KERN_INFO "Possible non-grip pad/joystick detected.\n");
446 printk(KERN_INFO "Got joy type 0x%x and packet 0x%x.\n", joytype, packet);
447 strange_code = joytype;
448 }
449 }
450 return flags;
451}
452
453/*
454 * Returns true if all multiport slot states appear valid.
455 */
456
457static int slots_valid(struct grip_mp *grip)
458{
459 int flags, slot, invalid = 0, active = 0;
460
461 flags = get_and_decode_packet(grip, 0);
462 if (!(flags & IO_GOT_PACKET))
463 return 0;
464
465 for (slot = 0; slot < 4; slot++) {
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500466 if (grip->port[slot]->mode == GRIP_MODE_RESET)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 invalid = 1;
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500468 if (grip->port[slot]->mode != GRIP_MODE_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 active = 1;
470 }
471
472 /* Return true if no active slot but multiport sent all its data */
473 if (!active)
474 return (flags & IO_DONE) ? 1 : 0;
475
476 /* Return false if invalid device code received */
477 return invalid ? 0 : 1;
478}
479
480/*
481 * Returns whether the multiport was placed into digital mode and
482 * able to communicate its state successfully.
483 */
484
485static int multiport_init(struct grip_mp *grip)
486{
487 int dig_mode, initialized = 0, tries = 0;
488 u32 packet;
489
490 dig_mode = dig_mode_start(grip->gameport, &packet);
491 while (!dig_mode && tries < 4) {
492 dig_mode = dig_mode_start(grip->gameport, &packet);
493 tries++;
494 }
495
496 if (dig_mode)
497 dbg("multiport_init(): digital mode activated.\n");
498 else {
499 dbg("multiport_init(): unable to activate digital mode.\n");
500 return 0;
501 }
502
503 /* Get packets, store multiport state, and check state's validity */
504 for (tries = 0; tries < 4096; tries++) {
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500505 if (slots_valid(grip)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 initialized = 1;
507 break;
508 }
509 }
510 dbg("multiport_init(): initialized == %d\n", initialized);
511 return initialized;
512}
513
514/*
515 * Reports joystick state to the linux input layer.
516 */
517
518static void report_slot(struct grip_mp *grip, int slot)
519{
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500520 struct grip_port *port = grip->port[slot];
521 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522
523 /* Store button states with linux input driver */
524
525 for (i = 0; i < 8; i++)
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500526 input_report_key(port->dev, grip_btn_gp[i], (port->buttons >> i) & 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527
528 /* Store axis states with linux driver */
529
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500530 input_report_abs(port->dev, ABS_X, port->xaxes);
531 input_report_abs(port->dev, ABS_Y, port->yaxes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532
533 /* Tell the receiver of the events to process them */
534
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500535 input_sync(port->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500537 port->dirty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538}
539
540/*
541 * Get the multiport state.
542 */
543
544static void grip_poll(struct gameport *gameport)
545{
546 struct grip_mp *grip = gameport_get_drvdata(gameport);
547 int i, npkts, flags;
548
549 for (npkts = 0; npkts < 4; npkts++) {
550 flags = IO_RETRY;
551 for (i = 0; i < 32; i++) {
552 flags = get_and_decode_packet(grip, flags);
553 if ((flags & IO_GOT_PACKET) || !(flags & IO_RETRY))
554 break;
555 }
556 if (flags & IO_DONE)
557 break;
558 }
559
560 for (i = 0; i < 4; i++)
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500561 if (grip->port[i]->dirty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 report_slot(grip, i);
563}
564
565/*
566 * Called when a joystick device file is opened
567 */
568
569static int grip_open(struct input_dev *dev)
570{
571 struct grip_mp *grip = dev->private;
572
573 gameport_start_polling(grip->gameport);
574 return 0;
575}
576
577/*
578 * Called when a joystick device file is closed
579 */
580
581static void grip_close(struct input_dev *dev)
582{
583 struct grip_mp *grip = dev->private;
584
585 gameport_start_polling(grip->gameport);
586}
587
588/*
589 * Tell the linux input layer about a newly plugged-in gamepad.
590 */
591
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500592static int register_slot(int slot, struct grip_mp *grip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593{
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500594 struct grip_port *port = grip->port[slot];
595 struct input_dev *input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 int j, t;
597
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500598 port->dev = input_dev = input_allocate_device();
599 if (!input_dev)
600 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500602 input_dev->name = grip_name[port->mode];
603 input_dev->id.bustype = BUS_GAMEPORT;
604 input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS;
605 input_dev->id.product = 0x0100 + port->mode;
606 input_dev->id.version = 0x0100;
607 input_dev->cdev.dev = &grip->gameport->dev;
608 input_dev->private = grip;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500610 input_dev->open = grip_open;
611 input_dev->close = grip_close;
612
613 input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
614
615 for (j = 0; (t = grip_abs[port->mode][j]) >= 0; j++)
616 input_set_abs_params(input_dev, t, -1, 1, 0, 0);
617
618 for (j = 0; (t = grip_btn[port->mode][j]) >= 0; j++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 if (t > 0)
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500620 set_bit(t, input_dev->keybit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500622 input_register_device(port->dev);
623 port->registered = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500625 if (port->dirty) /* report initial state, if any */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 report_slot(grip, slot);
627
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500628 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629}
630
631static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
632{
633 struct grip_mp *grip;
634 int err;
635
Pekka Enberga97e1482005-09-06 15:18:33 -0700636 if (!(grip = kzalloc(sizeof(struct grip_mp), GFP_KERNEL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 return -ENOMEM;
638
639 grip->gameport = gameport;
640
641 gameport_set_drvdata(gameport, grip);
642
643 err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
644 if (err)
645 goto fail1;
646
647 gameport_set_poll_handler(gameport, grip_poll);
648 gameport_set_poll_interval(gameport, 20);
649
650 if (!multiport_init(grip)) {
651 err = -ENODEV;
652 goto fail2;
653 }
654
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500655 if (!grip->port[0]->mode && !grip->port[1]->mode && !grip->port[2]->mode && !grip->port[3]->mode) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 /* nothing plugged in */
657 err = -ENODEV;
658 goto fail2;
659 }
660
661 return 0;
662
663fail2: gameport_close(gameport);
664fail1: gameport_set_drvdata(gameport, NULL);
665 kfree(grip);
666 return err;
667}
668
669static void grip_disconnect(struct gameport *gameport)
670{
671 struct grip_mp *grip = gameport_get_drvdata(gameport);
672 int i;
673
674 for (i = 0; i < 4; i++)
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500675 if (grip->port[i]->registered)
676 input_unregister_device(grip->port[i]->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 gameport_close(gameport);
678 gameport_set_drvdata(gameport, NULL);
679 kfree(grip);
680}
681
682static struct gameport_driver grip_drv = {
683 .driver = {
684 .name = "grip_mp",
685 },
686 .description = DRIVER_DESC,
687 .connect = grip_connect,
688 .disconnect = grip_disconnect,
689};
690
691static int __init grip_init(void)
692{
693 gameport_register_driver(&grip_drv);
694 return 0;
695}
696
697static void __exit grip_exit(void)
698{
699 gameport_unregister_driver(&grip_drv);
700}
701
702module_init(grip_init);
703module_exit(grip_exit);