|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.