diff options
Diffstat (limited to 'sysutils/brasero/files/patch-src_burn-medium-scsi.c')
-rw-r--r-- | sysutils/brasero/files/patch-src_burn-medium-scsi.c | 2073 |
1 files changed, 0 insertions, 2073 deletions
diff --git a/sysutils/brasero/files/patch-src_burn-medium-scsi.c b/sysutils/brasero/files/patch-src_burn-medium-scsi.c deleted file mode 100644 index 974754cdef2b..000000000000 --- a/sysutils/brasero/files/patch-src_burn-medium-scsi.c +++ /dev/null @@ -1,2073 +0,0 @@ ---- src/burn-medium-scsi.c.orig 2008-02-06 01:53:39.000000000 -0500 -+++ src/burn-medium-scsi.c 2008-02-06 01:54:19.000000000 -0500 -@@ -0,0 +1,2070 @@ -+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -+/* -+ * brasero -+ * Copyright (C) Philippe Rouquier 2007 <bonfire-app@wanadoo.fr> -+ * -+ * brasero is free software. -+ * -+ * You may redistribute it and/or modify it under the terms of the -+ * GNU General Public License, as published by the Free Software -+ * Foundation; either version 2 of the License, or (at your option) -+ * any later version. -+ * -+ * brasero is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -+ * See the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with brasero. If not, write to: -+ * The Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor -+ * Boston, MA 02110-1301, USA. -+ */ -+ -+#ifdef HAVE_CONFIG_H -+# include <config.h> -+#endif -+ -+#include <sys/types.h> -+#include <sys/stat.h> -+#include <fcntl.h> -+#include <errno.h> -+ -+#include <glib.h> -+#include <glib/gi18n-lib.h> -+ -+#include <nautilus-burn-drive.h> -+ -+#include "burn-basics.h" -+#include "burn-debug.h" -+#include "burn-medium.h" -+#include "scsi-mmc1.h" -+#include "scsi-mmc2.h" -+#include "scsi-mmc3.h" -+#include "scsi-spc1.h" -+#include "scsi-utils.h" -+#include "scsi-mode-pages.h" -+#include "scsi-status-page.h" -+#include "scsi-q-subchannel.h" -+#include "scsi-dvd-structures.h" -+#include "burn-volume.h" -+#include "brasero-ncb.h" -+ -+const gchar *icons [] = { "gnome-dev-removable", -+ "gnome-dev-cdrom", -+ "gnome-dev-disc-cdr", -+ "gnome-dev-disc-cdrw", -+ "gnome-dev-disc-dvdrom", -+ "gnome-dev-disc-dvdr", -+ "gnome-dev-disc-dvdrw", -+ "gnome-dev-disc-dvdr-plus", -+ "gnome-dev-disc-dvdram", -+ NULL }; -+const gchar *types [] = { N_("file"), -+ N_("CDROM"), -+ N_("CD-R"), -+ N_("CD-RW"), -+ N_("DVDROM"), -+ N_("DVD-R"), -+ N_("DVD-RW"), -+ N_("DVD+R"), -+ N_("DVD+RW"), -+ N_("DVD+R dual layer"), -+ N_("DVD+RW dual layer"), -+ N_("DVD-R dual layer"), -+ N_("DVD-RAM"), -+ N_("Blu-ray disc"), -+ N_("Writable Blu-ray disc"), -+ N_("Rewritable Blu-ray disc"), -+ NULL }; -+ -+ -+typedef struct _BraseroMediumPrivate BraseroMediumPrivate; -+struct _BraseroMediumPrivate -+{ -+ gint retry_id; -+ -+ GSList * tracks; -+ -+ const gchar *type; -+ const gchar *icon; -+ -+ gint max_rd; -+ gint max_wrt; -+ -+ gint *rd_speeds; -+ gint *wr_speeds; -+ -+ gint64 block_num; -+ gint64 block_size; -+ -+ guint64 next_wr_add; -+ BraseroMedia info; -+ NautilusBurnDrive * drive; -+}; -+ -+#define BRASERO_MEDIUM_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_MEDIUM, BraseroMediumPrivate)) -+ -+/** -+ * Try to open the drive exclusively but don't block; if drive can't be opened -+ * exclusively then retry every second until we're shut or the drive state -+ * changes to not busy. -+ * No exclusive at the moment since when the medium is mounted we can't use excl -+ */ -+ -+#define OPEN_FLAGS O_RDONLY /*|O_EXCL */|O_NONBLOCK -+#define BUSY_RETRY_TIME 1000 -+ -+enum -+{ -+ PROP_0, -+ PROP_DRIVE -+}; -+ -+static GObjectClass* parent_class = NULL; -+ -+const gchar * -+brasero_medium_get_type_string (BraseroMedium *medium) -+{ -+ BraseroMediumPrivate *priv; -+ -+ priv = BRASERO_MEDIUM_PRIVATE (medium); -+ return priv->type; -+} -+ -+const gchar * -+brasero_medium_get_icon (BraseroMedium *medium) -+{ -+ BraseroMediumPrivate *priv; -+ -+ priv = BRASERO_MEDIUM_PRIVATE (medium); -+ return priv->icon; -+} -+ -+BraseroMedia -+brasero_medium_get_status (BraseroMedium *medium) -+{ -+ BraseroMediumPrivate *priv; -+ -+ priv = BRASERO_MEDIUM_PRIVATE (medium); -+ return priv->info; -+} -+ -+GSList * -+brasero_medium_get_tracks (BraseroMedium *medium) -+{ -+ BraseroMediumPrivate *priv; -+ -+ priv = BRASERO_MEDIUM_PRIVATE (medium); -+ return g_slist_copy (priv->tracks); -+} -+ -+gboolean -+brasero_medium_get_last_data_track_address (BraseroMedium *medium, -+ gint64 *byte, -+ gint64 *sector) -+{ -+ GSList *iter; -+ BraseroMediumPrivate *priv; -+ BraseroMediumTrack *track = NULL; -+ -+ priv = BRASERO_MEDIUM_PRIVATE (medium); -+ -+ for (iter = priv->tracks; iter; iter = iter->next) { -+ BraseroMediumTrack *current; -+ -+ current = iter->data; -+ if (current->type & BRASERO_MEDIUM_TRACK_DATA) -+ track = current; -+ } -+ -+ if (!track) { -+ if (byte) -+ *byte = -1; -+ if (sector) -+ *sector = -1; -+ return FALSE; -+ } -+ -+ if (byte) -+ *byte = track->start * priv->block_size; -+ -+ if (sector) -+ *sector = track->start; -+ -+ return TRUE; -+} -+ -+gboolean -+brasero_medium_get_last_data_track_space (BraseroMedium *medium, -+ gint64 *size, -+ gint64 *blocks) -+{ -+ GSList *iter; -+ BraseroMediumPrivate *priv; -+ BraseroMediumTrack *track = NULL; -+ -+ priv = BRASERO_MEDIUM_PRIVATE (medium); -+ -+ for (iter = priv->tracks; iter; iter = iter->next) { -+ BraseroMediumTrack *current; -+ -+ current = iter->data; -+ if (current->type & BRASERO_MEDIUM_TRACK_DATA) -+ track = current; -+ } -+ -+ if (!track) { -+ if (size) -+ *size = -1; -+ if (blocks) -+ *blocks = -1; -+ return FALSE; -+ } -+ -+ if (size) -+ *size = track->blocks_num * priv->block_size; -+ if (blocks) -+ *blocks = track->blocks_num; -+ -+ return TRUE; -+} -+ -+guint -+brasero_medium_get_track_num (BraseroMedium *medium) -+{ -+ guint retval = 0; -+ GSList *iter; -+ BraseroMediumPrivate *priv; -+ -+ priv = BRASERO_MEDIUM_PRIVATE (medium); -+ for (iter = priv->tracks; iter; iter = iter->next) { -+ BraseroMediumTrack *current; -+ -+ current = iter->data; -+ if (current->type & BRASERO_MEDIUM_TRACK_LEADOUT) -+ break; -+ -+ retval ++; -+ } -+ -+ return retval; -+} -+ -+static BraseroMediumTrack * -+brasero_medium_get_track (BraseroMedium *medium, -+ guint num) -+{ -+ guint i = 1; -+ GSList *iter; -+ BraseroMediumPrivate *priv; -+ -+ priv = BRASERO_MEDIUM_PRIVATE (medium); -+ -+ for (iter = priv->tracks; iter; iter = iter->next) { -+ BraseroMediumTrack *current; -+ -+ current = iter->data; -+ if (current->type == BRASERO_MEDIUM_TRACK_LEADOUT) -+ break; -+ -+ if (i == num) -+ return current; -+ -+ i++; -+ } -+ -+ return NULL; -+} -+ -+gboolean -+brasero_medium_get_track_space (BraseroMedium *medium, -+ guint num, -+ gint64 *size, -+ gint64 *blocks) -+{ -+ BraseroMediumPrivate *priv; -+ BraseroMediumTrack *track; -+ -+ priv = BRASERO_MEDIUM_PRIVATE (medium); -+ -+ track = brasero_medium_get_track (medium, num); -+ if (!track) { -+ if (size) -+ *size = -1; -+ if (blocks) -+ *blocks = -1; -+ return FALSE; -+ } -+ -+ if (size) -+ *size = track->blocks_num * priv->block_size; -+ if (blocks) -+ *blocks = track->blocks_num; -+ -+ return TRUE; -+} -+ -+gboolean -+brasero_medium_get_track_address (BraseroMedium *medium, -+ guint num, -+ gint64 *byte, -+ gint64 *sector) -+{ -+ BraseroMediumPrivate *priv; -+ BraseroMediumTrack *track; -+ -+ priv = BRASERO_MEDIUM_PRIVATE (medium); -+ -+ track = brasero_medium_get_track (medium, num); -+ if (!track) { -+ if (byte) -+ *byte = -1; -+ if (sector) -+ *sector = -1; -+ return FALSE; -+ } -+ -+ if (byte) -+ *byte = track->start * priv->block_size; -+ if (sector) -+ *sector = track->start; -+ -+ return TRUE; -+} -+ -+gint64 -+brasero_medium_get_next_writable_address (BraseroMedium *medium) -+{ -+ BraseroMediumPrivate *priv; -+ -+ priv = BRASERO_MEDIUM_PRIVATE (medium); -+ return priv->next_wr_add; -+} -+ -+gint64 -+brasero_medium_get_max_write_speed (BraseroMedium *medium) -+{ -+ BraseroMediumPrivate *priv; -+ -+ priv = BRASERO_MEDIUM_PRIVATE (medium); -+ return priv->max_wrt * 1024; -+} -+ -+/** -+ * NOTEs about the following functions: -+ * for all closed media (including ROM types) capacity == size of data and -+ * should be the size of all data on the disc, free space is 0 -+ * for all blank -R types capacity == free space and size of data == 0 -+ * for all multisession -R types capacity == free space since having the real -+ * capacity of the media would be useless as we can only use this type of media -+ * to append more data -+ * for all -RW types capacity = free space + size of data. Here they can be -+ * appended (use free space) or rewritten (whole capacity). -+ * -+ * Usually: -+ * the free space is the size of the leadout track -+ * the size of data is the sum of track sizes (excluding leadout) -+ * the capacity depends on the media: -+ * for closed discs == sum of track sizes -+ * for multisession discs == free space (leadout size) -+ * for blank discs == (free space) leadout size -+ * for rewritable/blank == use SCSI functions to get capacity (see below) -+ * -+ * In fact we should really need the size of data in DVD+/-RW cases since the -+ * session is always equal to the size of the disc. -+ */ -+ -+void -+brasero_medium_get_data_size (BraseroMedium *medium, -+ gint64 *size, -+ gint64 *blocks) -+{ -+ GSList *iter; -+ BraseroMediumPrivate *priv; -+ BraseroMediumTrack *track = NULL; -+ -+ priv = BRASERO_MEDIUM_PRIVATE (medium); -+ -+ if (!priv->tracks) { -+ /* that's probably because it wasn't possible to retrieve info */ -+ if (size) -+ *size = 0; -+ -+ if (blocks) -+ *blocks = 0; -+ -+ return; -+ } -+ -+ for (iter = priv->tracks; iter; iter = iter->next) { -+ BraseroMediumTrack *tmp; -+ -+ tmp = iter->data; -+ if (tmp->type == BRASERO_MEDIUM_TRACK_LEADOUT) -+ break; -+ -+ track = iter->data; -+ } -+ -+ if (size) -+ *size = track ? (track->start + track->blocks_num) * priv->block_size: 0; -+ -+ if (blocks) -+ *blocks = track ? track->start + track->blocks_num: 0; -+} -+ -+void -+brasero_medium_get_free_space (BraseroMedium *medium, -+ gint64 *size, -+ gint64 *blocks) -+{ -+ GSList *iter; -+ BraseroMediumPrivate *priv; -+ BraseroMediumTrack *track = NULL; -+ -+ priv = BRASERO_MEDIUM_PRIVATE (medium); -+ -+ if (!priv->tracks) { -+ /* that's probably because it wasn't possible to retrieve info. -+ * maybe it also happens with unformatted DVD+RW */ -+ -+ if (priv->info & BRASERO_MEDIUM_CLOSED) { -+ if (size) -+ *size = 0; -+ -+ if (blocks) -+ *blocks = 0; -+ } -+ else { -+ if (size) -+ *size = priv->block_num * priv->block_size; -+ -+ if (blocks) -+ *blocks = priv->block_num; -+ } -+ -+ return; -+ } -+ -+ for (iter = priv->tracks; iter; iter = iter->next) { -+ BraseroMediumTrack *tmp; -+ -+ tmp = iter->data; -+ if (tmp->type == BRASERO_MEDIUM_TRACK_LEADOUT) { -+ track = iter->data; -+ break; -+ } -+ } -+ -+ if (size) { -+ if (!track) { -+ /* No leadout was found so the disc is probably closed: -+ * no free space left. */ -+ *size = 0; -+ } -+ else if (track->blocks_num <= 0) -+ *size = (priv->block_num - track->start) * priv->block_size; -+ else -+ *size = track->blocks_num * priv->block_size; -+ } -+ -+ if (blocks) { -+ if (!track) { -+ /* No leadout was found so the disc is probably closed: -+ * no free space left. */ -+ *blocks = 0; -+ } -+ else if (track->blocks_num <= 0) -+ *blocks = priv->block_num - track->blocks_num; -+ else -+ *blocks = track->blocks_num; -+ } -+} -+ -+void -+brasero_medium_get_capacity (BraseroMedium *medium, -+ gint64 *size, -+ gint64 *blocks) -+{ -+ BraseroMediumPrivate *priv; -+ -+ priv = BRASERO_MEDIUM_PRIVATE (medium); -+ -+ if (priv->info & BRASERO_MEDIUM_REWRITABLE) { -+ if (size) -+ *size = priv->block_num * priv->block_size; -+ -+ if (blocks) -+ *blocks = priv->block_num; -+ } -+ else if (priv->info & BRASERO_MEDIUM_CLOSED) -+ brasero_medium_get_data_size (medium, size, blocks); -+ else -+ brasero_medium_get_free_space (medium, size, blocks); -+} -+ -+/** -+ * Function to retrieve the capacity of a media -+ */ -+ -+static BraseroBurnResult -+brasero_medium_get_capacity_CD_RW (BraseroMedium *self, -+ int fd, -+ BraseroScsiErrCode *code) -+{ -+ BraseroScsiAtipData *atip_data = NULL; -+ BraseroMediumPrivate *priv; -+ BraseroScsiResult result; -+ int size = 0; -+ -+ priv = BRASERO_MEDIUM_PRIVATE (self); -+ -+ BRASERO_BURN_LOG ("Retrieving capacity from atip"); -+ -+ result = brasero_mmc1_read_atip (fd, -+ &atip_data, -+ &size, -+ NULL); -+ -+ if (result != BRASERO_SCSI_OK) { -+ BRASERO_BURN_LOG ("READ ATIP failed (scsi error)"); -+ return BRASERO_BURN_ERR; -+ } -+ -+ /* check the size of the structure: it must be at least 16 bytes long */ -+ if (size < 16) { -+ if (size) -+ g_free (atip_data); -+ -+ BRASERO_BURN_LOG ("READ ATIP failed (wrong size)"); -+ return BRASERO_BURN_ERR; -+ } -+ -+ priv->block_num = BRASERO_MSF_TO_LBA (atip_data->desc->leadout_mn, -+ atip_data->desc->leadout_sec, -+ atip_data->desc->leadout_frame); -+ g_free (atip_data); -+ -+ BRASERO_BURN_LOG ("Format capacity %lli %lli", -+ priv->block_num, -+ priv->block_size); -+ -+ return BRASERO_BURN_OK; -+} -+ -+static BraseroBurnResult -+brasero_medium_get_capacity_DVD_RW (BraseroMedium *self, -+ int fd, -+ BraseroScsiErrCode *code) -+{ -+ BraseroScsiFormatCapacitiesHdr *hdr = NULL; -+ BraseroScsiMaxCapacityDesc *current; -+ BraseroMediumPrivate *priv; -+ BraseroScsiResult result; -+ gint size; -+ -+ BRASERO_BURN_LOG ("Retrieving format capacity"); -+ -+ priv = BRASERO_MEDIUM_PRIVATE (self); -+ result = brasero_mmc2_read_format_capacities (fd, -+ &hdr, -+ &size, -+ code); -+ if (result != BRASERO_SCSI_OK) { -+ g_free (hdr); -+ -+ BRASERO_BURN_LOG ("READ FORMAT CAPACITIES failed"); -+ return BRASERO_BURN_ERR; -+ } -+ -+ current = hdr->max_caps; -+ -+ /* see if the media is already formatted */ -+ if (current->type != BRASERO_SCSI_DESC_FORMATTED) { -+ int i, max; -+ BraseroScsiFormattableCapacityDesc *desc; -+ -+ max = (hdr->len - -+ sizeof (BraseroScsiMaxCapacityDesc)) / -+ sizeof (BraseroScsiFormattableCapacityDesc); -+ -+ desc = hdr->desc; -+ for (i = 0; i < max; i ++, desc ++) { -+ /* search for the correct descriptor */ -+ if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DVDRW_PLUS)) { -+ if (desc->format_type == BRASERO_SCSI_DVDRW_PLUS) { -+ priv->block_num = BRASERO_GET_32 (desc->blocks_num); -+ priv->block_size = BRASERO_GET_24 (desc->type_param); -+ -+ /* that can happen */ -+ if (!priv->block_size) -+ priv->block_size = 2048; -+ break; -+ } -+ } -+ else if (desc->format_type == BRASERO_SCSI_BLOCK_SIZE_DEFAULT_AND_DB) { -+ priv->block_num = BRASERO_GET_32 (desc->blocks_num); -+ priv->block_size = BRASERO_GET_24 (desc->type_param); -+ break; -+ } -+ } -+ } -+ else { -+ priv->block_num = BRASERO_GET_32 (current->blocks_num); -+ priv->block_size = BRASERO_GET_24 (current->block_size); -+ } -+ -+ BRASERO_BURN_LOG ("Format capacity %lli %lli", -+ priv->block_num, -+ priv->block_size); -+ -+ g_free (hdr); -+ return BRASERO_BURN_OK; -+} -+ -+static BraseroBurnResult -+brasero_medium_get_capacity_by_type (BraseroMedium *self, -+ int fd, -+ BraseroScsiErrCode *code) -+{ -+ BraseroMediumPrivate *priv; -+ -+ priv = BRASERO_MEDIUM_PRIVATE (self); -+ -+ priv->block_size = 2048; -+ -+ if (!(priv->info & BRASERO_MEDIUM_REWRITABLE)) -+ return BRASERO_BURN_OK; -+ -+ if (priv->info & BRASERO_MEDIUM_CD) -+ brasero_medium_get_capacity_CD_RW (self, fd, code); -+ else -+ brasero_medium_get_capacity_DVD_RW (self, fd, code); -+ -+ return BRASERO_BURN_OK; -+} -+ -+/** -+ * Functions to retrieve the speed -+ */ -+ -+static BraseroBurnResult -+brasero_medium_get_speed_mmc3 (BraseroMedium *self, -+ int fd, -+ BraseroScsiErrCode *code) -+{ -+ int size; -+ int num_desc, i; -+ gint max_rd, max_wrt; -+ BraseroScsiResult result; -+ BraseroMediumPrivate *priv; -+ BraseroScsiWrtSpdDesc *desc; -+ BraseroScsiGetPerfData *wrt_perf = NULL; -+ -+ BRASERO_BURN_LOG ("Retrieving speed (Get Performance)"); -+ -+ /* NOTE: this only work if there is RT streaming feature with -+ * wspd bit set to 1. At least an MMC3 drive. */ -+ priv = BRASERO_MEDIUM_PRIVATE (self); -+ result = brasero_mmc3_get_performance_wrt_spd_desc (fd, -+ &wrt_perf, -+ &size, -+ code); -+ -+ if (result != BRASERO_SCSI_OK) { -+ g_free (wrt_perf); -+ -+ BRASERO_BURN_LOG ("GET PERFORMANCE failed"); -+ return BRASERO_BURN_ERR; -+ } -+ -+ num_desc = (size - sizeof (BraseroScsiGetPerfHdr)) / -+ sizeof (BraseroScsiWrtSpdDesc); -+ -+ if (num_desc <= 0) -+ goto end; -+ -+ priv->rd_speeds = g_new0 (gint, num_desc + 1); -+ priv->wr_speeds = g_new0 (gint, num_desc + 1); -+ -+ max_rd = 0; -+ max_wrt = 0; -+ -+ desc = (BraseroScsiWrtSpdDesc*) &wrt_perf->data; -+ for (i = 0; i < num_desc; i ++, desc ++) { -+ priv->rd_speeds [i] = BRASERO_GET_32 (desc->rd_speed); -+ priv->wr_speeds [i] = BRASERO_GET_32 (desc->wr_speed); -+ -+ max_rd = MAX (max_rd, priv->rd_speeds [i]); -+ max_wrt = MAX (max_wrt, priv->wr_speeds [i]); -+ } -+ -+ priv->max_rd = max_rd; -+ priv->max_wrt = max_wrt; -+ -+end: -+ -+ g_free (wrt_perf); -+ -+ /* strangely there are so drives (I know one case) which support this -+ * function but don't report any speed. So if our top speed is 0 then -+ * use the other way to get the speed. It was a Teac */ -+ if (!priv->max_wrt) -+ return BRASERO_BURN_ERR; -+ -+ return BRASERO_BURN_OK; -+} -+ -+static BraseroBurnResult -+brasero_medium_get_page_2A_write_speed_desc (BraseroMedium *self, -+ int fd, -+ BraseroScsiErrCode *code) -+{ -+ BraseroScsiStatusPage *page_2A = NULL; -+ BraseroScsiStatusWrSpdDesc *desc; -+ BraseroScsiModeData *data = NULL; -+ BraseroMediumPrivate *priv; -+ BraseroScsiResult result; -+ gint desc_num, i; -+ gint max_wrt = 0; -+ gint max_num; -+ int size = 0; -+ -+ BRASERO_BURN_LOG ("Retrieving speed (2A speeds)"); -+ -+ priv = BRASERO_MEDIUM_PRIVATE (self); -+ result = brasero_spc1_mode_sense_get_page (fd, -+ BRASERO_SPC_PAGE_STATUS, -+ &data, -+ &size, -+ code); -+ if (result != BRASERO_SCSI_OK) { -+ g_free (data); -+ -+ BRASERO_BURN_LOG ("MODE SENSE failed"); -+ return BRASERO_BURN_ERR; -+ } -+ -+ page_2A = (BraseroScsiStatusPage *) &data->page; -+ -+ /* FIXME: the following is not necessarily true */ -+ if (size < sizeof (BraseroScsiStatusPage)) { -+ g_free (data); -+ -+ BRASERO_BURN_LOG ("wrong size in page"); -+ return BRASERO_BURN_ERR; -+ } -+ -+ desc_num = BRASERO_GET_16 (page_2A->wr_speed_desc_num); -+ max_num = size - -+ sizeof (BraseroScsiStatusPage) - -+ sizeof (BraseroScsiModeHdr); -+ max_num /= sizeof (BraseroScsiWrtSpdDesc); -+ -+ if (max_num < 0) -+ max_num = 0; -+ -+ if (desc_num > max_num) -+ desc_num = max_num; -+ -+ priv->wr_speeds = g_new0 (gint, desc_num + 1); -+ desc = page_2A->wr_spd_desc; -+ for (i = 0; i < desc_num; i ++, desc ++) { -+ priv->wr_speeds [i] = BRASERO_GET_16 (desc->speed); -+ max_wrt = MAX (max_wrt, priv->wr_speeds [i]); -+ } -+ -+ if (!max_wrt) -+ priv->max_wrt = BRASERO_GET_16 (page_2A->wr_max_speed); -+ else -+ priv->max_wrt = max_wrt; -+ -+ priv->max_rd = BRASERO_GET_16 (page_2A->rd_max_speed); -+ g_free (data); -+ -+ return BRASERO_BURN_OK; -+} -+ -+static BraseroBurnResult -+brasero_medium_get_page_2A_max_speed (BraseroMedium *self, -+ int fd, -+ BraseroScsiErrCode *code) -+{ -+ BraseroScsiStatusPage *page_2A = NULL; -+ BraseroScsiModeData *data = NULL; -+ BraseroMediumPrivate *priv; -+ BraseroScsiResult result; -+ int size = 0; -+ -+ BRASERO_BURN_LOG ("Retrieving speed (2A max)"); -+ -+ priv = BRASERO_MEDIUM_PRIVATE (self); -+ -+ result = brasero_spc1_mode_sense_get_page (fd, -+ BRASERO_SPC_PAGE_STATUS, -+ &data, -+ &size, -+ code); -+ if (result != BRASERO_SCSI_OK) { -+ g_free (data); -+ -+ BRASERO_BURN_LOG ("MODE SENSE failed"); -+ return BRASERO_BURN_ERR; -+ } -+ -+ page_2A = (BraseroScsiStatusPage *) &data->page; -+ -+ if (size < 0x14) { -+ g_free (data); -+ -+ BRASERO_BURN_LOG ("wrong page size"); -+ return BRASERO_BURN_ERR; -+ } -+ -+ priv->max_rd = BRASERO_GET_16 (page_2A->rd_max_speed); -+ priv->max_wrt = BRASERO_GET_16 (page_2A->wr_max_speed); -+ -+ g_free (data); -+ return BRASERO_BURN_OK; -+} -+ -+static BraseroBurnResult -+brasero_medium_get_medium_type (BraseroMedium *self, -+ int fd, -+ BraseroScsiErrCode *code) -+{ -+ BraseroScsiGetConfigHdr *hdr = NULL; -+ BraseroMediumPrivate *priv; -+ BraseroScsiResult result; -+ int size; -+ -+ BRASERO_BURN_LOG ("Retrieving media profile"); -+ -+ priv = BRASERO_MEDIUM_PRIVATE (self); -+ result = brasero_mmc2_get_configuration_feature (fd, -+ BRASERO_SCSI_FEAT_REAL_TIME_STREAM, -+ &hdr, -+ &size, -+ code); -+ if (result != BRASERO_SCSI_OK) { -+ BraseroScsiAtipData *data = NULL; -+ int size = 0; -+ -+ BRASERO_BURN_LOG ("GET CONFIGURATION failed"); -+ -+ /* This could be a MMC1 drive since this command was -+ * introduced in MMC2 and is supported onward. So it -+ * has to be a CD (R/RW). The rest of the information -+ * will be provided by read_disc_information. */ -+ -+ /* The only thing here left to determine is if that's a WRITABLE -+ * or a REWRITABLE. To determine that information, we need to -+ * read TocPmaAtip. It if fails that's a ROM, if it succeeds. -+ * No need to set error code since we consider that it's a ROM -+ * if a failure happens. */ -+ result = brasero_mmc1_read_atip (fd, -+ &data, -+ &size, -+ NULL); -+ if (result != BRASERO_SCSI_OK) { -+ /* CDROM */ -+ priv->info = BRASERO_MEDIUM_CDROM; -+ priv->type = types [1]; -+ priv->icon = icons [1]; -+ } -+ else { -+ /* check the size of the structure: it must be at least 8 bytes long */ -+ if (size < 8) { -+ if (size) -+ g_free (data); -+ -+ BRASERO_BURN_LOG ("READ ATIP failed (wrong size)"); -+ return BRASERO_BURN_ERR; -+ } -+ -+ if (data->desc->erasable) { -+ /* CDRW */ -+ priv->info = BRASERO_MEDIUM_CDRW; -+ priv->type = types [3]; -+ priv->icon = icons [3]; -+ } -+ else { -+ /* CDR */ -+ priv->info = BRASERO_MEDIUM_CDR; -+ priv->type = types [2]; -+ priv->icon = icons [2]; -+ } -+ -+ g_free (data); -+ } -+ -+ /* retrieve the speed */ -+ result = brasero_medium_get_page_2A_max_speed (self, -+ fd, -+ code); -+ return result; -+ } -+ -+ switch (BRASERO_GET_16 (hdr->current_profile)) { -+ case BRASERO_SCSI_PROF_CDROM: -+ priv->info = BRASERO_MEDIUM_CDROM; -+ priv->type = types [1]; -+ priv->icon = icons [1]; -+ break; -+ -+ case BRASERO_SCSI_PROF_CDR: -+ priv->info = BRASERO_MEDIUM_CDR; -+ priv->type = types [2]; -+ priv->icon = icons [2]; -+ break; -+ -+ case BRASERO_SCSI_PROF_CDRW: -+ priv->info = BRASERO_MEDIUM_CDRW; -+ priv->type = types [3]; -+ priv->icon = icons [3]; -+ break; -+ -+ case BRASERO_SCSI_PROF_DVD_ROM: -+ priv->info = BRASERO_MEDIUM_DVD_ROM; -+ priv->type = types [4]; -+ priv->icon = icons [4]; -+ break; -+ -+ case BRASERO_SCSI_PROF_DVD_R: -+ priv->info = BRASERO_MEDIUM_DVDR; -+ priv->type = types [5]; -+ priv->icon = icons [5]; -+ break; -+ -+ case BRASERO_SCSI_PROF_DVD_RW_RESTRICTED: -+ priv->info = BRASERO_MEDIUM_DVDRW_RESTRICTED; -+ priv->type = types [6]; -+ priv->icon = icons [6]; -+ break; -+ -+ case BRASERO_SCSI_PROF_DVD_RW_SEQUENTIAL: -+ priv->info = BRASERO_MEDIUM_DVDRW; -+ priv->type = types [6]; -+ priv->icon = icons [6]; -+ break; -+ -+ case BRASERO_SCSI_PROF_DVD_R_PLUS: -+ priv->info = BRASERO_MEDIUM_DVDR_PLUS; -+ priv->type = types [7]; -+ priv->icon = icons [7]; -+ break; -+ -+ case BRASERO_SCSI_PROF_DVD_RW_PLUS: -+ priv->info = BRASERO_MEDIUM_DVDRW_PLUS; -+ priv->type = types [8]; -+ priv->icon = icons [7]; -+ break; -+ -+ /* WARNING: these types are recognized, no more */ -+ case BRASERO_SCSI_PROF_DVD_R_PLUS_DL: -+ priv->info = BRASERO_MEDIUM_DVDR_PLUS_DL; -+ priv->type = types [9]; -+ priv->icon = icons [7]; -+ break; -+ -+ case BRASERO_SCSI_PROF_DVD_RW_PLUS_DL: -+ priv->info = BRASERO_MEDIUM_DVDRW_PLUS_DL; -+ priv->type = types [10]; -+ priv->icon = icons [7]; -+ break; -+ -+ case BRASERO_SCSI_PROF_DVD_R_DL_SEQUENTIAL: -+ priv->info = BRASERO_MEDIUM_DVDR_DL; -+ priv->type = types [11]; -+ priv->icon = icons [5]; -+ break; -+ -+ case BRASERO_SCSI_PROF_DVD_R_DL_JUMP: -+ priv->info = BRASERO_MEDIUM_DVDR_JUMP_DL; -+ priv->type = types [11]; -+ priv->icon = icons [5]; -+ break; -+ -+ case BRASERO_SCSI_PROF_DVD_RAM: -+ priv->info = BRASERO_MEDIUM_DVD_RAM; -+ priv->type = types [12]; -+ priv->icon = icons [8]; -+ break; -+ -+ case BRASERO_SCSI_PROF_BD_ROM: -+ priv->info = BRASERO_MEDIUM_BD_ROM; -+ priv->type = types [13]; -+ priv->icon = icons [4]; -+ break; -+ -+ case BRASERO_SCSI_PROF_BR_R_SEQUENTIAL: -+ priv->info = BRASERO_MEDIUM_BDR; -+ priv->type = types [14]; -+ priv->icon = icons [5]; -+ break; -+ -+ case BRASERO_SCSI_PROF_BR_R_RANDOM: -+ priv->info = BRASERO_MEDIUM_BDR_RANDOM; -+ priv->type = types [14]; -+ priv->icon = icons [5]; -+ break; -+ -+ case BRASERO_SCSI_PROF_BD_RW: -+ priv->info = BRASERO_MEDIUM_BDRW; -+ priv->type = types [15]; -+ priv->icon = icons [6]; -+ break; -+ -+ case BRASERO_SCSI_PROF_NON_REMOVABLE: -+ case BRASERO_SCSI_PROF_REMOVABLE: -+ case BRASERO_SCSI_PROF_MO_ERASABLE: -+ case BRASERO_SCSI_PROF_MO_WRITE_ONCE: -+ case BRASERO_SCSI_PROF_MO_ADVANCED_STORAGE: -+ case BRASERO_SCSI_PROF_DDCD_ROM: -+ case BRASERO_SCSI_PROF_DDCD_R: -+ case BRASERO_SCSI_PROF_DDCD_RW: -+ case BRASERO_SCSI_PROF_HD_DVD_ROM: -+ case BRASERO_SCSI_PROF_HD_DVD_R: -+ case BRASERO_SCSI_PROF_HD_DVD_RAM: -+ priv->info = BRASERO_MEDIUM_UNSUPPORTED; -+ priv->icon = icons [0]; -+ g_free (hdr); -+ return BRASERO_BURN_NOT_SUPPORTED; -+ } -+ -+ /* try all SCSI functions to get write/read speeds in order */ -+ if (hdr->desc->add_len >= sizeof (BraseroScsiRTStreamDesc)) { -+ BraseroScsiRTStreamDesc *stream; -+ -+ /* means it's at least an MMC3 drive */ -+ stream = (BraseroScsiRTStreamDesc *) hdr->desc->data; -+ if (stream->wrt_spd) { -+ result = brasero_medium_get_speed_mmc3 (self, fd, code); -+ if (result == BRASERO_BURN_OK) -+ goto end; -+ } -+ -+ if (stream->mp2a) { -+ result = brasero_medium_get_page_2A_write_speed_desc (self, fd, code); -+ if (result == BRASERO_BURN_OK) -+ goto end; -+ } -+ } -+ -+ /* fallback for speeds */ -+ result = brasero_medium_get_page_2A_max_speed (self, fd, code); -+ -+end: -+ -+ g_free (hdr); -+ -+ if (result != BRASERO_BURN_OK) -+ return result; -+ -+ return BRASERO_BURN_OK; -+} -+ -+static BraseroBurnResult -+brasero_medium_get_css_feature (BraseroMedium *self, -+ int fd, -+ BraseroScsiErrCode *code) -+{ -+ BraseroScsiGetConfigHdr *hdr = NULL; -+ BraseroMediumPrivate *priv; -+ BraseroScsiResult result; -+ int size; -+ -+ priv = BRASERO_MEDIUM_PRIVATE (self); -+ -+ BRASERO_BURN_LOG ("Testing for Css encrypted media"); -+ result = brasero_mmc2_get_configuration_feature (fd, -+ BRASERO_SCSI_FEAT_DVD_CSS, -+ &hdr, -+ &size, -+ code); -+ if (result != BRASERO_SCSI_OK) { -+ g_free (hdr); -+ -+ BRASERO_BURN_LOG ("GET CONFIGURATION failed"); -+ return BRASERO_BURN_ERR; -+ } -+ -+ if (hdr->desc->add_len < sizeof (BraseroScsiDVDCssDesc)) { -+ g_free (hdr); -+ return BRASERO_BURN_OK; -+ } -+ -+ /* here we just need to see if this feature is current or not */ -+ if (hdr->desc->current) { -+ priv->info |= BRASERO_MEDIUM_PROTECTED; -+ BRASERO_BURN_LOG ("media is Css protected"); -+ } -+ -+ g_free (hdr); -+ return BRASERO_BURN_OK; -+} -+ -+/** -+ * Functions to get information about disc contents -+ */ -+ -+static void -+brasero_medium_set_track_type (BraseroMedium *self, -+ BraseroMediumTrack *track, -+ guchar control) -+{ -+ BraseroMediumPrivate *priv; -+ -+ priv = BRASERO_MEDIUM_PRIVATE (self); -+ -+ if (control & BRASERO_SCSI_TRACK_COPY) -+ track->type |= BRASERO_MEDIUM_TRACK_COPY; -+ -+ if (!(control & BRASERO_SCSI_TRACK_DATA)) { -+ track->type |= BRASERO_MEDIUM_TRACK_AUDIO; -+ priv->info |= BRASERO_MEDIUM_HAS_AUDIO; -+ -+ if (control & BRASERO_SCSI_TRACK_PREEMP) -+ track->type |= BRASERO_MEDIUM_TRACK_PREEMP; -+ -+ if (control & BRASERO_SCSI_TRACK_4_CHANNELS) -+ track->type |= BRASERO_MEDIUM_TRACK_4_CHANNELS; -+ } -+ else { -+ track->type |= BRASERO_MEDIUM_TRACK_DATA; -+ priv->info |= BRASERO_MEDIUM_HAS_DATA; -+ -+ if (control & BRASERO_SCSI_TRACK_DATA_INCREMENTAL) -+ track->type |= BRASERO_MEDIUM_TRACK_INCREMENTAL; -+ } -+} -+ -+static BraseroBurnResult -+brasero_medium_track_volume_size (BraseroMedium *self, -+ BraseroMediumTrack *track, -+ int fd) -+{ -+ BraseroMediumPrivate *priv; -+ BraseroBurnResult res; -+ GError *error = NULL; -+ gint64 nb_blocks; -+ -+ if (!track) -+ return BRASERO_BURN_ERR; -+ -+ priv = BRASERO_MEDIUM_PRIVATE (self); -+ -+ /* This is a special case. For DVD+RW and DVD-RW in restricted -+ * mode, there is only one session that takes the whole disc size -+ * once formatted. That doesn't necessarily means they have data -+ * Note also that they are reported as complete though you can -+ * still add data (with growisofs). It is nevertheless on the -+ * condition that the fs is valid. -+ * So we check if their first and only volume is valid. -+ * That's also used when the track size is reported a 300 Kio -+ * see below */ -+ res = brasero_volume_get_size_fd (fd, -+ track->start, -+ &nb_blocks, -+ NULL); -+ if (!res) { -+ BRASERO_BURN_LOG ("Failed to retrieve the volume size: %s", -+ error && error->message ? -+ error->message:"unknown error"); -+ -+ if (error) -+ g_error_free (error); -+ return BRASERO_BURN_ERR; -+ } -+ -+ track->blocks_num = nb_blocks; -+ return BRASERO_BURN_OK; -+} -+ -+static BraseroBurnResult -+brasero_medium_track_get_info (BraseroMedium *self, -+ BraseroMediumTrack *track, -+ int track_num, -+ int fd, -+ BraseroScsiErrCode *code) -+{ -+ BraseroScsiTrackInfo track_info; -+ BraseroMediumPrivate *priv; -+ BraseroScsiResult result; -+ int size; -+ -+ BRASERO_BURN_LOG ("Retrieving track information for %i", track_num); -+ -+ priv = BRASERO_MEDIUM_PRIVATE (self); -+ -+ /* at this point we know the type of the disc that's why we set the -+ * size according to this type. That may help to avoid outrange address -+ * errors. */ -+ if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DL|BRASERO_MEDIUM_WRITABLE)) -+ size = 48; -+ else if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_PLUS|BRASERO_MEDIUM_WRITABLE)) -+ size = 40; -+ else -+ size = 36; -+ -+ result = brasero_mmc1_read_track_info (fd, -+ track_num, -+ &track_info, -+ &size, -+ code); -+ -+ if (result != BRASERO_SCSI_OK) { -+ BRASERO_BURN_LOG ("READ TRACK INFO failed"); -+ return BRASERO_BURN_ERR; -+ } -+ -+ track->blocks_num = BRASERO_GET_32 (track_info.track_size); -+ track->session = BRASERO_SCSI_SESSION_NUM (track_info); -+ -+ /* Now here is a potential bug: we can write tracks (data or not) -+ * shorter than 300 Kio /2 sec but they will be padded to reach this -+ * floor value. That means that is blocks_num is 300 blocks that may -+ * mean that the data length on the track is actually shorter. -+ * So we read the volume descriptor. If it works, good otherwise -+ * use the old value. -+ * That's important for checksuming to have a perfect account of the -+ * data size. */ -+ if (track->blocks_num <= 300) { -+ BRASERO_BURN_LOG ("300 sectors size. Checking for real size"); -+ brasero_medium_track_volume_size (self, track, fd); -+ } -+ -+ if (track_info.next_wrt_address_valid) -+ priv->next_wr_add = BRASERO_GET_32 (track_info.next_wrt_address); -+ -+ BRASERO_BURN_LOG ("Track %i (session %i): type = %i start = %llu size = %llu", -+ track_num, -+ track->session, -+ track->type, -+ track->start, -+ track->blocks_num); -+ -+ return BRASERO_BURN_OK; -+} -+ -+/** -+ * return : -+ * 0 when it's not possible to determine (fallback to formatted toc) -+ * -1 for BCD -+ * 1 for HEX */ -+static guint -+brasero_medium_check_BCD_use (BraseroMedium *self, -+ int fd, -+ BraseroScsiRawTocDesc *desc, -+ guint num, -+ BraseroScsiErrCode *code) -+{ -+ guint i; -+ int size; -+ guint leadout = 0; -+ guint track_num = 0; -+ gboolean use_BCD = TRUE; -+ gboolean use_HEX = TRUE; -+ BraseroScsiResult result; -+ BraseroScsiTrackInfo track_info; -+ guint start_BCD, start_LBA, track_start; -+ -+ /* first check if all values are valid BCD numbers in the descriptors */ -+ for (i = 0; i < num; i++) { -+ if (desc [i].adr == 1 && desc [i].point <= BRASERO_SCSI_Q_SUB_CHANNEL_TRACK_START) { -+ if (!BRASERO_IS_BCD_VALID (desc [i].p_min) -+ || !BRASERO_IS_BCD_VALID (desc [i].p_sec) -+ || !BRASERO_IS_BCD_VALID (desc [i].p_frame)) { -+ use_BCD = FALSE; -+ break; -+ } -+ } -+ else if (desc [i].point == BRASERO_SCSI_Q_SUB_CHANNEL_LEADOUT_START) { -+ if (!BRASERO_IS_BCD_VALID (desc [i].p_min) -+ || !BRASERO_IS_BCD_VALID (desc [i].p_sec) -+ || !BRASERO_IS_BCD_VALID (desc [i].p_frame)) { -+ use_BCD = FALSE; -+ break; -+ } -+ } -+ } -+ -+ /* then check if there are valid Hex values */ -+ for (i = 0; i < num; i++) { -+ if (desc [i].adr != 1 || desc [i].point > BRASERO_SCSI_Q_SUB_CHANNEL_TRACK_START) -+ continue; -+ -+ if (desc [i].p_min > 99 -+ || desc [i].p_sec > 59 -+ || desc [i].p_frame > 74) { -+ use_HEX = FALSE; -+ break; -+ } -+ } -+ -+ if (use_BCD != use_HEX) { -+ if (use_BCD) -+ return -1; -+ -+ return 1; -+ } -+ -+ /* To check if the drive uses BCD values or HEX values we ask for the -+ * track information that contains also the start for the track but in -+ * HEX values. If values are the same then it works. */ -+ -+ /* NOTE: there could be another way to do it: get first track, in LBA -+ * and BCD it must be 150. */ -+ -+ /* First find the first track and get track start address in BCD */ -+ BRASERO_BURN_LOG ("Retrieving track information to determine number format"); -+ -+ for (i = 0; i < num; i++) { -+ if (desc [i].adr == BRASERO_SCSI_Q_SUB_CHANNEL_LEADIN_MODE5 -+ && desc [i].point == BRASERO_SCSI_Q_SUB_CHANNEL_MULTI_NEXT_SESSION) { -+ /* store the leadout number just in case */ -+ leadout = i; -+ continue; -+ } -+ -+ if (desc [i].adr != 1 || desc [i].point > BRASERO_SCSI_Q_SUB_CHANNEL_TRACK_START) -+ continue; -+ -+ track_num ++; -+ -+ start_BCD = BRASERO_MSF_TO_LBA (BRASERO_GET_BCD (desc [i].p_min), -+ BRASERO_GET_BCD (desc [i].p_sec), -+ BRASERO_GET_BCD (desc [i].p_frame)); -+ -+ start_LBA = BRASERO_MSF_TO_LBA (desc [i].p_min, -+ desc [i].p_sec, -+ desc [i].p_frame); -+ -+ BRASERO_BURN_LOG ("Comparing to track information from READ TRACK INFO for track %i", track_num); -+ -+ size = 36; -+ start_LBA -= 150; -+ start_BCD -= 150; -+ -+ result = brasero_mmc1_read_track_info (fd, -+ track_num, -+ &track_info, -+ &size, -+ code); -+ -+ if (result != BRASERO_SCSI_OK) { -+ BRASERO_BURN_LOG ("READ TRACK INFO failed"); -+ /* Fallback to formatted toc */ -+ return 0; -+ } -+ -+ track_start = BRASERO_GET_32 (track_info.start_lba); -+ BRASERO_BURN_LOG ("comparing DCB %i and LBA %i to real start address %i", -+ start_BCD, start_LBA, track_start); -+ -+ /* try to find a conclusive match */ -+ if (track_start == start_BCD && track_start != start_LBA) -+ return -1; -+ -+ if (track_start == start_LBA && track_start != start_BCD) -+ return 1; -+ } -+ -+ /* Our last chance, the leadout. -+ * NOTE: no need to remove 150 sectors here. */ -+ start_BCD = BRASERO_MSF_TO_LBA (BRASERO_GET_BCD (desc [leadout].min), -+ BRASERO_GET_BCD (desc [leadout].sec), -+ BRASERO_GET_BCD (desc [leadout].frame)); -+ -+ start_LBA = BRASERO_MSF_TO_LBA (desc [leadout].min, -+ desc [leadout].sec, -+ desc [leadout].frame); -+ -+ BRASERO_BURN_LOG ("Comparing to track information from READ TRACK INFO for leadout"); -+ -+ size = 36; -+ -+ /* leadout number is number of tracks + 1 */ -+ result = brasero_mmc1_read_track_info (fd, -+ track_num + 1, -+ &track_info, -+ &size, -+ code); -+ -+ if (result != BRASERO_SCSI_OK) { -+ BRASERO_BURN_LOG ("READ TRACK INFO failed for leadout"); -+ /* Fallback to formatted toc */ -+ return 0; -+ } -+ -+ track_start = BRASERO_GET_32 (track_info.start_lba); -+ BRASERO_BURN_LOG ("comparing DCB %i and LBA %i to real start address %i", -+ start_BCD, start_LBA, track_start); -+ -+ /* try to find a conclusive match */ -+ if (track_start == start_BCD && track_start != start_LBA) -+ return -1; -+ -+ if (track_start == start_LBA && track_start != start_BCD) -+ return 1; -+ -+ /* fallback to formatted toc */ -+ return 0; -+} -+ -+/** -+ * The reason why we use this perhaps more lengthy method is that with -+ * multisession discs, the first track is reported to be two sectors shorter -+ * than it should. As I don't know why and since the following works we use -+ * this one. */ -+static BraseroBurnResult -+brasero_medium_get_CD_sessions_info (BraseroMedium *self, -+ int fd, -+ BraseroScsiErrCode *code) -+{ -+ gint use_bcd; -+ GSList *iter; -+ int num, i, size; -+ gint leadout_start = 0; -+ BraseroScsiResult result; -+ BraseroMediumPrivate *priv; -+ BraseroScsiRawTocDesc *desc; -+ BraseroScsiRawTocData *toc = NULL; -+ -+ BRASERO_BURN_LOG ("Reading Raw Toc"); -+ -+ priv = BRASERO_MEDIUM_PRIVATE (self); -+ -+ size = 0; -+ result = brasero_mmc1_read_toc_raw (fd, -+ 0, -+ &toc, -+ &size, -+ code); -+ if (result != BRASERO_SCSI_OK) { -+ BRASERO_BURN_LOG ("READ TOC failed"); -+ return BRASERO_BURN_ERR; -+ } -+ -+ num = (size - sizeof (BraseroScsiRawTocData)) / -+ sizeof (BraseroScsiRawTocDesc); -+ -+ BRASERO_BURN_LOG ("%i track(s) found", num); -+ -+ desc = toc->desc; -+ use_bcd = brasero_medium_check_BCD_use (self, fd, desc, num, code); -+ if (!use_bcd) { -+ g_free (toc); -+ -+ BRASERO_BURN_LOG ("Fallback to formatted toc"); -+ return BRASERO_BURN_ERR; -+ } -+ -+ if (use_bcd > 0) -+ use_bcd = 0; -+ -+ if (use_bcd) { -+ BRASERO_BURN_LOG ("Using BCD format"); -+ } -+ else { -+ BRASERO_BURN_LOG ("Using HEX format"); -+ } -+ -+ for (i = 0; i < num; i++, desc ++) { -+ BraseroMediumTrack *track; -+ -+ track = NULL; -+ if (desc->adr == 1 && desc->point <= BRASERO_SCSI_Q_SUB_CHANNEL_TRACK_START) { -+ track = g_new0 (BraseroMediumTrack, 1); -+ track->session = desc->session_num; -+ -+ brasero_medium_set_track_type (self, track, desc->control); -+ if (use_bcd) -+ track->start = BRASERO_MSF_TO_LBA (BRASERO_GET_BCD (desc->p_min), -+ BRASERO_GET_BCD (desc->p_sec), -+ BRASERO_GET_BCD (desc->p_frame)); -+ else -+ track->start = BRASERO_MSF_TO_LBA (desc->p_min, -+ desc->p_sec, -+ desc->p_frame); -+ -+ track->start -= 150; -+ -+ /* if there are tracks and the last previously added track is in -+ * the same session then set the size */ -+ if (priv->tracks) { -+ BraseroMediumTrack *last_track; -+ -+ last_track = priv->tracks->data; -+ if (last_track->session == track->session) -+ last_track->blocks_num = track->start - last_track->start; -+ } -+ -+ priv->tracks = g_slist_prepend (priv->tracks, track); -+ } -+ else if (desc->point == BRASERO_SCSI_Q_SUB_CHANNEL_LEADOUT_START) { -+ /* NOTE: the leadout session is first in the list. So if -+ * we have tracks in the list set the last session track -+ * size when we reach a new leadout (and therefore a new -+ * session). */ -+ -+ if (priv->tracks) { -+ BraseroMediumTrack *last_track; -+ -+ last_track = priv->tracks->data; -+ last_track->blocks_num = leadout_start - last_track->start; -+ } -+ -+ if (use_bcd) -+ leadout_start = BRASERO_MSF_TO_LBA (BRASERO_GET_BCD (desc->p_min), -+ BRASERO_GET_BCD (desc->p_sec), -+ BRASERO_GET_BCD (desc->p_frame)); -+ else -+ leadout_start = BRASERO_MSF_TO_LBA (desc->p_min, -+ desc->p_sec, -+ desc->p_frame); -+ leadout_start -= 150; -+ } -+ } -+ -+ if (priv->tracks) { -+ BraseroMediumTrack *last_track; -+ -+ /* set the last found track size */ -+ last_track = priv->tracks->data; -+ last_track->blocks_num = leadout_start - last_track->start; -+ } -+ -+ /* Add a leadout */ -+ if (!(priv->info & BRASERO_MEDIUM_CLOSED)) { -+ BraseroMediumTrack *track; -+ -+ /* we shouldn't request info on leadout if the disc is closed */ -+ track = g_new0 (BraseroMediumTrack, 1); -+ priv->tracks = g_slist_prepend (priv->tracks, track); -+ track->start = leadout_start; -+ track->type = BRASERO_MEDIUM_TRACK_LEADOUT; -+ -+ brasero_medium_track_get_info (self, track, g_slist_length (priv->tracks), fd, code); -+ } -+ -+ priv->tracks = g_slist_reverse (priv->tracks); -+ -+ for (iter = priv->tracks; iter; iter = iter->next) { -+ BraseroMediumTrack *track; -+ -+ track = iter->data; -+ -+ /* check for tracks less that 300 sectors */ -+ if (track->blocks_num <= 300 && track->type != BRASERO_MEDIUM_TRACK_LEADOUT) { -+ BRASERO_BURN_LOG ("300 sectors size. Checking for real size"); -+ brasero_medium_track_volume_size (self, track, fd); -+ } -+ -+ BRASERO_BURN_LOG ("Track %i: type = %i start = %llu size = %llu", -+ g_slist_index (priv->tracks, track), -+ track->type, -+ track->start, -+ track->blocks_num); -+ } -+ -+ g_free (toc); -+ return BRASERO_BURN_OK; -+} -+ -+/** -+ * NOTE: for DVD-R multisession we lose 28688 blocks for each session -+ * so the capacity is the addition of all session sizes + 28688 for each -+ * For all multisession DVD-/+R and CDR-RW the remaining size is given -+ * in the leadout. One exception though with DVD+/-RW. -+ */ -+ -+static void -+brasero_medium_add_DVD_plus_RW_leadout (BraseroMedium *self, -+ gint32 start) -+{ -+ BraseroMediumTrack *leadout; -+ BraseroMediumPrivate *priv; -+ -+ priv = BRASERO_MEDIUM_PRIVATE (self); -+ -+ leadout = g_new0 (BraseroMediumTrack, 1); -+ priv->tracks = g_slist_append (priv->tracks, leadout); -+ -+ leadout->start = start; -+ leadout->type = BRASERO_MEDIUM_TRACK_LEADOUT; -+ -+ /* we fabricate the leadout here. We don't really need one in -+ * fact since it is always at the last sector whatever the -+ * amount of data written. So we need in fact to read the file -+ * system and get the last sector from it. Hopefully it won't be -+ * buggy */ -+ priv->next_wr_add = 0; -+ -+ leadout->blocks_num = priv->block_num; -+ if (g_slist_length (priv->tracks) > 1) { -+ BraseroMediumTrack *track; -+ -+ track = priv->tracks->data; -+ leadout->blocks_num -= ((track->blocks_num > 300) ? track->blocks_num : 300); -+ } -+ BRASERO_BURN_LOG ("Adding fabricated leadout start = %llu length = %llu", -+ leadout->start, -+ leadout->blocks_num); -+} -+ -+static BraseroBurnResult -+brasero_medium_get_sessions_info (BraseroMedium *self, -+ int fd, -+ BraseroScsiErrCode *code) -+{ -+ int num, i, size; -+ BraseroScsiResult result; -+ BraseroScsiTocDesc *desc; -+ BraseroMediumPrivate *priv; -+ BraseroScsiFormattedTocData *toc = NULL; -+ -+ BRASERO_BURN_LOG ("Reading Toc"); -+ -+ priv = BRASERO_MEDIUM_PRIVATE (self); -+ result = brasero_mmc1_read_toc_formatted (fd, -+ 0, -+ &toc, -+ &size, -+ code); -+ if (result != BRASERO_SCSI_OK) { -+ g_free (toc); -+ -+ BRASERO_BURN_LOG ("READ TOC failed"); -+ return BRASERO_BURN_ERR; -+ } -+ -+ num = (size - sizeof (BraseroScsiFormattedTocData)) / -+ sizeof (BraseroScsiTocDesc); -+ -+ BRASERO_BURN_LOG ("%i track(s) found", num); -+ -+ desc = toc->desc; -+ for (i = 0; i < num; i ++, desc ++) { -+ BraseroMediumTrack *track; -+ -+ if (desc->track_num == BRASERO_SCSI_TRACK_LEADOUT_START) -+ break; -+ -+ track = g_new0 (BraseroMediumTrack, 1); -+ priv->tracks = g_slist_prepend (priv->tracks, track); -+ track->start = BRASERO_GET_32 (desc->track_start); -+ -+ /* we shouldn't request info on a track if the disc is closed */ -+ brasero_medium_track_get_info (self, -+ track, -+ g_slist_length (priv->tracks), -+ fd, -+ code); -+ -+ if (desc->control & BRASERO_SCSI_TRACK_COPY) -+ track->type |= BRASERO_MEDIUM_TRACK_COPY; -+ -+ if (!(desc->control & BRASERO_SCSI_TRACK_DATA)) { -+ track->type |= BRASERO_MEDIUM_TRACK_AUDIO; -+ priv->info |= BRASERO_MEDIUM_HAS_AUDIO; -+ -+ if (desc->control & BRASERO_SCSI_TRACK_PREEMP) -+ track->type |= BRASERO_MEDIUM_TRACK_PREEMP; -+ -+ if (desc->control & BRASERO_SCSI_TRACK_4_CHANNELS) -+ track->type |= BRASERO_MEDIUM_TRACK_4_CHANNELS; -+ } -+ else if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DVDRW_PLUS) -+ || BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DVDRW_RESTRICTED)) { -+ BraseroBurnResult result; -+ -+ /* a special case for these two kinds of media (DVD+RW) -+ * which have only one track: the first. */ -+ result = brasero_medium_track_volume_size (self, -+ track, -+ fd); -+ if (result == BRASERO_BURN_OK) { -+ track->type |= BRASERO_MEDIUM_TRACK_DATA; -+ priv->info |= BRASERO_MEDIUM_HAS_DATA; -+ -+ priv->next_wr_add = 0; -+ -+ if (desc->control & BRASERO_SCSI_TRACK_DATA_INCREMENTAL) -+ track->type |= BRASERO_MEDIUM_TRACK_INCREMENTAL; -+ } -+ else { -+ priv->tracks = g_slist_remove (priv->tracks, track); -+ g_free (track); -+ -+ priv->info |= BRASERO_MEDIUM_BLANK; -+ priv->info &= ~BRASERO_MEDIUM_CLOSED; -+ } -+ } -+ else { -+ track->type |= BRASERO_MEDIUM_TRACK_DATA; -+ priv->info |= BRASERO_MEDIUM_HAS_DATA; -+ -+ if (desc->control & BRASERO_SCSI_TRACK_DATA_INCREMENTAL) -+ track->type |= BRASERO_MEDIUM_TRACK_INCREMENTAL; -+ } -+ } -+ -+ /* put the tracks in the right order */ -+ priv->tracks = g_slist_reverse (priv->tracks); -+ -+ if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DVDRW_PLUS) -+ || BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DVDRW_RESTRICTED)) -+ brasero_medium_add_DVD_plus_RW_leadout (self, BRASERO_GET_32 (desc->track_start)); -+ else if (!(priv->info & BRASERO_MEDIUM_CLOSED)) { -+ BraseroMediumTrack *track; -+ -+ /* we shouldn't request info on leadout if the disc is closed -+ * (except for DVD+/- (restricted) RW (see above) */ -+ track = g_new0 (BraseroMediumTrack, 1); -+ priv->tracks = g_slist_append (priv->tracks, track); -+ track->start = BRASERO_GET_32 (desc->track_start); -+ track->type = BRASERO_MEDIUM_TRACK_LEADOUT; -+ -+ brasero_medium_track_get_info (self, -+ track, -+ g_slist_length (priv->tracks), -+ fd, -+ code); -+ } -+ -+ g_free (toc); -+ -+ return BRASERO_BURN_OK; -+} -+ -+static BraseroBurnResult -+brasero_medium_get_contents (BraseroMedium *self, -+ int fd, -+ BraseroScsiErrCode *code) -+{ -+ int size; -+ BraseroScsiResult result; -+ BraseroMediumPrivate *priv; -+ BraseroScsiDiscInfoStd *info = NULL; -+ -+ BRASERO_BURN_LOG ("Retrieving media status"); -+ -+ priv = BRASERO_MEDIUM_PRIVATE (self); -+ -+ result = brasero_mmc1_read_disc_information_std (fd, -+ &info, -+ &size, -+ code); -+ if (result != BRASERO_SCSI_OK) { -+ g_free (info); -+ -+ BRASERO_BURN_LOG ("READ DISC INFORMATION failed"); -+ return BRASERO_BURN_ERR; -+ } -+ -+ if (info->erasable) -+ priv->info |= BRASERO_MEDIUM_REWRITABLE; -+ -+ if (info->status == BRASERO_SCSI_DISC_EMPTY) { -+ BraseroMediumTrack *track; -+ -+ BRASERO_BURN_LOG ("Empty media"); -+ -+ priv->info |= BRASERO_MEDIUM_BLANK; -+ priv->block_size = 2048; -+ -+ if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DVDRW_PLUS) -+ || BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DVDRW_RESTRICTED)) -+ brasero_medium_add_DVD_plus_RW_leadout (self, 0); -+ else { -+ track = g_new0 (BraseroMediumTrack, 1); -+ track->start = 0; -+ track->type = BRASERO_MEDIUM_TRACK_LEADOUT; -+ priv->tracks = g_slist_prepend (priv->tracks, track); -+ -+ brasero_medium_track_get_info (self, -+ track, -+ 1, -+ fd, -+ code); -+ } -+ goto end; -+ } -+ -+ if (info->status == BRASERO_SCSI_DISC_INCOMPLETE) { -+ priv->info |= BRASERO_MEDIUM_APPENDABLE; -+ BRASERO_BURN_LOG ("Appendable media"); -+ } -+ else if (info->status == BRASERO_SCSI_DISC_FINALIZED) { -+ priv->info |= BRASERO_MEDIUM_CLOSED; -+ BRASERO_BURN_LOG ("Closed media"); -+ } -+ -+ if (priv->info & BRASERO_MEDIUM_CD) { -+ result = brasero_medium_get_CD_sessions_info (self, fd, code); -+ if (result != BRASERO_BURN_OK) -+ result = brasero_medium_get_sessions_info (self, fd, code); -+ } -+ else -+ result = brasero_medium_get_sessions_info (self, fd, code); -+ -+ if (result != BRASERO_BURN_OK) -+ goto end; -+ -+end: -+ -+ g_free (info); -+ return BRASERO_BURN_OK; -+} -+ -+static void -+brasero_medium_init_real (BraseroMedium *object, int fd) -+{ -+ gchar *name; -+ BraseroBurnResult result; -+ BraseroMediumPrivate *priv; -+ BraseroScsiErrCode code = 0; -+ -+ priv = BRASERO_MEDIUM_PRIVATE (object); -+ -+ name = nautilus_burn_drive_get_name_for_display (priv->drive); -+ BRASERO_BURN_LOG ("Initializing information for medium in %s", name); -+ g_free (name); -+ -+ result = brasero_medium_get_medium_type (object, fd, &code); -+ if (result != BRASERO_BURN_OK) -+ return; -+ -+ brasero_medium_get_capacity_by_type (object, fd, &code); -+ -+ result = brasero_medium_get_contents (object, fd, &code); -+ if (result != BRASERO_BURN_OK) -+ return; -+ -+ /* assume that css feature is only for DVD-ROM which might be wrong but -+ * some drives wrongly reports that css is enabled for blank DVD+R/W */ -+ if (BRASERO_MEDIUM_IS (priv->info, (BRASERO_MEDIUM_DVD|BRASERO_MEDIUM_ROM))) -+ brasero_medium_get_css_feature (object, fd, &code); -+ -+ BRASERO_BURN_LOG_DISC_TYPE (priv->info, "media is "); -+} -+ -+static gboolean -+brasero_medium_retry_open (gpointer object) -+{ -+ int fd; -+ const gchar *path; -+ BraseroMedium *self; -+ BraseroMediumPrivate *priv; -+ -+ self = BRASERO_MEDIUM (object); -+ priv = BRASERO_MEDIUM_PRIVATE (object); -+ path = nautilus_burn_drive_get_device (priv->drive); -+ -+ BRASERO_BURN_LOG ("Retrying to open device %s", path); -+ fd = open (path, OPEN_FLAGS); -+ if (fd < 0) { -+ if (errno == EBUSY -+ || errno == EAGAIN -+ || errno == EWOULDBLOCK) { -+ BRASERO_BURN_LOG ("Device busy"); -+ /* we'll retry in a second */ -+ return TRUE; -+ } -+ -+ BRASERO_BURN_LOG ("Open () failed"); -+ priv->info = BRASERO_MEDIUM_UNSUPPORTED; -+ priv->retry_id = 0; -+ return FALSE; -+ } -+ -+ BRASERO_BURN_LOG ("Open () succeeded\n"); -+ priv->info = BRASERO_MEDIUM_NONE; -+ priv->icon = icons [0]; -+ -+ priv->retry_id = 0; -+ -+ brasero_medium_init_real (self, fd); -+ close (fd); -+ -+ return FALSE; -+} -+ -+static void -+brasero_medium_try_open (BraseroMedium *self) -+{ -+ int fd; -+ const gchar *path; -+ BraseroMediumPrivate *priv; -+ -+ priv = BRASERO_MEDIUM_PRIVATE (self); -+ path = nautilus_burn_drive_get_device (priv->drive); -+ -+ /* the drive might be busy (a burning is going on) so we don't block -+ * but we re-try to open it every second */ -+ BRASERO_BURN_LOG ("Trying to open device %s", path); -+ fd = open (path, OPEN_FLAGS); -+ if (fd < 0) { -+ if (errno == EAGAIN -+ || errno == EWOULDBLOCK -+ || errno == EBUSY) { -+ BRASERO_BURN_LOG ("Device busy"); -+ priv->info = BRASERO_MEDIUM_BUSY; -+ priv->icon = icons [0]; -+ -+ priv->retry_id = g_timeout_add (BUSY_RETRY_TIME, -+ brasero_medium_retry_open, -+ self); -+ } -+ -+ BRASERO_BURN_LOG ("Open () failed"); -+ return; -+ } -+ -+ BRASERO_BURN_LOG ("Open () succeeded"); -+ brasero_medium_init_real (self, fd); -+ close (fd); -+} -+ -+static void -+brasero_medium_init (BraseroMedium *object) -+{ -+ BraseroMediumPrivate *priv; -+ -+ priv = BRASERO_MEDIUM_PRIVATE (object); -+ priv->next_wr_add = -1; -+ -+ /* we can't do anything here since properties haven't been set yet */ -+} -+ -+static void -+brasero_medium_finalize (GObject *object) -+{ -+ BraseroMediumPrivate *priv; -+ -+ priv = BRASERO_MEDIUM_PRIVATE (object); -+ -+ if (priv->retry_id) { -+ g_source_remove (priv->retry_id); -+ priv->retry_id = 0; -+ } -+ -+ g_free (priv->rd_speeds); -+ priv->rd_speeds = NULL; -+ -+ g_free (priv->wr_speeds); -+ priv->wr_speeds = NULL; -+ -+ g_slist_foreach (priv->tracks, (GFunc) g_free, NULL); -+ g_slist_free (priv->tracks); -+ priv->tracks = NULL; -+ -+ nautilus_burn_drive_unref (priv->drive); -+ priv->drive = NULL; -+ -+ G_OBJECT_CLASS (parent_class)->finalize (object); -+} -+ -+static void -+brasero_medium_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -+{ -+ BraseroMediumPrivate *priv; -+ -+ g_return_if_fail (BRASERO_IS_MEDIUM (object)); -+ -+ priv = BRASERO_MEDIUM_PRIVATE (object); -+ -+ switch (prop_id) -+ { -+ case PROP_DRIVE: -+ priv->drive = g_value_get_object (value); -+ nautilus_burn_drive_ref (priv->drive); -+ brasero_medium_try_open (BRASERO_MEDIUM (object)); -+ break; -+ default: -+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); -+ break; -+ } -+} -+ -+static void -+brasero_medium_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -+{ -+ BraseroMediumPrivate *priv; -+ -+ g_return_if_fail (BRASERO_IS_MEDIUM (object)); -+ -+ priv = BRASERO_MEDIUM_PRIVATE (object); -+ -+ switch (prop_id) -+ { -+ case PROP_DRIVE: -+ nautilus_burn_drive_ref (priv->drive); -+ g_value_set_object (value, priv->drive); -+ break; -+ default: -+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); -+ break; -+ } -+} -+ -+static void -+brasero_medium_class_init (BraseroMediumClass *klass) -+{ -+ GObjectClass* object_class = G_OBJECT_CLASS (klass); -+ parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass)); -+ -+ g_type_class_add_private (klass, sizeof (BraseroMediumPrivate)); -+ -+ object_class->finalize = brasero_medium_finalize; -+ object_class->set_property = brasero_medium_set_property; -+ object_class->get_property = brasero_medium_get_property; -+ -+ g_object_class_install_property (object_class, -+ PROP_DRIVE, -+ g_param_spec_object ("drive", -+ "drive", -+ "drive in which medium is inserted", -+ NAUTILUS_BURN_TYPE_DRIVE, -+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); -+} -+ -+GType -+brasero_medium_get_type (void) -+{ -+ static GType our_type = 0; -+ -+ if (our_type == 0) -+ { -+ static const GTypeInfo our_info = -+ { -+ sizeof (BraseroMediumClass), /* class_size */ -+ (GBaseInitFunc) NULL, /* base_init */ -+ (GBaseFinalizeFunc) NULL, /* base_finalize */ -+ (GClassInitFunc) brasero_medium_class_init, /* class_init */ -+ (GClassFinalizeFunc) NULL, /* class_finalize */ -+ NULL /* class_data */, -+ sizeof (BraseroMedium), /* instance_size */ -+ 0, /* n_preallocs */ -+ (GInstanceInitFunc) brasero_medium_init, /* instance_init */ -+ NULL /* value_table */ -+ }; -+ -+ our_type = g_type_register_static (G_TYPE_OBJECT, "BraseroMedium", -+ &our_info, 0); -+ } -+ -+ return our_type; -+} -+ -+BraseroMedium * -+brasero_medium_new (NautilusBurnDrive *drive) -+{ -+ g_return_val_if_fail (drive != NULL, NULL); -+ return BRASERO_MEDIUM (g_object_new (BRASERO_TYPE_MEDIUM, -+ "drive", drive, -+ NULL)); -+} |