]> git.saurik.com Git - apple/xnu.git/blob - iokit/Drivers/platform/drvApplePS2Controller/ApplePS2Controller.h
d275c952092491e64af365b9e623fa50fb0bf7cc
[apple/xnu.git] / iokit / Drivers / platform / drvApplePS2Controller / ApplePS2Controller.h
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 */