|
|
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: * 05 Mar 99 ehewitt created. ! 27: * ! 28: * IOUSBInterface ! 29: * In USB there is the concept of a composite device, which means that ! 30: * each interface in a selected configuration can act as a separate device. ! 31: * Take for example a combo keyboard/trackball device. In this example, ! 32: * we might want a generic keyboard driver to handle the keyboard part and ! 33: * a generic pointer driver to handle the trackball part. ! 34: * So what we do is publish a IOUSBInterface for each interface of a ! 35: * composite device and intercept the few device requests that are not allowed ! 36: * by an interface, like set address and set configuration. ! 37: * If another driver handled both functions, or if there was a specific driver ! 38: * for that device, the matching logic would do the right thing. ! 39: * ! 40: */ ! 41: ! 42: #include <libkern/OSByteOrder.h> ! 43: #include <IOKit/usb/IOUSBDevice.h> ! 44: #include <IOKit/usb/IOUSBController.h> ! 45: #include <IOKit/usb/IOUSBInterface.h> ! 46: #include <libkern/c++/OSDictionary.h> ! 47: #include <libkern/c++/OSData.h> ! 48: #include <IOKit/assert.h> ! 49: ! 50: #include <IOKit/usb/IOUSBPipe.h> ! 51: #include "IOUSBUserClient.h" ! 52: #define super IOUSBNub ! 53: #define self this ! 54: ! 55: int devintdebug = 0; ! 56: #define DEBUGLOG if (devintdebug) kprintf ! 57: ! 58: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ! 59: ! 60: OSDefineMetaClassAndStructors(IOUSBInterface, IOUSBNub) ! 61: ! 62: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ! 63: ! 64: bool IOUSBInterface::init(OSDictionary * propTable, ! 65: const IOUSBConfigurationDescriptor *cfdesc, ! 66: const IOUSBInterfaceDescriptor *ifdesc) ! 67: { ! 68: if(!ifdesc || !cfdesc) ! 69: return (false); ! 70: ! 71: if( !IOUSBNub::init(propTable)) ! 72: return (false); ! 73: _configDesc = cfdesc; ! 74: _interfaceDesc = ifdesc; ! 75: ! 76: return (true); ! 77: } ! 78: ! 79: bool IOUSBInterface::attach(IOService *provider) ! 80: { ! 81: IOUSBDevice * device = OSDynamicCast(IOUSBDevice, provider); ! 82: if(!device) ! 83: return false; ! 84: if( !IOUSBNub::attach(provider)) ! 85: return false; ! 86: _device = device; ! 87: _controller = device->bus(); ! 88: _pipeZero = device->pipeZero(); ! 89: _pipeZero->retain(); ! 90: ! 91: if(_interfaceDesc->interfaceStrIndex) { ! 92: IOReturn err; ! 93: char name[128]; ! 94: ! 95: err = GetStringDescriptor(_interfaceDesc->interfaceStrIndex, name, sizeof(name)); ! 96: if(err == kIOReturnSuccess) ! 97: setName(name); ! 98: } ! 99: ! 100: return true; ! 101: } ! 102: ! 103: bool IOUSBInterface::finalize(IOOptionBits options) ! 104: { ! 105: cleanPipes(); ! 106: return IOUSBNub::finalize(options); ! 107: } ! 108: ! 109: /* ! 110: * deviceRequest ! 111: * The idea here is to intercept only the calls that an interface, ! 112: * thinking it's a driver, might make. These include setting it's ! 113: * configuration, getting it's device descriptor, and setting it's address. ! 114: */ ! 115: IOReturn IOUSBInterface::deviceRequest(IOUSBDevRequest *request, ! 116: IOUSBCompletion *completion = 0) ! 117: { ! 118: IOReturn err; ! 119: UInt16 theRequest; ! 120: ! 121: ! 122: if (!request) ! 123: return(kIOReturnBadArgument); ! 124: ! 125: theRequest = EncodeRequest(request->bRequest, request->rqDirection, ! 126: request->rqType, request->rqRecipient); ! 127: ! 128: if (theRequest == kSetConfiguration) ! 129: { ! 130: DEBUGLOG("\tignoring kSetConfiguration\n"); ! 131: err = kIOReturnNotPermitted; ! 132: } ! 133: else ! 134: { ! 135: err = super::deviceRequest(request, completion); ! 136: } ! 137: ! 138: return(err); ! 139: } ! 140: ! 141: void IOUSBInterface::cleanPipes(void) ! 142: { ! 143: IOUSBPipe * pipe; ! 144: ! 145: for( unsigned int i=0; i < kUSBMaxPipes; i++) { ! 146: if( (pipe = _pipeList[i])) { ! 147: pipe->release(); ! 148: _pipeList[i] = 0; ! 149: } ! 150: } ! 151: } ! 152: ! 153: // Open all the pipes. ! 154: bool IOUSBInterface::open(IOService * forClient, ! 155: IOOptionBits options = 0, ! 156: void * arg = 0 ) ! 157: { ! 158: unsigned int i = 0; ! 159: const IOUSBDescriptorHeader *pos = NULL; ! 160: if(!IOUSBNub::open(forClient, options, arg)) ! 161: return false; ! 162: ! 163: if(_currentAlt != _interfaceDesc->alternateSetting) { ! 164: IOUSBDevRequest request; ! 165: IOReturn res; ! 166: ! 167: request.rqDirection = kUSBOut; ! 168: request.rqType = kUSBStandard; ! 169: request.rqRecipient = kUSBInterface; ! 170: request.bRequest = kUSBRqSetInterface; ! 171: OSWriteLittleInt16(&request.wValue, 0, _interfaceDesc->alternateSetting); ! 172: OSWriteLittleInt16(&request.wIndex, 0, _interfaceDesc->interfaceNumber); ! 173: OSWriteLittleInt16(&request.wLength, 0, 0); ! 174: request.pData = 0; ! 175: res = deviceRequest(&request); ! 176: IOLog("SetInterface (%d, %d) returned 0x%x\n", ! 177: _interfaceDesc->interfaceNumber, _interfaceDesc->alternateSetting, res); ! 178: if(res != kIOReturnSuccess) { ! 179: close(forClient); ! 180: return false; ! 181: } ! 182: _currentAlt = _interfaceDesc->alternateSetting; ! 183: } ! 184: while ((pos = findNextAssociatedDescriptor(pos, kUSBEndpointDesc))) { ! 185: // Don't open twice! ! 186: if(_pipeList[i] == NULL) { ! 187: _pipeList[i] = IOUSBPipe::toEndpoint((const IOUSBEndpointDescriptor *)pos, ! 188: _speed, _address, _controller); ! 189: } ! 190: if(_pipeList[i] == NULL) { ! 191: close(forClient); ! 192: return false; ! 193: } ! 194: i++; ! 195: } ! 196: assert(i == _interfaceDesc->numEndpoints); ! 197: ! 198: return true; ! 199: } ! 200: ! 201: void IOUSBInterface::close(IOService * forClient, ! 202: IOOptionBits options = 0 ) ! 203: { ! 204: cleanPipes(); ! 205: IOUSBNub::close(forClient, options); ! 206: } ! 207: ! 208: const IOUSBInterfaceDescriptor * ! 209: IOUSBInterface::findNextAltInterface(const IOUSBInterfaceDescriptor *current, ! 210: FindInterfaceRequest *request) ! 211: { ! 212: const IOUSBInterfaceDescriptor * id; ! 213: const IOUSBDescriptorHeader * pos = NULL; ! 214: bool found; ! 215: if(current == NULL) ! 216: pos = (IOUSBDescriptorHeader *)_configDesc; ! 217: else ! 218: pos = (IOUSBDescriptorHeader *)current; ! 219: while (pos) ! 220: { ! 221: pos = findNextDescriptor(pos, kUSBInterfaceDesc); ! 222: id = (const IOUSBInterfaceDescriptor *)pos; ! 223: if(id == NULL || (id->interfaceNumber != _interfaceDesc->interfaceNumber)) { ! 224: continue; ! 225: } ! 226: ! 227: // check the request parameters ! 228: found = true; ! 229: if (request->theClass != 0 && request->theClass != id->interfaceClass) ! 230: found = false; // this is not it ! 231: if (request->subClass != 0 && request->subClass != id->interfaceSubClass) ! 232: found = false; // this is not it ! 233: if (request->protocol != 0 && request->protocol != id->interfaceProtocol) ! 234: found = false; // this is not it ! 235: if (found) ! 236: { ! 237: request->theClass = id->interfaceClass; ! 238: request->subClass = id->interfaceSubClass; ! 239: request->protocol = id->interfaceProtocol; ! 240: request->maxPower = _configDesc->maxPower; ! 241: request->busPowered = _configDesc->attributes & kUSBAtrBusPowered ? 2 : 1; ! 242: request->selfPowered = _configDesc->attributes & kUSBAtrSelfPowered ? 2 : 1; ! 243: request->remoteWakeup = _configDesc->attributes & kUSBAtrRemoteWakeup ? 2 : 1; ! 244: return(id); ! 245: } ! 246: } ! 247: return(0); ! 248: } ! 249: ! 250: ! 251: IOUSBPipe *IOUSBInterface::findNextPipe(IOUSBPipe *current, ! 252: IOUSBFindEndpointRequest *request) ! 253: { ! 254: const IOUSBController::Endpoint * endpoint; ! 255: IOUSBPipe * pipe; ! 256: int numEndpoints; ! 257: int i; ! 258: ! 259: numEndpoints = _interfaceDesc->numEndpoints; ! 260: ! 261: if (request == 0) ! 262: return NULL; ! 263: if(current != 0) { ! 264: for(i=0;i < numEndpoints; i++) { ! 265: if(_pipeList[i] == current) { ! 266: i++; // Skip the one we just did ! 267: break; ! 268: } ! 269: } ! 270: } ! 271: else ! 272: i = 0; // Start at beginning. ! 273: ! 274: for (;i < numEndpoints; i++) { ! 275: pipe = _pipeList[i]; ! 276: if(!pipe) ! 277: continue; ! 278: endpoint = pipe->endpoint(); ! 279: ! 280: // check the request parameters ! 281: if (request->type != kUSBAnyType && ! 282: request->type != endpoint->transferType) ! 283: pipe = 0; // this is not it ! 284: else if (request->direction != kUSBAnyDirn && ! 285: request->direction != endpoint->direction) ! 286: pipe = 0; // this is not it ! 287: ! 288: if (pipe == 0) ! 289: continue; ! 290: ! 291: request->type = endpoint->transferType; ! 292: request->direction = endpoint->direction; ! 293: request->maxPacketSize = endpoint->maxPacketSize; ! 294: request->interval = endpoint->interval; ! 295: return(pipe); ! 296: } ! 297: ! 298: return(0); ! 299: } ! 300: ! 301: const IOUSBDescriptorHeader * ! 302: IOUSBInterface::findNextAssociatedDescriptor(const void *current, UInt8 type) ! 303: { ! 304: const IOUSBDescriptorHeader *next; ! 305: if(current == NULL) ! 306: current = _interfaceDesc; ! 307: next = (const IOUSBDescriptorHeader *)current; ! 308: ! 309: while (true) { ! 310: next = findNextDescriptor(next, kUSBAnyDesc); ! 311: ! 312: if(!next || next->descriptorType == kUSBInterfaceDesc) ! 313: return NULL; // Reached end of our list. ! 314: if(next->descriptorType == type || type == kUSBAnyDesc) ! 315: break; ! 316: } ! 317: return next; ! 318: } ! 319: ! 320: IOReturn ! 321: IOUSBInterface::setAlternateInterface(UInt8 alternateSetting) ! 322: { ! 323: const IOUSBDescriptorHeader *next; ! 324: const IOUSBInterfaceDescriptor *ifdesc; ! 325: ! 326: next = (const IOUSBDescriptorHeader *)_configDesc; ! 327: ! 328: while( (next = findNextDescriptor(next, kUSBInterfaceDesc))) { ! 329: ifdesc = (const IOUSBInterfaceDescriptor *)next; ! 330: if(ifdesc->interfaceNumber == _interfaceDesc->interfaceNumber && ! 331: ifdesc->alternateSetting == alternateSetting) ! 332: break; ! 333: } ! 334: ! 335: if(ifdesc) { ! 336: _interfaceDesc = ifdesc; ! 337: OSData * data; ! 338: data = OSData::withBytes(ifdesc, sizeof(*ifdesc)); ! 339: if (data) { ! 340: setProperty("interface descriptor", data); ! 341: data->release(); ! 342: } ! 343: ! 344: return kIOReturnSuccess; ! 345: } ! 346: else ! 347: return kIOUSBConfigNotFound; ! 348: } ! 349: ! 350: UInt8 IOUSBInterface::getConfigValue() ! 351: { ! 352: return _configDesc->configValue; ! 353: } ! 354: ! 355: const IOUSBInterfaceDescriptor * IOUSBInterface::interfaceDescriptor() ! 356: { ! 357: return _interfaceDesc; ! 358: } ! 359: ! 360: IOUSBDevice * IOUSBInterface::device() ! 361: { ! 362: return _device; ! 363: } ! 364: ! 365: IOReturn IOUSBInterface::newUserClient( task_t owningTask, ! 366: void * /* security_id */, ! 367: UInt32 type, ! 368: IOUserClient ** handler ) ! 369: ! 370: { ! 371: IOReturn err = kIOReturnSuccess; ! 372: IOUSBInterfaceUserClient * client; ! 373: ! 374: if( type != kIOUSBDeviceConnectType) ! 375: return( kIOReturnBadArgument); ! 376: ! 377: client = IOUSBInterfaceUserClient::withTask(owningTask); ! 378: ! 379: if( !client || (false == client->attach( this )) || ! 380: (false == client->start( this )) ) { ! 381: if(client) { ! 382: client->detach( this ); ! 383: client->release(); ! 384: } ! 385: err = kIOReturnNoMemory; ! 386: } ! 387: ! 388: *handler = client; ! 389: return( err ); ! 390: } ! 391: ! 392: ! 393:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.