// 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
*/
struct gc_config { int args[GC_MAX_DEVICES + 1]; unsignedint nargs;
};
staticstruct 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 */
#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 */
/* * 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(gc->pd->port);
parport_write_data(gc->pd->port, GC_N64_POWER_R | GC_N64_CLOCK);
}
/* * We must wait 200 ms here for the controller to reinitialize before * the next read request. No worries as long as gc_read is polled less * frequently than this.
*/
}
staticvoid gc_n64_process_packet(struct gc *gc)
{ unsignedchar data[GC_N64_LENGTH]; struct input_dev *dev; int i, j, s; signedchar x, y;
gc_n64_read_packet(gc, data);
for (i = 0; i < GC_MAX_DEVICES; i++) {
if (gc->pads[i].type != GC_N64) continue;
dev = gc->pads[i].dev;
s = gc_status_bit[i];
if (s & ~(data[8] | data[9])) {
x = y = 0;
for (j = 0; j < 8; j++) { if (data[23 - j] & s)
x |= 1 << j; if (data[31 - j] & s)
y |= 1 << j;
}
#define GC_NES_DELAY 6/* Delay between bits - 6us */ #define GC_NES_LENGTH 8/* The NES pads use 8 bits of data */ #define GC_SNES_LENGTH 12/* The SNES true length is 16, but the
last 4 bits are unused */ #define GC_SNESMOUSE_LENGTH 32/* The SNES mouse uses 32 bits, the first
16 bits are equivalent to a gamepad */
for (j = 0; j < 8; j++)
input_report_key(dev, gc_snes_btn[j],
s & data[gc_snes_bytes[j]]);
input_sync(dev); break;
case GC_SNESMOUSE: /* * The 4 unused bits from SNES controllers appear * to be ID bits so use them to make sure we are * dealing with a mouse. * gamepad is connected. This is important since * my SNES gamepad sends 1's for bits 16-31, which * cause the mouse pointer to quickly move to the * upper left corner of the screen.
*/ if (!(s & data[12]) && !(s & data[13]) &&
!(s & data[14]) && (s & data[15])) {
input_report_key(dev, BTN_LEFT, s & data[9]);
input_report_key(dev, BTN_RIGHT, s & data[8]);
#define GC_PSX_DELAY 25/* 25 usec */ #define GC_PSX_LENGTH 8/* talk to the controller in bits */ #define GC_PSX_BYTES 6/* the maximum number of bytes to read off the controller */
#define GC_PSX_MOUSE 1/* Mouse */ #define GC_PSX_NEGCON 2/* NegCon */ #define GC_PSX_NORMAL 4/* Digital / Analog or Rumble in Digital mode */ #define GC_PSX_ANALOG 5/* Analog in Analog mode / Rumble in Green mode */ #define GC_PSX_RUMBLE 7/* Rumble in Red mode */
/* * For some reason if the extra axes are left unset * they drift. * for (i = 0; i < 4; i++) input_report_abs(dev, gc_psx_abs[i + 2], 128); * This needs to be debugged properly, * maybe fuzz processing needs to be done * in input_sync() * --vojtech
*/
}
for (i = 0; i < 8; i++)
input_report_key(dev, gc_psx_btn[i], ~data[1] & (1 << i));
case GC_SNES: for (i = 4; i < 8; i++)
input_set_capability(input_dev, EV_KEY, gc_snes_btn[i]);
fallthrough;
case GC_NES: for (i = 0; i < 4; i++)
input_set_capability(input_dev, EV_KEY, gc_snes_btn[i]); break;
case GC_MULTI2:
input_set_capability(input_dev, EV_KEY, BTN_THUMB);
fallthrough;
case GC_MULTI:
input_set_capability(input_dev, EV_KEY, BTN_TRIGGER); break;
case GC_PSX: for (i = 0; i < 6; i++)
input_set_abs_params(input_dev,
gc_psx_abs[i], 4, 252, 0, 2); for (i = 0; i < 12; i++)
input_set_capability(input_dev, EV_KEY, gc_psx_btn[i]); break;
break;
case GC_DDR: for (i = 0; i < 4; i++)
input_set_capability(input_dev, EV_KEY,
gc_psx_ddr_btn[i]); for (i = 0; i < 12; i++)
input_set_capability(input_dev, EV_KEY, gc_psx_btn[i]);
break;
}
err = input_register_device(pad->dev); if (err) goto err_free_dev;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.