1/* 2 * Copyright (c) 1998-2012 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include <IOKit/storage/IOCDBlockStorageDriver.h> 25#include <IOKit/storage/IOCDMedia.h> 26 27#define super IOMedia 28OSDefineMetaClassAndStructors(IOCDMedia, IOMedia) 29 30class IOStorageSyncerLock 31{ 32protected: 33 34 IOLock * _lock; 35 36public: 37 38 inline IOStorageSyncerLock( ) 39 { 40 _lock = IOLockAlloc( ); 41 } 42 43 inline ~IOStorageSyncerLock( ) 44 { 45 if ( _lock ) IOLockFree( _lock ); 46 } 47 48 inline void lock( ) 49 { 50 IOLockLock( _lock ); 51 } 52 53 inline void unlock( ) 54 { 55 IOLockUnlock( _lock ); 56 } 57 58 inline void sleep( void * event ) 59 { 60 IOLockSleep( _lock, event, THREAD_UNINT ); 61 } 62 63 inline void wakeup( void * event ) 64 { 65 IOLockWakeup( _lock, event, false ); 66 } 67}; 68 69static IOStorageSyncerLock gIOStorageSyncerLock; 70 71class IOStorageSyncer 72{ 73protected: 74 75 IOReturn _status; 76 bool _wakeup; 77 78public: 79 80 IOStorageSyncer( ) 81 { 82 _wakeup = false; 83 } 84 85 IOReturn wait( ) 86 { 87 gIOStorageSyncerLock.lock( ); 88 89 while ( _wakeup == false ) 90 { 91 gIOStorageSyncerLock.sleep( this ); 92 } 93 94 gIOStorageSyncerLock.unlock( ); 95 96 return _status; 97 } 98 99 void signal( IOReturn status ) 100 { 101 _status = status; 102 103 gIOStorageSyncerLock.lock( ); 104 105 _wakeup = true; 106 107 gIOStorageSyncerLock.wakeup( this ); 108 109 gIOStorageSyncerLock.unlock( ); 110 } 111}; 112 113static void storageCompletion(void * target, 114 void * parameter, 115 IOReturn status, 116 UInt64 actualByteCount) 117{ 118 // 119 // Internal completion routine for synchronous versions of read and write. 120 // 121 122 if (parameter) *((UInt64 *)parameter) = actualByteCount; 123 ((IOStorageSyncer *)target)->signal(status); 124} 125 126IOCDBlockStorageDriver * IOCDMedia::getProvider() const 127{ 128 // 129 // Obtain this object's provider. We override the superclass's method to 130 // return a more specific subclass of IOService -- IOCDBlockStorageDriver. 131 // This method serves simply as a convenience to subclass developers. 132 // 133 134 return (IOCDBlockStorageDriver *) IOService::getProvider(); 135} 136 137bool IOCDMedia::matchPropertyTable(OSDictionary * table, SInt32 * score) 138{ 139 // 140 // Compare the properties in the supplied table to this object's properties. 141 // 142 143 // Ask our superclass' opinion. 144 145 if (super::matchPropertyTable(table, score) == false) return false; 146 147 // We return success if the following expression is true -- individual 148 // comparisions evaluate to truth if the named property is not present 149 // in the supplied table. 150 151 return compareProperty(table, kIOCDMediaTOCKey ) && 152 compareProperty(table, kIOCDMediaTypeKey); 153} 154 155void IOCDMedia::read(IOService * /* client */, 156 UInt64 byteStart, 157 IOMemoryDescriptor * buffer, 158 IOStorageAttributes * attributes, 159 IOStorageCompletion * completion) 160{ 161 // 162 // Read data from the storage object at the specified byte offset into the 163 // specified buffer, asynchronously. When the read completes, the caller 164 // will be notified via the specified completion action. 165 // 166 // The buffer will be retained for the duration of the read. 167 // 168 // This method will work even when the media is in the terminated state. 169 // 170 171 if (isInactive()) 172 { 173 complete(completion, kIOReturnNoMedia); 174 return; 175 } 176 177 if (_openLevel == kIOStorageAccessNone) // (instantaneous value, no lock) 178 { 179 complete(completion, kIOReturnNotOpen); 180 return; 181 } 182 183 if (_mediaSize == 0 || _preferredBlockSize == 0) 184 { 185 complete(completion, kIOReturnUnformattedMedia); 186 return; 187 } 188 189 if (buffer == 0) 190 { 191 complete(completion, kIOReturnBadArgument); 192 return; 193 } 194 195 if (_mediaSize < byteStart + buffer->getLength()) 196 { 197 complete(completion, kIOReturnBadArgument); 198 return; 199 } 200 201 byteStart += _mediaBase; 202 getProvider()->readCD( /* client */ this, 203 /* byteStart */ byteStart, 204 /* buffer */ buffer, 205 /* sectorArea */ (CDSectorArea) 0xF8, // (2352 bytes) 206 /* sectorType */ (CDSectorType) 0x00, // ( all types) 207#ifdef __LP64__ 208 /* attributes */ attributes, 209 /* completion */ completion ); 210#else /* !__LP64__ */ 211 /* completion */ completion ? *completion : (IOStorageCompletion) { 0 } ); 212#endif /* !__LP64__ */ 213} 214 215void IOCDMedia::write(IOService * client, 216 UInt64 byteStart, 217 IOMemoryDescriptor * buffer, 218 IOStorageAttributes * attributes, 219 IOStorageCompletion * completion) 220{ 221 // 222 // Write data into the storage object at the specified byte offset from the 223 // specified buffer, asynchronously. When the write completes, the caller 224 // will be notified via the specified completion action. 225 // 226 // The buffer will be retained for the duration of the write. 227 // 228 // This method will work even when the media is in the terminated state. 229 // 230 231 if (isInactive()) 232 { 233 complete(completion, kIOReturnNoMedia); 234 return; 235 } 236 237 if (_openLevel == kIOStorageAccessNone) // (instantaneous value, no lock) 238 { 239 complete(completion, kIOReturnNotOpen); 240 return; 241 } 242 243 if (_openLevel == kIOStorageAccessReader) // (instantaneous value, no lock) 244 { 245 complete(completion, kIOReturnNotPrivileged); 246 return; 247 } 248 249 if (_isWritable == 0) 250 { 251 complete(completion, kIOReturnLockedWrite); 252 return; 253 } 254 255 if (_mediaSize == 0 || _preferredBlockSize == 0) 256 { 257 complete(completion, kIOReturnUnformattedMedia); 258 return; 259 } 260 261 if (buffer == 0) 262 { 263 complete(completion, kIOReturnBadArgument); 264 return; 265 } 266 267 if (_mediaSize < byteStart + buffer->getLength()) 268 { 269 complete(completion, kIOReturnBadArgument); 270 return; 271 } 272 273 byteStart += _mediaBase; 274 getProvider()->writeCD( 275 /* client */ this, 276 /* byteStart */ byteStart, 277 /* buffer */ buffer, 278 /* sectorArea */ (CDSectorArea) 0xF8, // (2352 bytes) 279 /* sectorType */ (CDSectorType) 0x00, // ( all types) 280#ifdef __LP64__ 281 /* attributes */ attributes, 282 /* completion */ completion ); 283#else /* !__LP64__ */ 284 /* completion */ completion ? *completion : (IOStorageCompletion) { 0 } ); 285#endif /* !__LP64__ */ 286} 287 288IOReturn IOCDMedia::readCD(IOService * client, 289 UInt64 byteStart, 290 IOMemoryDescriptor * buffer, 291 CDSectorArea sectorArea, 292 CDSectorType sectorType, 293#ifdef __LP64__ 294 IOStorageAttributes * attributes, 295#endif /* __LP64__ */ 296 UInt64 * actualByteCount) 297{ 298 // 299 // Read data from the CD media object at the specified byte offset into the 300 // specified buffer, synchronously. Special areas of the CD sector can be 301 // read via this method, such as the header and subchannel data. When the 302 // read completes, this method will return to the caller. The actual byte 303 // count field is optional. 304 // 305 // This method will work even when the media is in the terminated state. 306 // 307 308 IOStorageCompletion completion; 309 IOStorageSyncer syncer; 310 311 // Fill in the completion information for this request. 312 313 completion.target = &syncer; 314 completion.action = storageCompletion; 315 completion.parameter = actualByteCount; 316 317 // Issue the asynchronous read. 318 319#ifdef __LP64__ 320 readCD(client, byteStart, buffer, sectorArea, sectorType, attributes, &completion); 321#else /* !__LP64__ */ 322 readCD(client, byteStart, buffer, sectorArea, sectorType, completion); 323#endif /* !__LP64__ */ 324 325 // Wait for the read to complete. 326 327 return syncer.wait(); 328} 329 330void IOCDMedia::readCD(IOService * client, 331 UInt64 byteStart, 332 IOMemoryDescriptor * buffer, 333 CDSectorArea sectorArea, 334 CDSectorType sectorType, 335#ifdef __LP64__ 336 IOStorageAttributes * attributes, 337 IOStorageCompletion * completion) 338#else /* !__LP64__ */ 339 IOStorageCompletion completion) 340#endif /* !__LP64__ */ 341{ 342 // 343 // Read data from the CD media object at the specified byte offset into the 344 // specified buffer, asynchronously. Special areas of the CD sector can be 345 // read via this method, such as the header and subchannel data. When the 346 // read completes, the caller will be notified via the specified completion 347 // action. 348 // 349 // The buffer will be retained for the duration of the read. 350 // 351 // This method will work even when the media is in the terminated state. 352 // 353 354 if (isInactive()) 355 { 356 complete(completion, kIOReturnNoMedia); 357 return; 358 } 359 360 if (_openLevel == kIOStorageAccessNone) // (instantaneous value, no lock) 361 { 362 complete(completion, kIOReturnNotOpen); 363 return; 364 } 365 366 if (_mediaSize == 0 || _preferredBlockSize == 0) 367 { 368 complete(completion, kIOReturnUnformattedMedia); 369 return; 370 } 371 372 if (buffer == 0) 373 { 374 complete(completion, kIOReturnBadArgument); 375 return; 376 } 377 378 byteStart += _mediaBase; 379 getProvider()->readCD( /* client */ this, 380 /* byteStart */ byteStart, 381 /* buffer */ buffer, 382 /* sectorArea */ sectorArea, 383 /* sectorType */ sectorType, 384#ifdef __LP64__ 385 /* attributes */ attributes, 386#endif /* __LP64__ */ 387 /* completion */ completion ); 388} 389 390IOReturn IOCDMedia::readISRC(UInt8 track, CDISRC isrc) 391{ 392 // 393 // Read the International Standard Recording Code for the specified track. 394 // 395 // This method will work even when the media is in the terminated state. 396 // 397 398 if (isInactive()) 399 { 400 return kIOReturnNoMedia; 401 } 402 403 return getProvider()->readISRC(track, isrc); 404} 405 406IOReturn IOCDMedia::readMCN(CDMCN mcn) 407{ 408 // 409 // Read the Media Catalog Number (also known as the Universal Product Code). 410 // 411 // This method will work even when the media is in the terminated state. 412 // 413 414 if (isInactive()) 415 { 416 return kIOReturnNoMedia; 417 } 418 419 return getProvider()->readMCN(mcn); 420} 421 422CDTOC * IOCDMedia::getTOC() 423{ 424 // 425 // Get the full Table Of Contents. 426 // 427 // This method will work even when the media is in the terminated state. 428 // 429 430 if (isInactive()) 431 { 432 return 0; 433 } 434 435 return getProvider()->getTOC(); 436} 437 438IOReturn IOCDMedia::getSpeed(UInt16 * kilobytesPerSecond) 439{ 440 // 441 // Get the current speed used for data transfers. 442 // 443 444 if (isInactive()) 445 { 446 return kIOReturnNoMedia; 447 } 448 449 return getProvider()->getSpeed(kilobytesPerSecond); 450} 451 452IOReturn IOCDMedia::setSpeed(UInt16 kilobytesPerSecond) 453{ 454 // 455 // Set the speed to be used for data transfers. 456 // 457 458 if (isInactive()) 459 { 460 return kIOReturnNoMedia; 461 } 462 463 return getProvider()->setSpeed(kilobytesPerSecond); 464} 465 466IOReturn IOCDMedia::readTOC(IOMemoryDescriptor * buffer, 467 CDTOCFormat format, 468 UInt8 formatAsTime, 469 UInt8 trackOrSessionNumber, 470 UInt16 * actualByteCount) 471{ 472 if (isInactive()) 473 { 474 if (actualByteCount) *actualByteCount = 0; 475 476 return kIOReturnNoMedia; 477 } 478 479 if (buffer == 0) 480 { 481 if (actualByteCount) *actualByteCount = 0; 482 483 return kIOReturnBadArgument; 484 } 485 486 return getProvider()->readTOC( 487 /* buffer */ buffer, 488 /* format */ format, 489 /* formatAsTime */ formatAsTime, 490 /* trackOrSessionNumber */ trackOrSessionNumber, 491 /* actualByteCount */ actualByteCount ); 492} 493 494IOReturn IOCDMedia::readDiscInfo(IOMemoryDescriptor * buffer, 495 UInt16 * actualByteCount) 496{ 497 if (isInactive()) 498 { 499 if (actualByteCount) *actualByteCount = 0; 500 501 return kIOReturnNoMedia; 502 } 503 504 if (buffer == 0) 505 { 506 if (actualByteCount) *actualByteCount = 0; 507 508 return kIOReturnBadArgument; 509 } 510 511 return getProvider()->readDiscInfo( 512 /* buffer */ buffer, 513 /* actualByteCount */ actualByteCount ); 514} 515 516IOReturn IOCDMedia::readTrackInfo(IOMemoryDescriptor * buffer, 517 UInt32 address, 518 CDTrackInfoAddressType addressType, 519 UInt16 * actualByteCount) 520{ 521 if (isInactive()) 522 { 523 if (actualByteCount) *actualByteCount = 0; 524 525 return kIOReturnNoMedia; 526 } 527 528 if (buffer == 0) 529 { 530 if (actualByteCount) *actualByteCount = 0; 531 532 return kIOReturnBadArgument; 533 } 534 535 return getProvider()->readTrackInfo( 536 /* buffer */ buffer, 537 /* address */ address, 538 /* addressType */ addressType, 539 /* actualByteCount */ actualByteCount ); 540} 541 542void IOCDMedia::writeCD(IOService * client, 543 UInt64 byteStart, 544 IOMemoryDescriptor * buffer, 545 CDSectorArea sectorArea, 546 CDSectorType sectorType, 547#ifdef __LP64__ 548 IOStorageAttributes * attributes, 549 IOStorageCompletion * completion) 550#else /* !__LP64__ */ 551 IOStorageCompletion completion) 552#endif /* !__LP64__ */ 553{ 554 // 555 // Write data into the CD media object at the specified byte offset from the 556 // specified buffer, asynchronously. When the write completes, the caller 557 // will be notified via the specified completion action. 558 // 559 // The buffer will be retained for the duration of the write. 560 // 561 // This method will work even when the media is in the terminated state. 562 // 563 564 if (isInactive()) 565 { 566 complete(completion, kIOReturnNoMedia); 567 return; 568 } 569 570 if (_openLevel == kIOStorageAccessNone) // (instantaneous value, no lock) 571 { 572 complete(completion, kIOReturnNotOpen); 573 return; 574 } 575 576 if (_openLevel == kIOStorageAccessReader) // (instantaneous value, no lock) 577 { 578 complete(completion, kIOReturnNotPrivileged); 579 return; 580 } 581 582 if (_isWritable == 0) 583 { 584 complete(completion, kIOReturnLockedWrite); 585 return; 586 } 587 588 if (_mediaSize == 0 || _preferredBlockSize == 0) 589 { 590 complete(completion, kIOReturnUnformattedMedia); 591 return; 592 } 593 594 if (buffer == 0) 595 { 596 complete(completion, kIOReturnBadArgument); 597 return; 598 } 599 600 byteStart += _mediaBase; 601 getProvider()->writeCD( /* client */ this, 602 /* byteStart */ byteStart, 603 /* buffer */ buffer, 604 /* sectorArea */ sectorArea, 605 /* sectorType */ sectorType, 606#ifdef __LP64__ 607 /* attributes */ attributes, 608#endif /* __LP64__ */ 609 /* completion */ completion ); 610} 611 612IOReturn IOCDMedia::writeCD(IOService * client, 613 UInt64 byteStart, 614 IOMemoryDescriptor * buffer, 615 CDSectorArea sectorArea, 616 CDSectorType sectorType, 617#ifdef __LP64__ 618 IOStorageAttributes * attributes, 619#endif /* __LP64__ */ 620 UInt64 * actualByteCount) 621{ 622 // 623 // Write data into the CD media object at the specified byte offset from the 624 // specified buffer, synchronously. When the write completes, this method 625 // will return to the caller. The actual byte count field is optional. 626 // 627 // This method will work even when the media is in the terminated state. 628 // 629 630 IOStorageCompletion completion; 631 IOStorageSyncer syncer; 632 633 // Fill in the completion information for this request. 634 635 completion.target = &syncer; 636 completion.action = storageCompletion; 637 completion.parameter = actualByteCount; 638 639 // Issue the asynchronous write. 640 641#ifdef __LP64__ 642 writeCD(client, byteStart, buffer, sectorArea, sectorType, attributes, &completion); 643#else /* !__LP64__ */ 644 writeCD(client, byteStart, buffer, sectorArea, sectorType, completion); 645#endif /* !__LP64__ */ 646 647 // Wait for the write to complete. 648 649 return syncer.wait(); 650} 651 652#ifdef __LP64__ 653OSMetaClassDefineReservedUnused(IOCDMedia, 0); 654OSMetaClassDefineReservedUnused(IOCDMedia, 1); 655OSMetaClassDefineReservedUnused(IOCDMedia, 2); 656OSMetaClassDefineReservedUnused(IOCDMedia, 3); 657OSMetaClassDefineReservedUnused(IOCDMedia, 4); 658OSMetaClassDefineReservedUnused(IOCDMedia, 5); 659OSMetaClassDefineReservedUnused(IOCDMedia, 6); 660#else /* !__LP64__ */ 661OSMetaClassDefineReservedUsed(IOCDMedia, 0); 662OSMetaClassDefineReservedUsed(IOCDMedia, 1); 663OSMetaClassDefineReservedUsed(IOCDMedia, 2); 664OSMetaClassDefineReservedUsed(IOCDMedia, 3); 665OSMetaClassDefineReservedUsed(IOCDMedia, 4); 666OSMetaClassDefineReservedUsed(IOCDMedia, 5); 667OSMetaClassDefineReservedUsed(IOCDMedia, 6); 668#endif /* !__LP64__ */ 669OSMetaClassDefineReservedUnused(IOCDMedia, 7); 670OSMetaClassDefineReservedUnused(IOCDMedia, 8); 671OSMetaClassDefineReservedUnused(IOCDMedia, 9); 672OSMetaClassDefineReservedUnused(IOCDMedia, 10); 673OSMetaClassDefineReservedUnused(IOCDMedia, 11); 674OSMetaClassDefineReservedUnused(IOCDMedia, 12); 675OSMetaClassDefineReservedUnused(IOCDMedia, 13); 676OSMetaClassDefineReservedUnused(IOCDMedia, 14); 677OSMetaClassDefineReservedUnused(IOCDMedia, 15); 678