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