blob: c57e21d68c003e2970949744120b3384b8fe98e6 [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];
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 int reads;
57 int bads;
Linus Torvalds1da177e2005-04-16 15:20:36 -070058};
59
60/*
61 * Multiport packet interpretation
62 */
63
64#define PACKET_FULL 0x80000000 /* packet is full */
65#define PACKET_IO_FAST 0x40000000 /* 3 bits per gameport read */
66#define PACKET_IO_SLOW 0x20000000 /* 1 bit per gameport read */
67#define PACKET_MP_MORE 0x04000000 /* multiport wants to send more */
68#define PACKET_MP_DONE 0x02000000 /* multiport done sending */
69
70/*
71 * Packet status code interpretation
72 */
73
74#define IO_GOT_PACKET 0x0100 /* Got a packet */
75#define IO_MODE_FAST 0x0200 /* Used 3 data bits per gameport read */
76#define IO_SLOT_CHANGE 0x0800 /* Multiport physical slot status changed */
77#define IO_DONE 0x1000 /* Multiport is done sending packets */
78#define IO_RETRY 0x4000 /* Try again later to get packet */
79#define IO_RESET 0x8000 /* Force multiport to resend all packets */
80
81/*
82 * Gamepad configuration data. Other 9-pin digital joystick devices
83 * may work with the multiport, so this may not be an exhaustive list!
84 * Commodore 64 joystick remains untested.
85 */
86
87#define GRIP_INIT_DELAY 2000 /* 2 ms */
88
89#define GRIP_MODE_NONE 0
90#define GRIP_MODE_RESET 1
91#define GRIP_MODE_GP 2
92#define GRIP_MODE_C64 3
93
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -050094static const int grip_btn_gp[] = { BTN_TR, BTN_TL, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, -1 };
95static const int grip_btn_c64[] = { BTN_JOYSTICK, -1 };
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -050097static const int grip_abs_gp[] = { ABS_X, ABS_Y, -1 };
98static const int grip_abs_c64[] = { ABS_X, ABS_Y, -1 };
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500100static const int *grip_abs[] = { NULL, NULL, grip_abs_gp, grip_abs_c64 };
101static const int *grip_btn[] = { NULL, NULL, grip_btn_gp, grip_btn_c64 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500103static const char *grip_name[] = { NULL, NULL, "Gravis Grip Pad", "Commodore 64 Joystick" };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
105static const int init_seq[] = {
106 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,
107 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,
108 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,
109 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1 };
110
111/* Maps multiport directional values to X,Y axis values (each axis encoded in 3 bits) */
112
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500113static 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 -0700114
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500115static int register_slot(int i, struct grip_mp *grip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116
117/*
118 * Returns whether an odd or even number of bits are on in pkt.
119 */
120
121static int bit_parity(u32 pkt)
122{
123 int x = pkt ^ (pkt >> 16);
124 x ^= x >> 8;
125 x ^= x >> 4;
126 x ^= x >> 2;
127 x ^= x >> 1;
128 return x & 1;
129}
130
131/*
132 * Poll gameport; return true if all bits set in 'onbits' are on and
133 * all bits set in 'offbits' are off.
134 */
135
136static inline int poll_until(u8 onbits, u8 offbits, int u_sec, struct gameport* gp, u8 *data)
137{
138 int i, nloops;
139
140 nloops = gameport_time(gp, u_sec);
141 for (i = 0; i < nloops; i++) {
142 *data = gameport_read(gp);
143 if ((*data & onbits) == onbits &&
144 (~(*data) & offbits) == offbits)
145 return 1;
146 }
147 dbg("gameport timed out after %d microseconds.\n", u_sec);
148 return 0;
149}
150
151/*
152 * Gets a 28-bit packet from the multiport.
153 *
154 * After getting a packet successfully, commands encoded by sendcode may
155 * be sent to the multiport.
156 *
157 * The multiport clock value is reflected in gameport bit B4.
158 *
159 * Returns a packet status code indicating whether packet is valid, the transfer
160 * mode, and any error conditions.
161 *
162 * sendflags: current I/O status
163 * sendcode: data to send to the multiport if sendflags is nonzero
164 */
165
166static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet)
167{
168 u8 raw_data; /* raw data from gameport */
169 u8 data_mask; /* packet data bits from raw_data */
170 u32 pkt; /* packet temporary storage */
171 int bits_per_read; /* num packet bits per gameport read */
172 int portvals = 0; /* used for port value sanity check */
173 int i;
174
175 /* Gameport bits B0, B4, B5 should first be off, then B4 should come on. */
176
177 *packet = 0;
178 raw_data = gameport_read(gameport);
179 if (raw_data & 1)
Dmitry Torokhovab0c3442005-05-29 02:28:55 -0500180 return IO_RETRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
182 for (i = 0; i < 64; i++) {
183 raw_data = gameport_read(gameport);
184 portvals |= 1 << ((raw_data >> 4) & 3); /* Demux B4, B5 */
185 }
186
187 if (portvals == 1) { /* B4, B5 off */
188 raw_data = gameport_read(gameport);
189 portvals = raw_data & 0xf0;
190
191 if (raw_data & 0x31)
192 return IO_RESET;
193 gameport_trigger(gameport);
194
195 if (!poll_until(0x10, 0, 308, gameport, &raw_data))
196 return IO_RESET;
197 } else
198 return IO_RETRY;
199
200 /* Determine packet transfer mode and prepare for packet construction. */
201
202 if (raw_data & 0x20) { /* 3 data bits/read */
203 portvals |= raw_data >> 4; /* Compare B4-B7 before & after trigger */
204
205 if (portvals != 0xb)
206 return 0;
207 data_mask = 7;
208 bits_per_read = 3;
209 pkt = (PACKET_FULL | PACKET_IO_FAST) >> 28;
210 } else { /* 1 data bit/read */
211 data_mask = 1;
212 bits_per_read = 1;
213 pkt = (PACKET_FULL | PACKET_IO_SLOW) >> 28;
214 }
215
216 /* Construct a packet. Final data bits must be zero. */
217
218 while (1) {
219 if (!poll_until(0, 0x10, 77, gameport, &raw_data))
220 return IO_RESET;
221 raw_data = (raw_data >> 5) & data_mask;
222
223 if (pkt & PACKET_FULL)
224 break;
225 pkt = (pkt << bits_per_read) | raw_data;
226
227 if (!poll_until(0x10, 0, 77, gameport, &raw_data))
228 return IO_RESET;
229 }
230
231 if (raw_data)
232 return IO_RESET;
233
234 /* If 3 bits/read used, drop from 30 bits to 28. */
235
236 if (bits_per_read == 3) {
237 pkt = (pkt & 0xffff0000) | ((pkt << 1) & 0xffff);
238 pkt = (pkt >> 2) | 0xf0000000;
239 }
240
241 if (bit_parity(pkt) == 1)
242 return IO_RESET;
243
244 /* Acknowledge packet receipt */
245
246 if (!poll_until(0x30, 0, 77, gameport, &raw_data))
247 return IO_RESET;
248
249 raw_data = gameport_read(gameport);
250
251 if (raw_data & 1)
252 return IO_RESET;
253
254 gameport_trigger(gameport);
255
256 if (!poll_until(0, 0x20, 77, gameport, &raw_data))
257 return IO_RESET;
258
259 /* Return if we just wanted the packet or multiport wants to send more */
260
261 *packet = pkt;
262 if ((sendflags == 0) || ((sendflags & IO_RETRY) && !(pkt & PACKET_MP_DONE)))
263 return IO_GOT_PACKET;
264
265 if (pkt & PACKET_MP_MORE)
266 return IO_GOT_PACKET | IO_RETRY;
267
268 /* Multiport is done sending packets and is ready to receive data */
269
270 if (!poll_until(0x20, 0, 77, gameport, &raw_data))
271 return IO_GOT_PACKET | IO_RESET;
272
273 raw_data = gameport_read(gameport);
274 if (raw_data & 1)
275 return IO_GOT_PACKET | IO_RESET;
276
277 /* Trigger gameport based on bits in sendcode */
278
279 gameport_trigger(gameport);
280 do {
281 if (!poll_until(0x20, 0x10, 116, gameport, &raw_data))
282 return IO_GOT_PACKET | IO_RESET;
283
284 if (!poll_until(0x30, 0, 193, gameport, &raw_data))
285 return IO_GOT_PACKET | IO_RESET;
286
287 if (raw_data & 1)
288 return IO_GOT_PACKET | IO_RESET;
289
290 if (sendcode & 1)
291 gameport_trigger(gameport);
292
293 sendcode >>= 1;
294 } while (sendcode);
295
296 return IO_GOT_PACKET | IO_MODE_FAST;
297}
298
299/*
300 * Disables and restores interrupts for mp_io(), which does the actual I/O.
301 */
302
303static int multiport_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet)
304{
305 int status;
306 unsigned long flags;
307
308 local_irq_save(flags);
309 status = mp_io(gameport, sendflags, sendcode, packet);
310 local_irq_restore(flags);
311
312 return status;
313}
314
315/*
316 * Puts multiport into digital mode. Multiport LED turns green.
317 *
318 * Returns true if a valid digital packet was received, false otherwise.
319 */
320
321static int dig_mode_start(struct gameport *gameport, u32 *packet)
322{
Andi Drebes5ec1f7f2007-06-14 23:33:01 -0400323 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 int flags, tries = 0, bads = 0;
325
Andi Drebes5ec1f7f2007-06-14 23:33:01 -0400326 for (i = 0; i < ARRAY_SIZE(init_seq); i++) { /* Send magic sequence */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 if (init_seq[i])
328 gameport_trigger(gameport);
329 udelay(GRIP_INIT_DELAY);
330 }
331
332 for (i = 0; i < 16; i++) /* Wait for multiport to settle */
333 udelay(GRIP_INIT_DELAY);
334
335 while (tries < 64 && bads < 8) { /* Reset multiport and try getting a packet */
336
337 flags = multiport_io(gameport, IO_RESET, 0x27, packet);
338
339 if (flags & IO_MODE_FAST)
340 return 1;
341
342 if (flags & IO_RETRY)
343 tries++;
344 else
345 bads++;
346 }
347 return 0;
348}
349
350/*
351 * Packet structure: B0-B15 => gamepad state
352 * B16-B20 => gamepad device type
353 * B21-B24 => multiport slot index (1-4)
354 *
355 * Known device types: 0x1f (grip pad), 0x0 (no device). Others may exist.
356 *
357 * Returns the packet status.
358 */
359
360static int get_and_decode_packet(struct grip_mp *grip, int flags)
361{
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500362 struct grip_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 u32 packet;
364 int joytype = 0;
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500365 int slot;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366
367 /* Get a packet and check for validity */
368
369 flags &= IO_RESET | IO_RETRY;
370 flags = multiport_io(grip->gameport, flags, 0, &packet);
371 grip->reads++;
372
373 if (packet & PACKET_MP_DONE)
374 flags |= IO_DONE;
375
376 if (flags && !(flags & IO_GOT_PACKET)) {
377 grip->bads++;
378 return flags;
379 }
380
381 /* Ignore non-gamepad packets, e.g. multiport hardware version */
382
383 slot = ((packet >> 21) & 0xf) - 1;
384 if ((slot < 0) || (slot > 3))
385 return flags;
386
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500387 port = grip->port[slot];
388
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 /*
390 * Handle "reset" packets, which occur at startup, and when gamepads
391 * are removed or plugged in. May contain configuration of a new gamepad.
392 */
393
394 joytype = (packet >> 16) & 0x1f;
395 if (!joytype) {
396
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500397 if (port->registered) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 printk(KERN_INFO "grip_mp: removing %s, slot %d\n",
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500399 grip_name[port->mode], slot);
400 input_unregister_device(port->dev);
401 port->registered = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 }
403 dbg("Reset: grip multiport slot %d\n", slot);
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500404 port->mode = GRIP_MODE_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 flags |= IO_SLOT_CHANGE;
406 return flags;
407 }
408
409 /* Interpret a grip pad packet */
410
411 if (joytype == 0x1f) {
412
413 int dir = (packet >> 8) & 0xf; /* eight way directional value */
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500414 port->buttons = (~packet) & 0xff;
415 port->yaxes = ((axis_map[dir] >> 2) & 3) - 1;
416 port->xaxes = (axis_map[dir] & 3) - 1;
417 port->dirty = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500419 if (port->mode == GRIP_MODE_RESET)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 flags |= IO_SLOT_CHANGE;
421
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500422 port->mode = GRIP_MODE_GP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500424 if (!port->registered) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 dbg("New Grip pad in multiport slot %d.\n", slot);
Dmitry Torokhov127278c2006-11-05 22:40:09 -0500426 if (register_slot(slot, grip)) {
427 port->mode = GRIP_MODE_RESET;
428 port->dirty = 0;
429 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 }
431 return flags;
432 }
433
434 /* Handle non-grip device codes. For now, just print diagnostics. */
435
436 {
437 static int strange_code = 0;
438 if (strange_code != joytype) {
439 printk(KERN_INFO "Possible non-grip pad/joystick detected.\n");
440 printk(KERN_INFO "Got joy type 0x%x and packet 0x%x.\n", joytype, packet);
441 strange_code = joytype;
442 }
443 }
444 return flags;
445}
446
447/*
448 * Returns true if all multiport slot states appear valid.
449 */
450
451static int slots_valid(struct grip_mp *grip)
452{
453 int flags, slot, invalid = 0, active = 0;
454
455 flags = get_and_decode_packet(grip, 0);
456 if (!(flags & IO_GOT_PACKET))
457 return 0;
458
459 for (slot = 0; slot < 4; slot++) {
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500460 if (grip->port[slot]->mode == GRIP_MODE_RESET)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 invalid = 1;
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500462 if (grip->port[slot]->mode != GRIP_MODE_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 active = 1;
464 }
465
466 /* Return true if no active slot but multiport sent all its data */
467 if (!active)
468 return (flags & IO_DONE) ? 1 : 0;
469
470 /* Return false if invalid device code received */
471 return invalid ? 0 : 1;
472}
473
474/*
475 * Returns whether the multiport was placed into digital mode and
476 * able to communicate its state successfully.
477 */
478
479static int multiport_init(struct grip_mp *grip)
480{
481 int dig_mode, initialized = 0, tries = 0;
482 u32 packet;
483
484 dig_mode = dig_mode_start(grip->gameport, &packet);
485 while (!dig_mode && tries < 4) {
486 dig_mode = dig_mode_start(grip->gameport, &packet);
487 tries++;
488 }
489
490 if (dig_mode)
491 dbg("multiport_init(): digital mode activated.\n");
492 else {
493 dbg("multiport_init(): unable to activate digital mode.\n");
494 return 0;
495 }
496
497 /* Get packets, store multiport state, and check state's validity */
498 for (tries = 0; tries < 4096; tries++) {
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500499 if (slots_valid(grip)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 initialized = 1;
501 break;
502 }
503 }
504 dbg("multiport_init(): initialized == %d\n", initialized);
505 return initialized;
506}
507
508/*
509 * Reports joystick state to the linux input layer.
510 */
511
512static void report_slot(struct grip_mp *grip, int slot)
513{
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500514 struct grip_port *port = grip->port[slot];
515 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
517 /* Store button states with linux input driver */
518
519 for (i = 0; i < 8; i++)
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500520 input_report_key(port->dev, grip_btn_gp[i], (port->buttons >> i) & 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
522 /* Store axis states with linux driver */
523
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500524 input_report_abs(port->dev, ABS_X, port->xaxes);
525 input_report_abs(port->dev, ABS_Y, port->yaxes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
527 /* Tell the receiver of the events to process them */
528
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500529 input_sync(port->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500531 port->dirty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532}
533
534/*
535 * Get the multiport state.
536 */
537
538static void grip_poll(struct gameport *gameport)
539{
540 struct grip_mp *grip = gameport_get_drvdata(gameport);
541 int i, npkts, flags;
542
543 for (npkts = 0; npkts < 4; npkts++) {
544 flags = IO_RETRY;
545 for (i = 0; i < 32; i++) {
546 flags = get_and_decode_packet(grip, flags);
547 if ((flags & IO_GOT_PACKET) || !(flags & IO_RETRY))
548 break;
549 }
550 if (flags & IO_DONE)
551 break;
552 }
553
554 for (i = 0; i < 4; i++)
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500555 if (grip->port[i]->dirty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 report_slot(grip, i);
557}
558
559/*
560 * Called when a joystick device file is opened
561 */
562
563static int grip_open(struct input_dev *dev)
564{
Dmitry Torokhov8715c1c2007-04-12 01:34:14 -0400565 struct grip_mp *grip = input_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566
567 gameport_start_polling(grip->gameport);
568 return 0;
569}
570
571/*
572 * Called when a joystick device file is closed
573 */
574
575static void grip_close(struct input_dev *dev)
576{
Dmitry Torokhov8715c1c2007-04-12 01:34:14 -0400577 struct grip_mp *grip = input_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
Dmitry Torokhov8715c1c2007-04-12 01:34:14 -0400579 gameport_stop_polling(grip->gameport);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580}
581
582/*
583 * Tell the linux input layer about a newly plugged-in gamepad.
584 */
585
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500586static int register_slot(int slot, struct grip_mp *grip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587{
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500588 struct grip_port *port = grip->port[slot];
589 struct input_dev *input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 int j, t;
Dmitry Torokhov127278c2006-11-05 22:40:09 -0500591 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500593 port->dev = input_dev = input_allocate_device();
594 if (!input_dev)
595 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500597 input_dev->name = grip_name[port->mode];
598 input_dev->id.bustype = BUS_GAMEPORT;
599 input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS;
600 input_dev->id.product = 0x0100 + port->mode;
601 input_dev->id.version = 0x0100;
Dmitry Torokhov935e6582007-04-12 01:35:26 -0400602 input_dev->dev.parent = &grip->gameport->dev;
Dmitry Torokhov8715c1c2007-04-12 01:34:14 -0400603
604 input_set_drvdata(input_dev, grip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500606 input_dev->open = grip_open;
607 input_dev->close = grip_close;
608
Jiri Slaby7b19ada2007-10-18 23:40:32 -0700609 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500610
611 for (j = 0; (t = grip_abs[port->mode][j]) >= 0; j++)
612 input_set_abs_params(input_dev, t, -1, 1, 0, 0);
613
614 for (j = 0; (t = grip_btn[port->mode][j]) >= 0; j++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 if (t > 0)
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500616 set_bit(t, input_dev->keybit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
Dmitry Torokhov127278c2006-11-05 22:40:09 -0500618 err = input_register_device(port->dev);
619 if (err) {
620 input_free_device(port->dev);
621 return err;
622 }
623
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500624 port->registered = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500626 if (port->dirty) /* report initial state, if any */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 report_slot(grip, slot);
628
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500629 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630}
631
632static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
633{
634 struct grip_mp *grip;
635 int err;
636
Pekka Enberga97e1482005-09-06 15:18:33 -0700637 if (!(grip = kzalloc(sizeof(struct grip_mp), GFP_KERNEL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 return -ENOMEM;
639
640 grip->gameport = gameport;
641
642 gameport_set_drvdata(gameport, grip);
643
644 err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
645 if (err)
646 goto fail1;
647
648 gameport_set_poll_handler(gameport, grip_poll);
649 gameport_set_poll_interval(gameport, 20);
650
651 if (!multiport_init(grip)) {
652 err = -ENODEV;
653 goto fail2;
654 }
655
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500656 if (!grip->port[0]->mode && !grip->port[1]->mode && !grip->port[2]->mode && !grip->port[3]->mode) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 /* nothing plugged in */
658 err = -ENODEV;
659 goto fail2;
660 }
661
662 return 0;
663
664fail2: gameport_close(gameport);
665fail1: gameport_set_drvdata(gameport, NULL);
666 kfree(grip);
667 return err;
668}
669
670static void grip_disconnect(struct gameport *gameport)
671{
672 struct grip_mp *grip = gameport_get_drvdata(gameport);
673 int i;
674
675 for (i = 0; i < 4; i++)
Dmitry Torokhov17dd3f02005-09-15 02:01:52 -0500676 if (grip->port[i]->registered)
677 input_unregister_device(grip->port[i]->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 gameport_close(gameport);
679 gameport_set_drvdata(gameport, NULL);
680 kfree(grip);
681}
682
683static struct gameport_driver grip_drv = {
684 .driver = {
685 .name = "grip_mp",
686 },
687 .description = DRIVER_DESC,
688 .connect = grip_connect,
689 .disconnect = grip_disconnect,
690};
691
692static int __init grip_init(void)
693{
694 gameport_register_driver(&grip_drv);
695 return 0;
696}
697
698static void __exit grip_exit(void)
699{
700 gameport_unregister_driver(&grip_drv);
701}
702
703module_init(grip_init);
704module_exit(grip_exit);