Annotation of XNU/iokit/Drivers/platform/drvApplePS2Controller/ApplePS2Controller.cpp, revision 1.1.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.