summaryrefslogtreecommitdiff
path: root/usr/src/cmd/cdrw
diff options
context:
space:
mode:
authorarutz <none@none>2005-11-16 10:49:09 -0800
committerarutz <none@none>2005-11-16 10:49:09 -0800
commit9858459238fb4f2d8f924f4d3fe9f51ed2e32564 (patch)
treec25c83315a70c8739d45886b13bcd788ae6d6ffe /usr/src/cmd/cdrw
parentdafb55404788372f219f7456c26a732d130439d5 (diff)
downloadillumos-joyent-9858459238fb4f2d8f924f4d3fe9f51ed2e32564.tar.gz
6226041 "cdrw -p" command doesn't display the default speed
6327126 cdrw incorrectly interprets "1X" for DVD
Diffstat (limited to 'usr/src/cmd/cdrw')
-rw-r--r--usr/src/cmd/cdrw/dae.c11
-rw-r--r--usr/src/cmd/cdrw/device.c32
-rw-r--r--usr/src/cmd/cdrw/device.h17
-rw-r--r--usr/src/cmd/cdrw/misc_scsi.c264
-rw-r--r--usr/src/cmd/cdrw/misc_scsi.h17
-rw-r--r--usr/src/cmd/cdrw/mmc.h4
6 files changed, 269 insertions, 76 deletions
diff --git a/usr/src/cmd/cdrw/dae.c b/usr/src/cmd/cdrw/dae.c
index 4a0c059e6f..563b18a8a5 100644
--- a/usr/src/cmd/cdrw/dae.c
+++ b/usr/src/cmd/cdrw/dae.c
@@ -184,12 +184,13 @@ read_audio_track(cd_device *dev, struct track_info *ti, bstreamhandle h)
if (speed == requested_speed) {
(void) printf(gettext("Speed set to %dX.\n"),
speed);
+ } else if (speed == 0) {
+ (void) printf(gettext("Could not obtain "
+ "current Read Speed.\n"));
} else {
- (void) printf(gettext(
- "Speed set to closest approximation "));
-
- (void) printf(gettext(
- "of %dX allowed by device (%dX).\n"),
+ (void) printf(gettext("Speed set to "
+ "closest approximation of %dX allowed "
+ "by device (%dX).\n"),
requested_speed, speed);
}
}
diff --git a/usr/src/cmd/cdrw/device.c b/usr/src/cmd/cdrw/device.c
index 208170f057..f1a582b08f 100644
--- a/usr/src/cmd/cdrw/device.c
+++ b/usr/src/cmd/cdrw/device.c
@@ -864,3 +864,35 @@ get_media_type(int fd)
}
}
}
+
+/* Translate a transfer rate (eg, KB/s) into a Speed (eg, "2X") */
+uint_t
+cdrw_bandwidth_to_x(uint_t rate)
+{
+ switch (device_type) {
+ case DVD_PLUS_W:
+ case DVD_MINUS:
+ case DVD_PLUS:
+ return (DVD_RATE_TO_X(rate));
+
+ default:
+ case CD_RW:
+ return (CD_RATE_TO_X(rate));
+ }
+}
+
+/* Translate a Speed (eg, "2X") into a transfer rate (eg, KB/s) */
+uint_t
+cdrw_x_to_bandwidth(uint_t x)
+{
+ switch (device_type) {
+ case DVD_PLUS_W:
+ case DVD_MINUS:
+ case DVD_PLUS:
+ return (DVD_X_TO_RATE(x));
+
+ default:
+ case CD_RW:
+ return (CD_X_TO_RATE(x));
+ }
+}
diff --git a/usr/src/cmd/cdrw/device.h b/usr/src/cmd/cdrw/device.h
index 0cfb9a0774..851d67dd53 100644
--- a/usr/src/cmd/cdrw/device.h
+++ b/usr/src/cmd/cdrw/device.h
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -39,23 +39,24 @@ extern "C" {
#define DEFAULT_CAPACITY (74*60*75)
-#define DEV_CAP_EXTRACT_CDDA 1
-#define DEV_CAP_ACCURATE_CDDA 2
-#define DEV_CAP_SETTING_SPEED_NOT_ALLOWED 4
-
typedef struct _device {
char *d_node;
char *d_name;
int d_fd;
uint_t d_blksize;
- uchar_t *d_inq;
- uint32_t d_cap;
+ uchar_t *d_inq; /* INQUIRY response data */
+ uint32_t d_cap; /* capabilities */
int (*d_read_audio)(struct _device *dev, uint_t start_blk,
uint_t nblks, uchar_t *buf);
int (*d_speed_ctrl)(struct _device *dev, int cmd,
int speed);
} cd_device;
+/* values for d_cap */
+#define DEV_CAP_EXTRACT_CDDA 1
+#define DEV_CAP_ACCURATE_CDDA 2
+#define DEV_CAP_SETTING_SPEED_NOT_ALLOWED 4
+
/*
* Speed commands
*/
@@ -77,6 +78,8 @@ int scan_for_cd_device(int mode, cd_device **found);
void write_next_track(int mode, bstreamhandle h);
int check_device(cd_device *dev, int cond);
void get_media_type(int fd);
+uint_t cdrw_bandwidth_to_x(uint_t rate);
+uint_t cdrw_x_to_bandwidth(uint_t x);
#ifdef __cplusplus
}
diff --git a/usr/src/cmd/cdrw/misc_scsi.c b/usr/src/cmd/cdrw/misc_scsi.c
index 3729093f2b..75069a634c 100644
--- a/usr/src/cmd/cdrw/misc_scsi.c
+++ b/usr/src/cmd/cdrw/misc_scsi.c
@@ -43,6 +43,7 @@
#include "main.h"
#include "toshiba.h"
#include "msgs.h"
+#include "device.h"
uint32_t
read_scsi32(void *addr)
@@ -597,104 +598,246 @@ eject_media(cd_device *dev)
}
/*
- * Get CD speed from Page code 2A. since GET PERFORMANCE is not supported
- * (which is already checked before) this mode page *will* have the speed.
+ * Get current Read or Write Speed from Mode Page 0x2a.
+ *
+ * Use the size of the Page to determine which Multimedia Command
+ * set (MMC) is present. Based on the MMC version, get the
+ * specified Read/Write Speed.
+ *
+ * Note that some MMC versions do not necessarily support a
+ * (current) Read or Write Speed. As a result, this function
+ * _can_ return a value of zero.
+ *
+ * The newer standards (reserve and) mark the field(s) as Obsolete,
+ * yet many vendors populate the Obsolete fields with valid values
+ * (assumedly for backward compatibility). This is important, as
+ * a command like GET PERFORMANCE cannot return _the_ speed; it can
+ * only return a Logical-Block-Address-dependent (LBA) speed. Such
+ * values can vary widely between the innermost and outermost Track.
+ * Mode Page 0x2a is the best solution identifying "the current
+ * (nominal) speed".
*/
static uint16_t
-i_cd_speed_read(cd_device *dev, int cmd)
+cd_speed_get(cd_device *dev, int cmd)
{
- uchar_t *mp2a;
- uint16_t rate;
+ uchar_t *mp2a;
+ uint16_t rate = 0;
+ int offset;
+ uint_t buflen = 254;
+
+ /*
+ * Allocate a buffer acceptably larger than any nominal
+ * Page for Page Code 0x2A.
+ */
+ mp2a = (uchar_t *)my_zalloc(buflen);
+ if (get_mode_page(dev->d_fd, 0x2A, 0, buflen, mp2a) == 0)
+ goto end;
+
+ /* Determine MMC version based on 'Page Length' field */
+ switch (mp2a[1]) {
+ case 0x14: /* MMC-1 */
+ if (debug)
+ (void) printf("Mode Page 2A: MMC-1\n");
+
+ offset = (cmd == GET_READ_SPEED) ? 14 : 20;
+ rate = read_scsi16(&mp2a[offset]);
+ break;
+
+
+ case 0x18: /* MMC-2 */
+ if (debug)
+ (void) printf("Mode Page 2A: MMC-2;"
+ " Read and Write Speeds are "
+ "obsolete\n");
+
+ /* see if "Obsolete" values are valid: */
+ offset = (cmd == GET_READ_SPEED) ? 14 : 20;
+ rate = read_scsi16(&mp2a[offset]);
+ break;
+
+ default: /* MMC-3 or newer */
+ if (debug)
+ (void) printf("Mode Page 2A: MMC-3 or"
+ " newer; Read Speed is obsolete.\n");
- mp2a = (uchar_t *)my_zalloc(PAGE_CODE_2A_SIZE);
- if (get_mode_page(dev->d_fd, 0x2A, 0, PAGE_CODE_2A_SIZE,
- mp2a) == 0) {
- rate = 0;
- } else {
if (cmd == GET_READ_SPEED) {
- rate = ((uint16_t)mp2a[14] << 8) | mp2a[15];
+ /* this is Obsolete, but try it */
+ offset = 14;
+ rate = read_scsi16(&mp2a[offset]);
} else {
- rate = ((uint16_t)mp2a[20] << 8) | mp2a[21];
+ /* Write Speed is not obsolete */
+ offset = 28;
+ rate = read_scsi16(&mp2a[offset]);
+
+ if (rate == 0) {
+ /*
+ * then try an Obsolete field
+ * (but this shouldn't happen!)
+ */
+ offset = 20;
+ rate = read_scsi16(&mp2a[offset]);
+ }
}
+ break;
}
+end:
free(mp2a);
+
+ if (debug)
+ (void) printf("cd_speed_get: %s Speed is "
+ "%uX\n", (cmd == GET_READ_SPEED) ?
+ "Read" : "Write", cdrw_bandwidth_to_x(rate));
return (rate);
}
/*
* CD speed related functions (ioctl style) for drives which do not support
* real time streaming.
+ *
+ * For the SET operations, the SET CD SPEED command needs
+ * both the Read Speed and the Write Speed. Eg, if
+ * we're trying to set the Write Speed (SET_WRITE_SPEED),
+ * then we first need to obtain the current Read Speed.
+ * That speed is specified along with the chosen_speed (the
+ * Write Speed in this case) in the SET CD SPEED command.
*/
int
cd_speed_ctrl(cd_device *dev, int cmd, int speed)
{
uint16_t rate;
- if ((cmd == GET_READ_SPEED) || (cmd == GET_WRITE_SPEED))
- return (XFER_RATE_TO_SPEED(i_cd_speed_read(dev, cmd)));
- if (cmd == SET_READ_SPEED) {
- rate = i_cd_speed_read(dev, GET_WRITE_SPEED);
- return (set_cd_speed(dev->d_fd, SPEED_TO_XFER_RATE(speed),
- rate));
- }
- if (cmd == SET_WRITE_SPEED) {
- rate = i_cd_speed_read(dev, GET_READ_SPEED);
+ switch (cmd) {
+ case GET_READ_SPEED:
+ rate = cd_speed_get(dev, GET_READ_SPEED);
+ return (cdrw_bandwidth_to_x(rate));
+
+ case GET_WRITE_SPEED:
+ rate = cd_speed_get(dev, GET_WRITE_SPEED);
+ return (cdrw_bandwidth_to_x(rate));
+
+ case SET_READ_SPEED:
+ rate = cd_speed_get(dev, GET_WRITE_SPEED);
+ return (set_cd_speed(dev->d_fd,
+ cdrw_x_to_bandwidth(speed), rate));
+ break;
+
+ case SET_WRITE_SPEED:
+ rate = cd_speed_get(dev, GET_READ_SPEED);
return (set_cd_speed(dev->d_fd, rate,
- SPEED_TO_XFER_RATE(speed)));
+ cdrw_x_to_bandwidth(speed)));
+ break;
+
+ default:
+ return (0);
}
- return (0);
}
/*
- * cd speed related functions for drives which support RT-streaming
+ * Manage sending of SET STREAMING command using the specified
+ * read_speed and write_speed.
+ *
+ * This function allocates and initializes a Performance
+ * Descriptor, which is sent as part of the SET STREAMING
+ * command. The descriptor is deallocated before function
+ * exit.
*/
-int
-rt_streaming_ctrl(cd_device *dev, int cmd, int speed)
+static int
+do_set_streaming(cd_device *dev, uint_t read_speed,
+ uint_t write_speed)
{
- uchar_t *perf, *str;
- int write_perf;
int ret;
- uint16_t perf_got;
+ uchar_t *str;
- write_perf = 0;
- if ((cmd == GET_WRITE_SPEED) || (cmd == SET_READ_SPEED))
- write_perf = 1;
- perf = (uchar_t *)my_zalloc(GET_PERF_DATA_LEN);
- if (!get_performance(dev->d_fd, write_perf, perf)) {
- ret = 0;
- goto end_rsc;
- }
- perf_got = (uint16_t)read_scsi32(&perf[20]);
- if ((cmd == GET_READ_SPEED) || (cmd == GET_WRITE_SPEED)) {
- ret = XFER_RATE_TO_SPEED(perf_got);
- goto end_rsc;
- }
+ /* Allocate and initialize the Performance Descriptor */
str = (uchar_t *)my_zalloc(SET_STREAM_DATA_LEN);
- (void) memcpy(&str[8], &perf[16], 4);
+
+ /* Read Time (in milliseconds) */
load_scsi32(&str[16], 1000);
+ /* Write Time (in milliseconds) */
load_scsi32(&str[24], 1000);
- if (cmd == SET_WRITE_SPEED) {
- load_scsi32(&str[12], (uint32_t)perf_got);
- load_scsi32(&str[20], (uint32_t)SPEED_TO_XFER_RATE(speed));
- } else {
- load_scsi32(&str[20], (uint32_t)perf_got);
- load_scsi32(&str[12], (uint32_t)SPEED_TO_XFER_RATE(speed));
- }
+
+ /* Read Speed */
+ load_scsi32(&str[12], (uint32_t)read_speed);
+ /* Write Speed */
+ load_scsi32(&str[20], (uint32_t)write_speed);
+
+ /* issue SET STREAMING command */
ret = set_streaming(dev->d_fd, str);
free(str);
- /* If rt_speed_ctrl fails for any reason use cd_speed_ctrl */
- if (ret == 0) {
- if (debug)
- (void) printf(" real time speed control"
- " failed, using CD speed control\n");
+ return (ret);
+}
+
+/*
+ * cd speed related functions for drives which support
+ * Real-Time Streaming Feature.
+ *
+ * For the SET operations, the SET STREAMING command needs
+ * both the Read Speed and the Write Speed. Eg, if
+ * we're trying to set the Write Speed (SET_WRITE_SPEED),
+ * then we first need to obtain the current Read Speed.
+ * That speed is specified along with the chosen_speed (the
+ * Write Speed in this case) in the SET STREAMING command.
+ */
+int
+rt_streaming_ctrl(cd_device *dev, int cmd, int speed)
+{
+ int ret = 0;
+ uint_t rate;
+
+ switch (cmd) {
+ case GET_WRITE_SPEED:
+ rate = cd_speed_get(dev, GET_WRITE_SPEED);
+ ret = (int)cdrw_bandwidth_to_x(rate);
+ break;
+
+ case GET_READ_SPEED:
+ rate = cd_speed_get(dev, GET_READ_SPEED);
+ ret = (int)cdrw_bandwidth_to_x(rate);
+ break;
+
+ case SET_READ_SPEED: {
+ uint_t write_speed = cd_speed_get(dev, GET_WRITE_SPEED);
+
+ /* set Read Speed using SET STREAMING */
+ ret = do_set_streaming(dev,
+ cdrw_x_to_bandwidth(speed), write_speed);
+
+ /* If rt_speed_ctrl fails for any reason use cd_speed_ctrl */
+ if (ret == 0) {
+ if (debug)
+ (void) printf(" real time speed control"
+ " failed, using CD speed control\n");
+
+ dev->d_speed_ctrl = cd_speed_ctrl;
+ ret = dev->d_speed_ctrl(dev, cmd, speed);
+ }
+ break;
+ }
+
+ case SET_WRITE_SPEED: {
+ uint_t read_speed = cd_speed_get(dev, GET_READ_SPEED);
+
+ /* set Write Speed using SET STREAMING */
+ ret = do_set_streaming(dev, read_speed,
+ cdrw_x_to_bandwidth(speed));
+
+ /* If rt_speed_ctrl fails for any reason use cd_speed_ctrl */
+ if (ret == 0) {
+ if (debug)
+ (void) printf(" real time speed control"
+ " failed, using CD speed control\n");
+
+ dev->d_speed_ctrl = cd_speed_ctrl;
+ ret = dev->d_speed_ctrl(dev, cmd, speed);
+ }
+ break;
+ }
- dev->d_speed_ctrl = cd_speed_ctrl;
- ret = dev->d_speed_ctrl(dev, cmd, speed);
+ default:
+ break;
}
-end_rsc:
- free(perf);
return (ret);
}
@@ -780,6 +923,9 @@ write_init(int mode)
if (speed == requested_speed) {
(void) printf(gettext("Speed set to %dX.\n"),
speed);
+ } else if (speed == 0) {
+ (void) printf(gettext("Could not obtain "
+ "current Write Speed.\n"));
} else {
(void) printf(
gettext("Speed set to closest approximation "
diff --git a/usr/src/cmd/cdrw/misc_scsi.h b/usr/src/cmd/cdrw/misc_scsi.h
index b59efa3a28..9cd6d0cc53 100644
--- a/usr/src/cmd/cdrw/misc_scsi.h
+++ b/usr/src/cmd/cdrw/misc_scsi.h
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -74,11 +74,22 @@ struct track_info {
#define MAX_DVD_BLKS 2295100
/*
+ * Macros to translate between a bandwidth ("RATE") and a Speed ("X")
+ * for CDs. Eg, "1X == 176,400 bytes/second".
+ *
* Some devices just multiply speed by 176. But more accurate ones
* multiply speed by 176.4.
*/
-#define XFER_RATE_TO_SPEED(r) ((r) % 176 ? ((((r)*10)+5)/1764) : (r) / 176)
-#define SPEED_TO_XFER_RATE(s) ((((s)*1764)+5)/10)
+#define CD_RATE_TO_X(r) ((r) % 176 ? ((((r)*10)+5)/1764) : (r) / 176)
+#define CD_X_TO_RATE(s) ((((s)*1764)+5)/10)
+
+/*
+ * Macros to translate between a bandwidth ("RATE") and a Speed ("X")
+ * for DVDs. Eg, "1X == 1,385,000 bytes/second".
+ */
+#define DVD_RATE_TO_X(r) (((ulong_t)(r)*1000)/1385000)
+#define DVD_X_TO_RATE(s) (((s)*1385000)/1000)
+
#define FINALIZE_TIMEOUT (6 * 12) /* Six minutes */
diff --git a/usr/src/cmd/cdrw/mmc.h b/usr/src/cmd/cdrw/mmc.h
index 8215f3759c..34a9fffd83 100644
--- a/usr/src/cmd/cdrw/mmc.h
+++ b/usr/src/cmd/cdrw/mmc.h
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -33,8 +33,8 @@
extern "C" {
#endif
+/* bytelengths for some SCSI data structures */
#define SENSE_DATA_SIZE 16
-#define PAGE_CODE_2A_SIZE 26
#define TRACK_INFO_SIZE 36
#define DISC_INFO_BLOCK_SIZE 32
#define INQUIRY_DATA_LENGTH 96