|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: ! 23: #ifndef _APPLEPS2CONTROLLER_H ! 24: #define _APPLEPS2CONTROLLER_H ! 25: ! 26: #include <IOKit/IOInterruptEventSource.h> ! 27: #include <IOKit/IOService.h> ! 28: #include <IOKit/IOWorkLoop.h> ! 29: #include <IOKit/IOCommandQueue.h> ! 30: #include <IOKit/ps2/ApplePS2Device.h> ! 31: ! 32: class ApplePS2KeyboardDevice; ! 33: class ApplePS2MouseDevice; ! 34: ! 35: // ! 36: // This section describes the problem with the PS/2 controller design and what ! 37: // we are doing about it (OUT_OF_ORDER_DATA_CORRECTION_FEATURE). ! 38: // ! 39: // While the controller processes requests sent by the client drivers, at some ! 40: // point in most requests, a read needs to be made from the data port to check ! 41: // an acknowledge or receive some sort of data. We illustrate this issue with ! 42: // an example -- a write LEDs request to the keyboard: ! 43: // ! 44: // 1. Write Write LED command. ! 45: // 2. Read 0xFA Verify the acknowledge (0xFA). ! 46: // 3. Write Write LED state. ! 47: // 4. Read 0xFA Verify the acknowledge (0xFA). ! 48: // ! 49: // The problem is that the keyboard (when it is enabled) can send key events ! 50: // to the controller at any time, including when the controller is expecting ! 51: // to read an acknowledge next. What ends up happening is this sequence: ! 52: // ! 53: // a. Write Write LED command. ! 54: // b. Read 0x21 Keyboard reports [F] key was depressed, not realizing that ! 55: // we're still expecting a response to the command we JUST ! 56: // sent the keyboard. We receive 0x21 as a response to our ! 57: // command, and figure the command failed. ! 58: // c. Get 0xFA Keyboard NOW decides to respond to the command with an ! 59: // acknowledge. We're not waiting to read anything, so ! 60: // this byte gets dispatched to the driver's interrupt ! 61: // handler, which spews out an error message saying it ! 62: // wasn't expecting an acknowledge. ! 63: // ! 64: // What can we do about this? In the above case, we can take note of the fact ! 65: // that we are specifically looking for the 0xFA acknowledgement byte (through ! 66: // the information passed in the kPS2C_ReadAndCompare primitive). If we don't ! 67: // receive this byte next on the input data stream, we put the byte we did get ! 68: // aside for a moment, and give the keyboard (or mouse) a second chance to ! 69: // respond correctly. ! 70: // ! 71: // If we receive the 0xFA acknowledgement byte on the second read, that we ! 72: // assume that situation described above just happened. We transparently ! 73: // dispatch the first byte to the driver's interrupt handler, where it was ! 74: // meant to go, and return the second correct byte to the read-and-compare ! 75: // logic, where it was meant to go. Everyone wins. ! 76: // ! 77: // The only situation this feature cannot help is where a kPS2C_ReadDataPort ! 78: // primitive is issued in place of a kPS2C_ReadDataPortAndCompare primitive. ! 79: // This is necessary in some requests because the driver does not know what ! 80: // it is going to receive. This can be illustrated in the mouse get info ! 81: // command. ! 82: // ! 83: // 1. Write Prepare to write to mouse. ! 84: // 2. Write Write information command. ! 85: // 3. Read 0xFA Verify the acknowledge (0xFA). __-> mouse can report mouse ! 86: // 4. Read Get first information byte. __-> packet bytes in between ! 87: // 5. Read Get second information byte. __-> these reads ! 88: // 6. Rrad Get third information byte. ! 89: // ! 90: // Controller cannot build any defenses against this. It is suggested that the ! 91: // driver writer disable the mouse first, then send any dangerous commands, and ! 92: // re-enable the mouse when the command completes. ! 93: // ! 94: // Note that the OUT_OF_ORDER_DATA_CORRECTION_FEATURE can be turned off at ! 95: // compile time. Please see the readDataPort:expecting: method for more ! 96: // information about the assumptions necessary for this feature. ! 97: // ! 98: ! 99: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 100: // Definitions ! 101: // ! 102: ! 103: // Enable debugger support (eg. mini-monitor). ! 104: ! 105: #define DEBUGGER_SUPPORT 1 ! 106: ! 107: // Enable dynamic "second chance" re-ordering of input stream data if a ! 108: // command response fails to match the expected byte. ! 109: ! 110: #define OUT_OF_ORDER_DATA_CORRECTION_FEATURE 1 ! 111: ! 112: // PS/2 device types. ! 113: ! 114: typedef enum { kDT_Keyboard, kDT_Mouse } PS2DeviceType; ! 115: ! 116: // Interrupt definitions. ! 117: ! 118: #define kIRQ_Keyboard 1 ! 119: #define kIRQ_Mouse 12 ! 120: #define kIPL_Keyboard 6 ! 121: #define kIPL_Mouse 3 ! 122: ! 123: // Port timings. ! 124: ! 125: #define kDataDelay 7 // usec to delay before data is valid ! 126: ! 127: // Ports used to control the PS/2 keyboard/mouse and read data from it. ! 128: ! 129: #define kDataPort 0x60 // keyboard data & cmds (read/write) ! 130: #define kCommandPort 0x64 // keybd status (read), command (write) ! 131: ! 132: // Bit definitions for kCommandPort read values (status). ! 133: ! 134: #define kOutputReady 0x01 // output (from keybd) buffer full ! 135: #define kInputBusy 0x02 // input (to keybd) buffer full ! 136: #define kSystemFlag 0x04 // "System Flag" ! 137: #define kCommandLastSent 0x08 // 1 = cmd, 0 = data last sent ! 138: #define kKeyboardInhibited 0x10 // 0 if keyboard inhibited ! 139: #define kMouseData 0x20 // mouse data available ! 140: ! 141: #if DEBUGGER_SUPPORT ! 142: // Definitions for our internal keyboard queue (holds keys processed by the ! 143: // interrupt-time mini-monitor-key-sequence detection code). ! 144: ! 145: #define kKeyboardQueueSize 32 // number of KeyboardQueueElements ! 146: ! 147: typedef struct KeyboardQueueElement KeyboardQueueElement; ! 148: struct KeyboardQueueElement ! 149: { ! 150: queue_chain_t chain; ! 151: UInt8 data; ! 152: }; ! 153: #endif DEBUGGER_SUPPORT ! 154: ! 155: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 156: // ApplePS2Controller Class Declaration ! 157: // ! 158: ! 159: class ApplePS2Controller : public IOService ! 160: { ! 161: OSDeclareDefaultStructors(ApplePS2Controller); ! 162: ! 163: public: // interrupt-time variables and functions ! 164: IOInterruptEventSource * _interruptSourceKeyboard; ! 165: IOInterruptEventSource * _interruptSourceMouse; ! 166: ! 167: #if DEBUGGER_SUPPORT ! 168: void lockController(void); ! 169: void unlockController(void); ! 170: ! 171: bool doEscape(UInt8 key); ! 172: bool dequeueKeyboardData(UInt8 * key); ! 173: void enqueueKeyboardData(UInt8 key); ! 174: #endif DEBUGGER_SUPPORT ! 175: ! 176: private: ! 177: IOCommandQueue * _commandQueue; ! 178: IOWorkLoop * _workLoop; ! 179: ! 180: OSObject * _interruptTargetKeyboard; ! 181: OSObject * _interruptTargetMouse; ! 182: PS2InterruptAction _interruptActionKeyboard; ! 183: PS2InterruptAction _interruptActionMouse; ! 184: bool _interruptInstalledKeyboard; ! 185: bool _interruptInstalledMouse; ! 186: ! 187: ApplePS2MouseDevice * _mouseDevice; // mouse nub ! 188: ApplePS2KeyboardDevice * _keyboardDevice; // keyboard nub ! 189: ! 190: #if DEBUGGER_SUPPORT ! 191: usimple_lock_data_t _controllerLock; // mach simple spin lock ! 192: int _controllerLockOldSpl; // spl before lock taken ! 193: ! 194: KeyboardQueueElement * _keyboardQueueAlloc; // queues' allocation space ! 195: queue_head_t _keyboardQueue; // queue of available keys ! 196: queue_head_t _keyboardQueueUnused; // queue of unused entries ! 197: ! 198: bool _extendedState; ! 199: UInt16 _modifierState; ! 200: #endif DEBUGGER_SUPPORT ! 201: ! 202: virtual void dispatchDriverInterrupt(PS2DeviceType deviceType, UInt8 data); ! 203: virtual void interruptOccurred(IOInterruptEventSource *, int); ! 204: virtual void processRequest(PS2Request * request, void *, void *, void *); ! 205: static void submitRequestAndBlockCompletion(void *, void * param); ! 206: ! 207: virtual UInt8 readDataPort(PS2DeviceType deviceType); ! 208: virtual void writeCommandPort(UInt8 byte); ! 209: virtual void writeDataPort(UInt8 byte); ! 210: ! 211: #if OUT_OF_ORDER_DATA_CORRECTION_FEATURE ! 212: virtual UInt8 readDataPort(PS2DeviceType deviceType, UInt8 expectedByte); ! 213: #endif ! 214: ! 215: public: ! 216: virtual bool init(OSDictionary * properties); ! 217: virtual bool start(IOService * provider); ! 218: virtual void stop(IOService * provider); ! 219: ! 220: virtual IOWorkLoop * getWorkLoop() const; ! 221: ! 222: virtual void installInterruptAction(PS2DeviceType deviceType, ! 223: OSObject * target, ! 224: PS2InterruptAction action); ! 225: virtual void uninstallInterruptAction(PS2DeviceType deviceType); ! 226: ! 227: virtual PS2Request * allocateRequest(); ! 228: virtual void freeRequest(PS2Request * request); ! 229: virtual bool submitRequest(PS2Request * request); ! 230: virtual void submitRequestAndBlock(PS2Request * request); ! 231: }; ! 232: ! 233: #endif /* _APPLEPS2CONTROLLER_H */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.