bf787b0aa1
the works in progress.
1361 lines
32 KiB
Text
1361 lines
32 KiB
Text
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;
|
|
+}
|