/* * Builds track information database for track trackno. If trackno is * -1, builds the database for next blank track. */ int build_track_info(cd_device *dev, int trackno, struct track_info *t_info) { uchar_t *ti; uchar_t toc[20]; /* 2 entries + 4 byte header */ int ret; (void) memset(t_info, 0, sizeof (*t_info)); /* 1st try READ TRACK INFORMATION */ ti = (uchar_t *)my_zalloc(TRACK_INFO_SIZE); t_info->ti_track_no = trackno; /* Gererate faked information for writing to DVD */ if (device_type != CD_RW) { uint_t bsize; t_info->ti_flags = 0x3000; t_info->ti_track_no = 1; t_info->ti_session_no = 1; t_info->ti_track_mode = 0x4; t_info->ti_data_mode = 1; t_info->ti_start_address = 0; /* only 1 track on DVD make it max size */ t_info->ti_track_size = read_format_capacity(target->d_fd, &bsize); if (t_info->ti_track_size < MAX_CD_BLKS) { t_info->ti_track_size = MAX_DVD_BLKS; } t_info->ti_nwa = 0; t_info->ti_lra = 0; t_info->ti_packet_size = 0x10; t_info->ti_free_blocks = 0; } if (read_track_info(dev->d_fd, trackno, ti)) { if (debug) (void) printf("using read_track_info for TOC \n"); t_info->ti_track_no = ti[2]; t_info->ti_session_no = ti[3]; t_info->ti_flags = (ti[6] >> 4) & 0xf; t_info->ti_flags |= (uint32_t)(ti[5] & 0xf0); t_info->ti_flags |= (uint32_t)(ti[7]) << 8; t_info->ti_flags |= TI_SESSION_NO_VALID | TI_FREE_BLOCKS_VALID; t_info->ti_track_mode = ti[5] & 0xf; if ((ti[6] & 0xf) == 0xf) t_info->ti_data_mode = 0xff; else t_info->ti_data_mode = ti[6] & 0xf; t_info->ti_start_address = read_scsi32(&ti[8]); t_info->ti_nwa = read_scsi32(&ti[12]); t_info->ti_free_blocks = read_scsi32(&ti[16]); t_info->ti_packet_size = read_scsi32(&ti[20]); t_info->ti_track_size = read_scsi32(&ti[24]); t_info->ti_lra = read_scsi32(&ti[28]); free(ti); return (1); } /* READ TRACK INFORMATION not supported, try other options */ free(ti); /* * We can get info for next blank track if READ TRACK INFO is not * supported. */ if (trackno == -1) return (0); if (debug) (void) printf("using READ_TOC for TOC\n"); /* Try Read TOC */ if (!read_toc(dev->d_fd, 0, trackno, 20, toc)) { return (0); } t_info->ti_start_address = read_scsi32(&toc[8]); t_info->ti_track_mode = toc[5] & 0xf; t_info->ti_track_size = read_scsi32(&toc[16]) - read_scsi32(&toc[8]); t_info->ti_data_mode = get_data_mode(dev->d_fd, read_scsi32(&toc[8])); /* Numbers for audio tracks are always in 2K chunks */ if ((dev->d_blksize == 512) && ((t_info->ti_track_mode & 4) == 0)) { t_info->ti_start_address /= 4; t_info->ti_track_size /= 4; } /* Now find out the session thing */ ret = read_toc(dev->d_fd, 1, trackno, 12, toc); /* * Make sure that the call succeeds and returns the requested * TOC size correctly. */ if ((ret == 0) || (toc[1] != 0x0a)) { /* For ATAPI drives or old Toshiba drives */ ret = read_toc_as_per_8020(dev->d_fd, 1, trackno, 12, toc); } /* If this goes through well TOC length will always be 0x0a */ if (ret && (toc[1] == 0x0a)) { if (trackno >= toc[6]) { t_info->ti_session_no = toc[3]; t_info->ti_flags |= TI_SESSION_NO_VALID; } /* * This might be the last track of this session. If so, * exclude the leadout and next lead in. */ if (trackno == (toc[6] - 1)) { /* * 1.5 Min leadout + 1 min. leadin + 2 sec. pre-gap. * For 2nd+ leadout it will be 0.5 min. But currently * there is no direct way. And it will not happen * for any normal case. * * 75 frames/sec, 60 sec/min, so leadin gap is * ((1.5 +1)*60 + 2)*75 = 11400 frames (blocks) */ t_info->ti_track_size -= 11400; } } return (1); }
void info(void) { uchar_t *toc, *p, *conf; int ret, toc_size; uint_t bsize; size_t cap = 0; char *msg; struct track_info *ti; msg = gettext("Cannot read Table of contents\n"); get_media_type(target->d_fd); (void) printf(gettext("\nDevice : %.8s %.16s\n"), &target->d_inq[8], &target->d_inq[16]); (void) printf(gettext("Firmware : Rev. %.4s (%.12s)\n"), &target->d_inq[32], &target->d_inq[36]); if (check_device(target, CHECK_DEVICE_NOT_READY)) { (void) check_device(target, CHECK_NO_MEDIA | EXIT_IF_CHECK_FAILED); (void) check_device(target, CHECK_DEVICE_NOT_READY | EXIT_IF_CHECK_FAILED); } if (verbose != 0) { /* * Determine the media type by reading the active profile * from the profile list. */ (void) printf(gettext("Media Type : ")); conf = (uchar_t *)my_zalloc(MMC_FTR_HDR_LEN); if (get_configuration(target->d_fd, MMC_FTR_PRFL_LIST, MMC_FTR_HDR_LEN, conf)) print_profile_name(read_scsi16(&conf[6]), 0, 1); else (void) printf(gettext("UNKNOWN\n")); free(conf); /* * Get the start address of the last possible lead out. */ cap = get_last_possible_lba(target); /* * The start address of the last possible leadout will only * be zero if the disc is full or this drive does not support * this method of determining capacity. */ if (cap == 0) cap = read_format_capacity(target->d_fd, &bsize); /* * Since both methods of determining the capacity of the * media count the correct number of blocks, just multiply * the capacity by the block size. */ cap *= target->d_blksize; if (device_type == CD_RW) { (void) printf(gettext("Media Capacity : %.2f MB "), ((double)cap/ONE_MB_BASE2)); } else { /* * For DVD's make sure we print out "Formatted Media * Capacity". Don't do this for CD-RWs as only * DVDs are formatted. */ (void) printf(gettext("Formatted Media Capacity : " "%.2f GB "), ((double)cap/ONE_GB_BASE10)); } cap /= target->d_blksize; (void) printf(gettext("(%u blocks)\n"), (uint_t)cap); } if (!check_device(target, CHECK_MEDIA_IS_NOT_BLANK)) { (void) printf(gettext("Media is blank\n")); exit(0); } /* Find out the number of entries in the toc */ toc = (uchar_t *)my_zalloc(12); if (!read_toc(target->d_fd, 0, 1, 4, toc)) { err_msg(msg); } else { toc_size = 256*toc[0] + toc[1] + 2; free(toc); /* allocate enough space for each track entry */ toc = (uchar_t *)my_zalloc(toc_size); if (!read_toc(target->d_fd, 0, 1, toc_size, toc)) { err_msg(msg); exit(1); } (void) printf("\n"); /* l10n_NOTE : Preserve column numbers of '|' character */ (void) printf(gettext("Track No. |Type |Start address\n")); (void) printf("----------+--------+-------------\n"); /* look at each track and display it's type. */ for (p = &toc[4]; p < (toc + toc_size); p += 8) { if (p[2] != 0xAA) (void) printf(" %-3d |", p[2]); else (void) printf("Leadout |"); (void) printf("%s |", (p[1] & 4) ? gettext("Data ") : gettext("Audio")); (void) printf("%u\n", read_scsi32(&p[4])); } } (void) printf("\n"); ret = read_toc(target->d_fd, 1, 0, 12, toc); if ((ret == 0) || (toc[1] != 0x0a)) /* For ATAPI drives or old Toshiba drives */ ret = read_toc_as_per_8020(target->d_fd, 1, 0, 12, toc); if (ret && (toc[1] == 0x0a)) { (void) printf(gettext("Last session start address: %u\n"), read_scsi32(&toc[8])); } free(toc); ti = (struct track_info *)my_zalloc(sizeof (struct track_info)); if (build_track_info(target, -1, ti) && (ti->ti_flags & TI_NWA_VALID)) { (void) printf(gettext("Next writable address: %u\n"), ti->ti_nwa); } free(ti); exit(0); }