void get_read_write_speeds(int fd, int *read_speed, int *write_speed, intlist_t **speeds, int *n_speeds, intlist_t **speeds_mem) { int page_len; uchar_t p[254]; int n; /* number of write speed performance descriptor blocks */ *read_speed = *write_speed = 0; *speeds = *speeds_mem = NULL; if (!get_mode_page(fd, 0x2A, 0, sizeof (p), p, &page_len)) { return; } if (page_len > 8) { *read_speed = GET16(&p[8]); } if (page_len > 18) { *write_speed = GET16(&p[18]); } if (page_len < 28) { printf("MMC-2\n"); return; } else { printf("MMC-3\n"); } *write_speed = GET16(&p[28]); if (page_len < 30) { return; } /* retrieve speed list */ n = GET16(&p[30]); n = min(n, (sizeof (p) - 32) / 4); get_write_speeds(&p[32], n, speeds, n_speeds, speeds_mem); if (*speeds != NULL) { *write_speed = max(*write_speed, (*speeds)[0].val); } }
/* * 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 cd_speed_get(cd_device *dev, int cmd) { 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"); if (cmd == GET_READ_SPEED) { /* this is Obsolete, but try it */ offset = 14; rate = read_scsi16(&mp2a[offset]); } else { /* 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); }
/* * Set page code 5 for TAO mode. */ int prepare_for_write(cd_device *dev, int track_mode, int test_write, int keep_disc_open) { uchar_t *buf; int no_err; int reset_device; if ((write_mode == DAO_MODE) && keep_disc_open) { (void) printf(gettext( "Multi-session is not supported on DVD media\n")); exit(1); } if ((write_mode == DAO_MODE) && debug) { (void) printf("Preparing to write in DAO\n"); } (void) start_stop(dev->d_fd, 1); /* Some drives do not support this command but still do it */ (void) rezero_unit(dev->d_fd); buf = (uchar_t *)my_zalloc(64); no_err = get_mode_page(dev->d_fd, 5, 0, 64, buf); if (no_err) no_err = ((buf[1] + 2) > 64) ? 0 : 1; /* * If the device is already in simulation mode and again a * simulation is requested, then set the device in non-simulation * 1st and then take it to simulation mode. This will flush any * previous fake state in the drive. */ if (no_err && test_write && (buf[2] & 0x10)) { reset_device = 1; } else { reset_device = 0; } if (no_err != 0) { buf[0] &= 0x3f; /* set TAO or DAO writing mode */ buf[2] = (write_mode == TAO_MODE)?1:2; /* set simulation flag */ if (test_write && (!reset_device)) { buf[2] |= 0x10; } else { buf[2] &= ~0x10; } /* Turn on HW buffer underrun protection (BUFE) */ if (!test_write) { buf[2] |= 0x40; } /* set track mode type */ if (device_type == CD_RW) { buf[3] = track_mode & 0x0f; /* ctrl nibble */ } else { buf[3] = 5; /* always 5 for DVD */ } if (keep_disc_open) { buf[3] |= 0xc0; /* Allow more sessions */ } /* Select track type (audio or data) */ if (track_mode == TRACK_MODE_DATA) { buf[4] = 8; /* 2048 byte sector */ } else { buf[4] = 0; /* 2352 byte sector */ } buf[7] = buf[8] = 0; /* Need to clear these fields for setting into DAO */ if (write_mode == DAO_MODE) buf[5] = buf[15] = 0; /* print out mode for detailed log */ if (debug && verbose) { int i; (void) printf("setting = [ "); for (i = 0; i < 15; i++) (void) printf("0x%x ", buf[i]); (void) printf("]\n"); } no_err = set_mode_page(dev->d_fd, buf); if (no_err && reset_device) { /* Turn the test write bit back on */ buf[2] |= 0x10; no_err = set_mode_page(dev->d_fd, buf); } /* * Since BUFE is the only optional flag we are * setting we will try to turn it off if the command * fails. */ if (!no_err) { /* * Some old drives may not support HW * buffer underrun protection, try again * after turning it off. */ if (debug) (void) printf("Turning off BUFE\n"); buf[2] &= ~0x40; no_err = set_mode_page(dev->d_fd, buf); } } free(buf); return (no_err); }