// SPDX-License-Identifier: GPL-2.0-only /* * Driver for the Gravis Grip Multiport, a gamepad "hub" that * connects up to four 9-pin digital gamepads/joysticks. * Driver tested on SMP and UP kernel versions 2.4.18-4 and 2.4.18-5. * * Thanks to Chris Gassib for helpful advice. * * Copyright (c) 2002 Brian Bonnlander, Bill Soudan * Copyright (c) 1998-2000 Vojtech Pavlik */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/gameport.h> #include <linux/input.h> #include <linux/delay.h> #include <linux/proc_fs.h> #include <linux/jiffies.h> #define DRIVER_DESC … MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…); MODULE_LICENSE(…) …; #ifdef GRIP_DEBUG #define dbg … #else #define dbg(format, arg...) … #endif #define GRIP_MAX_PORTS … /* * Grip multiport state */ struct grip_port { … }; struct grip_mp { … }; /* * Multiport packet interpretation */ #define PACKET_FULL … #define PACKET_IO_FAST … #define PACKET_IO_SLOW … #define PACKET_MP_MORE … #define PACKET_MP_DONE … /* * Packet status code interpretation */ #define IO_GOT_PACKET … #define IO_MODE_FAST … #define IO_SLOT_CHANGE … #define IO_DONE … #define IO_RETRY … #define IO_RESET … /* * Gamepad configuration data. Other 9-pin digital joystick devices * may work with the multiport, so this may not be an exhaustive list! * Commodore 64 joystick remains untested. */ #define GRIP_INIT_DELAY … #define GRIP_MODE_NONE … #define GRIP_MODE_RESET … #define GRIP_MODE_GP … #define GRIP_MODE_C64 … static const int grip_btn_gp[] = …; static const int grip_btn_c64[] = …; static const int grip_abs_gp[] = …; static const int grip_abs_c64[] = …; static const int *grip_abs[] = …; static const int *grip_btn[] = …; static const char *grip_name[] = …; static const int init_seq[] = …; /* Maps multiport directional values to X,Y axis values (each axis encoded in 3 bits) */ static const int axis_map[] = …; static int register_slot(int i, struct grip_mp *grip); /* * Returns whether an odd or even number of bits are on in pkt. */ static int bit_parity(u32 pkt) { … } /* * Poll gameport; return true if all bits set in 'onbits' are on and * all bits set in 'offbits' are off. */ static inline int poll_until(u8 onbits, u8 offbits, int u_sec, struct gameport* gp, u8 *data) { … } /* * Gets a 28-bit packet from the multiport. * * After getting a packet successfully, commands encoded by sendcode may * be sent to the multiport. * * The multiport clock value is reflected in gameport bit B4. * * Returns a packet status code indicating whether packet is valid, the transfer * mode, and any error conditions. * * sendflags: current I/O status * sendcode: data to send to the multiport if sendflags is nonzero */ static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet) { … } /* * Disables and restores interrupts for mp_io(), which does the actual I/O. */ static int multiport_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet) { … } /* * Puts multiport into digital mode. Multiport LED turns green. * * Returns true if a valid digital packet was received, false otherwise. */ static int dig_mode_start(struct gameport *gameport, u32 *packet) { … } /* * Packet structure: B0-B15 => gamepad state * B16-B20 => gamepad device type * B21-B24 => multiport slot index (1-4) * * Known device types: 0x1f (grip pad), 0x0 (no device). Others may exist. * * Returns the packet status. */ static int get_and_decode_packet(struct grip_mp *grip, int flags) { … } /* * Returns true if all multiport slot states appear valid. */ static int slots_valid(struct grip_mp *grip) { … } /* * Returns whether the multiport was placed into digital mode and * able to communicate its state successfully. */ static int multiport_init(struct grip_mp *grip) { … } /* * Reports joystick state to the linux input layer. */ static void report_slot(struct grip_mp *grip, int slot) { … } /* * Get the multiport state. */ static void grip_poll(struct gameport *gameport) { … } /* * Called when a joystick device file is opened */ static int grip_open(struct input_dev *dev) { … } /* * Called when a joystick device file is closed */ static void grip_close(struct input_dev *dev) { … } /* * Tell the linux input layer about a newly plugged-in gamepad. */ static int register_slot(int slot, struct grip_mp *grip) { … } static int grip_connect(struct gameport *gameport, struct gameport_driver *drv) { … } static void grip_disconnect(struct gameport *gameport) { … } static struct gameport_driver grip_drv = …; module_gameport_driver(…) …;