|
|
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.