1/* 2 * Copyright (c) 1998-2004 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.2 (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, QUIET ENJOYMENT OR NON-INFRINGEMENT. 17 * Please see the License for the specific language governing rights and 18 * limitations under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22 23 /* AppleUSBCDCWCM.cpp - MacOSX implementation of */ 24 /* USB Communication Device Class (CDC) Driver, WMC Interface. */ 25 26#include <machine/limits.h> /* UINT_MAX */ 27#include <libkern/OSByteOrder.h> 28 29#include <IOKit/assert.h> 30#include <IOKit/IOLib.h> 31#include <IOKit/IOService.h> 32#include <IOKit/IOBufferMemoryDescriptor.h> 33#include <IOKit/IOMessage.h> 34 35#include <IOKit/pwr_mgt/RootDomain.h> 36 37#if !TARGET_OS_IPHONE 38#include <IOKit/usb/IOUSBBus.h> 39#endif /* TARGET_OS_IPHONE */ 40 41#include <IOKit/usb/IOUSBNub.h> 42#include <IOKit/usb/IOUSBDevice.h> 43#include <IOKit/usb/IOUSBLog.h> 44#include <IOKit/usb/IOUSBPipe.h> 45#include <IOKit/usb/USB.h> 46#include <IOKit/usb/IOUSBInterface.h> 47 48#include <IOKit/serial/IOSerialKeys.h> 49#include <IOKit/serial/IOSerialDriverSync.h> 50#include <IOKit/serial/IOModemSerialStreamSync.h> 51#include <IOKit/serial/IORS232SerialStreamSync.h> 52 53#include <UserNotification/KUNCUserNotifications.h> 54 55#define DEBUG_NAME "AppleUSBCDCWCM" 56 57#include "AppleUSBCDCWCM.h" 58 59 // Globals 60 61static IOPMPowerState gOurPowerStates[kNumCDCStates] = 62{ 63 {1,0,0,0,0,0,0,0,0,0,0,0}, 64 {1,IOPMDeviceUsable,IOPMPowerOn,IOPMPowerOn,0,0,0,0,0,0,0,0} 65}; 66 67#define super IOService 68 69OSDefineMetaClassAndStructors(AppleUSBCDCWCM, IOService); 70 71/****************************************************************************************************/ 72// 73// Method: AppleUSBCDCWCM::probe 74// 75// Inputs: provider - my provider 76// 77// Outputs: IOService - from super::probe, score - probe score 78// 79// Desc: Modify the probe score if necessary (we don't at the moment) 80// 81/****************************************************************************************************/ 82 83IOService* AppleUSBCDCWCM::probe( IOService *provider, SInt32 *score ) 84{ 85 IOService *res; 86 87 // If our IOUSBInterface has a "do not match" property, it means that we should not match and need 88 // to bail. See rdar://3716623 89 90 OSBoolean *boolObj = OSDynamicCast(OSBoolean, provider->getProperty("kDoNotClassMatchThisInterface")); 91 if (boolObj && boolObj->isTrue()) 92 { 93 XTRACE(this, 0, 0, "probe - provider doesn't want us to match"); 94 return NULL; 95 } 96 97 res = super::probe(provider, score); 98 99 return res; 100 101}/* end probe */ 102 103/****************************************************************************************************/ 104// 105// Method: AppleUSBCDCWCM::start 106// 107// Inputs: provider - my provider 108// 109// Outputs: Return code - true (it's me), false (sorry it probably was me, but I can't configure it) 110// 111// Desc: This is called once it has beed determined I'm probably the best 112// driver for this interface. 113// 114/****************************************************************************************************/ 115 116bool AppleUSBCDCWCM::start(IOService *provider) 117{ 118 119 fTerminate = false; 120 fStopping = false; 121 fControlLen = 0; 122 fControlMap = NULL; 123 124 XTRACE(this, 0, 0, "start"); 125 126 if(!super::start(provider)) 127 { 128 ALERT(0, 0, "start - super failed"); 129 return false; 130 } 131 132 // Get my USB provider - the interface 133 134 fInterface = OSDynamicCast(IOUSBInterface, provider); 135 if(!fInterface) 136 { 137 ALERT(0, 0, "start - provider invalid"); 138 return false; 139 } 140 141 if (!configureDevice()) 142 { 143 ALERT(0, 0, "start - configureDevice failed"); 144 return false; 145 } 146 147 if (!allocateResources()) 148 { 149 ALERT(0, 0, "start - allocateResources failed"); 150 return false; 151 } 152 153 if (!initForPM(provider)) 154 { 155 ALERT(0, 0, "start - initForPM failed"); 156 return false; 157 } 158 159 fInterface->retain(); 160 161 registerService(); 162 163 XTRACE(this, 0, 0, "start - successful"); 164 Log(DEBUG_NAME ": Version number - %s\n", VersionNumber); 165 166 return true; 167 168}/* end start */ 169 170/****************************************************************************************************/ 171// 172// Method: AppleUSBCDCWCM::stop 173// 174// Inputs: provider - my provider 175// 176// Outputs: None 177// 178// Desc: Stops the driver 179// 180/****************************************************************************************************/ 181 182void AppleUSBCDCWCM::stop(IOService *provider) 183{ 184 185 XTRACE(this, 0, 0, "stop"); 186 187 fStopping = true; 188 189 releaseResources(); 190 191 PMstop(); 192 193 if (fControlMap) 194 { 195 IOFree(fControlMap, fControlLen); 196 fControlMap = NULL; 197 fControlLen = 0; 198 } 199 200 super::stop(provider); 201 202}/* end stop */ 203 204/****************************************************************************************************/ 205// 206// Method: AppleUSBCDCWCM::configureWHCM 207// 208// Inputs: None 209// 210// Outputs: return Code - true (configured), false (not configured) 211// 212// Desc: Configures the Wireless handset Control Model interface 213// 214/****************************************************************************************************/ 215 216bool AppleUSBCDCWCM::configureWHCM() 217{ 218 219 XTRACE(this, 0, 0, "configureWHCM"); 220 221 fInterfaceNumber = fInterface->GetInterfaceNumber(); 222 XTRACE(this, 0, fInterfaceNumber, "configureWHCM - Comm interface number."); 223 224 if (!getFunctionalDescriptors()) 225 { 226 XTRACE(this, 0, 0, "configureWHCM - getFunctionalDescriptors failed"); 227 return false; 228 } 229 230 return true; 231 232}/* end configureWHCM */ 233 234/****************************************************************************************************/ 235// 236// Method: AppleUSBCDCWCM::configureDevice 237// 238// Inputs: None 239// 240// Outputs: return Code - true (device configured), false (device not configured) 241// 242// Desc: Finds the appropriate interface etc. 243// 244/****************************************************************************************************/ 245 246bool AppleUSBCDCWCM::configureDevice() 247{ 248 bool configOK = false; 249 250 XTRACE(this, 0, 0, "configureDevice"); 251 252 fInterfaceNumber = fInterface->GetInterfaceNumber(); 253 fSubClass = fInterface->GetInterfaceSubClass(); 254 XTRACE(this, fSubClass, fInterfaceNumber, "configureDevice - Subclass and interface number."); 255 256 switch (fSubClass) 257 { 258 case kUSBWirelessHandsetControlModel: 259 if (configureWHCM()) 260 { 261 configOK = true; 262 } 263 break; 264 default: 265 XTRACE(this, 0, fSubClass, "configureDevice - Unsupported subclass"); 266 break; 267 } 268 269 if (!configOK) 270 { 271 XTRACE(this, 0, 0, "configureDevice - configuration failed"); 272 return false; 273 } 274 275 return true; 276 277}/* end configureDevice */ 278 279/****************************************************************************************************/ 280// 281// Method: AppleUSBCDCWCM::getFunctionalDescriptors 282// 283// Inputs: 284// 285// Outputs: return - true (descriptors ok), false (somethings not right or not supported) 286// 287// Desc: Finds all the functional descriptors for the specific interface 288// 289/****************************************************************************************************/ 290 291bool AppleUSBCDCWCM::getFunctionalDescriptors() 292{ 293 bool gotDescriptors = false; 294 UInt16 vers; 295 UInt16 *chkVers; 296 const FunctionalDescriptorHeader *funcDesc = NULL; 297 HDRFunctionalDescriptor *HDRFDesc; // header functional descriptor 298 WHCMFunctionalDescriptor *WCMFDesc; // whcm functional descriptor 299 UnionFunctionalDescriptor *UNNFDesc; // union functional descriptor 300 301 XTRACE(this, 0, 0, "getFunctionalDescriptors"); 302 303 do 304 { 305 funcDesc = (const FunctionalDescriptorHeader *)fInterface->FindNextAssociatedDescriptor((void*)funcDesc, CS_INTERFACE); 306 if (!funcDesc) 307 { 308 gotDescriptors = true; // We're done 309 } else { 310 switch (funcDesc->bDescriptorSubtype) 311 { 312 case Header_FunctionalDescriptor: 313 HDRFDesc = (HDRFunctionalDescriptor *)funcDesc; 314 XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - Header Functional Descriptor"); 315 chkVers = (UInt16 *)&HDRFDesc->bcdCDC1; 316 vers = USBToHostWord(*chkVers); 317 if (vers > kUSBRel11) 318 { 319 XTRACE(this, vers, kUSBRel11, "getFunctionalDescriptors - Header descriptor version number is incorrect"); 320 } 321 break; 322 case Union_FunctionalDescriptor: 323 UNNFDesc = (UnionFunctionalDescriptor *)funcDesc; 324 XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - Union Functional Descriptor"); 325 if (UNNFDesc->bFunctionLength > sizeof(FunctionalDescriptorHeader)) 326 { 327 if (fInterfaceNumber != UNNFDesc->bMasterInterface) 328 { 329 XTRACE(this, fInterfaceNumber, UNNFDesc->bMasterInterface, "getFunctionalDescriptors - Master interface incorrect"); 330 } else { 331 fControlLen = UNNFDesc->bFunctionLength - sizeof(FunctionalDescriptorHeader); 332 fControlLen -= sizeof(UNNFDesc->bMasterInterface); // Step over master as it's us and we've already checked it 333 fControlMap = (UInt8 *)IOMalloc(fControlLen); 334 bcopy(&UNNFDesc->bSlaveInterface, fControlMap, fControlLen); // Just save them for now... 335 XTRACEP(this, fControlMap, fControlLen, "getFunctionalDescriptors - Map and length"); 336 } 337 } else { 338 XTRACE(this, UNNFDesc->bFunctionLength, 0, "getFunctionalDescriptors - Union descriptor length error"); 339 } 340 break; 341 case WCM_FunctionalDescriptor: 342 WCMFDesc = (WHCMFunctionalDescriptor *)funcDesc; 343 XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - WHCM Functional Descriptor"); 344 chkVers = (UInt16 *)&WCMFDesc->bcdCDC1; 345 vers = USBToHostWord(*chkVers); 346 if (vers > kUSBRel10) 347 { 348 XTRACE(this, vers, kUSBRel10, "getFunctionalDescriptors - WHCM descriptor version number is incorrect"); 349 } 350 break; 351 default: 352 XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - unknown Functional Descriptor"); 353 break; 354 } 355 } 356 } while(!gotDescriptors); 357 358 359 360 return true; 361 362}/* end getFunctionalDescriptors */ 363 364/****************************************************************************************************/ 365// 366// Method: AppleUSBCDCWCM::allocateResources 367// 368// Inputs: 369// 370// Outputs: return code - true (allocate was successful), false (it failed) 371// 372// Desc: Finishes up the rest of the configuration 373// 374/****************************************************************************************************/ 375 376bool AppleUSBCDCWCM::allocateResources() 377{ 378 379 XTRACE(this, 0, 0, "allocateResources."); 380 381 // Open the interface 382 383 if (!fInterface->open(this)) 384 { 385 XTRACE(this, 0, 0, "allocateResources - open comm interface failed."); 386 return false; 387 } 388 389 return true; 390 391}/* end allocateResources */ 392 393/****************************************************************************************************/ 394// 395// Method: AppleUSBCDCWCM::releaseResources 396// 397// Inputs: 398// 399// Outputs: 400// 401// Desc: Frees up the resources allocated in allocateResources 402// 403/****************************************************************************************************/ 404 405void AppleUSBCDCWCM::releaseResources() 406{ 407 XTRACE(this, 0, 0, "releaseResources"); 408 409 if (fInterface) 410 { 411 fInterface->close(this); 412 fInterface->release(); 413 fInterface = NULL; 414 } 415 416}/* end releaseResources */ 417 418/****************************************************************************************************/ 419// 420// Method: AppleUSBCDCWCM::resetLogicalHandset 421// 422// Inputs: 423// 424// Outputs: 425// 426// Desc: Reset the logical handset after waking. 427// 428/****************************************************************************************************/ 429 430void AppleUSBCDCWCM::resetLogicalHandset(void) 431{ 432 433 XTRACE(this, 0, 0, "resetLogicalHandset"); 434 435 if ((fStopping) || (fInterface == NULL)) 436 { 437 return; 438 } 439 440 441 442}/* end resetLogicalHandset */ 443 444/****************************************************************************************************/ 445// 446// Method: AppleUSBCDCWCM::message 447// 448// Inputs: type - message type 449// provider - my provider 450// argument - additional parameters 451// 452// Outputs: return Code - kIOReturnSuccess 453// 454// Desc: Handles IOKit messages. 455// 456/****************************************************************************************************/ 457 458IOReturn AppleUSBCDCWCM::message(UInt32 type, IOService *provider, void *argument) 459{ 460 461 XTRACE(this, 0, type, "message"); 462 463 switch (type) 464 { 465 case kIOMessageServiceIsTerminated: 466 XTRACE(this, 0, type, "message - kIOMessageServiceIsTerminated"); 467 fTerminate = true; // We're being terminated (unplugged) 468 releaseResources(); 469 return kIOReturnSuccess; 470 case kIOMessageServiceIsSuspended: 471 XTRACE(this, 0, type, "message - kIOMessageServiceIsSuspended"); 472 break; 473 case kIOMessageServiceIsResumed: 474 XTRACE(this, 0, type, "message - kIOMessageServiceIsResumed"); 475 break; 476 case kIOMessageServiceIsRequestingClose: 477 XTRACE(this, 0, type, "message - kIOMessageServiceIsRequestingClose"); 478 break; 479 case kIOMessageServiceWasClosed: 480 XTRACE(this, 0, type, "message - kIOMessageServiceWasClosed"); 481 break; 482 case kIOMessageServiceBusyStateChange: 483 XTRACE(this, 0, type, "message - kIOMessageServiceBusyStateChange"); 484 break; 485 case kIOUSBMessagePortHasBeenResumed: 486 XTRACE(this, 0, type, "message - kIOUSBMessagePortHasBeenResumed"); 487 break; 488 case kIOUSBMessageHubResumePort: 489 XTRACE(this, 0, type, "message - kIOUSBMessageHubResumePort"); 490 break; 491 default: 492 XTRACE(this, 0, type, "message - unknown message"); 493 break; 494 } 495 496 return super::message(type, provider, argument); 497 498}/* end message */ 499 500/****************************************************************************************************/ 501// 502// Method: AppleUSBCDCWCM::initForPM 503// 504// Inputs: provider - my provider 505// 506// Outputs: return code - true(initialized), false(failed) 507// 508// Desc: Add ourselves to the power management tree so we can do 509// the right thing on sleep/wakeup. 510// 511/****************************************************************************************************/ 512 513bool AppleUSBCDCWCM::initForPM(IOService *provider) 514{ 515 XTRACE(this, 0, 0, "initForPM"); 516 517 fPowerState = kCDCPowerOnState; // init our power state to be 'on' 518 PMinit(); // init power manager instance variables 519 provider->joinPMtree(this); // add us to the power management tree 520 if (pm_vars != NULL) 521 { 522 523 // register ourselves with ourself as policy-maker 524 525 registerPowerDriver(this, gOurPowerStates, kNumCDCStates); 526 return true; 527 } else { 528 XTRACE(this, 0, 0, "initForPM - Initializing power manager failed"); 529 } 530 531 return false; 532 533}/* end initForPM */ 534 535/****************************************************************************************************/ 536// 537// Method: AppleUSBCDCWCM::initialPowerStateForDomainState 538// 539// Inputs: flags - 540// 541// Outputs: return code - Current power state 542// 543// Desc: Request for our initial power state. 544// 545/****************************************************************************************************/ 546 547unsigned long AppleUSBCDCWCM::initialPowerStateForDomainState(IOPMPowerFlags flags) 548{ 549 550 XTRACE(this, 0, flags, "initialPowerStateForDomainState"); 551 552 return fPowerState; 553 554}/* end initialPowerStateForDomainState */ 555 556/****************************************************************************************************/ 557// 558// Method: AppleUSBCDCWCM::setPowerState 559// 560// Inputs: powerStateOrdinal - on/off 561// 562// Outputs: return code - IOPMNoErr, IOPMAckImplied or IOPMNoSuchState 563// 564// Desc: Request to turn device on or off. 565// 566/****************************************************************************************************/ 567 568IOReturn AppleUSBCDCWCM::setPowerState(unsigned long powerStateOrdinal, IOService *whatDevice) 569{ 570 571 XTRACE(this, 0, powerStateOrdinal, "setPowerState"); 572 573 if (powerStateOrdinal == kCDCPowerOffState || powerStateOrdinal == kCDCPowerOnState) 574 { 575 if (powerStateOrdinal == fPowerState) 576 return IOPMAckImplied; 577 578 fPowerState = powerStateOrdinal; 579 if (fPowerState == kCDCPowerOnState) 580 { 581 resetLogicalHandset(); 582 } 583 584 return IOPMAckImplied; 585 } 586 587 return IOPMAckImplied; 588 589}/* end setPowerState */