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/assert.h> 25#include <IOKit/IOBufferMemoryDescriptor.h> 26#include <IOKit/IOLib.h> 27#include <IOKit/storage/IOCDPartitionScheme.h> 28 29#define super IOPartitionScheme 30OSDefineMetaClassAndStructors(IOCDPartitionScheme, IOPartitionScheme); 31 32#define kIOCDPartitionSchemeContentTable "Content Table" 33 34IOCDMedia * IOCDPartitionScheme::getProvider() const 35{ 36 // 37 // Obtain this object's provider. We override the superclass's method 38 // to return a more specific subclass of OSObject -- IOCDMedia. This 39 // method serves simply as a convenience to subclass developers. 40 // 41 42 return (IOCDMedia *) IOService::getProvider(); 43} 44 45bool IOCDPartitionScheme::init(OSDictionary * properties) 46{ 47 // 48 // Initialize this object's minimal state. 49 // 50 51 // State our assumptions. 52 53 assert(sizeof(CDTOC) == 4); // (compiler/platform check) 54 assert(sizeof(CDTOCDescriptor) == 11); // (compiler/platform check) 55 56 // Ask our superclass' opinion. 57 58 if (super::init(properties) == false) return false; 59 60 // Initialize our state. 61 62 _partitions = 0; 63 64 return true; 65} 66 67void IOCDPartitionScheme::free() 68{ 69 // 70 // Free all of this object's outstanding resources. 71 // 72 73 if ( _partitions ) _partitions->release(); 74 75 super::free(); 76} 77 78IOService * IOCDPartitionScheme::probe(IOService * provider, SInt32 * score) 79{ 80 // 81 // Determine whether the provider media contains CD partitions. 82 // 83 84 // State our assumptions. 85 86 assert(OSDynamicCast(IOCDMedia, provider)); 87 88 // Ask superclass' opinion. 89 90 if (super::probe(provider, score) == 0) return 0; 91 92 // Scan the provider media for CD partitions. 93 94 _partitions = scan(score); 95 96 return ( _partitions ) ? this : 0; 97} 98 99bool IOCDPartitionScheme::start(IOService * provider) 100{ 101 // 102 // Publish the new media objects which represent our partitions. 103 // 104 105 IOMedia * partition; 106 OSIterator * partitionIterator; 107 108 // State our assumptions. 109 110 assert(_partitions); 111 112 // Ask our superclass' opinion. 113 114 if ( super::start(provider) == false ) return false; 115 116 // Attach and register the new media objects representing our partitions. 117 118 partitionIterator = OSCollectionIterator::withCollection(_partitions); 119 if ( partitionIterator == 0 ) return false; 120 121 while ( (partition = (IOMedia *) partitionIterator->getNextObject()) ) 122 { 123 if ( partition->attach(this) ) 124 { 125 partition->registerService(); 126 } 127 } 128 129 partitionIterator->release(); 130 131 return true; 132} 133 134OSSet * IOCDPartitionScheme::scan(SInt32 * score) 135{ 136 // 137 // Scan the provider media for CD partitions (in TOC). Returns the set 138 // of media objects representing each of the partitions (the retain for 139 // the set is passed to the caller), or null should no CD partitions be 140 // found. The default probe score can be adjusted up or down, based on 141 // the confidence of the scan. 142 // 143 144 struct CDSession 145 { 146 UInt32 formed:1; 147 UInt32 leadOut; 148 }; 149 150 struct CDTrack 151 { 152 UInt32 block; 153 CDSectorSize blockSize; 154 CDSectorType blockType; 155 CDTOCDescriptor * descriptor; 156 UInt32 session:8; 157 }; 158 159 #define kCDSessionMaxIndex 0x63 160 161 #define kCDTrackMinIndex 0x01 162 #define kCDTrackMaxIndex 0x63 163 164 IOBufferMemoryDescriptor * buffer = 0; 165 IOCDMedia * media = getProvider(); 166 UInt64 mediaBlockSize = media->getPreferredBlockSize(); 167 bool mediaIsOpen = false; 168 OSSet * partitions = 0; 169 CDSession * sessions = 0; 170 UInt32 sessionMinIndex = kCDSessionMaxIndex + 1; 171 UInt32 sessionMaxIndex = 0; 172 CDTOC * toc = 0; 173 UInt32 tocCount = 0; 174 CDTrack * tracks = 0; 175 UInt32 trackMinIndex = kCDTrackMaxIndex + 1; 176 UInt32 trackMaxIndex = 0; 177 CDTrack * trackMaxLinked = 0; 178 179 // State our assumptions. 180 181 assert(mediaBlockSize == kCDSectorSizeWhole); 182 183 // Determine whether this media is formatted. 184 185 if ( media->isFormatted() == false ) goto scanErr; 186 187 // Allocate a buffer large enough to hold a whole 2352-byte sector. 188 189 buffer = IOBufferMemoryDescriptor::withCapacity( 190 /* capacity */ mediaBlockSize, 191 /* withDirection */ kIODirectionIn ); 192 if ( buffer == 0 ) goto scanErr; 193 194 // Allocate a set to hold the set of media objects representing partitions. 195 196 partitions = OSSet::withCapacity(2); 197 if ( partitions == 0 ) goto scanErr; 198 199 // Open the media with read access. 200 201 mediaIsOpen = media->open(this, 0, kIOStorageAccessReader); 202 if ( mediaIsOpen == false ) goto scanErr; 203 204 // Obtain the table of contents. 205 206 toc = media->getTOC(); 207 if ( toc ) tocCount = CDTOCGetDescriptorCount(toc); 208 209 // Allocate a list large enough to hold information about each session. 210 211 sessions = IONew(CDSession, kCDSessionMaxIndex + 1); 212 if ( sessions == 0 ) goto scanErr; 213 214 bzero(sessions, (kCDSessionMaxIndex + 1) * sizeof(CDSession)); 215 216 // Allocate a list large enough to hold information about each track. 217 218 tracks = IONew(CDTrack, kCDTrackMaxIndex + 1); 219 if ( tracks == 0 ) goto scanErr; 220 221 bzero(tracks, (kCDTrackMaxIndex + 1) * sizeof(CDTrack)); 222 223 // Scan the table of contents, gathering information about the sessions 224 // and tracks on the CD, but without making assumptions about the order 225 // of the entries in the table. 226 227 for ( unsigned index = 0; index < tocCount; index++ ) 228 { 229 CDTOCDescriptor * descriptor = toc->descriptors + index; 230 231 // Determine whether this is an audio or data track descriptor. 232 233 if ( descriptor->point >= kCDTrackMinIndex && 234 descriptor->point <= kCDTrackMaxIndex && 235 descriptor->adr == 0x01 && 236 descriptor->session <= kCDSessionMaxIndex ) 237 { 238 CDTrack * track = tracks + descriptor->point; 239 240 // Record the relevant information about this track. 241 242 track->block = CDConvertMSFToClippedLBA(descriptor->p); 243 track->descriptor = descriptor; 244 track->session = descriptor->session; 245 246 if ( (descriptor->control & 0x04) ) // (data track?) 247 { 248 track->blockSize = kCDSectorSizeMode1; 249 track->blockType = kCDSectorTypeMode1; 250 } 251 else // (audio track?) 252 { 253 track->blockSize = kCDSectorSizeCDDA; 254 track->blockType = kCDSectorTypeCDDA; 255 } 256 257 trackMinIndex = min(descriptor->point, trackMinIndex); 258 trackMaxIndex = max(descriptor->point, trackMaxIndex); 259 } 260 261 // Determine whether this is a lead-in (A0) descriptor. 262 263 else if ( descriptor->point == 0xA0 && 264 descriptor->adr == 0x01 && 265 descriptor->session <= kCDSessionMaxIndex ) 266 { 267 CDSession * session = sessions + descriptor->session; 268 269 // Record whether the session has "form 1" or "form 2" tracks. 270 271 session->formed = ( descriptor->p.second ) ? true : false; 272 } 273 274 // Determine whether this is a lead-out (A2) descriptor. 275 276 else if ( descriptor->point == 0xA2 && 277 descriptor->adr == 0x01 && 278 descriptor->session <= kCDSessionMaxIndex ) 279 { 280 CDSession * session = sessions + descriptor->session; 281 282 // Record the position of the session lead-out. 283 284 session->leadOut = CDConvertMSFToClippedLBA(descriptor->p); 285 286 sessionMinIndex = min(descriptor->session, sessionMinIndex); 287 sessionMaxIndex = max(descriptor->session, sessionMaxIndex); 288 } 289 } 290 291 // Pre-scan the ordered list of tracks. 292 293 for ( unsigned index = trackMinIndex; index <= trackMaxIndex; index++ ) 294 { 295 CDTrack * track = tracks + index; 296 297 // Validate the existence of this track (and its session). 298 299 if ( track->descriptor == 0 || sessions[track->session].leadOut == 0 ) 300 { 301 goto scanErr; 302 } 303 304 // Determine the block type, and linkage requirement, for this track. 305 306 if ( track->blockType == kCDSectorTypeMode1 ) // (data track?) 307 { 308 IOReturn status; 309 310 // Read a whole sector from the data track into our buffer. 311 312 status = media->read( /* client */ this, 313 /* byteStart */ track->block * mediaBlockSize, 314 /* buffer */ buffer ); 315 316 if ( status == kIOReturnSuccess ) 317 { 318 UInt8 * sector = (UInt8 *) buffer->getBytesNoCopy(); 319 320 // Determine whether this is a "mode 2" data track. 321 322 if ( sector[15] == 0x02 ) 323 { 324 // Determine whether this is a "mode 2 formless", 325 // "mode 2 form 1" or "mode 2 form 2" data track. 326 327 if ( sessions[track->session ].formed || 328 sessions[sessionMinIndex].formed ) 329 { 330 if ( (sector[18] & 0x20) ) 331 { 332 track->blockSize = kCDSectorSizeMode2Form2; 333 track->blockType = kCDSectorTypeMode2Form2; 334 335 trackMaxLinked = track; 336 } 337 else 338 { 339 track->blockSize = kCDSectorSizeMode2Form1; 340 track->blockType = kCDSectorTypeMode2Form1; 341 342 // Determine whether this is a linked data track. 343 344 if ( memcmp(sector + 24, "ER", 2) ) 345 { 346 trackMaxLinked = track; 347 } 348 } 349 } 350 else 351 { 352 track->blockSize = kCDSectorSizeMode2; 353 track->blockType = kCDSectorTypeMode2; 354 355 trackMaxLinked = track; 356 } 357 } 358 359 // Determine whether this is a linked "mode 1" data track. 360 361 else if ( memcmp(sector + 16, "ER", 2) ) 362 { 363 trackMaxLinked = track; 364 } 365 } 366 else 367 { 368 trackMaxLinked = track; 369 } 370 } 371 } 372 373 // Create a media object to represent the linked data tracks, the hidden 374 // pre-gap-area data track, or even both, if it is applicable to this CD. 375 376 if ( trackMinIndex > kCDTrackMaxIndex || // (no tracks?) 377 trackMaxLinked || // (linked tracks?) 378 tracks[trackMinIndex].block ) // (hidden tracks?) 379 { 380 CDTOCDescriptor descriptor; 381 UInt32 trackBlockNext; 382 CDSectorSize trackBlockSize; 383 CDSectorType trackBlockType; 384 UInt64 trackSize; 385 386 descriptor.session = 0x01; 387 descriptor.control = 0x04; 388 descriptor.adr = 0x01; 389 descriptor.tno = 0x00; 390 descriptor.point = 0x00; 391 descriptor.address.minute = 0x00; 392 descriptor.address.second = 0x00; 393 descriptor.address.frame = 0x00; 394 descriptor.zero = 0x00; 395 descriptor.p = CDConvertLBAToMSF(0); 396 397 if ( trackMinIndex > kCDTrackMaxIndex ) // (no tracks?) 398 { 399 if ( sessionMinIndex > kCDSessionMaxIndex ) // (no sessions?) 400 { 401 if ( media->isWritable() == false ) goto scanErr; 402 } 403 else 404 { 405 descriptor.session = sessionMaxIndex; 406 } 407 408 if ( media->isWritable() ) // (is still writable?) 409 { 410 CDPMA * pma = (CDPMA *) buffer->getBytesNoCopy(); 411 UInt32 pmaCount = 0; 412 UInt16 pmaSize = 0; 413 414 trackBlockNext = media->getSize() / mediaBlockSize; 415 trackBlockSize = kCDSectorSizeMode2Form1; 416 trackBlockType = kCDSectorTypeMode2Form1; 417 418 // Determine whether this is a "mode 1" data track. 419 420 media->readTOC( /* buffer */ buffer, 421 /* format */ kCDTOCFormatPMA, 422 /* formatAsTime */ true, 423 /* trackOrSessionNumber */ 0, 424 /* actualByteCount */ &pmaSize ); 425 426 pmaSize = ( pmaSize <= sizeof(CDPMA) ) 427 ? pmaSize 428 : min( pmaSize, 429 OSSwapBigToHostInt16(pma->dataLength) + 430 sizeof(pma->dataLength) ); 431 pmaCount = ( pmaSize <= sizeof(CDPMA) ) 432 ? 0 433 : ( pmaSize - sizeof(CDPMA) ) / 434 sizeof(CDPMADescriptor); 435 436 for ( unsigned index = 0; index < pmaCount; index++ ) 437 { 438 if ( pma->descriptors[index].adr == 0x2 ) 439 { 440 if ( pma->descriptors[index].p.second == 0x00 ) 441 { 442 trackBlockSize = kCDSectorSizeMode1; 443 trackBlockType = kCDSectorTypeMode1; 444 break; 445 } 446 } 447 } 448 } 449 else 450 { 451 trackBlockNext = sessions[sessionMaxIndex].leadOut; 452 trackBlockSize = kCDSectorSizeMode2Form1; 453 trackBlockType = kCDSectorTypeMode2Form1; 454 } 455 } 456 else if ( trackMaxLinked ) // (linked tracks?) 457 { 458 descriptor.session = sessionMaxIndex; 459 descriptor.control = trackMaxLinked->descriptor->control; 460 461 if ( media->isWritable() ) // (is still writable?) 462 { 463 trackBlockNext = media->getSize() / mediaBlockSize; 464 } 465 else 466 { 467 trackBlockNext = sessions[sessionMaxIndex].leadOut; 468 } 469 470 if ( trackMaxLinked->blockType == kCDSectorTypeMode1 ) 471 { 472 trackBlockSize = kCDSectorSizeMode1; 473 trackBlockType = kCDSectorTypeMode1; 474 } 475 else 476 { 477 trackBlockSize = kCDSectorSizeMode2Form1; 478 trackBlockType = kCDSectorTypeMode2Form1; 479 } 480 } 481 else // (hidden tracks?) 482 { 483 IOReturn status; 484 485 descriptor.session = sessionMinIndex; 486 487 trackBlockNext = tracks[trackMinIndex].block; 488 trackBlockSize = kCDSectorSizeMode1; 489 trackBlockType = kCDSectorTypeMode1; 490 491 // Read a whole sector from the hidden track into our buffer. 492 493 status = media->read( /* client */ this, 494 /* byteStart */ 0, 495 /* buffer */ buffer ); 496 497 if ( status == kIOReturnSuccess ) 498 { 499 UInt8 * sector = (UInt8 *) buffer->getBytesNoCopy(); 500 501 // Determine whether this is an audio track. 502 503 if ( sector[ 0] != 0x00 || 504 sector[ 1] != 0xFF || 505 sector[ 2] != 0xFF || 506 sector[ 3] != 0xFF || 507 sector[ 4] != 0xFF || 508 sector[ 5] != 0xFF || 509 sector[ 6] != 0xFF || 510 sector[ 7] != 0xFF || 511 sector[ 8] != 0xFF || 512 sector[ 9] != 0xFF || 513 sector[10] != 0xFF || 514 sector[11] != 0x00 ) 515 { 516 trackBlockSize = kCDSectorSizeCDDA; 517 trackBlockType = kCDSectorTypeCDDA; 518 } 519 } 520 } 521 522 trackSize = trackBlockNext * trackBlockSize; 523 524 // Create a media object to represent this partition. 525 526 IOMedia * newMedia = instantiateMediaObject( 527 /* partition */ &descriptor, 528 /* partitionSize */ trackSize, 529 /* partitionBlockSize */ trackBlockSize, 530 /* partitionBlockType */ trackBlockType, 531 /* toc */ toc ); 532 533 if ( newMedia ) 534 { 535 partitions->setObject(newMedia); 536 newMedia->release(); 537 } 538 } 539 540 // Scan the ordered list of tracks. 541 542 for ( unsigned index = trackMinIndex; index <= trackMaxIndex; index++ ) 543 { 544 CDTrack * track = tracks + index; 545 UInt32 trackBlockNext; 546 UInt64 trackSize; 547 548 // Determine whether this is an audio track or an unlinked data track. 549 550 if ( ( ( track->blockType != kCDSectorTypeCDDA ) ) && 551 ( ( track->blockType != kCDSectorTypeMode1 && 552 track->blockType != kCDSectorTypeMode2Form1 ) || 553 ( trackMaxLinked ) ) ) 554 { 555 continue; 556 } 557 558 // Determine where the partitions ends. 559 560 if ( index < trackMaxIndex && track->session == (track + 1)->session ) 561 { 562 trackBlockNext = (track + 1)->block; 563 } 564 else 565 { 566 trackBlockNext = sessions[track->session].leadOut; 567 } 568 569 if ( track->block >= trackBlockNext ) 570 { 571 goto scanErr; 572 } 573 574 trackSize = (trackBlockNext - track->block) * track->blockSize; 575 576 // Determine whether the partition is corrupt (fatal). 577 578 if ( isPartitionCorrupt( /* partition */ track->descriptor, 579 /* partitionSize */ trackSize, 580 /* partitionBlockSize */ track->blockSize, 581 /* partitionBlockType */ track->blockType, 582 /* toc */ toc ) ) 583 { 584 goto scanErr; 585 } 586 587 // Determine whether the partition is invalid (skipped). 588 589 if ( isPartitionInvalid( /* partition */ track->descriptor, 590 /* partitionSize */ trackSize, 591 /* partitionBlockSize */ track->blockSize, 592 /* partitionBlockType */ track->blockType, 593 /* toc */ toc ) ) 594 { 595 continue; 596 } 597 598 // Create a media object to represent this partition. 599 600 IOMedia * newMedia = instantiateMediaObject( 601 /* partition */ track->descriptor, 602 /* partitionSize */ trackSize, 603 /* partitionBlockSize */ track->blockSize, 604 /* partitionBlockType */ track->blockType, 605 /* toc */ toc ); 606 607 if ( newMedia ) 608 { 609 partitions->setObject(newMedia); 610 newMedia->release(); 611 } 612 } 613 614 // Release our resources. 615 616 media->close(this); 617 buffer->release(); 618 IODelete(tracks, CDTrack, kCDTrackMaxIndex + 1); 619 IODelete(sessions, CDSession, kCDSessionMaxIndex + 1); 620 621 return partitions; 622 623scanErr: 624 625 // Release our resources. 626 627 if ( mediaIsOpen ) media->close(this); 628 if ( partitions ) partitions->release(); 629 if ( buffer ) buffer->release(); 630 if ( tracks ) IODelete(tracks, CDTrack, kCDTrackMaxIndex + 1); 631 if ( sessions ) IODelete(sessions, CDSession, kCDSessionMaxIndex + 1); 632 633 return 0; 634} 635 636bool IOCDPartitionScheme::isPartitionCorrupt( 637 CDTOCDescriptor * /* partition */ , 638 UInt64 /* partitionSize */ , 639 UInt32 /* partitionBlockSize */ , 640 CDSectorType /* partitionBlockType */ , 641 CDTOC * /* toc */ ) 642{ 643 // 644 // Ask whether the given partition appears to be corrupt. A partition that 645 // is corrupt will cause the failure of the CD partition scheme altogether. 646 // 647 648 return false; 649} 650 651bool IOCDPartitionScheme::isPartitionInvalid( 652 CDTOCDescriptor * partition, 653 UInt64 partitionSize, 654 UInt32 partitionBlockSize, 655 CDSectorType partitionBlockType, 656 CDTOC * toc ) 657{ 658 // 659 // Ask whether the given partition appears to be invalid. A partition that 660 // is invalid will cause it to be skipped in the scan, but will not cause a 661 // failure of the CD partition scheme. 662 // 663 664 IOMedia * media = getProvider(); 665 UInt64 mediaBlockSize = media->getPreferredBlockSize(); 666 UInt64 partitionBase = 0; 667 668 // Compute the relative byte position and size of the new partition, 669 // relative to the provider media's natural blocking factor of 2352. 670 671 partitionBase = CDConvertMSFToClippedLBA(partition->p) * mediaBlockSize; 672 partitionSize = (partitionSize / partitionBlockSize) * mediaBlockSize; 673 674 // Determine whether the partition leaves the confines of the container. 675 676 if ( partitionBase + partitionSize > media->getSize() ) return true; 677 678 return false; 679} 680 681IOMedia * IOCDPartitionScheme::instantiateMediaObject( 682 CDTOCDescriptor * partition, 683 UInt64 partitionSize, 684 UInt32 partitionBlockSize, 685 CDSectorType partitionBlockType, 686 CDTOC * toc ) 687{ 688 // 689 // Instantiate a new media object to represent the given partition. 690 // 691 692 IOMedia * media = getProvider(); 693 UInt64 partitionBase = 0; 694 char * partitionHint = 0; 695 bool partitionIsWritable = media->isWritable(); 696 697 // Compute the relative byte position of the new partition and encode it 698 // into the designated "logical space", given the partition's block type. 699 // 700 // 0x0000000000 through 0x00FFFFFFFF is the "don't care" space. 701 // 0x0100000000 through 0x01FFFFFFFF is the "audio" space. 702 // 0x0200000000 through 0x02FFFFFFFF is the "mode 1" space. 703 // 0x0300000000 through 0x03FFFFFFFF is the "mode 2 formless" space. 704 // 0x0400000000 through 0x04FFFFFFFF is the "mode 2 form 1" space. 705 // 0x0500000000 through 0x05FFFFFFFF is the "mode 2 form 2" space. 706 707 partitionBase = CDConvertMSFToClippedLBA(partition->p); 708 partitionBase *= partitionBlockSize; 709 partitionBase += ((UInt64) partitionBlockType) << 32; 710 711 // Look up a type for the new partition. 712 713 OSDictionary * hintTable = OSDynamicCast( 714 /* type */ OSDictionary, 715 /* instance */ getProperty(kIOCDPartitionSchemeContentTable) ); 716 717 if ( hintTable ) 718 { 719 char hintIndex[5]; 720 OSString * hintValue; 721 722 snprintf(hintIndex, sizeof(hintIndex), "0x%02X", partitionBlockType & 0xFF); 723 724 hintValue = OSDynamicCast(OSString, hintTable->getObject(hintIndex)); 725 726 if ( hintValue ) partitionHint = (char *) hintValue->getCStringNoCopy(); 727 } 728 729 // Determine whether the new partition is read-only. 730 731 if ( partition->point ) partitionIsWritable = false; 732 733 // Create the new media object. 734 735 IOMedia * newMedia = instantiateDesiredMediaObject( 736 /* partition */ partition, 737 /* partitionSize */ partitionSize, 738 /* partitionBlockSize */ partitionBlockSize, 739 /* partitionBlockType */ partitionBlockType, 740 /* toc */ toc ); 741 742 if ( newMedia ) 743 { 744 if ( newMedia->init( 745 /* base */ partitionBase, 746 /* size */ partitionSize, 747 /* preferredBlockSize */ partitionBlockSize, 748 /* attributes */ media->getAttributes(), 749 /* isWhole */ false, 750 /* isWritable */ partitionIsWritable, 751 /* contentHint */ partitionHint ) ) 752 { 753 // Set a name for this partition. 754 755 char name[24]; 756 snprintf(name, sizeof(name), "Untitled %d", partition->point); 757 newMedia->setName(name); 758 759 // Set a location value (the partition number) for this partition. 760 761 char location[12]; 762 snprintf(location, sizeof(location), "%d", partition->point); 763 newMedia->setLocation(location); 764 765 // Set the "Partition ID" key for this partition. 766 767 newMedia->setProperty(kIOMediaPartitionIDKey, partition->point, 32); 768 769 // Set the "Session ID" key for this partition. 770 771 newMedia->setProperty(kIOMediaSessionIDKey, partition->session, 32); 772 } 773 else 774 { 775 newMedia->release(); 776 newMedia = 0; 777 } 778 } 779 780 return newMedia; 781} 782 783IOMedia * IOCDPartitionScheme::instantiateDesiredMediaObject( 784 CDTOCDescriptor * /* partition */ , 785 UInt64 /* partitionSize */ , 786 UInt32 /* partitionBlockSize */ , 787 CDSectorType /* partitionBlockType */ , 788 CDTOC * /* toc */ ) 789{ 790 // 791 // Allocate a new media object (called from instantiateMediaObject). 792 // 793 794 return new IOMedia; 795} 796 797void IOCDPartitionScheme::read( IOService * client, 798 UInt64 byteStart, 799 IOMemoryDescriptor * buffer, 800 IOStorageAttributes * attributes, 801 IOStorageCompletion * completion ) 802{ 803 // 804 // Read data from the storage object at the specified byte offset into the 805 // specified buffer, asynchronously. When the read completes, the caller 806 // will be notified via the specified completion action. 807 // 808 // The buffer will be retained for the duration of the read. 809 // 810 // For the CD partition scheme, we convert the read from a partition 811 // object into the appropriate readCD command to our provider media. 812 // 813 814 getProvider()->readCD( /* client */ this, 815 /* byteStart */ (byteStart & 0xFFFFFFFF), 816 /* buffer */ buffer, 817 /* sectorArea */ (CDSectorArea) kCDSectorAreaUser, 818 /* sectorType */ (CDSectorType) (byteStart >> 32), 819#ifdef __LP64__ 820 /* attributes */ attributes, 821 /* completion */ completion ); 822#else /* !__LP64__ */ 823 /* completion */ completion ? *completion : (IOStorageCompletion) { 0 } ); 824#endif /* !__LP64__ */ 825} 826 827void IOCDPartitionScheme::write( IOService * client, 828 UInt64 byteStart, 829 IOMemoryDescriptor * buffer, 830 IOStorageAttributes * attributes, 831 IOStorageCompletion * completion ) 832{ 833 // 834 // Write data into the storage object at the specified byte offset from the 835 // specified buffer, asynchronously. When the write completes, the caller 836 // will be notified via the specified completion action. 837 // 838 // The buffer will be retained for the duration of the write. 839 // 840 // For the CD partition scheme, we convert the write from a partition 841 // object into the appropriate writeCD command to our provider media. 842 // 843 844 getProvider()->writeCD( /* client */ this, 845 /* byteStart */ (byteStart & 0xFFFFFFFF), 846 /* buffer */ buffer, 847 /* sectorArea */ (CDSectorArea) kCDSectorAreaUser, 848 /* sectorType */ (CDSectorType) (byteStart >> 32), 849#ifdef __LP64__ 850 /* attributes */ attributes, 851 /* completion */ completion ); 852#else /* !__LP64__ */ 853 /* completion */ completion ? *completion : (IOStorageCompletion) { 0 } ); 854#endif /* !__LP64__ */ 855} 856 857OSMetaClassDefineReservedUnused(IOCDPartitionScheme, 0); 858OSMetaClassDefineReservedUnused(IOCDPartitionScheme, 1); 859OSMetaClassDefineReservedUnused(IOCDPartitionScheme, 2); 860OSMetaClassDefineReservedUnused(IOCDPartitionScheme, 3); 861OSMetaClassDefineReservedUnused(IOCDPartitionScheme, 4); 862OSMetaClassDefineReservedUnused(IOCDPartitionScheme, 5); 863OSMetaClassDefineReservedUnused(IOCDPartitionScheme, 6); 864OSMetaClassDefineReservedUnused(IOCDPartitionScheme, 7); 865OSMetaClassDefineReservedUnused(IOCDPartitionScheme, 8); 866OSMetaClassDefineReservedUnused(IOCDPartitionScheme, 9); 867OSMetaClassDefineReservedUnused(IOCDPartitionScheme, 10); 868OSMetaClassDefineReservedUnused(IOCDPartitionScheme, 11); 869OSMetaClassDefineReservedUnused(IOCDPartitionScheme, 12); 870OSMetaClassDefineReservedUnused(IOCDPartitionScheme, 13); 871OSMetaClassDefineReservedUnused(IOCDPartitionScheme, 14); 872OSMetaClassDefineReservedUnused(IOCDPartitionScheme, 15); 873