|
|
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/IOLib.h> ! 25: #include "ApplePS2Mouse.h" ! 26: ! 27: // ============================================================================= ! 28: // ApplePS2Mouse Class Implementation ! 29: // ! 30: ! 31: #define super IOHIPointing ! 32: OSDefineMetaClassAndStructors(ApplePS2Mouse, IOHIPointing); ! 33: ! 34: UInt32 ApplePS2Mouse::deviceType() { return NX_EVS_DEVICE_TYPE_MOUSE; }; ! 35: UInt32 ApplePS2Mouse::interfaceID() { return NX_EVS_DEVICE_INTERFACE_BUS_ACE; }; ! 36: ! 37: IOItemCount ApplePS2Mouse::buttonCount() { return 3; }; ! 38: IOFixed ApplePS2Mouse::resolution() { return _resolution; }; ! 39: ! 40: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 41: ! 42: bool ApplePS2Mouse::init(OSDictionary * properties) ! 43: { ! 44: // ! 45: // Initialize this object's minimal state. This is invoked right after this ! 46: // object is instantiated. ! 47: // ! 48: ! 49: if (!super::init(properties)) return false; ! 50: ! 51: _device = 0; ! 52: _interruptHandlerInstalled = false; ! 53: _packetByteCount = 0; ! 54: _packetLength = kPacketLengthStandard; ! 55: _resolution = (150) << 16; // (default is 150 dpi; 6 counts/mm) ! 56: _type = kMouseTypeStandard; ! 57: ! 58: return true; ! 59: } ! 60: ! 61: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 62: ! 63: ApplePS2Mouse * ApplePS2Mouse::probe(IOService * provider, SInt32 * score) ! 64: { ! 65: // ! 66: // The driver has been instructed to verify the presence of the actual ! 67: // hardware we represent. We are guaranteed by the controller that the ! 68: // mouse clock is enabled and the mouse itself is disabled (thus it ! 69: // won't send any asynchronous mouse data that may mess up the ! 70: // responses expected by the commands we send it). ! 71: // ! 72: ! 73: ApplePS2MouseDevice * device = (ApplePS2MouseDevice *)provider; ! 74: PS2Request * request = device->allocateRequest(); ! 75: bool success; ! 76: ! 77: if (!super::probe(provider, score)) return 0; ! 78: ! 79: // ! 80: // Check to see if acknowledges are being received for commands to the mouse. ! 81: // ! 82: ! 83: // (get information command) ! 84: request->commands[0].command = kPS2C_WriteCommandPort; ! 85: request->commands[0].inOrOut = kCP_TransmitToMouse; ! 86: request->commands[1].command = kPS2C_WriteDataPort; ! 87: request->commands[1].inOrOut = kDP_GetMouseInformation; ! 88: request->commands[2].command = kPS2C_ReadDataPortAndCompare; ! 89: request->commands[2].inOrOut = kSC_Acknowledge; ! 90: request->commands[3].command = kPS2C_ReadDataPort; ! 91: request->commands[3].inOrOut = 0; ! 92: request->commands[4].command = kPS2C_ReadDataPort; ! 93: request->commands[4].inOrOut = 0; ! 94: request->commands[5].command = kPS2C_ReadDataPort; ! 95: request->commands[5].inOrOut = 0; ! 96: request->commandsCount = 6; ! 97: device->submitRequestAndBlock(request); ! 98: ! 99: // (free the request) ! 100: success = (request->commandsCount == 6); ! 101: device->freeRequest(request); ! 102: ! 103: return (success) ? this : 0; ! 104: } ! 105: ! 106: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 107: ! 108: bool ApplePS2Mouse::start(IOService * provider) ! 109: { ! 110: // ! 111: // The driver has been instructed to start. This is called after a ! 112: // successful probe and match. ! 113: // ! 114: ! 115: if (!super::start(provider)) return false; ! 116: ! 117: // ! 118: // Maintain a pointer to and retain the provider object. ! 119: // ! 120: ! 121: _device = (ApplePS2MouseDevice *)provider; ! 122: _device->retain(); ! 123: ! 124: // ! 125: // Install our driver's interrupt handler, for asynchronous data delivery. ! 126: // ! 127: ! 128: _device->installInterruptAction(this, ! 129: (PS2InterruptAction)&ApplePS2Mouse::interruptOccurred); ! 130: _interruptHandlerInstalled = true; ! 131: ! 132: // ! 133: // Obtain our mouse's resolution and sampling rate. ! 134: // ! 135: ! 136: switch (getMouseInformation() & 0x00FF00) ! 137: { ! 138: case 0x0000: _resolution = (25) << 16; break; // 25 dpi ! 139: case 0x0100: _resolution = (50) << 16; break; // 50 dpi ! 140: case 0x0200: _resolution = (100) << 16; break; // 100 dpi ! 141: case 0x0300: _resolution = (200) << 16; break; // 200 dpi ! 142: default: _resolution = (150) << 16; break; // 150 dpi ! 143: } ! 144: ! 145: // ! 146: // Enable the Intellimouse mode, should this be an Intellimouse. ! 147: // ! 148: ! 149: if ( setIntellimouseMode() == true ) ! 150: { ! 151: _packetLength = kPacketLengthIntellimouse; ! 152: _type = kMouseTypeIntellimouse; ! 153: } ! 154: ! 155: // ! 156: // Enable the mouse clock (should already be so) and the mouse IRQ line. ! 157: // ! 158: ! 159: setCommandByte(kCB_EnableMouseIRQ, kCB_DisableMouseClock); ! 160: ! 161: // ! 162: // Finally, we enable the mouse itself, so that it may start reporting ! 163: // mouse events. ! 164: // ! 165: ! 166: setMouseEnable(true); ! 167: ! 168: return true; ! 169: } ! 170: ! 171: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 172: ! 173: void ApplePS2Mouse::stop(IOService * provider) ! 174: { ! 175: // ! 176: // The driver has been instructed to stop. Note that we must break all ! 177: // connections to other service objects now (ie. no registered actions, ! 178: // no pointers and retains to objects, etc), if any. ! 179: // ! 180: ! 181: assert(_device == provider); ! 182: ! 183: // ! 184: // Disable the mouse itself, so that it may stop reporting mouse events. ! 185: // ! 186: ! 187: setMouseEnable(false); ! 188: ! 189: // ! 190: // Disable the mouse clock and the mouse IRQ line. ! 191: // ! 192: ! 193: setCommandByte(kCB_DisableMouseClock, kCB_EnableMouseIRQ); ! 194: ! 195: // ! 196: // Uninstall the interrupt handler. ! 197: // ! 198: ! 199: if ( _interruptHandlerInstalled ) _device->uninstallInterruptAction(); ! 200: _interruptHandlerInstalled = false; ! 201: ! 202: // ! 203: // Release the pointer to the provider object. ! 204: // ! 205: ! 206: _device->release(); ! 207: _device = 0; ! 208: ! 209: super::stop(provider); ! 210: } ! 211: ! 212: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 213: ! 214: void ApplePS2Mouse::interruptOccurred(UInt8 data) // PS2InterruptAction ! 215: { ! 216: // ! 217: // This will be invoked automatically from our device when asynchronous mouse ! 218: // needs to be delivered. Process the mouse data. Do NOT send any BLOCKING ! 219: // commands to our device in this context. ! 220: // ! 221: // We ignore all bytes until we see the start of a packet, otherwise the mouse ! 222: // packets may get out of sequence and things will get very confusing. ! 223: // ! 224: ! 225: if (_packetByteCount == 0 && ((data == kSC_Acknowledge) || !(data & 0x08))) ! 226: { ! 227: IOLog("%s: Unexpected data from PS/2 controller.\n", getName()); ! 228: return; ! 229: } ! 230: ! 231: // ! 232: // Add this byte to the packet buffer. If the packet is complete, that is, ! 233: // we have the three bytes, dispatch this packet for processing. ! 234: // ! 235: ! 236: _packetBuffer[_packetByteCount++] = data; ! 237: ! 238: if (_packetByteCount == _packetLength) ! 239: { ! 240: dispatchRelativePointerEventWithPacket(_packetBuffer); ! 241: _packetByteCount = 0; ! 242: } ! 243: } ! 244: ! 245: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 246: ! 247: void ApplePS2Mouse::dispatchRelativePointerEventWithPacket(UInt8 * packet) ! 248: { ! 249: // ! 250: // Process the three byte mouse packet that was retreived from the mouse. ! 251: // The format of the bytes is as follows: ! 252: // ! 253: // 7 6 5 4 3 2 1 0 ! 254: // YO XO YS XS 1 M R L ! 255: // X7 X6 X5 X4 X3 X3 X1 X0 ! 256: // Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 ! 257: // Z7 Z6 Z5 Z4 Z3 Z2 Z1 Z0 <- fourth byte returned only for Intellimouse type ! 258: // ! 259: ! 260: UInt32 buttons = 0; ! 261: SInt32 dx; ! 262: SInt32 dy; ! 263: SInt32 dz; ! 264: AbsoluteTime now; ! 265: ! 266: if ( !(packet[0] & 0x1) ) buttons |= 0x1; // left button (bit 0 in packet) ! 267: if ( !(packet[0] & 0x2) ) buttons |= 0x2; // right button (bit 1 in packet) ! 268: if ( !(packet[0] & 0x4) ) buttons |= 0x4; // middle button (bit 2 in packet) ! 269: ! 270: dx = ((packet[0] & 0x10) ? 0xffffff00 : 0 ) | packet[1]; ! 271: dy = -(((packet[0] & 0x20) ? 0xffffff00 : 0 ) | packet[2]); ! 272: dz = (SInt32)((SInt8)packet[3]); ! 273: ! 274: clock_get_uptime(&now); ! 275: ! 276: dispatchRelativePointerEvent(dx, dy, buttons, now); ! 277: ! 278: return; ! 279: } ! 280: ! 281: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 282: ! 283: void ApplePS2Mouse::setMouseEnable(bool enable) ! 284: { ! 285: // ! 286: // Instructs the mouse to start or stop the reporting of mouse events. ! 287: // Be aware that while the mouse is enabled, asynchronous mouse events ! 288: // may arrive in the middle of command sequences sent to the controller, ! 289: // and may get confused for expected command responses. ! 290: // ! 291: // It is safe to issue this request from the interrupt/completion context. ! 292: // ! 293: ! 294: PS2Request * request = _device->allocateRequest(); ! 295: ! 296: // (mouse enable/disable command) ! 297: request->commands[0].command = kPS2C_WriteCommandPort; ! 298: request->commands[0].inOrOut = kCP_TransmitToMouse; ! 299: request->commands[1].command = kPS2C_WriteDataPort; ! 300: request->commands[1].inOrOut = (enable)?kDP_Enable:kDP_SetDefaultsAndDisable; ! 301: request->commands[2].command = kPS2C_ReadDataPortAndCompare; ! 302: request->commands[2].inOrOut = kSC_Acknowledge; ! 303: request->commandsCount = 3; ! 304: _device->submitRequest(request); // asynchronous, auto-free'd ! 305: } ! 306: ! 307: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 308: ! 309: void ApplePS2Mouse::setMouseSampleRate(UInt8 sampleRate) ! 310: { ! 311: // ! 312: // Instructs the mouse to change its sampling rate to the given value, in ! 313: // reports per second. ! 314: // ! 315: // It is safe to issue this request from the interrupt/completion context. ! 316: // ! 317: ! 318: PS2Request * request = _device->allocateRequest(); ! 319: ! 320: // (set mouse sample rate command) ! 321: request->commands[0].command = kPS2C_WriteCommandPort; ! 322: request->commands[0].inOrOut = kCP_TransmitToMouse; ! 323: request->commands[1].command = kPS2C_WriteDataPort; ! 324: request->commands[1].inOrOut = kDP_SetMouseSampleRate; ! 325: request->commands[2].command = kPS2C_ReadDataPortAndCompare; ! 326: request->commands[2].inOrOut = kSC_Acknowledge; ! 327: request->commands[3].command = kPS2C_WriteCommandPort; ! 328: request->commands[3].inOrOut = kCP_TransmitToMouse; ! 329: request->commands[4].command = kPS2C_WriteDataPort; ! 330: request->commands[4].inOrOut = sampleRate; ! 331: request->commands[5].command = kPS2C_ReadDataPortAndCompare; ! 332: request->commands[5].inOrOut = kSC_Acknowledge; ! 333: request->commandsCount = 6; ! 334: _device->submitRequest(request); // asynchronous, auto-free'd ! 335: } ! 336: ! 337: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 338: ! 339: bool ApplePS2Mouse::setIntellimouseMode() ! 340: { ! 341: // ! 342: // Determines whether this mouse is a Microsoft Intellimouse, and if it is, ! 343: // it enables it (the mouse will send 4 byte packets for mouse events from ! 344: // then on). Returns true if the Intellimouse mode was succesfully enabled. ! 345: // ! 346: // Do NOT issue this request from the interrupt/completion context. ! 347: // ! 348: ! 349: UInt32 mouseInfo; ! 350: bool isIntellimouse; ! 351: ! 352: // ! 353: // Obtain the current sample rate, in order that we may restore it after ! 354: // the Intellimouse command sequence completes. ! 355: // ! 356: ! 357: mouseInfo = getMouseInformation(); ! 358: ! 359: if (mouseInfo == (UInt32)(-1)) return false; ! 360: ! 361: // ! 362: // Generate the special command sequence to enable the 'Intellimouse' mode. ! 363: // The sequence is to set the sampling rate to 200, 100, then 80, at which ! 364: // point the mouse will start sending 4 byte packets for mouse events and ! 365: // return a mouse ID of 3. ! 366: // ! 367: ! 368: setMouseSampleRate(200); ! 369: setMouseSampleRate(100); ! 370: setMouseSampleRate(80 ); ! 371: ! 372: // ! 373: // Determine whether we have an Intellimouse by asking for the mouse's ID. ! 374: // ! 375: ! 376: isIntellimouse = ( getMouseID() == kMouseTypeIntellimouse ); ! 377: ! 378: // ! 379: // Restore the original sampling rate, before we obliterated it. ! 380: // ! 381: ! 382: setMouseSampleRate(mouseInfo & 0x0000FF); ! 383: ! 384: return isIntellimouse; ! 385: } ! 386: ! 387: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 388: ! 389: UInt32 ApplePS2Mouse::getMouseInformation() ! 390: { ! 391: // ! 392: // Asks the mouse to transmit its three information bytes. Should the ! 393: // mouse not respond, a value of (UInt32)(-1) is returned. ! 394: // ! 395: // Do NOT issue this request from the interrupt/completion context. ! 396: // ! 397: ! 398: PS2Request * request = _device->allocateRequest(); ! 399: UInt32 returnValue = (UInt32)(-1); ! 400: ! 401: // (get information command) ! 402: request->commands[0].command = kPS2C_WriteCommandPort; ! 403: request->commands[0].inOrOut = kCP_TransmitToMouse; ! 404: request->commands[1].command = kPS2C_WriteDataPort; ! 405: request->commands[1].inOrOut = kDP_GetMouseInformation; ! 406: request->commands[2].command = kPS2C_ReadDataPortAndCompare; ! 407: request->commands[2].inOrOut = kSC_Acknowledge; ! 408: request->commands[3].command = kPS2C_ReadDataPort; ! 409: request->commands[3].inOrOut = 0; ! 410: request->commands[4].command = kPS2C_ReadDataPort; ! 411: request->commands[4].inOrOut = 0; ! 412: request->commands[5].command = kPS2C_ReadDataPort; ! 413: request->commands[5].inOrOut = 0; ! 414: request->commandsCount = 6; ! 415: _device->submitRequestAndBlock(request); ! 416: ! 417: if (request->commandsCount == 6) // success? ! 418: { ! 419: returnValue = ((UInt32)request->commands[3].inOrOut << 16) | ! 420: ((UInt32)request->commands[4].inOrOut << 8 ) | ! 421: ((UInt32)request->commands[5].inOrOut); ! 422: } ! 423: _device->freeRequest(request); ! 424: ! 425: return returnValue; ! 426: } ! 427: ! 428: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 429: ! 430: UInt8 ApplePS2Mouse::getMouseID() ! 431: { ! 432: // ! 433: // Asks the mouse to transmit its identification byte. Should the mouse ! 434: // not respond, a value of (UInt8)(-1) is returned. ! 435: // ! 436: // Note that some documentation on PS/2 mice implies that two identification ! 437: // bytes are returned and not one. This was proven to be false in my tests. ! 438: // ! 439: // Do NOT issue this request from the interrupt/completion context. ! 440: // ! 441: ! 442: PS2Request * request = _device->allocateRequest(); ! 443: UInt8 returnValue = (UInt8)(-1); ! 444: ! 445: // (get information command) ! 446: request->commands[0].command = kPS2C_WriteCommandPort; ! 447: request->commands[0].inOrOut = kCP_TransmitToMouse; ! 448: request->commands[1].command = kPS2C_WriteDataPort; ! 449: request->commands[1].inOrOut = kDP_GetId; ! 450: request->commands[2].command = kPS2C_ReadDataPortAndCompare; ! 451: request->commands[2].inOrOut = kSC_Acknowledge; ! 452: request->commands[3].command = kPS2C_ReadDataPort; ! 453: request->commands[3].inOrOut = 0; ! 454: request->commandsCount = 4; ! 455: _device->submitRequestAndBlock(request); ! 456: ! 457: if (request->commandsCount == 4) // success? ! 458: returnValue = request->commands[3].inOrOut; ! 459: ! 460: _device->freeRequest(request); ! 461: ! 462: return returnValue; ! 463: } ! 464: ! 465: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 466: ! 467: void ApplePS2Mouse::setCommandByte(UInt8 setBits, UInt8 clearBits) ! 468: { ! 469: // ! 470: // Sets the bits setBits and clears the bits clearBits "atomically" in the ! 471: // controller's Command Byte. Since the controller does not provide such ! 472: // a read-modify-write primitive, we resort to a test-and-set try loop. ! 473: // ! 474: // Do NOT issue this request from the interrupt/completion context. ! 475: // ! 476: ! 477: UInt8 commandByte; ! 478: UInt8 commandByteNew; ! 479: PS2Request * request = _device->allocateRequest(); ! 480: ! 481: do ! 482: { ! 483: // (read command byte) ! 484: request->commands[0].command = kPS2C_WriteCommandPort; ! 485: request->commands[0].inOrOut = kCP_GetCommandByte; ! 486: request->commands[1].command = kPS2C_ReadDataPort; ! 487: request->commands[1].inOrOut = 0; ! 488: request->commandsCount = 2; ! 489: _device->submitRequestAndBlock(request); ! 490: ! 491: // ! 492: // Modify the command byte as requested by caller. ! 493: // ! 494: ! 495: commandByte = request->commands[1].inOrOut; ! 496: commandByteNew = (commandByte | setBits) & (~clearBits); ! 497: ! 498: // ("test-and-set" command byte) ! 499: request->commands[0].command = kPS2C_WriteCommandPort; ! 500: request->commands[0].inOrOut = kCP_GetCommandByte; ! 501: request->commands[1].command = kPS2C_ReadDataPortAndCompare; ! 502: request->commands[1].inOrOut = commandByte; ! 503: request->commands[2].command = kPS2C_WriteCommandPort; ! 504: request->commands[2].inOrOut = kCP_SetCommandByte; ! 505: request->commands[3].command = kPS2C_WriteDataPort; ! 506: request->commands[3].inOrOut = commandByteNew; ! 507: request->commandsCount = 4; ! 508: _device->submitRequestAndBlock(request); ! 509: ! 510: // ! 511: // Repeat this loop if last command failed, that is, if the old command byte ! 512: // was modified since we first read it. ! 513: // ! 514: ! 515: } while (request->commandsCount != 4); ! 516: ! 517: _device->freeRequest(request); ! 518: } ! 519: ! 520: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! 521: ! 522: void ApplePS2Mouse::accelerationTable(IOHIAccelerationPoint ** table, ! 523: IOItemCount * numEntries) ! 524: { ! 525: static IOHIAccelerationPoint defaultTable[] = ! 526: { ! 527: { 0x0000000, 0x000000 }, ! 528: { 0x000713b, 0x006000 }, ! 529: { 0x0010000, 0x010000 }, ! 530: { 0x0044ec5, 0x108000 }, ! 531: { 0x00c0000, 0x5f0000 }, ! 532: { 0x016ec4f, 0x8b0000 }, ! 533: { 0x01d3b14, 0x948000 }, ! 534: { 0x0227627, 0x960000 }, ! 535: { 0x7ffffff, 0x960000 } ! 536: }; ! 537: ! 538: *table = defaultTable; ! 539: *numEntries = sizeof(defaultTable) / sizeof(defaultTable[0]); ! 540: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.