Annotation of XNU/iokit/Drivers/hidsystem/drvApplePS2Mouse/ApplePS2Mouse.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/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: }

unix.superglobalmegacorp.com

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