IOATAPICDDrive.cpp [plain text]
#include <IOKit/assert.h>
#include <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/storage/ata/IOATAPICDDrive.h>
#include <IOKit/storage/ata/IOATAPICDDriveNub.h>
#define super IOATAPIHDDrive
OSDefineMetaClassAndStructors( IOATAPICDDrive, IOATAPIHDDrive )
bool
IOATAPICDDrive::matchATAPIDeviceType(UInt8 type, SInt32 * score)
{
if (type == kIOATAPIDeviceTypeCDROM)
return true;
return false;
}
IOService *
IOATAPICDDrive::instantiateNub()
{
IOService * nub = new IOATAPICDDriveNub;
return nub;
}
IOReturn
IOATAPICDDrive::reportWriteProtection(bool * isWriteProtected)
{
*isWriteProtected = true;
return kIOReturnSuccess;
}
const char *
IOATAPICDDrive::getDeviceTypeName()
{
return kIOBlockStorageDeviceTypeCDROM;
}
#define LG_DVD_ROM_DRN8080B_SUPPORT
IOReturn
IOATAPICDDrive::readTOC(IOMemoryDescriptor * buffer)
{
IOReturn ret;
IOATACommand * cmd;
assert(buffer);
#ifdef LG_DVD_ROM_DRN8080B_SUPPORT
IOMemoryDescriptor * bufferOrig = buffer;
bool isLG_DVD_ROM_DRN8080B =
( getVendorString() &&
getProductString() &&
!strcmp(getVendorString(), "LG") &&
!strcmp(getProductString(), "DVD-ROM DRN8080B") );
if (isLG_DVD_ROM_DRN8080B) {
buffer = IOBufferMemoryDescriptor::withCapacity(
max(4096, (bufferOrig->getLength()+1) & (~1)),
kIODirectionIn);
if (!buffer)
return kIOReturnNoMemory;
}
#endif LG_DVD_ROM_DRN8080B_SUPPORT
cmd = atapiCommandReadTOC(buffer, true, 2, 0);
if (!cmd)
return kIOReturnNoMemory;
ret = syncExecute(cmd);
#ifdef LG_DVD_ROM_DRN8080B_SUPPORT
if (isLG_DVD_ROM_DRN8080B) {
void * toc;
UInt16 tocSize;
ATAResults results;
cmd->getResults(&results);
toc = ((IOBufferMemoryDescriptor *)buffer)->getBytesNoCopy();
tocSize = min(results.bytesTransferred, bufferOrig->getLength());
if (bufferOrig->writeBytes(0, toc, tocSize) < bufferOrig->getLength())
ret = (ret == kIOReturnSuccess) ? kIOReturnUnderrun : ret;
else
ret = (ret == kIOReturnUnderrun) ? kIOReturnSuccess : ret;
buffer->release();
}
#endif LG_DVD_ROM_DRN8080B_SUPPORT
cmd->release();
return ret;
}
IOReturn
IOATAPICDDrive::audioPlay(CDMSF timeStart,CDMSF timeStop)
{
IOATACommand * cmd;
IOReturn ret;
cmd = atapiCommandPlayAudioMSF(timeStart, timeStop);
if (!cmd)
return kIOReturnNoMemory;
ret = syncExecute(cmd);
cmd->release();
return ret;
}
IOReturn
IOATAPICDDrive::audioPause(bool pause)
{
IOATACommand * cmd;
IOReturn ret;
cmd = atapiCommandPauseResume(!pause);
if (!cmd)
return kIOReturnNoMemory;
ret = syncExecute(cmd);
cmd->release();
return ret;
}
IOReturn
IOATAPICDDrive::audioScan(CDMSF timeStart, bool reverse)
{
IOATACommand * cmd;
IOReturn ret;
cmd = atapiCommandScan(timeStart, reverse);
if (!cmd)
return kIOReturnNoMemory;
ret = syncExecute(cmd);
cmd->release();
return ret;
}
IOReturn
IOATAPICDDrive::audioStop()
{
IOATACommand * cmd;
IOReturn ret;
cmd = atapiCommandStopPlay();
if (!cmd)
return kIOReturnNoMemory;
ret = syncExecute(cmd);
cmd->release();
return ret;
}
IOReturn
IOATAPICDDrive::getAudioVolume(UInt8 * leftVolume, UInt8 * rightVolume)
{
UInt8 audio_control[24];
IOReturn status;
status = readModeSense(audio_control,sizeof(audio_control),(UInt32)0xe);
if (status == kIOReturnSuccess) {
assert((audio_control[0] ) == 0x00);
assert((audio_control[1] ) == sizeof(audio_control) - 2);
assert((audio_control[8] & 0x3f) == 0x0e);
assert((audio_control[9] ) == 0x0e);
*leftVolume = audio_control[17];
*rightVolume = audio_control[19];
}
return status;
}
IOReturn
IOATAPICDDrive::setAudioVolume(UInt8 leftVolume, UInt8 rightVolume)
{
UInt8 audio_control[24];
IOReturn status;
status = readModeSense(audio_control,sizeof(audio_control),(UInt32)0xe);
if (status == kIOReturnSuccess) {
assert((audio_control[0] ) == 0x00);
assert((audio_control[1] ) == sizeof(audio_control) - 2);
assert((audio_control[8] & 0x3f) == 0x0e);
assert((audio_control[9] ) == 0x0e);
audio_control[17] = audio_control[21] = leftVolume;
audio_control[19] = audio_control[23] = rightVolume;
status = writeModeSelect(audio_control,sizeof(audio_control));
}
return status;
}
IOReturn
IOATAPICDDrive::readModeSense(UInt8 * buffer,
UInt32 length,
UInt8 pageCode,
UInt8 pageControl = 0)
{
IOReturn ret;
IOATACommand * cmd;
IOMemoryDescriptor * senseDesc;
assert(buffer);
senseDesc = IOMemoryDescriptor::withAddress(buffer,
length,
kIODirectionIn);
if (!senseDesc)
return kIOReturnNoMemory;
cmd = atapiCommandModeSense(senseDesc, pageCode, pageControl);
if (!cmd)
return kIOReturnNoMemory;
ret = syncExecute(cmd);
senseDesc->release();
cmd->release();
return ret;
}
IOReturn
IOATAPICDDrive::writeModeSelect(UInt8 * buffer, UInt32 length)
{
IOReturn ret;
IOATACommand * cmd;
IOMemoryDescriptor * selectDesc;
assert(buffer);
selectDesc = IOMemoryDescriptor::withAddress(buffer,
length,
kIODirectionOut);
if (!selectDesc)
return kIOReturnNoMemory;
cmd = atapiCommandModeSelect(selectDesc);
if (!cmd)
return kIOReturnNoMemory;
ret = syncExecute(cmd);
selectDesc->release();
cmd->release();
return ret;
}
IOReturn
IOATAPICDDrive::getAudioStatus(CDAudioStatus * status)
{
UInt8 * channel_data;
IOReturn ret;
channel_data = (UInt8 *)IOMalloc(16);
if (!channel_data) return kIOReturnNoMemory;
ret = readSubChannel(channel_data,16,0x01,0x00);
if (ret == kIOReturnSuccess) {
assert(channel_data[2] == 0);
assert(channel_data[3] == 12);
assert(channel_data[4] == 1);
status->status = channel_data[ 1];
status->position.track.number = channel_data[ 6];
status->position.track.index = channel_data[ 7];
status->position.time.minute = channel_data[ 9];
status->position.time.second = channel_data[10];
status->position.time.frame = channel_data[11];
status->position.track.time.minute = channel_data[13];
status->position.track.time.second = channel_data[14];
status->position.track.time.frame = channel_data[15];
}
IOFree(channel_data,16);
return ret;
}
IOReturn
IOATAPICDDrive::readMCN(CDMCN mcn)
{
UInt8 * channel_data;
IOReturn ret;
channel_data = (UInt8 *)IOMalloc(24);
if (!channel_data) return kIOReturnNoMemory;
ret = readSubChannel(channel_data,24,0x02,0x00);
if (ret == kIOReturnSuccess) {
assert(channel_data[2] == 0);
assert(channel_data[3] == 20);
assert(channel_data[4] == 2);
if ((channel_data[8] & 0x80)) {
bcopy(&channel_data[9],mcn,kCDMCNMaxLength);
mcn[kCDMCNMaxLength] = '\0';
} else {
ret = kIOReturnNotFound;
}
}
IOFree(channel_data,24);
return ret;
}
IOReturn
IOATAPICDDrive::readISRC(UInt8 track, CDISRC isrc)
{
UInt8 * channel_data;
IOReturn ret;
channel_data = (UInt8 *)IOMalloc(24);
if (!channel_data) return kIOReturnNoMemory;
ret = readSubChannel(channel_data,24,0x03,track);
if (ret == kIOReturnSuccess) {
assert(channel_data[2] == 0);
assert(channel_data[3] == 20);
assert(channel_data[4] == 3);
if ((channel_data[8] & 0x80)) {
bcopy(&channel_data[9],isrc,kCDISRCMaxLength);
isrc[kCDISRCMaxLength] = '\0';
} else {
ret = kIOReturnNotFound;
}
}
IOFree(channel_data,24);
return ret;
}
IOReturn
IOATAPICDDrive::readSubChannel(UInt8 * buffer,
UInt32 length,
UInt8 dataFormat,
UInt8 trackNumber)
{
IOReturn ret;
IOATACommand * cmd;
IOMemoryDescriptor * readDesc;
assert(buffer);
readDesc = IOMemoryDescriptor::withAddress(buffer,
length,
kIODirectionIn);
if (!readDesc)
return kIOReturnNoMemory;
cmd = atapiCommandReadSubChannel(readDesc, dataFormat, trackNumber);
if (!cmd)
return kIOReturnNoMemory;
ret = syncExecute(cmd);
readDesc->release();
cmd->release();
return ret;
}
IOReturn
IOATAPICDDrive::doAsyncReadCD(IOMemoryDescriptor * buffer,
UInt32 block,
UInt32 nblks,
CDSectorArea sectorArea,
CDSectorType sectorType,
IOStorageCompletion completion)
{
IOReturn ret;
IOATACommand * cmd;
cmd = atapiCommandReadCD(buffer,block,nblks,sectorArea,sectorType);
if (!cmd)
return kIOReturnNoMemory;
ret = asyncExecute(cmd, completion);
cmd->release();
return ret;
}