/* # _____ ___ ____ ___ ____ # ____| | ____| | | |____| # | ___| |____ ___| ____| | \ PS2DEV Open Source Project. #----------------------------------------------------------------------- # Copyright 2001-2005, ps2dev - http://www.ps2dev.org # # This file is dual licensed, with permission by the original author # TyRaNiD, under both the Academic Free License version 2.0 and the GNU # General Public License version 2 or later. # # This means you can choose whether to use this code under the terms of # the Academic Free License version 2.0, or under the terms of the GNU # General Public License version 2 or later. As long as you comply to the # terms of at least one of these, you are allowed to use the code as # permitted by the respective license. # # $Id$ # USB Keyboard Driver for PS2 */ #include "types.h" #include "ioman.h" #include "loadcore.h" #include "stdio.h" #include "sifcmd.h" #include "sifrpc.h" #include "sysclib.h" #include "sysmem.h" #include "usbd.h" #include "usbd_macro.h" #include "thbase.h" #include "thevent.h" #include "thsemap.h" #include "ps2kbd.h" #include "us_keymap.h" #define PS2KBD_VERSION 0x100 #define USB_SUBCLASS_BOOT 1 #define USB_HIDPROTO_KEYBOARD 1 #define PS2KBD_MAXDEV 2 #define PS2KBD_MAXKEYS 6 #define PS2KBD_DEFLINELEN 4096 #define PS2KBD_DEFREPEATRATE 100 /* Default repeat rate in milliseconds */ #define PS2KBD_REPEATWAIT 1000 /* Number of milliseconds to wait before starting key repeat */ #define USB_KEYB_NUMLOCK 0x53 #define USB_KEYB_CAPSLOCK 0x39 #define USB_KEYB_SCRLOCK 0x47 #define USB_KEYB_NUMPAD_START 0x54 #define USB_KEYB_NUMPAD_END 0x63 #define SEMA_ZERO -419 #define SEMA_DELETED -425 int ps2kbd_init(); void ps2kbd_config_set(int resultCode, int bytes, void *arg); void ps2kbd_idlemode_set(int resultCode, int bytes, void *arg); void ps2kbd_data_recv(int resultCode, int bytes, void *arg); int ps2kbd_probe(int devId); int ps2kbd_connect(int devId); int ps2kbd_disconnect(int devId); void usb_getstring(int endp, int index, char *desc); typedef struct _kbd_data_recv { u8 mod_keys; u8 reserved; u8 keycodes[PS2KBD_MAXKEYS]; } kbd_data_recv; typedef struct _keyb_dev { int configEndp; int dataEndp; int packetSize; int devId; int interfaceNo; /* Holds the interface number selected on this device */ char repeatkeys[2]; u32 eventmask; u8 ledStatus; /* Maintains state on the led status */ kbd_data_recv oldData; kbd_data_recv data; /* Holds the data for the transfers */ } kbd_dev; /* Global Variables */ int kbd_readmode; u32 kbd_repeatrate; kbd_dev *devices[PS2KBD_MAXDEV]; /* Holds a list of current devices */ int dev_count; UsbDriver kbd_driver = { NULL, NULL, "PS2Kbd", ps2kbd_probe, ps2kbd_connect, ps2kbd_disconnect }; u8 *lineBuffer; u32 lineStartP, lineEndP; int lineSema; int bufferSema; u32 lineSize; u8 keymap[PS2KBD_KEYMAP_SIZE]; /* Normal key map */ u8 shiftkeymap[PS2KBD_KEYMAP_SIZE]; /* Shifted key map */ u8 keycap[PS2KBD_KEYMAP_SIZE]; /* Does this key get shifted by capslock ? */ u8 special_keys[PS2KBD_KEYMAP_SIZE]; u8 control_map[PS2KBD_KEYMAP_SIZE]; u8 alt_map[PS2KBD_KEYMAP_SIZE]; //static struct fileio_driver kbd_fdriver; iop_device_t kbd_filedrv; u8 keyModValue[8] = { 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7 }; int repeat_tid; int eventid; /* Id of the repeat event */ int _start () { FlushDcache(); ps2kbd_init(); printf("PS2KBD - USB Keyboard Library\n"); return 0; } int ps2kbd_probe(int devId) { UsbDeviceDescriptor *dev; UsbConfigDescriptor *conf; UsbInterfaceDescriptor *intf; UsbEndpointDescriptor *endp; //UsbStringDescriptor *str; if(dev_count >= PS2KBD_MAXDEV) { printf("ERROR: Maximum keyboard devices reached\n"); return 0; } //printf("PS2Kbd_probe devId %d\n", devId); dev = UsbGetDeviceStaticDescriptor(devId, NULL, USB_DT_DEVICE); /* Get device descriptor */ if(!dev) { printf("ERROR: Couldn't get device descriptor\n"); return 0; } //printf("Device class %d, Size %d, Man %d, Product %d Cpnfigurations %d\n", dev->bDeviceClass, dev->bMaxPacketSize0, dev->iManufacturer, dev->iProduct, dev->bNumConfigurations); /* Check that the device class is specified in the interfaces and it has at least one configuration */ if((dev->bDeviceClass != USB_CLASS_PER_INTERFACE) || (dev->bNumConfigurations < 1)) { //printf("This is not the droid you're looking for\n"); return 0; } conf = UsbGetDeviceStaticDescriptor(devId, dev, USB_DT_CONFIG); if(!conf) { printf("ERROR: Couldn't get configuration descriptor\n"); return 0; } //printf("Config Length %d Total %d Interfaces %d\n", conf->bLength, conf->wTotalLength, conf->bNumInterfaces); if((conf->bNumInterfaces < 1) || (conf->wTotalLength < (sizeof(UsbConfigDescriptor) + sizeof(UsbInterfaceDescriptor)))) { printf("ERROR: No interfaces available\n"); return 0; } intf = (UsbInterfaceDescriptor *) ((char *) conf + conf->bLength); /* Get first interface */ /* printf("Interface Length %d Endpoints %d Class %d Sub %d Proto %d\n", intf->bLength, */ /* intf->bNumEndpoints, intf->bInterfaceClass, intf->bInterfaceSubClass, */ /* intf->bInterfaceProtocol); */ if((intf->bInterfaceClass != USB_CLASS_HID) || (intf->bInterfaceSubClass != USB_SUBCLASS_BOOT) || (intf->bInterfaceProtocol != USB_HIDPROTO_KEYBOARD) || (intf->bNumEndpoints < 1)) { //printf("We came, we saw, we told it to fuck off\n"); return 0; } endp = (UsbEndpointDescriptor *) ((char *) intf + intf->bLength); endp = (UsbEndpointDescriptor *) ((char *) endp + endp->bLength); /* Go to the data endpoint */ //printf("Endpoint 1 Addr %d, Attr %d, MaxPacket %d\n", endp->bEndpointAddress, endp->bmAttributes, endp->wMaxPacketSizeLB); if(((endp->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) || ((endp->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN)) { printf("ERROR: Endpoint not interrupt type and/or an input\n"); return 0; } printf("PS2KBD: Found a keyboard device\n"); return 1; } int ps2kbd_connect(int devId) { /* Assume we can only get here if we have already checked the device is kosher */ UsbDeviceDescriptor *dev; UsbConfigDescriptor *conf; UsbInterfaceDescriptor *intf; UsbEndpointDescriptor *endp; kbd_dev *currDev; int devLoop; //printf("PS2Kbd_connect devId %d\n", devId); dev = UsbGetDeviceStaticDescriptor(devId, NULL, USB_DT_DEVICE); /* Get device descriptor */ if(!dev) { printf("ERROR: Couldn't get device descriptor\n"); return 1; } conf = UsbGetDeviceStaticDescriptor(devId, dev, USB_DT_CONFIG); if(!conf) { printf("ERROR: Couldn't get configuration descriptor\n"); return 1; } intf = (UsbInterfaceDescriptor *) ((char *) conf + conf->bLength); /* Get first interface */ endp = (UsbEndpointDescriptor *) ((char *) intf + intf->bLength); endp = (UsbEndpointDescriptor *) ((char *) endp + endp->bLength); /* Go to the data endpoint */ for(devLoop = 0; devLoop < PS2KBD_MAXDEV; devLoop++) { if(devices[devLoop] == NULL) { break; } } if(devLoop == PS2KBD_MAXDEV) { /* How the f*** did we end up here ??? */ printf("ERROR: Device Weirdness!!\n"); return 1; } currDev = (kbd_dev *) AllocSysMemory(0, sizeof(kbd_dev), NULL); if(!currDev) { printf("ERROR: Couldn't allocate a device point for the kbd\n"); return 1; } devices[devLoop] = currDev; memset(currDev, 0, sizeof(kbd_dev)); currDev->configEndp = UsbOpenEndpoint(devId, NULL); currDev->dataEndp = UsbOpenEndpoint(devId, endp); currDev->packetSize = endp->wMaxPacketSizeLB | ((int) endp->wMaxPacketSizeHB << 8); currDev->eventmask = (1 << devLoop); if(currDev->packetSize > sizeof(kbd_data_recv)) { currDev->packetSize = sizeof(kbd_data_recv); } if(dev->iManufacturer != 0) { usb_getstring(currDev->configEndp, dev->iManufacturer, "Keyboard Manufacturer"); } if(dev->iProduct != 0) { usb_getstring(currDev->configEndp, dev->iProduct, "Keyboard Product"); } currDev->devId = devId; currDev->interfaceNo = intf->bInterfaceNumber; currDev->ledStatus = 0; UsbSetDevicePrivateData(devId, currDev); /* Set the index for the device data */ //printf("Configuration value %d\n", conf->bConfigurationValue); UsbSetDeviceConfiguration(currDev->configEndp, conf->bConfigurationValue, ps2kbd_config_set, currDev); dev_count++; /* Increment device count */ printf("PS2KBD: Connected device\n"); return 0; } int ps2kbd_disconnect(int devId) { int devLoop; printf("PS2Kbd_disconnect devId %d\n", devId); for(devLoop = 0; devLoop < PS2KBD_MAXDEV; devLoop++) { if((devices[devLoop]) && (devices[devLoop]->devId == devId)) { dev_count--; FreeSysMemory(devices[devLoop]); devices[devLoop] = NULL; printf("PS2KBD: Disconnected device\n"); break; } } return 0; } typedef struct _string_descriptor { u8 buf[200]; char *desc; } string_descriptor; void ps2kbd_getstring_set(int resultCode, int bytes, void *arg) { UsbStringDescriptor *str = (UsbStringDescriptor *) arg; string_descriptor *strBuf = (string_descriptor *) arg; char string[50]; int strLoop; /* printf("=========getstring=========\n"); */ /* printf("PS2KEYBOARD: GET_DESCRIPTOR res %d, bytes %d, arg %p\n", resultCode, bytes, arg); */ if(resultCode == USB_RC_OK) { memset(string, 0, 50); for(strLoop = 0; strLoop < ((bytes - 2) / 2); strLoop++) { string[strLoop] = str->wData[strLoop] & 0xFF; } printf("%s: %s\n", strBuf->desc, string); } FreeSysMemory(arg); } void usb_getstring(int endp, int index, char *desc) { u8 *data; string_descriptor *str; int ret; data = (u8 *) AllocSysMemory(0, sizeof(string_descriptor), NULL); str = (string_descriptor *) data; if(data != NULL) { str->desc = desc; ret = UsbControlTransfer(endp, 0x80, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | index, 0, sizeof(string_descriptor) - 4, data, ps2kbd_getstring_set, data); if(ret != USB_RC_OK) { printf("PS2KBD: Error sending string descriptor request\n"); FreeSysMemory(data); } } } void ps2kbd_config_set(int resultCode, int bytes, void *arg) /* Called when we have finished choosing our configuration */ { kbd_dev *dev; if(resultCode != USB_RC_OK) { printf("PS2KEYBOARD: Configuration set error res %d, bytes %d, arg %p\n", resultCode, bytes, arg); return; } //printf("PS2KEYBOARD: Configuration set res %d, bytes %d, arg %p\n", resultCode, bytes, arg); /* Do a interrupt data transfer */ dev = (kbd_dev *) arg; if(dev != NULL) { int ret; ret = UsbControlTransfer(dev->configEndp, 0x21, USB_REQ_SET_IDLE, 0, dev->interfaceNo, 0, NULL, ps2kbd_idlemode_set, arg); } } void ps2kbd_idlemode_set(int resultCode, int bytes, void *arg) { kbd_dev *dev; if(resultCode != USB_RC_OK) { printf("PS2KBD: Idlemode set error res %d, bytes %d, arg %p\n", resultCode, bytes, arg); return; } dev = (kbd_dev *) arg; if(dev != NULL) { int ret; ret = UsbInterruptTransfer(dev->dataEndp, &dev->data, dev->packetSize, ps2kbd_data_recv, arg); } } void ps2kbd_led_set(int resultCode, int bytes, void *arg) { //printf("LED Set\n"); } void ps2kbd_build_uniquekeys(u8 *res, const u8 *new, const u8 *old) /* Builds a list of unique keys */ { int loopNew, loopOld; int loopRes = 0; int foundKey; for(loopNew = 0; loopNew < PS2KBD_MAXKEYS; loopNew++) { if(new[loopNew] != 0) { foundKey = 0; for(loopOld = 0; loopOld < PS2KBD_MAXKEYS; loopOld++) { if(new[loopNew] == old[loopOld]) { foundKey = 1; break; } } if(!foundKey) { res[loopRes++] = new[loopNew]; } } } } u32 ps2kbd_repeathandler(void *arg) { kbd_dev *dev = arg; iop_sys_clock_t t; //printf("Repeat handler\n"); iSetEventFlag(eventid, dev->eventmask); USec2SysClock(kbd_repeatrate * 1000, &t); iSetAlarm(&t, ps2kbd_repeathandler, arg); return t.hi; } void ps2kbd_getkeys(u8 keyMods, u8 ledStatus, const u8 *keys, kbd_dev *dev) { int loopKey; int tempPos = 0; int byteCount = 0; u8 currChars[2]; if(lineStartP < lineEndP) { tempPos = lineStartP + lineSize; } else { tempPos = lineStartP; } for(loopKey = 0; loopKey < PS2KBD_MAXKEYS; loopKey++) { u8 currKey = keys[loopKey]; currChars[0] = 0; currChars[1] = 0; if(lineEndP == (tempPos - 1)) { break; } if(currKey) /* If this is a valid key */ { if((currKey >= USB_KEYB_NUMPAD_START) && (currKey <= USB_KEYB_NUMPAD_END)) /* Handle numpad specially */ { if(ledStatus & PS2KBD_LED_NUMLOCK) { if(keymap[currKey]) { currChars[0] = keymap[currKey]; } } else { if(special_keys[currKey]) { currChars[0] = PS2KBD_ESCAPE_KEY; currChars[1] = special_keys[currKey]; } else if(keymap[currKey] != '5') /* Make sure this isnt a 5 key :) */ { currChars[0] = keymap[currKey]; } } } else if(special_keys[currKey]) /* This is a special key */ { currChars[0] = PS2KBD_ESCAPE_KEY; currChars[1] = special_keys[currKey]; } else if(keyMods & PS2KBD_CTRL) /* CTRL */ { if(control_map[currKey]) { currChars[0] = control_map[currKey]; } } else if(keyMods & PS2KBD_ALT) /* ALT */ { if(alt_map[currKey]) { currChars[0] = alt_map[currKey]; } } else if(keyMods & PS2KBD_SHIFT) /* SHIFT */ { if((ledStatus & PS2KBD_LED_CAPSLOCK) && (keycap[currKey])) { currChars[0] = keymap[currKey]; } else { currChars[0] = shiftkeymap[currKey]; } } else /* Normal key */ { if(keymap[keys[loopKey]]) { if((ledStatus & PS2KBD_LED_CAPSLOCK) && (keycap[currKey])) { currChars[0] = shiftkeymap[currKey]; } else { currChars[0] = keymap[currKey]; } } } } if((currChars[0] == PS2KBD_ESCAPE_KEY) && (currChars[1] != 0)) { if(lineEndP != (tempPos - 2)) { lineBuffer[lineEndP++] = currChars[0]; lineEndP %= lineSize; lineBuffer[lineEndP++] = currChars[1]; lineEndP %= lineSize; byteCount += 2; } dev->repeatkeys[0] = currChars[0]; dev->repeatkeys[1] = currChars[1]; } else if(currChars[0] != 0) { lineBuffer[lineEndP++] = currChars[0]; lineEndP %= lineSize; byteCount++; dev->repeatkeys[0] = currChars[0]; dev->repeatkeys[1] = 0; } } if(byteCount > 0) { iop_sys_clock_t t; /* Set alarm to do repeat rate */ //printf("repeatkeys %d %d\n", kbd_repeatkeys[0], kbd_repeatkeys[1]); USec2SysClock(PS2KBD_REPEATWAIT * 1000, &t); SetAlarm(&t, ps2kbd_repeathandler, dev); } for(loopKey = 0; loopKey < byteCount; loopKey++) /* Signal the sema to indicate data */ { SignalSema(bufferSema); } /* lineBuffer[PS2KBD_DEFLINELEN - 1] = 0; */ /* printf(lineBuffer); */ //printf("lineStart %d, lineEnd %d\n", lineStartP, lineEndP); } void ps2kbd_getkeys_raw(u8 newKeyMods, u8 oldKeyMods, u8 *new, const u8 *old) { int loopKey; u8 currKey; u8 keyMods = newKeyMods ^ oldKeyMods; u8 keyModsMap = newKeyMods & keyMods; int tempPos = 0; int byteCount = 0; if(lineStartP < lineEndP) { tempPos = lineStartP + lineSize; } else { tempPos = lineStartP; } for(loopKey = 0; loopKey < 8; loopKey++) { int currMod = (1 << loopKey); if(keyMods & currMod) { if(lineEndP == (tempPos - 2)) { return; } currKey = keyModValue[loopKey]; if(keyModsMap & currMod) /* If key pressed */ { lineBuffer[lineEndP++] = PS2KBD_RAWKEY_DOWN; //printf("Key down\n"); } else { lineBuffer[lineEndP++] = PS2KBD_RAWKEY_UP; //printf("Key up\n"); } lineEndP %= lineSize; lineBuffer[lineEndP++] = currKey; lineEndP %= lineSize; byteCount += 2; //printf("Key %d\n", currKey); } } for(loopKey = 0; loopKey < PS2KBD_MAXKEYS; loopKey++) { if(lineEndP == (tempPos - 2)) { return; } if(new[loopKey] != 0) { lineBuffer[lineEndP++] = PS2KBD_RAWKEY_DOWN; lineEndP %= lineSize; lineBuffer[lineEndP++] = new[loopKey]; lineEndP %= lineSize; byteCount += 2; //printf("Key down\nKey %d\n", new[loopKey]); } } for(loopKey = 0; loopKey < PS2KBD_MAXKEYS; loopKey++) { if(lineEndP == (tempPos - 2)) { return; } if(old[loopKey] != 0) { lineBuffer[lineEndP++] = PS2KBD_RAWKEY_UP; lineEndP %= lineSize; lineBuffer[lineEndP++] = old[loopKey]; lineEndP %= lineSize; byteCount += 2; //printf("Key up\nKey %d\n", old[loopKey]); } } for(loopKey = 0; loopKey < byteCount; loopKey++) /* Signal the sema for the number of bytes read */ { SignalSema(bufferSema); } } void ps2kbd_data_recv(int resultCode, int bytes, void *arg) { kbd_dev *dev; int ret; int phantom; int loop; if(resultCode != USB_RC_OK) { printf("PS2KEYBOARD: Data Recv set res %d, bytes %d, arg %p\n", resultCode, bytes, arg); return; } //printf("PS2KBD: Data Recv set res %d, bytes %d, arg %p\n", resultCode, bytes, arg); dev = (kbd_dev *) arg; if(dev == NULL) { printf("PS2KBD: dev == NULL\n"); return; } /* printf("PS2KBD Modifiers %02X, Keys ", dev->data.mod_keys); */ /* for(loop = 0; loop < PS2KBD_MAXKEYS; loop++) */ /* { */ /* printf("%02X ", dev->data.keycodes[loop]); */ /* } */ /* printf("\n"); */ CancelAlarm(ps2kbd_repeathandler, dev); /* Make sure repeat alarm is cancelled */ /* Check for phantom states */ phantom = 1; for(loop = 0; loop < PS2KBD_MAXKEYS; loop++) { if(dev->data.keycodes[loop] != 1) { phantom = 0; break; } } if(!phantom) /* If not in a phantom state */ { u8 uniqueKeys[PS2KBD_MAXKEYS]; u8 missingKeys[PS2KBD_MAXKEYS]; int loopKey; memset(uniqueKeys, 0, PS2KBD_MAXKEYS); memset(missingKeys, 0, PS2KBD_MAXKEYS); ps2kbd_build_uniquekeys(uniqueKeys, dev->data.keycodes, dev->oldData.keycodes); ps2kbd_build_uniquekeys(missingKeys, dev->oldData.keycodes, dev->data.keycodes); /* Build new and missing key lists */ /* printf("Unique keys : "); */ /* for(loopKey = 0; loopKey < PS2KBD_MAXKEYS; loopKey++) */ /* { */ /* printf("%02X ", uniqueKeys[loopKey]); */ /* } */ /* printf("\n"); */ /* printf("Missing keys : "); */ /* for(loopKey = 0; loopKey < PS2KBD_MAXKEYS; loopKey++) */ /* { */ /* printf("%02X ", missingKeys[loopKey]); */ /* } */ /* printf("\n"); */ if(kbd_readmode == PS2KBD_READMODE_NORMAL) { u8 ledStatus; ledStatus = dev->ledStatus; //printf("ledStatus %02X\n", ledStatus); for(loopKey = 0; loopKey < PS2KBD_MAXKEYS; loopKey++) /* Process key codes */ { switch(uniqueKeys[loopKey]) { case USB_KEYB_NUMLOCK : ledStatus ^= PS2KBD_LED_NUMLOCK; uniqueKeys[loopKey] = 0; break; case USB_KEYB_CAPSLOCK : ledStatus ^= PS2KBD_LED_CAPSLOCK; uniqueKeys[loopKey] = 0; break; case USB_KEYB_SCRLOCK : ledStatus ^= PS2KBD_LED_SCRLOCK; uniqueKeys[loopKey] = 0; break; } } if(ledStatus != dev->ledStatus) { dev->ledStatus = ledStatus & PS2KBD_LED_MASK; //printf("LEDS %02X\n", dev->ledStatus); /* Call Set LEDS */ UsbControlTransfer(dev->configEndp, 0x21, USB_REQ_SET_REPORT, 0x200, dev->interfaceNo, 1, &dev->ledStatus, ps2kbd_led_set, arg); } WaitSema(lineSema); /* Make sure no other thread is going to manipulate the buffer */ ps2kbd_getkeys(dev->data.mod_keys, dev->ledStatus, uniqueKeys, dev); /* read in remaining keys */ SignalSema(lineSema); } else /* RAW Mode */ { WaitSema(lineSema); ps2kbd_getkeys_raw(dev->data.mod_keys, dev->oldData.mod_keys, uniqueKeys, missingKeys); SignalSema(lineSema); } memcpy(&dev->oldData, &dev->data, sizeof(kbd_data_recv)); } ret = UsbInterruptTransfer(dev->dataEndp, &dev->data, dev->packetSize, ps2kbd_data_recv, arg); } void flushbuffer() { iop_sema_t s; lineStartP = 0; lineEndP = 0; memset(lineBuffer, 0, lineSize); DeleteSema(bufferSema); s.initial = 0; s.max = lineSize; s.option = 0; s.attr = 0; bufferSema = CreateSema(&s); /* Create a sema to maintain status of readable data */ if(bufferSema <= 0) { printf("Error creating buffer sema\n"); } } void ps2kbd_rpc_setreadmode(u32 readmode) { int devLoop; if(readmode == kbd_readmode) return; if((readmode == PS2KBD_READMODE_NORMAL) || (readmode == PS2KBD_READMODE_RAW)) { /* Reset line buffer */ //printf("ioctl_setreadmode %d\n", readmode); for(devLoop = 0; devLoop < PS2KBD_MAXDEV; devLoop++) { CancelAlarm(ps2kbd_repeathandler, devices[devLoop]); } WaitSema(lineSema); kbd_readmode = readmode; flushbuffer(); SignalSema(lineSema); } } void ps2kbd_rpc_setkeymap(kbd_keymap *keymaps) { //printf("ioctl_setkeymap %p\n", keymaps); WaitSema(lineSema); /* Lock the input so you dont end up with weird results */ memcpy(keymap, keymaps->keymap, PS2KBD_KEYMAP_SIZE); memcpy(shiftkeymap, keymaps->shiftkeymap, PS2KBD_KEYMAP_SIZE); memcpy(keycap, keymaps->keycap, PS2KBD_KEYMAP_SIZE); SignalSema(lineSema); } void ps2kbd_rpc_setctrlmap(u8 *ctrlmap) { //printf("ioctl_setctrlmap %p\n", ctrlmap); WaitSema(lineSema); memcpy(control_map, ctrlmap, PS2KBD_KEYMAP_SIZE); SignalSema(lineSema); } void ps2kbd_rpc_setaltmap(u8 *altmap) { //printf("ioctl_setaltmap %p\n", altmap); WaitSema(lineSema); memcpy(alt_map, altmap, PS2KBD_KEYMAP_SIZE); SignalSema(lineSema); } void ps2kbd_rpc_setspecialmap(u8 *special) { //printf("ioctl_setspecialmap %p\n", special); WaitSema(lineSema); memcpy(special_keys, special, PS2KBD_KEYMAP_SIZE); SignalSema(lineSema); } void ps2kbd_rpc_resetkeymap() /* Reset keymap to default US variety */ { //printf("ioctl_resetkeymap()\n"); WaitSema(lineSema); memcpy(keymap, us_keymap, PS2KBD_KEYMAP_SIZE); memcpy(shiftkeymap, us_shiftkeymap, PS2KBD_KEYMAP_SIZE); memcpy(keycap, us_keycap, PS2KBD_KEYMAP_SIZE); memcpy(special_keys, us_special_keys, PS2KBD_KEYMAP_SIZE); memcpy(control_map, us_control_map, PS2KBD_KEYMAP_SIZE); memcpy(alt_map, us_alt_map, PS2KBD_KEYMAP_SIZE); SignalSema(lineSema); } void ps2kbd_rpc_flushbuffer() /* Flush the internal buffer */ { //printf("ioctl_flushbuffer()\n"); WaitSema(lineSema); flushbuffer(); SignalSema(lineSema); } void ps2kbd_rpc_setleds(u8 ledStatus) { int devLoop; kbd_dev *dev; //printf("ioctl_setleds %d\n", ledStatus); ledStatus &= PS2KBD_LED_MASK; for(devLoop = 0; devLoop < PS2KBD_MAXDEV; devLoop++) { dev = devices[devLoop]; if(dev) { if(ledStatus != dev->ledStatus) { dev->ledStatus = ledStatus & PS2KBD_LED_MASK; UsbControlTransfer(dev->configEndp, 0x21, USB_REQ_SET_REPORT, 0x200, dev->interfaceNo, 1, &dev->ledStatus, ps2kbd_led_set, dev); } } } } void ps2kbd_rpc_setrepeatrate(u32 rate) { kbd_repeatrate = rate; } int kbd_read(void *buf, int size) { int count = 0; char *data = (char *) buf; if(kbd_readmode == PS2KBD_READMODE_RAW) size &= ~1; /* Ensure size of a multiple of 2 */ if (PollSema(bufferSema) >= 0) { SignalSema(bufferSema); if (WaitSema(lineSema) >= 0) { while((count < size) && (lineStartP != lineEndP)) { data[count] = lineBuffer[lineStartP++]; lineStartP %= lineSize; count++; PollSema(bufferSema); /* Take off one count from the sema */ } SignalSema(lineSema); } } return count; } void repeat_thread(void *arg) { u32 eventmask; int devLoop; for(;;) { WaitEventFlag(eventid, 0xFFFFFFFF, 0x01 | 0x10, &eventmask); //printf("Recieved event %08X\n", eventmask); for(devLoop = 0; devLoop < PS2KBD_MAXDEV; devLoop++) { if((eventmask & (1 << devLoop)) && (devices[devLoop])) { int tempPos = 0; WaitSema(lineSema); if(lineStartP < lineEndP) { tempPos = lineStartP + lineSize; } else { tempPos = lineStartP; } if((devices[devLoop]->repeatkeys[0]) && (devices[devLoop]->repeatkeys[1])) { if(lineEndP != (tempPos - 2)) { lineBuffer[lineEndP++] = devices[devLoop]->repeatkeys[0]; lineEndP %= lineSize; lineBuffer[lineEndP++] = devices[devLoop]->repeatkeys[1]; lineEndP %= lineSize; SignalSema(bufferSema); SignalSema(bufferSema); } } else if(devices[devLoop]->repeatkeys[0]) { if(lineEndP != (tempPos - 1)) { lineBuffer[lineEndP++] = devices[devLoop]->repeatkeys[0]; lineEndP %= lineSize; SignalSema(bufferSema); } } SignalSema(lineSema); } } } } int init_repeatthread() /* Creates a thread to handle key repeats */ { iop_thread_t param; iop_event_t event; event.attr = 0; event.option = 0; event.bits = 0; eventid = CreateEventFlag(&event); param.attr = TH_C; param.thread = repeat_thread; param.priority = 40; param.stacksize = 0x800; param.option = 0; repeat_tid = CreateThread(¶m); if (repeat_tid > 0) { StartThread(repeat_tid, 0); return 0; } else { return 1; } } static unsigned long retKey; void *ps2kbd_rpc_server(int fno, void *data, int size) { retKey = 0; switch (fno) { case KBD_RPC_SETREADMODE: ps2kbd_rpc_setreadmode(*(u32 *)data); break; case KBD_RPC_SETKEYMAP: ps2kbd_rpc_setkeymap((kbd_keymap *) data); break; case KBD_RPC_SETALTMAP: ps2kbd_rpc_setaltmap((u8 *) data); break; case KBD_RPC_SETCTRLMAP: ps2kbd_rpc_setctrlmap((u8 *) data); break; case KBD_RPC_SETSPECIALMAP: ps2kbd_rpc_setspecialmap((u8 *) data); break; case KBD_RPC_FLUSHBUFFER: ps2kbd_rpc_flushbuffer(); break; case KBD_RPC_SETLEDS: ps2kbd_rpc_setleds(*(u8 *) data); break; case KBD_RPC_RESETKEYMAP: ps2kbd_rpc_resetkeymap(); break; case KBD_RPC_SETREPEATRATE: ps2kbd_rpc_setrepeatrate(*(u32 *) data); break; case KBD_RPC_READRAW: kbd_read(&retKey, 2); return &retKey; case KBD_RPC_READKEY: kbd_read(&retKey, 1); return &retKey; default: printf("Ps2Kbd: Unknown RPC command %d\n", fno); break; } return NULL; } struct t_SifRpcDataQueue qd; struct t_SifRpcServerData sd0; void *rpcRcvBuf; void ps2kbd_start_rpc(unsigned long tid) { rpcRcvBuf = AllocSysMemory(0, 3 * PS2KBD_KEYMAP_SIZE, NULL); printf("Ps2Kbd: starting RPC server\n"); SifInitRpc(0); SifSetRpcQueue(&qd, tid); SifRegisterRpc(&sd0, PS2KBD_RPC_ID, ps2kbd_rpc_server, rpcRcvBuf, 0, 0, &qd); SifRpcLoop(&qd); } int ps2kbd_init_rpc(void) { struct _iop_thread param; int th; param.attr = 0x02000000; param.thread = (void *)ps2kbd_start_rpc; param.priority = 40; param.stacksize = 0x800; param.option = 0; th = CreateThread(¶m); if (th > 0) { StartThread(th, (void *)th); return 0; } else return -1; } int ps2kbd_init() { int ret; iop_sema_t s; s.initial = 1; s.max = 1; s.option = 0; s.attr = 0; lineSema = CreateSema(&s); if(lineSema <= 0) { printf("Error creating sema\n"); return 1; } s.initial = 0; s.max = PS2KBD_DEFLINELEN; s.option = 0; s.attr = 0; bufferSema = CreateSema(&s); /* Create a sema to maintain status of readable data */ if(bufferSema <= 0) { printf("Error creating buffer sema\n"); return 1; } lineBuffer = (u8 *) AllocSysMemory(0, PS2KBD_DEFLINELEN, NULL); if(lineBuffer == NULL) { printf("Error allocating line buffer\n"); return 1; } lineStartP = 0; lineEndP = 0; lineSize = PS2KBD_DEFLINELEN; memset(lineBuffer, 0, PS2KBD_DEFLINELEN); memset(devices, 0, sizeof(kbd_dev *) * PS2KBD_MAXDEV); dev_count = 0; kbd_readmode = PS2KBD_READMODE_NORMAL; kbd_repeatrate = PS2KBD_DEFREPEATRATE; memcpy(keymap, us_keymap, PS2KBD_KEYMAP_SIZE); memcpy(shiftkeymap, us_shiftkeymap, PS2KBD_KEYMAP_SIZE); memcpy(keycap, us_keycap, PS2KBD_KEYMAP_SIZE); memcpy(special_keys, us_special_keys, PS2KBD_KEYMAP_SIZE); memcpy(control_map, us_control_map, PS2KBD_KEYMAP_SIZE); memcpy(alt_map, us_alt_map, PS2KBD_KEYMAP_SIZE); ps2kbd_init_rpc(); init_repeatthread(); ret = UsbRegisterDriver(&kbd_driver); if(ret != USB_RC_OK) { printf("Error registering USB devices\n"); return 1; } printf("UsbRegisterDriver %d\n", ret); return 0; }