blob: c0f9c7b7eb4eb4a4d1c738f7fc4d81f295e81ed1 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * Driver for the Gravis Grip Multiport, a gamepad "hub" that
3 * connects up to four 9-pin digital gamepads/joysticks.
4 * Driver tested on SMP and UP kernel versions 2.4.18-4 and 2.4.18-5.
5 *
6 * Thanks to Chris Gassib for helpful advice.
7 *
8 * Copyright (c) 2002 Brian Bonnlander, Bill Soudan
9 * Copyright (c) 1998-2000 Vojtech Pavlik
10 */
11
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/slab.h>
16#include <linux/gameport.h>
17#include <linux/input.h>
18#include <linux/delay.h>
19#include <linux/proc_fs.h>
Tim Schmielau4e57b682005-10-30 15:03:48 -080020#include <linux/jiffies.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021
22#define DRIVER_DESC "Gravis Grip Multiport driver"
23
24MODULE_AUTHOR("Brian Bonnlander");
25MODULE_DESCRIPTION(DRIVER_DESC);
26MODULE_LICENSE("GPL");
27
28#ifdef GRIP_DEBUG
29#define dbg(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg)
30#else
31#define dbg(format, arg...) do {} while (0)
32#endif
33
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -050034#define GRIP_MAX_PORTS 4
Linus Torvalds1da177e2005-04-16 15:20:36 -070035/*
36 * Grip multiport state
37 */
38
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -050039struct grip_port {
40 struct input_dev *dev;
41 int mode;
42 int registered;
43
44 /* individual gamepad states */
45 int buttons;
46 int xaxes;
47 int yaxes;
48 int dirty; /* has the state been updated? */
49};
50
Linus Torvalds1da177e2005-04-16 15:20:36 -070051struct grip_mp {
52 struct gameport *gameport;
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -050053 struct grip_port *port[GRIP_MAX_PORTS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 int reads;
55 int bads;
Linus Torvalds1da177e2005-04-16 15:20:36 -070056};
57
58/*
59 * Multiport packet interpretation
60 */
61
62#define PACKET_FULL 0x80000000 /* packet is full */
63#define PACKET_IO_FAST 0x40000000 /* 3 bits per gameport read */
64#define PACKET_IO_SLOW 0x20000000 /* 1 bit per gameport read */
65#define PACKET_MP_MORE 0x04000000 /* multiport wants to send more */
66#define PACKET_MP_DONE 0x02000000 /* multiport done sending */
67
68/*
69 * Packet status code interpretation
70 */
71
72#define IO_GOT_PACKET 0x0100 /* Got a packet */
73#define IO_MODE_FAST 0x0200 /* Used 3 data bits per gameport read */
74#define IO_SLOT_CHANGE 0x0800 /* Multiport physical slot status changed */
75#define IO_DONE 0x1000 /* Multiport is done sending packets */
76#define IO_RETRY 0x4000 /* Try again later to get packet */
77#define IO_RESET 0x8000 /* Force multiport to resend all packets */
78
79/*
80 * Gamepad configuration data. Other 9-pin digital joystick devices
81 * may work with the multiport, so this may not be an exhaustive list!
82 * Commodore 64 joystick remains untested.
83 */
84
85#define GRIP_INIT_DELAY 2000 /* 2 ms */
86
87#define GRIP_MODE_NONE 0
88#define GRIP_MODE_RESET 1
89#define GRIP_MODE_GP 2
90#define GRIP_MODE_C64 3
91
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -050092static const int grip_btn_gp[] = { BTN_TR, BTN_TL, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, -1 };
93static const int grip_btn_c64[] = { BTN_JOYSTICK, -1 };
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -050095static const int grip_abs_gp[] = { ABS_X, ABS_Y, -1 };
96static const int grip_abs_c64[] = { ABS_X, ABS_Y, -1 };
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -050098static const int *grip_abs[] = { NULL, NULL, grip_abs_gp, grip_abs_c64 };
99static const int *grip_btn[] = { NULL, NULL, grip_btn_gp, grip_btn_c64 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500101static const char *grip_name[] = { NULL, NULL, "Gravis Grip Pad", "Commodore 64 Joystick" };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
103static const int init_seq[] = {
104 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,
105 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,
106 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,
107 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1 };
108
109/* Maps multiport directional values to X,Y axis values (each axis encoded in 3 bits) */
110
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500111static 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 -0700112
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500113static int register_slot(int i, struct grip_mp *grip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114
115/*
116 * Returns whether an odd or even number of bits are on in pkt.
117 */
118
119static int bit_parity(u32 pkt)
120{
121 int x = pkt ^ (pkt >> 16);
122 x ^= x >> 8;
123 x ^= x >> 4;
124 x ^= x >> 2;
125 x ^= x >> 1;
126 return x & 1;
127}
128
129/*
130 * Poll gameport; return true if all bits set in 'onbits' are on and
131 * all bits set in 'offbits' are off.
132 */
133
134static inline int poll_until(u8 onbits, u8 offbits, int u_sec, struct gameport* gp, u8 *data)
135{
136 int i, nloops;
137
138 nloops = gameport_time(gp, u_sec);
139 for (i = 0; i < nloops; i++) {
140 *data = gameport_read(gp);
141 if ((*data & onbits) == onbits &&
142 (~(*data) & offbits) == offbits)
143 return 1;
144 }
145 dbg("gameport timed out after %d microseconds.\n", u_sec);
146 return 0;
147}
148
149/*
150 * Gets a 28-bit packet from the multiport.
151 *
152 * After getting a packet successfully, commands encoded by sendcode may
153 * be sent to the multiport.
154 *
155 * The multiport clock value is reflected in gameport bit B4.
156 *
157 * Returns a packet status code indicating whether packet is valid, the transfer
158 * mode, and any error conditions.
159 *
160 * sendflags: current I/O status
161 * sendcode: data to send to the multiport if sendflags is nonzero
162 */
163
164static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet)
165{
166 u8 raw_data; /* raw data from gameport */
167 u8 data_mask; /* packet data bits from raw_data */
168 u32 pkt; /* packet temporary storage */
169 int bits_per_read; /* num packet bits per gameport read */
170 int portvals = 0; /* used for port value sanity check */
171 int i;
172
173 /* Gameport bits B0, B4, B5 should first be off, then B4 should come on. */
174
175 *packet = 0;
176 raw_data = gameport_read(gameport);
177 if (raw_data & 1)
Dmitry Torokhovab0c3442005-05-29 02:28:55 -0500178 return IO_RETRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
180 for (i = 0; i < 64; i++) {
181 raw_data = gameport_read(gameport);
182 portvals |= 1 << ((raw_data >> 4) & 3); /* Demux B4, B5 */
183 }
184
185 if (portvals == 1) { /* B4, B5 off */
186 raw_data = gameport_read(gameport);
187 portvals = raw_data & 0xf0;
188
189 if (raw_data & 0x31)
190 return IO_RESET;
191 gameport_trigger(gameport);
192
193 if (!poll_until(0x10, 0, 308, gameport, &raw_data))
194 return IO_RESET;
195 } else
196 return IO_RETRY;
197
198 /* Determine packet transfer mode and prepare for packet construction. */
199
200 if (raw_data & 0x20) { /* 3 data bits/read */
201 portvals |= raw_data >> 4; /* Compare B4-B7 before & after trigger */
202
203 if (portvals != 0xb)
204 return 0;
205 data_mask = 7;
206 bits_per_read = 3;
207 pkt = (PACKET_FULL | PACKET_IO_FAST) >> 28;
208 } else { /* 1 data bit/read */
209 data_mask = 1;
210 bits_per_read = 1;
211 pkt = (PACKET_FULL | PACKET_IO_SLOW) >> 28;
212 }
213
214 /* Construct a packet. Final data bits must be zero. */
215
216 while (1) {
217 if (!poll_until(0, 0x10, 77, gameport, &raw_data))
218 return IO_RESET;
219 raw_data = (raw_data >> 5) & data_mask;
220
221 if (pkt & PACKET_FULL)
222 break;
223 pkt = (pkt << bits_per_read) | raw_data;
224
225 if (!poll_until(0x10, 0, 77, gameport, &raw_data))
226 return IO_RESET;
227 }
228
229 if (raw_data)
230 return IO_RESET;
231
232 /* If 3 bits/read used, drop from 30 bits to 28. */
233
234 if (bits_per_read == 3) {
235 pkt = (pkt & 0xffff0000) | ((pkt << 1) & 0xffff);
236 pkt = (pkt >> 2) | 0xf0000000;
237 }
238
239 if (bit_parity(pkt) == 1)
240 return IO_RESET;
241
242 /* Acknowledge packet receipt */
243
244 if (!poll_until(0x30, 0, 77, gameport, &raw_data))
245 return IO_RESET;
246
247 raw_data = gameport_read(gameport);
248
249 if (raw_data & 1)
250 return IO_RESET;
251
252 gameport_trigger(gameport);
253
254 if (!poll_until(0, 0x20, 77, gameport, &raw_data))
255 return IO_RESET;
256
257 /* Return if we just wanted the packet or multiport wants to send more */
258
259 *packet = pkt;
260 if ((sendflags == 0) || ((sendflags & IO_RETRY) && !(pkt & PACKET_MP_DONE)))
261 return IO_GOT_PACKET;
262
263 if (pkt & PACKET_MP_MORE)
264 return IO_GOT_PACKET | IO_RETRY;
265
266 /* Multiport is done sending packets and is ready to receive data */
267
268 if (!poll_until(0x20, 0, 77, gameport, &raw_data))
269 return IO_GOT_PACKET | IO_RESET;
270
271 raw_data = gameport_read(gameport);
272 if (raw_data & 1)
273 return IO_GOT_PACKET | IO_RESET;
274
275 /* Trigger gameport based on bits in sendcode */
276
277 gameport_trigger(gameport);
278 do {
279 if (!poll_until(0x20, 0x10, 116, gameport, &raw_data))
280 return IO_GOT_PACKET | IO_RESET;
281
282 if (!poll_until(0x30, 0, 193, gameport, &raw_data))
283 return IO_GOT_PACKET | IO_RESET;
284
285 if (raw_data & 1)
286 return IO_GOT_PACKET | IO_RESET;
287
288 if (sendcode & 1)
289 gameport_trigger(gameport);
290
291 sendcode >>= 1;
292 } while (sendcode);
293
294 return IO_GOT_PACKET | IO_MODE_FAST;
295}
296
297/*
298 * Disables and restores interrupts for mp_io(), which does the actual I/O.
299 */
300
301static int multiport_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet)
302{
303 int status;
304 unsigned long flags;
305
306 local_irq_save(flags);
307 status = mp_io(gameport, sendflags, sendcode, packet);
308 local_irq_restore(flags);
309
310 return status;
311}
312
313/*
314 * Puts multiport into digital mode. Multiport LED turns green.
315 *
316 * Returns true if a valid digital packet was received, false otherwise.
317 */
318
319static int dig_mode_start(struct gameport *gameport, u32 *packet)
320{
Andi Drebes5ec1f7f2007-06-14 23:33:01 -0400321 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 int flags, tries = 0, bads = 0;
323
Andi Drebes5ec1f7f2007-06-14 23:33:01 -0400324 for (i = 0; i < ARRAY_SIZE(init_seq); i++) { /* Send magic sequence */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 if (init_seq[i])
326 gameport_trigger(gameport);
327 udelay(GRIP_INIT_DELAY);
328 }
329
330 for (i = 0; i < 16; i++) /* Wait for multiport to settle */
331 udelay(GRIP_INIT_DELAY);
332
333 while (tries < 64 && bads < 8) { /* Reset multiport and try getting a packet */
334
335 flags = multiport_io(gameport, IO_RESET, 0x27, packet);
336
337 if (flags & IO_MODE_FAST)
338 return 1;
339
340 if (flags & IO_RETRY)
341 tries++;
342 else
343 bads++;
344 }
345 return 0;
346}
347
348/*
349 * Packet structure: B0-B15 => gamepad state
350 * B16-B20 => gamepad device type
351 * B21-B24 => multiport slot index (1-4)
352 *
353 * Known device types: 0x1f (grip pad), 0x0 (no device). Others may exist.
354 *
355 * Returns the packet status.
356 */
357
358static int get_and_decode_packet(struct grip_mp *grip, int flags)
359{
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500360 struct grip_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 u32 packet;
362 int joytype = 0;
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500363 int slot;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
365 /* Get a packet and check for validity */
366
367 flags &= IO_RESET | IO_RETRY;
368 flags = multiport_io(grip->gameport, flags, 0, &packet);
369 grip->reads++;
370
371 if (packet & PACKET_MP_DONE)
372 flags |= IO_DONE;
373
374 if (flags && !(flags & IO_GOT_PACKET)) {
375 grip->bads++;
376 return flags;
377 }
378
379 /* Ignore non-gamepad packets, e.g. multiport hardware version */
380
381 slot = ((packet >> 21) & 0xf) - 1;
382 if ((slot < 0) || (slot > 3))
383 return flags;
384
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500385 port = grip->port[slot];
386
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 /*
388 * Handle "reset" packets, which occur at startup, and when gamepads
389 * are removed or plugged in. May contain configuration of a new gamepad.
390 */
391
392 joytype = (packet >> 16) & 0x1f;
393 if (!joytype) {
394
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500395 if (port->registered) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 printk(KERN_INFO "grip_mp: removing %s, slot %d\n",
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500397 grip_name[port->mode], slot);
398 input_unregister_device(port->dev);
399 port->registered = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 }
401 dbg("Reset: grip multiport slot %d\n", slot);
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500402 port->mode = GRIP_MODE_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 flags |= IO_SLOT_CHANGE;
404 return flags;
405 }
406
407 /* Interpret a grip pad packet */
408
409 if (joytype == 0x1f) {
410
411 int dir = (packet >> 8) & 0xf; /* eight way directional value */
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500412 port->buttons = (~packet) & 0xff;
413 port->yaxes = ((axis_map[dir] >> 2) & 3) - 1;
414 port->xaxes = (axis_map[dir] & 3) - 1;
415 port->dirty = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500417 if (port->mode == GRIP_MODE_RESET)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 flags |= IO_SLOT_CHANGE;
419
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500420 port->mode = GRIP_MODE_GP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500422 if (!port->registered) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 dbg("New Grip pad in multiport slot %d.\n", slot);
Dmitry Torokhov127278c2006-11-05 22:40:09 -0500424 if (register_slot(slot, grip)) {
425 port->mode = GRIP_MODE_RESET;
426 port->dirty = 0;
427 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 }
429 return flags;
430 }
431
432 /* Handle non-grip device codes. For now, just print diagnostics. */
433
434 {
435 static int strange_code = 0;
436 if (strange_code != joytype) {
437 printk(KERN_INFO "Possible non-grip pad/joystick detected.\n");
438 printk(KERN_INFO "Got joy type 0x%x and packet 0x%x.\n", joytype, packet);
439 strange_code = joytype;
440 }
441 }
442 return flags;
443}
444
445/*
446 * Returns true if all multiport slot states appear valid.
447 */
448
449static int slots_valid(struct grip_mp *grip)
450{
451 int flags, slot, invalid = 0, active = 0;
452
453 flags = get_and_decode_packet(grip, 0);
454 if (!(flags & IO_GOT_PACKET))
455 return 0;
456
457 for (slot = 0; slot < 4; slot++) {
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500458 if (grip->port[slot]->mode == GRIP_MODE_RESET)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 invalid = 1;
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500460 if (grip->port[slot]->mode != GRIP_MODE_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 active = 1;
462 }
463
464 /* Return true if no active slot but multiport sent all its data */
465 if (!active)
466 return (flags & IO_DONE) ? 1 : 0;
467
468 /* Return false if invalid device code received */
469 return invalid ? 0 : 1;
470}
471
472/*
473 * Returns whether the multiport was placed into digital mode and
474 * able to communicate its state successfully.
475 */
476
477static int multiport_init(struct grip_mp *grip)
478{
479 int dig_mode, initialized = 0, tries = 0;
480 u32 packet;
481
482 dig_mode = dig_mode_start(grip->gameport, &packet);
483 while (!dig_mode && tries < 4) {
484 dig_mode = dig_mode_start(grip->gameport, &packet);
485 tries++;
486 }
487
488 if (dig_mode)
489 dbg("multiport_init(): digital mode activated.\n");
490 else {
491 dbg("multiport_init(): unable to activate digital mode.\n");
492 return 0;
493 }
494
495 /* Get packets, store multiport state, and check state's validity */
496 for (tries = 0; tries < 4096; tries++) {
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500497 if (slots_valid(grip)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 initialized = 1;
499 break;
500 }
501 }
502 dbg("multiport_init(): initialized == %d\n", initialized);
503 return initialized;
504}
505
506/*
507 * Reports joystick state to the linux input layer.
508 */
509
510static void report_slot(struct grip_mp *grip, int slot)
511{
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500512 struct grip_port *port = grip->port[slot];
513 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
515 /* Store button states with linux input driver */
516
517 for (i = 0; i < 8; i++)
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500518 input_report_key(port->dev, grip_btn_gp[i], (port->buttons >> i) & 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
520 /* Store axis states with linux driver */
521
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500522 input_report_abs(port->dev, ABS_X, port->xaxes);
523 input_report_abs(port->dev, ABS_Y, port->yaxes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
525 /* Tell the receiver of the events to process them */
526
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500527 input_sync(port->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500529 port->dirty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530}
531
532/*
533 * Get the multiport state.
534 */
535
536static void grip_poll(struct gameport *gameport)
537{
538 struct grip_mp *grip = gameport_get_drvdata(gameport);
539 int i, npkts, flags;
540
541 for (npkts = 0; npkts < 4; npkts++) {
542 flags = IO_RETRY;
543 for (i = 0; i < 32; i++) {
544 flags = get_and_decode_packet(grip, flags);
545 if ((flags & IO_GOT_PACKET) || !(flags & IO_RETRY))
546 break;
547 }
548 if (flags & IO_DONE)
549 break;
550 }
551
552 for (i = 0; i < 4; i++)
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500553 if (grip->port[i]->dirty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 report_slot(grip, i);
555}
556
557/*
558 * Called when a joystick device file is opened
559 */
560
561static int grip_open(struct input_dev *dev)
562{
Dmitry Torokhov8715c1c2007-04-12 01:34:14 -0400563 struct grip_mp *grip = input_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564
565 gameport_start_polling(grip->gameport);
566 return 0;
567}
568
569/*
570 * Called when a joystick device file is closed
571 */
572
573static void grip_close(struct input_dev *dev)
574{
Dmitry Torokhov8715c1c2007-04-12 01:34:14 -0400575 struct grip_mp *grip = input_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
Dmitry Torokhov8715c1c2007-04-12 01:34:14 -0400577 gameport_stop_polling(grip->gameport);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578}
579
580/*
581 * Tell the linux input layer about a newly plugged-in gamepad.
582 */
583
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500584static int register_slot(int slot, struct grip_mp *grip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585{
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500586 struct grip_port *port = grip->port[slot];
587 struct input_dev *input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 int j, t;
Dmitry Torokhov127278c2006-11-05 22:40:09 -0500589 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500591 port->dev = input_dev = input_allocate_device();
592 if (!input_dev)
593 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500595 input_dev->name = grip_name[port->mode];
596 input_dev->id.bustype = BUS_GAMEPORT;
597 input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS;
598 input_dev->id.product = 0x0100 + port->mode;
599 input_dev->id.version = 0x0100;
Dmitry Torokhov935e6582007-04-12 01:35:26 -0400600 input_dev->dev.parent = &grip->gameport->dev;
Dmitry Torokhov8715c1c2007-04-12 01:34:14 -0400601
602 input_set_drvdata(input_dev, grip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500604 input_dev->open = grip_open;
605 input_dev->close = grip_close;
606
Jiri Slaby7b19ada2007-10-18 23:40:32 -0700607 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500608
609 for (j = 0; (t = grip_abs[port->mode][j]) >= 0; j++)
610 input_set_abs_params(input_dev, t, -1, 1, 0, 0);
611
612 for (j = 0; (t = grip_btn[port->mode][j]) >= 0; j++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 if (t > 0)
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500614 set_bit(t, input_dev->keybit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
Dmitry Torokhov127278c2006-11-05 22:40:09 -0500616 err = input_register_device(port->dev);
617 if (err) {
618 input_free_device(port->dev);
619 return err;
620 }
621
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500622 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
Axel Lin98a84132012-04-03 23:52:27 -0700690module_gameport_driver(grip_drv);