Applied cleaned up patch originally by Ziusudra as part of ticket #3473:
* Changed the session module to create an extra session for existing audio tracks. * Let cdda also recognize "audio partitions" as published by the session module. * If there is only a single session, the session module now gives file system drivers the chance to play with the device directly. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@41288 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -544,9 +544,9 @@ is_data_track(const scsi_toc_track& track)
|
||||
uint32
|
||||
count_audio_tracks(scsi_toc_toc* toc)
|
||||
{
|
||||
uint32 lastTrack = toc->last_track + 1 - toc->first_track;
|
||||
uint32 trackCount = toc->last_track + 1 - toc->first_track;
|
||||
uint32 count = 0;
|
||||
for (uint32 i = 0; i < lastTrack; i++) {
|
||||
for (uint32 i = 0; i < trackCount; i++) {
|
||||
if (!is_data_track(toc->tracks[i]))
|
||||
count++;
|
||||
}
|
||||
@@ -1330,8 +1330,10 @@ Inode::RemoveAttribute(const char* name, bool checkNamespace)
|
||||
AttrCookieList::Iterator i = fAttrCookies.GetIterator();
|
||||
while (i.HasNext()) {
|
||||
attr_cookie* cookie = i.Next();
|
||||
if (cookie->current == attribute)
|
||||
cookie->current = attribute->GetDoublyLinkedListLink()->next;
|
||||
if (cookie->current == attribute) {
|
||||
cookie->current
|
||||
= attribute->GetDoublyLinkedListLink()->next;
|
||||
}
|
||||
}
|
||||
|
||||
iterator.Remove();
|
||||
@@ -1378,11 +1380,41 @@ cdda_identify_partition(int fd, partition_data* partition, void** _cookie)
|
||||
|
||||
status_t status = read_table_of_contents(fd, toc, 2048);
|
||||
|
||||
// there has to be at least a single audio track
|
||||
if (status == B_OK && count_audio_tracks(toc) == 0)
|
||||
status = B_BAD_TYPE;
|
||||
// If we succeeded in reading the toc, check the tracks in the
|
||||
// partition, which may not be the whole CD, and if any are audio,
|
||||
// claim the partition.
|
||||
if (status == B_OK) {
|
||||
uint32 trackCount = toc->last_track + (uint32)1 - toc->first_track;
|
||||
uint64 sessionStartLBA = partition->offset / partition->block_size;
|
||||
uint64 sessionEndLBA = sessionStartLBA
|
||||
+ (partition->size / partition->block_size);
|
||||
TRACE(("cdda_identify_partition: session at %lld-%lld\n",
|
||||
sessionStartLBA, sessionEndLBA));
|
||||
status = B_ENTRY_NOT_FOUND;
|
||||
for (uint32 i = 0; i < trackCount; i++) {
|
||||
// We have to get trackLBA from track.start.time since
|
||||
// track.start.lba is useless for this.
|
||||
// This is how session gets it.
|
||||
uint64 trackLBA
|
||||
= ((toc->tracks[i].start.time.minute * kFramesPerMinute)
|
||||
+ (toc->tracks[i].start.time.second * kFramesPerSecond)
|
||||
+ toc->tracks[i].start.time.frame - 150);
|
||||
if (trackLBA >= sessionStartLBA && trackLBA < sessionEndLBA) {
|
||||
if (is_data_track(toc->tracks[i])) {
|
||||
TRACE(("cdda_identify_partition: track %ld at %lld is "
|
||||
"data\n", i + 1, trackLBA));
|
||||
status = B_BAD_TYPE;
|
||||
} else {
|
||||
TRACE(("cdda_identify_partition: track %ld at %lld is "
|
||||
"audio\n", i + 1, trackLBA));
|
||||
status = B_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (status < B_OK) {
|
||||
if (status != B_OK) {
|
||||
free(toc);
|
||||
return status;
|
||||
}
|
||||
@@ -1740,7 +1772,8 @@ cdda_read_stat(fs_volume* _volume, fs_vnode* _node, struct stat* stat)
|
||||
Volume* volume = (Volume*)_volume->private_volume;
|
||||
Inode* inode = (Inode*)_node->private_node;
|
||||
|
||||
TRACE(("cdda_read_stat: vnode %p (0x%Lx), stat %p\n", inode, inode->ID(), stat));
|
||||
TRACE(("cdda_read_stat: vnode %p (0x%Lx), stat %p\n", inode, inode->ID(),
|
||||
stat));
|
||||
|
||||
fill_stat_buffer(volume, inode, NULL, *stat);
|
||||
|
||||
@@ -1819,7 +1852,8 @@ cdda_read_dir(fs_volume* _volume, fs_vnode* _node, void* _cookie,
|
||||
Volume* volume = (Volume*)_volume->private_volume;
|
||||
Inode* inode = (Inode*)_node->private_node;
|
||||
|
||||
TRACE(("cdda_read_dir: vnode %p, cookie %p, buffer = %p, bufferSize = %ld, num = %p\n", _node, _cookie, dirent, bufferSize,_num));
|
||||
TRACE(("cdda_read_dir: vnode %p, cookie %p, buffer = %p, bufferSize = %ld,"
|
||||
" num = %p\n", _node, _cookie, buffer, bufferSize,_num));
|
||||
|
||||
if ((Inode*)_node->private_node != &volume->RootNode())
|
||||
return B_BAD_VALUE;
|
||||
@@ -1915,7 +1949,7 @@ cdda_free_dir_cookie(fs_volume* _volume, fs_vnode* _node, void* _cookie)
|
||||
{
|
||||
dir_cookie* cookie = (dir_cookie*)_cookie;
|
||||
|
||||
TRACE(("cdda_freecookie: entry vnode %p, cookie %p\n", _vnode, cookie));
|
||||
TRACE(("cdda_freecookie: entry vnode %p, cookie %p\n", _node, cookie));
|
||||
|
||||
free(cookie);
|
||||
return 0;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2009, Haiku, Inc.
|
||||
* Copyright 2003-2011, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Authors:
|
||||
@@ -86,9 +86,9 @@ public:
|
||||
|
||||
off_t start_lba;
|
||||
uint8 control;
|
||||
//!< only used to give what are probably useless warnings
|
||||
// Used to check for Yellow/Red Book mixed-mode CDs.
|
||||
uint8 adr;
|
||||
//!< only used to give what are probably useless warnings
|
||||
// only used to give what are probably useless warnings
|
||||
};
|
||||
|
||||
|
||||
@@ -548,12 +548,13 @@ Disc::Disc(int fd)
|
||||
int count;
|
||||
|
||||
header = (cdrom_table_of_contents_header*)data;
|
||||
entries = (cdrom_full_table_of_contents_entry*)(data+4);
|
||||
entries = (cdrom_full_table_of_contents_entry*)(data + 4);
|
||||
header->length = B_BENDIAN_TO_HOST_INT16(header->length);
|
||||
|
||||
count = (header->length - 2)
|
||||
/ sizeof(cdrom_full_table_of_contents_entry);
|
||||
|
||||
count = _AdjustForYellowBook(entries, count);
|
||||
error = _ParseTableOfContents(entries, count);
|
||||
// Dump();
|
||||
if (!error) {
|
||||
@@ -696,6 +697,92 @@ Disc::Dump()
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Checks for Yellow Book data tracks in audio sessions and if found
|
||||
inserts them as a new data session.
|
||||
*/
|
||||
uint32
|
||||
Disc::_AdjustForYellowBook(cdrom_full_table_of_contents_entry entries[],
|
||||
uint32 count)
|
||||
{
|
||||
uint8 foundCount = 0;
|
||||
uint8 endLBAEntry = 0;
|
||||
uint8 trackTwo = 0;
|
||||
|
||||
// Make sure TOC has only one session and that it is audio.
|
||||
bool sessionIsAudio = true;
|
||||
for (uint32 i = 0; i < count; i++) {
|
||||
if (entries[i].point == 0xa2) {
|
||||
if ((entries[i].control & kControlDataTrack) != 0) {
|
||||
sessionIsAudio = false;
|
||||
break;
|
||||
}
|
||||
foundCount++;
|
||||
endLBAEntry = i;
|
||||
}
|
||||
}
|
||||
if (!sessionIsAudio || foundCount != 1)
|
||||
return count;
|
||||
|
||||
TRACE(("%s: Single audio session, checking for data track\n",
|
||||
kModuleDebugName));
|
||||
|
||||
// See if there are any data tracks.
|
||||
for (uint32 i = 0; i < count; i++) {
|
||||
if (entries[i].point > 0 && entries[i].point < 100
|
||||
&& (entries[i].control & kControlDataTrack) != 0) {
|
||||
if (entries[i].point == 1) {
|
||||
// Create a new endLBA point for session one.
|
||||
entries[count] = entries[endLBAEntry];
|
||||
entries[count].control = entries[i].control;
|
||||
|
||||
// Get track two and use it's start as
|
||||
// the end of our new session.
|
||||
for (uint8 j = 0; j < count; j++) {
|
||||
if (entries[j].point == 2) {
|
||||
trackTwo = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
entries[count].pminutes = entries[trackTwo].pminutes;
|
||||
entries[count].pseconds = entries[trackTwo].pseconds;
|
||||
entries[count].pframes = entries[trackTwo].pframes;
|
||||
|
||||
// Change the other points to session two.
|
||||
for (uint32 j = 0; j < count; j++) {
|
||||
entries[j].session = 2;
|
||||
}
|
||||
entries[i].session = 1;
|
||||
|
||||
count++;
|
||||
TRACE(("%s: first track is data, adjusted TOC\n",
|
||||
kModuleDebugName));
|
||||
break;
|
||||
} else {
|
||||
// Change the track to session two.
|
||||
entries[i].session = 2;
|
||||
|
||||
// Create a new endLBA point for session two.
|
||||
entries[count] = entries[endLBAEntry];
|
||||
entries[count].session = 2;
|
||||
entries[count].control = entries[i].control;
|
||||
|
||||
// Use the beginning of the data track as the
|
||||
// end of the previous session.
|
||||
entries[endLBAEntry].pminutes = entries[i].pminutes;
|
||||
entries[endLBAEntry].pseconds = entries[i].pseconds;
|
||||
entries[endLBAEntry].pframes = entries[i].pframes;
|
||||
|
||||
count++;
|
||||
TRACE(("%s: last track is data, adjusted TOC\n",
|
||||
kModuleDebugName));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Reads through the given table of contents data and creates an
|
||||
unsorted, unverified (i.e. non-error-checked) list of sessions and tracks.
|
||||
*/
|
||||
@@ -813,7 +900,7 @@ Disc::_ParseTableOfContents(cdrom_full_table_of_contents_entry entries[],
|
||||
session->track_list.Add(track);
|
||||
} else {
|
||||
WARN(("%s: warning: illegal point 0x%2x found in table of "
|
||||
"contents\n", kModuleDebugName, entries[i].point));
|
||||
"contents\n", kModuleDebugName, point));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2009, Haiku, Inc.
|
||||
* Copyright 2003-2011, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Authors:
|
||||
@@ -32,27 +32,33 @@ class Session;
|
||||
*/
|
||||
class Disc {
|
||||
public:
|
||||
Disc(int fd);
|
||||
~Disc();
|
||||
Disc(int fd);
|
||||
~Disc();
|
||||
|
||||
status_t InitCheck();
|
||||
Session* GetSession(int32 index);
|
||||
status_t InitCheck();
|
||||
Session* GetSession(int32 index);
|
||||
|
||||
void Dump();
|
||||
void Dump();
|
||||
|
||||
// CDs and DVDs are required to have a block size of 2K by
|
||||
// the SCSI-3 standard
|
||||
static const int kBlockSize = 2048;
|
||||
static const int kBlockSize = 2048;
|
||||
|
||||
private:
|
||||
status_t _ParseTableOfContents(
|
||||
cdrom_full_table_of_contents_entry entries[],
|
||||
uint32 count);
|
||||
void _SortAndRemoveDuplicates();
|
||||
status_t _CheckForErrorsAndWarnings();
|
||||
uint32 _AdjustForYellowBook(
|
||||
cdrom_full_table_of_contents_entry
|
||||
entries[],
|
||||
uint32 count);
|
||||
status_t _ParseTableOfContents(
|
||||
cdrom_full_table_of_contents_entry
|
||||
entries[],
|
||||
uint32 count);
|
||||
void _SortAndRemoveDuplicates();
|
||||
status_t _CheckForErrorsAndWarnings();
|
||||
|
||||
status_t fInitStatus;
|
||||
List* fSessionList;
|
||||
private:
|
||||
status_t fInitStatus;
|
||||
List* fSessionList;
|
||||
};
|
||||
|
||||
|
||||
@@ -61,32 +67,35 @@ private:
|
||||
*/
|
||||
class Session {
|
||||
public:
|
||||
~Session();
|
||||
~Session();
|
||||
|
||||
off_t Offset() { return fOffset; }
|
||||
off_t Size() { return fSize; }
|
||||
uint32 BlockSize() { return fBlockSize; }
|
||||
int32 Index() { return fIndex; }
|
||||
uint32 Flags() { return fFlags; }
|
||||
const char* Type() { return fType; }
|
||||
off_t Offset() { return fOffset; }
|
||||
off_t Size() { return fSize; }
|
||||
uint32 BlockSize() { return fBlockSize; }
|
||||
int32 Index() { return fIndex; }
|
||||
uint32 Flags() { return fFlags; }
|
||||
const char* Type() { return fType; }
|
||||
|
||||
private:
|
||||
friend class Disc;
|
||||
|
||||
Session(off_t offset, off_t size, uint32 blockSize,
|
||||
int32 index, uint32 flags, const char* type);
|
||||
Session(off_t offset, off_t size,
|
||||
uint32 blockSize, int32 index, uint32 flags,
|
||||
const char* type);
|
||||
|
||||
Session(const Session& ref);
|
||||
// not implemented
|
||||
Session& operator=(const Session& ref);
|
||||
// not implemented
|
||||
Session(const Session& other);
|
||||
// not implemented
|
||||
Session& operator=(const Session& other);
|
||||
// not implemented
|
||||
|
||||
off_t fOffset;
|
||||
off_t fSize;
|
||||
uint32 fBlockSize;
|
||||
int32 fIndex;
|
||||
uint32 fFlags;
|
||||
char* fType;
|
||||
private:
|
||||
off_t fOffset;
|
||||
off_t fSize;
|
||||
uint32 fBlockSize;
|
||||
int32 fIndex;
|
||||
uint32 fFlags;
|
||||
char* fType;
|
||||
};
|
||||
|
||||
|
||||
#endif // _DISC_H
|
||||
|
||||
@@ -52,12 +52,17 @@ identify_partition(int fd, partition_data *partition, void **cookie)
|
||||
&& geometry.device_type == B_CD) {
|
||||
Disc *disc = new(std::nothrow) Disc(fd);
|
||||
if (disc != NULL && disc->InitCheck() == B_OK) {
|
||||
// If we have only a single session then we can let the file system
|
||||
// drivers play directly with the device.
|
||||
if (disc->GetSession(1) != NULL)
|
||||
result = 0.9f;
|
||||
else
|
||||
result = 0.1f;
|
||||
*cookie = static_cast<void*>(disc);
|
||||
result = 0.7;
|
||||
} else
|
||||
delete disc;
|
||||
}
|
||||
PRINT(("returning %ld\n", int32(result * 10000)));
|
||||
PRINT(("returning %g\n", result));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user