grip_mp.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. /*
  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. #include <linux/kernel.h>
  14. #include <linux/module.h>
  15. #include <linux/init.h>
  16. #include <linux/slab.h>
  17. #include <linux/gameport.h>
  18. #include <linux/input.h>
  19. #include <linux/delay.h>
  20. #include <linux/proc_fs.h>
  21. #define DRIVER_DESC "Gravis Grip Multiport driver"
  22. MODULE_AUTHOR("Brian Bonnlander");
  23. MODULE_DESCRIPTION(DRIVER_DESC);
  24. MODULE_LICENSE("GPL");
  25. #ifdef GRIP_DEBUG
  26. #define dbg(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg)
  27. #else
  28. #define dbg(format, arg...) do {} while (0)
  29. #endif
  30. /*
  31. * Grip multiport state
  32. */
  33. struct grip_mp {
  34. struct gameport *gameport;
  35. struct input_dev dev[4];
  36. int mode[4];
  37. int registered[4];
  38. int reads;
  39. int bads;
  40. /* individual gamepad states */
  41. int buttons[4];
  42. int xaxes[4];
  43. int yaxes[4];
  44. int dirty[4]; /* has the state been updated? */
  45. };
  46. /*
  47. * Multiport packet interpretation
  48. */
  49. #define PACKET_FULL 0x80000000 /* packet is full */
  50. #define PACKET_IO_FAST 0x40000000 /* 3 bits per gameport read */
  51. #define PACKET_IO_SLOW 0x20000000 /* 1 bit per gameport read */
  52. #define PACKET_MP_MORE 0x04000000 /* multiport wants to send more */
  53. #define PACKET_MP_DONE 0x02000000 /* multiport done sending */
  54. /*
  55. * Packet status code interpretation
  56. */
  57. #define IO_GOT_PACKET 0x0100 /* Got a packet */
  58. #define IO_MODE_FAST 0x0200 /* Used 3 data bits per gameport read */
  59. #define IO_SLOT_CHANGE 0x0800 /* Multiport physical slot status changed */
  60. #define IO_DONE 0x1000 /* Multiport is done sending packets */
  61. #define IO_RETRY 0x4000 /* Try again later to get packet */
  62. #define IO_RESET 0x8000 /* Force multiport to resend all packets */
  63. /*
  64. * Gamepad configuration data. Other 9-pin digital joystick devices
  65. * may work with the multiport, so this may not be an exhaustive list!
  66. * Commodore 64 joystick remains untested.
  67. */
  68. #define GRIP_INIT_DELAY 2000 /* 2 ms */
  69. #define GRIP_MODE_NONE 0
  70. #define GRIP_MODE_RESET 1
  71. #define GRIP_MODE_GP 2
  72. #define GRIP_MODE_C64 3
  73. static int grip_btn_gp[] = { BTN_TR, BTN_TL, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, -1 };
  74. static int grip_btn_c64[] = { BTN_JOYSTICK, -1 };
  75. static int grip_abs_gp[] = { ABS_X, ABS_Y, -1 };
  76. static int grip_abs_c64[] = { ABS_X, ABS_Y, -1 };
  77. static int *grip_abs[] = { NULL, NULL, grip_abs_gp, grip_abs_c64 };
  78. static int *grip_btn[] = { NULL, NULL, grip_btn_gp, grip_btn_c64 };
  79. static char *grip_name[] = { NULL, NULL, "Gravis Grip Pad", "Commodore 64 Joystick" };
  80. static const int init_seq[] = {
  81. 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  82. 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,
  83. 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  84. 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1 };
  85. /* Maps multiport directional values to X,Y axis values (each axis encoded in 3 bits) */
  86. static int axis_map[] = { 5, 9, 1, 5, 6, 10, 2, 6, 4, 8, 0, 4, 5, 9, 1, 5 };
  87. static void register_slot(int i, struct grip_mp *grip);
  88. /*
  89. * Returns whether an odd or even number of bits are on in pkt.
  90. */
  91. static int bit_parity(u32 pkt)
  92. {
  93. int x = pkt ^ (pkt >> 16);
  94. x ^= x >> 8;
  95. x ^= x >> 4;
  96. x ^= x >> 2;
  97. x ^= x >> 1;
  98. return x & 1;
  99. }
  100. /*
  101. * Poll gameport; return true if all bits set in 'onbits' are on and
  102. * all bits set in 'offbits' are off.
  103. */
  104. static inline int poll_until(u8 onbits, u8 offbits, int u_sec, struct gameport* gp, u8 *data)
  105. {
  106. int i, nloops;
  107. nloops = gameport_time(gp, u_sec);
  108. for (i = 0; i < nloops; i++) {
  109. *data = gameport_read(gp);
  110. if ((*data & onbits) == onbits &&
  111. (~(*data) & offbits) == offbits)
  112. return 1;
  113. }
  114. dbg("gameport timed out after %d microseconds.\n", u_sec);
  115. return 0;
  116. }
  117. /*
  118. * Gets a 28-bit packet from the multiport.
  119. *
  120. * After getting a packet successfully, commands encoded by sendcode may
  121. * be sent to the multiport.
  122. *
  123. * The multiport clock value is reflected in gameport bit B4.
  124. *
  125. * Returns a packet status code indicating whether packet is valid, the transfer
  126. * mode, and any error conditions.
  127. *
  128. * sendflags: current I/O status
  129. * sendcode: data to send to the multiport if sendflags is nonzero
  130. */
  131. static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet)
  132. {
  133. u8 raw_data; /* raw data from gameport */
  134. u8 data_mask; /* packet data bits from raw_data */
  135. u32 pkt; /* packet temporary storage */
  136. int bits_per_read; /* num packet bits per gameport read */
  137. int portvals = 0; /* used for port value sanity check */
  138. int i;
  139. /* Gameport bits B0, B4, B5 should first be off, then B4 should come on. */
  140. *packet = 0;
  141. raw_data = gameport_read(gameport);
  142. if (raw_data & 1)
  143. return IO_RETRY;
  144. for (i = 0; i < 64; i++) {
  145. raw_data = gameport_read(gameport);
  146. portvals |= 1 << ((raw_data >> 4) & 3); /* Demux B4, B5 */
  147. }
  148. if (portvals == 1) { /* B4, B5 off */
  149. raw_data = gameport_read(gameport);
  150. portvals = raw_data & 0xf0;
  151. if (raw_data & 0x31)
  152. return IO_RESET;
  153. gameport_trigger(gameport);
  154. if (!poll_until(0x10, 0, 308, gameport, &raw_data))
  155. return IO_RESET;
  156. } else
  157. return IO_RETRY;
  158. /* Determine packet transfer mode and prepare for packet construction. */
  159. if (raw_data & 0x20) { /* 3 data bits/read */
  160. portvals |= raw_data >> 4; /* Compare B4-B7 before & after trigger */
  161. if (portvals != 0xb)
  162. return 0;
  163. data_mask = 7;
  164. bits_per_read = 3;
  165. pkt = (PACKET_FULL | PACKET_IO_FAST) >> 28;
  166. } else { /* 1 data bit/read */
  167. data_mask = 1;
  168. bits_per_read = 1;
  169. pkt = (PACKET_FULL | PACKET_IO_SLOW) >> 28;
  170. }
  171. /* Construct a packet. Final data bits must be zero. */
  172. while (1) {
  173. if (!poll_until(0, 0x10, 77, gameport, &raw_data))
  174. return IO_RESET;
  175. raw_data = (raw_data >> 5) & data_mask;
  176. if (pkt & PACKET_FULL)
  177. break;
  178. pkt = (pkt << bits_per_read) | raw_data;
  179. if (!poll_until(0x10, 0, 77, gameport, &raw_data))
  180. return IO_RESET;
  181. }
  182. if (raw_data)
  183. return IO_RESET;
  184. /* If 3 bits/read used, drop from 30 bits to 28. */
  185. if (bits_per_read == 3) {
  186. pkt = (pkt & 0xffff0000) | ((pkt << 1) & 0xffff);
  187. pkt = (pkt >> 2) | 0xf0000000;
  188. }
  189. if (bit_parity(pkt) == 1)
  190. return IO_RESET;
  191. /* Acknowledge packet receipt */
  192. if (!poll_until(0x30, 0, 77, gameport, &raw_data))
  193. return IO_RESET;
  194. raw_data = gameport_read(gameport);
  195. if (raw_data & 1)
  196. return IO_RESET;
  197. gameport_trigger(gameport);
  198. if (!poll_until(0, 0x20, 77, gameport, &raw_data))
  199. return IO_RESET;
  200. /* Return if we just wanted the packet or multiport wants to send more */
  201. *packet = pkt;
  202. if ((sendflags == 0) || ((sendflags & IO_RETRY) && !(pkt & PACKET_MP_DONE)))
  203. return IO_GOT_PACKET;
  204. if (pkt & PACKET_MP_MORE)
  205. return IO_GOT_PACKET | IO_RETRY;
  206. /* Multiport is done sending packets and is ready to receive data */
  207. if (!poll_until(0x20, 0, 77, gameport, &raw_data))
  208. return IO_GOT_PACKET | IO_RESET;
  209. raw_data = gameport_read(gameport);
  210. if (raw_data & 1)
  211. return IO_GOT_PACKET | IO_RESET;
  212. /* Trigger gameport based on bits in sendcode */
  213. gameport_trigger(gameport);
  214. do {
  215. if (!poll_until(0x20, 0x10, 116, gameport, &raw_data))
  216. return IO_GOT_PACKET | IO_RESET;
  217. if (!poll_until(0x30, 0, 193, gameport, &raw_data))
  218. return IO_GOT_PACKET | IO_RESET;
  219. if (raw_data & 1)
  220. return IO_GOT_PACKET | IO_RESET;
  221. if (sendcode & 1)
  222. gameport_trigger(gameport);
  223. sendcode >>= 1;
  224. } while (sendcode);
  225. return IO_GOT_PACKET | IO_MODE_FAST;
  226. }
  227. /*
  228. * Disables and restores interrupts for mp_io(), which does the actual I/O.
  229. */
  230. static int multiport_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet)
  231. {
  232. int status;
  233. unsigned long flags;
  234. local_irq_save(flags);
  235. status = mp_io(gameport, sendflags, sendcode, packet);
  236. local_irq_restore(flags);
  237. return status;
  238. }
  239. /*
  240. * Puts multiport into digital mode. Multiport LED turns green.
  241. *
  242. * Returns true if a valid digital packet was received, false otherwise.
  243. */
  244. static int dig_mode_start(struct gameport *gameport, u32 *packet)
  245. {
  246. int i, seq_len = sizeof(init_seq)/sizeof(int);
  247. int flags, tries = 0, bads = 0;
  248. for (i = 0; i < seq_len; i++) { /* Send magic sequence */
  249. if (init_seq[i])
  250. gameport_trigger(gameport);
  251. udelay(GRIP_INIT_DELAY);
  252. }
  253. for (i = 0; i < 16; i++) /* Wait for multiport to settle */
  254. udelay(GRIP_INIT_DELAY);
  255. while (tries < 64 && bads < 8) { /* Reset multiport and try getting a packet */
  256. flags = multiport_io(gameport, IO_RESET, 0x27, packet);
  257. if (flags & IO_MODE_FAST)
  258. return 1;
  259. if (flags & IO_RETRY)
  260. tries++;
  261. else
  262. bads++;
  263. }
  264. return 0;
  265. }
  266. /*
  267. * Packet structure: B0-B15 => gamepad state
  268. * B16-B20 => gamepad device type
  269. * B21-B24 => multiport slot index (1-4)
  270. *
  271. * Known device types: 0x1f (grip pad), 0x0 (no device). Others may exist.
  272. *
  273. * Returns the packet status.
  274. */
  275. static int get_and_decode_packet(struct grip_mp *grip, int flags)
  276. {
  277. u32 packet;
  278. int joytype = 0;
  279. int slot = 0;
  280. /* Get a packet and check for validity */
  281. flags &= IO_RESET | IO_RETRY;
  282. flags = multiport_io(grip->gameport, flags, 0, &packet);
  283. grip->reads++;
  284. if (packet & PACKET_MP_DONE)
  285. flags |= IO_DONE;
  286. if (flags && !(flags & IO_GOT_PACKET)) {
  287. grip->bads++;
  288. return flags;
  289. }
  290. /* Ignore non-gamepad packets, e.g. multiport hardware version */
  291. slot = ((packet >> 21) & 0xf) - 1;
  292. if ((slot < 0) || (slot > 3))
  293. return flags;
  294. /*
  295. * Handle "reset" packets, which occur at startup, and when gamepads
  296. * are removed or plugged in. May contain configuration of a new gamepad.
  297. */
  298. joytype = (packet >> 16) & 0x1f;
  299. if (!joytype) {
  300. if (grip->registered[slot]) {
  301. printk(KERN_INFO "grip_mp: removing %s, slot %d\n",
  302. grip_name[grip->mode[slot]], slot);
  303. input_unregister_device(grip->dev + slot);
  304. grip->registered[slot] = 0;
  305. }
  306. dbg("Reset: grip multiport slot %d\n", slot);
  307. grip->mode[slot] = GRIP_MODE_RESET;
  308. flags |= IO_SLOT_CHANGE;
  309. return flags;
  310. }
  311. /* Interpret a grip pad packet */
  312. if (joytype == 0x1f) {
  313. int dir = (packet >> 8) & 0xf; /* eight way directional value */
  314. grip->buttons[slot] = (~packet) & 0xff;
  315. grip->yaxes[slot] = ((axis_map[dir] >> 2) & 3) - 1;
  316. grip->xaxes[slot] = (axis_map[dir] & 3) - 1;
  317. grip->dirty[slot] = 1;
  318. if (grip->mode[slot] == GRIP_MODE_RESET)
  319. flags |= IO_SLOT_CHANGE;
  320. grip->mode[slot] = GRIP_MODE_GP;
  321. if (!grip->registered[slot]) {
  322. dbg("New Grip pad in multiport slot %d.\n", slot);
  323. register_slot(slot, grip);
  324. }
  325. return flags;
  326. }
  327. /* Handle non-grip device codes. For now, just print diagnostics. */
  328. {
  329. static int strange_code = 0;
  330. if (strange_code != joytype) {
  331. printk(KERN_INFO "Possible non-grip pad/joystick detected.\n");
  332. printk(KERN_INFO "Got joy type 0x%x and packet 0x%x.\n", joytype, packet);
  333. strange_code = joytype;
  334. }
  335. }
  336. return flags;
  337. }
  338. /*
  339. * Returns true if all multiport slot states appear valid.
  340. */
  341. static int slots_valid(struct grip_mp *grip)
  342. {
  343. int flags, slot, invalid = 0, active = 0;
  344. flags = get_and_decode_packet(grip, 0);
  345. if (!(flags & IO_GOT_PACKET))
  346. return 0;
  347. for (slot = 0; slot < 4; slot++) {
  348. if (grip->mode[slot] == GRIP_MODE_RESET)
  349. invalid = 1;
  350. if (grip->mode[slot] != GRIP_MODE_NONE)
  351. active = 1;
  352. }
  353. /* Return true if no active slot but multiport sent all its data */
  354. if (!active)
  355. return (flags & IO_DONE) ? 1 : 0;
  356. /* Return false if invalid device code received */
  357. return invalid ? 0 : 1;
  358. }
  359. /*
  360. * Returns whether the multiport was placed into digital mode and
  361. * able to communicate its state successfully.
  362. */
  363. static int multiport_init(struct grip_mp *grip)
  364. {
  365. int dig_mode, initialized = 0, tries = 0;
  366. u32 packet;
  367. dig_mode = dig_mode_start(grip->gameport, &packet);
  368. while (!dig_mode && tries < 4) {
  369. dig_mode = dig_mode_start(grip->gameport, &packet);
  370. tries++;
  371. }
  372. if (dig_mode)
  373. dbg("multiport_init(): digital mode activated.\n");
  374. else {
  375. dbg("multiport_init(): unable to activate digital mode.\n");
  376. return 0;
  377. }
  378. /* Get packets, store multiport state, and check state's validity */
  379. for (tries = 0; tries < 4096; tries++) {
  380. if ( slots_valid(grip) ) {
  381. initialized = 1;
  382. break;
  383. }
  384. }
  385. dbg("multiport_init(): initialized == %d\n", initialized);
  386. return initialized;
  387. }
  388. /*
  389. * Reports joystick state to the linux input layer.
  390. */
  391. static void report_slot(struct grip_mp *grip, int slot)
  392. {
  393. struct input_dev *dev = &(grip->dev[slot]);
  394. int i, buttons = grip->buttons[slot];
  395. /* Store button states with linux input driver */
  396. for (i = 0; i < 8; i++)
  397. input_report_key(dev, grip_btn_gp[i], (buttons >> i) & 1);
  398. /* Store axis states with linux driver */
  399. input_report_abs(dev, ABS_X, grip->xaxes[slot]);
  400. input_report_abs(dev, ABS_Y, grip->yaxes[slot]);
  401. /* Tell the receiver of the events to process them */
  402. input_sync(dev);
  403. grip->dirty[slot] = 0;
  404. }
  405. /*
  406. * Get the multiport state.
  407. */
  408. static void grip_poll(struct gameport *gameport)
  409. {
  410. struct grip_mp *grip = gameport_get_drvdata(gameport);
  411. int i, npkts, flags;
  412. for (npkts = 0; npkts < 4; npkts++) {
  413. flags = IO_RETRY;
  414. for (i = 0; i < 32; i++) {
  415. flags = get_and_decode_packet(grip, flags);
  416. if ((flags & IO_GOT_PACKET) || !(flags & IO_RETRY))
  417. break;
  418. }
  419. if (flags & IO_DONE)
  420. break;
  421. }
  422. for (i = 0; i < 4; i++)
  423. if (grip->dirty[i])
  424. report_slot(grip, i);
  425. }
  426. /*
  427. * Called when a joystick device file is opened
  428. */
  429. static int grip_open(struct input_dev *dev)
  430. {
  431. struct grip_mp *grip = dev->private;
  432. gameport_start_polling(grip->gameport);
  433. return 0;
  434. }
  435. /*
  436. * Called when a joystick device file is closed
  437. */
  438. static void grip_close(struct input_dev *dev)
  439. {
  440. struct grip_mp *grip = dev->private;
  441. gameport_start_polling(grip->gameport);
  442. }
  443. /*
  444. * Tell the linux input layer about a newly plugged-in gamepad.
  445. */
  446. static void register_slot(int slot, struct grip_mp *grip)
  447. {
  448. int j, t;
  449. grip->dev[slot].private = grip;
  450. grip->dev[slot].open = grip_open;
  451. grip->dev[slot].close = grip_close;
  452. grip->dev[slot].name = grip_name[grip->mode[slot]];
  453. grip->dev[slot].id.bustype = BUS_GAMEPORT;
  454. grip->dev[slot].id.vendor = GAMEPORT_ID_VENDOR_GRAVIS;
  455. grip->dev[slot].id.product = 0x0100 + grip->mode[slot];
  456. grip->dev[slot].id.version = 0x0100;
  457. grip->dev[slot].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
  458. for (j = 0; (t = grip_abs[grip->mode[slot]][j]) >= 0; j++)
  459. input_set_abs_params(&grip->dev[slot], t, -1, 1, 0, 0);
  460. for (j = 0; (t = grip_btn[grip->mode[slot]][j]) >= 0; j++)
  461. if (t > 0)
  462. set_bit(t, grip->dev[slot].keybit);
  463. input_register_device(grip->dev + slot);
  464. grip->registered[slot] = 1;
  465. if (grip->dirty[slot]) /* report initial state, if any */
  466. report_slot(grip, slot);
  467. printk(KERN_INFO "grip_mp: added %s, slot %d\n",
  468. grip_name[grip->mode[slot]], slot);
  469. }
  470. static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
  471. {
  472. struct grip_mp *grip;
  473. int err;
  474. if (!(grip = kzalloc(sizeof(struct grip_mp), GFP_KERNEL)))
  475. return -ENOMEM;
  476. grip->gameport = gameport;
  477. gameport_set_drvdata(gameport, grip);
  478. err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
  479. if (err)
  480. goto fail1;
  481. gameport_set_poll_handler(gameport, grip_poll);
  482. gameport_set_poll_interval(gameport, 20);
  483. if (!multiport_init(grip)) {
  484. err = -ENODEV;
  485. goto fail2;
  486. }
  487. if (!grip->mode[0] && !grip->mode[1] && !grip->mode[2] && !grip->mode[3]) {
  488. /* nothing plugged in */
  489. err = -ENODEV;
  490. goto fail2;
  491. }
  492. return 0;
  493. fail2: gameport_close(gameport);
  494. fail1: gameport_set_drvdata(gameport, NULL);
  495. kfree(grip);
  496. return err;
  497. }
  498. static void grip_disconnect(struct gameport *gameport)
  499. {
  500. struct grip_mp *grip = gameport_get_drvdata(gameport);
  501. int i;
  502. for (i = 0; i < 4; i++)
  503. if (grip->registered[i])
  504. input_unregister_device(grip->dev + i);
  505. gameport_close(gameport);
  506. gameport_set_drvdata(gameport, NULL);
  507. kfree(grip);
  508. }
  509. static struct gameport_driver grip_drv = {
  510. .driver = {
  511. .name = "grip_mp",
  512. },
  513. .description = DRIVER_DESC,
  514. .connect = grip_connect,
  515. .disconnect = grip_disconnect,
  516. };
  517. static int __init grip_init(void)
  518. {
  519. gameport_register_driver(&grip_drv);
  520. return 0;
  521. }
  522. static void __exit grip_exit(void)
  523. {
  524. gameport_unregister_driver(&grip_drv);
  525. }
  526. module_init(grip_init);
  527. module_exit(grip_exit);