IOCDBlockStorageDriver.cpp [plain text]
#include <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/IOLib.h>
#include <IOKit/storage/IOCDBlockStorageDriver.h>
#include <IOKit/storage/IOCDMedia.h>
#include <IOKit/storage/IOCDBlockStorageDevice.h>
#include <libkern/OSByteOrder.h>
#define super IOBlockStorageDriver
OSDefineMetaClassAndStructors(IOCDBlockStorageDriver,IOBlockStorageDriver)
#ifdef __LP64__
#define original request
#endif
IOCDBlockStorageDevice *
IOCDBlockStorageDriver::getProvider() const
{
return (IOCDBlockStorageDevice *) IOService::getProvider();
}
IOReturn
IOCDBlockStorageDriver::acceptNewMedia(void)
{
IOReturn result;
int i;
int nentries;
int nAudioTracks;
result = cacheTocInfo();
if (result != kIOReturnSuccess) {
assert(_toc == NULL);
}
nAudioTracks = 0;
_minBlockNumberAudio = 0xFFFFFFFF;
_maxBlockNumberAudio = 0xFFFFFFFF;
if (_toc) {
nentries = CDTOCGetDescriptorCount(_toc);
for (i = 0; i < nentries; i++) {
UInt32 lba = CDConvertMSFToClippedLBA(_toc->descriptors[i].p);
if (_toc->descriptors[i].point <= 99 && _toc->descriptors[i].adr == 1) {
if ((_toc->descriptors[i].control & 0x04)) {
_maxBlockNumberAudio = min(_maxBlockNumberAudio, lba ? (lba - 1) : 0);
} else {
nAudioTracks++;
_minBlockNumberAudio = min(_minBlockNumberAudio, lba);
}
} else if (_toc->descriptors[i].point == 0xA2 && _toc->descriptors[i].adr == 1) {
_maxBlockNumber = max(_maxBlockNumber, lba ? (lba - 1) : 0);
_maxBlockNumberAudio = min(_maxBlockNumberAudio, lba ? (lba - 1) : 0);
}
}
if (_maxBlockNumberAudio < _minBlockNumberAudio) {
_maxBlockNumberAudio = 0xFFFFFFFF;
for (i = 0; i < nentries; i++) {
UInt32 lba = CDConvertMSFToClippedLBA(_toc->descriptors[i].p);
if (_toc->descriptors[i].point <= 99 && _toc->descriptors[i].adr == 1) {
if ((_toc->descriptors[i].control & 0x04)) {
if (lba > _minBlockNumberAudio) {
_maxBlockNumberAudio = min(_maxBlockNumberAudio, lba - 1);
}
}
} else if (_toc->descriptors[i].point == 0xA2 && _toc->descriptors[i].adr == 1) {
if (lba > _minBlockNumberAudio) {
_maxBlockNumberAudio = min(_maxBlockNumberAudio, lba - 1);
}
}
}
}
}
switch (getMediaType()) {
case kCDMediaTypeR:
case kCDMediaTypeRW: {
bool checkIsWritable = false;
CDDiscInfo discInfo;
CDTrackInfo trackInfo;
result = reportDiscInfo(&discInfo);
if (result != kIOReturnSuccess) {
break;
}
switch (discInfo.discStatus) {
case 0x01:
checkIsWritable = true;
break;
case 0x02:
checkIsWritable = discInfo.erasable ? true : false;
break;
}
if (checkIsWritable) {
UInt16 trackLast = discInfo.lastTrackNumberInLastSessionLSB;
result = reportTrackInfo(trackLast,&trackInfo);
if (result != kIOReturnSuccess) {
break;
}
if (discInfo.discStatus == 0x01) {
_maxBlockNumber = CDConvertMSFToClippedLBA(discInfo.lastPossibleStartTimeOfLeadOut);
}
if (trackInfo.packet) {
_writeProtected = false;
break;
}
if (discInfo.discStatus == 0x01) {
if (trackInfo.blank) {
UInt16 trackFirst = discInfo.firstTrackNumberInLastSessionLSB;
if (trackFirst < trackLast) {
result = reportTrackInfo(trackLast - 1,&trackInfo);
if (result != kIOReturnSuccess) {
break;
}
if (trackInfo.packet) {
_writeProtected = false;
break;
}
}
}
}
}
break;
}
}
result = super::acceptNewMedia();
if (result != kIOReturnSuccess) {
return(result);
}
return(result);
}
#ifndef __LP64__
IOReturn
IOCDBlockStorageDriver::audioPause(bool pause)
{
return(getProvider()->audioPause(pause));
}
IOReturn
IOCDBlockStorageDriver::audioPlay(CDMSF timeStart,CDMSF timeStop)
{
return(getProvider()->audioPlay(timeStart,timeStop));
}
IOReturn
IOCDBlockStorageDriver::audioScan(CDMSF timeStart,bool reverse)
{
return(getProvider()->audioScan(timeStart,reverse));
}
IOReturn
IOCDBlockStorageDriver::audioStop()
{
return(getProvider()->audioStop());
}
#endif
IOReturn
IOCDBlockStorageDriver::cacheTocInfo(void)
{
IOBufferMemoryDescriptor *buffer;
IOReturn result;
CDTOC *toc;
UInt16 tocSize;
assert(sizeof(CDTOC) == 4);
assert(sizeof(CDTOCDescriptor) == 11);
assert(_toc == NULL);
buffer = IOBufferMemoryDescriptor::withCapacity(sizeof(CDTOC),kIODirectionIn);
if (buffer == NULL) {
return(kIOReturnNoMemory);
}
result = getProvider()->readTOC(buffer);
if (result != kIOReturnSuccess) {
buffer->release();
return(result);
}
toc = (CDTOC *) buffer->getBytesNoCopy();
tocSize = OSSwapBigToHostInt16(toc->length) + sizeof(toc->length);
buffer->release();
if (tocSize <= sizeof(CDTOC)) {
return(kIOReturnNotFound);
}
buffer = IOBufferMemoryDescriptor::withCapacity(tocSize,kIODirectionIn);
if (buffer == NULL) {
return(kIOReturnNoMemory);
}
result = getProvider()->readTOC(buffer);
if (result != kIOReturnSuccess) {
buffer->release();
return(result);
}
toc = (CDTOC *) IOMalloc(tocSize);
if (toc == NULL) {
buffer->release();
return(kIOReturnNoMemory);
}
if (buffer->readBytes(0,toc,tocSize) != tocSize) {
buffer->release();
IOFree(toc,tocSize);
return(kIOReturnNoMemory);
}
_toc = toc;
_tocSize = tocSize;
buffer->release();
return(result);
}
IOReturn
IOCDBlockStorageDriver::decommissionMedia(bool forcible)
{
IOReturn result;
result = super::decommissionMedia(forcible);
if (result == kIOReturnSuccess) {
if (_toc) {
IOFree(_toc,_tocSize);
_toc = NULL;
_tocSize = 0;
}
_minBlockNumberAudio = 0;
_maxBlockNumberAudio = 0;
}
return(result);
}
IOReturn
IOCDBlockStorageDriver::ejectMedia(void)
{
return(super::ejectMedia());
}
void
IOCDBlockStorageDriver::executeRequest(UInt64 byteStart,
IOMemoryDescriptor *buffer,
#ifdef __LP64__
IOStorageAttributes *attributes,
IOStorageCompletion *completion,
#else
IOStorageCompletion completion,
#endif
IOBlockStorageDriver::Context *context)
{
UInt32 block;
UInt32 nblks;
IOReturn result;
if (!_mediaPresent) {
complete(completion, kIOReturnNoMedia,0);
return;
}
assert((byteStart % context->block.size) == 0);
assert((buffer->getLength() % context->block.size) == 0);
block = byteStart / context->block.size;
nblks = buffer->getLength() / context->block.size;
if (context->block.type == kBlockTypeCD) {
if (context->block.typeSub[1] == kCDSectorTypeUnknown &&
block >= _minBlockNumberAudio &&
block + nblks - 1 <= _maxBlockNumberAudio) {
context->block.typeSub[1] = kCDSectorTypeCDDA;
if (context->block.typeSub[0] & 0xF8) {
context->block.typeSub[0] &= ~(0xF8);
context->block.typeSub[0] |= kCDSectorAreaUser;
}
}
if (buffer->getDirection() == kIODirectionIn) {
result = getProvider()->doAsyncReadCD(buffer,block,nblks,
(CDSectorArea)context->block.typeSub[0],
(CDSectorType)context->block.typeSub[1],
#ifdef __LP64__
completion ? *completion : (IOStorageCompletion) { 0 });
#else
completion);
#endif
} else {
complete(completion,kIOReturnUnsupported);
return;
}
} else {
#ifdef __LP64__
result = getProvider()->doAsyncReadWrite(buffer,block,nblks,attributes,completion);
#else
result = getProvider()->doAsyncReadWrite(buffer,block,nblks,&context->request.attributes,&completion);
#endif
}
if (result != kIOReturnSuccess) {
complete(completion,result);
return;
}
}
void
IOCDBlockStorageDriver::free(void)
{
if (_expansionData) {
IODelete(_expansionData, ExpansionData, 1);
}
super::free();
}
#ifndef __LP64__
IOReturn
IOCDBlockStorageDriver::getAudioStatus(CDAudioStatus *status)
{
return(getProvider()->getAudioStatus(status));
}
IOReturn
IOCDBlockStorageDriver::getAudioVolume(UInt8 *leftVolume,UInt8 *rightVolume)
{
return(getProvider()->getAudioVolume(leftVolume,rightVolume));
}
#endif
const char *
IOCDBlockStorageDriver::getDeviceTypeName(void)
{
return(kIOBlockStorageDeviceTypeCDROM);
}
UInt64
IOCDBlockStorageDriver::getMediaBlockSize(CDSectorArea area,CDSectorType type)
{
UInt64 blockSize = 0;
const SInt16 areaSize[kCDSectorTypeCount][8] =
{
{ 96, 294, 16, 280, 2048, 4, 8, 12 },
{ 96, 294, 16, 0, 2352, 0, 0, 0 },
{ 96, 294, 16, 288, 2048, 4, 0, 12 },
{ 96, 294, 16, 0, 2336, 4, 0, 12 },
{ 96, 294, 16, 280, 2048, 4, 8, 12 },
{ 96, 294, 16, 0, 2328, 4, 8, 12 },
};
if ( type >= kCDSectorTypeCount ) return 0;
for ( UInt32 index = 0; index < 8; index++ )
{
if ( ((area >> index) & 0x01) )
{
if ( areaSize[type][index] == -1 ) return 0;
blockSize += areaSize[type][index];
}
}
return blockSize;
}
UInt32
IOCDBlockStorageDriver::getMediaType(void)
{
return(_mediaType);
}
CDTOC *
IOCDBlockStorageDriver::getTOC(void)
{
return(_toc);
}
bool
IOCDBlockStorageDriver::init(OSDictionary * properties)
{
if (super::init(properties) == false) {
return false;
}
_expansionData = IONew(ExpansionData, 1);
if (_expansionData == NULL) {
return false;
}
_minBlockNumberAudio = 0;
_maxBlockNumberAudio = 0;
#ifndef __LP64__
_maxReadByteTransfer = 196608;
_maxWriteByteTransfer = 196608;
#endif
_toc = NULL;
_tocSize = 0;
return(true);
}
IOMedia *
IOCDBlockStorageDriver::instantiateDesiredMediaObject(void)
{
return(new IOCDMedia);
}
IOMedia *
IOCDBlockStorageDriver::instantiateMediaObject(UInt64 base,UInt64 byteSize,
UInt32 blockSize,char *mediaName)
{
IOMedia *media;
if (blockSize) {
byteSize /= blockSize;
byteSize *= kBlockSizeCD;
blockSize = kBlockSizeCD;
}
media = super::instantiateMediaObject(base,byteSize,blockSize,mediaName);
if (media) {
const char *description = NULL;
const char *picture = NULL;
switch (getMediaType()) {
case kCDMediaTypeROM:
description = kIOCDMediaTypeROM;
picture = "CD.icns";
break;
case kCDMediaTypeR:
description = kIOCDMediaTypeR;
picture = "CD-R.icns";
break;
case kCDMediaTypeRW:
description = kIOCDMediaTypeRW;
picture = "CD-RW.icns";
break;
}
if (description) {
media->setProperty(kIOCDMediaTypeKey, description);
}
if (picture) {
OSDictionary *dictionary = OSDictionary::withCapacity(2);
OSString *identifier = OSString::withCString("com.apple.iokit.IOCDStorageFamily");
OSString *resourceFile = OSString::withCString(picture);
if (dictionary && identifier && resourceFile) {
dictionary->setObject("CFBundleIdentifier", identifier);
dictionary->setObject("IOBundleResourceFile", resourceFile);
}
media->setProperty(kIOMediaIconKey, dictionary);
if (resourceFile) {
resourceFile->release();
}
if (identifier) {
identifier->release();
}
if (dictionary) {
dictionary->release();
}
}
if (_toc) {
media->setProperty(kIOCDMediaTOCKey,(void*)_toc,_tocSize);
}
}
return media;
}
void
IOCDBlockStorageDriver::readCD(IOService *client,
UInt64 byteStart,
IOMemoryDescriptor *buffer,
CDSectorArea sectorArea,
CDSectorType sectorType,
#ifdef __LP64__
IOStorageAttributes *attributes,
IOStorageCompletion *completion)
#else
IOStorageCompletion completion)
#endif
{
assert(buffer->getDirection() == kIODirectionIn);
#ifdef __LP64__
prepareRequest(byteStart, buffer, sectorArea, sectorType, attributes, completion);
#else
prepareRequest(byteStart, buffer, sectorArea, sectorType, completion);
#endif
}
IOReturn
IOCDBlockStorageDriver::reportDiscInfo(CDDiscInfo *discInfo)
{
IOMemoryDescriptor *buffer;
IOReturn result;
UInt16 discInfoSize;
bzero(discInfo,sizeof(CDDiscInfo));
buffer = IOMemoryDescriptor::withAddress(discInfo,sizeof(CDDiscInfo),kIODirectionIn);
if (buffer == NULL) {
return(kIOReturnNoMemory);
}
result = getProvider()->readDiscInfo(buffer,&discInfoSize);
if (result != kIOReturnSuccess) {
buffer->release();
return(result);
}
buffer->release();
if (discInfoSize < sizeof(CDDiscInfo)) {
return(kIOReturnNotFound);
}
discInfoSize = OSSwapBigToHostInt16(discInfo->dataLength) + sizeof(discInfo->dataLength);
if (discInfoSize < sizeof(CDDiscInfo)) {
return(kIOReturnNotFound);
}
return(result);
}
IOReturn
IOCDBlockStorageDriver::reportTrackInfo(UInt16 track,CDTrackInfo *trackInfo)
{
IOMemoryDescriptor *buffer;
IOReturn result;
UInt16 trackInfoSize;
bzero(trackInfo,sizeof(CDTrackInfo));
buffer = IOMemoryDescriptor::withAddress(trackInfo,sizeof(CDTrackInfo),kIODirectionIn);
if (buffer == NULL) {
return(kIOReturnNoMemory);
}
result = getProvider()->readTrackInfo(buffer,track,kCDTrackInfoAddressTypeTrackNumber,&trackInfoSize);
if (result != kIOReturnSuccess) {
buffer->release();
return(result);
}
buffer->release();
if (trackInfoSize < offsetof(CDTrackInfo, lastRecordedAddress)) {
return(kIOReturnNotFound);
}
trackInfoSize = OSSwapBigToHostInt16(trackInfo->dataLength) + sizeof(trackInfo->dataLength);
if (trackInfoSize < offsetof(CDTrackInfo, lastRecordedAddress)) {
return(kIOReturnNotFound);
}
return(result);
}
void
IOCDBlockStorageDriver::prepareRequest(UInt64 byteStart,
IOMemoryDescriptor *buffer,
CDSectorArea sectorArea,
CDSectorType sectorType,
#ifdef __LP64__
IOStorageAttributes *attributes,
IOStorageCompletion *completion)
#else
IOStorageCompletion completion)
#endif
{
IOStorageCompletion completionOut;
Context * context;
if ((sectorArea & 0xFF) == 0x00 || (sectorArea & 0x05) == 0x05)
{
complete(completion, kIOReturnBadArgument);
return;
}
if (sectorType >= kCDSectorTypeCount)
{
complete(completion, kIOReturnBadArgument);
return;
}
if (sectorType == kCDSectorTypeUnknown)
{
if ((sectorArea & 0xF8) != 0x00 && (sectorArea & 0xF8) != 0xF8)
{
complete(completion, kIOReturnBadArgument);
return;
}
}
context = allocateContext();
if (context == 0)
{
complete(completion, kIOReturnNoMemory);
return;
}
if ( ( sectorArea == kCDSectorAreaUser ) &&
( sectorType == kCDSectorTypeMode1 ||
sectorType == kCDSectorTypeMode2Form1 ) )
{
context->block.size = getMediaBlockSize();
context->block.type = kBlockTypeStandard;
}
else
{
context->block.size = getMediaBlockSize(sectorArea, sectorType);
context->block.type = kBlockTypeCD;
context->block.typeSub[0] = sectorArea;
context->block.typeSub[1] = sectorType;
}
context->original.byteStart = byteStart;
context->original.buffer = buffer;
context->original.buffer->retain();
#ifdef __LP64__
if (attributes) context->request.attributes = *attributes;
if (completion) context->request.completion = *completion;
#else
context->original.completion = completion;
#endif
clock_get_uptime(&context->timeStart);
completionOut.target = this;
completionOut.action = prepareRequestCompletion;
completionOut.parameter = context;
#ifdef __LP64__
deblockRequest(byteStart, buffer, attributes, &completionOut, context);
#else
deblockRequest(byteStart, buffer, completionOut, context);
#endif
}
IOReturn
IOCDBlockStorageDriver::readISRC(UInt8 track,CDISRC isrc)
{
return(getProvider()->readISRC(track,isrc));
}
IOReturn
IOCDBlockStorageDriver::readMCN(CDMCN mcn)
{
return(getProvider()->readMCN(mcn));
}
IOReturn
IOCDBlockStorageDriver::recordMediaParameters(void)
{
IOReturn result;
result = super::recordMediaParameters();
if (result != kIOReturnSuccess) {
return(result);
}
_mediaType = getProvider()->getMediaType();
return(kIOReturnSuccess);
}
#ifndef __LP64__
IOReturn
IOCDBlockStorageDriver::setAudioVolume(UInt8 leftVolume,UInt8 rightVolume)
{
return(getProvider()->setAudioVolume(leftVolume,rightVolume));
}
#endif
IOReturn
IOCDBlockStorageDriver::getSpeed(UInt16 * kilobytesPerSecond)
{
return(getProvider()->getSpeed(kilobytesPerSecond));
}
IOReturn
IOCDBlockStorageDriver::setSpeed(UInt16 kilobytesPerSecond)
{
return(getProvider()->setSpeed(kilobytesPerSecond));
}
IOReturn
IOCDBlockStorageDriver::readTOC(IOMemoryDescriptor *buffer,CDTOCFormat format,
UInt8 formatAsTime,UInt8 trackOrSessionNumber,
UInt16 *actualByteCount)
{
return(getProvider()->readTOC(buffer,format,formatAsTime,trackOrSessionNumber,actualByteCount));
}
IOReturn
IOCDBlockStorageDriver::readDiscInfo(IOMemoryDescriptor *buffer,
UInt16 *actualByteCount)
{
return(getProvider()->readDiscInfo(buffer,actualByteCount));
}
IOReturn
IOCDBlockStorageDriver::readTrackInfo(IOMemoryDescriptor *buffer,UInt32 address,
CDTrackInfoAddressType addressType,
UInt16 *actualByteCount)
{
return(getProvider()->readTrackInfo(buffer,address,addressType,actualByteCount));
}
void
IOCDBlockStorageDriver::writeCD(IOService *client,
UInt64 byteStart,
IOMemoryDescriptor *buffer,
CDSectorArea sectorArea,
CDSectorType sectorType,
#ifdef __LP64__
IOStorageAttributes *attributes,
IOStorageCompletion *completion)
#else
IOStorageCompletion completion)
#endif
{
assert(buffer->getDirection() == kIODirectionOut);
#ifdef __LP64__
prepareRequest(byteStart, buffer, sectorArea, sectorType, attributes, completion);
#else
prepareRequest(byteStart, buffer, sectorArea, sectorType, completion);
#endif
}
#ifdef __LP64__
OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver, 0);
OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver, 1);
OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver, 2);
OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver, 3);
OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver, 4);
OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver, 5);
#else
OSMetaClassDefineReservedUsed(IOCDBlockStorageDriver, 0);
OSMetaClassDefineReservedUsed(IOCDBlockStorageDriver, 1);
OSMetaClassDefineReservedUsed(IOCDBlockStorageDriver, 2);
OSMetaClassDefineReservedUsed(IOCDBlockStorageDriver, 3);
OSMetaClassDefineReservedUsed(IOCDBlockStorageDriver, 4);
OSMetaClassDefineReservedUsed(IOCDBlockStorageDriver, 5);
#endif
OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver, 6);
OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver, 7);
OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver, 8);
OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver, 9);
OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver, 10);
OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver, 11);
OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver, 12);
OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver, 13);
OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver, 14);
OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver, 15);