// SPDX-License-Identifier: GPL-2.0-or-later
/*
* NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux
*
* Copyright (c) 1999-2004 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2004 Peter Nelson <rufus-kernel@hackish.org>
*
* Based on the work of:
* Andree Borrmann John Dahlstrom
* David Kuder Nathan Hand
* Raphael Assenat
*/
/*
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/parport.h>
#include <linux/input.h>
#include <linux/mutex.h>
#include <linux/slab.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("NES, SNES, N64, MultiSystem, PSX gamepad driver");
MODULE_LICENSE("GPL");
#define GC_MAX_PORTS 3
#define GC_MAX_DEVICES 5
struct gc_config {
int args[GC_MAX_DEVICES + 1];
unsigned int nargs;
};
static struct gc_config gc_cfg[GC_MAX_PORTS];
module_param_array_named(map, gc_cfg[0].args, int, &gc_cfg[0].nargs, 0);
MODULE_PARM_DESC(map, "Describes first set of devices (<parport#>,<pad1>,<pad2>,..<pad5>)");
module_param_array_named(map2, gc_cfg[1].args, int, &gc_cfg[1].nargs, 0);
MODULE_PARM_DESC(map2, "Describes second set of devices");
module_param_array_named(map3, gc_cfg[2].args, int, &gc_cfg[2].nargs, 0);
MODULE_PARM_DESC(map3, "Describes third set of devices");
/* see also gs_psx_delay parameter in PSX support section */
enum gc_type {
GC_NONE = 0,
GC_SNES,
GC_NES,
GC_NES4,
GC_MULTI,
GC_MULTI2,
GC_N64,
GC_PSX,
GC_DDR,
GC_SNESMOUSE,
GC_MAX
};
#define GC_REFRESH_TIME HZ/100
struct gc_pad {
struct input_dev *dev;
enum gc_type type;
char phys[32];
};
struct gc {
struct pardevice *pd;
struct gc_pad pads[GC_MAX_DEVICES];
struct timer_list timer;
int pad_count[GC_MAX];
int used;
int parportno;
struct mutex mutex;
};
struct gc_subdev {
unsigned int idx;
};
static struct gc *gc_base[3];
static const int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
static const char *gc_names[] = {
NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick",
"Multisystem 2-button joystick", "N64 controller", "PSX controller",
"PSX DDR controller", "SNES mouse"
};
/*
* N64 support.
*/
static const unsigned char gc_n64_bytes[] = { 0, 1, 13, 15, 14, 12, 10, 11, 2, 3 };
static const short gc_n64_btn[] = {
BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z,
BTN_TL, BTN_TR, BTN_TRIGGER, BTN_START
};
#define GC_N64_LENGTH 32 /* N64 bit length, not including stop bit */
#define GC_N64_STOP_LENGTH 5 /* Length of encoded stop bit */
#define GC_N64_CMD_00 0x11111111UL
#define GC_N64_CMD_01 0xd1111111UL
#define GC_N64_CMD_03 0xdd111111UL
#define GC_N64_CMD_1b 0xdd1dd111UL
#define GC_N64_CMD_c0 0x111111ddUL
#define GC_N64_CMD_80 0x1111111dUL
#define GC_N64_STOP_BIT 0x1d /* Encoded stop bit */
#define GC_N64_REQUEST_DATA GC_N64_CMD_01 /* the request data command */
#define GC_N64_DELAY 133 /* delay between transmit request, and response ready (us) */
#define GC_N64_DWS 3 /* delay between write segments (required for sound playback because of ISA DMA) */
/* GC_N64_DWS > 24 is known to fail */
#define GC_N64_POWER_W 0xe2 /* power during write (transmit request) */
#define GC_N64_POWER_R 0xfd /* power during read */
#define GC_N64_OUT 0x1d /* output bits to the 4 pads */
/* Reading the main axes of any N64 pad is known to fail if the corresponding bit */
/* in GC_N64_OUT is pulled low on the output port (by any routine) for more */
/* than 123 us */
#define GC_N64_CLOCK 0x02 /* clock bits for read */
/*
* Used for rumble code.
*/
/* Send encoded command */
static void gc_n64_send_command(struct gc *gc, unsigned long cmd,
unsigned char target)
{
struct parport *port = gc->pd->port;
int i;
for (i = 0; i < GC_N64_LENGTH; i++) {
unsigned char data = (cmd >> i) & 1 ? target : 0;
parport_write_data(port, GC_N64_POWER_W | data);
udelay(GC_N64_DWS);
}
}
/* Send stop bit */
static void gc_n64_send_stop_bit(struct gc *gc, unsigned char target)
{
struct parport *port = gc->pd->port;
int i;
for (i = 0; i < GC_N64_STOP_LENGTH; i++) {
unsigned char data = (GC_N64_STOP_BIT >> i) & 1 ? target : 0;
parport_write_data(port, GC_N64_POWER_W | data);
udelay(GC_N64_DWS);
}
}
/*
* gc_n64_read_packet() reads an N64 packet.
* Each pad uses one bit per byte. So all pads connected to this port
* are read in parallel.
*/
static void gc_n64_read_packet(struct gc *gc, unsigned char *data)
{
int i;
unsigned long flags;
/*
* Request the pad to transmit data
*/
local_irq_save(flags);
gc_n64_send_command(gc, GC_N64_REQUEST_DATA, GC_N64_OUT);
gc_n64_send_stop_bit(gc, GC_N64_OUT);
local_irq_restore(flags);
/*
* Wait for the pad response to be loaded into the 33-bit register
* of the adapter.
*/
udelay(GC_N64_DELAY);
/*
* Grab data (ignoring the last bit, which is a stop bit)
*/
for (i = 0; i < GC_N64_LENGTH; i++) {
parport_write_data(gc->pd->port, GC_N64_POWER_R);
udelay(2);
data[i] = parport_read_status(