Annotation of XNU/iokit/Drivers/usb/drvAppleMouse/AppleMouse.cpp, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*
        !            23:  * Copyright (c) 1998 Apple Computer, Inc.  All rights reserved.
        !            24:  *
        !            25:  * HISTORY
        !            26:  *
        !            27:  */
        !            28: 
        !            29: 
        !            30: #include "AppleMouse.h"
        !            31: #include <IOKit/hidsystem/IOHIPointing.h>
        !            32: #include <IOKit/IOBufferMemoryDescriptor.h>
        !            33: #include <IOKit/usb/IOUSBInterface.h>
        !            34: #include <IOKit/usb/IOUSBPipe.h>
        !            35: #include <libkern/OSByteOrder.h>
        !            36: #include <IOKit/hidsystem/IOHIDShared.h>
        !            37: #include <IOKit/hidsystem/IOHIDDescriptorParser.h>
        !            38: 
        !            39: #define super IOHIPointing
        !            40: #define DEBUGGING_LEVEL 0
        !            41: 
        !            42: #define kMaxButtons    32      // Is this defined anywhere in the event headers?
        !            43: #define kMaxValues     32      // This should be plenty big to find the X, Y and wheel values - is there some absolute max?
        !            44: 
        !            45: OSDefineMetaClassAndStructors(AppleMouse, IOHIPointing)
        !            46: 
        !            47: bool AppleMouse::start(IOService * provider)
        !            48: {
        !            49:     IOReturn                   err = 0;
        !            50: 
        !            51:     if( !super::start(provider))
        !            52:         return (false);
        !            53: 
        !            54:     if( !provider->open(this))
        !            55:         return (false);
        !            56: 
        !            57:     // remember my device
        !            58:     _preparsedReportDescriptorData = NULL;
        !            59:     _buttonCollection = -1;
        !            60:     _xCollection = -1;
        !            61:     _yCollection = -1;
        !            62:     _tipPressureCollection = -1;
        !            63:     _digitizerButtonCollection = -1;
        !            64:     _scrollWheelCollection = -1;
        !            65:     _hasInRangeReport = false;
        !            66:     _tipPressureMin = 255;
        !            67:     _tipPressureMax = 255;
        !            68:     _numButtons = 1;
        !            69: 
        !            70:     _interface         = OSDynamicCast(IOUSBInterface, provider);
        !            71:     _deviceDescriptor  = _interface->deviceDescriptor();
        !            72:     
        !            73:     do {
        !            74:         IOUSBFindEndpointRequest request;
        !            75: 
        !            76:         IOLog("%s: USB Generic Mouse @ %d\n", getName(), _interface->address());
        !            77: 
        !            78:         request.type = kUSBInterrupt;
        !            79:         request.direction = kUSBIn;
        !            80:         _interruptPipe = _interface->findNextPipe(NULL, &request);
        !            81: 
        !            82:         if(!_interruptPipe)
        !            83:             return false;
        !            84: 
        !            85:         if (!parseHIDDescriptor()) {
        !            86:             break;
        !            87:         }
        !            88: 
        !            89:         _maxPacketSize = request.maxPacketSize;
        !            90:         _buffer = IOBufferMemoryDescriptor::withCapacity(8, kIODirectionIn);
        !            91: 
        !            92:         _completion.target = (void *)this;
        !            93:         _completion.action = (IOUSBCompletionAction) &AppleMouse::readHandler;
        !            94:         _completion.parameter = (void *)0;  // not used
        !            95: 
        !            96:         _buffer->setLength(_maxPacketSize);
        !            97: 
        !            98:         if ((err = _interruptPipe->read(_buffer, &_completion)))
        !            99:             break;
        !           100: 
        !           101: #if (DEBUGGING_LEVEL > 0)
        !           102:         printInterfaceDescriptor(_interface->descriptor);
        !           103: #endif
        !           104:         return(true);
        !           105: 
        !           106:     } while (false);
        !           107: 
        !           108:     IOLog("%s: aborting startup.  err = %d\n", getName(), err);
        !           109: 
        !           110:     provider->close(this);
        !           111:     stop(provider);
        !           112: 
        !           113:     return(false);
        !           114: }
        !           115: 
        !           116: bool AppleMouse::parseHIDDescriptor()
        !           117: {
        !           118:     bool                       success = true;
        !           119:     IOReturn                   err;
        !           120:     IOUSBDevRequest            devReq;
        !           121:     IOUSBHIDDescriptor         hidDescriptor;
        !           122:     UInt8 *                    reportDescriptor = NULL;
        !           123:     UInt16                     size = 0;
        !           124:     OSStatus                   result;
        !           125:     HIDButtonCaps              buttonCaps[kMaxButtons];
        !           126:     UInt32                     numButtonCaps = kMaxButtons;
        !           127:     HIDValueCaps               valueCaps[kMaxValues];
        !           128:     UInt32                     numValueCaps = kMaxValues;
        !           129: 
        !           130:     do {
        !           131:         devReq.rqDirection = kUSBIn;
        !           132:         devReq.rqType = kUSBStandard;
        !           133:         devReq.rqRecipient = kUSBInterface;
        !           134:         devReq.bRequest = kUSBRqGetDescriptor;
        !           135:         OSWriteLittleInt16(&devReq.wValue, 0, ((0x20 | kUSBHIDDesc) << 8));
        !           136:         OSWriteLittleInt16(&devReq.wIndex, 0, _interface->interfaceDescriptor()->interfaceNumber);
        !           137:         OSWriteLittleInt16(&devReq.wLength, 0, sizeof(IOUSBHIDDescriptor));
        !           138:         devReq.pData = &hidDescriptor;
        !           139: 
        !           140:         err = _interface->deviceRequest(&devReq);
        !           141:         if (err) {
        !           142:             IOLog ("%s: error getting HID Descriptor.  err=0x%x\n", getName(), err);
        !           143:             success = false;
        !           144:             break;
        !           145:         }
        !           146: 
        !           147:         size = (hidDescriptor.hidDescriptorLengthHi * 256) + hidDescriptor.hidDescriptorLengthLo;
        !           148:         reportDescriptor = (UInt8 *)IOMalloc(size);
        !           149: 
        !           150:         OSWriteLittleInt16(&devReq.wValue, 0, ((0x20 | kUSBReportDesc) << 8));
        !           151:         OSWriteLittleInt16(&devReq.wLength, 0, size);
        !           152:         devReq.pData = reportDescriptor;
        !           153: 
        !           154:         err = _interface->deviceRequest(&devReq);
        !           155:         if (err) {
        !           156:             IOLog ("%s: error getting HID report descriptor.  err=0x%x\n", getName(), err);
        !           157:             success = false;
        !           158:             break;
        !           159:         }
        !           160:     
        !           161:         result = HIDOpenReportDescriptor (reportDescriptor, size, &_preparsedReportDescriptorData, 0);
        !           162:         if (result != noErr) {
        !           163:             IOLog ("%s: error parsing HID report descriptor.  err=0x%lx\n", getName(), result);
        !           164:             success = false;
        !           165:             break;
        !           166:         }
        !           167: 
        !           168:         result = HIDGetSpecificButtonCaps(kHIDInputReport,
        !           169:                                           kHIDPage_Button,
        !           170:                                           0,
        !           171:                                           0,
        !           172:                                           buttonCaps,
        !           173:                                           &numButtonCaps,
        !           174:                                           _preparsedReportDescriptorData);
        !           175:         if ((result == noErr) && (numButtonCaps > 0)) {
        !           176:             _buttonCollection = buttonCaps[0].collection;      // Do we actually need to look at and store all of the button page collections?
        !           177:             if (buttonCaps[0].isRange) {
        !           178:                 _numButtons = buttonCaps[0].u.range.usageMax - buttonCaps[0].u.range.usageMin + 1;
        !           179:             }
        !           180:             
        !           181:         }
        !           182: 
        !           183:         numButtonCaps = kMaxButtons;
        !           184:         result = HIDGetSpecificButtonCaps(kHIDInputReport,
        !           185:                                           kHIDPage_Digitizer,
        !           186:                                           0,
        !           187:                                           0,
        !           188:                                           buttonCaps,
        !           189:                                           &numButtonCaps,
        !           190:                                           _preparsedReportDescriptorData);
        !           191:         if ((result == noErr) && (numButtonCaps > 0)) {
        !           192:             _digitizerButtonCollection = buttonCaps[0].collection;
        !           193:         }
        !           194: 
        !           195:         numButtonCaps = kMaxButtons;
        !           196:         result = HIDGetSpecificButtonCaps(kHIDInputReport,
        !           197:                                           kHIDPage_Digitizer,
        !           198:                                           0,
        !           199:                                           kHIDUsage_Dig_InRange,
        !           200:                                           buttonCaps,
        !           201:                                           &numButtonCaps,
        !           202:                                           _preparsedReportDescriptorData);
        !           203:         if (result == noErr) {
        !           204:             _hasInRangeReport = true;
        !           205:         }
        !           206: 
        !           207:         result = HIDGetSpecificValueCaps(kHIDInputReport,
        !           208:                                          kHIDPage_GenericDesktop,
        !           209:                                          0,
        !           210:                                          kHIDUsage_GD_X,
        !           211:                                          valueCaps,
        !           212:                                          &numValueCaps,
        !           213:                                          _preparsedReportDescriptorData);
        !           214:         if ((result == noErr) && (numValueCaps > 0)) {
        !           215:             _xCollection = valueCaps[0].collection;
        !           216:             _absoluteCoordinates = valueCaps[0].isAbsolute;
        !           217:             _bounds.minx = valueCaps[0].logicalMin;
        !           218:             _bounds.maxx = valueCaps[0].logicalMax;
        !           219:         } else {
        !           220:             IOLog ("%s: error getting X axis information from HID report descriptor.  err=0x%lx\n", getName(), result);
        !           221:             success = false;
        !           222:             break;
        !           223:         }
        !           224: 
        !           225:         numValueCaps = kMaxValues;
        !           226:         result = HIDGetSpecificValueCaps(kHIDInputReport,
        !           227:                                          kHIDPage_GenericDesktop,
        !           228:                                          0,
        !           229:                                          kHIDUsage_GD_Y,
        !           230:                                          valueCaps,
        !           231:                                          &numValueCaps,
        !           232:                                          _preparsedReportDescriptorData);
        !           233:         if ((result == noErr) && (numValueCaps > 0)) {
        !           234:             _yCollection = valueCaps[0].collection;
        !           235:             _bounds.miny = valueCaps[0].logicalMin;
        !           236:             _bounds.maxy = valueCaps[0].logicalMax;
        !           237:         } else {
        !           238:             IOLog ("%s: error getting Y axis information from HID report descriptor.  err=0x%lx\n", getName(), result);
        !           239:             success = false;
        !           240:             break;
        !           241:         }
        !           242: 
        !           243:         numValueCaps = kMaxValues;
        !           244:         result = HIDGetSpecificValueCaps(kHIDInputReport,
        !           245:                                          kHIDPage_Digitizer,
        !           246:                                          0,
        !           247:                                          kHIDUsage_Dig_TipPressure,
        !           248:                                          valueCaps,
        !           249:                                          &numValueCaps,
        !           250:                                          _preparsedReportDescriptorData);
        !           251:         if ((result == noErr) && (numValueCaps > 0)) {
        !           252:             _tipPressureCollection = valueCaps[0].collection;
        !           253:             _tipPressureMin = valueCaps[0].logicalMin;
        !           254:             _tipPressureMax = valueCaps[0].logicalMax;
        !           255:         }
        !           256: 
        !           257:         numValueCaps = kMaxValues;
        !           258:         result = HIDGetSpecificValueCaps(kHIDInputReport,
        !           259:                                          kHIDPage_GenericDesktop,
        !           260:                                          0,
        !           261:                                          kHIDUsage_GD_Wheel,
        !           262:                                          valueCaps,
        !           263:                                          &numValueCaps,
        !           264:                                          _preparsedReportDescriptorData);
        !           265:         if ((result == noErr) && (numValueCaps > 0)) {
        !           266:             _scrollWheelCollection = valueCaps[0].collection;
        !           267:         }
        !           268:     } while (false);
        !           269: 
        !           270:     if (reportDescriptor) {
        !           271:         IOFree(reportDescriptor, size);
        !           272:     }
        !           273:     
        !           274:     return success;
        !           275: }
        !           276: 
        !           277: void AppleMouse::stop(IOService * provider)
        !           278: {
        !           279:     if (_buffer) {
        !           280:        _buffer->release();
        !           281:         _buffer = 0;
        !           282:     }
        !           283:     if (_preparsedReportDescriptorData) {
        !           284:         HIDCloseReportDescriptor(_preparsedReportDescriptorData);
        !           285:     }
        !           286:     super::stop(provider);
        !           287: }
        !           288: 
        !           289: void AppleMouse::readHandler(void *    parameter,
        !           290:                              IOReturn  status,
        !           291:                              UInt32    bufferSizeRemaining)
        !           292: {
        !           293:     switch (status)
        !           294:     {
        !           295:         case kIOReturnSuccess:
        !           296:             break;
        !           297: 
        !           298:         case kIOReturnOverrun:
        !           299:             // Not sure what to do with this error.  It means more data
        !           300:             // came back than the size of a descriptor.  Hmmm.  For now
        !           301:             // just ignore it and assume the data that did come back is
        !           302:             // useful.
        !           303:             IOLog("%s: overrun error.  ignoring.\n", getName());
        !           304:             break;
        !           305: 
        !           306:         case kIOReturnNotResponding:
        !           307:             // This probably means the device was unplugged.  Now
        !           308:             // we need to close the driver.
        !           309:             IOLog("%s: Device unplugged.  Goodbye\n", getName());
        !           310:             goto close;
        !           311: 
        !           312:         default:
        !           313:             // We should handle other errors more intelligently, but
        !           314:             // for now just return and assume the error is recoverable.
        !           315:             IOLog("%s: error reading interrupt pipe\n", getName());
        !           316:             goto queueAnother;
        !           317:     }
        !           318: 
        !           319:     // Handle the data
        !           320:     MoveMouse((UInt8 *) _buffer->getBytesNoCopy(),
        !           321:               (UInt32)  _maxPacketSize - bufferSizeRemaining);
        !           322: 
        !           323: queueAnother:
        !           324:     // Reset the buffer
        !           325:     _buffer->setLength(_maxPacketSize);
        !           326: 
        !           327:     // Queue up another one before we leave.
        !           328:     if ((status = _interruptPipe->read(_buffer, &_completion)))
        !           329:     {
        !           330:         // This is bad.  We probably shouldn't continue on from here.
        !           331:         IOLog("%s: immediate error %d queueing read\n", getName(), status);
        !           332:         goto close;
        !           333:     }
        !           334: 
        !           335:     return;
        !           336: 
        !           337: close:
        !           338:     _interface->close(this);
        !           339:     return;
        !           340: }
        !           341: 
        !           342: void AppleMouse::MoveMouse(UInt8 *     mouseData,
        !           343:                            UInt32      ret_bufsize)
        !           344: {
        !           345:     OSStatus   status;
        !           346:     HIDUsage   usageList[kMaxButtons];
        !           347:     UInt32     usageListSize = kMaxButtons;
        !           348:     UInt32     buttonState = 0;
        !           349:     SInt32     usageValue;
        !           350:     SInt32     pressure = MAXPRESSURE;
        !           351:     int                dx = 0, dy = 0, scrollWheelDelta = 0;
        !           352:     AbsoluteTime now;
        !           353:     bool       inRange = !_hasInRangeReport;
        !           354: 
        !           355:     if (_buttonCollection != -1) {
        !           356:         status = HIDGetButtonsOnPage (kHIDInputReport,
        !           357:                                       kHIDPage_Button,
        !           358:                                       _buttonCollection,
        !           359:                                       usageList,
        !           360:                                       &usageListSize,
        !           361:                                       _preparsedReportDescriptorData,
        !           362:                                       mouseData,
        !           363:                                       ret_bufsize);
        !           364:         if (status == noErr) {
        !           365:             UInt32 usageNum;
        !           366:             for (usageNum = 0; usageNum < usageListSize; usageNum++) {
        !           367:                 if (usageList[usageNum] <= kMaxButtons) {
        !           368:                     buttonState |= (1 << (usageList[usageNum] - 1));
        !           369:                 }
        !           370:             }
        !           371:         }
        !           372: 
        !           373:     }
        !           374: 
        !           375:     if (_tipPressureCollection != -1) {
        !           376:         status = HIDGetUsageValue (kHIDInputReport,
        !           377:                                    kHIDPage_Digitizer,
        !           378:                                    _tipPressureCollection,
        !           379:                                    kHIDUsage_Dig_TipPressure,
        !           380:                                    &usageValue,
        !           381:                                    _preparsedReportDescriptorData,
        !           382:                                    mouseData,
        !           383:                                    ret_bufsize);
        !           384:         if (status == noErr) {
        !           385:             pressure = usageValue;
        !           386:         }
        !           387:     }
        !           388: 
        !           389:     if (_digitizerButtonCollection != -1) {
        !           390:         usageListSize = kMaxButtons;
        !           391:         status = HIDGetButtonsOnPage (kHIDInputReport,
        !           392:                                       kHIDPage_Digitizer,
        !           393:                                       _digitizerButtonCollection,
        !           394:                                       usageList,
        !           395:                                       &usageListSize,
        !           396:                                       _preparsedReportDescriptorData,
        !           397:                                       mouseData,
        !           398:                                       ret_bufsize);
        !           399:         if (status == noErr) {
        !           400:             UInt32 usageNum;
        !           401:             for (usageNum = 0; usageNum < usageListSize; usageNum++) {
        !           402:                 switch (usageList[usageNum]) {
        !           403:                     case kHIDUsage_Dig_BarrelSwitch:
        !           404:                         buttonState |= 2;      // Set the right (secondary) button for the barrel switch
        !           405:                         break;
        !           406:                     case kHIDUsage_Dig_TipSwitch:
        !           407:                         buttonState |= 1;      // Set the left (primary) button for the tip switch
        !           408:                         break;
        !           409:                     case kHIDUsage_Dig_InRange:
        !           410:                         inRange = 1;
        !           411:                         break;
        !           412:                     default:
        !           413:                         break;
        !           414:                 }
        !           415:             }
        !           416:         }
        !           417:     }
        !           418: 
        !           419:     if (_scrollWheelCollection != -1) {
        !           420:         status = HIDGetUsageValue (kHIDInputReport,
        !           421:                                    kHIDPage_GenericDesktop,
        !           422:                                    _scrollWheelCollection,
        !           423:                                    kHIDUsage_GD_Wheel,
        !           424:                                    &usageValue,
        !           425:                                    _preparsedReportDescriptorData,
        !           426:                                    mouseData,
        !           427:                                    ret_bufsize);
        !           428:         if (status == noErr) {
        !           429:             scrollWheelDelta = usageValue;
        !           430:         }
        !           431:     }
        !           432: 
        !           433:     status = HIDGetUsageValue (kHIDInputReport,
        !           434:                                kHIDPage_GenericDesktop,
        !           435:                                _xCollection,
        !           436:                                kHIDUsage_GD_X,
        !           437:                                &usageValue,
        !           438:                                _preparsedReportDescriptorData,
        !           439:                                mouseData,
        !           440:                                ret_bufsize);
        !           441:     if (status == noErr) {
        !           442:         dx = usageValue;
        !           443:     }
        !           444: 
        !           445:     status = HIDGetUsageValue (kHIDInputReport,
        !           446:                                kHIDPage_GenericDesktop,
        !           447:                                _yCollection,
        !           448:                                kHIDUsage_GD_Y,
        !           449:                                &usageValue,
        !           450:                                _preparsedReportDescriptorData,
        !           451:                                mouseData,
        !           452:                                ret_bufsize);
        !           453:     if (status == noErr) {
        !           454:         dy = usageValue;
        !           455:     }
        !           456: 
        !           457:     clock_get_uptime(&now);
        !           458: 
        !           459:     if (_absoluteCoordinates) {
        !           460:         Point newLoc;
        !           461: 
        !           462:         newLoc.x = dx;
        !           463:         newLoc.y = dy;
        !           464: 
        !           465:         dispatchAbsolutePointerEvent(&newLoc, &_bounds, buttonState, inRange, pressure, _tipPressureMin, _tipPressureMax, 90, now);
        !           466:     } else {
        !           467:         dispatchRelativePointerEvent(dx, dy, buttonState, now);
        !           468:     }
        !           469: 
        !           470:     if (scrollWheelDelta != 0) {
        !           471:         dispatchScrollWheelEvent(scrollWheelDelta, 0, 0, now);
        !           472:     }
        !           473: }
        !           474: 
        !           475: UInt32 AppleMouse::interfaceID( void )
        !           476: {
        !           477:     return( NX_EVS_DEVICE_INTERFACE_OTHER );
        !           478: }
        !           479: 
        !           480: UInt32 AppleMouse::deviceType( void )
        !           481: {
        !           482:     return( 0 );
        !           483: }
        !           484: 
        !           485: /*
        !           486:  * This was taken directly from the AppleADBMouse driver.
        !           487:  * We need to determine the best generic acceleration curve for USB devices.
        !           488:  */
        !           489: 
        !           490: void AppleMouse::accelerationTable ( IOHIAccelerationPoint ** table, IOItemCount * numEntries )
        !           491: {
        !           492: static IOHIAccelerationPoint defaultTable[] = {
        !           493:         { 0x0000000, 0x000000 },
        !           494:         { 0x000713b, 0x006000 },
        !           495:         { 0x0010000, 0x010000 },
        !           496:         { 0x0044ec5, 0x108000 },
        !           497:         { 0x00c0000, 0x5f0000 },
        !           498:         { 0x016ec4f, 0x8b0000 },
        !           499:         { 0x01d3b14, 0x948000 },
        !           500:         { 0x0227627, 0x960000 },
        !           501:         { 0x7ffffff, 0x960000 }
        !           502:     };
        !           503: 
        !           504: *table = defaultTable;
        !           505: *numEntries = sizeof(defaultTable) / sizeof(defaultTable[0]);
        !           506: }
        !           507: 
        !           508: IOFixed AppleMouse::resolution()
        !           509: {
        !           510:     return (400 << 16);
        !           511: }
        !           512: 
        !           513: IOItemCount AppleMouse::buttonCount()
        !           514: {
        !           515:     return _numButtons;
        !           516: }
        !           517: 

unix.superglobalmegacorp.com

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