/* * QEMU USB HID devices * * Copyright (c) 2005 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "USBinternal.h" /* HID interface requests */ #define GET_REPORT 0xa101 #define GET_IDLE 0xa102 #define GET_PROTOCOL 0xa103 #define SET_IDLE 0x210a #define SET_PROTOCOL 0x210b #define USB_MOUSE 1 #define USB_TABLET 2 typedef struct USBKeyboardState { USBDevice dev; int keyboard_grabbed; } USBKeyboardState; USBDeviceInfo devinfo; #define VK_BASED #ifdef VK_BASED static const uint8_t vk_to_key_code[] = { 0x00, //FAIL: 0x00 0x00, //FAIL: LMOUSE 0x00, //FAIL: RMOUSE 0x00, //FAIL: Break 0x00, //FAIL: MMOUSE 0x00, //FAIL: X1MOUSE 0x00, //FAIL: X2MOUSE 0x00, //FAIL: 0x00 0x2A, //OK: Backspace 0x2B, //OK: Tab 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x9C, //OK: Clear 0x28, //FAIL: ENTER 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: SHIFT 0x00, //FAIL: CTRL 0x00, //FAIL: ALT 0x48, //OK: Pause 0x39, //OK: Caps Lock 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 //0x00, //FAIL: 0x00 //0x00, //FAIL: 0x00 //0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x29, //FAIL: ESC 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x2C, //OK: Spacebar #ifdef ENABLE_KEYPAD_Fx 0x4B, //FAIL: PAGE UP 0x4E, //FAIL: PAGE DOWN 0x4D, //OK: End 0x4A, //OK: Home 0x50, //FAIL: LEFT ARROW 0x52, //FAIL: UP ARROW 0x4F, //FAIL: RIGHT ARROW 0x51, //FAIL: DOWN ARROW 0x77, //OK: Select 0x00, //FAIL: PRINT 0x74, //OK: Execute 0x46, //FAIL: PRINT SCREEN 0x49, //FAIL: INS 0x4C, //FAIL: DEL 0x75, //OK: Help VK_HOME #else 0x00, //FAIL: PAGE UP 0x00, //FAIL: PAGE DOWN 0x00, //OK: End 0x00, //OK: Home 0x00, //FAIL: LEFT ARROW 0x00, //FAIL: UP ARROW 0x00, //FAIL: RIGHT ARROW 0x00, //FAIL: DOWN ARROW 0x00, //OK: Select 0x00, //FAIL: PRINT 0x00, //OK: Execute 0x00, //FAIL: PRINT SCREEN 0x00, //FAIL: INS 0x00, //FAIL: DEL 0x00, //OK: Help VK_HOME #endif 0x27, //OK: 0 0x1E, //OK: 1 0x1F, //OK: 2 0x20, //OK: 3 0x21, //OK: 4 0x22, //OK: 5 0x23, //OK: 6 0x24, //OK: 7 0x25, //OK: 8 0x26, //OK: 9 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: not found 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x04, //OK: A 0x05, //OK: B 0x06, //OK: C 0x07, //OK: D 0x08, //OK: E 0x09, //OK: F 0x0A, //OK: G 0x0B, //OK: H 0x0C, //OK: I 0x0D, //OK: J 0x0E, //OK: K 0x0F, //OK: L 0x10, //OK: M 0x11, //OK: N 0x12, //OK: O 0x13, //OK: P 0x14, //OK: Q 0x15, //OK: R 0x16, //OK: S 0x17, //OK: T 0x18, //OK: U 0x19, //OK: V 0x1A, //OK: W 0x1B, //OK: X 0x1C, //OK: Y 0x1D, //OK: Z #ifdef ENABLE_KEYPAD_Fx 0xE3, //OK: LGUI 0xE7, //OK: RGUI 0x65, //OK: Application 0x00, //FAIL: 0x00 0x00, //FAIL: SLEEP 0x62, //OK: Keypad 0 0x59, //OK: Keypad 1 0x5A, //OK: Keypad 2 0x5B, //OK: Keypad 3 0x5C, //OK: Keypad 4 0x5D, //OK: Keypad 5 0x5E, //OK: Keypad 6 0x5F, //OK: Keypad 7 0x60, //OK: Keypad 8 0x61, //OK: Keypad 9 0x55, //OK: Keypad * 0x57, //OK: Keypad + 0x9F, //OK: Separator 0x56, //OK: Keypad - 0x63, //OK: Keypad . 0x54, //OK: Keypad / 0x3A, //OK: F1 0x3B, //OK: F2 0x3C, //OK: F3 0x3D, //OK: F4 0x3E, //OK: F5 0x3F, //OK: F6 0x40, //OK: F7 0x41, //OK: F8 0x42, //OK: F9 0x43, //OK: F10 0x44, //OK: F11 0x45, //OK: F12 0x68, //OK: F13 0x69, //OK: F14 0x6A, //OK: F15 0x6B, //OK: F16 0x6C, //OK: F17 0x6D, //OK: F18 0x6E, //OK: F19 0x6F, //OK: F20 0x70, //OK: F21 0x71, //OK: F22 0x72, //OK: F23 0x73, //OK: F24 #else 0x00, //OK: LGUI 0x00, //OK: RGUI 0x00, //OK: Application 0x00, //FAIL: 0x00 0x00, //FAIL: SLEEP 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, #endif 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x83, //OK: NUM LOCK 0x47, //OK: Scroll Lock 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0xE1, //OK: LSHIFT 0xE5, //OK: RSHIFT 0xE0, //OK: LCONTROL 0xE4, //OK: RCONTROL 0xE3, //OK: LGUI 0xE7, //OK: RGUI 0x00, //FAIL: Windows 2000/XP: Browser Back 0x00, //FAIL: Windows 2000/XP: Browser Forward 0x00, //FAIL: Windows 2000/XP: Browser Refresh 0x00, //FAIL: Windows 2000/XP: Browser Stop 0x00, //FAIL: Windows 2000/XP: Browser Search 0x00, //FAIL: Windows 2000/XP: Browser Favorites 0x00, //FAIL: Windows 2000/XP: Browser Start and Home 0x00, //FAIL: Windows 2000/XP: Volume Mute 0x00, //FAIL: Windows 2000/XP: Volume Down 0x00, //FAIL: Windows 2000/XP: Volume Up 0x00, //FAIL: Windows 2000/XP: Next Track 0x00, //FAIL: Windows 2000/XP: Previous Track 0x00, //FAIL: Windows 2000/XP: Stop Media 0x00, //FAIL: Windows 2000/XP: Play/Pause Media 0x00, //FAIL: Windows 2000/XP: Start Mail 0x00, //FAIL: Windows 2000/XP: Select Media 0x00, //FAIL: Windows 2000/XP: Start Application 1 0x00, //FAIL: Windows 2000/XP: Start Application 2 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x33, //FAIL: Windows 2000/XP: For the US standard keyboard, the ';:' key 0x2E, //FAIL: Windows 2000/XP: For any country/region, the '+' 0x36, //FAIL: Windows 2000/XP: For any country/region, the ',' 0x2D, //FAIL: Windows 2000/XP: For any country/region, the '-' 0x37, //FAIL: Windows 2000/XP: For any country/region, the '.' 0x38, //FAIL: Windows 2000/XP: For the US standard keyboard, the '/?' key 0x35, //FAIL: Windows 2000/XP: For the US standard keyboard, the '`~' key 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: not found 0x00, //FAIL: not found 0x00, //FAIL: not found 0x00, //FAIL: not found 0x00, //FAIL: not found 0x00, //FAIL: not found 0x00, //FAIL: not found 0x00, //FAIL: not found 0x00, //FAIL: not found 0x00, //FAIL: not found 0x00, //FAIL: not found 0x00, //FAIL: not found 0x00, //FAIL: not found 0x00, //FAIL: not found 0x00, //FAIL: not found 0x00, //FAIL: not found 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x2F, //FAIL: Windows 2000/XP: For the US standard keyboard, the '[{' key 0x31, //FAIL: Windows 2000/XP: For the US standard keyboard, the '\|' key 0x30, //FAIL: Windows 2000/XP: For the US standard keyboard, the ']}' key 0x34, //FAIL: Windows 2000/XP: For the US standard keyboard, the 'single-quote/double-quote' key 0x00, //FAIL: Used for miscellaneous characters; it can vary byboard. 0x00, //FAIL: Reserved 0x00, //FAIL: OEM specific 0x32, //FAIL: Windows 2000/XP: Either the angle bracket or the backslash key on the RT 102-key keyboard 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: Windows 95/98/Me, Windows NT 4.0, Windows 2000/XP: IME PROCEE6 0x00, //FAIL: OEM specific 0x00, //FAIL: Windows 2000/XP: Used to pass Unicode characters as if they E8 0x00, //FAIL: Unassigned 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: 0x00 0x00, //FAIL: Attn 0xA3, //OK: CrSel 0xA4, //OK: ExSel 0x00, //FAIL: Erase EOF 0x00, //FAIL: Play 0x00, //FAIL: Zoom 0x00, //FAIL: Reserved 0x00, //FAIL: PA1 0x9C, //OK: Clear 0x00, //FAIL: 0x00 }; #else # ifdef ENABLE_KEYPAD_Fx static const unsigned char scan_to_usb[] = { 0x00,0x29,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x2f,0x30,0x2a,0x2b, 0x14,0x1a,0x08,0x15,0x17,0x1c,0x18,0x0c,0x12,0x13,0x33,0x2e,0x28,0xe0,0x04,0x16, 0x07,0x09,0x0a,0x0b,0x0d,0x0e,0x0f,0x35,0x34,0x31,0xe1,0x38,0x1d,0x1b,0x06,0x19, 0x05,0x11,0x10,0x36,0x37,0x2d,0xe5,0x55,0xe3,0x2c,0x39,0x3a,0x3b,0x3c,0x3d,0x3e, 0x3f,0x40,0x41,0x42,0x43,0x83,0x47,0x5f,0x60,0x61,0x56,0x5c,0x5d,0x5e,0x57,0x59, 0x5a,0x5b,0x62,0x63,0x46,0x00,0x32,0x44,0x45,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x75,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x73,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe4,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x54,0x00,0x00,0xe7,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe3,0xe7,0x65,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, }; # else static const unsigned char scan_to_usb[] = { 0x00,0x29,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x2f,0x30,0x2a,0x2b, 0x14,0x1a,0x08,0x15,0x17,0x1c,0x18,0x0c,0x12,0x13,0x33,0x2e,0x28,0xe0,0x04,0x16, 0x07,0x09,0x0a,0x0b,0x0d,0x0e,0x0f,0x35,0x34,0x31,0xe1,0x38,0x1d,0x1b,0x06,0x19, 0x05,0x11,0x10,0x36,0x37,0x2d,0xe5,0x00,0xe3,0x2c,0x39,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x83,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x46,0x00,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe4,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe7,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe3,0xe7,0x65,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, }; # endif #endif /* mostly the same values as the Bochs USB Keyboard device */ static const uint8_t qemu_keyboard_dev_descriptor[] = { 0x12, /* u8 bLength; */ 0x01, /* u8 bDescriptorType; Device */ 0x10, 0x00, /* u16 bcdUSB; v1.0 */ 0x00, /* u8 bDeviceClass; */ 0x00, /* u8 bDeviceSubClass; */ 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ 0x27, 0x06, /* u16 idVendor; */ 0x01, 0x00, /* u16 idProduct; */ 0x00, 0x00, /* u16 bcdDevice */ 0x03, /* u8 iManufacturer; */ 0x02, /* u8 iProduct; */ 0x01, /* u8 iSerialNumber; */ 0x01 /* u8 bNumConfigurations; */ }; static const uint8_t qemu_keyboard_config_descriptor[] = { /* one configuration */ 0x09, /* u8 bLength; */ 0x02, /* u8 bDescriptorType; Configuration */ 0x22, 0x00, /* u16 wTotalLength; */ 0x01, /* u8 bNumInterfaces; (1) */ 0x01, /* u8 bConfigurationValue; */ 0x04, /* u8 iConfiguration; */ 0xa0, /* u8 bmAttributes; Bit 7: must be set, 6: Self-powered, 5: Remote wakeup, 4..0: resvd */ 50, /* u8 MaxPower; */ /* USB 1.1: * USB 2.0, single TT organization (mandatory): * one interface, protocol 0 * * USB 2.0, multiple TT organization (optional): * two interfaces, protocols 1 (like single TT) * and 2 (multiple TT mode) ... config is * sometimes settable * NOT IMPLEMENTED */ /* one interface */ 0x09, /* u8 if_bLength; */ 0x04, /* u8 if_bDescriptorType; Interface */ 0x00, /* u8 if_bInterfaceNumber; */ 0x00, /* u8 if_bAlternateSetting; */ 0x01, /* u8 if_bNumEndpoints; */ 0x03, /* u8 if_bInterfaceClass; */ 0x01, /* u8 if_bInterfaceSubClass; */ 0x01, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ 0x05, /* u8 if_iInterface; */ /* HID descriptor */ 0x09, /* u8 bLength; */ 0x21, /* u8 bDescriptorType; */ 0x01, 0x00, /* u16 HID_class */ 0x00, /* u8 country_code */ 0x01, /* u8 num_descriptors */ 0x22, /* u8 type; Report */ 50, 0, /* u16 len */ /* one endpoint (status change endpoint) */ 0x07, /* u8 ep_bLength; */ 0x05, /* u8 ep_bDescriptorType; Endpoint */ 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ 0x03, /* u8 ep_bmAttributes; Interrupt */ 0x03, 0x00, /* u16 ep_wMaxPacketSize; */ 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ }; static const uint8_t qemu_tablet_config_descriptor[] = { /* one configuration */ 0x09, /* u8 bLength; */ 0x02, /* u8 bDescriptorType; Configuration */ 0x22, 0x00, /* u16 wTotalLength; */ 0x01, /* u8 bNumInterfaces; (1) */ 0x01, /* u8 bConfigurationValue; */ 0x04, /* u8 iConfiguration; */ 0xa0, /* u8 bmAttributes; Bit 7: must be set, 6: Self-powered, 5: Remote wakeup, 4..0: resvd */ 50, /* u8 MaxPower; */ /* USB 1.1: * USB 2.0, single TT organization (mandatory): * one interface, protocol 0 * * USB 2.0, multiple TT organization (optional): * two interfaces, protocols 1 (like single TT) * and 2 (multiple TT mode) ... config is * sometimes settable * NOT IMPLEMENTED */ /* one interface */ 0x09, /* u8 if_bLength; */ 0x04, /* u8 if_bDescriptorType; Interface */ 0x00, /* u8 if_bInterfaceNumber; */ 0x00, /* u8 if_bAlternateSetting; */ 0x01, /* u8 if_bNumEndpoints; */ 0x03, /* u8 if_bInterfaceClass; */ 0x01, /* u8 if_bInterfaceSubClass; */ 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ 0x05, /* u8 if_iInterface; */ /* HID descriptor */ 0x09, /* u8 bLength; */ 0x21, /* u8 bDescriptorType; */ 0x03, 0x00, /* u16 HID_class */ 0x00, /* u8 country_code */ 0x01, /* u8 num_descriptors */ 0x22, /* u8 type; Report */ 74, 0, /* u16 len */ /* one endpoint (status change endpoint) */ 0x07, /* u8 ep_bLength; */ 0x05, /* u8 ep_bDescriptorType; Endpoint */ 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ 0x03, /* u8 ep_bmAttributes; Interrupt */ 0x08, 0x00, /* u16 ep_wMaxPacketSize; */ 0x03, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ }; static const uint8_t qemu_keyboard_hid_report_descriptor[] = { 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x06, // USAGE (Keyboard) 0xa1, 0x01, // COLLECTION (Application) 0x05, 0x07, // USAGE_PAGE (Keyboard) 0x19, 0xe0, // USAGE_MINIMUM (Keyboard Left Control) 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x75, 0x01, // REPORT_SIZE (1) 0x95, 0x08, // REPORT_COUNT (8) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x08, // REPORT_SIZE (8) 0x81, 0x03, // INPUT (Cnst,Var,Abs) 0x95, 0x05, // REPORT_COUNT (5) 0x75, 0x01, // REPORT_SIZE (1) 0x05, 0x08, // USAGE_PAGE (LEDs) 0x19, 0x01, // USAGE_MINIMUM (Num Lock) 0x29, 0x05, // USAGE_MAXIMUM (Kana) 0x91, 0x02, // OUTPUT (Data,Var,Abs) 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x03, // REPORT_SIZE (3) 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) 0x95, 0x06, // REPORT_COUNT (6) 0x75, 0x08, // REPORT_SIZE (8) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x65, // LOGICAL_MAXIMUM (101) 0x05, 0x07, // USAGE_PAGE (Keyboard) 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) 0x81, 0x00, // INPUT (Data,Ary,Abs) 0xc0 // END_COLLECTION }; static int usb_keyboard_poll(USBKeyboardState *s, uint8_t *buf, int len) { static unsigned char keys[256]; int i,l; if (!s->keyboard_grabbed) { //qemu_add_keyboard_event_handler(usb_keyboard_event, s, 0); s->keyboard_grabbed = 1; } if(gsWindowHandle != GetForegroundWindow()) { for(int i=0;i<256;i++) { keys[i] = 0; } } else { for(int i=0;i<256;i++) { keys[i] = GetAsyncKeyState(i)>>8; } } l=1; l=2; buf[0] = 0; if(keys[VK_LCONTROL]>>7) buf[0]|=(1<<0); if(keys[VK_LSHIFT]>>7) buf[0]|=(1<<1); if(keys[VK_LMENU]>>7) buf[0]|=(1<<2); //ALT key if(keys[VK_LWIN]>>7) buf[0]|=(1<<3); if(keys[VK_RCONTROL]>>7) buf[0]|=(1<<4); if(keys[VK_RSHIFT]>>7) buf[0]|=(1<<5); if(keys[VK_RMENU]>>7) buf[0]|=(1<<6); if(keys[VK_RWIN]>>7) buf[0]|=(1<<7); buf[1] = 0; //reserved byte int k=0; for(int i=0;i<256;i++) { if(keys[i]>>7) //if pressed { if(l==8) { buf[1]=buf[1]=buf[1]=buf[1]=buf[1]=buf[1]=buf[1]=buf[1]=1; } #ifdef VK_BASED int uc = vk_to_key_code[i]; #else int sc = MapVirtualKey(i,MAPVK_VK_TO_VSC_EX); if((sc>>8)!=0) sc=(sc&0x1FF)+256; int uc = scan_to_usb[sc]; printf("// %08x->%02x ",i,sc); k++; #endif if((uc>0)&&(uc<=0x65)) // buf[l++]=uc; } } if(k) printf("\n"); /*if(l>=1) { while(l<8) buf[l++]=0; printf("KEYS: %02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); l=l; }*/ while(l<7) buf[l++]=0; return l; } static void usb_keyboard_handle_reset(USBDevice *dev) { USBKeyboardState *s = (USBKeyboardState *)dev; } static int usb_keyboard_handle_control(USBDevice *dev, int request, int value, int index, int length, uint8_t *data) { USBKeyboardState *s = (USBKeyboardState *)dev; int ret = 0; switch(request) { case DeviceRequest | USB_REQ_GET_STATUS: data[0] = (1 << USB_DEVICE_SELF_POWERED) | (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); data[1] = 0x00; ret = 2; break; case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: if (value == USB_DEVICE_REMOTE_WAKEUP) { dev->remote_wakeup = 0; } else { goto fail; } ret = 0; break; case DeviceOutRequest | USB_REQ_SET_FEATURE: if (value == USB_DEVICE_REMOTE_WAKEUP) { dev->remote_wakeup = 1; } else { goto fail; } ret = 0; break; case DeviceOutRequest | USB_REQ_SET_ADDRESS: dev->addr = value; ret = 0; break; case DeviceRequest | USB_REQ_GET_DESCRIPTOR: switch(value >> 8) { case USB_DT_DEVICE: memcpy(data, qemu_keyboard_dev_descriptor, sizeof(qemu_keyboard_dev_descriptor)); ret = sizeof(qemu_keyboard_dev_descriptor); break; case USB_DT_CONFIG: memcpy(data, qemu_keyboard_config_descriptor, sizeof(qemu_keyboard_config_descriptor)); ret = sizeof(qemu_keyboard_config_descriptor); break; case USB_DT_STRING: switch(value & 0xff) { case 0: /* language ids */ data[0] = 4; data[1] = 3; data[2] = 0x09; data[3] = 0x04; ret = 4; break; case 1: /* serial number */ ret = set_usb_string(data, "1"); break; case 2: /* product description */ ret = set_usb_string(data, "Generic USB Keyboard"); break; case 3: /* vendor description */ ret = set_usb_string(data, "PCSX2/QEMU"); break; case 4: ret = set_usb_string(data, "HID Keyboard"); break; case 5: ret = set_usb_string(data, "Endpoint1 Interrupt Pipe"); break; default: goto fail; } break; default: goto fail; } break; case DeviceRequest | USB_REQ_GET_CONFIGURATION: data[0] = 1; ret = 1; break; case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: ret = 0; break; case DeviceRequest | USB_REQ_GET_INTERFACE: data[0] = 0; ret = 1; break; case DeviceOutRequest | USB_REQ_SET_INTERFACE: ret = 0; break; /* hid specific requests */ case InterfaceRequest | USB_REQ_GET_DESCRIPTOR: switch(value >> 8) { case 0x22: memcpy(data, qemu_keyboard_hid_report_descriptor, sizeof(qemu_keyboard_hid_report_descriptor)); ret = sizeof(qemu_keyboard_hid_report_descriptor); break; default: goto fail; } break; case GET_REPORT: ret = usb_keyboard_poll(s, data, length); break; case SET_IDLE: ret = 0; break; default: fail: ret = USB_RET_STALL; break; } return ret; } static int usb_keyboard_handle_data(USBDevice *dev, USBPacket* packet) { USBKeyboardState *s = (USBKeyboardState *)dev; int ret = 0; switch(packet->pid) { case USB_TOKEN_IN: if (packet->devep == 1) { ret = usb_keyboard_poll(s, packet->data, packet->len); } else { goto fail; } break; case USB_TOKEN_OUT: default: fail: ret = USB_RET_STALL; break; } return ret; } static void usb_keyboard_handle_destroy(USBDevice *dev) { USBKeyboardState *s = (USBKeyboardState *)dev; //qemu_add_keyboard_event_handler(NULL, NULL, 0); free(s); } USBDevice *usb_keyboard_init(void) { USBKeyboardState *s; s = (USBKeyboardState *)malloc(sizeof(USBKeyboardState)); if (!s) return NULL; memset(s,0,sizeof(USBKeyboardState)); s->dev.speed = USB_SPEED_FULL; s->dev.info = &devinfo; s->dev.info->handle_packet = usb_generic_handle_packet; s->dev.info->handle_reset = usb_keyboard_handle_reset; s->dev.info->handle_control = usb_keyboard_handle_control; s->dev.info->handle_data = usb_keyboard_handle_data; s->dev.info->handle_destroy = usb_keyboard_handle_destroy; s->dev.info->product_desc = "Generic USB Keyboard"; return (USBDevice *)s; } #if 0 #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; int kbd_blocking; 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("PS2KBD %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, (void *)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, (void *)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((void *)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("PS2KBD: Error creating buffer sema\n"); } } void ps2kbd_ioctl_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((void *)ps2kbd_repeathandler, devices[devLoop]); } WaitSema(lineSema); kbd_readmode = readmode; flushbuffer(); SignalSema(lineSema); } } void ps2kbd_ioctl_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_ioctl_setctrlmap(u8 *ctrlmap) { //printf("ioctl_setctrlmap %p\n", ctrlmap); WaitSema(lineSema); memcpy(control_map, ctrlmap, PS2KBD_KEYMAP_SIZE); SignalSema(lineSema); } void ps2kbd_ioctl_setaltmap(u8 *altmap) { //printf("ioctl_setaltmap %p\n", altmap); WaitSema(lineSema); memcpy(alt_map, altmap, PS2KBD_KEYMAP_SIZE); SignalSema(lineSema); } void ps2kbd_ioctl_setspecialmap(u8 *special) { //printf("ioctl_setspecialmap %p\n", special); WaitSema(lineSema); memcpy(special_keys, special, PS2KBD_KEYMAP_SIZE); SignalSema(lineSema); } void ps2kbd_ioctl_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_ioctl_flushbuffer() /* Flush the internal buffer */ { //printf("ioctl_flushbuffer()\n"); WaitSema(lineSema); flushbuffer(); SignalSema(lineSema); } void ps2kbd_ioctl_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_ioctl_setblockmode(u32 blockmode) { if((blockmode == PS2KBD_BLOCKING) || (blockmode == PS2KBD_NONBLOCKING)) { kbd_blocking = blockmode; //printf("ioctl_setblockmode %d\n", blockmode); } } void ps2kbd_ioctl_setrepeatrate(u32 rate) { kbd_repeatrate = rate; } int fio_dummy() { //printf("fio_dummy()\n"); return -5; } int fio_init(iop_device_t *driver) { //printf("fio_init()\n"); return 0; } int fio_format(iop_file_t *f) { //printf("fio_format()\n"); return 0; } int fio_open(iop_file_t *f, const char *name, int mode) { //printf("fio_open() %s %d\n", name, mode); if(strcmp(name, PS2KBD_KBDFILE)) /* If not the keyboard file */ { return -1; } return 0; } int fio_read(iop_file_t *f, void *buf, int size) { int count = 0; char *data = (char *) buf; int ret; //printf("fio_read() %p %d\n", buf, size); if(kbd_readmode == PS2KBD_READMODE_RAW) { size &= ~1; /* Ensure size of a multiple of 2 */ } ret = PollSema(bufferSema); if(ret < 0) { if((ret == SEMA_ZERO) && (kbd_blocking == PS2KBD_BLOCKING)) { //printf("Blocking\n"); ret = WaitSema(bufferSema); if(ret < 0) /* Means either an error or the sema was deleted from under us */ { return 0; } } else { return 0; } } SignalSema(bufferSema); ret = WaitSema(lineSema); if(ret < 0) return 0; while((count < size) && (lineStartP != lineEndP)) { data[count] = lineBuffer[lineStartP++]; lineStartP %= lineSize; count++; PollSema(bufferSema); /* Take off one count from the sema */ } SignalSema(lineSema); /* //printf("read %d bytes\n", count); */ /* { */ /* struct t_sema_status s; */ /* ReferSemaStatus(bufferSema, &s); */ /* //printf("Sema count %d\n", s.curr_count); */ /* } */ return count; } int fio_ioctl(iop_file_t *f, unsigned long arg, void *param) { //printf("fio_ioctl() %ld %d\n", arg, *((u32 *) param)); switch(arg) { case PS2KBD_IOCTL_SETREADMODE: ps2kbd_ioctl_setreadmode(*((u32 *) param)); break; case PS2KBD_IOCTL_SETKEYMAP: ps2kbd_ioctl_setkeymap((kbd_keymap *) param); break; case PS2KBD_IOCTL_SETALTMAP: ps2kbd_ioctl_setaltmap((u8 *) param); break; case PS2KBD_IOCTL_SETCTRLMAP: ps2kbd_ioctl_setctrlmap((u8 *) param); break; case PS2KBD_IOCTL_SETSPECIALMAP: ps2kbd_ioctl_setspecialmap((u8 *) param); break; case PS2KBD_IOCTL_FLUSHBUFFER: ps2kbd_ioctl_flushbuffer(); break; case PS2KBD_IOCTL_SETLEDS: ps2kbd_ioctl_setleds(*(u8*) param); break; case PS2KBD_IOCTL_SETBLOCKMODE: ps2kbd_ioctl_setblockmode(*(u32 *) param); break; case PS2KBD_IOCTL_RESETKEYMAP: ps2kbd_ioctl_resetkeymap(); break; case PS2KBD_IOCTL_SETREPEATRATE: ps2kbd_ioctl_setrepeatrate(*(u32 *) param); break; default : return -1; } return 0; } int fio_close(iop_file_t *f) { //printf("fio_close()\n"); return 0; } iop_device_ops_t fio_ops = { fio_init, fio_dummy, fio_format, fio_open, fio_close, fio_read, fio_dummy, fio_dummy, fio_ioctl, fio_dummy, fio_dummy, fio_dummy, fio_dummy, fio_dummy, fio_dummy, fio_dummy, fio_dummy }; int init_fio() { kbd_filedrv.name = PS2KBD_FSNAME; kbd_filedrv.type = IOP_DT_CHAR; kbd_filedrv.version = 0; kbd_filedrv.desc = "USB Keyboard FIO driver"; kbd_filedrv.ops = &fio_ops; return AddDrv(&kbd_filedrv); } 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; } } 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("PS2KBD: 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("PS2KBD: Error creating buffer sema\n"); return 1; } lineBuffer = (u8 *) AllocSysMemory(0, PS2KBD_DEFLINELEN, NULL); if(lineBuffer == NULL) { printf("PS2KBD: 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_blocking = PS2KBD_NONBLOCKING; 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); ret = init_fio(); //printf("ps2kbd AddDrv [%d]\n", ret); init_repeatthread(); ret = UsbRegisterDriver(&kbd_driver); if(ret != USB_RC_OK) { printf("PS2KBD: Error registering USB devices\n"); return 1; } //printf("UsbRegisterDriver %d\n", ret); return 0; } #endif