|
|
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: * 08 Dec 98 ehewitt created. ! 27: * ! 28: */ ! 29: ! 30: #include <libkern/OSByteOrder.h> ! 31: ! 32: #include <libkern/c++/OSDictionary.h> ! 33: #include <IOKit/IOMemoryDescriptor.h> ! 34: #include <libkern/c++/OSData.h> ! 35: ! 36: #include <IOKit/usb/USB.h> ! 37: #include <IOKit/usb/IOUSBController.h> ! 38: #include <IOKit/usb/IOUSBDevice.h> ! 39: #include <IOKit/usb/IOUSBInterface.h> ! 40: #include <IOKit/usb/IOUSBPipe.h> ! 41: ! 42: #include "IOUSBUserClient.h" ! 43: #include "IOUSBHub.h" ! 44: ! 45: #define super IOUSBNub ! 46: ! 47: static int devdebug = 0; ! 48: #define DEBUGLOG if (devdebug) kprintf ! 49: ! 50: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ! 51: ! 52: OSDefineMetaClassAndStructors(IOUSBDevice, IOUSBNub) ! 53: ! 54: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ! 55: ! 56: void IOUSBDevice::setPort(IOUSBHubPort *port) ! 57: { ! 58: _port = port; ! 59: } ! 60: ! 61: bool IOUSBDevice::init(OSDictionary * propTable) ! 62: { ! 63: if(!IOUSBNub::init(propTable)) ! 64: return false; ! 65: if(_descriptor.numConf) { ! 66: _configList = (UInt8 **)IOMalloc(sizeof(UInt8 *) * _descriptor.numConf); ! 67: if(!_configList) ! 68: return false; ! 69: bzero(_configList, sizeof(UInt8 *) * _descriptor.numConf); ! 70: } ! 71: return true; ! 72: } ! 73: ! 74: void IOUSBDevice::free() ! 75: { ! 76: if(_configList) { ! 77: int i; ! 78: for(i=0; i<_descriptor.numConf; i++) { ! 79: if(_configList[i]) { ! 80: int len = OSReadLittleInt16(&((IOUSBConfigurationDescriptor *)_configList[i])->totalLength, 0); ! 81: IOFree(_configList[i], len+2); ! 82: _configList[i] = NULL; ! 83: } ! 84: } ! 85: IOFree(_configList, sizeof(UInt8 *) * _descriptor.numConf); ! 86: } ! 87: IOUSBNub::free(); ! 88: } ! 89: ! 90: bool IOUSBDevice::attach(IOService *provider) ! 91: { ! 92: IOReturn err; ! 93: char name[128]; ! 94: ! 95: if( !IOUSBNub::attach(provider)) ! 96: return (false); ! 97: // Set controller if we weren't given one earlier. ! 98: if(_controller == NULL) ! 99: _controller = OSDynamicCast(IOUSBController, provider); ! 100: if(_controller == NULL) ! 101: return false; ! 102: ! 103: // Don't do this until we have a controller ! 104: _endpointZero.length = sizeof(_endpointZero); ! 105: _endpointZero.descriptorType = kUSBEndpointDesc; ! 106: _endpointZero.endpointAddress = 0; ! 107: _endpointZero.attributes = kUSBControl; ! 108: OSWriteLittleInt16(&_endpointZero.maxPacketSizeLo, 0, _descriptor.maxPacketSize); ! 109: _endpointZero.interval = 0; ! 110: ! 111: _pipeZero = IOUSBPipe::toEndpoint(&_endpointZero, _speed, _address, _controller); ! 112: ! 113: if(_descriptor.prodIdx) { ! 114: err = GetStringDescriptor(_descriptor.prodIdx, name, sizeof(name)); ! 115: if(err == kIOReturnSuccess) { ! 116: setName(name); ! 117: setProperty("USB Product Name", name); ! 118: } ! 119: } ! 120: if(_descriptor.manuIdx) { ! 121: err = GetStringDescriptor(_descriptor.manuIdx, name, sizeof(name)); ! 122: if(err == kIOReturnSuccess) { ! 123: setProperty("USB Vendor Name", name); ! 124: } ! 125: } ! 126: if(_descriptor.serialIdx) { ! 127: err = GetStringDescriptor(_descriptor.serialIdx, name, sizeof(name)); ! 128: if(err == kIOReturnSuccess) { ! 129: setProperty("USB Serial Number", name); ! 130: } ! 131: } ! 132: return true; ! 133: } ! 134: ! 135: // Stop all activity, reset device, restart. ! 136: IOReturn IOUSBDevice::resetDevice() ! 137: { ! 138: IOReturn err; ! 139: ! 140: if(_pipeZero) { ! 141: _pipeZero->release(); ! 142: _pipeZero = NULL; ! 143: } ! 144: err = _port->resetDevice(); ! 145: ! 146: // Recreate pipe 0 object ! 147: if(err == kIOReturnSuccess) { ! 148: _pipeZero = IOUSBPipe::toEndpoint(&_endpointZero, _speed, _address, _controller); ! 149: if(!_pipeZero) ! 150: err = kIOReturnNoMemory; ! 151: } ! 152: ! 153: return err; ! 154: } ! 155: ! 156: /****************************************************** ! 157: * Helper Methods ! 158: ******************************************************/ ! 159: ! 160: const IOUSBConfigurationDescriptor * ! 161: IOUSBDevice::findConfig(UInt8 configValue, int *configIndex) ! 162: { ! 163: int i; ! 164: const IOUSBConfigurationDescriptor *cd = NULL; ! 165: ! 166: for(i = 0; i < _descriptor.numConf; i++) { ! 167: cd = getFullConfigurationDescriptor(i); ! 168: if(!cd) ! 169: continue; ! 170: if(cd->configValue == configValue) ! 171: break; ! 172: } ! 173: if(cd && configIndex) ! 174: *configIndex = i; ! 175: ! 176: return cd; ! 177: } ! 178: ! 179: // Finding the correct interface ! 180: /* ! 181: * findNextInterface ! 182: * This method should really be rewritten to use iterators or ! 183: * be broken out into more functions without a request structure. ! 184: * Or even better, make the interfaces and endpoint objects that ! 185: * have their own methods for this stuff. ! 186: * ! 187: * returns: ! 188: * next interface matching criteria. 0 if no matches ! 189: */ ! 190: IOUSBInterface * ! 191: IOUSBDevice::findNextInterface(IOUSBInterface *current, ! 192: FindInterfaceRequest *request) ! 193: { ! 194: const IOUSBConfigurationDescriptor *cd; ! 195: const IOUSBInterfaceDescriptor * id; ! 196: const IOUSBDescriptorHeader * pos = NULL; ! 197: bool found; ! 198: int configIndex; ! 199: if(current == NULL) { ! 200: configIndex = 0; ! 201: cd = getFullConfigurationDescriptor(configIndex); ! 202: if(!cd) ! 203: return NULL; ! 204: pos = (IOUSBDescriptorHeader *)cd; ! 205: } ! 206: else { ! 207: cd = findConfig(current->getConfigValue(), &configIndex); ! 208: if(!cd) ! 209: return NULL; ! 210: pos = (IOUSBDescriptorHeader *)cd; ! 211: while((pos = findNextDescriptor(pos, kUSBInterfaceDesc))) { ! 212: if(bcmp(pos, current->interfaceDescriptor(), ! 213: sizeof(IOUSBInterfaceDescriptor)) == 0) { ! 214: break; ! 215: } ! 216: } ! 217: } ! 218: while (configIndex < _descriptor.numConf) ! 219: { ! 220: pos = findNextDescriptor(pos, kUSBInterfaceDesc); ! 221: if(pos == NULL) { ! 222: // End of that configuration ! 223: configIndex++; ! 224: if(configIndex >= _descriptor.numConf) ! 225: break; ! 226: ! 227: cd = getFullConfigurationDescriptor(configIndex); ! 228: continue; ! 229: } ! 230: id = (const IOUSBInterfaceDescriptor *)pos; ! 231: ! 232: // check the request parameters ! 233: found = true; ! 234: if (request->theClass != 0 && request->theClass != id->interfaceClass) ! 235: found = false; // this is not it ! 236: if (request->subClass != 0 && request->subClass != id->interfaceSubClass) ! 237: found = false; // this is not it ! 238: if (request->protocol != 0 && request->protocol != id->interfaceProtocol) ! 239: found = false; // this is not it ! 240: if (request->maxPower != 0 && request->maxPower < cd->maxPower) ! 241: found = false; // draws too much power ! 242: if (id->alternateSetting != 0) ! 243: found = false; // Only want main setting ! 244: ! 245: if (found) ! 246: { ! 247: request->theClass = id->interfaceClass; ! 248: request->subClass = id->interfaceSubClass; ! 249: request->protocol = id->interfaceProtocol; ! 250: request->maxPower = cd->maxPower; ! 251: request->busPowered = cd->attributes & kUSBAtrBusPowered ? 2 : 1; ! 252: request->selfPowered = cd->attributes & kUSBAtrSelfPowered ? 2 : 1; ! 253: request->remoteWakeup = cd->attributes & kUSBAtrRemoteWakeup ? 2 : 1; ! 254: return(GetInterface(id, cd)); ! 255: } ! 256: } ! 257: return(0); ! 258: } ! 259: ! 260: const IOUSBConfigurationDescriptor *IOUSBDevice::getFullConfigurationDescriptor(UInt8 index) ! 261: { ! 262: IOReturn err; ! 263: ! 264: if(_configList[index] == NULL) { ! 265: int len; ! 266: IOUSBConfigurationDescriptor temp; ! 267: err = GetConfigDescriptor(index, &temp, sizeof(temp)); ! 268: if (err) { ! 269: DEBUGLOG("getFullConfigurationDescriptor: Error 0x%x getting configuration descriptor\n", err); ! 270: return(0); ! 271: } ! 272: len = OSReadLittleInt16(&temp.totalLength, 0); ! 273: _configList[index] = (UInt8 *)IOMalloc(len + 2); ! 274: if(_configList[index] == NULL) ! 275: return 0; ! 276: err = GetConfigDescriptor(index, _configList[index], len); ! 277: if (err) { ! 278: DEBUGLOG("getFullConfigurationDescriptor: Error %d getting full configuration\n", err); ! 279: return(0); ! 280: } ! 281: *(_configList[index]+len) = 0; // A Known ~Elephant. ! 282: *(_configList[index]+len+1) = 0;// A Known ~Elephant. ! 283: } ! 284: return (IOUSBConfigurationDescriptor *)_configList[index]; ! 285: } ! 286: ! 287: /* ! 288: * GetConfigDescriptor: ! 289: * In: pointer to buffer for config descriptor, length to get ! 290: * Assumes: desc is has enough space to put it all ! 291: */ ! 292: IOReturn IOUSBDevice::GetConfigDescriptor(UInt8 configIndex, ! 293: void *desc, int len) ! 294: { ! 295: IOReturn err = kIOReturnSuccess; ! 296: IOUSBDevRequest request; ! 297: ! 298: DEBUGLOG("********** GET CONFIG DESCRIPTOR (%d)**********\n", len); ! 299: ! 300: /* ! 301: * with config descriptors, the device will send back all descriptors, ! 302: * if the request is big enough. ! 303: */ ! 304: ! 305: request.rqDirection = kUSBIn; ! 306: request.rqType = kUSBStandard; ! 307: request.rqRecipient = kUSBDevice; ! 308: request.bRequest = kUSBRqGetDescriptor; ! 309: OSWriteLittleInt16(&request.wValue, 0, (kUSBConfDesc << 8) + configIndex); ! 310: OSWriteLittleInt16(&request.wIndex, 0, 0); ! 311: OSWriteLittleInt16(&request.wLength, 0, len); ! 312: request.pData = desc; ! 313: ! 314: err = deviceRequest(&request); ! 315: ! 316: if (err) ! 317: { ! 318: DEBUGLOG("%s: error getting device config descriptor. err=0x%x\n", getName(), err); ! 319: } ! 320: ! 321: return(err); ! 322: } ! 323: ! 324: IOReturn IOUSBDevice::SetConfiguration(UInt8 configNumber) ! 325: { ! 326: IOReturn err = kIOReturnSuccess; ! 327: IOUSBDevRequest request; ! 328: ! 329: DEBUGLOG("********** SET CONFIGURATION TO %d **********\n", configNumber); ! 330: ! 331: request.rqDirection = kUSBOut; ! 332: request.rqType = kUSBStandard; ! 333: request.rqRecipient = kUSBDevice; ! 334: request.bRequest = kUSBRqSetConfig; ! 335: OSWriteLittleInt16(&request.wValue, 0, configNumber); ! 336: OSWriteLittleInt16(&request.wIndex, 0, 0); ! 337: OSWriteLittleInt16(&request.wLength, 0, 0); ! 338: request.pData = 0; ! 339: ! 340: err = deviceRequest(&request); ! 341: ! 342: if (err) ! 343: { ! 344: DEBUGLOG("%s: error setting config. err=%d\n", getName(), err); ! 345: } ! 346: ! 347: return(err); ! 348: } ! 349: ! 350: IOUSBInterface * IOUSBDevice::GetInterface(const IOUSBInterfaceDescriptor *interface, ! 351: const IOUSBConfigurationDescriptor *config) ! 352: { ! 353: OSDictionary * propTable = 0; ! 354: OSArray * epArray = 0; ! 355: IOUSBInterface * newDevice = 0; ! 356: OSData * data; ! 357: OSNumber * offset; ! 358: int i; ! 359: char location[8]; ! 360: OSIterator * clients; ! 361: /* ! 362: * First see if the interface has already been created, ! 363: * ie. there's already one with the given interface descriptor and config descriptor ! 364: */ ! 365: clients = getClientIterator(); ! 366: if(clients) { ! 367: OSObject *next; ! 368: while((next = clients->getNextObject())) { ! 369: IOUSBInterface *testIt = OSDynamicCast(IOUSBInterface, next); ! 370: if(testIt) { ! 371: if(config->configValue == testIt->getConfigValue() && ! 372: bcmp(interface, testIt->interfaceDescriptor(), sizeof(IOUSBInterfaceDescriptor)) == 0) { ! 373: newDevice = testIt; ! 374: break; ! 375: } ! 376: } ! 377: } ! 378: clients->release(); ! 379: } ! 380: if(newDevice) { ! 381: newDevice->retain(); ! 382: return newDevice; ! 383: } ! 384: do { ! 385: propTable = OSDictionary::withCapacity(13); ! 386: if (!propTable) ! 387: continue; ! 388: ! 389: data = OSData::withBytes( &_descriptor, sizeof( _descriptor )); ! 390: if (data) { ! 391: propTable->setObject("device descriptor", data); ! 392: data->release(); ! 393: } ! 394: offset = OSNumber::withNumber(interface->interfaceClass, 8); ! 395: if(offset) { ! 396: propTable->setObject("class", offset); ! 397: offset->release(); ! 398: } ! 399: offset = OSNumber::withNumber(interface->interfaceSubClass, 8); ! 400: if(offset) { ! 401: propTable->setObject("subClass", offset); ! 402: offset->release(); ! 403: } ! 404: offset = OSNumber::withNumber(interface->interfaceProtocol, 8); ! 405: if(offset) { ! 406: propTable->setObject("protocol", offset); ! 407: offset->release(); ! 408: } ! 409: offset = OSNumber::withNumber(OSReadLittleInt16(&_descriptor.vendor, 0), 16); ! 410: if(offset) { ! 411: propTable->setObject("vendor", offset); ! 412: offset->release(); ! 413: } ! 414: offset = OSNumber::withNumber(OSReadLittleInt16(&_descriptor.product, 0), 16); ! 415: if(offset) { ! 416: propTable->setObject("product", offset); ! 417: offset->release(); ! 418: } ! 419: offset = OSNumber::withNumber(OSReadLittleInt16(&_descriptor.devRel, 0), 16); ! 420: if(offset) { ! 421: propTable->setObject("version", offset); ! 422: offset->release(); ! 423: } ! 424: data = OSData::withBytes(&_address, sizeof( _address )); ! 425: if (data) { ! 426: propTable->setObject("device address", data); ! 427: data->release(); ! 428: } ! 429: data = OSData::withBytes( config, ! 430: sizeof( *config )); ! 431: if (data) { ! 432: propTable->setObject("configuration descriptor", data); ! 433: data->release(); ! 434: } ! 435: data = OSData::withBytes( interface, ! 436: sizeof(*interface)); ! 437: if (data) { ! 438: propTable->setObject("interface descriptor", data); ! 439: data->release(); ! 440: } ! 441: data = OSData::withBytes(&_busPowerAvailable, sizeof(_busPowerAvailable)); ! 442: if (data) { ! 443: propTable->setObject("bus power available", data); ! 444: data->release(); ! 445: } ! 446: data = OSData::withBytes(&_speed, sizeof(_speed)); ! 447: if (data) { ! 448: propTable->setObject("low speed device", data); ! 449: data->release(); ! 450: } ! 451: ! 452: epArray = OSArray::withCapacity(interface->numEndpoints); ! 453: if (!epArray) ! 454: continue; ! 455: IOUSBEndpointDescriptor *ep = (IOUSBEndpointDescriptor *)interface; ! 456: for(i=0; i<interface->numEndpoints; i++) { ! 457: ep = (IOUSBEndpointDescriptor *)findNextDescriptor(ep, kUSBEndpointDesc); ! 458: if(!ep) ! 459: break; ! 460: data = OSData::withBytes(ep, sizeof(IOUSBEndpointDescriptor)); ! 461: if (data) { ! 462: epArray->setObject(i, data); ! 463: data->release(); ! 464: } ! 465: } ! 466: propTable->setObject("Endpoints", epArray); ! 467: epArray->release(); ! 468: ! 469: newDevice = createInterface(propTable, config, interface); ! 470: ! 471: if (!newDevice ) ! 472: continue; ! 473: ! 474: propTable->release(); // done with it after init ! 475: propTable = 0; ! 476: ! 477: sprintf( location, "%x", _address ); ! 478: newDevice->setLocation(location); ! 479: if (!newDevice->attach(this)) ! 480: break; ! 481: ! 482: return(newDevice); ! 483: ! 484: } while (false); ! 485: ! 486: if (propTable) ! 487: propTable->release(); ! 488: if (epArray) ! 489: epArray->release(); ! 490: if (newDevice) ! 491: newDevice->release(); ! 492: ! 493: return(NULL); ! 494: } ! 495: ! 496: IOUSBInterface * ! 497: IOUSBDevice::createInterface(OSDictionary *table, ! 498: const IOUSBConfigurationDescriptor *config, ! 499: const IOUSBInterfaceDescriptor *interface) ! 500: { ! 501: IOUSBInterface *newIface; ! 502: ! 503: newIface = new IOUSBInterface; ! 504: if(!newIface) ! 505: return NULL; ! 506: if(!newIface->init(table, config, interface)) { ! 507: newIface->release(); ! 508: newIface = NULL; ! 509: } ! 510: return newIface; ! 511: } ! 512: ! 513: // Copy data into supplied buffer, up to 'len' bytes. ! 514: IOReturn IOUSBDevice::getConfigurationDescriptor(UInt8 configValue, void *data, UInt32 len) ! 515: { ! 516: unsigned int toCopy; ! 517: const IOUSBConfigurationDescriptor *cd; ! 518: cd = findConfig(configValue); ! 519: if(!cd) ! 520: return kIOUSBConfigNotFound; ! 521: ! 522: toCopy = OSReadLittleInt16(&cd->totalLength, 0); ! 523: if(len < toCopy) ! 524: toCopy = len; ! 525: bcopy(cd, data, toCopy); ! 526: return kIOReturnSuccess; ! 527: } ! 528: ! 529: ! 530: /** ! 531: ** IOUserClient methods ! 532: **/ ! 533: ! 534: IOReturn IOUSBDevice::newUserClient( task_t owningTask, ! 535: void * /* security_id */, ! 536: UInt32 type, ! 537: IOUserClient ** handler ) ! 538: ! 539: { ! 540: IOReturn err = kIOReturnSuccess; ! 541: IOUSBDeviceUserClient * client; ! 542: ! 543: if( type != kIOUSBDeviceConnectType) ! 544: return( kIOReturnBadArgument); ! 545: ! 546: client = IOUSBDeviceUserClient::withTask(owningTask); ! 547: ! 548: if( !client || (false == client->attach( this )) || ! 549: (false == client->start( this )) ) { ! 550: if(client) { ! 551: client->detach( this ); ! 552: client->release(); ! 553: } ! 554: err = kIOReturnNoMemory; ! 555: } ! 556: ! 557: *handler = client; ! 558: return( err ); ! 559: } ! 560: ! 561:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.