1/* 2 * Copyright (c) 1998-2014 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/IODeviceTreeSupport.h> // (gIODTPlane, ...) 25#include <IOKit/IOLib.h> // (IONew, ...) 26#include <IOKit/storage/IOMedia.h> 27 28#define super IOStorage 29OSDefineMetaClassAndStructors(IOMedia, IOStorage) 30 31#ifndef __LP64__ 32extern IOStorageAttributes gIOStorageAttributesUnsupported; 33#endif /* !__LP64__ */ 34 35enum 36{ 37 kIOStorageAccessWriter = 0x00000002, 38 kIOStorageAccessInvalid = 0x0000000D, 39 kIOStorageAccessReserved = 0xFFFFFFF0 40}; 41 42static UInt8 gIOMediaAccessTable[8][8] = 43{ /* Rea, Wri, R|S, W|S, R|E, W|E, Inv, Non */ 44 /* Rea */ { 000, 001, 002, 003, 006, 006, 006, 000 }, 45 /* Wri */ { 011, 006, 011, 006, 006, 006, 006, 011 }, 46 /* R|S */ { 002, 001, 002, 003, 006, 006, 006, 002 }, 47 /* W|S */ { 003, 006, 003, 003, 006, 006, 006, 003 }, 48 /* R|E */ { 006, 006, 006, 006, 006, 006, 006, 004 }, 49 /* W|E */ { 006, 006, 006, 006, 006, 006, 006, 015 }, 50 /* Inv */ { 006, 006, 006, 006, 006, 006, 006, 006 }, 51 /* Inv */ { 006, 006, 006, 006, 006, 006, 006, 006 } 52}; 53 54class IOMediaAccess 55{ 56protected: 57 58 IOStorageAccess _access; 59 60public: 61 62 inline void operator=( IOStorageAccess access ) 63 { 64 _access = access; 65 } 66 67 inline void operator=( OSObject * access ) 68 { 69 if ( access ) 70 { 71 operator=( ( ( OSNumber * ) access )->unsigned32BitValue( ) ); 72 } 73 else 74 { 75 operator=( kIOStorageAccessNone ); 76 } 77 } 78 79 inline void operator+=( IOStorageAccess access ) 80 { 81 _access = ( ( _access - 1 ) >> 1 ) & 7; 82 _access = gIOMediaAccessTable[ ( ( access - 1 ) >> 1 ) & 7 ][ _access ]; 83 _access = ( ( _access & 7 ) << 1 ) + 1; 84 } 85 86 inline void operator+=( OSObject * access ) 87 { 88 if ( access ) 89 { 90 operator+=( ( ( OSNumber * ) access )->unsigned32BitValue( ) ); 91 } 92 } 93 94 inline operator IOStorageAccess( ) 95 { 96 return _access; 97 } 98}; 99 100IOStorage * IOMedia::getProvider() const 101{ 102 // 103 // Obtain this object's provider. We override the superclass's method to 104 // return a more specific subclass of OSObject -- IOStorage. This method 105 // serves simply as a convenience to subclass developers. 106 // 107 108 return (IOStorage *) IOService::getProvider(); 109} 110 111bool IOMedia::matchPropertyTable(OSDictionary * table, SInt32 * score) 112{ 113 // 114 // Compare the properties in the supplied table to this object's properties. 115 // 116 117 // Ask our superclass' opinion. 118 119 if (super::matchPropertyTable(table, score) == false) return false; 120 121 // We return success if the following expression is true -- individual 122 // comparisions evaluate to truth if the named property is not present 123 // in the supplied table. 124 125 return compareProperty(table, kIOMediaContentKey ) && 126 compareProperty(table, kIOMediaContentHintKey ) && 127 compareProperty(table, kIOMediaEjectableKey ) && 128 compareProperty(table, kIOMediaLeafKey ) && 129 compareProperty(table, kIOMediaOpenKey ) && 130 compareProperty(table, kIOMediaPreferredBlockSizeKey) && 131 compareProperty(table, kIOMediaRemovableKey ) && 132 compareProperty(table, kIOMediaSizeKey ) && 133 compareProperty(table, kIOMediaUUIDKey ) && 134 compareProperty(table, kIOMediaWholeKey ) && 135 compareProperty(table, kIOMediaWritableKey ); 136} 137 138#ifndef __LP64__ 139bool IOMedia::init(UInt64 base, 140 UInt64 size, 141 UInt64 preferredBlockSize, 142 bool isEjectable, 143 bool isWhole, 144 bool isWritable, 145 const char * contentHint, 146 OSDictionary * properties) 147{ 148 // 149 // Initialize this object's minimal state. 150 // 151 152 IOMediaAttributeMask attributes = 0; 153 154 attributes |= isEjectable ? kIOMediaAttributeEjectableMask : 0; 155 attributes |= isEjectable ? kIOMediaAttributeRemovableMask : 0; 156 157 return init( /* base */ base, 158 /* size */ size, 159 /* preferredBlockSize */ preferredBlockSize, 160 /* attributes */ attributes, 161 /* isWhole */ isWhole, 162 /* isWritable */ isWritable, 163 /* contentHint */ contentHint, 164 /* properties */ properties ); 165} 166#endif /* !__LP64__ */ 167 168void IOMedia::free(void) 169{ 170 // 171 // Free all of this object's outstanding resources. 172 // 173 174 if (_openClients) _openClients->release(); 175 176 super::free(); 177} 178 179bool IOMedia::attachToChild(IORegistryEntry * client, 180 const IORegistryPlane * plane) 181{ 182 // 183 // This method is called for each client interested in the services we 184 // provide. The superclass links us as a parent to this client in the 185 // I/O Kit registry on success. 186 // 187 188 OSString * s; 189 190 // Ask our superclass' opinion. 191 192 if (super::attachToChild(client, plane) == false) return false; 193 194 // 195 // Determine whether the client is a storage driver, which we consider 196 // to be a consumer of this storage object's content and a producer of 197 // new content. A storage driver need not be an IOStorage subclass, so 198 // long as it identifies itself with a match category of "IOStorage". 199 // 200 // If the client is indeed a storage driver, we reset the media's Leaf 201 // property to false and replace the media's Content property with the 202 // client's Content Mask property, if any. 203 // 204 205 s = OSDynamicCast(OSString, client->getProperty(gIOMatchCategoryKey)); 206 207 if (s && s->isEqualTo(kIOStorageCategory)) 208 { 209 setProperty(kIOMediaLeafKey, false); 210 211 s = OSDynamicCast(OSString,client->getProperty(kIOMediaContentMaskKey)); 212 if (s) setProperty(kIOMediaContentKey, s->getCStringNoCopy()); 213 } 214 215 return true; 216} 217 218void IOMedia::detachFromChild(IORegistryEntry * client, 219 const IORegistryPlane * plane) 220{ 221 // 222 // This method is called for each client that loses interest in the 223 // services we provide. The superclass unlinks us from this client 224 // in the I/O Kit registry on success. 225 // 226 // Note that this method is called at a nondeterministic time after 227 // our client is terminated, which means another client may already 228 // have arrived and attached in the meantime. This is not an issue 229 // should the termination be issued synchrnously, however, which we 230 // take advantage of when this media needs to eliminate one of its 231 // clients. If the termination was issued on this media or farther 232 // below in the hierarchy, we don't really care that the properties 233 // would not be consistent since this media object is going to die 234 // anyway. 235 // 236 237 OSString * s; 238 239 // 240 // Determine whether the client is a storage driver, which we consider 241 // to be a consumer of this storage object's content and a producer of 242 // new content. A storage driver need not be an IOStorage subclass, so 243 // long as it identifies itself with a match category of "IOStorage". 244 // 245 // If the client is indeed a storage driver, we reset the media's Leaf 246 // property to true and reset the media's Content property to the hint 247 // we obtained when this media was initialized. 248 // 249 250 s = OSDynamicCast(OSString, client->getProperty(gIOMatchCategoryKey)); 251 252 if (s && s->isEqualTo(kIOStorageCategory)) 253 { 254 setProperty(kIOMediaContentKey, getContentHint()); 255 setProperty(kIOMediaLeafKey, true); 256 } 257 258 // Pass the call onto our superclass. 259 260 super::detachFromChild(client, plane); 261} 262 263bool IOMedia::handleOpen(IOService * client, 264 IOOptionBits options, 265 void * argument) 266{ 267 // 268 // The handleOpen method grants or denies permission to access this object 269 // to an interested client. The argument is an IOStorageAccess value that 270 // specifies the level of access desired -- reader or reader-writer. 271 // 272 // This method can be invoked to upgrade or downgrade the access level for 273 // an existing client as well. The previous access level will prevail for 274 // upgrades that fail, of course. A downgrade should never fail. If the 275 // new access level should be the same as the old for a given client, this 276 // method will do nothing and return success. In all cases, one, singular 277 // close-per-client is expected for all opens-per-client received. 278 // 279 // This method will work even when the media is in the terminated state. 280 // 281 // We are guaranteed that no other opens or closes will be processed until 282 // we make our decision, change our state, and return from this method. 283 // 284 285 IOMediaAccess access; 286 IOStorageAccess accessIn; 287 IOService * driver; 288 IOMediaAccess level; 289 OSObject * object; 290 OSIterator * objects; 291 bool rebuild; 292 bool success; 293 bool teardown; 294 295 // 296 // State our assumptions. 297 // 298 299 assert( client ); 300 301 // 302 // Initialize our minimal state. 303 // 304 305 access = _openClients->getObject( ( OSSymbol * ) client ); 306 accessIn = ( uintptr_t ) argument; 307 driver = 0; 308 309 rebuild = false; 310 success = false; 311 teardown = false; 312 313 // 314 // Determine whether one of our clients is a storage driver. 315 // 316 317 object = ( OSObject * ) OSSymbol::withCString( kIOStorageCategory ); 318 319 if ( object == 0 ) 320 { 321 goto handleOpenErr; 322 } 323 324 driver = copyClientWithCategory( ( OSSymbol * ) object ); 325 326 object->release( ); 327 328 // 329 // Reevaluate the open we have on the level below us. 330 // 331 332 objects = OSCollectionIterator::withCollection( _openClients ); 333 334 if ( objects == 0 ) 335 { 336 goto handleOpenErr; 337 } 338 339 level = kIOStorageAccessNone; 340 341 while ( ( object = objects->getNextObject( ) ) ) 342 { 343 if ( object != client ) 344 { 345 level += _openClients->getObject( ( OSSymbol * ) object ); 346 } 347 } 348 349 objects->release( ); 350 351 // 352 // Evaluate the open we have from the level above us. 353 // 354 355 level += accessIn; 356 357 if ( level == kIOStorageAccessInvalid ) 358 { 359 goto handleOpenErr; 360 } 361 362 if ( ( accessIn & kIOStorageAccessWriter ) ) 363 { 364 if ( _isWritable == false ) 365 { 366 goto handleOpenErr; 367 } 368 369 if ( ( accessIn & kIOStorageAccessSharedLock ) == false ) 370 { 371 if ( driver ) 372 { 373 if ( driver != client ) 374 { 375 teardown = true; 376 } 377 } 378 } 379 } 380 else 381 { 382 if ( ( access & kIOStorageAccessWriter ) ) 383 { 384 rebuild = true; 385 } 386 } 387 388 // 389 // If we are in the terminated state, we only accept downgrades. 390 // 391 392 if ( isInactive( ) ) 393 { 394 if ( access == kIOStorageAccessNone ) 395 { 396 goto handleOpenErr; 397 } 398 399 if ( ( accessIn & kIOStorageAccessWriter ) ) 400 { 401 goto handleOpenErr; 402 } 403 } 404 405 // 406 // Determine whether the storage driver above us can be torn down, if 407 // this is a new exclusive writer open, or an upgrade to an exclusive 408 // writer open (and if the client issuing the open is not the storage 409 // driver itself). 410 // 411 412 if ( teardown ) 413 { 414 if ( _openClients->getObject( ( OSSymbol * ) driver ) ) 415 { 416 goto handleOpenErr; 417 } 418 419 if ( driver->terminate( kIOServiceSynchronous ) == false ) 420 { 421 goto handleOpenErr; 422 } 423 } 424 425 // 426 // Determine whether the storage object below us accepts the open at this 427 // multiplexed level of access -- new opens, upgrades and downgrades (and 428 // no changes in access) all enter through the same method. 429 // 430 431 level = ( level & kIOStorageAccessReaderWriter ); 432 433 if ( _openLevel != level ) 434 { 435 IOStorage * provider; 436 437 provider = OSDynamicCast( IOStorage, getProvider( ) ); 438 439 if ( provider ) 440 { 441 success = provider->open( this, options, level ); 442 443 if ( success == false ) 444 { 445 // 446 // We were unable to open the storage object below us. We 447 // must recover from the terminate we invoked above before 448 // bailing out, if applicable, by re-registering the media 449 // object for matching. 450 // 451 452 if ( teardown ) 453 { 454 registerService( kIOServiceAsynchronous ); 455 } 456 457 goto handleOpenErr; 458 } 459 460 setProperty( kIOMediaOpenKey, true ); 461 } 462 } 463 464 success = true; 465 466 // 467 // Process the open. 468 // 469 470 object = OSNumber::withNumber( accessIn, 32 ); 471 472 assert( object ); 473 474 _openClients->setObject( ( OSSymbol * ) client, object ); 475 476 _openLevel = level; 477 478 object->release( ); 479 480 // 481 // If a writer just closed, re-register the media so that I/O Kit will 482 // attempt to match storage drivers that may now be interested in this 483 // media. 484 // 485 486 if ( rebuild ) 487 { 488 if ( isInactive( ) == false ) 489 { 490 if ( driver ) 491 { 492 if ( driver != client ) 493 { 494 driver->requestProbe( 0 ); 495 } 496 } 497 else 498 { 499 registerService( kIOServiceAsynchronous ); 500 } 501 } 502 } 503 504handleOpenErr: 505 506 // 507 // Release our resources. 508 // 509 510 if ( driver ) 511 { 512 driver->release( ); 513 } 514 515 return success; 516} 517 518bool IOMedia::handleIsOpen(const IOService * client) const 519{ 520 // 521 // The handleIsOpen method determines whether the specified client, or any 522 // client if none is specificed, presently has an open on this object. 523 // 524 // This method will work even when the media is in the terminated state. 525 // 526 // We are guaranteed that no other opens or closes will be processed until 527 // we return from this method. 528 // 529 530 if ( client ) 531 { 532 return _openClients->getObject( ( OSSymbol * ) client ) ? true : false; 533 } 534 else 535 { 536 return _openClients->getCount( ) ? true : false; 537 } 538} 539 540void IOMedia::handleClose(IOService * client, IOOptionBits options) 541{ 542 // 543 // A client is informing us that it is giving up access to our contents. 544 // 545 // This method will work even when the media is in the terminated state. 546 // 547 // We are guaranteed that no other opens or closes will be processed until 548 // we change our state and return from this method. 549 // 550 551 IOMediaAccess access; 552 IOService * driver; 553 IOMediaAccess level; 554 OSObject * object; 555 OSIterator * objects; 556 557 // 558 // State our assumptions. 559 // 560 561 assert( client ); 562 563 assert( _openClients->getObject( ( OSSymbol * ) client ) ); 564 565 // 566 // Initialize our minimal state. 567 // 568 569 access = _openClients->getObject( ( OSSymbol * ) client ); 570 driver = 0; 571 572 // 573 // Determine whether one of our clients is a storage driver. 574 // 575 576 object = ( OSObject * ) OSSymbol::withCString( kIOStorageCategory ); 577 578 if ( object == 0 ) 579 { 580 goto handleCloseErr; 581 } 582 583 driver = copyClientWithCategory( ( OSSymbol * ) object ); 584 585 object->release( ); 586 587 // 588 // Reevaluate the open we have on the level below us. 589 // 590 591 objects = OSCollectionIterator::withCollection( _openClients ); 592 593 if ( objects == 0 ) 594 { 595 goto handleCloseErr; 596 } 597 598 level = kIOStorageAccessNone; 599 600 while ( ( object = objects->getNextObject( ) ) ) 601 { 602 if ( object != client ) 603 { 604 level += _openClients->getObject( ( OSSymbol * ) object ); 605 } 606 } 607 608 objects->release( ); 609 610 // 611 // If no opens remain, we close, or if no writers remain, but readers do, 612 // we downgrade. 613 // 614 615 level = ( level & kIOStorageAccessReaderWriter ); 616 617 if ( _openLevel != level ) 618 { 619 IOStorage * provider; 620 621 provider = OSDynamicCast( IOStorage, getProvider( ) ); 622 623 if ( provider ) 624 { 625 if ( level == kIOStorageAccessNone ) 626 { 627 provider->close( this, options ); 628 629 setProperty( kIOMediaOpenKey, false ); 630 } 631 else 632 { 633 bool success; 634 635 success = provider->open( this, 0, level ); 636 637 assert( success ); 638 } 639 } 640 } 641 642 // 643 // Process the close. 644 // 645 646 _openClients->removeObject( ( OSSymbol * ) client ); 647 648 _openLevel = level; 649 650 // 651 // If a writer just closed, re-register the media so that I/O Kit will 652 // attempt to match storage drivers that may now be interested in this 653 // media. 654 // 655 656 if ( ( access & kIOStorageAccessWriter ) ) 657 { 658 if ( isInactive( ) == false ) 659 { 660 if ( driver ) 661 { 662 if ( driver != client ) 663 { 664 driver->requestProbe( 0 ); 665 } 666 } 667 else 668 { 669 registerService( kIOServiceAsynchronous ); 670 } 671 } 672 } 673 674handleCloseErr: 675 676 // 677 // Release our resources. 678 // 679 680 if ( driver ) 681 { 682 driver->release( ); 683 } 684} 685 686void IOMedia::read(IOService * client, 687 UInt64 byteStart, 688 IOMemoryDescriptor * buffer, 689 IOStorageAttributes * attributes, 690 IOStorageCompletion * completion) 691{ 692 // 693 // Read data from the storage object at the specified byte offset into the 694 // specified buffer, asynchronously. When the read completes, the caller 695 // will be notified via the specified completion action. 696 // 697 // The buffer will be retained for the duration of the read. 698 // 699 // This method will work even when the media is in the terminated state. 700 // 701 702#ifndef __LP64__ 703 if (IOStorage::_expansionData) 704 { 705 if (attributes == &gIOStorageAttributesUnsupported) 706 { 707 attributes = NULL; 708 } 709 else 710 { 711 IOStorage::read(client, byteStart, buffer, attributes, completion); 712 return; 713 } 714 } 715#endif /* !__LP64__ */ 716 717 if (isInactive()) 718 { 719 complete(completion, kIOReturnNoMedia); 720 return; 721 } 722 723 if (_openLevel == kIOStorageAccessNone) // (instantaneous value, no lock) 724 { 725 complete(completion, kIOReturnNotOpen); 726 return; 727 } 728 729 if (_mediaSize == 0 || _preferredBlockSize == 0) 730 { 731 complete(completion, kIOReturnUnformattedMedia); 732 return; 733 } 734 735 if (buffer == 0) 736 { 737 complete(completion, kIOReturnBadArgument); 738 return; 739 } 740 741 if (_mediaSize < byteStart + buffer->getLength()) 742 { 743 complete(completion, kIOReturnBadArgument); 744 return; 745 } 746 747 byteStart += _mediaBase; 748 getProvider()->read(this, byteStart, buffer, attributes, completion); 749} 750 751void IOMedia::write(IOService * client, 752 UInt64 byteStart, 753 IOMemoryDescriptor * buffer, 754 IOStorageAttributes * attributes, 755 IOStorageCompletion * completion) 756{ 757 // 758 // Write data into the storage object at the specified byte offset from the 759 // specified buffer, asynchronously. When the write completes, the caller 760 // will be notified via the specified completion action. 761 // 762 // The buffer will be retained for the duration of the write. 763 // 764 // This method will work even when the media is in the terminated state. 765 // 766 767#ifndef __LP64__ 768 if (IOStorage::_expansionData) 769 { 770 if (attributes == &gIOStorageAttributesUnsupported) 771 { 772 attributes = NULL; 773 } 774 else 775 { 776 IOStorage::write(client, byteStart, buffer, attributes, completion); 777 return; 778 } 779 } 780#endif /* !__LP64__ */ 781 782 if (isInactive()) 783 { 784 complete(completion, kIOReturnNoMedia); 785 return; 786 } 787 788 if (_openLevel == kIOStorageAccessNone) // (instantaneous value, no lock) 789 { 790 complete(completion, kIOReturnNotOpen); 791 return; 792 } 793 794 if (_openLevel == kIOStorageAccessReader) // (instantaneous value, no lock) 795 { 796#if !TARGET_OS_EMBEDDED 797#ifdef __LP64__ 798 complete(completion, kIOReturnNotPrivileged); 799 return; 800#endif /* __LP64__ */ 801#endif /* !TARGET_OS_EMBEDDED */ 802 } 803 804 if (_isWritable == 0) 805 { 806 complete(completion, kIOReturnLockedWrite); 807 return; 808 } 809 810 if (_mediaSize == 0 || _preferredBlockSize == 0) 811 { 812 complete(completion, kIOReturnUnformattedMedia); 813 return; 814 } 815 816 if (buffer == 0) 817 { 818 complete(completion, kIOReturnBadArgument); 819 return; 820 } 821 822 if (_mediaSize < byteStart + buffer->getLength()) 823 { 824 complete(completion, kIOReturnBadArgument); 825 return; 826 } 827 828 byteStart += _mediaBase; 829 getProvider()->write(this, byteStart, buffer, attributes, completion); 830} 831 832IOReturn IOMedia::synchronizeCache(IOService * client) 833{ 834 // 835 // Flush the cached data in the storage object, if any, synchronously. 836 // 837 838 if (isInactive()) 839 { 840 return kIOReturnNoMedia; 841 } 842 843 if (_openLevel == kIOStorageAccessNone) // (instantaneous value, no lock) 844 { 845 return kIOReturnNotOpen; 846 } 847 848 if (_openLevel == kIOStorageAccessReader) // (instantaneous value, no lock) 849 { 850#if !TARGET_OS_EMBEDDED 851#ifdef __LP64__ 852 return kIOReturnNotPrivileged; 853#endif /* __LP64__ */ 854#endif /* !TARGET_OS_EMBEDDED */ 855 } 856 857 if (_isWritable == 0) 858 { 859 return kIOReturnLockedWrite; 860 } 861 862 if (_mediaSize == 0 || _preferredBlockSize == 0) 863 { 864 return kIOReturnUnformattedMedia; 865 } 866 867 return getProvider()->synchronizeCache(this); 868} 869 870IOReturn IOMedia::unmap(IOService * client, 871 IOStorageExtent * extents, 872 UInt32 extentsCount, 873 UInt32 options) 874{ 875 // 876 // Delete unused data from the storage object at the specified byte offsets, 877 // synchronously. 878 // 879 880 UInt32 extentsIndex; 881 882 if (isInactive()) 883 { 884 return kIOReturnNoMedia; 885 } 886 887 if (_openLevel == kIOStorageAccessNone) // (instantaneous value, no lock) 888 { 889 return kIOReturnNotOpen; 890 } 891 892 if (_openLevel == kIOStorageAccessReader) // (instantaneous value, no lock) 893 { 894#if !TARGET_OS_EMBEDDED 895#ifdef __LP64__ 896 return kIOReturnNotPrivileged; 897#endif /* __LP64__ */ 898#endif /* !TARGET_OS_EMBEDDED */ 899 } 900 901 if (_isWritable == 0) 902 { 903 return kIOReturnLockedWrite; 904 } 905 906 if (_mediaSize == 0 || _preferredBlockSize == 0) 907 { 908 return kIOReturnUnformattedMedia; 909 } 910 911 for (extentsIndex = 0; extentsIndex < extentsCount; extentsIndex++) 912 { 913 if (_mediaSize < extents[extentsIndex].byteStart + extents[extentsIndex].byteCount) 914 { 915 return kIOReturnBadArgument; 916 } 917 918 extents[extentsIndex].byteStart += _mediaBase; 919 } 920 921 return getProvider()->unmap(this, extents, extentsCount, options); 922} 923 924bool IOMedia::lockPhysicalExtents(IOService * client) 925{ 926 // 927 // Lock the contents of the storage object against relocation temporarily, 928 // for the purpose of getting physical extents. 929 // 930 931 if (isInactive()) 932 { 933 return false; 934 } 935 936 if (_openLevel == kIOStorageAccessNone) // (instantaneous value, no lock) 937 { 938 return false; 939 } 940 941 if (_mediaSize == 0 || _preferredBlockSize == 0) 942 { 943 return false; 944 } 945 946 return getProvider( )->lockPhysicalExtents( this ); 947} 948 949IOStorage * IOMedia::copyPhysicalExtent(IOService * client, 950 UInt64 * byteStart, 951 UInt64 * byteCount) 952{ 953 // 954 // Convert the specified byte offset into a physical byte offset, relative 955 // to a physical storage object. This call should only be made within the 956 // context of lockPhysicalExtents(). 957 // 958 959 if (isInactive()) 960 { 961 return NULL; 962 } 963 964 if (_openLevel == kIOStorageAccessNone) // (instantaneous value, no lock) 965 { 966 return NULL; 967 } 968 969 if (_mediaSize == 0 || _preferredBlockSize == 0) 970 { 971 return NULL; 972 } 973 974 if (_mediaSize < *byteStart + *byteCount) 975 { 976 return NULL; 977 } 978 979 *byteStart += _mediaBase; 980 return getProvider( )->copyPhysicalExtent( this, byteStart, byteCount ); 981} 982 983void IOMedia::unlockPhysicalExtents(IOService * client) 984{ 985 // 986 // Unlock the contents of the storage object for relocation again. This 987 // call must balance a successful call to lockPhysicalExtents(). 988 // 989 990 if (_openLevel == kIOStorageAccessNone) // (instantaneous value, no lock) 991 { 992 return; 993 } 994 995 getProvider( )->unlockPhysicalExtents( this ); 996} 997 998IOReturn IOMedia::setPriority(IOService * client, 999 IOStorageExtent * extents, 1000 UInt32 extentsCount, 1001 IOStoragePriority priority) 1002{ 1003 // 1004 // Reprioritize read or write requests at the specified byte offsets. 1005 // 1006 1007 UInt32 extentsIndex; 1008 1009 if (isInactive()) 1010 { 1011 return kIOReturnNoMedia; 1012 } 1013 1014 if (_openLevel == kIOStorageAccessNone) // (instantaneous value, no lock) 1015 { 1016 return kIOReturnNotOpen; 1017 } 1018 1019 if (_mediaSize == 0 || _preferredBlockSize == 0) 1020 { 1021 return kIOReturnUnformattedMedia; 1022 } 1023 1024 for (extentsIndex = 0; extentsIndex < extentsCount; extentsIndex++) 1025 { 1026 if (_mediaSize < extents[extentsIndex].byteStart + extents[extentsIndex].byteCount) 1027 { 1028 return kIOReturnBadArgument; 1029 } 1030 1031 extents[extentsIndex].byteStart += _mediaBase; 1032 } 1033 1034 return getProvider()->setPriority(this, extents, extentsCount, priority); 1035} 1036 1037UInt64 IOMedia::getPreferredBlockSize() const 1038{ 1039 // 1040 // Ask the media object for its natural block size. This information 1041 // is useful to clients that want to optimize access to the media. 1042 // 1043 1044 return _preferredBlockSize; 1045} 1046 1047UInt64 IOMedia::getSize() const 1048{ 1049 // 1050 // Ask the media object for its total length in bytes. 1051 // 1052 1053 return _mediaSize; 1054} 1055 1056UInt64 IOMedia::getBase() const 1057{ 1058 // 1059 // Ask the media object for its byte offset relative to the provider media. 1060 // 1061 1062 return _mediaBase; 1063} 1064 1065bool IOMedia::isEjectable() const 1066{ 1067 // 1068 // Ask the media object whether it is ejectable. 1069 // 1070 1071 return (_attributes & kIOMediaAttributeEjectableMask) ? true : false; 1072} 1073 1074bool IOMedia::isFormatted() const 1075{ 1076 // 1077 // Ask the media object whether it is formatted. 1078 // 1079 1080 return (_mediaSize && _preferredBlockSize); 1081} 1082 1083bool IOMedia::isWritable() const 1084{ 1085 // 1086 // Ask the media object whether it is writable. 1087 // 1088 1089 return _isWritable; 1090} 1091 1092bool IOMedia::isWhole() const 1093{ 1094 // 1095 // Ask the media object whether it represents the whole disk. 1096 // 1097 1098 return _isWhole; 1099} 1100 1101const char * IOMedia::getContent() const 1102{ 1103 // 1104 // Ask the media object for a description of its contents. The description 1105 // is the same as the hint at the time of the object's creation, but it is 1106 // possible that the description be overrided by a client (which has probed 1107 // the media and identified the content correctly) of the media object. It 1108 // is more accurate than the hint for this reason. The string is formed in 1109 // the likeness of Apple's "Apple_HFS" strings or in the likeness of a UUID. 1110 // 1111 // The content description can be overrided by any client that matches onto 1112 // this media object with a match category of kIOStorageCategory. The media 1113 // object checks for a kIOMediaContentMaskKey property in the client, and if 1114 // it finds one, it copies it into kIOMediaContentKey property. 1115 // 1116 1117 OSString * string; 1118 1119 string = OSDynamicCast(OSString, getProperty(kIOMediaContentKey)); 1120 if (string == 0) return ""; 1121 return string->getCStringNoCopy(); 1122} 1123 1124const char * IOMedia::getContentHint() const 1125{ 1126 // 1127 // Ask the media object for a hint of its contents. The hint is set at the 1128 // time of the object's creation, should the creator have a clue as to what 1129 // it may contain. The hint string does not change for the lifetime of the 1130 // object and is also formed in the likeness of Apple's "Apple_HFS" strings 1131 // or in the likeness of a UUID. 1132 // 1133 1134 OSString * string; 1135 1136 string = OSDynamicCast(OSString, getProperty(kIOMediaContentHintKey)); 1137 if (string == 0) return ""; 1138 return string->getCStringNoCopy(); 1139} 1140 1141bool IOMedia::init(UInt64 base, 1142 UInt64 size, 1143 UInt64 preferredBlockSize, 1144 IOMediaAttributeMask attributes, 1145 bool isWhole, 1146 bool isWritable, 1147 const char * contentHint, 1148 OSDictionary * properties) 1149{ 1150 // 1151 // Initialize this object's minimal state. 1152 // 1153 1154 bool isEjectable; 1155 bool isRemovable; 1156 1157 // Ask our superclass' opinion. 1158 1159 if (_openClients == 0) 1160 { 1161 if (super::init(properties) == false) return false; 1162 } 1163 1164 // Initialize our state. 1165 1166 isEjectable = (attributes & kIOMediaAttributeEjectableMask) ? true : false; 1167 isRemovable = (attributes & kIOMediaAttributeRemovableMask) ? true : false; 1168 1169 if (isEjectable) 1170 { 1171 attributes |= kIOMediaAttributeRemovableMask; 1172 isRemovable = true; 1173 } 1174 1175 _attributes = attributes; 1176 _mediaBase = base; 1177 _isWhole = isWhole; 1178 _isWritable = isWritable; 1179 _preferredBlockSize = preferredBlockSize; 1180 1181#ifdef __LP64__ 1182 _mediaSize = size; 1183#else /* !__LP64__ */ 1184 if (size > _mediaSize) 1185 { 1186 *((volatile UInt64 *) &_mediaSize) = (size & (UINT64_MAX ^ UINT32_MAX)) | (_mediaSize & UINT32_MAX); 1187 } 1188 else 1189 { 1190 *((volatile UInt64 *) &_mediaSize) = (size & UINT32_MAX) | (_mediaSize & (UINT64_MAX ^ UINT32_MAX)); 1191 } 1192 *((volatile UInt64 *) &_mediaSize) = size; 1193#endif /* !__LP64__ */ 1194 1195 if (_openClients == 0) 1196 { 1197 _openClients = OSDictionary::withCapacity(2); 1198 _openLevel = kIOStorageAccessNone; 1199 1200 if (_openClients == 0) return false; 1201 1202 setProperty(kIOMediaContentKey, contentHint ? contentHint : ""); 1203 setProperty(kIOMediaLeafKey, true); 1204 setProperty(kIOMediaOpenKey, false); 1205 } 1206 else 1207 { 1208 IOService * driver; 1209 OSObject * object; 1210 1211 object = (OSObject *) OSSymbol::withCString(kIOStorageCategory); 1212 if (object == 0) return false; 1213 1214 driver = copyClientWithCategory((OSSymbol *) object); 1215 object->release(); 1216 object = 0; 1217 1218 if (driver) 1219 { 1220 object = OSDynamicCast(OSString, driver->getProperty(kIOMediaContentMaskKey)); 1221 driver->release(); 1222 } 1223 1224 if (object == 0) setProperty(kIOMediaContentKey, contentHint ? contentHint : ""); 1225 } 1226 1227 // Create our registry properties. 1228 1229 setProperty(kIOMediaContentHintKey, contentHint ? contentHint : ""); 1230 setProperty(kIOMediaEjectableKey, isEjectable); 1231 setProperty(kIOMediaPreferredBlockSizeKey, preferredBlockSize, 64); 1232 setProperty(kIOMediaRemovableKey, isRemovable); 1233 setProperty(kIOMediaSizeKey, size, 64); 1234 setProperty(kIOMediaWholeKey, isWhole); 1235 setProperty(kIOMediaWritableKey, isWritable); 1236 1237 return true; 1238} 1239 1240IOMediaAttributeMask IOMedia::getAttributes() const 1241{ 1242 // 1243 // Ask the media object for its attributes. 1244 // 1245 1246 return _attributes; 1247} 1248 1249#ifdef __LP64__ 1250OSMetaClassDefineReservedUnused(IOMedia, 0); 1251OSMetaClassDefineReservedUnused(IOMedia, 1); 1252#else /* !__LP64__ */ 1253OSMetaClassDefineReservedUsed(IOMedia, 0); 1254OSMetaClassDefineReservedUsed(IOMedia, 1); 1255#endif /* !__LP64__ */ 1256OSMetaClassDefineReservedUnused(IOMedia, 2); 1257OSMetaClassDefineReservedUnused(IOMedia, 3); 1258OSMetaClassDefineReservedUnused(IOMedia, 4); 1259OSMetaClassDefineReservedUnused(IOMedia, 5); 1260OSMetaClassDefineReservedUnused(IOMedia, 6); 1261OSMetaClassDefineReservedUnused(IOMedia, 7); 1262OSMetaClassDefineReservedUnused(IOMedia, 8); 1263OSMetaClassDefineReservedUnused(IOMedia, 9); 1264OSMetaClassDefineReservedUnused(IOMedia, 10); 1265OSMetaClassDefineReservedUnused(IOMedia, 11); 1266OSMetaClassDefineReservedUnused(IOMedia, 12); 1267OSMetaClassDefineReservedUnused(IOMedia, 13); 1268OSMetaClassDefineReservedUnused(IOMedia, 14); 1269OSMetaClassDefineReservedUnused(IOMedia, 15); 1270 1271#ifndef __LP64__ 1272extern "C" void _ZN7IOMedia4readEP9IOServiceyP18IOMemoryDescriptor19IOStorageCompletion( IOMedia * media, IOService * client, UInt64 byteStart, IOMemoryDescriptor * buffer, IOStorageCompletion completion ) 1273{ 1274 media->read( client, byteStart, buffer, NULL, &completion ); 1275} 1276 1277extern "C" void _ZN7IOMedia5writeEP9IOServiceyP18IOMemoryDescriptor19IOStorageCompletion( IOMedia * media, IOService * client, UInt64 byteStart, IOMemoryDescriptor * buffer, IOStorageCompletion completion ) 1278{ 1279 media->write( client, byteStart, buffer, NULL, &completion ); 1280} 1281#endif /* !__LP64__ */ 1282