2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
23 #include <IOKit/assert.h>
24 #include <IOKit/IOService.h>
25 #include <IOKit/IOSyncer.h>
26 #include <IOKit/IOCommandQueue.h>
27 #include <IOKit/ps2/ApplePS2KeyboardDevice.h>
28 #include <IOKit/ps2/ApplePS2MouseDevice.h>
29 #include "ApplePS2Controller.h"
33 #include <architecture/i386/pio.h>
34 #include <machine/machine_routines.h>
37 static ApplePS2Controller
* gApplePS2Controller
= 0; // global variable to self
39 // =============================================================================
40 // Interrupt-Time Support Functions
43 static void interruptHandlerMouse(OSObject
*, void *, IOService
*, int)
46 // Wake our workloop to service the interrupt. This is an edge-triggered
47 // interrupt, so returning from this routine without clearing the interrupt
48 // condition is perfectly normal.
51 gApplePS2Controller
->_interruptSourceMouse
->interruptOccurred(0, 0, 0);
54 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
56 static void interruptHandlerKeyboard(OSObject
*, void *, IOService
*, int)
60 // The keyboard interrupt handler reads in the pending scan code and stores
61 // it on our internal queue; should it completes a debugger escape sequence,
62 // we jump to the debugger function immediately.
68 // Lock out the keyboard interrupt handler [redundant here] and claim
69 // exclusive access to the internal keyboard queue.
71 gApplePS2Controller
->lockController();
73 // Verify that data is available on the controller's input port.
75 if ( ((status
= inb(kCommandPort
)) & kOutputReady
) )
77 // Verify that the data is keyboard data, otherwise call mouse handler.
78 // This case should never really happen, but if it does, we handle it.
80 if ( (status
& kMouseData
) )
82 interruptHandlerMouse(0, 0, 0, 0);
86 // Retrieve the keyboard data on the controller's input port.
90 // Call the debugger-key-sequence checking code (if a debugger sequence
91 // completes, the debugger function will be invoked immediately within
92 // doEscape). The doEscape call may insist that we drop the scan code
93 // we just received in some cases (a true return) -- we don't question
94 // it's judgement and comply.
96 if (gApplePS2Controller
->doEscape(key
) == false)
97 gApplePS2Controller
->enqueueKeyboardData(key
);
99 // In all cases, we wake up our workloop to service the interrupt data.
100 gApplePS2Controller
->_interruptSourceKeyboard
->interruptOccurred(0, 0, 0);
104 // Remove the lockout on the keyboard interrupt handler [ineffective here]
105 // and release our exclusive access to the internal keyboard queue.
107 gApplePS2Controller
->unlockController();
110 // Wake our workloop to service the interrupt. This is an edge-triggered
111 // interrupt, so returning from this routine without clearing the interrupt
112 // condition is perfectly normal.
115 gApplePS2Controller
->_interruptSourceKeyboard
->interruptOccurred(0, 0, 0);
117 #endif DEBUGGER_SUPPORT
120 // =============================================================================
121 // ApplePS2Controller Class Implementation
124 #define super IOService
125 OSDefineMetaClassAndStructors(ApplePS2Controller
, IOService
);
127 bool ApplePS2Controller::init(OSDictionary
* properties
)
129 if (!super::init(properties
)) return false;
132 // Initialize minimal state.
138 _interruptSourceKeyboard
= 0;
139 _interruptSourceMouse
= 0;
141 _interruptTargetKeyboard
= 0;
142 _interruptTargetMouse
= 0;
144 _interruptActionKeyboard
= NULL
;
145 _interruptActionMouse
= NULL
;
147 _interruptInstalledKeyboard
= false;
148 _interruptInstalledMouse
= false;
154 _extendedState
= false;
155 _modifierState
= 0x00;
157 _keyboardQueueAlloc
= NULL
;
158 queue_init(&_keyboardQueue
);
159 queue_init(&_keyboardQueueUnused
);
161 _controllerLockOldSpl
= 0;
162 usimple_lock_init(&_controllerLock
, ETAP_NO_TRACE
);
163 #endif DEBUGGER_SUPPORT
168 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
170 bool ApplePS2Controller::start(IOService
* provider
)
173 // The driver has been instructed to start. Allocate all our resources.
176 if (!super::start(provider
)) return false;
179 _keyboardQueueAlloc
= (KeyboardQueueElement
*)
180 IOMalloc(kKeyboardQueueSize
*sizeof(KeyboardQueueElement
));
181 if (!_keyboardQueueAlloc
) return false;
183 // Add the allocated keyboard queue entries to "unused" queue.
184 for (int index
= 0; index
< kKeyboardQueueSize
; index
++)
185 queue_enter(&_keyboardQueueUnused
, &_keyboardQueueAlloc
[index
],
186 KeyboardQueueElement
*, chain
);
187 #endif DEBUGGER_SUPPORT
190 // Initialize the mouse and keyboard hardware to a known state -- the IRQs
191 // are disabled (don't want interrupts), the clock line is enabled (want to
192 // be able to send commands), and the device itself is disabled (don't want
193 // asynchronous data arrival for key/mouse events). We call the read/write
194 // port routines directly, since no other thread will conflict with us.
198 writeCommandPort(kCP_GetCommandByte
);
199 commandByte
= readDataPort(kDT_Keyboard
);
200 commandByte
&= ~(kCB_EnableMouseIRQ
| kCB_DisableMouseClock
);
201 writeCommandPort(kCP_SetCommandByte
);
202 writeDataPort(commandByte
);
204 writeDataPort(kDP_SetDefaultsAndDisable
);
205 readDataPort(kDT_Keyboard
); // (discard acknowledge; success irrelevant)
207 writeCommandPort(kCP_TransmitToMouse
);
208 writeDataPort(kDP_SetDefaultsAndDisable
);
209 readDataPort(kDT_Mouse
); // (discard acknowledge; success irrelevant)
212 // Clear out garbage in the controller's input streams, before starting up
216 while ( inb(kCommandPort
) & kOutputReady
)
223 // Initialize our work loop, our command queue, and our interrupt event
224 // sources. The work loop can accept requests after this step.
227 _workLoop
= IOWorkLoop::workLoop();
228 _commandQueue
= IOCommandQueue::commandQueue(
229 this, (IOCommandQueueAction
) &ApplePS2Controller::processRequest
);
230 _interruptSourceMouse
= IOInterruptEventSource::interruptEventSource(
231 this, (IOInterruptEventAction
) &ApplePS2Controller::interruptOccurred
);
232 _interruptSourceKeyboard
= IOInterruptEventSource::interruptEventSource(
233 this, (IOInterruptEventAction
) &ApplePS2Controller::interruptOccurred
);
237 !_interruptSourceMouse
||
238 !_interruptSourceKeyboard
) return false;
240 if ( _workLoop
->addEventSource(_commandQueue
) != kIOReturnSuccess
)
244 // Create the keyboard nub and the mouse nub. The keyboard and mouse drivers
245 // will query these nubs to determine the existence of the keyboard or mouse,
246 // and should they exist, will attach themselves to the nub as clients.
249 _keyboardDevice
= new ApplePS2KeyboardDevice
;
251 if ( !_keyboardDevice
||
252 !_keyboardDevice
->init() ||
253 !_keyboardDevice
->attach(this) ) return false;
255 _mouseDevice
= new ApplePS2MouseDevice
;
257 if ( !_mouseDevice
||
258 !_mouseDevice
->init() ||
259 !_mouseDevice
->attach(this) ) return false;
261 gApplePS2Controller
= this;
263 _keyboardDevice
->registerService();
264 _mouseDevice
->registerService();
266 return true; // success
269 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
271 void ApplePS2Controller::stop(IOService
* provider
)
274 // The driver has been instructed to stop. Note that we must break all
275 // connections to other service objects now (ie. no registered actions,
276 // no pointers and retains to objects, etc), if any.
279 // Ensure that the interrupt handlers have been uninstalled (ie. no clients).
280 assert(_interruptInstalledKeyboard
== false);
281 assert(_interruptInstalledMouse
== false);
283 // Free the nubs we created.
284 if (_keyboardDevice
) _keyboardDevice
->release();
285 if (_mouseDevice
) _mouseDevice
->release();
287 // Free the work loop.
288 if (_workLoop
) _workLoop
->release();
290 // Free the interrupt source and command queue.
291 if (_commandQueue
) _commandQueue
->release();
292 if (_interruptSourceKeyboard
) _interruptSourceKeyboard
->release();
293 if (_interruptSourceMouse
) _interruptSourceMouse
->release();
296 // Free the keyboard queue allocation space (after disabling interrupt).
297 if (_keyboardQueueAlloc
)
298 IOFree(_keyboardQueueAlloc
,kKeyboardQueueSize
*sizeof(KeyboardQueueElement
));
299 #endif DEBUGGER_SUPPORT
301 gApplePS2Controller
= 0;
303 super::stop(provider
);
306 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
308 IOWorkLoop
* ApplePS2Controller::getWorkLoop() const
313 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
315 void ApplePS2Controller::installInterruptAction(PS2DeviceType deviceType
,
317 PS2InterruptAction action
)
320 // Install the keyboard or mouse interrupt handler.
322 // This method assumes only one possible mouse and only one possible
323 // keyboard client (ie. callers), and assumes two distinct interrupt
324 // handlers for each, hence needs no protection against races.
327 // Is it the keyboard or the mouse interrupt handler that was requested?
328 // We only install it if it is currently uninstalled.
330 if (deviceType
== kDT_Keyboard
&& _interruptInstalledKeyboard
== false)
333 _interruptTargetKeyboard
= target
;
334 _interruptActionKeyboard
= action
;
335 _workLoop
->addEventSource(_interruptSourceKeyboard
);
336 getProvider()->registerInterrupt(kIRQ_Keyboard
,0, interruptHandlerKeyboard
);
337 getProvider()->enableInterrupt(kIRQ_Keyboard
);
338 _interruptInstalledKeyboard
= true;
341 else if (deviceType
== kDT_Mouse
&& _interruptInstalledMouse
== false)
344 _interruptTargetMouse
= target
;
345 _interruptActionMouse
= action
;
346 _workLoop
->addEventSource(_interruptSourceMouse
);
347 getProvider()->registerInterrupt(kIRQ_Mouse
, 0, interruptHandlerMouse
);
348 getProvider()->enableInterrupt(kIRQ_Mouse
);
349 _interruptInstalledMouse
= true;
353 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
355 void ApplePS2Controller::uninstallInterruptAction(PS2DeviceType deviceType
)
358 // Uninstall the keyboard or mouse interrupt handler.
360 // This method assumes only one possible mouse and only one possible
361 // keyboard client (ie. callers), and assumes two distinct interrupt
362 // handlers for each, hence needs no protection against races.
365 // Is it the keyboard or the mouse interrupt handler that was requested?
366 // We only install it if it is currently uninstalled.
368 if (deviceType
== kDT_Keyboard
&& _interruptInstalledKeyboard
== true)
370 getProvider()->disableInterrupt(kIRQ_Keyboard
);
371 getProvider()->unregisterInterrupt(kIRQ_Keyboard
);
372 _workLoop
->removeEventSource(_interruptSourceMouse
);
373 _interruptInstalledKeyboard
= false;
374 _interruptActionKeyboard
= NULL
;
375 _interruptTargetKeyboard
->release();
376 _interruptTargetKeyboard
= 0;
379 else if (deviceType
== kDT_Mouse
&& _interruptInstalledMouse
== true)
381 getProvider()->disableInterrupt(kIRQ_Mouse
);
382 getProvider()->unregisterInterrupt(kIRQ_Mouse
);
383 _workLoop
->removeEventSource(_interruptSourceMouse
);
384 _interruptInstalledMouse
= false;
385 _interruptActionMouse
= NULL
;
386 _interruptTargetMouse
->release();
387 _interruptTargetMouse
= 0;
391 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
393 PS2Request
* ApplePS2Controller::allocateRequest()
396 // Allocate a request structure. Blocks until successful. Request structure
397 // is guaranteed to be zeroed.
400 PS2Request
* request
= (PS2Request
*) IOMalloc(sizeof(PS2Request
));
401 bzero(request
, sizeof(PS2Request
));
405 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
407 void ApplePS2Controller::freeRequest(PS2Request
* request
)
410 // Deallocate a request structure.
413 IOFree(request
, sizeof(PS2Request
));
416 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
418 bool ApplePS2Controller::submitRequest(PS2Request
* request
)
421 // Submit the request to the controller for processing, asynchronously.
424 return (_commandQueue
->enqueueCommand(false, request
) == KERN_SUCCESS
);
427 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
429 void ApplePS2Controller::submitRequestAndBlock(PS2Request
* request
)
432 // Submit the request to the controller for processing, synchronously.
435 IOSyncer
* completionSyncer
= IOSyncer::create();
437 assert(completionSyncer
);
438 request
->completionTarget
= this;
439 request
->completionAction
= submitRequestAndBlockCompletion
;
440 request
->completionParam
= completionSyncer
;
442 _commandQueue
->enqueueCommand(true, request
);
444 completionSyncer
->wait(); // wait 'till done
447 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
449 void ApplePS2Controller::submitRequestAndBlockCompletion(void *, void * param
)
450 { // PS2CompletionAction
451 IOSyncer
* completionSyncer
= (IOSyncer
*) param
;
452 completionSyncer
->signal();
455 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
457 void ApplePS2Controller::interruptOccurred(IOInterruptEventSource
*, int)
458 { // IOInterruptEventAction
460 // Our work loop has informed us of an interrupt, that is, asynchronous
461 // data has arrived on our input stream. Read the data and dispatch it
462 // to the appropriate driver.
464 // This method should only be called from our single-threaded work loop.
470 lockController(); // (lock out interrupt + access to queue)
473 // See if data is available on the keyboard input stream (off queue);
474 // we do not read keyboard data from the real data port if it should
477 if (dequeueKeyboardData(&status
))
480 dispatchDriverInterrupt(kDT_Keyboard
, status
);
484 // See if data is available on the mouse input stream (off real port).
486 else if ( (inb(kCommandPort
) & (kOutputReady
| kMouseData
)) ==
487 (kOutputReady
| kMouseData
))
490 dispatchDriverInterrupt(kDT_Mouse
, inb(kDataPort
));
493 else break; // out of loop
495 unlockController(); // (release interrupt lockout + access to queue)
497 // Loop only while there is data currently on the input stream.
499 while ( ((status
= inb(kCommandPort
)) & kOutputReady
) )
501 // Read in and dispatch the data, but only if it isn't what is required
502 // by the active command.
504 dispatchDriverInterrupt((status
&kMouseData
)?kDT_Mouse
:kDT_Keyboard
,
507 #endif DEBUGGER_SUPPORT
510 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
512 void ApplePS2Controller::dispatchDriverInterrupt(PS2DeviceType deviceType
,
516 // The supplied data is passed onto the interrupt handler in the appropriate
517 // driver, if one is registered, otherwise the data byte is thrown away.
519 // This method should only be called from our single-threaded work loop.
522 if ( deviceType
== kDT_Mouse
)
524 // Dispatch the data to the mouse driver.
525 if (_interruptInstalledMouse
)
526 (*_interruptActionMouse
)(_interruptTargetMouse
, data
);
528 else if ( deviceType
== kDT_Keyboard
)
530 // Dispatch the data to the keyboard driver.
531 if (_interruptInstalledKeyboard
)
532 (*_interruptActionKeyboard
)(_interruptTargetKeyboard
, data
);
536 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
538 void ApplePS2Controller::processRequest(PS2Request
* request
,
542 // IOCommandQueueAction
545 // Our work loop has informed us of a request submission. Process
546 // the request. Note that this code "figures out" when the mouse
547 // input stream should be read over the keyboard input stream.
549 // This method should only be called from our single-threaded work loop.
553 PS2DeviceType deviceMode
= kDT_Keyboard
;
555 bool transmitToMouse
= false;
558 // Process each of the commands in the list.
560 for (index
= 0; index
< request
->commandsCount
; index
++)
562 switch (request
->commands
[index
].command
)
564 case kPS2C_ReadDataPort
:
565 request
->commands
[index
].inOrOut
= readDataPort(deviceMode
);
568 case kPS2C_ReadDataPortAndCompare
:
569 #if OUT_OF_ORDER_DATA_CORRECTION_FEATURE
570 byte
= readDataPort(deviceMode
, request
->commands
[index
].inOrOut
);
572 byte
= readDataPort(deviceMode
);
574 failed
= (byte
!= request
->commands
[index
].inOrOut
);
577 case kPS2C_WriteDataPort
:
578 writeDataPort(request
->commands
[index
].inOrOut
);
579 if (transmitToMouse
) // next reads from mouse input stream
581 deviceMode
= kDT_Mouse
;
582 transmitToMouse
= false;
586 deviceMode
= kDT_Keyboard
;
590 case kPS2C_WriteCommandPort
:
591 writeCommandPort(request
->commands
[index
].inOrOut
);
592 if (request
->commands
[index
].inOrOut
== kCP_TransmitToMouse
)
593 transmitToMouse
= true; // preparing to transmit data to mouse
600 // If a command failed and stopped the request processing, store its
601 // index into the commandsCount field.
603 if (failed
) request
->commandsCount
= index
;
605 // Invoke the completion routine, if one was supplied.
607 if (request
->completionTarget
&& request
->completionAction
)
609 (*request
->completionAction
)(request
->completionTarget
,
610 request
->completionParam
);
614 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
616 UInt8
ApplePS2Controller::readDataPort(PS2DeviceType deviceType
)
619 // Blocks until keyboard or mouse data is available from the controller
620 // and returns that data. Note, if mouse data is requested but keyboard
621 // data is what is available, the data is delivered to the appropriate
622 // driver interrupt routine immediately (effectively, the request is
623 // "preempted" temporarily).
625 // There is a built-in timeout for this command of (timeoutCounter X
626 // kDataDelay) microseconds, approximately.
628 // This method should only be called from our single-threaded work loop.
633 UInt32 timeoutCounter
= 10000; // (timeoutCounter * kDataDelay = 70 ms)
638 lockController(); // (lock out interrupt + access to queue)
639 if (deviceType
== kDT_Keyboard
&& dequeueKeyboardData(&readByte
))
644 #endif DEBUGGER_SUPPORT
647 // Wait for the controller's output buffer to become ready.
650 while (timeoutCounter
&& !((status
= inb(kCommandPort
)) & kOutputReady
))
657 // If we timed out, something went awfully wrong; return a fake value.
660 if (timeoutCounter
== 0)
663 unlockController(); // (release interrupt lockout + access to queue)
664 #endif DEBUGGER_SUPPORT
666 IOLog("%s: Timed out on %s input stream.\n", getName(),
667 (deviceType
== kDT_Keyboard
) ? "keyboard" : "mouse");
672 // Read in the data. We return the data, however, only if it arrived on
673 // the requested input stream.
676 readByte
= inb(kDataPort
);
679 unlockController(); // (release interrupt lockout + access to queue)
680 #endif DEBUGGER_SUPPORT
682 if ( (status
& kMouseData
) )
684 if (deviceType
== kDT_Mouse
) return readByte
;
688 if (deviceType
== kDT_Keyboard
) return readByte
;
692 // The data we just received is for the other input stream, not the one
693 // that was requested, so dispatch other device's interrupt handler.
696 dispatchDriverInterrupt((deviceType
==kDT_Keyboard
)?kDT_Mouse
:kDT_Keyboard
,
701 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
703 #if OUT_OF_ORDER_DATA_CORRECTION_FEATURE
705 UInt8
ApplePS2Controller::readDataPort(PS2DeviceType deviceType
,
709 // Blocks until keyboard or mouse data is available from the controller
710 // and returns that data. Note, if mouse data is requested but keyboard
711 // data is what is available, the data is delivered to the appropriate
712 // driver interrupt routine immediately (effectively, the request is
713 // "preempted" temporarily).
715 // There is a built-in timeout for this command of (timeoutCounter X
716 // kDataDelay) microseconds, approximately.
718 // This method should only be called from our single-threaded work loop.
720 // This version of readDataPort does exactly the same as the original,
721 // except that if the value that should be read from the (appropriate)
722 // input stream is not what is expected, we make these assumptions:
724 // (a) the data byte we did get was "asynchronous" data being sent by
725 // the device, which has not figured out that it has to respond to
726 // the command we just sent to it.
727 // (b) that the real "expected" response will be the next byte in the
728 // stream; so what we do is put aside the first byte we read and
729 // wait for the next byte; if it's the expected value, we dispatch
730 // the first byte we read to the driver's interrupt handler, then
731 // return the expected byte. The caller will have never known that
732 // asynchronous data arrived at a very bad time.
733 // (c) that the real "expected" response will arrive within (kDataDelay
734 // X timeoutCounter) microseconds from the time the call is made.
738 bool firstByteHeld
= false;
740 bool requestedStream
;
742 UInt32 timeoutCounter
= 10000; // (timeoutCounter * kDataDelay = 70 ms)
747 lockController(); // (lock out interrupt + access to queue)
748 if (deviceType
== kDT_Keyboard
&& dequeueKeyboardData(&readByte
))
750 requestedStream
= true;
753 #endif DEBUGGER_SUPPORT
756 // Wait for the controller's output buffer to become ready.
759 while (timeoutCounter
&& !((status
= inb(kCommandPort
)) & kOutputReady
))
766 // If we timed out, we return the first byte we read, unless THIS IS the
767 // first byte we are trying to read, then something went awfully wrong
768 // and we return a fake value rather than lock up the controller longer.
771 if (timeoutCounter
== 0)
774 unlockController(); // release interrupt lockout + access to queue
775 #endif DEBUGGER_SUPPORT
777 if (firstByteHeld
) return firstByte
;
779 IOLog("%s: Timed out on %s input stream.\n", getName(),
780 (deviceType
== kDT_Keyboard
) ? "keyboard" : "mouse");
785 // Read in the data. We process the data, however, only if it arrived on
786 // the requested input stream.
789 readByte
= inb(kDataPort
);
790 requestedStream
= false;
792 if ( (status
& kMouseData
) )
794 if (deviceType
== kDT_Mouse
) requestedStream
= true;
798 if (deviceType
== kDT_Keyboard
) requestedStream
= true;
803 unlockController(); // (release interrupt lockout + access to queue)
804 #endif DEBUGGER_SUPPORT
808 if (readByte
== expectedByte
)
810 if (firstByteHeld
== false)
813 // Normal case. Return first byte received.
821 // Our assumption was correct. The second byte matched. Dispatch
822 // the first byte to the interrupt handler, and return the second.
825 dispatchDriverInterrupt(deviceType
, firstByte
);
829 else // (readByte does not match expectedByte)
831 if (firstByteHeld
== false)
834 // The first byte was received, and does not match the byte we are
835 // expecting. Put it aside for the moment.
838 firstByteHeld
= true;
839 firstByte
= readByte
;
841 else if (readByte
!= expectedByte
)
844 // The second byte mismatched as well. I have yet to see this case
845 // occur [Dan], however I do think it's plausible. No error logged.
848 dispatchDriverInterrupt(deviceType
, readByte
);
856 // The data we just received is for the other input stream, not ours,
857 // so dispatch appropriate interrupt handler.
860 dispatchDriverInterrupt((deviceType
==kDT_Keyboard
)?kDT_Mouse
:kDT_Keyboard
,
868 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
870 void ApplePS2Controller::writeDataPort(UInt8 byte
)
873 // Block until room in the controller's input buffer is available, then
874 // write the given byte to the Data Port.
876 // This method should only be dispatched from our single-threaded work loop.
879 while (inb(kCommandPort
) & kInputBusy
) IODelay(kDataDelay
);
880 outb(kDataPort
, byte
);
883 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
885 void ApplePS2Controller::writeCommandPort(UInt8 byte
)
888 // Block until room in the controller's input buffer is available, then
889 // write the given byte to the Command Port.
891 // This method should only be dispatched from our single-threaded work loop.
894 while (inb(kCommandPort
) & kInputBusy
) IODelay(kDataDelay
);
895 outb(kCommandPort
, byte
);
898 // =============================================================================
899 // Escape-Key Processing Stuff Localized Here (eg. Mini-Monitor)
904 #define kModifierShiftLeft 0x01
905 #define kModifierShiftRight 0x02
906 #define kModifierCtrlLeft 0x04
907 #define kModifierCtrlRight 0x08
908 #define kModifierAltLeft 0x10
909 #define kModifierAltRight 0x20
910 #define kModifierWindowsLeft 0x40
911 #define kModifierWindowsRight 0x80
913 #define kModifierShiftMask (kModifierShiftLeft | kModifierShiftRight )
914 #define kModifierCtrlMask (kModifierCtrlLeft | kModifierCtrlRight )
915 #define kModifierAltMask (kModifierAltLeft | kModifierAltRight )
916 #define kModifierWindowsMask (kModifierWindowsLeft | kModifierWindowsRight)
918 bool ApplePS2Controller::doEscape(UInt8 scancode
)
925 } modifierTable
[] = { { kSC_Alt
, false, kModifierAltLeft
},
926 { kSC_Alt
, true, kModifierAltRight
},
927 { kSC_Ctrl
, false, kModifierCtrlLeft
},
928 { kSC_Ctrl
, true, kModifierCtrlRight
},
929 { kSC_ShiftLeft
, false, kModifierShiftLeft
},
930 { kSC_ShiftRight
, false, kModifierShiftRight
},
931 { kSC_WindowsLeft
, true, kModifierWindowsLeft
},
932 { kSC_WindowsRight
, true, kModifierWindowsRight
},
936 bool releaseModifiers
= false;
937 bool upBit
= (scancode
& kSC_UpBit
) ? true : false;
940 // See if this is an extened scancode sequence.
943 if (scancode
== kSC_Extend
)
945 _extendedState
= true;
950 // Update the modifier state, if applicable.
953 scancode
&= ~kSC_UpBit
;
955 for (index
= 0; modifierTable
[index
].scancode
; index
++)
957 if ( modifierTable
[index
].scancode
== scancode
&&
958 modifierTable
[index
].extended
== _extendedState
)
960 if (upBit
) _modifierState
&= ~modifierTable
[index
].modifier
;
961 else _modifierState
|= modifierTable
[index
].modifier
;
963 _extendedState
= false;
969 // Call the debugger function, if applicable.
972 if (scancode
== kSC_Delete
) // (both extended and non-extended scancodes)
974 if ( _modifierState
== kModifierAltLeft
||
975 _modifierState
== kModifierAltRight
)
977 // Disable the mouse by forcing the clock line low.
979 while (inb(kCommandPort
) & kInputBusy
) IODelay(kDataDelay
);
980 outb(kCommandPort
, kCP_DisableMouseClock
);
982 // Call the debugger function.
984 Debugger("Programmer Key");
986 // Re-enable the mouse by making the clock line active.
988 while (inb(kCommandPort
) & kInputBusy
) IODelay(kDataDelay
);
989 outb(kCommandPort
, kCP_EnableMouseClock
);
991 releaseModifiers
= true;
996 // Release all the modifier keys that were down before the debugger
997 // function was called (assumption is that they are no longer held
998 // down after the debugger function returns).
1001 if (releaseModifiers
)
1003 for (index
= 0; modifierTable
[index
].scancode
; index
++)
1005 if ( _modifierState
& modifierTable
[index
].modifier
)
1007 if (modifierTable
[index
].extended
) enqueueKeyboardData(kSC_Extend
);
1008 enqueueKeyboardData(modifierTable
[index
].scancode
| kSC_UpBit
);
1011 _modifierState
= 0x00;
1015 // Update all other state and return status.
1018 _extendedState
= false;
1019 return (releaseModifiers
);
1022 void ApplePS2Controller::enqueueKeyboardData(UInt8 key
)
1025 // Enqueue the supplied keyboard data onto our internal queues. The
1026 // controller must already be locked.
1029 KeyboardQueueElement
* element
;
1031 // Obtain an unused keyboard data element.
1032 if (!queue_empty(&_keyboardQueueUnused
))
1034 queue_remove_first(&_keyboardQueueUnused
,
1035 element
, KeyboardQueueElement
*, chain
);
1037 // Store the new keyboard data element on the queue.
1038 element
->data
= key
;
1039 queue_enter(&_keyboardQueue
, element
, KeyboardQueueElement
*, chain
);
1043 bool ApplePS2Controller::dequeueKeyboardData(UInt8
* key
)
1046 // Dequeue keyboard data from our internal queues, if the queue is not
1047 // empty. Should the queue be empty, false is returned. The controller
1048 // must already be locked.
1051 KeyboardQueueElement
* element
;
1053 // Obtain an unused keyboard data element.
1054 if (!queue_empty(&_keyboardQueue
))
1056 queue_remove_first(&_keyboardQueue
, element
, KeyboardQueueElement
*, chain
);
1057 *key
= element
->data
;
1059 // Place the unused keyboard data element onto the unused queue.
1060 queue_enter(&_keyboardQueueUnused
, element
, KeyboardQueueElement
*, chain
);
1067 void ApplePS2Controller::unlockController(void)
1069 usimple_unlock(&_controllerLock
);
1070 ml_set_interrupts_enabled(_controllerLockOldSpl
);
1073 void ApplePS2Controller::lockController(void)
1075 int oldSpl
= ml_set_interrupts_enabled(FALSE
);
1076 usimple_lock(&_controllerLock
);
1077 _controllerLockOldSpl
= oldSpl
;
1080 #endif DEBUGGER_SUPPORT