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@
22 #include <IOKit/IOBufferMemoryDescriptor.h>
23 #include <IOKit/IOLib.h>
24 #include <IOKit/storage/IOCDBlockStorageDriver.h>
25 #include <IOKit/storage/IOCDMedia.h>
26 #include <IOKit/storage/IOCDAudioControl.h>
27 #include <IOKit/storage/IOCDBlockStorageDevice.h>
28 #include <libkern/OSByteOrder.h>
31 // Hack for Cheetah to prevent sleep if there's disk activity.
32 static IOService
* gIORootPowerDomain
= NULL
;
34 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
36 #define super IOBlockStorageDriver
37 OSDefineMetaClassAndStructors(IOCDBlockStorageDriver
,IOBlockStorageDriver
)
39 IOCDBlockStorageDevice
*
40 IOCDBlockStorageDriver::getProvider() const
42 return (IOCDBlockStorageDevice
*) IOService::getProvider();
46 /* Accept a new piece of media, doing whatever's necessary to make it
47 * show up properly to the system. The arbitration lock is assumed to
48 * be held during the call.
51 IOCDBlockStorageDriver::acceptNewMedia(void)
63 /* First, we cache information about the tracks on the disc: */
65 result
= cacheTocInfo();
66 if (result
!= kIOReturnSuccess
) {
70 /* Scan thru the track list, counting up the number of Data and Audio tracks. */
77 nentries
= (_toc
->length
- sizeof(UInt16
)) / sizeof(CDTOCDescriptor
);
79 for (i
= 0; i
< nentries
; i
++) {
80 /* tracks 1-99, not leadout or skip intervals */
81 if (_toc
->descriptors
[i
].point
<= 99 && _toc
->descriptors
[i
].adr
== 1) {
82 if ((_toc
->descriptors
[i
].control
& 0x04)) {
83 /* it's a data track */
89 } else if (_toc
->descriptors
[i
].point
== 0xA2 && _toc
->descriptors
[i
].adr
== 1) {
90 if (nblocks
< CDConvertMSFToLBA(_toc
->descriptors
[i
].p
)) {
91 nblocks
= CDConvertMSFToLBA(_toc
->descriptors
[i
].p
);
96 if (nblocks
< _maxBlockNumber
+ 1) {
97 nblocks
= _maxBlockNumber
+ 1;
99 } else if (_maxBlockNumber
) {
100 nblocks
= _maxBlockNumber
+ 1;
103 /* Instantiate a CD Media nub above ourselves. */
107 if (getProvider()->getVendorString()) {
108 strcat(name
, getProvider()->getVendorString());
111 if (getProvider()->getProductString()) {
112 if (nameSep
== true) strcat(name
, " ");
113 strcat(name
, getProvider()->getProductString());
116 if (nameSep
== true) strcat(name
, " ");
117 strcat(name
, "Media");
119 _mediaObject
= instantiateMediaObject(0,nblocks
*kBlockSizeCD
,kBlockSizeCD
,name
);
120 result
= (_mediaObject
) ? kIOReturnSuccess
: kIOReturnBadArgument
;
122 if (result
== kIOReturnSuccess
) {
123 ok
= _mediaObject
->attach(this);
125 IOLog("%s[IOCDBlockStorageDriver]::acceptNewMedia; can't instantiate CD media nub.\n",getName());
126 return(result
); /* give up now */
129 IOLog("%s[IOCDBlockStorageDriver]::acceptNewMedia; can't attach CD media nub.\n",getName());
130 _mediaObject
->release();
132 return(kIOReturnNoMemory
); /* give up now */
135 /* Instantiate an audio control nub for the audio portion of the media. */
138 _acNub
= new IOCDAudioControl
;
141 ok
= _acNub
->attach(this);
143 IOLog("%s[IOCDBlockStorageDriver]::acceptNewMedia; can't attach audio control nub.\n",getName());
148 IOLog("%s[IOCDBlockStorageDriver]::acceptNewMedia; can't instantiate audio control nub.\n",
153 /* Now that the nubs are attached, register them. */
155 _mediaPresent
= true;
157 _mediaObject
->setProperty(kIOCDMediaTOCKey
,(void*)_toc
,_tocSize
);
159 _mediaObject
->registerService();
162 _acNub
->registerService();
169 IOCDBlockStorageDriver::audioPause(bool pause
)
171 return(getProvider()->audioPause(pause
));
175 IOCDBlockStorageDriver::audioPlay(CDMSF timeStart
,CDMSF timeStop
)
177 return(getProvider()->audioPlay(timeStart
,timeStop
));
181 IOCDBlockStorageDriver::audioScan(CDMSF timeStart
,bool reverse
)
183 return(getProvider()->audioScan(timeStart
,reverse
));
187 IOCDBlockStorageDriver::audioStop()
189 return(getProvider()->audioStop());
193 IOCDBlockStorageDriver::cacheTocInfo(void)
195 IOBufferMemoryDescriptor
*buffer
= NULL
;
200 assert(sizeof(CDTOC
) == 4); /* (compiler/platform check) */
201 assert(sizeof(CDTOCDescriptor
) == 11); /* (compiler/platform check) */
203 assert(_toc
== NULL
);
205 /* Read the TOC header: */
207 buffer
= IOBufferMemoryDescriptor::withCapacity(sizeof(CDTOC
),kIODirectionIn
);
208 if (buffer
== NULL
) {
209 return(kIOReturnNoMemory
);
212 result
= getProvider()->readTOC(buffer
);
213 if (result
!= kIOReturnSuccess
) {
218 toc
= (CDTOC
*) buffer
->getBytesNoCopy();
219 tocSize
= OSSwapBigToHostInt16(toc
->length
) + sizeof(UInt16
);
223 /* Read the TOC in full: */
225 buffer
= IOBufferMemoryDescriptor::withCapacity(tocSize
,kIODirectionIn
);
226 if (buffer
== NULL
) {
227 return(kIOReturnNoMemory
);
230 result
= getProvider()->readTOC(buffer
);
231 if (result
!= kIOReturnSuccess
) {
236 toc
= (CDTOC
*) IOMalloc(tocSize
);
239 return(kIOReturnNoMemory
);
242 if (buffer
->readBytes(0,toc
,tocSize
) != tocSize
) {
245 return(kIOReturnNoMemory
);
253 /* Convert big-endian values in TOC to host-endianess: */
255 if (_tocSize
>= sizeof(UInt16
)) {
256 _toc
->length
= OSSwapBigToHostInt16(_toc
->length
);
262 /* Decommission all nubs. The arbitration lock is assumed to
263 * be held during the call.
266 IOCDBlockStorageDriver::decommissionMedia(bool forcible
)
271 /* If this is a forcible decommission (i.e. media is gone), we don't
272 * care whether the teardown worked; we forget about the media.
274 if (_mediaObject
->terminate(forcible
? kIOServiceRequired
: 0) || forcible
) {
275 _mediaObject
->release();
278 initMediaState(); /* clear all knowledge of the media */
279 result
= kIOReturnSuccess
;
282 result
= kIOReturnBusy
;
285 result
= kIOReturnNoMedia
;
288 /* We only attempt to decommission the audio portion of the
289 * CD if all the data tracks decommissioned successfully.
292 if (result
== kIOReturnSuccess
) {
294 _acNub
->terminate(kIOServiceRequired
);
299 IOFree(_toc
,_tocSize
);
308 /* We should check with other clients using the other nubs before we allow
309 * the client of the IOCDMedia to eject the media.
312 IOCDBlockStorageDriver::ejectMedia(void)
314 /* For now, we don't check with the other clients. */
316 return(super::ejectMedia());
320 IOCDBlockStorageDriver::executeRequest(UInt64 byteStart
,
321 IOMemoryDescriptor
*buffer
,
322 IOStorageCompletion completion
,
323 IOBlockStorageDriver::Context
*context
)
329 if (!_mediaPresent
) { /* no media? you lose */
330 complete(completion
, kIOReturnNoMedia
,0);
334 /* We know that we are never called with a request too large,
335 * nor one that is misaligned with a block.
337 assert((byteStart
% context
->block
.size
) == 0);
338 assert((buffer
->getLength() % context
->block
.size
) == 0);
340 block
= byteStart
/ context
->block
.size
;
341 nblks
= buffer
->getLength() / context
->block
.size
;
343 /* Now the protocol-specific provider implements the actual
344 * start of the data transfer: */
346 // Tickle the root power domain to reset the sleep countdown.
347 if (gIORootPowerDomain
) {
348 gIORootPowerDomain
->activityTickle(kIOPMSubclassPolicy
);
351 if (context
->block
.type
== kBlockTypeCD
) {
352 result
= getProvider()->doAsyncReadCD(buffer
,block
,nblks
,
353 (CDSectorArea
)context
->block
.typeSub
[0],
354 (CDSectorType
)context
->block
.typeSub
[1],
357 result
= getProvider()->doAsyncReadWrite(buffer
,block
,nblks
,completion
);
360 if (result
!= kIOReturnSuccess
) { /* it failed to start */
361 complete(completion
,result
);
367 IOCDBlockStorageDriver::getAudioStatus(CDAudioStatus
*status
)
369 return(getProvider()->getAudioStatus(status
));
373 IOCDBlockStorageDriver::getAudioVolume(UInt8
*leftVolume
,UInt8
*rightVolume
)
375 return(getProvider()->getAudioVolume(leftVolume
,rightVolume
));
379 IOCDBlockStorageDriver::getDeviceTypeName(void)
381 return(kIOBlockStorageDeviceTypeCDROM
);
385 IOCDBlockStorageDriver::getMediaBlockSize(CDSectorArea area
,CDSectorType type
)
387 UInt64 blockSize
= 0;
389 const SInt16 areaSize
[kCDSectorTypeCount
][8] =
390 { /* 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 */
391 /* Unknown */ { 96, 294, -1, 280, 2048, 4, 8, 12 },
392 /* CDDA */ { 96, 294, -1, 0, 2352, 0, 0, 0 },
393 /* Mode1 */ { 96, 294, -1, 288, 2048, 4, 0, 12 },
394 /* Mode2 */ { 96, 294, -1, 0, 2336, 4, 0, 12 },
395 /* Mode2Form1 */ { 96, 294, -1, 280, 2048, 4, 8, 12 },
396 /* Mode2Form2 */ { 96, 294, -1, 0, 2328, 4, 8, 12 },
399 if ( type
>= kCDSectorTypeCount
) return 0;
401 for ( UInt32 index
= 0; index
< 8; index
++ )
403 if ( ((area
>> index
) & 0x01) )
405 if ( areaSize
[type
][index
] == -1 ) return 0;
406 blockSize
+= areaSize
[type
][index
];
414 IOCDBlockStorageDriver::getMediaType(void)
416 return(getProvider()->getMediaType());
420 IOCDBlockStorageDriver::getTOC(void)
426 IOCDBlockStorageDriver::init(OSDictionary
* properties
)
432 // Hack for Cheetah to prevent sleep if there's disk activity.
433 if (!gIORootPowerDomain
) {
434 // No danger of race here as we're ultimately just setting
435 // the gIORootPowerDomain variable.
438 IOService
* root
= NULL
;
439 OSIterator
* iterator
= NULL
;
440 OSDictionary
* pmDict
= NULL
;
442 root
= IOService::getServiceRoot();
445 pmDict
= root
->serviceMatching("IOPMrootDomain");
448 iterator
= root
->getMatchingServices(pmDict
);
450 if (!iterator
) break;
453 gIORootPowerDomain
= OSDynamicCast(IOService
, iterator
->getNextObject());
459 return(super::init(properties
));
463 IOCDBlockStorageDriver::instantiateDesiredMediaObject(void)
465 return(new IOCDMedia
);
469 IOCDBlockStorageDriver::instantiateMediaObject(UInt64 base
,UInt64 byteSize
,
470 UInt32 blockSize
,char *mediaName
)
474 media
= super::instantiateMediaObject(base
,byteSize
,blockSize
,mediaName
);
477 char *description
= NULL
;
479 switch (getMediaType()) {
480 case kCDMediaTypeROM
:
481 description
= kIOCDMediaTypeROM
;
484 description
= kIOCDMediaTypeR
;
487 description
= kIOCDMediaTypeRW
;
492 media
->setProperty(kIOCDMediaTypeKey
, description
);
500 IOCDBlockStorageDriver::readCD(IOService
*client
,
502 IOMemoryDescriptor
*buffer
,
503 CDSectorArea sectorArea
,
504 CDSectorType sectorType
,
505 IOStorageCompletion completion
)
507 assert(buffer
->getDirection() == kIODirectionIn
);
509 prepareRequest(byteStart
, buffer
, sectorArea
, sectorType
, completion
);
513 IOCDBlockStorageDriver::prepareRequest(UInt64 byteStart
,
514 IOMemoryDescriptor
*buffer
,
515 CDSectorArea sectorArea
,
516 CDSectorType sectorType
,
517 IOStorageCompletion completion
)
522 // Allocate a context structure to hold some of our state.
524 context
= allocateContext();
528 complete(completion
, kIOReturnNoMemory
);
532 // Prepare the transfer buffer.
534 status
= buffer
->prepare();
536 if (status
!= kIOReturnSuccess
)
538 deleteContext(context
);
539 complete(completion
, status
);
543 // Fill in the context structure with some of our state.
545 if ( ( sectorArea
== kCDSectorAreaUser
) &&
546 ( sectorType
== kCDSectorTypeMode1
||
547 sectorType
== kCDSectorTypeMode2Form1
) )
549 context
->block
.size
= _mediaBlockSize
;
550 context
->block
.type
= kBlockTypeStandard
;
554 context
->block
.size
= getMediaBlockSize(sectorArea
, sectorType
);
555 context
->block
.type
= kBlockTypeCD
;
556 context
->block
.typeSub
[0] = sectorArea
;
557 context
->block
.typeSub
[1] = sectorType
;
560 context
->original
.byteStart
= byteStart
;
561 context
->original
.buffer
= buffer
;
562 context
->original
.buffer
->retain();
563 context
->original
.completion
= completion
;
565 completion
.target
= this;
566 completion
.action
= prepareRequestCompletion
;
567 completion
.parameter
= context
;
569 // Deblock the transfer.
571 deblockRequest(byteStart
, buffer
, completion
, context
);
575 IOCDBlockStorageDriver::readISRC(UInt8 track
,CDISRC isrc
)
577 return(getProvider()->readISRC(track
,isrc
));
581 IOCDBlockStorageDriver::readMCN(CDMCN mcn
)
583 return(getProvider()->readMCN(mcn
));
587 IOCDBlockStorageDriver::setAudioVolume(UInt8 leftVolume
,UInt8 rightVolume
)
589 return(getProvider()->setAudioVolume(leftVolume
,rightVolume
));
592 OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver
, 0);
593 OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver
, 1);
594 OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver
, 2);
595 OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver
, 3);
596 OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver
, 4);
597 OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver
, 5);
598 OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver
, 6);
599 OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver
, 7);
600 OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver
, 8);
601 OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver
, 9);
602 OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver
, 10);
603 OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver
, 11);
604 OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver
, 12);
605 OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver
, 13);
606 OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver
, 14);
607 OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver
, 15);