pcsx2/plugins/USBqemu/qemu-usb/usb-kbd.cpp

2114 lines
60 KiB
C++

/*
* 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, USBPacket *p, 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(&param);
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