Annotation of XNU/iokit/Drivers/platform/drvApplePS2Controller/ApplePS2Controller.cpp, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.