mirror of
https://github.com/dkgrizzly/GreenSCSI.git
synced 2025-01-16 17:30:19 +00:00
596 lines
17 KiB
C++
Executable File
596 lines
17 KiB
C++
Executable File
#include "config.h"
|
|
#include "scsi_defs.h"
|
|
|
|
#if SUPPORT_OPTICAL
|
|
|
|
static const uint8_t SessionTOC[] =
|
|
{
|
|
0x00, // toc length, MSB
|
|
0x0A, // toc length, LSB
|
|
0x01, // First session number
|
|
0x01, // Last session number,
|
|
// TRACK 1 Descriptor
|
|
0x00, // reserved
|
|
0x14, // Q sub-channel encodes current position, Digital track
|
|
0x01, // First track number in last complete session
|
|
0x00, // Reserved
|
|
0x00,0x00,0x00,0x00 // LBA of first track in last session
|
|
};
|
|
|
|
static const uint8_t FullTOC[] =
|
|
{
|
|
0x00, // toc length, MSB
|
|
0x44, // toc length, LSB
|
|
0x01, // First session number
|
|
0x01, // Last session number,
|
|
// A0 Descriptor
|
|
0x01, // session number
|
|
0x14, // ADR/Control
|
|
0x00, // TNO
|
|
0xA0, // POINT
|
|
0x00, // Min
|
|
0x00, // Sec
|
|
0x00, // Frame
|
|
0x00, // Zero
|
|
0x01, // First Track number.
|
|
0x00, // Disc type 00 = Mode 1
|
|
0x00, // PFRAME
|
|
// A1
|
|
0x01, // session number
|
|
0x14, // ADR/Control
|
|
0x00, // TNO
|
|
0xA1, // POINT
|
|
0x00, // Min
|
|
0x00, // Sec
|
|
0x00, // Frame
|
|
0x00, // Zero
|
|
0x01, // Last Track number
|
|
0x00, // PSEC
|
|
0x00, // PFRAME
|
|
// A2
|
|
0x01, // session number
|
|
0x14, // ADR/Control
|
|
0x00, // TNO
|
|
0xA2, // POINT
|
|
0x00, // Min
|
|
0x00, // Sec
|
|
0x00, // Frame
|
|
0x00, // Zero
|
|
0x79, // LEADOUT position BCD
|
|
0x59, // leadout PSEC BCD
|
|
0x74, // leadout PFRAME BCD
|
|
// TRACK 1 Descriptor
|
|
0x01, // session number
|
|
0x14, // ADR/Control
|
|
0x00, // TNO
|
|
0x01, // Point
|
|
0x00, // Min
|
|
0x00, // Sec
|
|
0x00, // Frame
|
|
0x00, // Zero
|
|
0x00, // PMIN
|
|
0x00, // PSEC
|
|
0x00, // PFRAME
|
|
// b0
|
|
0x01, // session number
|
|
0x54, // ADR/Control
|
|
0x00, // TNO
|
|
0xB1, // POINT
|
|
0x79, // Min BCD
|
|
0x59, // Sec BCD
|
|
0x74, // Frame BCD
|
|
0x00, // Zero
|
|
0x79, // PMIN BCD
|
|
0x59, // PSEC BCD
|
|
0x74, // PFRAME BCD
|
|
// c0
|
|
0x01, // session number
|
|
0x54, // ADR/Control
|
|
0x00, // TNO
|
|
0xC0, // POINT
|
|
0x00, // Min
|
|
0x00, // Sec
|
|
0x00, // Frame
|
|
0x00, // Zero
|
|
0x00, // PMIN
|
|
0x00, // PSEC
|
|
0x00 // PFRAME
|
|
};
|
|
|
|
static const uint8_t DiscInfoBlock[] =
|
|
{
|
|
0x00, // disc info length, MSB
|
|
0x44, // disc info length, LSB
|
|
0x0e, // DiscStatus = Complete
|
|
0x01, // First Track on Disc
|
|
0x01, // Sessions on Disc (LSB)
|
|
0x01, // First Track in Last Session (LSB)
|
|
0x01, // Last Track in Last Session (LSB)
|
|
0x20, // DID_V DBC_V URU
|
|
0x00, // Disc Type
|
|
0x00, // Sessions on Disc (MSB)
|
|
0x00, // First Track in Last Session (MSB)
|
|
0x00, // Last Track in Last Session (MSB)
|
|
0x00, // DiscID (MSB)
|
|
0x00, // DiscID
|
|
0x00, // DiscID
|
|
0x00, // DiscID (LSB)
|
|
0x00, // Last Session Lead-In Start (MSB)
|
|
0x00, // IN MSF
|
|
0x00, //
|
|
0x00, // Last Session Lead-In Start (LSB)
|
|
0x00, // Last Possible Lead-Out Start (MSB)
|
|
0x00, // IN MSF
|
|
0x00, //
|
|
0x00, // Last Possible Lead-Out Start (LSB)
|
|
0x00, // Bar Code (MSB)
|
|
0x00, //
|
|
0x00, //
|
|
0x00, //
|
|
0x00, //
|
|
0x00, //
|
|
0x00, //
|
|
0x00, // Bar Code (LSB)
|
|
0x00, // Reserved
|
|
0x00, // Number of OPC Entries
|
|
};
|
|
|
|
static void LBA2MSF(uint32_t LBA, uint8_t* MSF)
|
|
{
|
|
MSF[0] = 0; // reserved.
|
|
MSF[3] = (uint32_t)(LBA % 75); // F
|
|
uint32_t rem = LBA / 75;
|
|
|
|
MSF[2] = (uint32_t)(rem % 60); // S
|
|
MSF[1] = (uint32_t)(rem / 60); // M
|
|
}
|
|
|
|
void OpticalReadSimpleTOC()
|
|
{
|
|
int MSF = m_cmd[1] & 0x02 ? 1 : 0;
|
|
uint16_t allocationLength = (m_cmd[7] << 8) | m_cmd[8];
|
|
uint8_t len = 0;
|
|
|
|
if(!m_sel) {
|
|
m_sts |= STATUS_CHECK;
|
|
m_phase = PHASE_STATUSIN;
|
|
return;
|
|
}
|
|
|
|
memset(m_responsebuffer, 0, sizeof(m_responsebuffer));
|
|
|
|
uint32_t capacity = (m_sel->m_fileSize / m_sel->m_blocksize) - 1;
|
|
m_responsebuffer[len++] = 0x00; // toc length, MSB
|
|
m_responsebuffer[len++] = 0x00; // toc length, LSB
|
|
m_responsebuffer[len++] = 0x01; // First track number
|
|
m_responsebuffer[len++] = 0x01; // Last track number
|
|
|
|
// We only support track 1 and 0xaa (lead-out).
|
|
// track 0 means "return all tracks"
|
|
switch (m_cmd[6]) {
|
|
case 0x00:
|
|
case 0x01:
|
|
m_responsebuffer[len++] = 0x00; // reserved
|
|
m_responsebuffer[len++] = 0x14; // Q sub-channel encodes current position, Digital track
|
|
m_responsebuffer[len++] = 0x01; // Track 1
|
|
m_responsebuffer[len++] = 0x00; // Reserved
|
|
m_responsebuffer[len++] = 0x00; // MSB LBA
|
|
m_responsebuffer[len++] = 0x00; //
|
|
m_responsebuffer[len++] = 0x00; //
|
|
m_responsebuffer[len++] = 0x00; // LSB LBA
|
|
case 0xAA:
|
|
m_responsebuffer[len++] = 0x00; // reserved
|
|
m_responsebuffer[len++] = 0x14; // Q sub-channel encodes current position, Digital track
|
|
m_responsebuffer[len++] = 0xAA; // Leadout Track
|
|
m_responsebuffer[len++] = 0x00; // Reserved
|
|
// Replace start of leadout track
|
|
if (MSF)
|
|
{
|
|
LBA2MSF(capacity, m_responsebuffer + len);
|
|
len+=4;
|
|
}
|
|
else
|
|
{
|
|
// Track start sector (LBA)
|
|
m_responsebuffer[len++] = capacity >> 24;
|
|
m_responsebuffer[len++] = capacity >> 16;
|
|
m_responsebuffer[len++] = capacity >> 8;
|
|
m_responsebuffer[len++] = capacity;
|
|
}
|
|
break;
|
|
default:
|
|
m_sts |= STATUS_CHECK;
|
|
m_sel->m_sense.m_key = ILLEGAL_REQUEST; // Illegal Request
|
|
m_sel->m_sense.m_code = INVALID_FIELD_IN_CDB; // Invalid field in CDB
|
|
m_sel->m_sense.m_key_specific[0] = ERROR_IN_OPCODE; // Error in Byte 6
|
|
m_sel->m_sense.m_key_specific[1] = 0x00;
|
|
m_sel->m_sense.m_key_specific[2] = 0x06;
|
|
m_phase = PHASE_STATUSIN;
|
|
}
|
|
|
|
m_responsebuffer[0] = (len >> 8) & 0xff;
|
|
m_responsebuffer[1] = len & 0xff;
|
|
|
|
// Truncate if necessary
|
|
if(allocationLength < len)
|
|
len = allocationLength;
|
|
|
|
// Send it
|
|
writeDataPhase(len, m_responsebuffer);
|
|
m_phase = PHASE_STATUSIN;
|
|
}
|
|
|
|
void OpticalReadSessionInfo()
|
|
{
|
|
// int MSF = m_cmd[1] & 0x02 ? 1 : 0;
|
|
uint16_t allocationLength = (m_cmd[7] << 8) | m_cmd[8];
|
|
uint32_t len = sizeof(SessionTOC);
|
|
memcpy(m_responsebuffer, SessionTOC, len);
|
|
|
|
// Truncate if necessary
|
|
if(allocationLength < len)
|
|
len = allocationLength;
|
|
|
|
// Send it
|
|
writeDataPhase(len, m_responsebuffer);
|
|
m_phase = PHASE_STATUSIN;
|
|
}
|
|
|
|
uint8_t fromBCD(uint8_t val)
|
|
{
|
|
return ((val >> 4) * 10) + (val & 0xF);
|
|
}
|
|
|
|
void OpticalReadFullTOC(int convertBCD)
|
|
{
|
|
uint16_t allocationLength = (m_cmd[7] << 8) | m_cmd[8];
|
|
// We only support session 1.
|
|
if (m_cmd[6] > 1) {
|
|
m_sts |= STATUS_CHECK;
|
|
m_sel->m_sense.m_key = ILLEGAL_REQUEST; // Illegal Request
|
|
m_sel->m_sense.m_code = INVALID_FIELD_IN_CDB; // Invalid field in CDB
|
|
m_sel->m_sense.m_key_specific[0] = ERROR_IN_OPCODE; // Error in Byte 6
|
|
m_sel->m_sense.m_key_specific[1] = 0x00;
|
|
m_sel->m_sense.m_key_specific[2] = 0x06;
|
|
m_phase = PHASE_STATUSIN;
|
|
return;
|
|
}
|
|
|
|
uint32_t len = sizeof(FullTOC);
|
|
memcpy(m_responsebuffer, FullTOC, len);
|
|
|
|
if (convertBCD)
|
|
{
|
|
uint32_t descriptor = 4;
|
|
while (descriptor < len)
|
|
{
|
|
int i;
|
|
for (i = 0; i < 7; ++i)
|
|
{
|
|
m_responsebuffer[descriptor + i] =
|
|
fromBCD(m_responsebuffer[descriptor + 4 + i]);
|
|
}
|
|
descriptor += 11;
|
|
}
|
|
|
|
}
|
|
|
|
// Truncate if necessary
|
|
if(allocationLength < len)
|
|
len = allocationLength;
|
|
|
|
// Send it
|
|
writeDataPhase(len, m_responsebuffer);
|
|
m_phase = PHASE_STATUSIN;
|
|
}
|
|
|
|
void OpticalReadTOCCommandHandler()
|
|
{
|
|
LOGN("[Read TOC]");
|
|
switch(m_cmd[2] & 0xf) {
|
|
case 0:
|
|
LOGN("Simple");
|
|
OpticalReadSimpleTOC();
|
|
return;
|
|
case 1:
|
|
LOGN("Session");
|
|
OpticalReadSessionInfo();
|
|
return;
|
|
case 2:
|
|
LOGN("Full 0");
|
|
OpticalReadFullTOC(0);
|
|
return;
|
|
case 3:
|
|
LOGN("Full 1");
|
|
OpticalReadFullTOC(1);
|
|
return;
|
|
}
|
|
|
|
m_sts |= STATUS_CHECK;
|
|
m_sel->m_sense.m_key = ILLEGAL_REQUEST; // Illegal Request
|
|
m_sel->m_sense.m_code = INVALID_FIELD_IN_CDB; // Invalid field in CDB
|
|
m_sel->m_sense.m_key_specific[0] = ERROR_IN_OPCODE; // Error in Byte 2
|
|
m_sel->m_sense.m_key_specific[1] = 0x00;
|
|
m_sel->m_sense.m_key_specific[2] = 0x02;
|
|
m_phase = PHASE_STATUSIN;
|
|
}
|
|
|
|
static uint8_t SimpleHeader[] =
|
|
{
|
|
0x01, // 2048byte user data, L-EC in 288 byte aux field.
|
|
0x00, // reserved
|
|
0x00, // reserved
|
|
0x00, // reserved
|
|
0x00,0x00,0x00,0x00 // Track start sector (LBA or MSF)
|
|
};
|
|
|
|
void OpticalHeaderCommandHandler()
|
|
{
|
|
uint32_t len = sizeof(SimpleHeader);
|
|
memcpy(m_responsebuffer, SimpleHeader, len);
|
|
|
|
LOGN("[Read Header]");
|
|
|
|
//int MSF = m_cmd[1] & 0x02 ? 1 : 0;
|
|
//uint32_t lba = 0;
|
|
uint16_t allocationLength = (m_cmd[7] << 8) | m_cmd[8];
|
|
|
|
// Truncate if necessary
|
|
if(allocationLength < len)
|
|
len = allocationLength;
|
|
|
|
// Send it
|
|
writeDataPhase(len, m_responsebuffer);
|
|
m_phase = PHASE_STATUSIN;
|
|
}
|
|
|
|
|
|
void OpticalReadDiscInfoCommandHandler()
|
|
{
|
|
uint16_t allocationLength = (m_cmd[7] << 8) | m_cmd[8];
|
|
uint32_t len = sizeof(DiscInfoBlock);
|
|
uint32_t capacity = (m_sel->m_fileSize / m_sel->m_blocksize) - 1;
|
|
memcpy(m_responsebuffer, DiscInfoBlock, len);
|
|
|
|
LOGN("[DiscInfo]");
|
|
|
|
// Truncate if necessary
|
|
if(allocationLength < len)
|
|
len = allocationLength;
|
|
|
|
LBA2MSF(capacity, m_responsebuffer + 20);
|
|
|
|
// Send it
|
|
writeDataPhase(len, m_responsebuffer);
|
|
m_phase = PHASE_STATUSIN;
|
|
}
|
|
|
|
uint16_t SupportedFeatures[] = {
|
|
0x0001, // Core Features
|
|
0x0003, // Removable Media
|
|
0x0010, // Random Readable
|
|
0x001D, // Reads all Media Types
|
|
0x001E, // Reads CD Structures
|
|
};
|
|
|
|
void OpticalGetConfigurationCommandHandler()
|
|
{
|
|
uint16_t sfn = (m_cmd[2] << 8) | m_cmd[3];
|
|
uint16_t allocationLength = (m_cmd[7] << 8) | m_cmd[8];
|
|
uint16_t sfnmax = (allocationLength - 8) / 4;
|
|
uint16_t sfi = 0;
|
|
uint8_t len;
|
|
|
|
LOGN("[GetConfiguration]");
|
|
|
|
memset(m_responsebuffer, 0, sizeof(m_responsebuffer));
|
|
|
|
switch(m_cmd[1] & 0x3) {
|
|
case 0: {
|
|
break;
|
|
}
|
|
case 1: {
|
|
break;
|
|
}
|
|
case 2: {
|
|
sfnmax = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
len = 8;
|
|
for(sfi = 0; (sfi < sizeof(SupportedFeatures)) && sfnmax; sfi++) {
|
|
if( SupportedFeatures[sfi] > sfn ) {
|
|
m_responsebuffer[len++] = (SupportedFeatures[sfi] >> 8) & 0xff;
|
|
m_responsebuffer[len++] = SupportedFeatures[sfi] & 0xff;
|
|
m_responsebuffer[len++] = 0;
|
|
m_responsebuffer[len++] = 0;
|
|
sfnmax--;
|
|
}
|
|
}
|
|
|
|
m_responsebuffer[0] = (len >> 24) & 0xff;
|
|
m_responsebuffer[1] = (len >> 16) & 0xff;
|
|
m_responsebuffer[2] = (len >> 8) & 0xff;
|
|
m_responsebuffer[3] = (len) & 0xff;
|
|
|
|
m_responsebuffer[6] = 0x00; // CD-ROM Profile
|
|
m_responsebuffer[7] = 0x08;
|
|
|
|
// Truncate if necessary
|
|
if(allocationLength < len)
|
|
len = allocationLength;
|
|
|
|
// Send it
|
|
writeDataPhase(len, m_responsebuffer);
|
|
m_phase = PHASE_STATUSIN;
|
|
}
|
|
|
|
|
|
void OpticalEventStatusCommandHandler()
|
|
{
|
|
uint8_t len = 0;
|
|
memset(m_responsebuffer, 0, sizeof(m_responsebuffer));
|
|
|
|
LOGN("[Read Event Status]");
|
|
|
|
if((m_cmd[1] & 1) == 0) {
|
|
m_sts |= STATUS_CHECK;
|
|
m_sel->m_sense.m_key = ILLEGAL_REQUEST; // Illegal Request
|
|
m_sel->m_sense.m_code = INVALID_FIELD_IN_CDB; // Invalid field in CDB
|
|
m_sel->m_sense.m_key_specific[0] = ERROR_IN_OPCODE; // Error in Byte 1
|
|
m_sel->m_sense.m_key_specific[1] = 0x00;
|
|
m_sel->m_sense.m_key_specific[2] = 0x01;
|
|
m_phase = PHASE_STATUSIN;
|
|
return;
|
|
}
|
|
|
|
int ncr;
|
|
for(ncr = 0; ncr < 8; ncr++) {
|
|
if(m_cmd[4] & (1<<ncr)) {
|
|
switch (ncr) {
|
|
case 1:
|
|
m_responsebuffer[len++] = 0x00; // MSB Descriptor Length
|
|
m_responsebuffer[len++] = 0x06; // LSB
|
|
m_responsebuffer[len++] = 0x02; // Operational Change Event
|
|
m_responsebuffer[len++] = 0x12; // Supported Event Class
|
|
m_responsebuffer[len++] = 0x00; // No Change
|
|
m_responsebuffer[len++] = 0x00; // Operational Status
|
|
m_responsebuffer[len++] = 0x00; // MSB Operational Change
|
|
m_responsebuffer[len++] = 0x00; // LSB
|
|
break;
|
|
case 4:
|
|
m_responsebuffer[len++] = 0x00; // MSB Descriptor Length
|
|
m_responsebuffer[len++] = 0x06; // LSB
|
|
m_responsebuffer[len++] = 0x04; // Media Change Event
|
|
m_responsebuffer[len++] = 0x12; // Supported Event Class
|
|
m_responsebuffer[len++] = 0x00; // No Change
|
|
m_responsebuffer[len++] = (!m_sel) ? 0x00 : 0x02; // Media Present
|
|
m_responsebuffer[len++] = 0x00; // Start Slot
|
|
m_responsebuffer[len++] = 0x00; // End Slot
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint16_t allocationLength = (m_cmd[7] << 8) | m_cmd[8];
|
|
|
|
// Truncate if necessary
|
|
if(allocationLength < len)
|
|
len = allocationLength;
|
|
|
|
// Send it
|
|
writeDataPhase(len, m_responsebuffer);
|
|
m_phase = PHASE_STATUSIN;
|
|
}
|
|
|
|
void OpticalLockTrayCommandHandler() {
|
|
if(m_cmd[4] & 1) {
|
|
LOGN("[Lock Tray]");
|
|
} else {
|
|
LOGN("[Unlock Tray]");
|
|
}
|
|
m_phase = PHASE_STATUSIN;
|
|
}
|
|
|
|
void OpticalReadCapacityCommandHandler() {
|
|
LOGN("[ReadCapacity]");
|
|
if(!m_sel) {
|
|
m_sts |= STATUS_CHECK; // Image file absent
|
|
m_sel->m_sense.m_key_specific[0] = 0x04;
|
|
m_sel->m_sense.m_key_specific[1] = 0x03;
|
|
m_sel->m_sense.m_key_specific[2] = 0x00;
|
|
m_sel->m_sense.m_key_specific[3] = 0x00;
|
|
m_phase = PHASE_STATUSIN;
|
|
return;
|
|
}
|
|
|
|
uint32_t bl = m_sel->m_blocksize;
|
|
uint32_t bc = m_sel->m_fileSize / bl;
|
|
uint8_t buf[8] = {
|
|
(uint8_t)(((uint32_t)(bc >> 24))&0xff), (uint8_t)(((uint32_t)(bc >> 16))&0xff), (uint8_t)(((uint32_t)(bc >> 8))&0xff), (uint8_t)(((uint32_t)(bc))&0xff),
|
|
(uint8_t)(((uint32_t)(bl >> 24))&0xff), (uint8_t)(((uint32_t)(bl >> 16))&0xff), (uint8_t)(((uint32_t)(bl >> 8))&0xff), (uint8_t)(((uint32_t)(bl))&0xff)
|
|
};
|
|
writeDataPhase(8, buf);
|
|
m_phase = PHASE_STATUSIN;
|
|
}
|
|
|
|
void ConfigureOpticalHandlers(VirtualDevice_t *vdev) {
|
|
for(int c = 0; c < 256; c++)
|
|
vdev->m_handler[c] = &UnknownCommandHandler;
|
|
|
|
vdev->m_handler[CMD_TEST_UNIT_READY] = &TestUnitCommandHandler;
|
|
vdev->m_handler[CMD_REZERO_UNIT] = &RezeroUnitCommandHandler;
|
|
vdev->m_handler[CMD_REQUEST_SENSE] = &RequestSenseCommandHandler;
|
|
vdev->m_handler[CMD_READ6] = &Read6CommandHandler;
|
|
vdev->m_handler[CMD_SEEK6] = &Seek6CommandHandler;
|
|
vdev->m_handler[CMD_INQUIRY] = &InquiryCommandHandler;
|
|
vdev->m_handler[CMD_MODE_SELECT6] = &ModeSelect6CommandHandler;
|
|
vdev->m_handler[CMD_MODE_SENSE6] = &ModeSenseCommandHandler;
|
|
vdev->m_handler[CMD_START_STOP_UNIT] = &StartStopUnitCommandHandler;
|
|
vdev->m_handler[CMD_PREVENT_REMOVAL] = &OpticalLockTrayCommandHandler;
|
|
vdev->m_handler[CMD_READ_CAPACITY10] = &OpticalReadCapacityCommandHandler;
|
|
vdev->m_handler[CMD_READ10] = &Read10CommandHandler;
|
|
vdev->m_handler[CMD_SEEK10] = &Seek10CommandHandler;
|
|
vdev->m_handler[CMD_READ_TOC] = &OpticalReadTOCCommandHandler;
|
|
vdev->m_handler[CMD_READ_HEADER] = &OpticalHeaderCommandHandler;
|
|
//vdev->m_handler[CMD_GET_CONFIGURATION] = &OpticalGetConfigurationCommandHandler;
|
|
vdev->m_handler[CMD_SEND_DIAGNOSTIC] = &SendDiagnosticCommandHandler;
|
|
vdev->m_handler[CMD_GET_EVENT_STATUS_NOTIFICATION] = &OpticalEventStatusCommandHandler;
|
|
vdev->m_handler[CMD_READ_DISC_INFORMATION] = &OpticalReadDiscInfoCommandHandler;
|
|
vdev->m_handler[CMD_MODE_SELECT10] = &ModeSelect10CommandHandler;
|
|
vdev->m_handler[CMD_MODE_SENSE10] = &ModeSenseCommandHandler;
|
|
}
|
|
|
|
// If config file exists, read the first three lines and copy the contents.
|
|
// File must be well formed or you will get junk in the SCSI Vendor fields.
|
|
void ConfigureOptical(VirtualDevice_t *vdev, const char *image_name) {
|
|
for(int i = 0; SCSI_INQUIRY_RESPONSE[i][0] != 0xff; i++) {
|
|
if(SCSI_INQUIRY_RESPONSE[i][0] == DEV_OPTICAL) {
|
|
memcpy(vdev->m_inquiryresponse, SCSI_INQUIRY_RESPONSE[i], SCSI_INQUIRY_RESPONSE_SIZE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(image_name) {
|
|
char configname[MAX_FILE_PATH+1];
|
|
memcpy(configname, image_name, MAX_FILE_PATH+1);
|
|
char *psuffix = strstr(configname, ".img");
|
|
if(psuffix) {
|
|
strcpy(psuffix, ".cfg");
|
|
} else {
|
|
sprintf(configname, "cd%d%d.cfg", vdev->m_id, vdev->m_lun);
|
|
}
|
|
|
|
FsFile config_file = sd.open(configname, O_RDONLY);
|
|
if (config_file.isOpen()) {
|
|
char vendor[9];
|
|
memset(vendor, 0, sizeof(vendor));
|
|
config_file.readBytes(vendor, sizeof(vendor));
|
|
LOGN("SCSI VENDOR: ");
|
|
LOGN(vendor);
|
|
memcpy(&(vdev->m_inquiryresponse[8]), vendor, 8);
|
|
|
|
char product[17];
|
|
memset(product, 0, sizeof(product));
|
|
config_file.readBytes(product, sizeof(product));
|
|
LOGN("SCSI PRODUCT: ");
|
|
LOGN(product);
|
|
memcpy(&(vdev->m_inquiryresponse[16]), product, 16);
|
|
|
|
char version[5];
|
|
memset(version, 0, sizeof(version));
|
|
config_file.readBytes(version, sizeof(version));
|
|
LOGN("SCSI VERSION: ");
|
|
LOGN(version);
|
|
memcpy(&(vdev->m_inquiryresponse[32]), version, 4);
|
|
config_file.close();
|
|
}
|
|
}
|
|
|
|
vdev->m_type = DEV_OPTICAL;
|
|
ConfigureOpticalHandlers(vdev);
|
|
}
|
|
|
|
#endif
|