Now handles "sessions" with multiple "tracks" correctly.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2548 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
34a81c2f00
commit
ee072b68f7
|
@ -27,8 +27,8 @@
|
|||
#include <scsi.h>
|
||||
#include <disk_scanner/session.h>
|
||||
|
||||
//#define DBG(y) (y)
|
||||
#define DBG(y)
|
||||
#define DBG(y) (y)
|
||||
//#define DBG(y)
|
||||
|
||||
#define TRACE(x) DBG(dprintf x)
|
||||
|
||||
|
@ -351,6 +351,8 @@ cdrom_session_identify(int deviceFD, off_t deviceSize, int32 blockSize)
|
|||
}
|
||||
|
||||
// cdrom_session_get_nth_info
|
||||
/*! \todo Check that read_toc buffer was large enough on success
|
||||
*/
|
||||
static
|
||||
status_t
|
||||
cdrom_session_get_nth_info(int deviceFD, int32 index, off_t deviceSize,
|
||||
|
@ -360,9 +362,9 @@ cdrom_session_get_nth_info(int deviceFD, int32 index, off_t deviceSize,
|
|||
uchar data[2048];
|
||||
int32 session = index+1;
|
||||
|
||||
bool found_track = false;
|
||||
bool found_start = false;
|
||||
bool found_end = false;
|
||||
// bool found_track = false;
|
||||
// bool found_start = false;
|
||||
// bool found_end = false;
|
||||
|
||||
off_t start_lba = 0;
|
||||
off_t end_lba = 0;
|
||||
|
@ -372,11 +374,11 @@ cdrom_session_get_nth_info(int deviceFD, int32 index, off_t deviceSize,
|
|||
|
||||
// Attempt to read the table of contents, first in lba mode, then in msf mode
|
||||
if (!error) {
|
||||
error = read_table_of_contents(deviceFD, index+1, data, 2048, false);
|
||||
error = read_table_of_contents(deviceFD, 1, data, 2048, false);
|
||||
}
|
||||
if (error) {
|
||||
TRACE(("%s: lba read_toc failed, trying msf instead\n", kModuleDebugName));
|
||||
error = read_table_of_contents(deviceFD, index+1, data, 2048, true);
|
||||
error = read_table_of_contents(deviceFD, 1, data, 2048, true);
|
||||
}
|
||||
|
||||
// Interpret the data returned, if successful
|
||||
|
@ -384,7 +386,6 @@ cdrom_session_get_nth_info(int deviceFD, int32 index, off_t deviceSize,
|
|||
cdrom_table_of_contents_header *header;
|
||||
cdrom_full_table_of_contents_entry *entries;
|
||||
int i, count;
|
||||
int first_track = session;
|
||||
|
||||
header = (cdrom_table_of_contents_header*)data;
|
||||
entries = (cdrom_full_table_of_contents_entry*)(data+4);
|
||||
|
@ -393,45 +394,145 @@ cdrom_session_get_nth_info(int deviceFD, int32 index, off_t deviceSize,
|
|||
count = (header->length-2) / sizeof(cdrom_full_table_of_contents_entry);
|
||||
|
||||
// Check for a valid session index
|
||||
if (session < header->first || session > header->last)
|
||||
if (session < 1 || session > 99)
|
||||
error = B_ENTRY_NOT_FOUND;
|
||||
|
||||
// Extract the data of interest
|
||||
if (!error) {
|
||||
for (i = 0; i < count; i++) {
|
||||
uint32 current_session = 0; // The number given the current session
|
||||
uint32 current_toc_session = 0; // The number given the current "session"
|
||||
uint first_track = 0; // Track # of first track in "session"
|
||||
uint last_track = 0; // Track # of last track in "session"
|
||||
off_t lead_out_lba; // The address of the end of the current "session"
|
||||
enum {
|
||||
cdromStart,
|
||||
cdromFoundFirstTrack,
|
||||
cdromFoundLastTrack,
|
||||
cdromFoundLeadOut,
|
||||
cdromNeedEndLBA,
|
||||
cdromFinished,
|
||||
cdromError,
|
||||
} state = cdromStart;
|
||||
|
||||
for (i = 0; i < count && state != cdromError && state != cdromFinished; i++) {
|
||||
// We're only interested in positional info for data tracks
|
||||
if ((entries[i].control == 0x04 || entries[i].control == 0x06)
|
||||
// 0x04 == data track, digital copy prohibited
|
||||
// 0x06 == data track, digital copy allowed
|
||||
&& entries[i].adr == 0x01)
|
||||
// 0x01 == positional information
|
||||
{
|
||||
switch (entries[i].point) {
|
||||
// first track number (in pmin)
|
||||
case 0xa0:
|
||||
// PMin holds first track in session
|
||||
if (entries[i].session == session) {
|
||||
if (entries[i].session == current_toc_session+1) {
|
||||
current_toc_session++;
|
||||
first_track = entries[i].pminutes;
|
||||
found_track = true;
|
||||
state = cdromFoundFirstTrack;
|
||||
} else {
|
||||
// something screwy
|
||||
state = cdromError;
|
||||
TRACE(("%s: Point 0xA0 found in state %d\n",
|
||||
kModuleDebugName, state));
|
||||
}
|
||||
break;
|
||||
|
||||
// last track number (in pmin)
|
||||
case 0xa1:
|
||||
if (entries[i].session == current_toc_session
|
||||
&& state == cdromFoundFirstTrack)
|
||||
{
|
||||
last_track = entries[i].pminutes;
|
||||
state = cdromFoundLastTrack;
|
||||
} else {
|
||||
// something screwy
|
||||
state = cdromError;
|
||||
TRACE(("%s: Point 0xA1 found in state %d\n",
|
||||
kModuleDebugName, state));
|
||||
}
|
||||
break;
|
||||
|
||||
// start position of lead-out (in pmsf)
|
||||
case 0xa2:
|
||||
// PMSF holds end of session
|
||||
if (entries[i].session == session) {
|
||||
end_lba = msf_to_lba(make_msf_address(entries[i].pminutes,
|
||||
entries[i].pseconds, entries[i].pframes));
|
||||
found_end = true;
|
||||
if (entries[i].session == current_toc_session
|
||||
&& state == cdromFoundLastTrack)
|
||||
{
|
||||
lead_out_lba = msf_to_lba(make_msf_address(
|
||||
entries[i].pminutes,
|
||||
entries[i].pseconds,
|
||||
entries[i].pframes));
|
||||
state = cdromFoundLeadOut;
|
||||
} else {
|
||||
// something screwy
|
||||
state = cdromError;
|
||||
TRACE(("%s: Point 0xA2 found in state %d\n",
|
||||
kModuleDebugName, state));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (entries[i].session == session && entries[i].point == first_track) {
|
||||
if (!found_track) {
|
||||
TRACE(("WARNING: %s: No \"first track in session\" info found; "
|
||||
"using session as first track number\n", kModuleDebugName));
|
||||
// start position of track (in pmsf)
|
||||
if (1 <= entries[i].point && entries[i].point <= 99
|
||||
// valid track number
|
||||
&& entries[i].session == current_toc_session)
|
||||
{
|
||||
switch (state) {
|
||||
case cdromFoundLeadOut:
|
||||
current_session++;
|
||||
if ((int)current_session == session) {
|
||||
// This is the session we're interested in
|
||||
start_lba = msf_to_lba(make_msf_address(
|
||||
entries[i].pminutes,
|
||||
entries[i].pseconds,
|
||||
entries[i].pframes));
|
||||
if (entries[i].point == last_track) {
|
||||
// Hooray! This the last track in the "session", so
|
||||
// we already know the end_lba
|
||||
end_lba = lead_out_lba;
|
||||
state = cdromFinished;
|
||||
} else {
|
||||
// Damn, we have to look up the start of the next
|
||||
// track still...
|
||||
state = cdromNeedEndLBA;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case cdromNeedEndLBA:
|
||||
end_lba = msf_to_lba(make_msf_address(
|
||||
entries[i].pminutes,
|
||||
entries[i].pseconds,
|
||||
entries[i].pframes));
|
||||
state = cdromFinished;
|
||||
break;
|
||||
|
||||
default:
|
||||
// something screwy
|
||||
state = cdromError;
|
||||
TRACE(("%s: Session of interest found in state %d\n",
|
||||
kModuleDebugName, state));
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
// something screwy
|
||||
state = cdromError;
|
||||
if (entries[i].session == current_toc_session) {
|
||||
TRACE(("%s: New session encountered with track information; "
|
||||
" session == %d, previous session == %d, track == %d\n",
|
||||
kModuleDebugName, entries[i].session, current_toc_session,
|
||||
entries[i].point));
|
||||
} else {
|
||||
TRACE(("%s: Invalid track encountered: %d\n", kModuleDebugName,
|
||||
entries[i].point));
|
||||
}
|
||||
// PMSF holds start of session
|
||||
start_lba = msf_to_lba(make_msf_address(entries[i].pminutes,
|
||||
entries[i].pseconds, entries[i].pframes));
|
||||
found_start = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found_start && found_end) {
|
||||
if (state == cdromFinished) {
|
||||
TRACE(("%s: found session #%ld info\n", kModuleDebugName, session));
|
||||
sessionInfo->offset = start_lba * blockSize;
|
||||
sessionInfo->size = (end_lba - start_lba) * blockSize;
|
||||
|
@ -439,10 +540,8 @@ cdrom_session_get_nth_info(int deviceFD, int32 index, off_t deviceSize,
|
|||
sessionInfo->index = index;
|
||||
sessionInfo->flags = B_DATA_SESSION; // possibly B_AUDIO_SESSION for audio tracks?
|
||||
} else {
|
||||
TRACE(("%s: error in table of contents data: %s\n", kModuleDebugName,
|
||||
(found_start ? (found_end ? "(can't happen)" : "session end not found")
|
||||
: (found_end ? "session start not found"
|
||||
: "no session info found"))));
|
||||
TRACE(("%s: error reading table of contents, ended up in state %d\n",
|
||||
kModuleDebugName, state));
|
||||
error = B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue