Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  Driver for the Gravis Grip Multiport, a gamepad "hub" that
0004  *  connects up to four 9-pin digital gamepads/joysticks.
0005  *  Driver tested on SMP and UP kernel versions 2.4.18-4 and 2.4.18-5.
0006  *
0007  *  Thanks to Chris Gassib for helpful advice.
0008  *
0009  *  Copyright (c)      2002 Brian Bonnlander, Bill Soudan
0010  *  Copyright (c) 1998-2000 Vojtech Pavlik
0011  */
0012 
0013 #include <linux/kernel.h>
0014 #include <linux/module.h>
0015 #include <linux/slab.h>
0016 #include <linux/gameport.h>
0017 #include <linux/input.h>
0018 #include <linux/delay.h>
0019 #include <linux/proc_fs.h>
0020 #include <linux/jiffies.h>
0021 
0022 #define DRIVER_DESC "Gravis Grip Multiport driver"
0023 
0024 MODULE_AUTHOR("Brian Bonnlander");
0025 MODULE_DESCRIPTION(DRIVER_DESC);
0026 MODULE_LICENSE("GPL");
0027 
0028 #ifdef GRIP_DEBUG
0029 #define dbg(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg)
0030 #else
0031 #define dbg(format, arg...) do {} while (0)
0032 #endif
0033 
0034 #define GRIP_MAX_PORTS  4
0035 /*
0036  * Grip multiport state
0037  */
0038 
0039 struct grip_port {
0040     struct input_dev *dev;
0041     int mode;
0042     int registered;
0043 
0044     /* individual gamepad states */
0045     int buttons;
0046     int xaxes;
0047     int yaxes;
0048     int dirty;     /* has the state been updated? */
0049 };
0050 
0051 struct grip_mp {
0052     struct gameport *gameport;
0053     struct grip_port *port[GRIP_MAX_PORTS];
0054     int reads;
0055     int bads;
0056 };
0057 
0058 /*
0059  * Multiport packet interpretation
0060  */
0061 
0062 #define PACKET_FULL          0x80000000       /* packet is full                        */
0063 #define PACKET_IO_FAST       0x40000000       /* 3 bits per gameport read              */
0064 #define PACKET_IO_SLOW       0x20000000       /* 1 bit per gameport read               */
0065 #define PACKET_MP_MORE       0x04000000       /* multiport wants to send more          */
0066 #define PACKET_MP_DONE       0x02000000       /* multiport done sending                */
0067 
0068 /*
0069  * Packet status code interpretation
0070  */
0071 
0072 #define IO_GOT_PACKET        0x0100           /* Got a packet                           */
0073 #define IO_MODE_FAST         0x0200           /* Used 3 data bits per gameport read     */
0074 #define IO_SLOT_CHANGE       0x0800           /* Multiport physical slot status changed */
0075 #define IO_DONE              0x1000           /* Multiport is done sending packets      */
0076 #define IO_RETRY             0x4000           /* Try again later to get packet          */
0077 #define IO_RESET             0x8000           /* Force multiport to resend all packets  */
0078 
0079 /*
0080  * Gamepad configuration data.  Other 9-pin digital joystick devices
0081  * may work with the multiport, so this may not be an exhaustive list!
0082  * Commodore 64 joystick remains untested.
0083  */
0084 
0085 #define GRIP_INIT_DELAY         2000          /*  2 ms */
0086 
0087 #define GRIP_MODE_NONE      0
0088 #define GRIP_MODE_RESET         1
0089 #define GRIP_MODE_GP        2
0090 #define GRIP_MODE_C64       3
0091 
0092 static const int grip_btn_gp[]  = { BTN_TR, BTN_TL, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, -1 };
0093 static const int grip_btn_c64[] = { BTN_JOYSTICK, -1 };
0094 
0095 static const int grip_abs_gp[]  = { ABS_X, ABS_Y, -1 };
0096 static const int grip_abs_c64[] = { ABS_X, ABS_Y, -1 };
0097 
0098 static const int *grip_abs[] = { NULL, NULL, grip_abs_gp, grip_abs_c64 };
0099 static const int *grip_btn[] = { NULL, NULL, grip_btn_gp, grip_btn_c64 };
0100 
0101 static const char *grip_name[] = { NULL, NULL, "Gravis Grip Pad", "Commodore 64 Joystick" };
0102 
0103 static const int init_seq[] = {
0104     1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0105     1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,
0106     1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0107     0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1 };
0108 
0109 /* Maps multiport directional values to X,Y axis values (each axis encoded in 3 bits) */
0110 
0111 static const int axis_map[] = { 5, 9, 1, 5, 6, 10, 2, 6, 4, 8, 0, 4, 5, 9, 1, 5 };
0112 
0113 static int register_slot(int i, struct grip_mp *grip);
0114 
0115 /*
0116  * Returns whether an odd or even number of bits are on in pkt.
0117  */
0118 
0119 static int bit_parity(u32 pkt)
0120 {
0121     int x = pkt ^ (pkt >> 16);
0122     x ^= x >> 8;
0123     x ^= x >> 4;
0124     x ^= x >> 2;
0125     x ^= x >> 1;
0126     return x & 1;
0127 }
0128 
0129 /*
0130  * Poll gameport; return true if all bits set in 'onbits' are on and
0131  * all bits set in 'offbits' are off.
0132  */
0133 
0134 static inline int poll_until(u8 onbits, u8 offbits, int u_sec, struct gameport* gp, u8 *data)
0135 {
0136     int i, nloops;
0137 
0138     nloops = gameport_time(gp, u_sec);
0139     for (i = 0; i < nloops; i++) {
0140         *data = gameport_read(gp);
0141         if ((*data & onbits) == onbits &&
0142             (~(*data) & offbits) == offbits)
0143             return 1;
0144     }
0145     dbg("gameport timed out after %d microseconds.\n", u_sec);
0146     return 0;
0147 }
0148 
0149 /*
0150  * Gets a 28-bit packet from the multiport.
0151  *
0152  * After getting a packet successfully, commands encoded by sendcode may
0153  * be sent to the multiport.
0154  *
0155  * The multiport clock value is reflected in gameport bit B4.
0156  *
0157  * Returns a packet status code indicating whether packet is valid, the transfer
0158  * mode, and any error conditions.
0159  *
0160  * sendflags:      current I/O status
0161  * sendcode:   data to send to the multiport if sendflags is nonzero
0162  */
0163 
0164 static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet)
0165 {
0166     u8  raw_data;            /* raw data from gameport */
0167     u8  data_mask;           /* packet data bits from raw_data */
0168     u32 pkt;                 /* packet temporary storage */
0169     int bits_per_read;       /* num packet bits per gameport read */
0170     int portvals = 0;        /* used for port value sanity check */
0171     int i;
0172 
0173     /* Gameport bits B0, B4, B5 should first be off, then B4 should come on. */
0174 
0175     *packet = 0;
0176     raw_data = gameport_read(gameport);
0177     if (raw_data & 1)
0178         return IO_RETRY;
0179 
0180     for (i = 0; i < 64; i++) {
0181         raw_data = gameport_read(gameport);
0182         portvals |= 1 << ((raw_data >> 4) & 3); /* Demux B4, B5 */
0183     }
0184 
0185     if (portvals == 1) {                            /* B4, B5 off */
0186         raw_data = gameport_read(gameport);
0187         portvals = raw_data & 0xf0;
0188 
0189         if (raw_data & 0x31)
0190             return IO_RESET;
0191         gameport_trigger(gameport);
0192 
0193         if (!poll_until(0x10, 0, 308, gameport, &raw_data))
0194             return IO_RESET;
0195     } else
0196         return IO_RETRY;
0197 
0198     /* Determine packet transfer mode and prepare for packet construction. */
0199 
0200     if (raw_data & 0x20) {                 /* 3 data bits/read */
0201         portvals |= raw_data >> 4;     /* Compare B4-B7 before & after trigger */
0202 
0203         if (portvals != 0xb)
0204             return 0;
0205         data_mask = 7;
0206         bits_per_read = 3;
0207         pkt = (PACKET_FULL | PACKET_IO_FAST) >> 28;
0208     } else {                                 /* 1 data bit/read */
0209         data_mask = 1;
0210         bits_per_read = 1;
0211         pkt = (PACKET_FULL | PACKET_IO_SLOW) >> 28;
0212     }
0213 
0214     /* Construct a packet.  Final data bits must be zero. */
0215 
0216     while (1) {
0217         if (!poll_until(0, 0x10, 77, gameport, &raw_data))
0218             return IO_RESET;
0219         raw_data = (raw_data >> 5) & data_mask;
0220 
0221         if (pkt & PACKET_FULL)
0222             break;
0223         pkt = (pkt << bits_per_read) | raw_data;
0224 
0225         if (!poll_until(0x10, 0, 77, gameport, &raw_data))
0226             return IO_RESET;
0227     }
0228 
0229     if (raw_data)
0230         return IO_RESET;
0231 
0232     /* If 3 bits/read used, drop from 30 bits to 28. */
0233 
0234     if (bits_per_read == 3) {
0235         pkt = (pkt & 0xffff0000) | ((pkt << 1) & 0xffff);
0236         pkt = (pkt >> 2) | 0xf0000000;
0237     }
0238 
0239     if (bit_parity(pkt) == 1)
0240         return IO_RESET;
0241 
0242     /* Acknowledge packet receipt */
0243 
0244     if (!poll_until(0x30, 0, 77, gameport, &raw_data))
0245         return IO_RESET;
0246 
0247     raw_data = gameport_read(gameport);
0248 
0249     if (raw_data & 1)
0250         return IO_RESET;
0251 
0252     gameport_trigger(gameport);
0253 
0254     if (!poll_until(0, 0x20, 77, gameport, &raw_data))
0255         return IO_RESET;
0256 
0257         /* Return if we just wanted the packet or multiport wants to send more */
0258 
0259     *packet = pkt;
0260     if ((sendflags == 0) || ((sendflags & IO_RETRY) && !(pkt & PACKET_MP_DONE)))
0261         return IO_GOT_PACKET;
0262 
0263     if (pkt & PACKET_MP_MORE)
0264         return IO_GOT_PACKET | IO_RETRY;
0265 
0266     /* Multiport is done sending packets and is ready to receive data */
0267 
0268     if (!poll_until(0x20, 0, 77, gameport, &raw_data))
0269         return IO_GOT_PACKET | IO_RESET;
0270 
0271     raw_data = gameport_read(gameport);
0272     if (raw_data & 1)
0273         return IO_GOT_PACKET | IO_RESET;
0274 
0275     /* Trigger gameport based on bits in sendcode */
0276 
0277     gameport_trigger(gameport);
0278     do {
0279         if (!poll_until(0x20, 0x10, 116, gameport, &raw_data))
0280             return IO_GOT_PACKET | IO_RESET;
0281 
0282         if (!poll_until(0x30, 0, 193, gameport, &raw_data))
0283             return IO_GOT_PACKET | IO_RESET;
0284 
0285         if (raw_data & 1)
0286             return IO_GOT_PACKET | IO_RESET;
0287 
0288         if (sendcode & 1)
0289             gameport_trigger(gameport);
0290 
0291         sendcode >>= 1;
0292     } while (sendcode);
0293 
0294     return IO_GOT_PACKET | IO_MODE_FAST;
0295 }
0296 
0297 /*
0298  * Disables and restores interrupts for mp_io(), which does the actual I/O.
0299  */
0300 
0301 static int multiport_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet)
0302 {
0303     int status;
0304     unsigned long flags;
0305 
0306     local_irq_save(flags);
0307     status = mp_io(gameport, sendflags, sendcode, packet);
0308     local_irq_restore(flags);
0309 
0310     return status;
0311 }
0312 
0313 /*
0314  * Puts multiport into digital mode.  Multiport LED turns green.
0315  *
0316  * Returns true if a valid digital packet was received, false otherwise.
0317  */
0318 
0319 static int dig_mode_start(struct gameport *gameport, u32 *packet)
0320 {
0321     int i;
0322     int flags, tries = 0, bads = 0;
0323 
0324     for (i = 0; i < ARRAY_SIZE(init_seq); i++) {     /* Send magic sequence */
0325         if (init_seq[i])
0326             gameport_trigger(gameport);
0327         udelay(GRIP_INIT_DELAY);
0328     }
0329 
0330     for (i = 0; i < 16; i++)            /* Wait for multiport to settle */
0331         udelay(GRIP_INIT_DELAY);
0332 
0333     while (tries < 64 && bads < 8) {    /* Reset multiport and try getting a packet */
0334 
0335         flags = multiport_io(gameport, IO_RESET, 0x27, packet);
0336 
0337         if (flags & IO_MODE_FAST)
0338             return 1;
0339 
0340         if (flags & IO_RETRY)
0341             tries++;
0342         else
0343             bads++;
0344     }
0345     return 0;
0346 }
0347 
0348 /*
0349  * Packet structure: B0-B15   => gamepad state
0350  *                   B16-B20  => gamepad device type
0351  *                   B21-B24  => multiport slot index (1-4)
0352  *
0353  * Known device types: 0x1f (grip pad), 0x0 (no device).  Others may exist.
0354  *
0355  * Returns the packet status.
0356  */
0357 
0358 static int get_and_decode_packet(struct grip_mp *grip, int flags)
0359 {
0360     struct grip_port *port;
0361     u32 packet;
0362     int joytype = 0;
0363     int slot;
0364 
0365     /* Get a packet and check for validity */
0366 
0367     flags &= IO_RESET | IO_RETRY;
0368     flags = multiport_io(grip->gameport, flags, 0, &packet);
0369     grip->reads++;
0370 
0371     if (packet & PACKET_MP_DONE)
0372         flags |= IO_DONE;
0373 
0374     if (flags && !(flags & IO_GOT_PACKET)) {
0375         grip->bads++;
0376         return flags;
0377     }
0378 
0379     /* Ignore non-gamepad packets, e.g. multiport hardware version */
0380 
0381     slot = ((packet >> 21) & 0xf) - 1;
0382     if ((slot < 0) || (slot > 3))
0383         return flags;
0384 
0385     port = grip->port[slot];
0386 
0387     /*
0388      * Handle "reset" packets, which occur at startup, and when gamepads
0389      * are removed or plugged in.  May contain configuration of a new gamepad.
0390      */
0391 
0392     joytype = (packet >> 16) & 0x1f;
0393     if (!joytype) {
0394 
0395         if (port->registered) {
0396             printk(KERN_INFO "grip_mp: removing %s, slot %d\n",
0397                    grip_name[port->mode], slot);
0398             input_unregister_device(port->dev);
0399             port->registered = 0;
0400         }
0401         dbg("Reset: grip multiport slot %d\n", slot);
0402         port->mode = GRIP_MODE_RESET;
0403         flags |= IO_SLOT_CHANGE;
0404         return flags;
0405     }
0406 
0407     /* Interpret a grip pad packet */
0408 
0409     if (joytype == 0x1f) {
0410 
0411         int dir = (packet >> 8) & 0xf;          /* eight way directional value */
0412         port->buttons = (~packet) & 0xff;
0413         port->yaxes = ((axis_map[dir] >> 2) & 3) - 1;
0414         port->xaxes = (axis_map[dir] & 3) - 1;
0415         port->dirty = 1;
0416 
0417         if (port->mode == GRIP_MODE_RESET)
0418             flags |= IO_SLOT_CHANGE;
0419 
0420         port->mode = GRIP_MODE_GP;
0421 
0422         if (!port->registered) {
0423             dbg("New Grip pad in multiport slot %d.\n", slot);
0424             if (register_slot(slot, grip)) {
0425                 port->mode = GRIP_MODE_RESET;
0426                 port->dirty = 0;
0427             }
0428         }
0429         return flags;
0430     }
0431 
0432     /* Handle non-grip device codes.  For now, just print diagnostics. */
0433 
0434     {
0435         static int strange_code = 0;
0436         if (strange_code != joytype) {
0437             printk(KERN_INFO "Possible non-grip pad/joystick detected.\n");
0438             printk(KERN_INFO "Got joy type 0x%x and packet 0x%x.\n", joytype, packet);
0439             strange_code = joytype;
0440         }
0441     }
0442     return flags;
0443 }
0444 
0445 /*
0446  * Returns true if all multiport slot states appear valid.
0447  */
0448 
0449 static int slots_valid(struct grip_mp *grip)
0450 {
0451     int flags, slot, invalid = 0, active = 0;
0452 
0453     flags = get_and_decode_packet(grip, 0);
0454     if (!(flags & IO_GOT_PACKET))
0455         return 0;
0456 
0457     for (slot = 0; slot < 4; slot++) {
0458         if (grip->port[slot]->mode == GRIP_MODE_RESET)
0459             invalid = 1;
0460         if (grip->port[slot]->mode != GRIP_MODE_NONE)
0461             active = 1;
0462     }
0463 
0464     /* Return true if no active slot but multiport sent all its data */
0465     if (!active)
0466         return (flags & IO_DONE) ? 1 : 0;
0467 
0468     /* Return false if invalid device code received */
0469     return invalid ? 0 : 1;
0470 }
0471 
0472 /*
0473  * Returns whether the multiport was placed into digital mode and
0474  * able to communicate its state successfully.
0475  */
0476 
0477 static int multiport_init(struct grip_mp *grip)
0478 {
0479     int dig_mode, initialized = 0, tries = 0;
0480     u32 packet;
0481 
0482     dig_mode = dig_mode_start(grip->gameport, &packet);
0483     while (!dig_mode && tries < 4) {
0484         dig_mode = dig_mode_start(grip->gameport, &packet);
0485         tries++;
0486     }
0487 
0488     if (dig_mode)
0489         dbg("multiport_init(): digital mode activated.\n");
0490     else {
0491         dbg("multiport_init(): unable to activate digital mode.\n");
0492         return 0;
0493     }
0494 
0495     /* Get packets, store multiport state, and check state's validity */
0496     for (tries = 0; tries < 4096; tries++) {
0497         if (slots_valid(grip)) {
0498             initialized = 1;
0499             break;
0500         }
0501     }
0502     dbg("multiport_init(): initialized == %d\n", initialized);
0503     return initialized;
0504 }
0505 
0506 /*
0507  * Reports joystick state to the linux input layer.
0508  */
0509 
0510 static void report_slot(struct grip_mp *grip, int slot)
0511 {
0512     struct grip_port *port = grip->port[slot];
0513     int i;
0514 
0515     /* Store button states with linux input driver */
0516 
0517     for (i = 0; i < 8; i++)
0518         input_report_key(port->dev, grip_btn_gp[i], (port->buttons >> i) & 1);
0519 
0520     /* Store axis states with linux driver */
0521 
0522     input_report_abs(port->dev, ABS_X, port->xaxes);
0523     input_report_abs(port->dev, ABS_Y, port->yaxes);
0524 
0525     /* Tell the receiver of the events to process them */
0526 
0527     input_sync(port->dev);
0528 
0529     port->dirty = 0;
0530 }
0531 
0532 /*
0533  * Get the multiport state.
0534  */
0535 
0536 static void grip_poll(struct gameport *gameport)
0537 {
0538     struct grip_mp *grip = gameport_get_drvdata(gameport);
0539     int i, npkts, flags;
0540 
0541     for (npkts = 0; npkts < 4; npkts++) {
0542         flags = IO_RETRY;
0543         for (i = 0; i < 32; i++) {
0544             flags = get_and_decode_packet(grip, flags);
0545             if ((flags & IO_GOT_PACKET) || !(flags & IO_RETRY))
0546                 break;
0547         }
0548         if (flags & IO_DONE)
0549             break;
0550     }
0551 
0552     for (i = 0; i < 4; i++)
0553         if (grip->port[i]->dirty)
0554             report_slot(grip, i);
0555 }
0556 
0557 /*
0558  * Called when a joystick device file is opened
0559  */
0560 
0561 static int grip_open(struct input_dev *dev)
0562 {
0563     struct grip_mp *grip = input_get_drvdata(dev);
0564 
0565     gameport_start_polling(grip->gameport);
0566     return 0;
0567 }
0568 
0569 /*
0570  * Called when a joystick device file is closed
0571  */
0572 
0573 static void grip_close(struct input_dev *dev)
0574 {
0575     struct grip_mp *grip = input_get_drvdata(dev);
0576 
0577     gameport_stop_polling(grip->gameport);
0578 }
0579 
0580 /*
0581  * Tell the linux input layer about a newly plugged-in gamepad.
0582  */
0583 
0584 static int register_slot(int slot, struct grip_mp *grip)
0585 {
0586     struct grip_port *port = grip->port[slot];
0587     struct input_dev *input_dev;
0588     int j, t;
0589     int err;
0590 
0591     port->dev = input_dev = input_allocate_device();
0592     if (!input_dev)
0593         return -ENOMEM;
0594 
0595     input_dev->name = grip_name[port->mode];
0596     input_dev->id.bustype = BUS_GAMEPORT;
0597     input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS;
0598     input_dev->id.product = 0x0100 + port->mode;
0599     input_dev->id.version = 0x0100;
0600     input_dev->dev.parent = &grip->gameport->dev;
0601 
0602     input_set_drvdata(input_dev, grip);
0603 
0604     input_dev->open = grip_open;
0605     input_dev->close = grip_close;
0606 
0607     input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
0608 
0609     for (j = 0; (t = grip_abs[port->mode][j]) >= 0; j++)
0610         input_set_abs_params(input_dev, t, -1, 1, 0, 0);
0611 
0612     for (j = 0; (t = grip_btn[port->mode][j]) >= 0; j++)
0613         if (t > 0)
0614             set_bit(t, input_dev->keybit);
0615 
0616     err = input_register_device(port->dev);
0617     if (err) {
0618         input_free_device(port->dev);
0619         return err;
0620     }
0621 
0622     port->registered = 1;
0623 
0624     if (port->dirty)                /* report initial state, if any */
0625         report_slot(grip, slot);
0626 
0627     return 0;
0628 }
0629 
0630 static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
0631 {
0632     struct grip_mp *grip;
0633     int err;
0634 
0635     if (!(grip = kzalloc(sizeof(struct grip_mp), GFP_KERNEL)))
0636         return -ENOMEM;
0637 
0638     grip->gameport = gameport;
0639 
0640     gameport_set_drvdata(gameport, grip);
0641 
0642     err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
0643     if (err)
0644         goto fail1;
0645 
0646     gameport_set_poll_handler(gameport, grip_poll);
0647     gameport_set_poll_interval(gameport, 20);
0648 
0649     if (!multiport_init(grip)) {
0650         err = -ENODEV;
0651         goto fail2;
0652     }
0653 
0654     if (!grip->port[0]->mode && !grip->port[1]->mode && !grip->port[2]->mode && !grip->port[3]->mode) {
0655         /* nothing plugged in */
0656         err = -ENODEV;
0657         goto fail2;
0658     }
0659 
0660     return 0;
0661 
0662 fail2:  gameport_close(gameport);
0663 fail1:  gameport_set_drvdata(gameport, NULL);
0664     kfree(grip);
0665     return err;
0666 }
0667 
0668 static void grip_disconnect(struct gameport *gameport)
0669 {
0670     struct grip_mp *grip = gameport_get_drvdata(gameport);
0671     int i;
0672 
0673     for (i = 0; i < 4; i++)
0674         if (grip->port[i]->registered)
0675             input_unregister_device(grip->port[i]->dev);
0676     gameport_close(gameport);
0677     gameport_set_drvdata(gameport, NULL);
0678     kfree(grip);
0679 }
0680 
0681 static struct gameport_driver grip_drv = {
0682     .driver     = {
0683         .name   = "grip_mp",
0684     },
0685     .description    = DRIVER_DESC,
0686     .connect    = grip_connect,
0687     .disconnect = grip_disconnect,
0688 };
0689 
0690 module_gameport_driver(grip_drv);