2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 #include <machine/limits.h> // (ULONG_MAX, ...)
24 #include <IOKit/IODeviceTreeSupport.h> // (gIODTPlane, ...)
25 #include <IOKit/storage/IOMedia.h>
27 #define super IOStorage
28 OSDefineMetaClassAndStructors(IOMedia
, IOStorage
)
30 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
32 IOStorage
* IOMedia::getProvider() const
35 // Obtain this object's provider. We override the superclass's method to
36 // return a more specific subclass of OSObject -- IOStorage. This method
37 // serves simply as a convenience to subclass developers.
40 return (IOStorage
*) IOService::getProvider();
43 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
45 bool IOMedia::init(UInt64 base
,
47 UInt64 preferredBlockSize
,
51 const char * contentHint
= 0,
52 OSDictionary
* properties
= 0)
55 // Initialize this object's minimal state.
58 if (super::init(properties
) == false) return false;
62 _isEjectable
= isEjectable
;
64 _isWritable
= isWritable
;
65 _openLevel
= kIOStorageAccessNone
;
66 _openReaders
= OSSet::withCapacity(1);
67 _openReaderWriter
= 0;
68 _preferredBlockSize
= preferredBlockSize
;
70 if (_openReaders
== 0) return false;
73 // Create the standard media registry properties.
76 setProperty(kIOMediaContentKey
, contentHint
? contentHint
: "");
77 setProperty(kIOMediaContentHintKey
, contentHint
? contentHint
: "");
78 setProperty(kIOMediaEjectableKey
, isEjectable
);
79 setProperty(kIOMediaLeafKey
, true);
80 setProperty(kIOMediaPreferredBlockSizeKey
, preferredBlockSize
, 64);
81 setProperty(kIOMediaSizeKey
, size
, 64);
82 setProperty(kIOMediaWholeKey
, isWhole
);
83 setProperty(kIOMediaWritableKey
, isWritable
);
88 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
90 void IOMedia::free(void)
93 // Free all of this object's outstanding resources.
96 if (_openReaders
) _openReaders
->release();
101 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
103 bool IOMedia::attachToChild(IORegistryEntry
* client
,
104 const IORegistryPlane
* plane
)
107 // This method is called for each client interested in the services we
108 // provide. The superclass links us as a parent to this client in the
109 // I/O Kit registry on success.
114 // Ask our superclass' opinion.
116 if (super::attachToChild(client
, plane
) == false) return false;
119 // Determine whether the client is a storage object, which we consider
120 // to be a consumer of this storage object's content and a producer of
121 // new content. A storage object need not be an IOStorage subclass, so
122 // long as it identifies itself with a match category of "IOStorage".
124 // If the client is indeed a storage object, we reset the media's Leaf
125 // property to false and replace the media's Content property with the
126 // client's Content Mask property, if any.
129 s
= OSDynamicCast(OSString
, client
->getProperty(gIOMatchCategoryKey
));
131 if (s
&& !strcmp(s
->getCStringNoCopy(), kIOStorageCategory
))
133 setProperty(kIOMediaLeafKey
, false);
135 s
= OSDynamicCast(OSString
,client
->getProperty(kIOMediaContentMaskKey
));
136 if (s
) setProperty(kIOMediaContentKey
, s
->getCStringNoCopy());
142 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
144 void IOMedia::detachFromChild(IORegistryEntry
* client
,
145 const IORegistryPlane
* plane
)
148 // This method is called for each client that loses interest in the
149 // services we provide. The superclass unlinks us from this client
150 // in the I/O Kit registry on success.
152 // Note that this method is called at a nondeterministic time after
153 // our client is terminated, which means another client may already
154 // have arrived and attached in the meantime. This is not an issue
155 // should the termination be issued synchrnously, however, which we
156 // take advantage of when this media needs to eliminate one of its
157 // clients. If the termination was issued on this media or farther
158 // below in the hierarchy, we don't really care that the properties
159 // would not be consistent since this media object is going to die
166 // Determine whether the client is a storage object, which we consider
167 // to be a consumer of this storage object's content and a producer of
168 // new content. A storage object need not be an IOStorage subclass, so
169 // long as it identifies itself with a match category of "IOStorage".
171 // If the client is indeed a storage object, we reset the media's Leaf
172 // property to true and reset the media's Content property to the hint
173 // we obtained when this media was initialized.
176 s
= OSDynamicCast(OSString
, client
->getProperty(gIOMatchCategoryKey
));
178 if (s
&& !strcmp(s
->getCStringNoCopy(), kIOStorageCategory
))
180 setProperty(kIOMediaContentKey
, getContentHint());
181 setProperty(kIOMediaLeafKey
, true);
184 // Pass the call onto our superclass.
186 super::detachFromChild(client
, plane
);
189 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
191 bool IOMedia::handleOpen(IOService
* client
,
192 IOOptionBits options
,
196 // The handleOpen method grants or denies permission to access this object
197 // to an interested client. The argument is an IOStorageAccess value that
198 // specifies the level of access desired -- reader or reader-writer.
200 // This method can be invoked to upgrade or downgrade the access level for
201 // an existing client as well. The previous access level will prevail for
202 // upgrades that fail, of course. A downgrade should never fail. If the
203 // new access level should be the same as the old for a given client, this
204 // method will do nothing and return success. In all cases, one, singular
205 // close-per-client is expected for all opens-per-client received.
207 // This method will work even when the media is in the terminated state.
209 // We are guaranteed that no other opens or closes will be processed until
210 // we make our decision, change our state, and return from this method.
213 IOStorageAccess access
= (IOStorageAccess
) argument
;
214 IOStorageAccess level
;
219 // Chart our course of action.
224 case kIOStorageAccessReader
:
226 if (_openReaders
->containsObject(client
)) // (access: no change)
228 else if (_openReaderWriter
== client
) // (access: downgrade)
229 level
= kIOStorageAccessReader
;
230 else // (access: new reader)
231 level
= _openReaderWriter
? kIOStorageAccessReaderWriter
232 : kIOStorageAccessReader
;
235 case kIOStorageAccessReaderWriter
:
237 if (_openReaders
->containsObject(client
)) // (access: upgrade)
238 level
= kIOStorageAccessReaderWriter
;
239 else if (_openReaderWriter
== client
) // (access: no change)
241 else // (access: new writer)
242 level
= kIOStorageAccessReaderWriter
;
244 if (_isWritable
== false) // (is this media object writable?)
247 if (_openReaderWriter
) // (does a reader-writer already exist?)
260 // If we are in the terminated state, we only accept downgrades.
263 if (isInactive() && _openReaderWriter
!= client
) // (dead? not a downgrade?)
267 // Determine whether the storage objects above us can be torn down, should
268 // this be a new reader-writer open or an upgrade into a reader-writer (if
269 // the client issuing the open is not a storage object itself, of course).
272 if (access
== kIOStorageAccessReaderWriter
) // (new reader-writer/upgrade?)
274 const OSSymbol
* category
= OSSymbol::withCString(kIOStorageCategory
);
278 IOService
* storageObject
= getClientWithCategory(category
);
281 if (storageObject
&& storageObject
!= client
)
283 if (storageObject
->terminate(kIOServiceSynchronous
) == false)
290 // Determine whether the storage objects below us accept this open at this
291 // multiplexed level of access -- new opens, upgrades, and downgrades (and
292 // no changes in access) all enter through the same open api.
295 if (_openLevel
!= level
) // (has open level changed?)
297 IOStorage
* provider
= OSDynamicCast(IOStorage
, getProvider());
299 if (provider
&& provider
->open(this, options
, level
) == false)
302 // We were unable to open the storage objects below us. We must
303 // recover from the terminate we issued above before bailing out,
304 // if applicable, by re-registering the media object for matching.
307 if (access
== kIOStorageAccessReaderWriter
)
308 registerService(kIOServiceSynchronous
); // (re-register media)
317 // We make sure our open state is consistent before calling registerService
318 // (if applicable) since this method can be called again on the same thread
319 // (the lock protecting handleOpen is recursive, so access would be given).
324 if (access
== kIOStorageAccessReader
)
326 _openReaders
->setObject(client
);
328 if (_openReaderWriter
== client
) // (for a downgrade)
330 _openReaderWriter
= 0;
331 registerService(kIOServiceSynchronous
); // (re-register media)
334 else // (access == kIOStorageAccessReaderWriter)
336 _openReaderWriter
= client
;
338 _openReaders
->removeObject(client
); // (for an upgrade)
344 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
346 bool IOMedia::handleIsOpen(const IOService
* client
) const
349 // The handleIsOpen method determines whether the specified client, or any
350 // client if none is specificed, presently has an open on this object.
352 // This method will work even when the media is in the terminated state.
354 // We are guaranteed that no other opens or closes will be processed until
355 // we return from this method.
358 if (client
== 0) return (_openLevel
!= kIOStorageAccessNone
);
360 return ( _openReaderWriter
== client
||
361 _openReaders
->containsObject(client
) );
364 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
366 void IOMedia::handleClose(IOService
* client
, IOOptionBits options
)
369 // A client is informing us that it is giving up access to our contents.
371 // This method will work even when the media is in the terminated state.
373 // We are guaranteed that no other opens or closes will be processed until
374 // we change our state and return from this method.
380 // Process the close.
383 bool reregister
= (_openReaderWriter
== client
) && (isInactive() == false);
385 if (_openReaderWriter
== client
) // (is the client a reader-writer?)
387 _openReaderWriter
= 0;
389 else if (_openReaders
->containsObject(client
)) // (is the client a reader?)
391 _openReaders
->removeObject(client
);
393 else // (is the client is an imposter?)
400 // Reevaluate the open we have on the level below us. If no opens remain,
401 // we close, or if no reader-writer remains, but readers do, we downgrade.
404 IOStorageAccess level
;
406 if (_openReaderWriter
) level
= kIOStorageAccessReaderWriter
;
407 else if (_openReaders
->getCount()) level
= kIOStorageAccessReader
;
408 else level
= kIOStorageAccessNone
;
410 if (_openLevel
!= level
) // (has open level changed?)
412 IOStorage
* provider
= OSDynamicCast(IOStorage
, getProvider());
414 assert(level
!= kIOStorageAccessReaderWriter
);
418 if (level
== kIOStorageAccessNone
) // (is a close in order?)
420 provider
->close(this, options
);
422 else // (is a downgrade in order?)
425 success
= provider
->open(this, 0, level
);
426 assert(success
); // (should never fail, unless avoided deadlock)
430 _openLevel
= level
; // (set new open level)
434 // If the reader-writer just closeed, re-register the media so that I/O Kit
435 // will attempt to match storage objects that may now be interested in this
438 // We make sure our open state is consistent before calling registerService
439 // (if applicable) since this method can be called again on the same thread
440 // (the lock protecting handleClose is recursive, so access would be given).
444 registerService(kIOServiceSynchronous
); // (re-register media)
447 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
449 void IOMedia::read(IOService
* /* client */,
451 IOMemoryDescriptor
* buffer
,
452 IOStorageCompletion completion
)
455 // Read data from the storage object at the specified byte offset into the
456 // specified buffer, asynchronously. When the read completes, the caller
457 // will be notified via the specified completion action.
459 // The buffer will be retained for the duration of the read.
461 // This method will work even when the media is in the terminated state.
466 complete(completion
, kIOReturnNoMedia
);
470 if (_openLevel
== kIOStorageAccessNone
) // (instantaneous value, no lock)
472 complete(completion
, kIOReturnNotOpen
);
476 if (_mediaSize
== 0 || _preferredBlockSize
== 0)
478 complete(completion
, kIOReturnUnformattedMedia
);
482 if (_mediaSize
< byteStart
+ buffer
->getLength())
484 complete(completion
, kIOReturnBadArgument
);
488 byteStart
+= _mediaBase
;
489 getProvider()->read(this, byteStart
, buffer
, completion
);
492 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
494 void IOMedia::write(IOService
* client
,
496 IOMemoryDescriptor
* buffer
,
497 IOStorageCompletion completion
)
500 // Write data into the storage object at the specified byte offset from the
501 // specified buffer, asynchronously. When the write completes, the caller
502 // will be notified via the specified completion action.
504 // The buffer will be retained for the duration of the write.
506 // This method will work even when the media is in the terminated state.
511 complete(completion
, kIOReturnNoMedia
);
515 if (_openLevel
== kIOStorageAccessNone
) // (instantaneous value, no lock)
517 complete(completion
, kIOReturnNotOpen
);
521 if (_openReaderWriter
!= client
) // (instantaneous value, no lock)
523 ///m:2425148:workaround:commented:start
524 // complete(completion, kIOReturnNotPrivileged);
526 ///m:2425148:workaround:commented:stop
529 if (_isWritable
== 0)
531 complete(completion
, kIOReturnLockedWrite
);
535 if (_mediaSize
== 0 || _preferredBlockSize
== 0)
537 complete(completion
, kIOReturnUnformattedMedia
);
541 if (_mediaSize
< byteStart
+ buffer
->getLength())
543 complete(completion
, kIOReturnBadArgument
);
547 byteStart
+= _mediaBase
;
548 getProvider()->write(this, byteStart
, buffer
, completion
);
551 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
553 IOReturn
IOMedia::synchronizeCache(IOService
* client
)
557 return kIOReturnNoMedia
;
560 if (_openLevel
== kIOStorageAccessNone
) // (instantaneous value, no lock)
562 return kIOReturnNotOpen
;
565 if (_openReaderWriter
!= client
) // (instantaneous value, no lock)
567 return kIOReturnNotPrivileged
;
570 if (_isWritable
== 0)
572 return kIOReturnLockedWrite
;
575 if (_mediaSize
== 0 || _preferredBlockSize
== 0)
577 return kIOReturnUnformattedMedia
;
580 return getProvider()->synchronizeCache(this);
583 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
585 UInt64
IOMedia::getPreferredBlockSize() const
588 // Ask the media object for its natural block size. This information
589 // is useful to clients that want to optimize access to the media.
592 return _preferredBlockSize
;
595 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
597 UInt64
IOMedia::getSize() const
600 // Ask the media object for its total length in bytes.
606 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
608 UInt64
IOMedia::getBase() const
611 // Ask the media object for its byte offset relative to its provider media
612 // object below it in the storage hierarchy.
618 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
620 bool IOMedia::isEjectable() const
623 // Ask the media object whether it is ejectable.
629 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
631 bool IOMedia::isFormatted() const
634 // Ask the media object whether it is formatted.
637 return (_mediaSize
&& _preferredBlockSize
);
640 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
642 bool IOMedia::isWritable() const
645 // Ask the media object whether it is writable.
651 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
653 bool IOMedia::isWhole() const
656 // Ask the media object whether it represents the whole disk.
662 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
664 const char * IOMedia::getContent() const
667 // Ask the media object for a description of its contents. The description
668 // is the same as the hint at the time of the object's creation, but it is
669 // possible that the description be overrided by a client (which has probed
670 // the media and identified the content correctly) of the media object. It
671 // is more accurate than the hint for this reason. The string is formed in
672 // the likeness of Apple's "Apple_HFS" strings.
674 // The content description can be overrided by any client that matches onto
675 // this media object with a match category of kIOStorageCategory. The media
676 // object checks for a kIOMediaContentMaskKey property in the client, and if
677 // it finds one, it copies it into kIOMediaContentKey property.
682 string
= OSDynamicCast(OSString
, getProperty(kIOMediaContentKey
));
683 if (string
== 0) return "";
684 return string
->getCStringNoCopy();
687 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
689 const char * IOMedia::getContentHint() const
692 // Ask the media object for a hint of its contents. The hint is set at the
693 // time of the object's creation, should the creator have a clue as to what
694 // it may contain. The hint string does not change for the lifetime of the
695 // object and is also formed in the likeness of Apple's "Apple_HFS" strings.
700 string
= OSDynamicCast(OSString
, getProperty(kIOMediaContentHintKey
));
701 if (string
== 0) return "";
702 return string
->getCStringNoCopy();
705 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
707 bool IOMedia::matchPropertyTable(OSDictionary
* table
, SInt32
* score
)
710 // Compare the properties in the supplied table to this object's properties.
713 // Ask our superclass' opinion.
715 if (super::matchPropertyTable(table
, score
) == false) return false;
717 // We return success if the following expression is true -- individual
718 // comparisions evaluate to truth if the named property is not present
719 // in the supplied table.
721 return compareProperty(table
, kIOMediaContentKey
) &&
722 compareProperty(table
, kIOMediaContentHintKey
) &&
723 compareProperty(table
, kIOMediaEjectableKey
) &&
724 compareProperty(table
, kIOMediaLeafKey
) &&
725 compareProperty(table
, kIOMediaSizeKey
) &&
726 compareProperty(table
, kIOMediaWholeKey
) &&
727 compareProperty(table
, kIOMediaWritableKey
) ;
730 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
732 OSMetaClassDefineReservedUnused(IOMedia
, 0);
734 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
736 OSMetaClassDefineReservedUnused(IOMedia
, 1);
738 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
740 OSMetaClassDefineReservedUnused(IOMedia
, 2);
742 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
744 OSMetaClassDefineReservedUnused(IOMedia
, 3);
746 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
748 OSMetaClassDefineReservedUnused(IOMedia
, 4);
750 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
752 OSMetaClassDefineReservedUnused(IOMedia
, 5);
754 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
756 OSMetaClassDefineReservedUnused(IOMedia
, 6);
758 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
760 OSMetaClassDefineReservedUnused(IOMedia
, 7);
762 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
764 OSMetaClassDefineReservedUnused(IOMedia
, 8);
766 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
768 OSMetaClassDefineReservedUnused(IOMedia
, 9);
770 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
772 OSMetaClassDefineReservedUnused(IOMedia
, 10);
774 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
776 OSMetaClassDefineReservedUnused(IOMedia
, 11);
778 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
780 OSMetaClassDefineReservedUnused(IOMedia
, 12);
782 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
784 OSMetaClassDefineReservedUnused(IOMedia
, 13);
786 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
788 OSMetaClassDefineReservedUnused(IOMedia
, 14);
790 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
792 OSMetaClassDefineReservedUnused(IOMedia
, 15);