|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: ! 23: #include <IOKit/assert.h> ! 24: #include <IOKit/IOService.h> ! 25: #include <IOKit/IOSyncer.h> ! 26: #include <IOKit/IOCommandQueue.h> ! 27: #include <IOKit/ps2/ApplePS2KeyboardDevice.h> ! 28: #include <IOKit/ps2/ApplePS2MouseDevice.h> ! 29: #include "ApplePS2Controller.h" ! 30: ! 31: extern "C" ! 32: { ! 33: #include <architecture/i386/pio.h> ! 34: #include <machine/machine_routines.h> ! 35: } ! 36: ! 37: static ApplePS2Controller * gApplePS2Controller = 0; // global variable to self ! 38: ! 39: // ============================================================================= ! 40: // Interrupt-Time Support Functions ! 41: // ! 42: ! 43: static void interruptHandlerMouse(OSObject *, void *, IOService *, int) ! 44: { ! 45: // ! 46: // Wake our workloop to service the interrupt. This is an edge-triggered ! 47: // interrupt, so returning from this routine without clearing the interrupt ! 48: // condition is perfectly normal. ! 49: // ! 50: ! 51: gApplePS2Controller->_interruptSourceMouse->interruptOccurred(0, 0, 0); ! 52: } ! 53: ! 54: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 55: ! 56: static void interruptHandlerKeyboard(OSObject *, void *, IOService *, int) ! 57: { ! 58: #if DEBUGGER_SUPPORT ! 59: // ! 60: // The keyboard interrupt handler reads in the pending scan code and stores ! 61: // it on our internal queue; should it completes a debugger escape sequence, ! 62: // we jump to the debugger function immediately. ! 63: // ! 64: ! 65: UInt8 key; ! 66: UInt8 status; ! 67: ! 68: // Lock out the keyboard interrupt handler [redundant here] and claim ! 69: // exclusive access to the internal keyboard queue. ! 70: ! 71: gApplePS2Controller->lockController(); ! 72: ! 73: // Verify that data is available on the controller's input port. ! 74: ! 75: if ( ((status = inb(kCommandPort)) & kOutputReady) ) ! 76: { ! 77: // Verify that the data is keyboard data, otherwise call mouse handler. ! 78: // This case should never really happen, but if it does, we handle it. ! 79: ! 80: if ( (status & kMouseData) ) ! 81: { ! 82: interruptHandlerMouse(0, 0, 0, 0); ! 83: } ! 84: else ! 85: { ! 86: // Retrieve the keyboard data on the controller's input port. ! 87: ! 88: key = inb(kDataPort); ! 89: ! 90: // Call the debugger-key-sequence checking code (if a debugger sequence ! 91: // completes, the debugger function will be invoked immediately within ! 92: // doEscape). The doEscape call may insist that we drop the scan code ! 93: // we just received in some cases (a true return) -- we don't question ! 94: // it's judgement and comply. ! 95: ! 96: if (gApplePS2Controller->doEscape(key) == false) ! 97: gApplePS2Controller->enqueueKeyboardData(key); ! 98: ! 99: // In all cases, we wake up our workloop to service the interrupt data. ! 100: gApplePS2Controller->_interruptSourceKeyboard->interruptOccurred(0, 0, 0); ! 101: } ! 102: } ! 103: ! 104: // Remove the lockout on the keyboard interrupt handler [ineffective here] ! 105: // and release our exclusive access to the internal keyboard queue. ! 106: ! 107: gApplePS2Controller->unlockController(); ! 108: #else ! 109: // ! 110: // Wake our workloop to service the interrupt. This is an edge-triggered ! 111: // interrupt, so returning from this routine without clearing the interrupt ! 112: // condition is perfectly normal. ! 113: // ! 114: ! 115: gApplePS2Controller->_interruptSourceKeyboard->interruptOccurred(0, 0, 0); ! 116: ! 117: #endif DEBUGGER_SUPPORT ! 118: } ! 119: ! 120: // ============================================================================= ! 121: // ApplePS2Controller Class Implementation ! 122: // ! 123: ! 124: #define super IOService ! 125: OSDefineMetaClassAndStructors(ApplePS2Controller, IOService); ! 126: ! 127: bool ApplePS2Controller::init(OSDictionary * properties) ! 128: { ! 129: if (!super::init(properties)) return false; ! 130: ! 131: // ! 132: // Initialize minimal state. ! 133: // ! 134: ! 135: _commandQueue = 0; ! 136: _workLoop = 0; ! 137: ! 138: _interruptSourceKeyboard = 0; ! 139: _interruptSourceMouse = 0; ! 140: ! 141: _interruptTargetKeyboard = 0; ! 142: _interruptTargetMouse = 0; ! 143: ! 144: _interruptActionKeyboard = NULL; ! 145: _interruptActionMouse = NULL; ! 146: ! 147: _interruptInstalledKeyboard = false; ! 148: _interruptInstalledMouse = false; ! 149: ! 150: _mouseDevice = 0; ! 151: _keyboardDevice = 0; ! 152: ! 153: #if DEBUGGER_SUPPORT ! 154: _extendedState = false; ! 155: _modifierState = 0x00; ! 156: ! 157: _keyboardQueueAlloc = NULL; ! 158: queue_init(&_keyboardQueue); ! 159: queue_init(&_keyboardQueueUnused); ! 160: ! 161: _controllerLockOldSpl = 0; ! 162: usimple_lock_init(&_controllerLock, ETAP_NO_TRACE); ! 163: #endif DEBUGGER_SUPPORT ! 164: ! 165: return true; ! 166: } ! 167: ! 168: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 169: ! 170: bool ApplePS2Controller::start(IOService * provider) ! 171: { ! 172: // ! 173: // The driver has been instructed to start. Allocate all our resources. ! 174: // ! 175: ! 176: if (!super::start(provider)) return false; ! 177: ! 178: #if DEBUGGER_SUPPORT ! 179: _keyboardQueueAlloc = (KeyboardQueueElement *) ! 180: IOMalloc(kKeyboardQueueSize*sizeof(KeyboardQueueElement)); ! 181: if (!_keyboardQueueAlloc) return false; ! 182: ! 183: // Add the allocated keyboard queue entries to "unused" queue. ! 184: for (int index = 0; index < kKeyboardQueueSize; index++) ! 185: queue_enter(&_keyboardQueueUnused, &_keyboardQueueAlloc[index], ! 186: KeyboardQueueElement *, chain); ! 187: #endif DEBUGGER_SUPPORT ! 188: ! 189: // ! 190: // Initialize the mouse and keyboard hardware to a known state -- the IRQs ! 191: // are disabled (don't want interrupts), the clock line is enabled (want to ! 192: // be able to send commands), and the device itself is disabled (don't want ! 193: // asynchronous data arrival for key/mouse events). We call the read/write ! 194: // port routines directly, since no other thread will conflict with us. ! 195: // ! 196: ! 197: UInt8 commandByte; ! 198: writeCommandPort(kCP_GetCommandByte); ! 199: commandByte = readDataPort(kDT_Keyboard); ! 200: commandByte &= ~(kCB_EnableMouseIRQ | kCB_DisableMouseClock); ! 201: writeCommandPort(kCP_SetCommandByte); ! 202: writeDataPort(commandByte); ! 203: ! 204: writeDataPort(kDP_SetDefaultsAndDisable); ! 205: readDataPort(kDT_Keyboard); // (discard acknowledge; success irrelevant) ! 206: ! 207: writeCommandPort(kCP_TransmitToMouse); ! 208: writeDataPort(kDP_SetDefaultsAndDisable); ! 209: readDataPort(kDT_Mouse); // (discard acknowledge; success irrelevant) ! 210: ! 211: // ! 212: // Clear out garbage in the controller's input streams, before starting up ! 213: // the work loop. ! 214: // ! 215: ! 216: while ( inb(kCommandPort) & kOutputReady ) ! 217: { ! 218: inb(kDataPort); ! 219: IODelay(kDataDelay); ! 220: } ! 221: ! 222: // ! 223: // Initialize our work loop, our command queue, and our interrupt event ! 224: // sources. The work loop can accept requests after this step. ! 225: // ! 226: ! 227: _workLoop = IOWorkLoop::workLoop(); ! 228: _commandQueue = IOCommandQueue::commandQueue( ! 229: this, (IOCommandQueueAction) &ApplePS2Controller::processRequest); ! 230: _interruptSourceMouse = IOInterruptEventSource::interruptEventSource( ! 231: this, (IOInterruptEventAction) &ApplePS2Controller::interruptOccurred); ! 232: _interruptSourceKeyboard = IOInterruptEventSource::interruptEventSource( ! 233: this, (IOInterruptEventAction) &ApplePS2Controller::interruptOccurred); ! 234: ! 235: if ( !_workLoop || ! 236: !_commandQueue || ! 237: !_interruptSourceMouse || ! 238: !_interruptSourceKeyboard ) return false; ! 239: ! 240: if ( _workLoop->addEventSource(_commandQueue) != kIOReturnSuccess ) ! 241: return false; ! 242: ! 243: // ! 244: // Create the keyboard nub and the mouse nub. The keyboard and mouse drivers ! 245: // will query these nubs to determine the existence of the keyboard or mouse, ! 246: // and should they exist, will attach themselves to the nub as clients. ! 247: // ! 248: ! 249: _keyboardDevice = new ApplePS2KeyboardDevice; ! 250: ! 251: if ( !_keyboardDevice || ! 252: !_keyboardDevice->init() || ! 253: !_keyboardDevice->attach(this) ) return false; ! 254: ! 255: _mouseDevice = new ApplePS2MouseDevice; ! 256: ! 257: if ( !_mouseDevice || ! 258: !_mouseDevice->init() || ! 259: !_mouseDevice->attach(this) ) return false; ! 260: ! 261: gApplePS2Controller = this; ! 262: ! 263: _keyboardDevice->registerService(); ! 264: _mouseDevice->registerService(); ! 265: ! 266: return true; // success ! 267: } ! 268: ! 269: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 270: ! 271: void ApplePS2Controller::stop(IOService * provider) ! 272: { ! 273: // ! 274: // The driver has been instructed to stop. Note that we must break all ! 275: // connections to other service objects now (ie. no registered actions, ! 276: // no pointers and retains to objects, etc), if any. ! 277: // ! 278: ! 279: // Ensure that the interrupt handlers have been uninstalled (ie. no clients). ! 280: assert(_interruptInstalledKeyboard == false); ! 281: assert(_interruptInstalledMouse == false); ! 282: ! 283: // Free the nubs we created. ! 284: if (_keyboardDevice) _keyboardDevice->release(); ! 285: if (_mouseDevice) _mouseDevice->release(); ! 286: ! 287: // Free the work loop. ! 288: if (_workLoop) _workLoop->release(); ! 289: ! 290: // Free the interrupt source and command queue. ! 291: if (_commandQueue) _commandQueue->release(); ! 292: if (_interruptSourceKeyboard) _interruptSourceKeyboard->release(); ! 293: if (_interruptSourceMouse) _interruptSourceMouse->release(); ! 294: ! 295: #if DEBUGGER_SUPPORT ! 296: // Free the keyboard queue allocation space (after disabling interrupt). ! 297: if (_keyboardQueueAlloc) ! 298: IOFree(_keyboardQueueAlloc,kKeyboardQueueSize*sizeof(KeyboardQueueElement)); ! 299: #endif DEBUGGER_SUPPORT ! 300: ! 301: gApplePS2Controller = 0; ! 302: ! 303: super::stop(provider); ! 304: } ! 305: ! 306: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 307: ! 308: IOWorkLoop * ApplePS2Controller::getWorkLoop() const ! 309: { ! 310: return _workLoop; ! 311: } ! 312: ! 313: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 314: ! 315: void ApplePS2Controller::installInterruptAction(PS2DeviceType deviceType, ! 316: OSObject * target, ! 317: PS2InterruptAction action) ! 318: { ! 319: // ! 320: // Install the keyboard or mouse interrupt handler. ! 321: // ! 322: // This method assumes only one possible mouse and only one possible ! 323: // keyboard client (ie. callers), and assumes two distinct interrupt ! 324: // handlers for each, hence needs no protection against races. ! 325: // ! 326: ! 327: // Is it the keyboard or the mouse interrupt handler that was requested? ! 328: // We only install it if it is currently uninstalled. ! 329: ! 330: if (deviceType == kDT_Keyboard && _interruptInstalledKeyboard == false) ! 331: { ! 332: target->retain(); ! 333: _interruptTargetKeyboard = target; ! 334: _interruptActionKeyboard = action; ! 335: _workLoop->addEventSource(_interruptSourceKeyboard); ! 336: getProvider()->registerInterrupt(kIRQ_Keyboard,0, interruptHandlerKeyboard); ! 337: getProvider()->enableInterrupt(kIRQ_Keyboard); ! 338: _interruptInstalledKeyboard = true; ! 339: } ! 340: ! 341: else if (deviceType == kDT_Mouse && _interruptInstalledMouse == false) ! 342: { ! 343: target->retain(); ! 344: _interruptTargetMouse = target; ! 345: _interruptActionMouse = action; ! 346: _workLoop->addEventSource(_interruptSourceMouse); ! 347: getProvider()->registerInterrupt(kIRQ_Mouse, 0, interruptHandlerMouse); ! 348: getProvider()->enableInterrupt(kIRQ_Mouse); ! 349: _interruptInstalledMouse = true; ! 350: } ! 351: } ! 352: ! 353: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 354: ! 355: void ApplePS2Controller::uninstallInterruptAction(PS2DeviceType deviceType) ! 356: { ! 357: // ! 358: // Uninstall the keyboard or mouse interrupt handler. ! 359: // ! 360: // This method assumes only one possible mouse and only one possible ! 361: // keyboard client (ie. callers), and assumes two distinct interrupt ! 362: // handlers for each, hence needs no protection against races. ! 363: // ! 364: ! 365: // Is it the keyboard or the mouse interrupt handler that was requested? ! 366: // We only install it if it is currently uninstalled. ! 367: ! 368: if (deviceType == kDT_Keyboard && _interruptInstalledKeyboard == true) ! 369: { ! 370: getProvider()->disableInterrupt(kIRQ_Keyboard); ! 371: getProvider()->unregisterInterrupt(kIRQ_Keyboard); ! 372: _workLoop->removeEventSource(_interruptSourceMouse); ! 373: _interruptInstalledKeyboard = false; ! 374: _interruptActionKeyboard = NULL; ! 375: _interruptTargetKeyboard->release(); ! 376: _interruptTargetKeyboard = 0; ! 377: } ! 378: ! 379: else if (deviceType == kDT_Mouse && _interruptInstalledMouse == true) ! 380: { ! 381: getProvider()->disableInterrupt(kIRQ_Mouse); ! 382: getProvider()->unregisterInterrupt(kIRQ_Mouse); ! 383: _workLoop->removeEventSource(_interruptSourceMouse); ! 384: _interruptInstalledMouse = false; ! 385: _interruptActionMouse = NULL; ! 386: _interruptTargetMouse->release(); ! 387: _interruptTargetMouse = 0; ! 388: } ! 389: } ! 390: ! 391: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 392: ! 393: PS2Request * ApplePS2Controller::allocateRequest() ! 394: { ! 395: // ! 396: // Allocate a request structure. Blocks until successful. Request structure ! 397: // is guaranteed to be zeroed. ! 398: // ! 399: ! 400: PS2Request * request = (PS2Request *) IOMalloc(sizeof(PS2Request)); ! 401: bzero(request, sizeof(PS2Request)); ! 402: return request; ! 403: } ! 404: ! 405: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 406: ! 407: void ApplePS2Controller::freeRequest(PS2Request * request) ! 408: { ! 409: // ! 410: // Deallocate a request structure. ! 411: // ! 412: ! 413: IOFree(request, sizeof(PS2Request)); ! 414: } ! 415: ! 416: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 417: ! 418: bool ApplePS2Controller::submitRequest(PS2Request * request) ! 419: { ! 420: // ! 421: // Submit the request to the controller for processing, asynchronously. ! 422: // ! 423: ! 424: return (_commandQueue->enqueueCommand(false, request) == KERN_SUCCESS); ! 425: } ! 426: ! 427: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 428: ! 429: void ApplePS2Controller::submitRequestAndBlock(PS2Request * request) ! 430: { ! 431: // ! 432: // Submit the request to the controller for processing, synchronously. ! 433: // ! 434: ! 435: IOSyncer * completionSyncer = IOSyncer::create(); ! 436: ! 437: assert(completionSyncer); ! 438: request->completionTarget = this; ! 439: request->completionAction = submitRequestAndBlockCompletion; ! 440: request->completionParam = completionSyncer; ! 441: ! 442: _commandQueue->enqueueCommand(true, request); ! 443: ! 444: completionSyncer->wait(); // wait 'till done ! 445: } ! 446: ! 447: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 448: ! 449: void ApplePS2Controller::submitRequestAndBlockCompletion(void *, void * param) ! 450: { // PS2CompletionAction ! 451: IOSyncer * completionSyncer = (IOSyncer *) param; ! 452: completionSyncer->signal(); ! 453: } ! 454: ! 455: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 456: ! 457: void ApplePS2Controller::interruptOccurred(IOInterruptEventSource *, int) ! 458: { // IOInterruptEventAction ! 459: // ! 460: // Our work loop has informed us of an interrupt, that is, asynchronous ! 461: // data has arrived on our input stream. Read the data and dispatch it ! 462: // to the appropriate driver. ! 463: // ! 464: // This method should only be called from our single-threaded work loop. ! 465: // ! 466: ! 467: UInt8 status; ! 468: ! 469: #if DEBUGGER_SUPPORT ! 470: lockController(); // (lock out interrupt + access to queue) ! 471: while (1) ! 472: { ! 473: // See if data is available on the keyboard input stream (off queue); ! 474: // we do not read keyboard data from the real data port if it should ! 475: // be available. ! 476: ! 477: if (dequeueKeyboardData(&status)) ! 478: { ! 479: unlockController(); ! 480: dispatchDriverInterrupt(kDT_Keyboard, status); ! 481: lockController(); ! 482: } ! 483: ! 484: // See if data is available on the mouse input stream (off real port). ! 485: ! 486: else if ( (inb(kCommandPort) & (kOutputReady | kMouseData)) == ! 487: (kOutputReady | kMouseData)) ! 488: { ! 489: unlockController(); ! 490: dispatchDriverInterrupt(kDT_Mouse, inb(kDataPort)); ! 491: lockController(); ! 492: } ! 493: else break; // out of loop ! 494: } ! 495: unlockController(); // (release interrupt lockout + access to queue) ! 496: #else ! 497: // Loop only while there is data currently on the input stream. ! 498: ! 499: while ( ((status = inb(kCommandPort)) & kOutputReady) ) ! 500: { ! 501: // Read in and dispatch the data, but only if it isn't what is required ! 502: // by the active command. ! 503: ! 504: dispatchDriverInterrupt((status&kMouseData)?kDT_Mouse:kDT_Keyboard, ! 505: inb(kDataPort)); ! 506: } ! 507: #endif DEBUGGER_SUPPORT ! 508: } ! 509: ! 510: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 511: ! 512: void ApplePS2Controller::dispatchDriverInterrupt(PS2DeviceType deviceType, ! 513: UInt8 data) ! 514: { ! 515: // ! 516: // The supplied data is passed onto the interrupt handler in the appropriate ! 517: // driver, if one is registered, otherwise the data byte is thrown away. ! 518: // ! 519: // This method should only be called from our single-threaded work loop. ! 520: // ! 521: ! 522: if ( deviceType == kDT_Mouse ) ! 523: { ! 524: // Dispatch the data to the mouse driver. ! 525: if (_interruptInstalledMouse) ! 526: (*_interruptActionMouse)(_interruptTargetMouse, data); ! 527: } ! 528: else if ( deviceType == kDT_Keyboard ) ! 529: { ! 530: // Dispatch the data to the keyboard driver. ! 531: if (_interruptInstalledKeyboard) ! 532: (*_interruptActionKeyboard)(_interruptTargetKeyboard, data); ! 533: } ! 534: } ! 535: ! 536: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 537: ! 538: void ApplePS2Controller::processRequest(PS2Request * request, ! 539: void * /* field1 */, ! 540: void * /* field2 */, ! 541: void * /* field3 */) ! 542: // IOCommandQueueAction ! 543: { ! 544: // ! 545: // Our work loop has informed us of a request submission. Process ! 546: // the request. Note that this code "figures out" when the mouse ! 547: // input stream should be read over the keyboard input stream. ! 548: // ! 549: // This method should only be called from our single-threaded work loop. ! 550: // ! 551: ! 552: UInt8 byte; ! 553: PS2DeviceType deviceMode = kDT_Keyboard; ! 554: bool failed = false; ! 555: bool transmitToMouse = false; ! 556: unsigned index; ! 557: ! 558: // Process each of the commands in the list. ! 559: ! 560: for (index = 0; index < request->commandsCount; index++) ! 561: { ! 562: switch (request->commands[index].command) ! 563: { ! 564: case kPS2C_ReadDataPort: ! 565: request->commands[index].inOrOut = readDataPort(deviceMode); ! 566: break; ! 567: ! 568: case kPS2C_ReadDataPortAndCompare: ! 569: #if OUT_OF_ORDER_DATA_CORRECTION_FEATURE ! 570: byte = readDataPort(deviceMode, request->commands[index].inOrOut); ! 571: #else ! 572: byte = readDataPort(deviceMode); ! 573: #endif ! 574: failed = (byte != request->commands[index].inOrOut); ! 575: break; ! 576: ! 577: case kPS2C_WriteDataPort: ! 578: writeDataPort(request->commands[index].inOrOut); ! 579: if (transmitToMouse) // next reads from mouse input stream ! 580: { ! 581: deviceMode = kDT_Mouse; ! 582: transmitToMouse = false; ! 583: } ! 584: else ! 585: { ! 586: deviceMode = kDT_Keyboard; ! 587: } ! 588: break; ! 589: ! 590: case kPS2C_WriteCommandPort: ! 591: writeCommandPort(request->commands[index].inOrOut); ! 592: if (request->commands[index].inOrOut == kCP_TransmitToMouse) ! 593: transmitToMouse = true; // preparing to transmit data to mouse ! 594: break; ! 595: } ! 596: ! 597: if (failed) break; ! 598: } ! 599: ! 600: // If a command failed and stopped the request processing, store its ! 601: // index into the commandsCount field. ! 602: ! 603: if (failed) request->commandsCount = index; ! 604: ! 605: // Invoke the completion routine, if one was supplied. ! 606: ! 607: if (request->completionTarget && request->completionAction) ! 608: { ! 609: (*request->completionAction)(request->completionTarget, ! 610: request->completionParam); ! 611: } ! 612: } ! 613: ! 614: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 615: ! 616: UInt8 ApplePS2Controller::readDataPort(PS2DeviceType deviceType) ! 617: { ! 618: // ! 619: // Blocks until keyboard or mouse data is available from the controller ! 620: // and returns that data. Note, if mouse data is requested but keyboard ! 621: // data is what is available, the data is delivered to the appropriate ! 622: // driver interrupt routine immediately (effectively, the request is ! 623: // "preempted" temporarily). ! 624: // ! 625: // There is a built-in timeout for this command of (timeoutCounter X ! 626: // kDataDelay) microseconds, approximately. ! 627: // ! 628: // This method should only be called from our single-threaded work loop. ! 629: // ! 630: ! 631: UInt8 readByte; ! 632: UInt8 status; ! 633: UInt32 timeoutCounter = 10000; // (timeoutCounter * kDataDelay = 70 ms) ! 634: ! 635: while (1) ! 636: { ! 637: #if DEBUGGER_SUPPORT ! 638: lockController(); // (lock out interrupt + access to queue) ! 639: if (deviceType == kDT_Keyboard && dequeueKeyboardData(&readByte)) ! 640: { ! 641: unlockController(); ! 642: return readByte; ! 643: } ! 644: #endif DEBUGGER_SUPPORT ! 645: ! 646: // ! 647: // Wait for the controller's output buffer to become ready. ! 648: // ! 649: ! 650: while (timeoutCounter && !((status = inb(kCommandPort)) & kOutputReady)) ! 651: { ! 652: timeoutCounter--; ! 653: IODelay(kDataDelay); ! 654: } ! 655: ! 656: // ! 657: // If we timed out, something went awfully wrong; return a fake value. ! 658: // ! 659: ! 660: if (timeoutCounter == 0) ! 661: { ! 662: #if DEBUGGER_SUPPORT ! 663: unlockController(); // (release interrupt lockout + access to queue) ! 664: #endif DEBUGGER_SUPPORT ! 665: ! 666: IOLog("%s: Timed out on %s input stream.\n", getName(), ! 667: (deviceType == kDT_Keyboard) ? "keyboard" : "mouse"); ! 668: return 0; ! 669: } ! 670: ! 671: // ! 672: // Read in the data. We return the data, however, only if it arrived on ! 673: // the requested input stream. ! 674: // ! 675: ! 676: readByte = inb(kDataPort); ! 677: ! 678: #if DEBUGGER_SUPPORT ! 679: unlockController(); // (release interrupt lockout + access to queue) ! 680: #endif DEBUGGER_SUPPORT ! 681: ! 682: if ( (status & kMouseData) ) ! 683: { ! 684: if (deviceType == kDT_Mouse) return readByte; ! 685: } ! 686: else ! 687: { ! 688: if (deviceType == kDT_Keyboard) return readByte; ! 689: } ! 690: ! 691: // ! 692: // The data we just received is for the other input stream, not the one ! 693: // that was requested, so dispatch other device's interrupt handler. ! 694: // ! 695: ! 696: dispatchDriverInterrupt((deviceType==kDT_Keyboard)?kDT_Mouse:kDT_Keyboard, ! 697: readByte); ! 698: } // while (forever) ! 699: } ! 700: ! 701: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 702: ! 703: #if OUT_OF_ORDER_DATA_CORRECTION_FEATURE ! 704: ! 705: UInt8 ApplePS2Controller::readDataPort(PS2DeviceType deviceType, ! 706: UInt8 expectedByte) ! 707: { ! 708: // ! 709: // Blocks until keyboard or mouse data is available from the controller ! 710: // and returns that data. Note, if mouse data is requested but keyboard ! 711: // data is what is available, the data is delivered to the appropriate ! 712: // driver interrupt routine immediately (effectively, the request is ! 713: // "preempted" temporarily). ! 714: // ! 715: // There is a built-in timeout for this command of (timeoutCounter X ! 716: // kDataDelay) microseconds, approximately. ! 717: // ! 718: // This method should only be called from our single-threaded work loop. ! 719: // ! 720: // This version of readDataPort does exactly the same as the original, ! 721: // except that if the value that should be read from the (appropriate) ! 722: // input stream is not what is expected, we make these assumptions: ! 723: // ! 724: // (a) the data byte we did get was "asynchronous" data being sent by ! 725: // the device, which has not figured out that it has to respond to ! 726: // the command we just sent to it. ! 727: // (b) that the real "expected" response will be the next byte in the ! 728: // stream; so what we do is put aside the first byte we read and ! 729: // wait for the next byte; if it's the expected value, we dispatch ! 730: // the first byte we read to the driver's interrupt handler, then ! 731: // return the expected byte. The caller will have never known that ! 732: // asynchronous data arrived at a very bad time. ! 733: // (c) that the real "expected" response will arrive within (kDataDelay ! 734: // X timeoutCounter) microseconds from the time the call is made. ! 735: // ! 736: ! 737: UInt8 firstByte = 0; ! 738: bool firstByteHeld = false; ! 739: UInt8 readByte; ! 740: bool requestedStream; ! 741: UInt8 status; ! 742: UInt32 timeoutCounter = 10000; // (timeoutCounter * kDataDelay = 70 ms) ! 743: ! 744: while (1) ! 745: { ! 746: #if DEBUGGER_SUPPORT ! 747: lockController(); // (lock out interrupt + access to queue) ! 748: if (deviceType == kDT_Keyboard && dequeueKeyboardData(&readByte)) ! 749: { ! 750: requestedStream = true; ! 751: goto skipForwardToY; ! 752: } ! 753: #endif DEBUGGER_SUPPORT ! 754: ! 755: // ! 756: // Wait for the controller's output buffer to become ready. ! 757: // ! 758: ! 759: while (timeoutCounter && !((status = inb(kCommandPort)) & kOutputReady)) ! 760: { ! 761: timeoutCounter--; ! 762: IODelay(kDataDelay); ! 763: } ! 764: ! 765: // ! 766: // If we timed out, we return the first byte we read, unless THIS IS the ! 767: // first byte we are trying to read, then something went awfully wrong ! 768: // and we return a fake value rather than lock up the controller longer. ! 769: // ! 770: ! 771: if (timeoutCounter == 0) ! 772: { ! 773: #if DEBUGGER_SUPPORT ! 774: unlockController(); // release interrupt lockout + access to queue ! 775: #endif DEBUGGER_SUPPORT ! 776: ! 777: if (firstByteHeld) return firstByte; ! 778: ! 779: IOLog("%s: Timed out on %s input stream.\n", getName(), ! 780: (deviceType == kDT_Keyboard) ? "keyboard" : "mouse"); ! 781: return 0; ! 782: } ! 783: ! 784: // ! 785: // Read in the data. We process the data, however, only if it arrived on ! 786: // the requested input stream. ! 787: // ! 788: ! 789: readByte = inb(kDataPort); ! 790: requestedStream = false; ! 791: ! 792: if ( (status & kMouseData) ) ! 793: { ! 794: if (deviceType == kDT_Mouse) requestedStream = true; ! 795: } ! 796: else ! 797: { ! 798: if (deviceType == kDT_Keyboard) requestedStream = true; ! 799: } ! 800: ! 801: #if DEBUGGER_SUPPORT ! 802: skipForwardToY: ! 803: unlockController(); // (release interrupt lockout + access to queue) ! 804: #endif DEBUGGER_SUPPORT ! 805: ! 806: if (requestedStream) ! 807: { ! 808: if (readByte == expectedByte) ! 809: { ! 810: if (firstByteHeld == false) ! 811: { ! 812: // ! 813: // Normal case. Return first byte received. ! 814: // ! 815: ! 816: return readByte; ! 817: } ! 818: else ! 819: { ! 820: // ! 821: // Our assumption was correct. The second byte matched. Dispatch ! 822: // the first byte to the interrupt handler, and return the second. ! 823: // ! 824: ! 825: dispatchDriverInterrupt(deviceType, firstByte); ! 826: return readByte; ! 827: } ! 828: } ! 829: else // (readByte does not match expectedByte) ! 830: { ! 831: if (firstByteHeld == false) ! 832: { ! 833: // ! 834: // The first byte was received, and does not match the byte we are ! 835: // expecting. Put it aside for the moment. ! 836: // ! 837: ! 838: firstByteHeld = true; ! 839: firstByte = readByte; ! 840: } ! 841: else if (readByte != expectedByte) ! 842: { ! 843: // ! 844: // The second byte mismatched as well. I have yet to see this case ! 845: // occur [Dan], however I do think it's plausible. No error logged. ! 846: // ! 847: ! 848: dispatchDriverInterrupt(deviceType, readByte); ! 849: return firstByte; ! 850: } ! 851: } ! 852: } ! 853: else ! 854: { ! 855: // ! 856: // The data we just received is for the other input stream, not ours, ! 857: // so dispatch appropriate interrupt handler. ! 858: // ! 859: ! 860: dispatchDriverInterrupt((deviceType==kDT_Keyboard)?kDT_Mouse:kDT_Keyboard, ! 861: readByte); ! 862: } ! 863: } // while (forever) ! 864: } ! 865: ! 866: #endif ! 867: ! 868: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 869: ! 870: void ApplePS2Controller::writeDataPort(UInt8 byte) ! 871: { ! 872: // ! 873: // Block until room in the controller's input buffer is available, then ! 874: // write the given byte to the Data Port. ! 875: // ! 876: // This method should only be dispatched from our single-threaded work loop. ! 877: // ! 878: ! 879: while (inb(kCommandPort) & kInputBusy) IODelay(kDataDelay); ! 880: outb(kDataPort, byte); ! 881: } ! 882: ! 883: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 884: ! 885: void ApplePS2Controller::writeCommandPort(UInt8 byte) ! 886: { ! 887: // ! 888: // Block until room in the controller's input buffer is available, then ! 889: // write the given byte to the Command Port. ! 890: // ! 891: // This method should only be dispatched from our single-threaded work loop. ! 892: // ! 893: ! 894: while (inb(kCommandPort) & kInputBusy) IODelay(kDataDelay); ! 895: outb(kCommandPort, byte); ! 896: } ! 897: ! 898: // ============================================================================= ! 899: // Escape-Key Processing Stuff Localized Here (eg. Mini-Monitor) ! 900: // ! 901: ! 902: #if DEBUGGER_SUPPORT ! 903: ! 904: #define kModifierShiftLeft 0x01 ! 905: #define kModifierShiftRight 0x02 ! 906: #define kModifierCtrlLeft 0x04 ! 907: #define kModifierCtrlRight 0x08 ! 908: #define kModifierAltLeft 0x10 ! 909: #define kModifierAltRight 0x20 ! 910: #define kModifierWindowsLeft 0x40 ! 911: #define kModifierWindowsRight 0x80 ! 912: ! 913: #define kModifierShiftMask (kModifierShiftLeft | kModifierShiftRight ) ! 914: #define kModifierCtrlMask (kModifierCtrlLeft | kModifierCtrlRight ) ! 915: #define kModifierAltMask (kModifierAltLeft | kModifierAltRight ) ! 916: #define kModifierWindowsMask (kModifierWindowsLeft | kModifierWindowsRight) ! 917: ! 918: bool ApplePS2Controller::doEscape(UInt8 scancode) ! 919: { ! 920: static struct ! 921: { ! 922: UInt8 scancode; ! 923: UInt8 extended; ! 924: UInt16 modifier; ! 925: } modifierTable[] = { { kSC_Alt, false, kModifierAltLeft }, ! 926: { kSC_Alt, true, kModifierAltRight }, ! 927: { kSC_Ctrl, false, kModifierCtrlLeft }, ! 928: { kSC_Ctrl, true, kModifierCtrlRight }, ! 929: { kSC_ShiftLeft, false, kModifierShiftLeft }, ! 930: { kSC_ShiftRight, false, kModifierShiftRight }, ! 931: { kSC_WindowsLeft, true, kModifierWindowsLeft }, ! 932: { kSC_WindowsRight, true, kModifierWindowsRight }, ! 933: { 0, 0, 0 } }; ! 934: ! 935: UInt32 index; ! 936: bool releaseModifiers = false; ! 937: bool upBit = (scancode & kSC_UpBit) ? true : false; ! 938: ! 939: // ! 940: // See if this is an extened scancode sequence. ! 941: // ! 942: ! 943: if (scancode == kSC_Extend) ! 944: { ! 945: _extendedState = true; ! 946: return false; ! 947: } ! 948: ! 949: // ! 950: // Update the modifier state, if applicable. ! 951: // ! 952: ! 953: scancode &= ~kSC_UpBit; ! 954: ! 955: for (index = 0; modifierTable[index].scancode; index++) ! 956: { ! 957: if ( modifierTable[index].scancode == scancode && ! 958: modifierTable[index].extended == _extendedState ) ! 959: { ! 960: if (upBit) _modifierState &= ~modifierTable[index].modifier; ! 961: else _modifierState |= modifierTable[index].modifier; ! 962: ! 963: _extendedState = false; ! 964: return false; ! 965: } ! 966: } ! 967: ! 968: // ! 969: // Call the debugger function, if applicable. ! 970: // ! 971: ! 972: if (scancode == kSC_Delete) // (both extended and non-extended scancodes) ! 973: { ! 974: if ( _modifierState == kModifierAltLeft || ! 975: _modifierState == kModifierAltRight ) ! 976: { ! 977: // Disable the mouse by forcing the clock line low. ! 978: ! 979: while (inb(kCommandPort) & kInputBusy) IODelay(kDataDelay); ! 980: outb(kCommandPort, kCP_DisableMouseClock); ! 981: ! 982: // Call the debugger function. ! 983: ! 984: Debugger("Programmer Key"); ! 985: ! 986: // Re-enable the mouse by making the clock line active. ! 987: ! 988: while (inb(kCommandPort) & kInputBusy) IODelay(kDataDelay); ! 989: outb(kCommandPort, kCP_EnableMouseClock); ! 990: ! 991: releaseModifiers = true; ! 992: } ! 993: } ! 994: ! 995: // ! 996: // Release all the modifier keys that were down before the debugger ! 997: // function was called (assumption is that they are no longer held ! 998: // down after the debugger function returns). ! 999: // ! 1000: ! 1001: if (releaseModifiers) ! 1002: { ! 1003: for (index = 0; modifierTable[index].scancode; index++) ! 1004: { ! 1005: if ( _modifierState & modifierTable[index].modifier ) ! 1006: { ! 1007: if (modifierTable[index].extended) enqueueKeyboardData(kSC_Extend); ! 1008: enqueueKeyboardData(modifierTable[index].scancode | kSC_UpBit); ! 1009: } ! 1010: } ! 1011: _modifierState = 0x00; ! 1012: } ! 1013: ! 1014: // ! 1015: // Update all other state and return status. ! 1016: // ! 1017: ! 1018: _extendedState = false; ! 1019: return (releaseModifiers); ! 1020: } ! 1021: ! 1022: void ApplePS2Controller::enqueueKeyboardData(UInt8 key) ! 1023: { ! 1024: // ! 1025: // Enqueue the supplied keyboard data onto our internal queues. The ! 1026: // controller must already be locked. ! 1027: // ! 1028: ! 1029: KeyboardQueueElement * element; ! 1030: ! 1031: // Obtain an unused keyboard data element. ! 1032: if (!queue_empty(&_keyboardQueueUnused)) ! 1033: { ! 1034: queue_remove_first(&_keyboardQueueUnused, ! 1035: element, KeyboardQueueElement *, chain); ! 1036: ! 1037: // Store the new keyboard data element on the queue. ! 1038: element->data = key; ! 1039: queue_enter(&_keyboardQueue, element, KeyboardQueueElement *, chain); ! 1040: } ! 1041: } ! 1042: ! 1043: bool ApplePS2Controller::dequeueKeyboardData(UInt8 * key) ! 1044: { ! 1045: // ! 1046: // Dequeue keyboard data from our internal queues, if the queue is not ! 1047: // empty. Should the queue be empty, false is returned. The controller ! 1048: // must already be locked. ! 1049: // ! 1050: ! 1051: KeyboardQueueElement * element; ! 1052: ! 1053: // Obtain an unused keyboard data element. ! 1054: if (!queue_empty(&_keyboardQueue)) ! 1055: { ! 1056: queue_remove_first(&_keyboardQueue, element, KeyboardQueueElement *, chain); ! 1057: *key = element->data; ! 1058: ! 1059: // Place the unused keyboard data element onto the unused queue. ! 1060: queue_enter(&_keyboardQueueUnused, element, KeyboardQueueElement *, chain); ! 1061: ! 1062: return true; ! 1063: } ! 1064: return false; ! 1065: } ! 1066: ! 1067: void ApplePS2Controller::unlockController(void) ! 1068: { ! 1069: usimple_unlock(&_controllerLock); ! 1070: ml_set_interrupts_enabled(_controllerLockOldSpl); ! 1071: } ! 1072: ! 1073: void ApplePS2Controller::lockController(void) ! 1074: { ! 1075: int oldSpl = ml_set_interrupts_enabled(FALSE); ! 1076: usimple_lock(&_controllerLock); ! 1077: _controllerLockOldSpl = oldSpl; ! 1078: } ! 1079: ! 1080: #endif DEBUGGER_SUPPORT
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.