From: <st...@us...> - 2004-06-23 14:01:57
|
Update of /cvsroot/gc-linux/linux/drivers/input In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6141 Added Files: Kconfig Makefile gamecube_keymap.h gamecube_si.c Log Message: First version of the new input driver. Detects standard pads and keyboard. --- NEW FILE: Kconfig --- # # Input device configuration # menu "Input device support" config INPUT tristate "Input devices (needed for keyboard, mouse, ...)" if EMBEDDED default y ---help--- Say Y here if you have any input device (mouse, keyboard, tablet, joystick, steering wheel ...) connected to your system and want it to be available to applications. This includes standard PS/2 keyboard and mouse. Say N here if you have a headless (no monitor, no keyboard) system. More information is available: <file:Documentation/input/input.txt> If unsure, say Y. To compile this driver as a module, choose M here: the module will be called input. comment "Userland interfaces" config INPUT_MOUSEDEV tristate "Mouse interface" if EMBEDDED default y depends on INPUT ---help--- Say Y here if you want your mouse to be accessible as char devices 13:32+ - /dev/input/mouseX and 13:63 - /dev/input/mice as an emulated IntelliMouse Explorer PS/2 mouse. That way, all user space programs (includung SVGAlib, GPM and X) will be able to use your mouse. If unsure, say Y. To compile this driver as a module, choose M here: the module will be called mousedev. config INPUT_MOUSEDEV_PSAUX bool "Provide legacy /dev/psaux device" default y depends on INPUT_MOUSEDEV ---help--- Say Y here if you want your mouse also be accessible as char device 10:1 - /dev/psaux. The data available through /dev/psaux is exactly the same as the data from /dev/input/mice. If unsure, say Y. config INPUT_MOUSEDEV_SCREEN_X int "Horizontal screen resolution" depends on INPUT_MOUSEDEV default "1024" help If you're using a digitizer, or a graphic tablet, and want to use it as a mouse then the mousedev driver needs to know the X window screen resolution you are using to correctly scale the data. If you're not using a digitizer, this value is ignored. config INPUT_MOUSEDEV_SCREEN_Y int "Vertical screen resolution" depends on INPUT_MOUSEDEV default "768" help If you're using a digitizer, or a graphic tablet, and want to use it as a mouse then the mousedev driver needs to know the X window screen resolution you are using to correctly scale the data. If you're not using a digitizer, this value is ignored. config INPUT_JOYDEV tristate "Joystick interface" depends on INPUT ---help--- Say Y here if you want your joystick or gamepad to be accessible as char device 13:0+ - /dev/input/jsX device. If unsure, say Y. More information is available: <file:Documentation/input/joystick.txt> To compile this driver as a module, choose M here: the module will be called joydev. config INPUT_TSDEV tristate "Touchscreen interface" depends on INPUT ---help--- Say Y here if you have an application that only can understand the Compaq touchscreen protocol for absolute pointer data. This is useful namely for embedded configurations. If unsure, say N. To compile this driver as a module, choose M here: the module will be called tsdev. config INPUT_TSDEV_SCREEN_X int "Horizontal screen resolution" depends on INPUT_TSDEV default "240" config INPUT_TSDEV_SCREEN_Y int "Vertical screen resolution" depends on INPUT_TSDEV default "320" config INPUT_EVDEV tristate "Event interface" depends on INPUT help Say Y here if you want your input device events be accessible under char device 13:64+ - /dev/input/eventX in a generic way. To compile this driver as a module, choose M here: the module will be called evdev. config INPUT_EVBUG tristate "Event debugging" depends on INPUT ---help--- Say Y here if you have a problem with the input subsystem and want all events (keypresses, mouse movements), to be output to the system log. While this is useful for debugging, it's also a security threat - your keypresses include your passwords, of course. If unsure, say N. To compile this driver as a module, choose M here: the module will be called evbug. comment "Input I/O drivers" config GAMECUBE_SI tristate "Gamecube SI driver" ---help--- Say Y here if you want to use the standard pads as joysticks or want to use a keyboard. Everything is autodetected. NOTE: Keyboard detection doesn't work 100%. Building this as a module is recommended, this way you can unload/load the driver to re-detect. source "drivers/input/gameport/Kconfig" source "drivers/input/serio/Kconfig" comment "Input Device Drivers" source "drivers/input/keyboard/Kconfig" source "drivers/input/mouse/Kconfig" source "drivers/input/joystick/Kconfig" source "drivers/input/touchscreen/Kconfig" source "drivers/input/misc/Kconfig" endmenu --- NEW FILE: Makefile --- # # Makefile for the input core drivers. # # Each configuration option enables a list of files. obj-$(CONFIG_INPUT) += input.o obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o obj-$(CONFIG_INPUT_JOYDEV) += joydev.o obj-$(CONFIG_INPUT_EVDEV) += evdev.o obj-$(CONFIG_INPUT_TSDEV) += tsdev.o obj-$(CONFIG_INPUT_POWER) += power.o obj-$(CONFIG_INPUT_EVBUG) += evbug.o obj-$(CONFIG_INPUT_KEYBOARD) += keyboard/ obj-$(CONFIG_INPUT_MOUSE) += mouse/ obj-$(CONFIG_INPUT_JOYSTICK) += joystick/ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/ obj-$(CONFIG_INPUT_MISC) += misc/ obj-$(CONFIG_GAMECUBE_SI) += gamecube_si.o --- NEW FILE: gamecube_keymap.h --- // keymap for a Datel adapater + US keyboard (not the normal keyboard) // not mapped: // printscreen / sysreq // scroll lcok // pause / break // numlock // windows key 1 // windows key 2 // windows menu key static unsigned char gamecube_keymap[] = { /* 00 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_HOME, KEY_END, /* 08 */ KEY_PAGEUP, KEY_PAGEDOWN, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, /* 10 */ KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, /* 18 */ KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, /* 20 */ KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W, KEY_X, /* 28 */ KEY_Y, KEY_Z, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, /* 30 */ KEY_7, KEY_8, KEY_9, KEY_0, KEY_MINUS, KEY_EQUAL, KEY_BACKSLASH, KEY_APOSTROPHE, /* 38 */ KEY_LEFTBRACE, KEY_EQUAL, KEY_KPASTERISK, KEY_RIGHTBRACE, KEY_COMMA, KEY_DOT, KEY_SLASH, KEY_RESERVED, /* 40 */ KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, /* 48 */ KEY_F9, KEY_F10, KEY_F11, KEY_F12, KEY_ESC, KEY_INSERT, KEY_DELETE, KEY_GRAVE, /* 50 */ KEY_BACKSPACE, KEY_TAB, KEY_RESERVED, KEY_CAPSLOCK, KEY_LEFTSHIFT, KEY_RIGHTSHIFT, KEY_LEFTCTRL, KEY_LEFTALT, /* 58 */ KEY_RESERVED, KEY_SPACE, KEY_RESERVED, KEY_RESERVED, KEY_LEFT, KEY_DOWN, KEY_UP, KEY_RIGHT, /* 60 */ KEY_RESERVED, KEY_ENTER, KEY_RESERVED, KEY_RESERVED, KEY_SEMICOLON, KEY_KPPLUS, KEY_RESERVED, KEY_RESERVED, /* 68 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, /* 70 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, /* 78 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, /* 80 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, /* 88 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, /* 90 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, /* 98 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, /* a0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, /* a8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, /* b0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, /* b8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, /* c0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, /* c8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, /* d0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, /* d8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, /* e0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, /* e8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, /* f0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, /* f8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED }; --- NEW FILE: gamecube_si.c --- #include <linux/input.h> #include <linux/module.h> #include <linux/init.h> #include <linux/ioport.h> #include <linux/timer.h> #include <linux/delay.h> #include <asm/io.h> // this keymap is for a datel adapter + normal US keyboard, if you need somehitng else // copy the keymap, edit it and change the #include #include "gamecube_keymap.h" MODULE_AUTHOR ("Steven Looman <st...@kr...>"); MODULE_DESCRIPTION ("Nintendo Gamecube controller input driver"); MODULE_LICENSE ("GPL"); #define REFRESH_TIME HZ/100 #define SICOUTBUF(x) (0xCC006400 + x * 12) #define SICINBUFH(x) (0xCC006404 + x * 12) #define SICINBUFL(x) (0xCC006408 + x * 12) #define SIPOLL 0xCC006430 #define SICOMCSR 0xCC006434 #define SISR 0xCC006438 #define SIEXILK 0xCC00643C #define ID_PAD 0x0900 #define ID_KEYBOARD 0x0820 #define ID_GBA 0x0004 #define ID_GBA_NA 0x0800 #define ID_WAVEBIRD 0xa800 #define ID_WAVEBIRD_RCV 0xe960 #define PAD_START (1 << 28) #define PAD_Y (1 << 27) #define PAD_X (1 << 26) #define PAD_B (1 << 25) #define PAD_A (1 << 24) #define PAD_LT (1 << 22) #define PAD_RT (1 << 21) #define PAD_Z (1 << 20) #define PAD_UP (1 << 19) #define PAD_DOWN (1 << 18) #define PAD_RIGHT (1 << 17) #define PAD_LEFT (1 << 16) //#define GCSIDEBUG static struct resource resources = { "Gamecube SI", 0xCC006400, 0xCC006500, IORESOURCE_MEM|IORESOURCE_BUSY }; typedef struct { unsigned char key[3]; unsigned char old[3]; } keyboardStatus; struct { unsigned int id; unsigned int raw[2]; unsigned char errStat : 1; unsigned char errLatch : 1; struct input_dev inputDev; struct timer_list timer; union { keyboardStatus keyboard; }; char name[32]; // char phys[32]; } port[4]; static void resetSi (void) { int i; // clear si registers // SICOUTBUF for (i = 0; i < 4; ++i) writel (0, SICOUTBUF (i)); // SICINBUFH for (i = 0; i < 4; ++i) writel (0, SICINBUFH (i)); // SICINBUFL for (i = 0; i < 4; ++i) writel (0, SICINBUFL (i)); writel (0, SIPOLL); writel (0, SICOMCSR); writel (0, SISR); writel (0, 0xCC006480); writel (0, 0xCC006484); writel (0, 0xCC006488); writel (0, 0xCC00648c); writel (0, 0xCC006490); writel (0, 0xCC006494); writel (0, 0xCC006498); writel (0, 0xCC00649c); writel (0, 0xCC0064a0); writel (0, 0xCC0064a4); writel (0, 0xCC0064a8); writel (0, 0xCC0064ac); } static void waitTransferDone (void) { unsigned long transferDone; do { transferDone = readl (SICOMCSR) & (1 << 31); } while (!transferDone); writel (readl (SICOMCSR) |= (1 << 31), SICOMCSR); // mask IRQ } static unsigned long getControllerID (int port) { resetSi(); writel (0, SIPOLL); writel (0, SICOUTBUF (port)); writel (0x80000000, SISR); writel (0xD0010001 | port << 1, SICOMCSR); waitTransferDone(); return readl (0xCC006480); } static void setPolling (void) { unsigned long padBits = 0; int i; for (i = 0; i < 4; ++i) { switch (port[i].id) { case ID_PAD: writel (0x00400300, SICOUTBUF (i)); break; case ID_KEYBOARD: writel (0x00540000, SICOUTBUF (i)); break; } padBits |= 1 << (7 - i); } writel (0x00F70200 | padBits, SIPOLL); writel (0x80000000, SISR); writel (0xC0010801, SICOMCSR); waitTransferDone(); } static void gcSiTimer (unsigned long portNo) { int i; unsigned long raw[2]; raw[0] = readl (SICINBUFH (portNo)); raw[1] = readl (SICINBUFL (portNo)); switch (port[portNo].id) { case ID_PAD: // buttons input_report_key (&port[portNo].inputDev, BTN_A, raw[0] & PAD_A); input_report_key (&port[portNo].inputDev, BTN_B, raw[0] & PAD_B); input_report_key (&port[portNo].inputDev, BTN_X, raw[0] & PAD_X); input_report_key (&port[portNo].inputDev, BTN_Y, raw[0] & PAD_Y); input_report_key (&port[portNo].inputDev, BTN_Z, raw[0] & PAD_Z); input_report_key (&port[portNo].inputDev, BTN_TL, raw[0] & PAD_LT); input_report_key (&port[portNo].inputDev, BTN_TR, raw[0] & PAD_RT); input_report_key (&port[portNo].inputDev, BTN_START, raw[0] & PAD_START); // axis // a stick input_report_abs (&port[portNo].inputDev, ABS_X, raw[0] >> 8 & 0xFF); input_report_abs (&port[portNo].inputDev, ABS_Y, raw[0] >> 0 & 0xFF); // b pad if (raw[0] & PAD_RIGHT) input_report_abs (&port[portNo].inputDev, ABS_HAT0X, 1); else if (raw[0] & PAD_LEFT) input_report_abs (&port[portNo].inputDev, ABS_HAT0X, -1); else input_report_abs (&port[portNo].inputDev, ABS_HAT0X, 0); if (raw[0] & PAD_UP) input_report_abs (&port[portNo].inputDev, ABS_HAT0Y, 1); else if (raw[0] & PAD_DOWN) input_report_abs (&port[portNo].inputDev, ABS_HAT0Y, -1); else input_report_abs (&port[portNo].inputDev, ABS_HAT0Y, 0); // c stick input_report_abs (&port[portNo].inputDev, ABS_RX, raw[1] >> 24 & 0xFF); input_report_abs (&port[portNo].inputDev, ABS_RY, raw[1] >> 16 & 0xFF); // triggers input_report_abs (&port[portNo].inputDev, ABS_BRAKE, raw[1] >> 8 & 0xFF); input_report_abs (&port[portNo].inputDev, ABS_GAS, raw[1] >> 0 & 0xFF); break; case ID_KEYBOARD: port[portNo].keyboard.key[0] = (raw[0] >> 12) & 0xFF; port[portNo].keyboard.key[1] = (raw[0] >> 4) & 0xFF; port[portNo].keyboard.key[2] = (raw[0] << 4) & 0xFF; port[portNo].keyboard.key[2]|= (raw[1] << 28) & 0xFF; // check if anything was released for (i = 0; i < 3; ++i) { unsigned char key = port[portNo].keyboard.old[i]; if (key != port[portNo].keyboard.key[0] && key != port[portNo].keyboard.key[1] && key != port[portNo].keyboard.key[2]) input_report_key (&port[portNo].inputDev, gamecube_keymap[key], 0); } // reports keys for (i = 0; i < 3; ++i) { unsigned char key = port[portNo].keyboard.key[i]; if (key) input_report_key (&port[portNo].inputDev, gamecube_keymap[key], 1); port[portNo].keyboard.old[i] = port[portNo].keyboard.key[i]; } break; default: break; } input_sync(&port[portNo].inputDev); mod_timer (&port[portNo].timer, jiffies + REFRESH_TIME); } static int gcSiOpen (struct input_dev *inputDev) { int portNo = (int)inputDev->private; init_timer (&port[portNo].timer); port[portNo].timer.function = gcSiTimer; port[portNo].timer.data = (int)inputDev->private; port[portNo].timer.expires = jiffies + REFRESH_TIME; add_timer (&port[portNo].timer); return 0; } static void gcSiClose (struct input_dev *inputDev) { int portNo = (int)inputDev->private; del_timer (&port[portNo].timer); } static int __init gcSiInit(void) { int i; printk (KERN_WARNING "Gamecube SI: init\n"); if (request_resource (&iomem_resource, &resources) < 0) { printk (KERN_WARNING "Gamecube SI: resource busy\n"); return -EBUSY; } for (i = 0; i < 4; ++i) { int j; memset (&port[i], 0, sizeof (port[i])); // probe ports port[i].id = getControllerID(i) >> 16; #ifdef GCSIDEBUG printk (KERN_WARNING "Gamecube SI: port[%d] = 0x%x\n", i, port[i].id); #endif init_input_dev (&port[i].inputDev); port[i].inputDev.open = gcSiOpen; port[i].inputDev.close = gcSiClose; port[i].inputDev.private = (unsigned int *)i; printk (KERN_WARNING "Gamecube Si: Port %d: ", i); switch (port[i].id) { case ID_PAD: printk (KERN_WARNING "standard pad\n"); sprintf (port[i].name, "Gamecube standard pad"); port[i].inputDev.name = port[i].name; // sprintf (port[i].phys, "gcsi/port%d", i); // port[i].inputDev.phys = port[i].phys; set_bit (EV_KEY, port[i].inputDev.evbit); set_bit (EV_ABS, port[i].inputDev.evbit); set_bit (BTN_A, port[i].inputDev.keybit); set_bit (BTN_B, port[i].inputDev.keybit); set_bit (BTN_X, port[i].inputDev.keybit); set_bit (BTN_Y, port[i].inputDev.keybit); set_bit (BTN_Z, port[i].inputDev.keybit); set_bit (BTN_TL, port[i].inputDev.keybit); set_bit (BTN_TR, port[i].inputDev.keybit); set_bit (BTN_START, port[i].inputDev.keybit); // a stick set_bit (ABS_X, port[i].inputDev.absbit); port[i].inputDev.absmin[ABS_X] = 0; port[i].inputDev.absmax[ABS_X] = 255; port[i].inputDev.absfuzz[ABS_X] = 8; port[i].inputDev.absflat[ABS_X] = 8; set_bit (ABS_Y, port[i].inputDev.absbit); port[i].inputDev.absmin[ABS_Y] = 0; port[i].inputDev.absmax[ABS_Y] = 255; port[i].inputDev.absfuzz[ABS_Y] = 8; port[i].inputDev.absflat[ABS_Y] = 8; // b pad set_bit (ABS_HAT0X, port[i].inputDev.absbit); port[i].inputDev.absmin[ABS_HAT0X] = -1; port[i].inputDev.absmax[ABS_HAT0X] = 1; set_bit (ABS_HAT0Y, port[i].inputDev.absbit); port[i].inputDev.absmin[ABS_HAT0Y] = -1; port[i].inputDev.absmax[ABS_HAT0Y] = 1; // c stick set_bit (ABS_RX, port[i].inputDev.absbit); port[i].inputDev.absmin[ABS_RX] = 0; port[i].inputDev.absmax[ABS_RX] = 255; port[i].inputDev.absfuzz[ABS_RX] = 8; port[i].inputDev.absflat[ABS_RX] = 8; set_bit (ABS_RY, port[i].inputDev.absbit); port[i].inputDev.absmin[ABS_RY] = 0; port[i].inputDev.absmax[ABS_RY] = 255; port[i].inputDev.absfuzz[ABS_RY] = 8; port[i].inputDev.absflat[ABS_RY] = 8; // triggers set_bit (ABS_GAS, port[i].inputDev.absbit); port[i].inputDev.absmin[ABS_GAS] = -255; port[i].inputDev.absmax[ABS_GAS] = 255; port[i].inputDev.absfuzz[ABS_GAS] = 16; port[i].inputDev.absflat[ABS_GAS] = 16; set_bit (ABS_BRAKE, port[i].inputDev.absbit); port[i].inputDev.absmin[ABS_BRAKE] = -255; port[i].inputDev.absmax[ABS_BRAKE] = 255; port[i].inputDev.absfuzz[ABS_BRAKE] = 16; port[i].inputDev.absflat[ABS_BRAKE] = 16; input_register_device (&port[i].inputDev); break; case ID_KEYBOARD: printk (KERN_WARNING "keyboard\n"); set_bit (EV_KEY, port[i].inputDev.evbit); set_bit (EV_REP, port[i].inputDev.evbit); for (j = 0; j < 255; ++j) set_bit (gamecube_keymap[j], port[i].inputDev.keybit); input_register_device (&port[i].inputDev); break; default: // unknown device if (port[i].id) printk (KERN_WARNING "unknown device (%x)\n", port[i].id); else printk (KERN_WARNING "no device\n"); break; } } setPolling(); return 0; } static void __exit gcSiExit(void) { int i; printk (KERN_WARNING "Gamecube SI: exit\n"); for (i = 0; i < 4; ++i) if (port[i].id == ID_PAD || port[i].id == ID_KEYBOARD) input_unregister_device (&port[i].inputDev); release_resource (&resources); } module_init (gcSiInit); module_exit (gcSiExit); |