From: <he...@us...> - 2004-10-19 23:55:53
|
Update of /cvsroot/gc-linux/linux/drivers/input In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2920/drivers/input Modified Files: Kconfig Makefile Added Files: gcn-keymap.h gcn-si.c Removed Files: gamecube_keymap.h gamecube_si.c Log Message: - Made the Serial Interface driver depend on GAMECUBE. - Renamed gamecube_keymap.h as gcn-keymap.h. - Renamed gamecube_si.c as gcn-si.c. Also renamed parts of the code accordingly and sanitized comments. Changed slightly the way input devices are reported on init. --- NEW FILE: gcn-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: gcn-si.c --- /* * drivers/input/gcn-si.c * * Nintendo GameCube Serial Interface driver * Copyright (C) 2004 Steven Looman * Copyright (C) 2004 The GameCube Linux Team * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * */ /* #define SI_DEBUG */ #include <linux/module.h> #include <linux/init.h> #include <linux/input.h> #include <linux/ioport.h> #include <linux/timer.h> #include <linux/delay.h> #include <asm/io.h> #ifdef SI_DEBUG # define DPRINTK(fmt, args...) \ printk(KERN_ERR "%s: " fmt, __FUNCTION__ , ## args) #else # define DPRINTK(fmt, args...) #endif #define DRV_MODULE_NAME "gcn-si" #define DRV_DESCRIPTION "Nintendo GameCube Serial Interface driver" #define DRV_AUTHOR "Steven Looman <st...@kr...>" MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_AUTHOR(DRV_AUTHOR); MODULE_LICENSE(GPL); #define PFX DRV_MODULE_NAME ": " #define si_printk(level, format, arg...) \ printk(level PFX format , ## arg) /* * This keymap is for a datel adapter + normal US keyboard. */ #include "gcn-keymap.h" #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) static struct resource gcn_si_resources = { "GCN SI", 0xcc006400, 0xcc006500, IORESOURCE_MEM | IORESOURCE_BUSY }; typedef struct { unsigned char old[3]; } keyboard_status; struct { unsigned int id; unsigned int raw[2]; #if 0 unsigned char errStat:1; unsigned char errLatch:1; #endif struct input_dev idev; struct timer_list timer; union { keyboard_status keyboard; }; char name[32]; /* char phys[32]; */ } port[4]; /** * */ static void gcn_si_reset(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 gcn_si_wait_transfer_done(void) { unsigned long transfer_done; do { transfer_done = readl(SICOMCSR) & (1 << 31); } while (!transfer_done); writel(readl(SICOMCSR) |= (1 << 31), SICOMCSR); /* ack IRQ */ } /** * */ static unsigned long gcn_si_get_controller_id(int port) { gcn_si_reset(); writel(0, SIPOLL); writel(0, SICOUTBUF(port)); writel(0x80000000, SISR); writel(0xd0010001 | port << 1, SICOMCSR); gcn_si_wait_transfer_done(); return readl(0xcc006480); } /** * */ static void gcn_si_set_polling(void) { unsigned long pad_bits = 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; } pad_bits |= 1 << (7 - i); } writel(0x00F70200 | pad_bits, SIPOLL); writel(0x80000000, SISR); writel(0xC0010801, SICOMCSR); gcn_si_wait_transfer_done(); } /** * */ static void gcn_si_set_rumbling(int portno, int rumble) { if (rumble) { writel(0x00400001, SICOUTBUF(portno)); writel(0x80000000, SISR); } else { writel(0x00400000, SICOUTBUF(portno)); writel(0x80000000, SISR); } } /** * */ static void gcn_si_timer(unsigned long portno) { unsigned long raw[2]; unsigned char key[3]; unsigned char oldkey; int i; raw[0] = readl(SICINBUFH(portno)); raw[1] = readl(SICINBUFL(portno)); switch (port[portno].id) { case ID_PAD: /* buttons */ input_report_key(&port[portno].idev, BTN_A, raw[0] & PAD_A); input_report_key(&port[portno].idev, BTN_B, raw[0] & PAD_B); input_report_key(&port[portno].idev, BTN_X, raw[0] & PAD_X); input_report_key(&port[portno].idev, BTN_Y, raw[0] & PAD_Y); input_report_key(&port[portno].idev, BTN_Z, raw[0] & PAD_Z); input_report_key(&port[portno].idev, BTN_TL, raw[0] & PAD_LT); input_report_key(&port[portno].idev, BTN_TR, raw[0] & PAD_RT); input_report_key(&port[portno].idev, BTN_START, raw[0] & PAD_START); /* axis */ /* a stick */ input_report_abs(&port[portno].idev, ABS_X, (raw[0] >> 8) & 0xFF); input_report_abs(&port[portno].idev, ABS_Y, -(raw[0] >> 0) & 0xFF); /* b pad */ if (raw[0] & PAD_RIGHT) input_report_abs(&port[portno].idev, ABS_HAT0X, 1); else if (raw[0] & PAD_LEFT) input_report_abs(&port[portno].idev, ABS_HAT0X, -1); else input_report_abs(&port[portno].idev, ABS_HAT0X, 0); if (raw[0] & PAD_UP) input_report_abs(&port[portno].idev, ABS_HAT0Y, 1); else if (raw[0] & PAD_DOWN) input_report_abs(&port[portno].idev, ABS_HAT0Y, -1); else input_report_abs(&port[portno].idev, ABS_HAT0Y, 0); /* c stick */ input_report_abs(&port[portno].idev, ABS_RX, raw[1] >> 24 & 0xFF); input_report_abs(&port[portno].idev, ABS_RY, raw[1] >> 16 & 0xFF); /* triggers */ input_report_abs(&port[portno].idev, ABS_BRAKE, raw[1] >> 8 & 0xFF); input_report_abs(&port[portno].idev, ABS_GAS, raw[1] >> 0 & 0xFF); break; case ID_KEYBOARD: key[0] = (raw[0] >> 12) & 0xFF; key[1] = (raw[0] >> 4) & 0xFF; key[2] = (raw[0] << 4) & 0xFF; key[2] |= (raw[1] << 28) & 0xFF; /* check if anything was released */ for (i = 0; i < 3; ++i) { oldkey = port[portno].keyboard.old[i]; if (oldkey != key[0] && oldkey != key[1] && oldkey != key[2]) input_report_key(&port[portno].idev, gamecube_keymap[oldkey], 0); } /* report keys */ for (i = 0; i < 3; ++i) { if (key[i]) input_report_key(&port[portno].idev, gamecube_keymap[key[i]], 1); port[portno].keyboard.old[i] = key[i]; } break; default: break; } input_sync(&port[portno].idev); mod_timer(&port[portno].timer, jiffies + REFRESH_TIME); } /** * */ static int gcn_si_open(struct input_dev *idev) { int portno = (int)idev->private; init_timer(&port[portno].timer); port[portno].timer.function = gcn_si_timer; port[portno].timer.data = (int)idev->private; port[portno].timer.expires = jiffies + REFRESH_TIME; add_timer(&port[portno].timer); return 0; } /** * */ static void gcn_si_close(struct input_dev *idev) { int portno = (int)idev->private; del_timer(&port[portno].timer); } /** * */ static int gcn_si_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { int portno = (int)dev->private; if (type == EV_FF) { if (code == FF_RUMBLE) { gcn_si_set_rumbling(portno, value); } } return value; } /** * */ static int __init gcn_si_init(void) { int i; si_printk(KERN_INFO, "%s\n", DRV_DESCRIPTION); if (request_resource(&iomem_resource, &gcn_si_resources) < 0) { printk(KERN_WARNING PFX "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 = gcn_si_get_controller_id(i) >> 16; DPRINTK("port[%d] = 0x%x\n", i, port[i].id); init_input_dev(&port[i].idev); port[i].idev.open = gcn_si_open; port[i].idev.close = gcn_si_close; port[i].idev.private = (unsigned int *)i; switch (port[i].id) { case ID_PAD: sprintf(port[i].name, "standard pad"); /* sprintf (port[i].phys, "gcsi/port%d", i); */ /* port[i].idev.phys = port[i].phys; */ set_bit(EV_KEY, port[i].idev.evbit); set_bit(EV_ABS, port[i].idev.evbit); set_bit(EV_FF, port[i].idev.evbit); set_bit(BTN_A, port[i].idev.keybit); set_bit(BTN_B, port[i].idev.keybit); set_bit(BTN_X, port[i].idev.keybit); set_bit(BTN_Y, port[i].idev.keybit); set_bit(BTN_Z, port[i].idev.keybit); set_bit(BTN_TL, port[i].idev.keybit); set_bit(BTN_TR, port[i].idev.keybit); set_bit(BTN_START, port[i].idev.keybit); /* a stick */ set_bit(ABS_X, port[i].idev.absbit); port[i].idev.absmin[ABS_X] = 0; port[i].idev.absmax[ABS_X] = 255; port[i].idev.absfuzz[ABS_X] = 8; port[i].idev.absflat[ABS_X] = 8; set_bit(ABS_Y, port[i].idev.absbit); port[i].idev.absmin[ABS_Y] = 0; port[i].idev.absmax[ABS_Y] = 255; port[i].idev.absfuzz[ABS_Y] = 8; port[i].idev.absflat[ABS_Y] = 8; /* b pad */ set_bit(ABS_HAT0X, port[i].idev.absbit); port[i].idev.absmin[ABS_HAT0X] = -1; port[i].idev.absmax[ABS_HAT0X] = 1; set_bit(ABS_HAT0Y, port[i].idev.absbit); port[i].idev.absmin[ABS_HAT0Y] = -1; port[i].idev.absmax[ABS_HAT0Y] = 1; /* c stick */ set_bit(ABS_RX, port[i].idev.absbit); port[i].idev.absmin[ABS_RX] = 0; port[i].idev.absmax[ABS_RX] = 255; port[i].idev.absfuzz[ABS_RX] = 8; port[i].idev.absflat[ABS_RX] = 8; set_bit(ABS_RY, port[i].idev.absbit); port[i].idev.absmin[ABS_RY] = 0; port[i].idev.absmax[ABS_RY] = 255; port[i].idev.absfuzz[ABS_RY] = 8; port[i].idev.absflat[ABS_RY] = 8; /* triggers */ set_bit(ABS_GAS, port[i].idev.absbit); port[i].idev.absmin[ABS_GAS] = -255; port[i].idev.absmax[ABS_GAS] = 255; port[i].idev.absfuzz[ABS_GAS] = 16; port[i].idev.absflat[ABS_GAS] = 16; set_bit(ABS_BRAKE, port[i].idev.absbit); port[i].idev.absmin[ABS_BRAKE] = -255; port[i].idev.absmax[ABS_BRAKE] = 255; port[i].idev.absfuzz[ABS_BRAKE] = 16; port[i].idev.absflat[ABS_BRAKE] = 16; /* rumbling */ set_bit(FF_RUMBLE, port[i].idev.ffbit); port[i].idev.event = gcn_si_event; port[i].idev.ff_effects_max = 1; input_register_device(&port[i].idev); break; case ID_KEYBOARD: sprintf(port[i].name, "keyboard"); set_bit(EV_KEY, port[i].idev.evbit); set_bit(EV_REP, port[i].idev.evbit); for (j = 0; j < 255; ++j) set_bit(gamecube_keymap[j], port[i].idev.keybit); input_register_device(&port[i].idev); break; default: /* unknown device */ if (port[i].id) sprintf(port[i].name, "unknown (%x)", port[i].id); else sprintf(port[i].name, "not present"); break; } port[i].idev.name = port[i].name; si_printk(KERN_INFO, "Port %d: %s\n", i, port[i].name); } gcn_si_set_polling(); return 0; } /** * */ static void __exit gcn_si_exit(void) { int i; si_printk(KERN_INFO, "exit\n"); for (i = 0; i < 4; ++i) { if (port[i].id == ID_PAD || port[i].id == ID_KEYBOARD) { input_unregister_device(&port[i].idev); } } release_resource(&gcn_si_resources); } module_init(gcn_si_init); module_exit(gcn_si_exit); Index: Kconfig =================================================================== RCS file: /cvsroot/gc-linux/linux/drivers/input/Kconfig,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- Kconfig 23 Jun 2004 19:58:25 -0000 1.2 +++ Kconfig 19 Oct 2004 23:55:27 -0000 1.3 @@ -137,7 +137,8 @@ comment "Input I/O drivers" config GAMECUBE_SI - tristate "Gamecube SI driver" + tristate "Nintendo GameCube Serial Interface" + depends on GAMECUBE ---help--- Say Y here if you want to use the standard pads as joysticks or want to use a keyboard. Everything is autodetected. Index: Makefile =================================================================== RCS file: /cvsroot/gc-linux/linux/drivers/input/Makefile,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- Makefile 23 Jun 2004 14:01:47 -0000 1.1 +++ Makefile 19 Oct 2004 23:55:42 -0000 1.2 @@ -18,4 +18,4 @@ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/ obj-$(CONFIG_INPUT_MISC) += misc/ -obj-$(CONFIG_GAMECUBE_SI) += gamecube_si.o +obj-$(CONFIG_GAMECUBE_SI) += gcn-si.o --- gamecube_keymap.h DELETED --- --- gamecube_si.c DELETED --- |