|
|
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: #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"
30:
31: extern "C"
32: {
33: #include <architecture/i386/pio.h>
34: #include <machine/machine_routines.h>
35: }
36:
37: static ApplePS2Controller * gApplePS2Controller = 0; // global variable to self
38:
39: // =============================================================================
40: // Interrupt-Time Support Functions
41: //
42:
43: static void interruptHandlerMouse(OSObject *, void *, IOService *, int)
44: {
45: //
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.
49: //
50:
51: gApplePS2Controller->_interruptSourceMouse->interruptOccurred(0, 0, 0);
52: }
53:
54: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
55:
56: static void interruptHandlerKeyboard(OSObject *, void *, IOService *, int)
57: {
58: #if DEBUGGER_SUPPORT
59: //
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.
63: //
64:
65: UInt8 key;
66: UInt8 status;
67:
68: // Lock out the keyboard interrupt handler [redundant here] and claim
69: // exclusive access to the internal keyboard queue.
70:
71: gApplePS2Controller->lockController();
72:
73: // Verify that data is available on the controller's input port.
74:
75: if ( ((status = inb(kCommandPort)) & kOutputReady) )
76: {
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.
79:
80: if ( (status & kMouseData) )
81: {
82: interruptHandlerMouse(0, 0, 0, 0);
83: }
84: else
85: {
86: // Retrieve the keyboard data on the controller's input port.
87:
88: key = inb(kDataPort);
89:
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.
95:
96: if (gApplePS2Controller->doEscape(key) == false)
97: gApplePS2Controller->enqueueKeyboardData(key);
98:
99: // In all cases, we wake up our workloop to service the interrupt data.
100: gApplePS2Controller->_interruptSourceKeyboard->interruptOccurred(0, 0, 0);
101: }
102: }
103:
104: // Remove the lockout on the keyboard interrupt handler [ineffective here]
105: // and release our exclusive access to the internal keyboard queue.
106:
107: gApplePS2Controller->unlockController();
108: #else
109: //
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.
113: //
114:
115: gApplePS2Controller->_interruptSourceKeyboard->interruptOccurred(0, 0, 0);
116:
117: #endif DEBUGGER_SUPPORT
118: }
119:
120: // =============================================================================
121: // ApplePS2Controller Class Implementation
122: //
123:
124: #define super IOService
125: OSDefineMetaClassAndStructors(ApplePS2Controller, IOService);
126:
127: bool ApplePS2Controller::init(OSDictionary * properties)
128: {
129: if (!super::init(properties)) return false;
130:
131: //
132: // Initialize minimal state.
133: //
134:
135: _commandQueue = 0;
136: _workLoop = 0;
137:
138: _interruptSourceKeyboard = 0;
139: _interruptSourceMouse = 0;
140:
141: _interruptTargetKeyboard = 0;
142: _interruptTargetMouse = 0;
143:
144: _interruptActionKeyboard = NULL;
145: _interruptActionMouse = NULL;
146:
147: _interruptInstalledKeyboard = false;
148: _interruptInstalledMouse = false;
149:
150: _mouseDevice = 0;
151: _keyboardDevice = 0;
152:
153: #if DEBUGGER_SUPPORT
154: _extendedState = false;
155: _modifierState = 0x00;
156:
157: _keyboardQueueAlloc = NULL;
158: queue_init(&_keyboardQueue);
159: queue_init(&_keyboardQueueUnused);
160:
161: _controllerLockOldSpl = 0;
162: usimple_lock_init(&_controllerLock, ETAP_NO_TRACE);
163: #endif DEBUGGER_SUPPORT
164:
165: return true;
166: }
167:
168: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
169:
170: bool ApplePS2Controller::start(IOService * provider)
171: {
172: //
173: // The driver has been instructed to start. Allocate all our resources.
174: //
175:
176: if (!super::start(provider)) return false;
177:
178: #if DEBUGGER_SUPPORT
179: _keyboardQueueAlloc = (KeyboardQueueElement *)
180: IOMalloc(kKeyboardQueueSize*sizeof(KeyboardQueueElement));
181: if (!_keyboardQueueAlloc) return false;
182:
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
188:
189: //
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.
195: //
196:
197: UInt8 commandByte;
198: writeCommandPort(kCP_GetCommandByte);
199: commandByte = readDataPort(kDT_Keyboard);
200: commandByte &= ~(kCB_EnableMouseIRQ | kCB_DisableMouseClock);
201: writeCommandPort(kCP_SetCommandByte);
202: writeDataPort(commandByte);
203:
204: writeDataPort(kDP_SetDefaultsAndDisable);
205: readDataPort(kDT_Keyboard); // (discard acknowledge; success irrelevant)
206:
207: writeCommandPort(kCP_TransmitToMouse);
208: writeDataPort(kDP_SetDefaultsAndDisable);
209: readDataPort(kDT_Mouse); // (discard acknowledge; success irrelevant)
210:
211: //
212: // Clear out garbage in the controller's input streams, before starting up
213: // the work loop.
214: //
215:
216: while ( inb(kCommandPort) & kOutputReady )
217: {
218: inb(kDataPort);
219: IODelay(kDataDelay);
220: }
221:
222: //
223: // Initialize our work loop, our command queue, and our interrupt event
224: // sources. The work loop can accept requests after this step.
225: //
226:
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);
234:
235: if ( !_workLoop ||
236: !_commandQueue ||
237: !_interruptSourceMouse ||
238: !_interruptSourceKeyboard ) return false;
239:
240: if ( _workLoop->addEventSource(_commandQueue) != kIOReturnSuccess )
241: return false;
242:
243: //
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.
247: //
248:
249: _keyboardDevice = new ApplePS2KeyboardDevice;
250:
251: if ( !_keyboardDevice ||
252: !_keyboardDevice->init() ||
253: !_keyboardDevice->attach(this) ) return false;
254:
255: _mouseDevice = new ApplePS2MouseDevice;
256:
257: if ( !_mouseDevice ||
258: !_mouseDevice->init() ||
259: !_mouseDevice->attach(this) ) return false;
260:
261: gApplePS2Controller = this;
262:
263: _keyboardDevice->registerService();
264: _mouseDevice->registerService();
265:
266: return true; // success
267: }
268:
269: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
270:
271: void ApplePS2Controller::stop(IOService * provider)
272: {
273: //
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.
277: //
278:
279: // Ensure that the interrupt handlers have been uninstalled (ie. no clients).
280: assert(_interruptInstalledKeyboard == false);
281: assert(_interruptInstalledMouse == false);
282:
283: // Free the nubs we created.
284: if (_keyboardDevice) _keyboardDevice->release();
285: if (_mouseDevice) _mouseDevice->release();
286:
287: // Free the work loop.
288: if (_workLoop) _workLoop->release();
289:
290: // Free the interrupt source and command queue.
291: if (_commandQueue) _commandQueue->release();
292: if (_interruptSourceKeyboard) _interruptSourceKeyboard->release();
293: if (_interruptSourceMouse) _interruptSourceMouse->release();
294:
295: #if DEBUGGER_SUPPORT
296: // Free the keyboard queue allocation space (after disabling interrupt).
297: if (_keyboardQueueAlloc)
298: IOFree(_keyboardQueueAlloc,kKeyboardQueueSize*sizeof(KeyboardQueueElement));
299: #endif DEBUGGER_SUPPORT
300:
301: gApplePS2Controller = 0;
302:
303: super::stop(provider);
304: }
305:
306: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
307:
308: IOWorkLoop * ApplePS2Controller::getWorkLoop() const
309: {
310: return _workLoop;
311: }
312:
313: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
314:
315: void ApplePS2Controller::installInterruptAction(PS2DeviceType deviceType,
316: OSObject * target,
317: PS2InterruptAction action)
318: {
319: //
320: // Install the keyboard or mouse interrupt handler.
321: //
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.
325: //
326:
327: // Is it the keyboard or the mouse interrupt handler that was requested?
328: // We only install it if it is currently uninstalled.
329:
330: if (deviceType == kDT_Keyboard && _interruptInstalledKeyboard == false)
331: {
332: target->retain();
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;
339: }
340:
341: else if (deviceType == kDT_Mouse && _interruptInstalledMouse == false)
342: {
343: target->retain();
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;
350: }
351: }
352:
353: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
354:
355: void ApplePS2Controller::uninstallInterruptAction(PS2DeviceType deviceType)
356: {
357: //
358: // Uninstall the keyboard or mouse interrupt handler.
359: //
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.
363: //
364:
365: // Is it the keyboard or the mouse interrupt handler that was requested?
366: // We only install it if it is currently uninstalled.
367:
368: if (deviceType == kDT_Keyboard && _interruptInstalledKeyboard == true)
369: {
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;
377: }
378:
379: else if (deviceType == kDT_Mouse && _interruptInstalledMouse == true)
380: {
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;
388: }
389: }
390:
391: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
392:
393: PS2Request * ApplePS2Controller::allocateRequest()
394: {
395: //
396: // Allocate a request structure. Blocks until successful. Request structure
397: // is guaranteed to be zeroed.
398: //
399:
400: PS2Request * request = (PS2Request *) IOMalloc(sizeof(PS2Request));
401: bzero(request, sizeof(PS2Request));
402: return request;
403: }
404:
405: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
406:
407: void ApplePS2Controller::freeRequest(PS2Request * request)
408: {
409: //
410: // Deallocate a request structure.
411: //
412:
413: IOFree(request, sizeof(PS2Request));
414: }
415:
416: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
417:
418: bool ApplePS2Controller::submitRequest(PS2Request * request)
419: {
420: //
421: // Submit the request to the controller for processing, asynchronously.
422: //
423:
424: return (_commandQueue->enqueueCommand(false, request) == KERN_SUCCESS);
425: }
426:
427: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
428:
429: void ApplePS2Controller::submitRequestAndBlock(PS2Request * request)
430: {
431: //
432: // Submit the request to the controller for processing, synchronously.
433: //
434:
435: IOSyncer * completionSyncer = IOSyncer::create();
436:
437: assert(completionSyncer);
438: request->completionTarget = this;
439: request->completionAction = submitRequestAndBlockCompletion;
440: request->completionParam = completionSyncer;
441:
442: _commandQueue->enqueueCommand(true, request);
443:
444: completionSyncer->wait(); // wait 'till done
445: }
446:
447: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
448:
449: void ApplePS2Controller::submitRequestAndBlockCompletion(void *, void * param)
450: { // PS2CompletionAction
451: IOSyncer * completionSyncer = (IOSyncer *) param;
452: completionSyncer->signal();
453: }
454:
455: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
456:
457: void ApplePS2Controller::interruptOccurred(IOInterruptEventSource *, int)
458: { // IOInterruptEventAction
459: //
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.
463: //
464: // This method should only be called from our single-threaded work loop.
465: //
466:
467: UInt8 status;
468:
469: #if DEBUGGER_SUPPORT
470: lockController(); // (lock out interrupt + access to queue)
471: while (1)
472: {
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
475: // be available.
476:
477: if (dequeueKeyboardData(&status))
478: {
479: unlockController();
480: dispatchDriverInterrupt(kDT_Keyboard, status);
481: lockController();
482: }
483:
484: // See if data is available on the mouse input stream (off real port).
485:
486: else if ( (inb(kCommandPort) & (kOutputReady | kMouseData)) ==
487: (kOutputReady | kMouseData))
488: {
489: unlockController();
490: dispatchDriverInterrupt(kDT_Mouse, inb(kDataPort));
491: lockController();
492: }
493: else break; // out of loop
494: }
495: unlockController(); // (release interrupt lockout + access to queue)
496: #else
497: // Loop only while there is data currently on the input stream.
498:
499: while ( ((status = inb(kCommandPort)) & kOutputReady) )
500: {
501: // Read in and dispatch the data, but only if it isn't what is required
502: // by the active command.
503:
504: dispatchDriverInterrupt((status&kMouseData)?kDT_Mouse:kDT_Keyboard,
505: inb(kDataPort));
506: }
507: #endif DEBUGGER_SUPPORT
508: }
509:
510: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
511:
512: void ApplePS2Controller::dispatchDriverInterrupt(PS2DeviceType deviceType,
513: UInt8 data)
514: {
515: //
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.
518: //
519: // This method should only be called from our single-threaded work loop.
520: //
521:
522: if ( deviceType == kDT_Mouse )
523: {
524: // Dispatch the data to the mouse driver.
525: if (_interruptInstalledMouse)
526: (*_interruptActionMouse)(_interruptTargetMouse, data);
527: }
528: else if ( deviceType == kDT_Keyboard )
529: {
530: // Dispatch the data to the keyboard driver.
531: if (_interruptInstalledKeyboard)
532: (*_interruptActionKeyboard)(_interruptTargetKeyboard, data);
533: }
534: }
535:
536: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
537:
538: void ApplePS2Controller::processRequest(PS2Request * request,
539: void * /* field1 */,
540: void * /* field2 */,
541: void * /* field3 */)
542: // IOCommandQueueAction
543: {
544: //
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.
548: //
549: // This method should only be called from our single-threaded work loop.
550: //
551:
552: UInt8 byte;
553: PS2DeviceType deviceMode = kDT_Keyboard;
554: bool failed = false;
555: bool transmitToMouse = false;
556: unsigned index;
557:
558: // Process each of the commands in the list.
559:
560: for (index = 0; index < request->commandsCount; index++)
561: {
562: switch (request->commands[index].command)
563: {
564: case kPS2C_ReadDataPort:
565: request->commands[index].inOrOut = readDataPort(deviceMode);
566: break;
567:
568: case kPS2C_ReadDataPortAndCompare:
569: #if OUT_OF_ORDER_DATA_CORRECTION_FEATURE
570: byte = readDataPort(deviceMode, request->commands[index].inOrOut);
571: #else
572: byte = readDataPort(deviceMode);
573: #endif
574: failed = (byte != request->commands[index].inOrOut);
575: break;
576:
577: case kPS2C_WriteDataPort:
578: writeDataPort(request->commands[index].inOrOut);
579: if (transmitToMouse) // next reads from mouse input stream
580: {
581: deviceMode = kDT_Mouse;
582: transmitToMouse = false;
583: }
584: else
585: {
586: deviceMode = kDT_Keyboard;
587: }
588: break;
589:
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
594: break;
595: }
596:
597: if (failed) break;
598: }
599:
600: // If a command failed and stopped the request processing, store its
601: // index into the commandsCount field.
602:
603: if (failed) request->commandsCount = index;
604:
605: // Invoke the completion routine, if one was supplied.
606:
607: if (request->completionTarget && request->completionAction)
608: {
609: (*request->completionAction)(request->completionTarget,
610: request->completionParam);
611: }
612: }
613:
614: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
615:
616: UInt8 ApplePS2Controller::readDataPort(PS2DeviceType deviceType)
617: {
618: //
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).
624: //
625: // There is a built-in timeout for this command of (timeoutCounter X
626: // kDataDelay) microseconds, approximately.
627: //
628: // This method should only be called from our single-threaded work loop.
629: //
630:
631: UInt8 readByte;
632: UInt8 status;
633: UInt32 timeoutCounter = 10000; // (timeoutCounter * kDataDelay = 70 ms)
634:
635: while (1)
636: {
637: #if DEBUGGER_SUPPORT
638: lockController(); // (lock out interrupt + access to queue)
639: if (deviceType == kDT_Keyboard && dequeueKeyboardData(&readByte))
640: {
641: unlockController();
642: return readByte;
643: }
644: #endif DEBUGGER_SUPPORT
645:
646: //
647: // Wait for the controller's output buffer to become ready.
648: //
649:
650: while (timeoutCounter && !((status = inb(kCommandPort)) & kOutputReady))
651: {
652: timeoutCounter--;
653: IODelay(kDataDelay);
654: }
655:
656: //
657: // If we timed out, something went awfully wrong; return a fake value.
658: //
659:
660: if (timeoutCounter == 0)
661: {
662: #if DEBUGGER_SUPPORT
663: unlockController(); // (release interrupt lockout + access to queue)
664: #endif DEBUGGER_SUPPORT
665:
666: IOLog("%s: Timed out on %s input stream.\n", getName(),
667: (deviceType == kDT_Keyboard) ? "keyboard" : "mouse");
668: return 0;
669: }
670:
671: //
672: // Read in the data. We return the data, however, only if it arrived on
673: // the requested input stream.
674: //
675:
676: readByte = inb(kDataPort);
677:
678: #if DEBUGGER_SUPPORT
679: unlockController(); // (release interrupt lockout + access to queue)
680: #endif DEBUGGER_SUPPORT
681:
682: if ( (status & kMouseData) )
683: {
684: if (deviceType == kDT_Mouse) return readByte;
685: }
686: else
687: {
688: if (deviceType == kDT_Keyboard) return readByte;
689: }
690:
691: //
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.
694: //
695:
696: dispatchDriverInterrupt((deviceType==kDT_Keyboard)?kDT_Mouse:kDT_Keyboard,
697: readByte);
698: } // while (forever)
699: }
700:
701: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
702:
703: #if OUT_OF_ORDER_DATA_CORRECTION_FEATURE
704:
705: UInt8 ApplePS2Controller::readDataPort(PS2DeviceType deviceType,
706: UInt8 expectedByte)
707: {
708: //
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).
714: //
715: // There is a built-in timeout for this command of (timeoutCounter X
716: // kDataDelay) microseconds, approximately.
717: //
718: // This method should only be called from our single-threaded work loop.
719: //
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:
723: //
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.
735: //
736:
737: UInt8 firstByte = 0;
738: bool firstByteHeld = false;
739: UInt8 readByte;
740: bool requestedStream;
741: UInt8 status;
742: UInt32 timeoutCounter = 10000; // (timeoutCounter * kDataDelay = 70 ms)
743:
744: while (1)
745: {
746: #if DEBUGGER_SUPPORT
747: lockController(); // (lock out interrupt + access to queue)
748: if (deviceType == kDT_Keyboard && dequeueKeyboardData(&readByte))
749: {
750: requestedStream = true;
751: goto skipForwardToY;
752: }
753: #endif DEBUGGER_SUPPORT
754:
755: //
756: // Wait for the controller's output buffer to become ready.
757: //
758:
759: while (timeoutCounter && !((status = inb(kCommandPort)) & kOutputReady))
760: {
761: timeoutCounter--;
762: IODelay(kDataDelay);
763: }
764:
765: //
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.
769: //
770:
771: if (timeoutCounter == 0)
772: {
773: #if DEBUGGER_SUPPORT
774: unlockController(); // release interrupt lockout + access to queue
775: #endif DEBUGGER_SUPPORT
776:
777: if (firstByteHeld) return firstByte;
778:
779: IOLog("%s: Timed out on %s input stream.\n", getName(),
780: (deviceType == kDT_Keyboard) ? "keyboard" : "mouse");
781: return 0;
782: }
783:
784: //
785: // Read in the data. We process the data, however, only if it arrived on
786: // the requested input stream.
787: //
788:
789: readByte = inb(kDataPort);
790: requestedStream = false;
791:
792: if ( (status & kMouseData) )
793: {
794: if (deviceType == kDT_Mouse) requestedStream = true;
795: }
796: else
797: {
798: if (deviceType == kDT_Keyboard) requestedStream = true;
799: }
800:
801: #if DEBUGGER_SUPPORT
802: skipForwardToY:
803: unlockController(); // (release interrupt lockout + access to queue)
804: #endif DEBUGGER_SUPPORT
805:
806: if (requestedStream)
807: {
808: if (readByte == expectedByte)
809: {
810: if (firstByteHeld == false)
811: {
812: //
813: // Normal case. Return first byte received.
814: //
815:
816: return readByte;
817: }
818: else
819: {
820: //
821: // Our assumption was correct. The second byte matched. Dispatch
822: // the first byte to the interrupt handler, and return the second.
823: //
824:
825: dispatchDriverInterrupt(deviceType, firstByte);
826: return readByte;
827: }
828: }
829: else // (readByte does not match expectedByte)
830: {
831: if (firstByteHeld == false)
832: {
833: //
834: // The first byte was received, and does not match the byte we are
835: // expecting. Put it aside for the moment.
836: //
837:
838: firstByteHeld = true;
839: firstByte = readByte;
840: }
841: else if (readByte != expectedByte)
842: {
843: //
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.
846: //
847:
848: dispatchDriverInterrupt(deviceType, readByte);
849: return firstByte;
850: }
851: }
852: }
853: else
854: {
855: //
856: // The data we just received is for the other input stream, not ours,
857: // so dispatch appropriate interrupt handler.
858: //
859:
860: dispatchDriverInterrupt((deviceType==kDT_Keyboard)?kDT_Mouse:kDT_Keyboard,
861: readByte);
862: }
863: } // while (forever)
864: }
865:
866: #endif
867:
868: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
869:
870: void ApplePS2Controller::writeDataPort(UInt8 byte)
871: {
872: //
873: // Block until room in the controller's input buffer is available, then
874: // write the given byte to the Data Port.
875: //
876: // This method should only be dispatched from our single-threaded work loop.
877: //
878:
879: while (inb(kCommandPort) & kInputBusy) IODelay(kDataDelay);
880: outb(kDataPort, byte);
881: }
882:
883: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
884:
885: void ApplePS2Controller::writeCommandPort(UInt8 byte)
886: {
887: //
888: // Block until room in the controller's input buffer is available, then
889: // write the given byte to the Command Port.
890: //
891: // This method should only be dispatched from our single-threaded work loop.
892: //
893:
894: while (inb(kCommandPort) & kInputBusy) IODelay(kDataDelay);
895: outb(kCommandPort, byte);
896: }
897:
898: // =============================================================================
899: // Escape-Key Processing Stuff Localized Here (eg. Mini-Monitor)
900: //
901:
902: #if DEBUGGER_SUPPORT
903:
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
912:
913: #define kModifierShiftMask (kModifierShiftLeft | kModifierShiftRight )
914: #define kModifierCtrlMask (kModifierCtrlLeft | kModifierCtrlRight )
915: #define kModifierAltMask (kModifierAltLeft | kModifierAltRight )
916: #define kModifierWindowsMask (kModifierWindowsLeft | kModifierWindowsRight)
917:
918: bool ApplePS2Controller::doEscape(UInt8 scancode)
919: {
920: static struct
921: {
922: UInt8 scancode;
923: UInt8 extended;
924: UInt16 modifier;
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 },
933: { 0, 0, 0 } };
934:
935: UInt32 index;
936: bool releaseModifiers = false;
937: bool upBit = (scancode & kSC_UpBit) ? true : false;
938:
939: //
940: // See if this is an extened scancode sequence.
941: //
942:
943: if (scancode == kSC_Extend)
944: {
945: _extendedState = true;
946: return false;
947: }
948:
949: //
950: // Update the modifier state, if applicable.
951: //
952:
953: scancode &= ~kSC_UpBit;
954:
955: for (index = 0; modifierTable[index].scancode; index++)
956: {
957: if ( modifierTable[index].scancode == scancode &&
958: modifierTable[index].extended == _extendedState )
959: {
960: if (upBit) _modifierState &= ~modifierTable[index].modifier;
961: else _modifierState |= modifierTable[index].modifier;
962:
963: _extendedState = false;
964: return false;
965: }
966: }
967:
968: //
969: // Call the debugger function, if applicable.
970: //
971:
972: if (scancode == kSC_Delete) // (both extended and non-extended scancodes)
973: {
974: if ( _modifierState == kModifierAltLeft ||
975: _modifierState == kModifierAltRight )
976: {
977: // Disable the mouse by forcing the clock line low.
978:
979: while (inb(kCommandPort) & kInputBusy) IODelay(kDataDelay);
980: outb(kCommandPort, kCP_DisableMouseClock);
981:
982: // Call the debugger function.
983:
984: Debugger("Programmer Key");
985:
986: // Re-enable the mouse by making the clock line active.
987:
988: while (inb(kCommandPort) & kInputBusy) IODelay(kDataDelay);
989: outb(kCommandPort, kCP_EnableMouseClock);
990:
991: releaseModifiers = true;
992: }
993: }
994:
995: //
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).
999: //
1000:
1001: if (releaseModifiers)
1002: {
1003: for (index = 0; modifierTable[index].scancode; index++)
1004: {
1005: if ( _modifierState & modifierTable[index].modifier )
1006: {
1007: if (modifierTable[index].extended) enqueueKeyboardData(kSC_Extend);
1008: enqueueKeyboardData(modifierTable[index].scancode | kSC_UpBit);
1009: }
1010: }
1011: _modifierState = 0x00;
1012: }
1013:
1014: //
1015: // Update all other state and return status.
1016: //
1017:
1018: _extendedState = false;
1019: return (releaseModifiers);
1020: }
1021:
1022: void ApplePS2Controller::enqueueKeyboardData(UInt8 key)
1023: {
1024: //
1025: // Enqueue the supplied keyboard data onto our internal queues. The
1026: // controller must already be locked.
1027: //
1028:
1029: KeyboardQueueElement * element;
1030:
1031: // Obtain an unused keyboard data element.
1032: if (!queue_empty(&_keyboardQueueUnused))
1033: {
1034: queue_remove_first(&_keyboardQueueUnused,
1035: element, KeyboardQueueElement *, chain);
1036:
1037: // Store the new keyboard data element on the queue.
1038: element->data = key;
1039: queue_enter(&_keyboardQueue, element, KeyboardQueueElement *, chain);
1040: }
1041: }
1042:
1043: bool ApplePS2Controller::dequeueKeyboardData(UInt8 * key)
1044: {
1045: //
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.
1049: //
1050:
1051: KeyboardQueueElement * element;
1052:
1053: // Obtain an unused keyboard data element.
1054: if (!queue_empty(&_keyboardQueue))
1055: {
1056: queue_remove_first(&_keyboardQueue, element, KeyboardQueueElement *, chain);
1057: *key = element->data;
1058:
1059: // Place the unused keyboard data element onto the unused queue.
1060: queue_enter(&_keyboardQueueUnused, element, KeyboardQueueElement *, chain);
1061:
1062: return true;
1063: }
1064: return false;
1065: }
1066:
1067: void ApplePS2Controller::unlockController(void)
1068: {
1069: usimple_unlock(&_controllerLock);
1070: ml_set_interrupts_enabled(_controllerLockOldSpl);
1071: }
1072:
1073: void ApplePS2Controller::lockController(void)
1074: {
1075: int oldSpl = ml_set_interrupts_enabled(FALSE);
1076: usimple_lock(&_controllerLock);
1077: _controllerLockOldSpl = oldSpl;
1078: }
1079:
1080: #endif DEBUGGER_SUPPORT
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.