diff -rupN cam.orig/freebsd_dvd_rw_utils.h cam/freebsd_dvd_rw_utils.h
--- /dev/null	1969-12-31 19:00:00.000000000 -0500
+++ src/cam/freebsd_dvd_rw_utils.h	2008-01-24 16:52:25.000000000 -0500
@@ -0,0 +1,49 @@
+//
+// This is part of dvd+rw-tools by Andy Polyakov <appro@fy.chalmers.se>
+//
+// Use-it-on-your-own-risk, GPL bless...
+//
+// For further details see http://fy.chalmers.se/~appro/linux/DVD+RW/
+//
+
+#ifndef FREEBSD_DVD_RW_UTILS_H
+#define FREEBSD_DVD_RW_UTILS_H
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <glib.h>
+
+#include "cam-cdrom.h"
+
+#define DRIVE_CDROM_CAPS_DVDRW		1
+#define DRIVE_CDROM_CAPS_DVDPLUSR	2
+#define DRIVE_CDROM_CAPS_DVDPLUSRW	4
+#define DRIVE_CDROM_CAPS_DVDPLUSRWDL	8
+#define DRIVE_CDROM_CAPS_DVDPLUSRDL	16
+#define DRIVE_CDROM_CAPS_BDROM		32
+#define DRIVE_CDROM_CAPS_BDR		64
+#define DRIVE_CDROM_CAPS_BDRE		128
+#define DRIVE_CDROM_CAPS_HDDVDROM	256
+#define DRIVE_CDROM_CAPS_HDDVDR		512
+#define DRIVE_CDROM_CAPS_HDDVDRW	1024
+
+int brasero_cdrom_get_dvd_r_rw_profile (BRASEROCDROM *cdrom);
+int brasero_cdrom_get_read_write_speed (BRASEROCDROM *cdrom, int *read_speed, int *write_speed, char **write_speeds);
+int brasero_cdrom_get_disc_capacity_for_type (BRASEROCDROM *cdrom, int type, guint64 *capacity);
+int brasero_cdrom_get_disc_type (BRASEROCDROM *cdrom);
+int brasero_cdrom_read_disc_information_std (BRASEROCDROM *cdrom, unsigned char *buf);
+int brasero_cdrom_disc_is_appendable (BRASEROCDROM *cdrom);
+int brasero_cdrom_disc_is_rewritable (BRASEROCDROM *cdrom);
+int brasero_cdrom_read_atip (BRASEROCDROM *cdrom, unsigned char **buf);
+int brasero_cdrom_read_format_capacities (BRASEROCDROM *cdrom, unsigned char **buf);
+int brasero_cdrom_get_performance_wrt_spd_desc (BRASEROCDROM *cdrom, unsigned char **buf);
+int brasero_cdrom_get_configuration_feature (BRASEROCDROM *cdrom, int feature, unsigned char **buf);
+int brasero_cdrom_read_track_info (BRASEROCDROM *cdrom, int track_num, unsigned char *buf, int size);
+int brasero_cdrom_read_toc_raw (BRASEROCDROM *cdrom, int track_num, unsigned char **buf);
+int brasero_cdrom_read_toc_formatted (BRASEROCDROM *cdrom, int track_num, unsigned char **buf);
+int brasero_read_disc_information_std (BRASEROCDROM *cdrom, unsigned char *buf);
+int brasero_cdrom_read_format_capacities (BRASEROCDROM *cdrom, unsigned char **buf);
+
+#endif				/* FREEBSD_DVD_RW_UTILS_H */
--- /dev/null	2008-02-03 02:26:39.000000000 -0500
+++ src/cam/cam-cdrom.h	2008-02-03 11:32:23.000000000 -0500
@@ -0,0 +1,68 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * hfp-cdrom.h : SCSI CD-ROM abstraction layer
+ *
+ * Copyright (C) 2006 Jean-Yves Lefort <jylefort@FreeBSD.org>
+ *
+ * This program is free software; you can 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ **************************************************************************/
+
+#ifndef _BRASERO_CDROM_H
+#define _BRASERO_CDROM_H
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <glib.h>
+
+#include <sys/types.h>
+
+typedef struct _BRASEROCDROM BRASEROCDROM;
+
+typedef enum
+{
+  BRASERO_CDROM_DIRECTION_NONE,
+  BRASERO_CDROM_DIRECTION_IN,
+  BRASERO_CDROM_DIRECTION_OUT
+} BRASEROCDROMDirection;
+
+/* ATAPI/SCSI commands */
+enum
+{
+  BRASERO_CDROM_TEST_UNIT_READY			= 0x00,
+  BRASERO_CDROM_GET_EVENT_STATUS_NOTIFICATION	= 0x4a,
+  BRASERO_CDROM_MODE_SENSE_BIG			= 0x5a
+};
+
+BRASEROCDROM *brasero_cdrom_new (const char *path);
+
+gboolean brasero_cdrom_send_ccb (BRASEROCDROM *cdrom,
+			    const char *ccb,
+			    int ccb_len,
+			    BRASEROCDROMDirection direction,
+			    void *data,
+			    int len,
+			    char **err);
+
+gboolean brasero_cdrom_test_unit_ready (BRASEROCDROM *cdrom);
+
+int brasero_cdrom_get_fd (BRASEROCDROM *cdrom);
+
+void brasero_cdrom_free (BRASEROCDROM *cdrom);
+
+#endif /* _BRASERO_CDROM_H */
--- /dev/null	2008-02-03 13:11:45.000000000 -0500
+++ src/cam/cam-cdrom.c	2008-02-03 13:24:53.000000000 -0500
@@ -0,0 +1,156 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * cam-cdrom.c : SCSI CD-ROM abstraction layer
+ *
+ * Copyright (C) 2006 Jean-Yves Lefort <jylefort@FreeBSD.org>
+ *
+ * This program is free software; you can 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/ata.h>
+#include <stdio.h>
+#include <camlib.h>
+#include <cam/scsi/scsi_message.h>
+#include <glib.h>
+
+#include "cam-cdrom.h"
+
+struct _BRASEROCDROM
+{
+  struct cam_device	*cam;		/* for SCSI drives */
+  int                    fd;
+};
+
+BRASEROCDROM *
+brasero_cdrom_new (const char *path)
+{
+  BRASEROCDROM *cdrom = NULL;
+  struct cam_device *cam;
+  int fd;
+
+  g_assert(path != NULL);
+
+  /* brasero_open_device() fails unless we use O_RDWR */
+  cam = cam_open_device(path, O_RDWR);
+  fd = open(path, O_RDONLY | O_NONBLOCK);
+  if (cam && fd > -1)
+    {
+      cdrom = g_new0(BRASEROCDROM, 1);
+      cdrom->cam = cam;
+      cdrom->fd = fd;
+    }
+
+  return cdrom;
+}
+
+gboolean
+brasero_cdrom_send_ccb (BRASEROCDROM *cdrom,
+		    const char *ccb,
+		    int ccb_len,
+		    BRASEROCDROMDirection direction,
+		    void *data,
+		    int len,
+		    char **err)
+{
+  int timeout;
+
+  g_assert(cdrom != NULL);
+  g_assert(ccb != NULL);
+  g_assert(direction == BRASERO_CDROM_DIRECTION_NONE
+	 || direction == BRASERO_CDROM_DIRECTION_IN
+	 || direction == BRASERO_CDROM_DIRECTION_OUT);
+  g_assert(direction == BRASERO_CDROM_DIRECTION_NONE || data != NULL);
+
+  timeout = 10;
+
+  union ccb cam_ccb;
+  static int scsi_direction[] = { CAM_DIR_NONE, CAM_DIR_IN, CAM_DIR_OUT };
+
+  memset(&cam_ccb, 0, sizeof(cam_ccb));
+
+  cam_ccb.ccb_h.path_id = cdrom->cam->path_id;
+  cam_ccb.ccb_h.target_id = cdrom->cam->target_id;
+  cam_ccb.ccb_h.target_lun = cdrom->cam->target_lun;
+
+  cam_fill_csio(&cam_ccb.csio,
+		1,
+		NULL,
+		scsi_direction[direction],
+		MSG_SIMPLE_Q_TAG,
+		data,
+		len,
+		sizeof(cam_ccb.csio.sense_data),
+		ccb_len,
+		timeout * 1000);
+
+  memcpy(cam_ccb.csio.cdb_io.cdb_bytes, ccb, 16);
+
+  if (cam_send_ccb(cdrom->cam, &cam_ccb) == -1)
+    {
+      if (err)
+        *err = g_strdup_printf("cam_send_ccb() failure: %s", g_strerror(errno));
+    }
+  if ((cam_ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
+    {
+      if (err)
+        *err = g_strdup_printf("CCB request failed with status %i", cam_ccb.ccb_h.status & CAM_STATUS_MASK);
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+gboolean
+brasero_cdrom_test_unit_ready (BRASEROCDROM *cdrom)
+{
+  static char ccb[16] = { BRASERO_CDROM_TEST_UNIT_READY };
+
+  g_assert(cdrom != NULL);
+
+  return brasero_cdrom_send_ccb(cdrom, ccb, 6, BRASERO_CDROM_DIRECTION_NONE, NULL, 0, NULL);
+}
+
+int
+brasero_cdrom_get_fd (BRASEROCDROM *cdrom)
+{
+  g_assert(cdrom != NULL);
+
+  return (cdrom->fd);
+}
+
+void
+brasero_cdrom_free (BRASEROCDROM *cdrom)
+{
+  g_assert(cdrom != NULL);
+
+  if (cdrom->cam)
+    cam_close_device(cdrom->cam);
+
+  close(cdrom->fd);
+
+  g_free(cdrom);
+}
--- /dev/null	2008-02-03 13:11:45.000000000 -0500
+++ src/cam/freebsd_dvd_rw_utils.c	2008-02-03 13:30:36.000000000 -0500
@@ -0,0 +1,1075 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
+ *
+ * This is part of dvd+rw-tools by Andy Polyakov <appro@fy.chalmers.se>
+ *
+ * Use-it-on-your-own-risk, GPL bless...
+ *
+ * For further details see http://fy.chalmers.se/~appro/linux/DVD+RW/
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <glib.h>
+
+#include "freebsd_dvd_rw_utils.h"
+
+typedef enum {
+	NONE = BRASERO_CDROM_DIRECTION_NONE,
+	READ = BRASERO_CDROM_DIRECTION_IN,
+	WRITE = BRASERO_CDROM_DIRECTION_OUT
+} Direction;
+
+typedef struct ScsiCommand ScsiCommand;
+
+struct ScsiCommand {
+	BRASEROCDROM		*cdrom;
+	char			ccb[16];
+	int			len;
+};
+
+static ScsiCommand *
+scsi_command_new_from_cdrom (BRASEROCDROM *cdrom)
+{
+	ScsiCommand *cmd;
+
+	cmd = g_new0 (ScsiCommand, 1);
+	cmd->cdrom = cdrom;
+
+	return cmd;
+}
+
+static void
+scsi_command_free (ScsiCommand * cmd)
+{
+	free (cmd);
+}
+
+static void
+scsi_command_init (ScsiCommand * cmd, size_t i, int arg)
+{
+	cmd->ccb[i] = arg;
+	if (i == 0 || i >= cmd->len)
+		cmd->len = i + 1;
+}
+
+static int
+scsi_command_transport (ScsiCommand * cmd, Direction dir, void *buf,
+			size_t sz)
+{
+	if (brasero_cdrom_send_ccb(cmd->cdrom, cmd->ccb, cmd->len, dir, buf, sz, NULL))
+		return 0;
+	else
+		return -1;
+}
+
+int
+brasero_cdrom_get_dvd_r_rw_profile (BRASEROCDROM *cdrom)
+{
+	ScsiCommand *cmd;
+	int retval = 0;
+	unsigned char page[20];
+	unsigned char *list;
+	int i, len;
+
+	g_return_val_if_fail (cdrom != NULL, -1);
+
+	cmd = scsi_command_new_from_cdrom (cdrom);
+
+	scsi_command_init (cmd, 0, 0x46);
+	scsi_command_init (cmd, 1, 2);
+	scsi_command_init (cmd, 8, 8);
+	scsi_command_init (cmd, 9, 0);
+	if (scsi_command_transport (cmd, READ, page, 8)) {
+		/* GET CONFIGURATION failed */
+		scsi_command_free (cmd);
+		return -1;
+	}
+
+	/* See if it's 2 gen drive by checking if DVD+R profile is an option */
+	len = 4 + (page[0] << 24 | page[1] << 16 | page[2] << 8 | page[3]);
+	if (len > 264) {
+		scsi_command_free (cmd);
+		/* insane profile list length */
+		return -1;
+	}
+
+	list = g_new (unsigned char, len);
+
+	scsi_command_init (cmd, 0, 0x46);
+	scsi_command_init (cmd, 1, 2);
+	scsi_command_init (cmd, 7, len >> 8);
+	scsi_command_init (cmd, 8, len);
+	scsi_command_init (cmd, 9, 0);
+	if (scsi_command_transport (cmd, READ, list, len)) {
+		/* GET CONFIGURATION failed */
+		scsi_command_free (cmd);
+		free (list);
+		return -1;
+	}
+
+	for (i = 12; i < list[11]; i += 4) {
+		int profile = (list[i] << 8 | list[i + 1]);
+		/* 0x13: DVD-RW Restricted Overwrite
+		 * 0x14: DVD-RW Sequential
+		 * 0x1B: DVD+R
+		 * 0x1A: DVD+RW
+		 * 0x2A: DVD+RW DL
+		 * 0x2B: DVD+R DL
+		 * 0x40: BD-ROM
+		 * 0x41: BD-R SRM
+		 * 0x42: BD-R RRM
+		 * 0x43: BD-RE
+		 * 0x50: HD DVD-ROM
+		 * 0x51: HD DVD-R
+		 * 0x52: HD DVD-Rewritable
+		 */
+
+		switch (profile) {
+			case 0x13:
+			case 0x14:
+				retval |= DRIVE_CDROM_CAPS_DVDRW;
+				break;
+			case 0x1B:
+				retval |= DRIVE_CDROM_CAPS_DVDPLUSR;
+				break;
+			case 0x1A:
+				retval |= DRIVE_CDROM_CAPS_DVDPLUSRW;
+				break;
+			case 0x2A:
+				retval |= DRIVE_CDROM_CAPS_DVDPLUSRWDL;
+				break;
+			case 0x2B:
+				retval |= DRIVE_CDROM_CAPS_DVDPLUSRDL;
+				break;
+			case 0x40:
+				retval |= DRIVE_CDROM_CAPS_BDROM;
+				break;
+			case 0x41:
+			case 0x42:
+				retval |= DRIVE_CDROM_CAPS_BDR;
+				break;
+			case 0x43:
+				retval |= DRIVE_CDROM_CAPS_BDRE;
+				break;
+			case 0x50:
+				retval |= DRIVE_CDROM_CAPS_HDDVDROM;
+				break;
+			case 0x51:
+				retval |= DRIVE_CDROM_CAPS_HDDVDR;
+				break;
+			case 0x52:
+				retval |= DRIVE_CDROM_CAPS_HDDVDRW;
+				break;
+			default:
+				break;
+		}
+	}
+
+	scsi_command_free (cmd);
+	free (list);
+
+	return retval;
+
+}
+
+static unsigned char *
+pull_page2a_from_cdrom (BRASEROCDROM *cdrom)
+{
+	ScsiCommand *cmd;
+	unsigned char header[12], *page2A;
+	unsigned int len, bdlen;
+
+	g_return_val_if_fail (cdrom != NULL, NULL);
+
+	cmd = scsi_command_new_from_cdrom (cdrom);
+
+	scsi_command_init (cmd, 0, 0x5A);	/* MODE SENSE */
+	scsi_command_init (cmd, 1, 0x08);	/* Disable Block Descriptors */
+	scsi_command_init (cmd, 2, 0x2A);	/* Capabilities and Mechanical Status */
+	scsi_command_init (cmd, 8, sizeof (header));	/* header only to start with */
+	scsi_command_init (cmd, 9, 0);
+
+	if (scsi_command_transport (cmd, READ, header, sizeof (header))) {
+		/* MODE SENSE failed */
+		scsi_command_free (cmd);
+		return NULL;
+	}
+
+	len = (header[0] << 8 | header[1]) + 2;
+	bdlen = header[6] << 8 | header[7];
+
+	/* should never happen as we set "DBD" above */
+	if (bdlen) {
+		if (len < (8 + bdlen + 30)) {
+			/* LUN impossible to bear with */
+			scsi_command_free (cmd);
+			return NULL;
+		}
+	} else if (len < (8 + 2 + (unsigned int) header[9])) {
+		/* SANYO does this. */
+		len = 8 + 2 + header[9];
+	}
+
+	page2A = g_new (unsigned char, len);
+	if (page2A == NULL) {
+		/* ENOMEM */
+		scsi_command_free (cmd);
+		return NULL;
+	}
+
+	scsi_command_init (cmd, 0, 0x5A);	/* MODE SENSE */
+	scsi_command_init (cmd, 1, 0x08);	/* Disable Block Descriptors */
+	scsi_command_init (cmd, 2, 0x2A);	/* Capabilities and Mechanical Status */
+	scsi_command_init (cmd, 7, len >> 8);
+	scsi_command_init (cmd, 8, len);	/* Real length */
+	scsi_command_init (cmd, 9, 0);
+	if (scsi_command_transport (cmd, READ, page2A, len)) {
+		/* MODE SENSE failed */
+		scsi_command_free (cmd);
+		free (page2A);
+		return NULL;
+	}
+
+	scsi_command_free (cmd);
+
+	len -= 2;
+	/* paranoia */
+	if (len < ((unsigned int) page2A[0] << 8 | page2A[1])) {
+		page2A[0] = len >> 8;
+		page2A[1] = len;
+	}
+
+	return page2A;
+}
+
+static int
+int_compare (const void *a, const void *b)
+{
+	/* descending order */
+	return *((int *) b) - *((int *) a);
+}
+
+/* gets the list of supported write speeds.  in the event
+ * that anything goes wrong, returns NULL.
+ */
+static char *
+get_write_speeds (const unsigned char *p, int length, int max_speed)
+{
+	char *result, *str;
+	int nr_records;
+	int *tmpspeeds;
+	int i, j;
+
+	result = NULL;
+
+	/* paranoia */
+	if (length < 32)
+		return NULL;
+
+	nr_records = p[30] << 8 | p[31];
+
+	/* paranoia */
+	if (length < 32 + 4 * nr_records)
+		return NULL;
+
+	tmpspeeds = g_new (int, nr_records);
+
+	for (i = 0; i < nr_records; i++)
+	{
+		tmpspeeds[i] = p[4*i + 34] << 8 | p[4*i + 35];
+
+		/* i'm not sure how likely this is to show up, but it's
+		 * definitely wrong.  if we see it, abort.
+		 */
+		if (tmpspeeds[i] == 0)
+			goto free_tmpspeeds;
+	}
+
+	/* sort */
+	qsort (tmpspeeds, nr_records, sizeof (int), int_compare);
+
+	/* uniq */
+	for (i = j = 0; i < nr_records; i++)
+	{
+		tmpspeeds[j] = tmpspeeds[i];
+
+		/* make sure we don't look past the end of the array */
+		if (i >= (nr_records - 1) || tmpspeeds[i+1] != tmpspeeds[i])
+			j++;
+	}
+
+	/* j is now the number of unique entries in the array */
+	if (j == 0)
+		/* no entries?  this isn't right. */
+		goto free_tmpspeeds;
+
+	/* sanity check: the first item in the descending order
+	 * list ought to be the highest speed as detected through
+	 * other means
+	 */
+	if (tmpspeeds[0] != max_speed)
+		/* sanity check failed. */
+		goto free_tmpspeeds;
+
+	/* our values are 16-bit.  8 bytes per value
+	 * is more than enough including space for
+	 * ',' and '\0'.  we know j is not zero.
+	 */
+	result = str = g_new (char, 8 * j);
+
+	for (i = 0; i < j; i++)
+	{
+		if (i > 0)
+			*(str++) = ',';
+
+		str += sprintf (str, "%d", tmpspeeds[i]);
+	}
+
+free_tmpspeeds:
+	free (tmpspeeds);
+
+	return result;
+}
+
+int
+brasero_cdrom_get_read_write_speed (BRASEROCDROM *cdrom, int *read_speed, int *write_speed, char **write_speeds)
+{
+	unsigned char *page2A;
+	int len, hlen;
+	unsigned char *p;
+
+	g_return_val_if_fail (cdrom != NULL, -1);
+
+	*read_speed = 0;
+	*write_speed = 0;
+	*write_speeds = NULL;
+
+	page2A = pull_page2a_from_cdrom (cdrom);
+	if (page2A == NULL) {
+		printf ("Failed to get Page 2A\n");
+		/* Failed to get Page 2A */
+		return -1;
+	}
+
+	len = (page2A[0] << 8 | page2A[1]) + 2;
+	hlen = 8 + (page2A[6] << 8 | page2A[7]);
+	p = page2A + hlen;
+
+	/* Values guessed from the cd_mode_page_2A struct
+	 * in cdrecord's libscg/scg/scsireg.h */
+	if (len < (hlen + 30) || p[1] < (30 - 2)) {
+		/* no MMC-3 "Current Write Speed" present,
+		 * try to use the MMC-2 one */
+		if (len < (hlen + 20) || p[1] < (20 - 2))
+			*write_speed = 0;
+		else
+			*write_speed = p[18] << 8 | p[19];
+	} else {
+		*write_speed = p[28] << 8 | p[29];
+	}
+
+	if (len >= hlen+9)
+	    *read_speed = p[8] << 8 | p[9];
+	else
+	    *read_speed = 0;
+
+	*write_speeds = get_write_speeds (p, len, *write_speed);
+
+	free (page2A);
+
+	return 0;
+}
+
+
+static int
+get_disc_capacity_cd (BRASEROCDROM *cdrom, guint64 *size)
+{
+	ScsiCommand *cmd;
+	int retval;
+	guint64 block_size;
+	guint64 num_blocks;
+	unsigned char header [8];
+
+	g_return_val_if_fail (cdrom != NULL, -1);
+
+	retval = -1;
+
+	cmd = scsi_command_new_from_cdrom (cdrom);
+	scsi_command_init (cmd, 0, 0x25);
+	scsi_command_init (cmd, 9, 0);
+	if (scsi_command_transport (cmd, READ, header, 8)) {
+		/* READ CDROM CAPACITY failed */
+		goto done;
+	}
+
+	num_blocks = (header [0] << 24) | (header [1] << 16) | (header [2] << 8) | header [3];
+	num_blocks++;
+	block_size = header [4] << 24 | header [5] << 16 | header [6] << 8 | header [7];
+
+	if (size) {
+		*size = num_blocks * block_size;
+	}
+	retval = 0;
+
+ done:
+	scsi_command_free (cmd);
+
+	return retval;
+}
+
+static int
+get_disc_capacity_cdr (BRASEROCDROM *cdrom, guint64 *size)
+{
+	ScsiCommand *cmd;
+	int retval;
+	guint64 secs;
+	unsigned char toc [8];
+	unsigned char *atip;
+	int len;
+
+	g_return_val_if_fail (cdrom != NULL, -1);
+
+	retval = -1;
+
+	cmd = scsi_command_new_from_cdrom (cdrom);
+	/* READ_TOC */
+	scsi_command_init (cmd, 0, 0x43);
+	/* FMT_ATIP */
+	scsi_command_init (cmd, 2, 4 & 0x0F);
+	scsi_command_init (cmd, 6, 0);
+	scsi_command_init (cmd, 8, 4);
+	scsi_command_init (cmd, 9, 0);
+
+	if (scsi_command_transport (cmd, READ, toc, 4)) {
+		/* READ TOC failed */
+		goto done;
+	}
+
+	len = 2 + (toc [0] << 8 | toc [1]);
+
+	atip = g_new (unsigned char, len);
+
+	scsi_command_init (cmd, 0, 0x43);
+	scsi_command_init (cmd, 2, 4 & 0x0F);
+	scsi_command_init (cmd, 6, 0);
+	scsi_command_init (cmd, 7, len >> 8);
+	scsi_command_init (cmd, 8, len);
+	scsi_command_init (cmd, 9, 0);
+
+	if (scsi_command_transport (cmd, READ, atip, len)) {
+		/* READ TOC failed */
+		free (atip);
+		goto done;
+	}
+
+	secs = atip [12] * 60 + atip [13] + (atip [14] / 75 + 1);
+
+	if (size) {
+		*size = (1 + secs * 7 / 48) * 1024 * 1024;
+	}
+	retval = 0;
+
+	free (atip);
+ done:
+	scsi_command_free (cmd);
+
+	return retval;
+}
+
+static int
+get_disc_capacity_dvdr_from_type (BRASEROCDROM *cdrom, int type, guint64 *size)
+{
+	ScsiCommand *cmd;
+	unsigned char formats [260];
+	unsigned char buf [32];
+	guint64 blocks;
+	guint64 nwa;
+	int i;
+	int len;
+	int obligatory;
+	int retval;
+	int next_track;
+
+	g_return_val_if_fail (cdrom != NULL, -1);
+
+	retval = -1;
+	blocks = 0;
+	next_track = 1;
+
+	cmd = scsi_command_new_from_cdrom (cdrom);
+
+ retry:
+	if (type == 0x1A || type == 0x14 || type == 0x13 || type == 0x12) {
+
+		/* READ FORMAT CAPACITIES */
+		scsi_command_init (cmd, 0, 0x23);
+		scsi_command_init (cmd, 8, 12);
+		scsi_command_init (cmd, 9, 0);
+		if (scsi_command_transport (cmd, READ, formats, 12)) {
+			/* READ FORMAT CAPACITIES failed */
+			goto done;
+		}
+
+		len = formats [3];
+		if (len & 7 || len < 16) {
+			/* Length isn't sane */
+			goto done;
+		}
+
+		scsi_command_init (cmd, 0, 0x23);
+		scsi_command_init (cmd, 7, (4 + len) >> 8);
+		scsi_command_init (cmd, 8, (4 + len) & 0xFF);
+		scsi_command_init (cmd, 9, 0);
+		if (scsi_command_transport (cmd, READ, formats, 4 + len)) {
+			/* READ FORMAT CAPACITIES failed */
+			goto done;
+		}
+
+		if (len != formats [3]) {
+			/* Parameter length inconsistency */
+			goto done;
+		}
+	}
+
+	obligatory = 0x00;
+
+	switch (type) {
+    	case 0x1A:		/* DVD+RW */
+		obligatory = 0x26;
+	case 0x13:		/* DVD-RW Restricted Overwrite */
+	case 0x14:		/* DVD-RW Sequential */
+		for (i = 8, len = formats [3]; i < len; i += 8) {
+			if ((formats [4 + i + 4] >> 2) == obligatory) {
+				break;
+			}
+		}
+
+		if (i == len) {
+			/* Can't find obligatory format descriptor */
+			goto done;
+		}
+
+		blocks  = formats [4 + i + 0] << 24;
+		blocks |= formats [4 + i + 1] << 16;
+		blocks |= formats [4 + i + 2] << 8;
+		blocks |= formats [4 + i + 3];
+		nwa = formats [4 + 5] << 16 | formats [4 + 6] << 8 | formats [4 + 7];
+		if (nwa > 2048) {
+			blocks *= nwa / 2048;
+		} else if (nwa < 2048) {
+			blocks /= 2048 / nwa;
+		}
+
+		retval = 0;
+		break;
+
+	case 0x12:		/* DVD-RAM */
+
+		blocks  = formats [4 + 0] << 24;
+		blocks |= formats [4 + 1] << 16;
+		blocks |= formats [4 + 2] << 8;
+		blocks |= formats [4 + 3];
+		nwa = formats [4 + 5] << 16 | formats [4 + 6] << 8 | formats [4 + 7];
+		if (nwa > 2048) {
+			blocks *= nwa / 2048;
+		} else if (nwa < 2048) {
+			blocks /= 2048 / nwa;
+		}
+
+		retval = 0;
+		break;
+
+	case 0x11:		/* DVD-R */
+	case 0x1B:		/* DVD+R */
+	case 0x2B:		/* DVD+R Double Layer */
+	case 0x41:		/* BD-R SRM */
+
+		/* READ TRACK INFORMATION */
+		scsi_command_init (cmd, 0, 0x52);
+		scsi_command_init (cmd, 1, 1);
+		scsi_command_init (cmd, 4, next_track >> 8);
+		scsi_command_init (cmd, 5, next_track & 0xFF);
+		scsi_command_init (cmd, 8, sizeof (buf));
+		scsi_command_init (cmd, 9, 0);
+		if (scsi_command_transport (cmd, READ, buf, sizeof (buf))) {
+			/* READ TRACK INFORMATION failed */
+			if (next_track > 0) {
+				goto done;
+			} else {
+				next_track = 1;
+				goto retry;
+			}
+		}
+
+		blocks = buf [24] << 24;
+		blocks |= buf [25] << 16;
+		blocks |= buf [26] << 8;
+		blocks |= buf [27];
+
+		retval = 0;
+		break;
+	case 0x43:	/* DB-RE */
+		/* Pull the formatted capacity */
+		blocks  = formats [4 + 0] << 24;
+		blocks |= formats [4 + 1] << 16;
+		blocks |= formats [4 + 2] << 8;
+		blocks |= formats [4 + 3];
+		break;
+	default:
+		blocks = 0;
+		break;
+	}
+
+ done:
+	scsi_command_free (cmd);
+
+	if (size) {
+		*size = blocks * 2048;
+	}
+
+	return retval;
+}
+
+int
+brasero_cdrom_get_disc_capacity_for_type (BRASEROCDROM *cdrom, int type, guint64 *size)
+{
+	int retval;
+
+	g_return_val_if_fail (cdrom != NULL, -1);
+
+	retval = -1;
+
+	switch (type) {
+	case 0x8:
+		retval = get_disc_capacity_cd (cdrom, size);
+		break;
+	case 0x9:
+	case 0xa:
+		retval = get_disc_capacity_cdr (cdrom, size);
+		break;
+	case 0x10:
+		retval = get_disc_capacity_cd (cdrom, size);
+		break;
+	case 0x11:
+	case 0x13:
+	case 0x14:
+	case 0x1B:
+	case 0x2B:
+	case 0x1A:
+	case 0x12:
+	case 0x41:
+	case 0x43:
+		retval = get_disc_capacity_dvdr_from_type (cdrom, type, size);
+		break;
+	default:
+		retval = -1;
+	}
+
+	return retval;
+}
+
+int
+brasero_cdrom_get_disc_type (BRASEROCDROM *cdrom)
+{
+	ScsiCommand *cmd;
+	int retval = -1;
+	unsigned char header[8];
+
+	g_return_val_if_fail (cdrom != NULL, -1);
+
+	cmd = scsi_command_new_from_cdrom (cdrom);
+
+	scsi_command_init (cmd, 0, 0x46);
+	scsi_command_init (cmd, 1, 1);
+	scsi_command_init (cmd, 8, 8);
+	scsi_command_init (cmd, 9, 0);
+	if (scsi_command_transport (cmd, READ, header, 8)) {
+		/* GET CONFIGURATION failed */
+		scsi_command_free (cmd);
+		return -1;
+	}
+
+	retval = (header[6]<<8)|(header[7]);
+
+
+	scsi_command_free (cmd);
+	return retval;
+}
+
+int
+brasero_cdrom_get_configuration_feature (BRASEROCDROM *cdrom,
+				  	 int feature,
+				  	 unsigned char **buf)
+{
+	ScsiCommand *cmd;
+	int retval = 0;
+	int len;
+	unsigned char header[8];
+
+	g_return_val_if_fail (cdrom != NULL, -1);
+	g_return_val_if_fail (buf != NULL, -1);
+
+	cmd = scsi_command_new_from_cdrom (cdrom);
+
+	scsi_command_init (cmd, 0, 0x46);
+	scsi_command_init (cmd, 1, 2);
+	scsi_command_init (cmd, 2, feature >> 8);
+	scsi_command_init (cmd, 3, feature);
+	scsi_command_init (cmd, 8, 8);
+	scsi_command_init (cmd, 9, 0);
+	if (scsi_command_transport (cmd, READ, header, 8)) {
+		scsi_command_free (cmd);
+		return -1;
+	}
+
+	len = 4 + (header[0] << 24 | header[1] << 16 | header[2] << 8 | header[3]);
+	if (len > 264) {
+		scsi_command_free (cmd);
+		return -1;
+	}
+
+	*buf = g_new (unsigned char, len);
+
+	scsi_command_init (cmd, 0, 0x46);
+	scsi_command_init (cmd, 1, 2);
+	scsi_command_init (cmd, 2, feature >> 8);
+	scsi_command_init (cmd, 3, feature);
+	scsi_command_init (cmd, 7, len >> 8);
+	scsi_command_init (cmd, 8, len);
+	scsi_command_init (cmd, 9, 0);
+	if (scsi_command_transport (cmd, READ, *buf, len)) {
+		g_free (*buf);
+		*buf = NULL;
+		retval = -1;
+	}
+
+	scsi_command_free (cmd);
+
+	return retval;
+}
+
+int
+brasero_cdrom_read_disc_information_std (BRASEROCDROM *cdrom,
+				         unsigned char *buf)
+{
+	ScsiCommand *cmd;
+	int retval = 0;
+
+	g_return_val_if_fail (cdrom != NULL, -1);
+	g_return_val_if_fail (buf != NULL, -1);
+
+	cmd = scsi_command_new_from_cdrom (cdrom);
+
+	/* see section 5.19 of MMC-3 from http://www.t10.org/drafts.htm#mmc3 */
+	scsi_command_init (cmd, 0, 0x51); /* READ_DISC_INFORMATION */
+	scsi_command_init (cmd, 8, 32);
+	scsi_command_init (cmd, 9, 0);
+	if (scsi_command_transport (cmd, READ, buf, 32)) {
+		retval = -1;
+	}
+
+	scsi_command_free (cmd);
+	return retval;
+}
+
+int
+brasero_cdrom_read_track_info (BRASEROCDROM *cdrom,
+			       int track_num,
+			       unsigned char *buf,
+			       int size)
+{
+	ScsiCommand *cmd;
+	int retval = 0;
+
+	g_return_val_if_fail (cdrom != NULL, -1);
+	g_return_val_if_fail (buf != NULL, -1);
+
+	cmd = scsi_command_new_from_cdrom (cdrom);
+
+	scsi_command_init (cmd, 0, 0x52);
+	scsi_command_init (cmd, 1, 1);
+	scsi_command_init (cmd, 4, track_num >> 8);
+	scsi_command_init (cmd, 5, track_num & 0xFF);
+	scsi_command_init (cmd, 8, size);
+	scsi_command_init (cmd, 9, 0);
+	if (scsi_command_transport (cmd, READ, buf, size)) {
+		retval = -1;
+	}
+
+	scsi_command_free (cmd);
+	return retval;
+}
+
+int
+brasero_cdrom_read_toc_formatted (BRASEROCDROM *cdrom,
+				  int track_num,
+				  unsigned char **buf)
+{
+	ScsiCommand *cmd;
+	int retval = 0;
+	int len;
+	unsigned char header[4];
+
+	g_return_val_if_fail (cdrom != NULL, -1);
+	g_return_val_if_fail (buf != NULL, -1);
+
+	cmd = scsi_command_new_from_cdrom (cdrom);
+
+	scsi_command_init (cmd, 0, 0x43);
+	scsi_command_init (cmd, 2, 0);
+	scsi_command_init (cmd, 6, track_num);
+	scsi_command_init (cmd, 8, 4);
+	scsi_command_init (cmd, 9, 0);
+	if (scsi_command_transport (cmd, READ, header, 4)) {
+		scsi_command_free (cmd);
+		*buf = NULL;
+		return -1;
+	}
+
+	len = (header[0] << 8 | header[1]) + 2;
+
+	*buf = g_malloc0 (len);
+
+	scsi_command_init (cmd, 8, len);
+	scsi_command_init (cmd, 9, 0);
+	if (scsi_command_transport (cmd, READ, *buf, len)) {
+		g_free (*buf);
+		*buf = NULL;
+		retval = -1;
+	}
+
+	scsi_command_free (cmd);
+	return retval;
+}
+
+int
+brasero_cdrom_read_toc_raw (BRASEROCDROM *cdrom,
+			    int track_num,
+			    unsigned char **buf)
+{
+	ScsiCommand *cmd;
+	int retval = 0;
+	int len;
+	unsigned char header[4];
+
+	g_return_val_if_fail (cdrom != NULL, -1);
+	g_return_val_if_fail (buf != NULL, -1);
+
+	cmd = scsi_command_new_from_cdrom (cdrom);
+
+	scsi_command_init (cmd, 0, 0x43);
+	scsi_command_init (cmd, 2, 2);
+	scsi_command_init (cmd, 6, track_num);
+	scsi_command_init (cmd, 8, 4);
+	scsi_command_init (cmd, 9, 0);
+	if (scsi_command_transport (cmd, READ, header, 4)) {
+		scsi_command_free (cmd);
+		*buf = NULL;
+		return -1;
+	}
+
+	len = (header[0] << 8 | header[1]) + 2;
+
+	*buf = g_malloc0 (len);
+
+	scsi_command_init (cmd, 8, len);
+	scsi_command_init (cmd, 9, 0);
+	if (scsi_command_transport (cmd, READ, *buf, len)) {
+		g_free (*buf);
+		*buf = NULL;
+		retval = -1;
+	}
+
+	scsi_command_free (cmd);
+	return retval;
+}
+
+int
+brasero_cdrom_read_atip (BRASEROCDROM *cdrom,
+			 unsigned char **buf)
+{
+	ScsiCommand *cmd;
+	int retval = 0;
+	int len;
+	unsigned char header[4];
+
+	g_return_val_if_fail (cdrom != NULL, -1);
+	g_return_val_if_fail (buf != NULL, -1);
+
+	cmd = scsi_command_new_from_cdrom (cdrom);
+
+	scsi_command_init (cmd, 0, 0x43);
+	scsi_command_init (cmd, 2, 4);
+	scsi_command_init (cmd, 6, 0);
+	scsi_command_init (cmd, 8, 4);
+	scsi_command_init (cmd, 9, 0);
+	if (scsi_command_transport (cmd, READ, header, 4)) {
+		scsi_command_free (cmd);
+		*buf = NULL;
+		return -1;
+	}
+
+	len = (header[0] << 8 | header[1]) + 2;
+
+	*buf = g_malloc0 (len);
+
+	scsi_command_init (cmd, 8, len);
+	scsi_command_init (cmd, 9, 0);
+	if (scsi_command_transport (cmd, READ, *buf, len)) {
+		g_free (*buf);
+		*buf = NULL;
+		retval = -1;
+	}
+
+	scsi_command_free (cmd);
+	return retval;
+}
+
+int
+brasero_cdrom_read_format_capacities (BRASEROCDROM *cdrom,
+			 	      unsigned char **buf)
+{
+	ScsiCommand *cmd;
+	int retval = 0;
+	int len;
+	unsigned char header[12];
+
+	g_return_val_if_fail (cdrom != NULL, -1);
+	g_return_val_if_fail (buf != NULL, -1);
+
+	cmd = scsi_command_new_from_cdrom (cdrom);
+
+	scsi_command_init (cmd, 0, 0x23);
+	scsi_command_init (cmd, 8, 12);
+	scsi_command_init (cmd, 9, 0);
+	if (scsi_command_transport (cmd, READ, header, 12)) {
+		/* READ FORMAT CAPACITIES failed */
+		return -1;
+	}
+
+	len = header [3];
+	if (len & 7 || len < 16) {
+		/* Length isn't sane */
+		return -1;
+	}
+
+	*buf = g_new (unsigned char, len + 4);
+
+	scsi_command_init (cmd, 0, 0x23);
+	scsi_command_init (cmd, 7, (4 + len) >> 8);
+	scsi_command_init (cmd, 8, (4 + len) & 0xFF);
+	scsi_command_init (cmd, 9, 0);
+	if (scsi_command_transport (cmd, READ, *buf, 4 + len)) {
+		/* READ FORMAT CAPACITIES failed */
+		g_free (*buf);
+		*buf = NULL;
+		retval = -1;
+	}
+
+	return retval;
+}
+
+int
+brasero_cdrom_get_performance_wrt_spd_desc (BRASEROCDROM *cdrom,
+			    		    unsigned char **buf)
+{
+	ScsiCommand *cmd;
+	int retval = 0;
+	int len;
+	int desc_num;
+	unsigned char header[8];
+
+	g_return_val_if_fail (cdrom != NULL, -1);
+	g_return_val_if_fail (buf != NULL, -1);
+
+	cmd = scsi_command_new_from_cdrom (cdrom);
+
+	scsi_command_init (cmd, 0, 0xac);
+	scsi_command_init (cmd, 8, 0);
+	scsi_command_init (cmd, 9, 0);
+	scsi_command_init (cmd, 10, 3);
+	scsi_command_init (cmd, 11, 0);
+	if (scsi_command_transport (cmd, READ, header, 8)) {
+		scsi_command_free (cmd);
+		*buf = NULL;
+		return -1;
+	}
+
+	len = (header[0] << 24 | header[1] << 16 | header[2] << 8 | header[3]) + 4;
+	if (len > 2048) {
+		len = 2048;
+	}
+
+	desc_num = (len - 8) / 12;
+
+	*buf = g_malloc0 (len);
+
+	scsi_command_init (cmd, 8, desc_num >> 8);
+	scsi_command_init (cmd, 9, desc_num);
+	scsi_command_init (cmd, 11, 0);
+	if (scsi_command_transport (cmd, READ, *buf, len)) {
+		g_free (*buf);
+		*buf = NULL;
+		retval = -1;
+	}
+
+	scsi_command_free (cmd);
+	return retval;
+}
+
+int
+brasero_cdrom_disc_is_appendable (BRASEROCDROM *cdrom)
+{
+	ScsiCommand *cmd;
+	int retval = -1;
+	unsigned char header[32];
+
+	g_return_val_if_fail (cdrom != NULL, -1);
+
+	cmd = scsi_command_new_from_cdrom (cdrom);
+
+	/* see section 5.19 of MMC-3 from http://www.t10.org/drafts.htm#mmc3 */
+	scsi_command_init (cmd, 0, 0x51); /* READ_DISC_INFORMATION */
+	scsi_command_init (cmd, 8, 32);
+	scsi_command_init (cmd, 9, 0);
+	if (scsi_command_transport (cmd, READ, header, 32)) {
+		/* READ_DISC_INFORMATION failed */
+		scsi_command_free (cmd);
+		return 0;
+	}
+
+	retval = ((header[2]&0x03) == 0x01);
+
+	scsi_command_free (cmd);
+	return retval;
+}
+
+int
+brasero_cdrom_disc_is_rewritable (BRASEROCDROM *cdrom)
+{
+	ScsiCommand *cmd;
+	int retval = -1;
+	unsigned char header[32];
+
+	g_return_val_if_fail (cdrom != NULL, -1);
+
+	cmd = scsi_command_new_from_cdrom (cdrom);
+
+	/* see section 5.19 of MMC-3 from http://www.t10.org/drafts.htm#mmc3 */
+	scsi_command_init (cmd, 0, 0x51); /* READ_DISC_INFORMATION */
+	scsi_command_init (cmd, 8, 32);
+	scsi_command_init (cmd, 9, 0);
+	if (scsi_command_transport (cmd, READ, header, 32)) {
+		/* READ_DISC_INFORMATION failed */
+		scsi_command_free (cmd);
+		return 0;
+	}
+
+	retval = ((header[2]&0x10) != 0);
+
+	scsi_command_free (cmd);
+	return retval;
+}
