Author: axeld Date: 2011-04-28 20:27:12 +0200 (Thu, 28 Apr 2011) New Revision: 41288 Changeset: https://dev.haiku-os.org/changeset/41288 Ticket: https://dev.haiku-os.org/ticket/3473 Modified: haiku/trunk/src/add-ons/kernel/file_systems/cdda/kernel_interface.cpp haiku/trunk/src/add-ons/kernel/partitioning_systems/session/Disc.cpp haiku/trunk/src/add-ons/kernel/partitioning_systems/session/Disc.h haiku/trunk/src/add-ons/kernel/partitioning_systems/session/session.cpp Log: 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. Modified: haiku/trunk/src/add-ons/kernel/file_systems/cdda/kernel_interface.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/cdda/kernel_interface.cpp 2011-04-28 18:10:42 UTC (rev 41287) +++ haiku/trunk/src/add-ons/kernel/file_systems/cdda/kernel_interface.cpp 2011-04-28 18:27:12 UTC (rev 41288) @@ -544,9 +544,9 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ { 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; Modified: haiku/trunk/src/add-ons/kernel/partitioning_systems/session/Disc.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/partitioning_systems/session/Disc.cpp 2011-04-28 18:10:42 UTC (rev 41287) +++ haiku/trunk/src/add-ons/kernel/partitioning_systems/session/Disc.cpp 2011-04-28 18:27:12 UTC (rev 41288) @@ -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 @@ 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 @@ 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 @@ } +/*! \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 @@ 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; } Modified: haiku/trunk/src/add-ons/kernel/partitioning_systems/session/Disc.h =================================================================== --- haiku/trunk/src/add-ons/kernel/partitioning_systems/session/Disc.h 2011-04-28 18:10:42 UTC (rev 41287) +++ haiku/trunk/src/add-ons/kernel/partitioning_systems/session/Disc.h 2011-04-28 18:27:12 UTC (rev 41288) @@ -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 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 @@ */ 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 Modified: haiku/trunk/src/add-ons/kernel/partitioning_systems/session/session.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/partitioning_systems/session/session.cpp 2011-04-28 18:10:42 UTC (rev 41287) +++ haiku/trunk/src/add-ons/kernel/partitioning_systems/session/session.cpp 2011-04-28 18:27:12 UTC (rev 41288) @@ -52,12 +52,17 @@ && 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; }