/* * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. * * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ #include #include #include #include #include "ApplePS2Keyboard.h" // ============================================================================= // ApplePS2Keyboard Class Implementation // #define super IOHIKeyboard OSDefineMetaClassAndStructors(ApplePS2Keyboard, IOHIKeyboard); UInt32 ApplePS2Keyboard::deviceType() { return NX_EVS_DEVICE_TYPE_KEYBOARD; }; UInt32 ApplePS2Keyboard::interfaceID() { return NX_EVS_DEVICE_INTERFACE_ACE; }; UInt32 ApplePS2Keyboard::maxKeyCodes() { return KBV_NUM_KEYCODES; }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool ApplePS2Keyboard::init(OSDictionary * properties) { // // Initialize this object's minimal state. This is invoked right after this // object is instantiated. // if (!super::init(properties)) return false; _device = 0; _extendCount = 0; _interruptHandlerInstalled = false; _ledState = 0; for (int index = 0; index < KBV_NUNITS; index++) _keyBitVector[index] = 0; return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ApplePS2Keyboard * ApplePS2Keyboard::probe(IOService * provider, SInt32 * score) { // // The driver has been instructed to verify the presence of the actual // hardware we represent. We are guaranteed by the controller that the // keyboard clock is enabled and the keyboard itself is disabled (thus // it won't send any asynchronous scan codes that may mess up the // responses expected by the commands we send it). This is invoked // after the init. // ApplePS2KeyboardDevice * device = (ApplePS2KeyboardDevice *)provider; PS2Request * request = device->allocateRequest(); bool success; if (!super::probe(provider, score)) return 0; // // Check to see if the keyboard responds to a basic diagnostic echo. // // (diagnostic echo command) request->commands[0].command = kPS2C_WriteDataPort; request->commands[0].inOrOut = kDP_TestKeyboardEcho; request->commands[1].command = kPS2C_ReadDataPortAndCompare; request->commands[1].inOrOut = 0xEE; request->commandsCount = 2; device->submitRequestAndBlock(request); // (free the request) success = (request->commandsCount == 2); device->freeRequest(request); return (success) ? this : 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool ApplePS2Keyboard::start(IOService * provider) { // // The driver has been instructed to start. This is called after a // successful attach. // if (!super::start(provider)) return false; // // Maintain a pointer to and retain the provider object. // _device = (ApplePS2KeyboardDevice *)provider; _device->retain(); // // Install our driver's interrupt handler, for asynchronous data delivery. // _device->installInterruptAction(this, (PS2InterruptAction)&ApplePS2Keyboard::interruptOccurred); _interruptHandlerInstalled = true; // // Initialize the keyboard LED state. // setLEDs(_ledState); // // Enable the keyboard clock (should already be so), the keyboard IRQ line, // and the keyboard Kscan -> scan code translation mode. // setCommandByte(kCB_EnableKeyboardIRQ | kCB_TranslateMode, kCB_DisableKeyboardClock); // // Finally, we enable the keyboard itself, so that it may start reporting // key events. // setKeyboardEnable(true); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ApplePS2Keyboard::stop(IOService * provider) { // // The driver has been instructed to stop. Note that we must break all // connections to other service objects now (ie. no registered actions, // no pointers and retains to objects, etc), if any. // assert(_device == provider); // // Disable the keyboard itself, so that it may stop reporting key events. // setKeyboardEnable(false); // // Disable the keyboard clock and the keyboard IRQ line. // setCommandByte(kCB_DisableKeyboardClock, kCB_EnableKeyboardIRQ); // // Uninstall the interrupt handler. // if ( _interruptHandlerInstalled ) _device->uninstallInterruptAction(); _interruptHandlerInstalled = false; // // Release the pointer to the provider object. // _device->release(); _device = 0; super::stop(provider); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ApplePS2Keyboard::interruptOccurred(UInt8 scanCode) // PS2InterruptAction { // // This will be invoked automatically from our device when asynchronous // keyboard data needs to be delivered. Process the keyboard data. Do // NOT send any BLOCKING commands to our device in this context. // if (scanCode == kSC_Acknowledge) IOLog("%s: Unexpected acknowledge from PS/2 controller.\n", getName()); else if (scanCode == kSC_Resend) IOLog("%s: Unexpected resend request from PS/2 controller.\n", getName()); else dispatchKeyboardEventWithScancode(scanCode); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool ApplePS2Keyboard::dispatchKeyboardEventWithScancode(UInt8 scanCode) { // // Parses the given scan code, updating all necessary internal state, and // should a new key be detected, the key event is dispatched. // // Returns true if a key event was indeed dispatched. // unsigned int keyCode; bool goingDown; AbsoluteTime now; // // See if this scan code introduces an extended key sequence. If so, note // it and then return. Next time we get a key we'll finish the sequence. // if (scanCode == kSC_Extend) { _extendCount = 1; return false; } // // See if this scan code introduces an extended key sequence for the Pause // Key. If so, note it and then return. The next time we get a key, drop // it. The next key we get after that finishes the Pause Key sequence. // // The sequence actually sent to us by the keyboard for the Pause Key is: // // 1. E1 Extended Sequence for Pause Key // 2. 1D Useless Data, with Up Bit Cleared // 3. 45 Pause Key, with Up Bit Cleared // 4. E1 Extended Sequence for Pause Key // 5. 9D Useless Data, with Up Bit Set // 6. C5 Pause Key, with Up Bit Set // // The reason items 4 through 6 are sent with the Pause Key is because the // keyboard hardware never generates a release code for the Pause Key and // the designers are being smart about it. The sequence above translates // to this parser as two separate events, as it should be -- one down key // event and one up key event (for the Pause Key). // if (scanCode == kSC_Pause) { _extendCount = 2; return false; } // // Convert the scan code into a key code. // if (_extendCount == 0) keyCode = scanCode & ~kSC_UpBit; else { _extendCount--; if (_extendCount) return false; // // Convert certain extended codes on the PC keyboard into single scancodes. // Refer to the conversion table in defaultKeymapOfLength. // switch (scanCode & ~kSC_UpBit) { case 0x1D: keyCode = 0x60; break; // ctrl case 0x38: keyCode = 0x61; break; // alt case 0x1C: keyCode = 0x62; break; // enter case 0x35: keyCode = 0x63; break; // / case 0x48: keyCode = 0x64; break; // up arrow case 0x50: keyCode = 0x65; break; // down arrow case 0x4B: keyCode = 0x66; break; // left arrow case 0x4D: keyCode = 0x67; break; // right arrow case 0x52: keyCode = 0x68; break; // insert case 0x53: keyCode = 0x69; break; // delete case 0x49: keyCode = 0x6A; break; // page up case 0x51: keyCode = 0x6B; break; // page down case 0x47: keyCode = 0x6C; break; // home case 0x4F: keyCode = 0x6D; break; // end case 0x37: keyCode = 0x6E; break; // PrintScreen case 0x45: keyCode = 0x6F; break; // Pause case 0x5B: keyCode = 0x70; break; // Left Windows case 0x5C: keyCode = 0x71; break; // Right Windows case 0x5D: keyCode = 0x72; break; // Application case 0x2A: // header or trailer for PrintScreen default: return false; } } if (keyCode == 0) return false; // // Update our key bit vector, which maintains the up/down status of all keys. // goingDown = !(scanCode & kSC_UpBit); if (goingDown) { // // Verify that this is not an autorepeated key -- discard it if it is. // if (KBV_IS_KEYDOWN(keyCode, _keyBitVector)) return false; KBV_KEYDOWN(keyCode, _keyBitVector); } else { KBV_KEYUP(keyCode, _keyBitVector); } // // We have a valid key event -- dispatch it to our superclass. // clock_get_uptime(&now); dispatchKeyboardEvent(keyCode, /*direction*/ goingDown, /*timeStamp*/ now); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ApplePS2Keyboard::setAlphaLockFeedback(bool locked) { // // Set the keyboard LEDs to reflect the state of alpha (caps) lock. // // It is safe to issue this request from the interrupt/completion context. // _ledState = locked ? (_ledState | kLED_CapsLock):(_ledState & ~kLED_CapsLock); setLEDs(_ledState); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ApplePS2Keyboard::setLEDs(UInt8 ledState) { // // Asynchronously instructs the controller to set the keyboard LED state. // // It is safe to issue this request from the interrupt/completion context. // PS2Request * request = _device->allocateRequest(); // (set LEDs command) request->commands[0].command = kPS2C_WriteDataPort; request->commands[0].inOrOut = kDP_SetKeyboardLEDs; request->commands[1].command = kPS2C_ReadDataPortAndCompare; request->commands[1].inOrOut = kSC_Acknowledge; request->commands[2].command = kPS2C_WriteDataPort; request->commands[2].inOrOut = ledState; request->commands[3].command = kPS2C_ReadDataPortAndCompare; request->commands[3].inOrOut = kSC_Acknowledge; request->commandsCount = 4; _device->submitRequest(request); // asynchronous, auto-free'd } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ApplePS2Keyboard::setKeyboardEnable(bool enable) { // // Instructs the keyboard to start or stop the reporting of key events. // Be aware that while the keyboard is enabled, asynchronous key events // may arrive in the middle of command sequences sent to the controller, // and may get confused for expected command responses. // // It is safe to issue this request from the interrupt/completion context. // PS2Request * request = _device->allocateRequest(); // (keyboard enable/disable command) request->commands[0].command = kPS2C_WriteDataPort; request->commands[0].inOrOut = (enable)?kDP_Enable:kDP_SetDefaultsAndDisable; request->commands[1].command = kPS2C_ReadDataPortAndCompare; request->commands[1].inOrOut = kSC_Acknowledge; request->commandsCount = 2; _device->submitRequest(request); // asynchronous, auto-free'd } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ApplePS2Keyboard::setCommandByte(UInt8 setBits, UInt8 clearBits) { // // Sets the bits setBits and clears the bits clearBits "atomically" in the // controller's Command Byte. Since the controller does not provide such // a read-modify-write primitive, we resort to a test-and-set try loop. // // Do NOT issue this request from the interrupt/completion context. // UInt8 commandByte; UInt8 commandByteNew; PS2Request * request = _device->allocateRequest(); do { // (read command byte) request->commands[0].command = kPS2C_WriteCommandPort; request->commands[0].inOrOut = kCP_GetCommandByte; request->commands[1].command = kPS2C_ReadDataPort; request->commands[1].inOrOut = 0; request->commandsCount = 2; _device->submitRequestAndBlock(request); // // Modify the command byte as requested by caller. // commandByte = request->commands[1].inOrOut; commandByteNew = (commandByte | setBits) & (~clearBits); // ("test-and-set" command byte) request->commands[0].command = kPS2C_WriteCommandPort; request->commands[0].inOrOut = kCP_GetCommandByte; request->commands[1].command = kPS2C_ReadDataPortAndCompare; request->commands[1].inOrOut = commandByte; request->commands[2].command = kPS2C_WriteCommandPort; request->commands[2].inOrOut = kCP_SetCommandByte; request->commands[3].command = kPS2C_WriteDataPort; request->commands[3].inOrOut = commandByteNew; request->commandsCount = 4; _device->submitRequestAndBlock(request); // // Repeat this loop if last command failed, that is, if the old command byte // was modified since we first read it. // } while (request->commandsCount != 4); _device->freeRequest(request); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const unsigned char * ApplePS2Keyboard::defaultKeymapOfLength(UInt32 * length) { // // Returns the default x86 keymap string. // // The following keys are multi-byte sequences on the x86 keyboard. They get // mapped into a single scan code for our purposes. Here is the mapping: // PC Key PC Code NeXT Code // Right-Ctrl E0-1D 0x60 // Right-Alt E0-38 0x61 // Keypad-Enter E0-1C 0x62 // Keypad-/ E0-35 0x63 // Up-Arrow E0-48 0x64 // Down-Arrow E0-50 0x65 // Left-Arrow E0-4B 0x66 // Right-Arrow E0-4D 0x67 // Insert E0-52 0x68 // Delete E0-53 0x69 // Page Up E0-49 0x6A // Page Down E0-51 0x6B // Home E0-47 0x6C // End E0-4F 0x6D // // Because there is no Command key on the x86 keyboard, we've split the ALT // keys up. We'll use Left-Alt as Command, and Right-Alt as ALT. // #define CTRL(c) ((c)&037) #define NX_MODIFIERKEY_ALPHALOCK 0 #define NX_MODIFIERKEY_SHIFT 1 #define NX_MODIFIERKEY_CONTROL 2 #define NX_MODIFIERKEY_ALTERNATE 3 #define NX_MODIFIERKEY_COMMAND 4 #define NX_MODIFIERKEY_NUMERICPAD 5 #define NX_MODIFIERKEY_HELP 6 static const unsigned char defaultKeymapForPC[] = { 0x00, 0x00, // char file format 6, // MODIFIER KEY DEFINITIONS (6) 0x01, 0x02, 0x2A, 0x36, // Shift, 2 keys 0x02, 0x02, 0x1D, 0x60, // Ctrl, 2 keys 0x03, 0x01, 0x61, // Alt, 1 key 0x04, 0x01, 0x38, // Cmd, 1 key 0x05, 0x15, 0x52, 0x53, 0x62, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x4E, 0x47, 0x48, 0x49, 0x45, 0x63, 0x37, 0x4A, 0x64, 0x65, 0x66, 0x67, // NumPad, 21 keys 0x06, 0x01, 0x3B, // Help, 1 key 104, // KEY DEFINITIONS 0xff, // Key 0x00 unassigned // Key 0x01 modifier key mask bits (0x02) (1<', // Shift NX_ASCIISET, 0xbc, // Alt NX_SYMBOLSET, 0xb3, // Shift Alt // Key 0x35 modifier key mask bits (0x0a) (1<