Mercurial > illumos > illumos-gate
changeset 936:bb51223d93d7
6226041 "cdrw -p" command doesn't display the default speed
6327126 cdrw incorrectly interprets "1X" for DVD
author | arutz |
---|---|
date | Wed, 16 Nov 2005 10:49:09 -0800 |
parents | 375bf7616dfc |
children | e808c6c8cf8e |
files | usr/src/cmd/cdrw/dae.c usr/src/cmd/cdrw/device.c usr/src/cmd/cdrw/device.h usr/src/cmd/cdrw/misc_scsi.c usr/src/cmd/cdrw/misc_scsi.h usr/src/cmd/cdrw/mmc.h |
diffstat | 6 files changed, 274 insertions(+), 81 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/cmd/cdrw/dae.c Wed Nov 16 09:13:23 2005 -0800 +++ b/usr/src/cmd/cdrw/dae.c Wed Nov 16 10:49:09 2005 -0800 @@ -184,12 +184,13 @@ 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); } }
--- a/usr/src/cmd/cdrw/device.c Wed Nov 16 09:13:23 2005 -0800 +++ b/usr/src/cmd/cdrw/device.c Wed Nov 16 10:49:09 2005 -0800 @@ -864,3 +864,35 @@ } } } + +/* 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)); + } +}
--- a/usr/src/cmd/cdrw/device.h Wed Nov 16 09:13:23 2005 -0800 +++ b/usr/src/cmd/cdrw/device.h Wed Nov 16 10:49:09 2005 -0800 @@ -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 @@ #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 @@ 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 }
--- a/usr/src/cmd/cdrw/misc_scsi.c Wed Nov 16 09:13:23 2005 -0800 +++ b/usr/src/cmd/cdrw/misc_scsi.c Wed Nov 16 10:49:09 2005 -0800 @@ -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 @@ } /* - * 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"); - 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 { + /* 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"); + 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)); + 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, + cdrw_x_to_bandwidth(speed))); + break; + + default: + return (0); } - if (cmd == SET_WRITE_SPEED) { - rate = i_cd_speed_read(dev, GET_READ_SPEED); - return (set_cd_speed(dev->d_fd, rate, - SPEED_TO_XFER_RATE(speed))); - } - 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. + */ +static int +do_set_streaming(cd_device *dev, uint_t read_speed, + uint_t write_speed) +{ + int ret; + uchar_t *str; + + /* Allocate and initialize the Performance Descriptor */ + str = (uchar_t *)my_zalloc(SET_STREAM_DATA_LEN); + + /* Read Time (in milliseconds) */ + load_scsi32(&str[16], 1000); + /* Write Time (in milliseconds) */ + load_scsi32(&str[24], 1000); + + /* 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); + + 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) { - uchar_t *perf, *str; - int write_perf; - int ret; - uint16_t perf_got; + 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; - 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; - } - str = (uchar_t *)my_zalloc(SET_STREAM_DATA_LEN); - (void) memcpy(&str[8], &perf[16], 4); - load_scsi32(&str[16], 1000); - 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)); - } - ret = set_streaming(dev->d_fd, str); - free(str); + 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"); + /* 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); + dev->d_speed_ctrl = cd_speed_ctrl; + ret = dev->d_speed_ctrl(dev, cmd, speed); + } + break; } -end_rsc: - free(perf); + 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; + } + + default: + break; + } + return (ret); } @@ -780,6 +923,9 @@ 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 "
--- a/usr/src/cmd/cdrw/misc_scsi.h Wed Nov 16 09:13:23 2005 -0800 +++ b/usr/src/cmd/cdrw/misc_scsi.h Wed Nov 16 10:49:09 2005 -0800 @@ -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 @@ #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 */
--- a/usr/src/cmd/cdrw/mmc.h Wed Nov 16 09:13:23 2005 -0800 +++ b/usr/src/cmd/cdrw/mmc.h Wed Nov 16 10:49:09 2005 -0800 @@ -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