diff --git a/src/add-ons/kernel/partitioning_systems/session/Disc.cpp b/src/add-ons/kernel/partitioning_systems/session/Disc.cpp index 9ce2e06c4c..ecd8a786c9 100644 --- a/src/add-ons/kernel/partitioning_systems/session/Disc.cpp +++ b/src/add-ons/kernel/partitioning_systems/session/Disc.cpp @@ -1,11 +1,13 @@ -//---------------------------------------------------------------------- -// This software is part of the OpenBeOS distribution and is covered -// by the OpenBeOS license. -// -// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net -//--------------------------------------------------------------------- -/*! - \file Disc.cpp +/* + * Copyright 2003-2009, Haiku, Inc. + * Distributed under the terms of the MIT license. + * + * Authors: + * Tyler Akidau, haiku@akidau.net + */ + + +/*! \file Disc.cpp Disc class implementation, used to enumerate the CD/DVD sessions. @@ -19,6 +21,7 @@ number \c 0x2. */ + #include "Disc.h" #include @@ -26,36 +29,26 @@ #include "Debug.h" -DBG(static const char *kModuleDebugName = "session"); -//------------------------------------------------------------------------------ -// Helper function declarations -//------------------------------------------------------------------------------ +DBG(static const char* kModuleDebugName = "session"); -static -status_t -read_table_of_contents(int deviceFD, uint32 first_session, uchar *buffer, - uint16 buffer_length, bool msf); - - -//------------------------------------------------------------------------------ -// Helper class declarations -//------------------------------------------------------------------------------ /*! \brief An item that can be stored in a List object. */ struct list_item { public: - list_item(uint32 index, list_item *next = NULL) - : index(index) - , next(next) + list_item(uint32 index, list_item* next = NULL) + : + index(index), + next(next) { - }; + } - int32 index; - list_item *next; + int32 index; + list_item* next; }; + /*! \brief A simple, singly linked list. */ class List { @@ -64,7 +57,7 @@ public: ~List(); list_item* Find(int32 index) const; - void Add(list_item *item); + void Add(list_item* item); void Clear(); void SortAndRemoveDuplicates(); @@ -72,36 +65,38 @@ public: list_item* Last() const; private: - list_item *fFirst; - list_item *fLast; + list_item* fFirst; + list_item* fLast; }; -/*! \brief Keeps track of track information. - Can be stored in a List object. +/*! \brief Keeps track of track information. */ struct track : public list_item { public: - track(uint32 index, off_t startLBA, uint8 control, uint8 adr, track *next = NULL) - : list_item(index, next) - , start_lba(startLBA) - , control(control) - , adr(adr) + track(uint32 index, off_t startLBA, uint8 control, uint8 adr, + track* next = NULL) + : + list_item(index, next), + start_lba(startLBA), + control(control), + adr(adr) { } - off_t start_lba; - uint8 control; //!< only used to give what are probably useless warnings - uint8 adr; //!< only used to give what are probably useless warnings + off_t start_lba; + uint8 control; + //!< only used to give what are probably useless warnings + uint8 adr; + //!< only used to give what are probably useless warnings }; -/*! \brief Keeps track of session information. - Can be stored in a List object. +/*! \brief Keeps track of session information. */ struct session : public list_item { public: - session(uint32 index, session *next = NULL); + session(uint32 index, session* next = NULL); bool first_track_hint_is_set(); bool last_track_hint_is_set(); @@ -109,51 +104,237 @@ public: bool is_audio(); - int8 first_track_hint; - int8 last_track_hint; - int8 control; - int8 adr; - off_t end_lba; + int8 first_track_hint; + int8 last_track_hint; + int8 control; + int8 adr; + off_t end_lba; - List track_list; + List track_list; }; -//------------------------------------------------------------------------------ -// List -//------------------------------------------------------------------------------ + +// #pragma mark - Helper functions + + +#ifdef DEBUG +/* +static void +dump_scsi_command(raw_device_command* cmd) +{ + int i; + uint j; + scsi_table_of_contents_command* scsi_command + = (scsi_table_of_contents_command*)(&(cmd->command)); + + for (i = 0; i < cmd->command_length; i++) + TRACE(("%.2x,", cmd->command[i])); + TRACE(("\n")); + + TRACE(("raw_device_command:\n")); + TRACE((" command:\n")); + TRACE((" command = %d (0x%.2x)\n", scsi_command->command, + scsi_command->command)); + TRACE((" msf = %d\n", scsi_command->msf)); + TRACE((" format = %d (0x%.2x)\n", scsi_command->format, + scsi_command->format)); + TRACE((" number = %d\n", scsi_command->number)); + TRACE((" length = %d\n", + B_BENDIAN_TO_HOST_INT16(scsi_command->length))); + TRACE((" control = %d\n", scsi_command->control)); + TRACE((" command_length = %d\n", cmd->command_length)); + TRACE((" flags = %d\n", cmd->flags)); + TRACE((" scsi_status = 0x%x\n", cmd->scsi_status)); + TRACE((" cam_status = 0x%x\n", cmd->cam_status)); + TRACE((" data = %p\n", cmd->data)); + TRACE((" data_length = %ld\n", cmd->data_length)); + TRACE((" sense_data = %p\n", cmd->sense_data)); + TRACE((" sense_data_length = %ld\n", cmd->sense_data_length)); + TRACE((" timeout = %lld\n", cmd->timeout)); + TRACE(("data dump:\n")); + for (j = 0; j < 2048; j++) {//cmd->data_length; j++) { + uchar c = ((uchar*)cmd->data)[j]; + + if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') + || ('0' <= c && c <= '9')) + TRACE(("\\%c,", c)); + else + TRACE(("%.2x,", c)); + } + TRACE(("\n")); + TRACE(("sense_data dump:\n")); + for (j = 0; j < cmd->sense_data_length; j++) { + uchar c = ((uchar*)cmd->sense_data)[j]; + if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') + || ('0' <= c && c <= '9')) + TRACE(("%c", c)); + else if (c == 0) + TRACE(("_")); + else + TRACE(("-")); + } + TRACE(("\n")); +} +*/ + + +static void +dump_full_table_of_contents(uchar* data, uint16 dataLength) +{ + cdrom_table_of_contents_header* header + = (cdrom_table_of_contents_header*)data; + cdrom_full_table_of_contents_entry* entries + = (cdrom_full_table_of_contents_entry*)(data + 4); + int headerLength = B_BENDIAN_TO_HOST_INT16(header->length); + + if (dataLength < headerLength) { + TRACE(("dump_full_table_of_contents: warning, data buffer not large " + "enough (%d < %d)\n", dataLength, headerLength)); + headerLength = dataLength; + } + + TRACE(("%s: table of contents dump:\n", kModuleDebugName)); + TRACE(("--------------------------------------------------\n")); + TRACE(("header:\n")); + TRACE((" length = %d\n", header_length)); + TRACE((" first = %d\n", header->first)); + TRACE((" last = %d\n", header->last)); + + int count = (headerLength - 2) / sizeof(cdrom_full_table_of_contents_entry); + TRACE(("\n")); + TRACE(("entry count = %d\n", count)); + + for (int i = 0; i < count; i++) { + TRACE(("\n")); + TRACE(("entry #%d:\n", i)); + TRACE((" session = %d\n", entries[i].session)); + TRACE((" adr = %d\n", entries[i].adr)); + TRACE((" control = %d (%s track, copy %s)\n", entries[i].control, + (entries[i].control & kControlDataTrack ? "data" : "audio"), + (entries[i].control & kControlCopyPermitted + ? "permitted" : "prohibited"))); + TRACE((" tno = %d\n", entries[i].tno)); + TRACE((" point = %d (0x%.2x)\n", entries[i].point, + entries[i].point)); + TRACE((" minutes = %d\n", entries[i].minutes)); + TRACE((" frames = %d\n", entries[i].seconds)); + TRACE((" seconds = %d\n", entries[i].frames)); + TRACE((" zero = %d\n", entries[i].zero)); + TRACE((" pminutes = %d\n", entries[i].pminutes)); + TRACE((" pseconds = %d\n", entries[i].pseconds)); + TRACE((" pframes = %d\n", entries[i].pframes)); + TRACE((" lba = %ld\n", + msf_to_lba(make_msf_address(entries[i].pminutes, + entries[i].pseconds, entries[i].pframes)))); + } + TRACE(("--------------------------------------------------\n")); +} +#endif // DEBUG + + +static status_t +read_table_of_contents(int deviceFD, uint32 first_session, uchar* buffer, + uint16 buffer_length, bool msf) +{ + scsi_table_of_contents_command scsi_command; + raw_device_command raw_command; + const uint32 sense_data_length = 1024; + uchar sense_data[sense_data_length]; + status_t error = buffer ? B_OK : B_BAD_VALUE; + + DEBUG_INIT_ETC(NULL, ("fd: %d, buffer: %p, buffer_length: %d", + deviceFD, buffer, buffer_length)); + + if (error) + return error; + + // Init the scsi command and copy it into the "raw scsi command" + // ioctl struct + memset(raw_command.command, 0, 16); + scsi_command.command = 0x43; + scsi_command.msf = 1; + scsi_command.format = kFullTableOfContentsFormat; + scsi_command.number = first_session; + scsi_command.length = B_HOST_TO_BENDIAN_INT16(buffer_length); + scsi_command.control = 0; + scsi_command.reserved0 = scsi_command.reserved1 = scsi_command.reserved2 + = scsi_command.reserved3 = scsi_command.reserved4 + = scsi_command.reserved5 = scsi_command.reserved6 = 0; + memcpy(raw_command.command, &scsi_command, sizeof(scsi_command)); + + // Init the rest of the raw command + raw_command.command_length = 10; + raw_command.flags = kScsiFlags; + raw_command.scsi_status = 0; + raw_command.cam_status = 0; + raw_command.data = buffer; + raw_command.data_length = buffer_length; + memset(raw_command.data, 0, raw_command.data_length); + raw_command.sense_data = sense_data; + raw_command.sense_data_length = sense_data_length; + memset(raw_command.sense_data, 0, raw_command.sense_data_length); + raw_command.timeout = kScsiTimeout; + + if (ioctl(deviceFD, B_RAW_DEVICE_COMMAND, &raw_command) == 0) { + if (raw_command.scsi_status == 0 && raw_command.cam_status == 1) { + // SUCCESS!!! + DBG(dump_full_table_of_contents(buffer, buffer_length)); + } else { + error = B_FILE_ERROR; + TRACE(("%s: scsi ioctl succeeded, but scsi command failed\n", + kModuleDebugName)); + } + } else { + error = errno; + TRACE(("%s: scsi command failed with error 0x%lx\n", kModuleDebugName, + error)); + } + + return error; + +} + + +// #pragma mark - List +// TODO: get rid of this, and use the standard DoublyLinkedList + /*! \brief Creates an empty list. */ List::List() - : fFirst(NULL) - , fLast(NULL) + : + fFirst(NULL), + fLast(NULL) { } + List::~List() { Clear(); } + /*! \brief Returns the ListItem with the given index, or NULL if not found. */ list_item* List::Find(int32 index) const { // TRACE(("%s: List::Find(%ld)\n", kModuleDebugName, index)); - list_item *item = fFirst; + list_item* item = fFirst; while (item && item->index != index) { item = item->next; } return item; } + /*! \brief Adds the given item to the end of the list. \param item The item to add (may not be NULL) */ void -List::Add(list_item *item) +List::Add(list_item* item) { // TRACE(("%s: List::Add(%p)\n", kModuleDebugName, item)); if (item) { @@ -169,24 +350,27 @@ List::Add(list_item *item) } } + /*! \brief Clears the list. */ void List::Clear() { - list_item *item = fFirst; + list_item* item = fFirst; while (item) { - list_item *next = item->next; + list_item* next = item->next; delete item; item = next; } fFirst = fLast = NULL; } + /*! \brief Bubble sorts the list by index, removing any duplicates (the first instance is kept). - \todo I believe duplicate removal is actually unnecessary, but I need to verify that. + \todo I believe duplicate removal is actually unnecessary, but + I need to verify that. */ void List::SortAndRemoveDuplicates() @@ -195,9 +379,9 @@ List::SortAndRemoveDuplicates() while (!sorted) { sorted = true; - list_item *prev = NULL; - list_item *item = fFirst; - list_item *next = NULL; + list_item* prev = NULL; + list_item* item = fFirst; + list_item* next = NULL; while (item && item->next) { next = item->next; // dprintf("List::Sort: %ld -> %ld\n", item->index, next->index); @@ -222,8 +406,9 @@ List::SortAndRemoveDuplicates() } } else if (item->index == next->index) { // Duplicate indicies - TRACE(("%s: List::SortAndRemoveDuplicates: duplicate indicies found (#%ld); " - "keeping first instance\n", kModuleDebugName, item->index)); + TRACE(("%s: List::SortAndRemoveDuplicates: duplicate indicies " + "found (#%ld); keeping first instance\n", kModuleDebugName, + item->index)); item->next = next->next; delete next; next = item->next; @@ -235,36 +420,42 @@ List::SortAndRemoveDuplicates() } } + /*! \brief Returns the first item in the list, or NULL if empty */ list_item* -List::First() const { +List::First() const +{ return fFirst; } + /*! \brief Returns the last item in the list, or NULL if empty */ list_item* -List::Last() const { +List::Last() const +{ return fLast; } -//------------------------------------------------------------------------------ -// session -//------------------------------------------------------------------------------ + +// #pragma mark - session + /*! \brief Creates an unitialized session object */ -session::session(uint32 index, session *next) - : list_item(index, next) - , first_track_hint(-1) - , last_track_hint(-1) - , control(-1) - , adr(-1) - , end_lba(0) +session::session(uint32 index, session* next) + : + list_item(index, next), + first_track_hint(-1), + last_track_hint(-1), + control(-1), + adr(-1), + end_lba(0) { } + /*! \brief Returns true if the \a first_track_hint member has not been set to a legal value yet. */ @@ -274,6 +465,7 @@ session::first_track_hint_is_set() return 1 <= first_track_hint && first_track_hint <= 99; } + /*! \brief Returns true if the \a last_track_hint member has not been set to a legal value yet. */ @@ -283,6 +475,7 @@ session::last_track_hint_is_set() return 1 <= last_track_hint && last_track_hint <= 99; } + /*! \brief Returns true if the \a end_lba member has not been set to a legal value yet. @@ -296,6 +489,7 @@ session::end_lba_is_set() return end_lba > 0; } + /*! \brief Returns true if the session is flagged as being audio. If the \c control value for the session has not been set, returns @@ -307,9 +501,9 @@ session::is_audio() return end_lba_is_set() && !(control & kControlDataTrack); } -//------------------------------------------------------------------------------ -// Disc -//------------------------------------------------------------------------------ + +// #pragma mark - Disc + /*! \brief Creates a new Disc object by parsing the given table of contents entries and checking the resultant data structure for errors and @@ -319,8 +513,9 @@ session::is_audio() elsewise they will return an error code. */ Disc::Disc(int fd) - : fInitStatus(B_NO_INIT) - , fSessionList(new List) + : + fInitStatus(B_NO_INIT), + fSessionList(new List) { DEBUG_INIT_ETC("Disc", ("fd: %d", fd)); @@ -336,26 +531,28 @@ Disc::Disc(int fd) status_t error = fSessionList ? B_OK : B_NO_MEMORY; - // Attempt to read the table of contents, first in lba mode, then in msf mode - if (!error) { + // Attempt to read the table of contents, first in lba mode, then in msf + // mode + if (!error) error = read_table_of_contents(fd, 1, data, kBlockSize, false); - } if (error) { - TRACE(("%s: lba read_toc failed, trying msf instead\n", kModuleDebugName)); + TRACE(("%s: lba read_toc failed, trying msf instead\n", + kModuleDebugName)); error = read_table_of_contents(fd, 1, data, kBlockSize, true); } // Interpret the data returned, if successful if (!error) { - cdrom_table_of_contents_header *header; - cdrom_full_table_of_contents_entry *entries; + cdrom_table_of_contents_header* header; + cdrom_full_table_of_contents_entry* entries; int count; header = (cdrom_table_of_contents_header*)data; 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 = (header->length - 2) + / sizeof(cdrom_full_table_of_contents_entry); error = _ParseTableOfContents(entries, count); // Dump(); @@ -369,12 +566,15 @@ Disc::Disc(int fd) fInitStatus = error; } + /*! \brief Destroys the Disc's internal list. */ -Disc::~Disc() { +Disc::~Disc() +{ delete fSessionList; } + /*! \brief Returns \c B_OK if the object was successfully initialized, or an error code if not. */ @@ -384,6 +584,7 @@ Disc::InitCheck() return fInitStatus; } + /*! \brief Stores the info for the given session (using 0 based indicies) in the struct pointed to by \a sessionInfo. @@ -394,59 +595,60 @@ Disc::GetSession(int32 index) { DEBUG_INIT_ETC("Disc", ("index: %ld", index)); int32 counter = -1; - for (session *session = (struct session*)fSessionList->First(); - session; - session = (struct session*)session->next) - { + for (session* session = (struct session*)fSessionList->First(); session; + session = (struct session*)session->next) { if (session->is_audio()) { - counter++; // only one session per audio session + counter++; + // only one session per audio session if (counter == index) { // Found an audio session. Take the start of the first // track with the end of session. - track *track = (struct track*)session->track_list.First(); - if (track) { + track* track = (struct track*)session->track_list.First(); + if (track != NULL) { PRINT(("found session #%ld info (audio session)\n", index)); - off_t start_lba = track->start_lba; - off_t end_lba = session->end_lba; + off_t startLBA = track->start_lba; + off_t endLBA = session->end_lba; - off_t offset = start_lba * kBlockSize; - off_t size = (end_lba - start_lba) * kBlockSize; + off_t offset = startLBA * kBlockSize; + off_t size = (endLBA - startLBA) * kBlockSize; - Session *result = new Session(offset, size, kBlockSize, - index, B_PARTITION_READ_ONLY, - kPartitionTypeAudioSession); - if (!result) - PRINT(("Error allocating new Session object; out of memory!\n")); + Session* result = new Session(offset, size, kBlockSize, + index, B_PARTITION_READ_ONLY, + kPartitionTypeAudioSession); + if (result == NULL) { + PRINT(("Error allocating new Session object; out of " + "memory!\n")); + } return result; } else { - PRINT(("Error: session #%ld is an audio " - "session with no tracks!\n", index)); + PRINT(("Error: session #%ld is an audio session with no " + "tracks!\n", index)); return NULL; } } } else { - for (track *track = (struct track*)session->track_list.First(); - track; - track = (struct track*)track->next) - { + for (track* track = (struct track*)session->track_list.First(); + track; track = (struct track*)track->next) { counter++; if (counter == index) { PRINT(("found session #%ld info (data session)\n", index)); - off_t start_lba = track->start_lba; - off_t end_lba = track->next - ? ((struct track*)track->next)->start_lba - : session->end_lba; + off_t startLBA = track->start_lba; + off_t endLBA = track->next + ? ((struct track*)track->next)->start_lba + : session->end_lba; - off_t offset = start_lba * kBlockSize; - off_t size = (end_lba - start_lba) * kBlockSize; + off_t offset = startLBA * kBlockSize; + off_t size = (endLBA - startLBA) * kBlockSize; - Session *result = new Session(offset, size, kBlockSize, - index, B_PARTITION_READ_ONLY, - kPartitionTypeDataSession); - if (!result) - PRINT(("Error allocating new Session object; out of memory!\n")); + Session* result = new Session(offset, size, kBlockSize, + index, B_PARTITION_READ_ONLY, + kPartitionTypeDataSession); + if (result == NULL) { + PRINT(("Error allocating new Session object; out of " + "memory!\n")); + } return result; } } @@ -457,24 +659,27 @@ Disc::GetSession(int32 index) return NULL; } + /*! \brief Dumps a printout of the disc using TRACE. */ void Disc::Dump() { TRACE(("%s: Disc dump:\n", kModuleDebugName)); - session *session = (struct session*)fSessionList->First(); - while (session) { + session* session = (struct session*)fSessionList->First(); + while (session != NULL) { TRACE(("session %ld:\n", session->index)); TRACE((" first track hint: %d\n", session->first_track_hint)); TRACE((" last track hint: %d\n", session->last_track_hint)); TRACE((" end_lba: %lld\n", session->end_lba)); - TRACE((" control: %d (%s session, copy %s)\n", session->control, - (session->control & kControlDataTrack ? "data" : "audio"), - (session->control & kControlCopyPermitted ? "permitted" : "prohibited"))); + TRACE((" control: %d (%s session, copy %s)\n", + session->control, (session->control & kControlDataTrack + ? "data" : "audio"), + (session->control & kControlCopyPermitted + ? "permitted" : "prohibited"))); TRACE((" adr: %d\n", session->adr)); - track *track = (struct track*)session->track_list.First(); - while (track) { + track* track = (struct track*)session->track_list.First(); + while (track != NULL) { TRACE((" track %ld:\n", track->index)); TRACE((" start_lba: %lld\n", track->start_lba)); track = (struct track*)track->next; @@ -483,124 +688,125 @@ Disc::Dump() } } -/*! \brief Reads through the given table of contents data and creates an unsorted, - unverified (i.e. non-error-checked) list of sessions and tracks. + +/*! \brief Reads through the given table of contents data and creates an + unsorted, unverified (i.e. non-error-checked) list of sessions and tracks. */ status_t -Disc::_ParseTableOfContents(cdrom_full_table_of_contents_entry entries[], uint32 count) +Disc::_ParseTableOfContents(cdrom_full_table_of_contents_entry entries[], + uint32 count) { DEBUG_INIT_ETC("Disc", ("entries: %p, count: %ld", entries, count)); + for (uint32 i = 0; i < count; i++) { // Find or create the appropriate session - uint8 session_index = entries[i].session; - session *session = (struct session*)fSessionList->Find(session_index); - if (!session) { - session = new struct session(session_index); - if (!session) { + uint8 sessionIndex = entries[i].session; + session* session = (struct session*)fSessionList->Find(sessionIndex); + if (session == NULL) { + session = new struct session(sessionIndex); + if (session == NULL) return B_NO_MEMORY; - } else { - fSessionList->Add(session); - } + + fSessionList->Add(session); } uint8 point = entries[i].point; switch (point) { - // first track hint case 0xA0: if (!session->first_track_hint_is_set()) { - int8 first_track_hint = entries[i].pminutes; - if (1 <= first_track_hint && first_track_hint <= 99) { - session->first_track_hint = first_track_hint; + int8 firstTrackHint = entries[i].pminutes; + if (1 <= firstTrackHint && firstTrackHint <= 99) { + session->first_track_hint = firstTrackHint; } else { WARN(("%s: warning: illegal first track hint %d found " - "for session %d\n", kModuleDebugName, first_track_hint, - session_index)); + "for session %d\n", kModuleDebugName, + firstTrackHint, sessionIndex)); } } else { - WARN(("%s: warning: duplicated first track hint values found for" - "session %d; using first value encountered: %d", kModuleDebugName, - session_index, session->first_track_hint)); + WARN(("%s: warning: duplicated first track hint values " + "found for session %d; using first value " + "encountered: %d", kModuleDebugName, sessionIndex, + session->first_track_hint)); } break; // last track hint case 0xA1: if (!session->last_track_hint_is_set()) { - int8 last_track_hint = entries[i].pminutes; - if (1 <= last_track_hint && last_track_hint <= 99) { - session->last_track_hint = last_track_hint; + int8 lastTrackHint = entries[i].pminutes; + if (1 <= lastTrackHint && lastTrackHint <= 99) { + session->last_track_hint = lastTrackHint; } else { WARN(("%s: warning: illegal last track hint %d found " - "for session %d\n", kModuleDebugName, last_track_hint, - session_index)); + "for session %d\n", kModuleDebugName, + lastTrackHint, sessionIndex)); } } else { - WARN(("%s: warning: duplicate last track hint values found for" - "session %d; using first value encountered: %d", kModuleDebugName, - session_index, session->last_track_hint)); + WARN(("%s: warning: duplicate last track hint values found " + "for session %d; using first value encountered: %d", + kModuleDebugName, sessionIndex, + session->last_track_hint)); } break; // end of session address case 0xA2: if (!session->end_lba_is_set()) { - off_t end_lba = msf_to_lba(make_msf_address( - entries[i].pminutes, - entries[i].pseconds, - entries[i].pframes)); - if (end_lba > 0) { - session->end_lba = end_lba; + off_t endLBA = msf_to_lba(make_msf_address( + entries[i].pminutes, entries[i].pseconds, + entries[i].pframes)); + if (endLBA > 0) { + session->end_lba = endLBA; // We also grab the session's control and adr values // from this entry session->control = entries[i].control; session->adr = entries[i].adr; } else { - WARN(("%s: warning: illegal end lba %lld found " - "for session %d\n", kModuleDebugName, end_lba, - session_index)); + WARN(("%s: warning: illegal end lba %lld found for " + "session %d\n", kModuleDebugName, endLBA, + sessionIndex)); } } else { - WARN(("%s: warning: duplicate end lba values found for" - "session %d; using first value encountered: %lld", - kModuleDebugName, session_index, session->end_lba)); + WARN(("%s: warning: duplicate end lba values found for " + "session %d; using first value encountered: %lld", + kModuleDebugName, sessionIndex, session->end_lba)); } break; - // Valid, but uninteresting, points - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: - case 0xB4: - case 0xC0: - case 0xC1: - break; + // Valid, but uninteresting, points + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xC0: + case 0xC1: + break; default: // Anything else had better be a valid track number, // or it's an invalid point if (1 <= point && point <= 99) { - // Create and add the track. We'll weed out any duplicates later. - uint8 track_index = point; - off_t start_lba = msf_to_lba(make_msf_address( - entries[i].pminutes, - entries[i].pseconds, - entries[i].pframes)); - // The control and adr values grabbed here are only used later on - // to signal a warning if they don't match the corresponding values - // of the parent session. - track *track = new(nothrow) struct track(track_index, start_lba, - entries[i].control, entries[i].adr); - if (!track) { + // Create and add the track. We'll weed out any duplicates + // later. + uint8 trackIndex = point; + off_t startLBA = msf_to_lba(make_msf_address( + entries[i].pminutes, entries[i].pseconds, + entries[i].pframes)); + // The control and adr values grabbed here are only used + // later on to signal a warning if they don't match the + // corresponding values of the parent session. + track* track = new(std::nothrow) struct track(trackIndex, + startLBA, entries[i].control, entries[i].adr); + if (track == NULL) return B_NO_MEMORY; - } else { - session->track_list.Add(track); - } + + session->track_list.Add(track); } else { - WARN(("%s: warning: illegal point 0x%2x found in table of contents\n", - kModuleDebugName, entries[i].point)); + WARN(("%s: warning: illegal point 0x%2x found in table of " + "contents\n", kModuleDebugName, entries[i].point)); } break; } @@ -608,6 +814,7 @@ Disc::_ParseTableOfContents(cdrom_full_table_of_contents_entry entries[], uint32 return B_OK; } + /*! \brief Bubble sorts the session list and each session's track lists, removing all but the first of any duplicates (by index) found along the way. @@ -616,13 +823,14 @@ void Disc::_SortAndRemoveDuplicates() { fSessionList->SortAndRemoveDuplicates(); - session *session = (struct session*)fSessionList->First(); - while (session) { + session* session = (struct session*)fSessionList->First(); + while (session != NULL) { session->track_list.SortAndRemoveDuplicates(); session = (struct session*)session->next; } } + /* \brief Checks the sessions and tracks for any anomalies. Errors will return an error code, warnings will return B_OK. @@ -653,84 +861,85 @@ Disc::_CheckForErrorsAndWarnings() { int32 lastSessionIndex = 0; int32 lastTrackIndex = 0; - for (session *session = (struct session*)fSessionList->First(); - session; - session = (struct session*)session->next) - { + for (session* session = (struct session*)fSessionList->First(); session; + session = (struct session*)session->next) { // Check for errors - //----------------- // missing end lba if (!session->end_lba_is_set()) { - TRACE(("%s: Disc::_CheckForErrorsAndWarnings: error: no end of session " - "address for session #%ld\n", kModuleDebugName, session->index)); + TRACE(("%s: Disc::_CheckForErrorsAndWarnings: error: no end of " + "session address for session #%ld\n", kModuleDebugName, + session->index)); return B_ERROR; } // empty track list - track *track = (struct track*)session->track_list.First(); - if (!track) { - TRACE(("%s: Disc::_CheckForErrorsAndWarnings: error: session #%ld has no" - "tracks\n", kModuleDebugName, session->index)); + track* track = (struct track*)session->track_list.First(); + if (track == NULL) { + TRACE(("%s: Disc::_CheckForErrorsAndWarnings: error: session #%ld " + "has no tracks\n", kModuleDebugName, session->index)); return B_ERROR; } // Check for warnings - //------------------- // incorrect first track hint if (session->first_track_hint_is_set() - && session->first_track_hint != track->index) - { - TRACE(("%s: Disc::_CheckForErrorsAndWarnings: warning: session #%ld: first " - "track hint (%d) doesn't match actual first track (%ld)\n", kModuleDebugName, - session->index, session->first_track_hint, track->index)); + && session->first_track_hint != track->index) { + TRACE(("%s: Disc::_CheckForErrorsAndWarnings: warning: session " + "#%ld: first track hint (%d) doesn't match actual first track " + "(%ld)\n", kModuleDebugName, session->index, + session->first_track_hint, track->index)); } // incorrect last track hint - struct track *last = (struct track*)session->track_list.Last(); + struct track* last = (struct track*)session->track_list.Last(); if (session->last_track_hint_is_set() && last - && session->last_track_hint != last->index) - { - TRACE(("%s: Disc::_CheckForErrorsAndWarnings: warning: session #%ld: last " - "track hint (%d) doesn't match actual last track (%ld)\n", kModuleDebugName, - session->index, session->last_track_hint, last->index)); + && session->last_track_hint != last->index) { + TRACE(("%s: Disc::_CheckForErrorsAndWarnings: warning: session " + "#%ld: last track hint (%d) doesn't match actual last track " + "(%ld)\n", kModuleDebugName, session->index, + session->last_track_hint, last->index)); } // invalid session sequence - if (lastSessionIndex+1 != session->index) { - TRACE(("%s: Disc::_CheckForErrorsAndWarnings: warning: index for session #%ld " - "is out of sequence (should have been #%ld)\n", kModuleDebugName, - session->index, lastSessionIndex)); + if (lastSessionIndex + 1 != session->index) { + TRACE(("%s: Disc::_CheckForErrorsAndWarnings: warning: index for " + "session #%ld is out of sequence (should have been #%ld)\n", + kModuleDebugName, session->index, lastSessionIndex)); } lastSessionIndex = session->index; - for ( ; track; track = (struct track*)track->next) { + for (; track; track = (struct track*)track->next) { // invalid track sequence - if (lastTrackIndex+1 != track->index) { - TRACE(("%s: Disc::_CheckForErrorsAndWarnings: warning: index for track #%ld " - "is out of sequence (should have been #%ld)\n", kModuleDebugName, - track->index, lastTrackIndex)); + if (lastTrackIndex + 1 != track->index) { + TRACE(("%s: Disc::_CheckForErrorsAndWarnings: warning: index " + "for track #%ld is out of sequence (should have been " + "#%ld)\n", kModuleDebugName, track->index, lastTrackIndex)); } lastTrackIndex = track->index; // mismatched control if (track->control != session->control) { - TRACE(("%s: Disc::_CheckForErrorsAndWarnings: warning: control for track #%ld " - "(%d, %s track, copy %s) does not match control for parent session #%ld " - "(%d, %s session, copy %s)\n", kModuleDebugName, track->index, track->control, - (track->control & kControlDataTrack ? "data" : "audio"), - (track->control & kControlCopyPermitted ? "permitted" : "prohibited"), - session->index, session->control, - (session->control & kControlDataTrack ? "data" : "audio"), - (session->control & kControlCopyPermitted ? "permitted" : "prohibited"))); + TRACE(("%s: Disc::_CheckForErrorsAndWarnings: warning: control " + "for track #%ld (%d, %s track, copy %s) does not match " + "control for parent session #%ld (%d, %s session, copy " + "%s)\n", kModuleDebugName, track->index, track->control, + (track->control & kControlDataTrack ? "data" : "audio"), + (track->control & kControlCopyPermitted + ? "permitted" : "prohibited"), + session->index, session->control, + (session->control & kControlDataTrack ? "data" : "audio"), + (session->control & kControlCopyPermitted + ? "permitted" : "prohibited"))); } // mismatched adr if (track->adr != session->adr) { - TRACE(("%s: Disc::_CheckForErrorsAndWarnings: warning: adr for track #%ld " - "(adr = %d) does not match adr for parent session #%ld (adr = %d)\n", kModuleDebugName, - track->index, track->adr, session->index, session->adr)); + TRACE(("%s: Disc::_CheckForErrorsAndWarnings: warning: adr " + "for track #%ld (adr = %d) does not match adr for parent " + "session #%ld (adr = %d)\n", kModuleDebugName, track->index, + track->adr, session->index, session->adr)); } } } @@ -738,251 +947,24 @@ Disc::_CheckForErrorsAndWarnings() { return B_OK; } -//------------------------------------------------------------------------------ -// Session -//------------------------------------------------------------------------------ + +// #pragma mark - Session + Session::Session(off_t offset, off_t size, uint32 blockSize, int32 index, - uint32 flags, const char *type) - : fOffset(offset) - , fSize(size) - , fBlockSize(blockSize) - , fIndex(index) - , fFlags(flags) - , fType(strdup(type)) + uint32 flags, const char* type) + : + fOffset(offset), + fSize(size), + fBlockSize(blockSize), + fIndex(index), + fFlags(flags), + fType(strdup(type)) { } -Session::~Session() { + +Session::~Session() +{ free(fType); } - -//------------------------------------------------------------------------------ -// C functions -//------------------------------------------------------------------------------ - -/* -static -void -dump_scsi_command(raw_device_command *cmd) { - int i; - uint j; - scsi_table_of_contents_command *scsi_command = (scsi_table_of_contents_command*)(&(cmd->command)); - - for (i = 0; i < cmd->command_length; i++) - TRACE(("%.2x,", cmd->command[i])); - TRACE(("\n")); - - TRACE(("raw_device_command:\n")); - TRACE((" command:\n")); - TRACE((" command = %d (0x%.2x)\n", scsi_command->command, scsi_command->command)); - TRACE((" msf = %d\n", scsi_command->msf)); - TRACE((" format = %d (0x%.2x)\n", scsi_command->format, scsi_command->format)); - TRACE((" number = %d\n", scsi_command->number)); - TRACE((" length = %d\n", B_BENDIAN_TO_HOST_INT16(scsi_command->length))); - TRACE((" control = %d\n", scsi_command->control)); - TRACE((" command_length = %d\n", cmd->command_length)); - TRACE((" flags = %d\n", cmd->flags)); - TRACE((" scsi_status = 0x%x\n", cmd->scsi_status)); - TRACE((" cam_status = 0x%x\n", cmd->cam_status)); - TRACE((" data = %p\n", cmd->data)); - TRACE((" data_length = %ld\n", cmd->data_length)); - TRACE((" sense_data = %p\n", cmd->sense_data)); - TRACE((" sense_data_length = %ld\n", cmd->sense_data_length)); - TRACE((" timeout = %lld\n", cmd->timeout)); - TRACE(("data dump:\n")); - for (j = 0; j < 2048; j++) {//cmd->data_length; j++) { - uchar c = ((uchar*)cmd->data)[j]; - - if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9')) - TRACE(("\\%c,", c)); - else - TRACE(("%.2x,", c)); - } - TRACE(("\n")); - TRACE(("sense_data dump:\n")); - for (j = 0; j < cmd->sense_data_length; j++) { - uchar c = ((uchar*)cmd->sense_data)[j]; - if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9')) - TRACE(("%c", c)); - else if (c == 0) - TRACE(("_")); - else - TRACE(("-")); - } - TRACE(("\n")); -} -*/ - - -#ifdef DEBUG -static void -dump_full_table_of_contents(uchar *data, uint16 data_length) -{ - cdrom_table_of_contents_header *header; - cdrom_full_table_of_contents_entry *entries; - int i, count; - int header_length; - - header = (cdrom_table_of_contents_header*)data; - entries = (cdrom_full_table_of_contents_entry*)(data+4); - header_length = B_BENDIAN_TO_HOST_INT16(header->length); - if (data_length < header_length) { - TRACE(("dump_full_table_of_contents: warning, data buffer not large enough (%d < %d)\n", - data_length, header_length)); - header_length = data_length; - } - - TRACE(("%s: table of contents dump:\n", kModuleDebugName)); - TRACE(("--------------------------------------------------\n")); - TRACE(("header:\n")); - TRACE((" length = %d\n", header_length)); - TRACE((" first = %d\n", header->first)); - TRACE((" last = %d\n", header->last)); - - count = (header_length-2) / sizeof(cdrom_full_table_of_contents_entry); - TRACE(("\n")); - TRACE(("entry count = %d\n", count)); - - for (i = 0; i < count; i++) { - TRACE(("\n")); - TRACE(("entry #%d:\n", i)); - TRACE((" session = %d\n", entries[i].session)); - TRACE((" adr = %d\n", entries[i].adr)); - TRACE((" control = %d (%s track, copy %s)\n", entries[i].control, - (entries[i].control & kControlDataTrack ? "data" : "audio"), - (entries[i].control & kControlCopyPermitted ? "permitted" : "prohibited"))); - TRACE((" tno = %d\n", entries[i].tno)); - TRACE((" point = %d (0x%.2x)\n", entries[i].point, entries[i].point)); - TRACE((" minutes = %d\n", entries[i].minutes)); - TRACE((" frames = %d\n", entries[i].seconds)); - TRACE((" seconds = %d\n", entries[i].frames)); - TRACE((" zero = %d\n", entries[i].zero)); - TRACE((" pminutes = %d\n", entries[i].pminutes)); - TRACE((" pseconds = %d\n", entries[i].pseconds)); - TRACE((" pframes = %d\n", entries[i].pframes)); - TRACE((" lba = %ld\n", msf_to_lba(make_msf_address(entries[i].pminutes, - entries[i].pseconds, entries[i].pframes)))); - } - TRACE(("--------------------------------------------------\n")); -} -#endif // DEBUG - - -static status_t -read_table_of_contents(int deviceFD, uint32 first_session, uchar *buffer, - uint16 buffer_length, bool msf) -{ - scsi_table_of_contents_command scsi_command; - raw_device_command raw_command; - const uint32 sense_data_length = 1024; - uchar sense_data[sense_data_length]; - status_t error = buffer ? B_OK : B_BAD_VALUE; - - DEBUG_INIT_ETC(NULL, ("fd: %d, buffer: %p, buffer_length: %d", - deviceFD, buffer, buffer_length)); - - if (error) - return error; - - // Init the scsi command and copy it into the BeOS "raw scsi command" ioctl struct - memset(raw_command.command, 0, 16); - scsi_command.command = 0x43; - scsi_command.msf = 1; - scsi_command.format = kFullTableOfContentsFormat; - scsi_command.number = first_session; - scsi_command.length = B_HOST_TO_BENDIAN_INT16(buffer_length); - scsi_command.control = 0; - scsi_command.reserved0 = scsi_command.reserved1 = scsi_command.reserved2 - = scsi_command.reserved3 = scsi_command.reserved4 - = scsi_command.reserved5 = scsi_command.reserved6 = 0; - memcpy(raw_command.command, &scsi_command, sizeof(scsi_command)); - - // Init the rest of the raw command - raw_command.command_length = 10; - raw_command.flags = kScsiFlags; - raw_command.scsi_status = 0; - raw_command.cam_status = 0; - raw_command.data = buffer; - raw_command.data_length = buffer_length; - memset(raw_command.data, 0, raw_command.data_length); - raw_command.sense_data = sense_data; - raw_command.sense_data_length = sense_data_length; - memset(raw_command.sense_data, 0, raw_command.sense_data_length); - raw_command.timeout = kScsiTimeout; - - if (ioctl(deviceFD, B_RAW_DEVICE_COMMAND, &raw_command) == 0) { - if (raw_command.scsi_status == 0 && raw_command.cam_status == 1) { - // SUCCESS!!! - DBG(dump_full_table_of_contents(buffer, buffer_length)); - } else { - error = B_FILE_ERROR; - TRACE(("%s: scsi ioctl succeeded, but scsi command failed\n", - kModuleDebugName)); - } - } else { - error = errno; - TRACE(("%s: scsi command failed with error 0x%lx\n", kModuleDebugName, - error)); - } - - return error; - -} - -// 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, - int32 blockSize, struct session_info *sessionInfo) -{ - status_t error = sessionInfo && index >= 0 ? B_OK : B_BAD_VALUE; - uchar data[2048]; - int32 session = index+1; - - TRACE(("%s: get_nth_info(%d, %ld, %lld, %ld, %p)\n", kModuleDebugName, - deviceFD, index, deviceSize, blockSize, sessionInfo)); - - // Attempt to read the table of contents, first in lba mode, then in msf mode - if (!error) { - 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, 1, data, 2048, true); - } - - // Interpret the data returned, if successful - if (!error) { - cdrom_table_of_contents_header *header; - cdrom_full_table_of_contents_entry *entries; - int count; - - header = (cdrom_table_of_contents_header*)data; - 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); - - // Check for a valid session index - if (session < 1 || session > 99) - error = B_ENTRY_NOT_FOUND; - - // Extract the data of interest - if (!error) { - Disc disc(entries, count); - error = disc.InitCheck(); - if (!error) - error = disc.GetSessionInfo(index, blockSize, sessionInfo); - } - } - - if (error) - TRACE(("%s: get_nth error 0x%lx\n", kModuleDebugName, error)); - - return error; -} -*/ diff --git a/src/add-ons/kernel/partitioning_systems/session/Disc.h b/src/add-ons/kernel/partitioning_systems/session/Disc.h index 4103ae1757..6523ed9004 100644 --- a/src/add-ons/kernel/partitioning_systems/session/Disc.h +++ b/src/add-ons/kernel/partitioning_systems/session/Disc.h @@ -1,18 +1,14 @@ -//---------------------------------------------------------------------- -// This software is part of the OpenBeOS distribution and is covered -// by the OpenBeOS license. -// -// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net -//--------------------------------------------------------------------- -/*! - \file Disc.cpp - - Disc class, used to enumerate the CD/DVD sessions. -*/ - +/* + * Copyright 2003-2009, Haiku, Inc. + * Distributed under the terms of the MIT license. + * + * Authors: + * Tyler Akidau, haiku@akidau.net + */ #ifndef _DISC_H #define _DISC_H + #include #include #include @@ -26,62 +22,71 @@ #include "Debug.h" #include "scsi-mmc.h" + class List; class Session; + /*! \brief A class that encapsulates a complete, parsed, and error checked table of contents for a CD-ROM. */ 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(); + status_t _ParseTableOfContents( + cdrom_full_table_of_contents_entry entries[], + uint32 count); + void _SortAndRemoveDuplicates(); + status_t _CheckForErrorsAndWarnings(); - status_t fInitStatus; - List *fSessionList; + status_t fInitStatus; + List* fSessionList; }; + /*! \brief Encapsulates the pertinent information for a given session on a Disc. */ 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(const Session &ref); // not implemented - Session& operator=(const Session &ref); // not implemented - off_t fOffset; - off_t fSize; - uint32 fBlockSize; - int32 fIndex; - uint32 fFlags; - char *fType; + 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 + + off_t fOffset; + off_t fSize; + uint32 fBlockSize; + int32 fIndex; + uint32 fFlags; + char* fType; }; #endif // _DISC_H