/* sony - Sony CDU 92x-specific SCSI routines. */ #include #include #include #include #include #include #include #include #include #include #include #include "WriteCDR.h" #include "util.h" #include "sony.h" /* Sony CDU 92x vendor specific commands. */ #define READ_BUFFER_CAPACITY 0xEC #define WRITE_CONTINUE 0xE1 #define WRITE_START 0xE0 #define CLOSE_TRACK 0xF0 #define FINALIZE 0xF1 #define WRITE_TRACK 0xF5 /* Symbolic data field values. */ #define DISC_STYLE_UNINTERRUPTED 0 #define DISC_STYLE_INTERRUPTED_AUDIO 0x80 #define DISC_STYLE_INTERRUPTED_DATA 0xC0 #define DISC_TYPE_CD_DA_OR_CD_ROM 0 #define DISC_TYPE_CD_I 0x10 #define DISC_TYPE_CD__ROM_XA 0x20 #define DATA_FORM_COPY (0<<6) #define DATA_FORM_ORIGINAL_WITH_COPYRIGHT (1<<6) #define DATA_FORM_COPYRIGHT_FREE (2<<6) #define DATA_FORM_2CH_AUDIO_WITHOUT_PREEMPHASIS 0 #define DATA_FORM_2CH_AUDIO_WITH_PREEMPHASIS 2 #define DATA_FORM_CD_ROM_MODE_1 0x10 #define DATA_FORM_CD_ROM_MODE_2 0x11 #define DATA_FORM_CD_ROM_MODE_2_FORM_1_2 0x12 /* A cue sheet entry. */ typedef struct { unchar control; unchar track_number; unchar index; unchar data_form; unchar zero; unchar min; unchar sec; unchar frame; } cue_sheet_entry; /* mode sense / mode select page layout. */ typedef struct { unchar sense_data_length; unchar medium_type; unchar reserved; unchar block_descriptor_length; } sense_header; typedef struct { unchar reserved1; unchar medium_type; unchar reserved2; unchar block_descriptor_length; } select_header; typedef struct { unchar density_code; unsigned number_of_blocks: 24; unchar reserved; unsigned block_length: 24; } block_descriptor; typedef struct { /* CD-R Mastering information Page. */ unsigned ps: 1; unsigned reserved0: 1; unsigned page_code: 6; unchar page_length; unchar offset; unsigned reserved1: 3; unsigned subcode_ecc: 1; unsigned c2po: 1; unsigned reserved2: 1; unsigned pseudo: 1; unsigned reserved3: 1; unchar reserved4; unchar cue_sheet_option; unchar reserved5; unchar reserved6; } page20; typedef struct { /* CD-R Disc Information Page. */ unsigned ps: 1; unsigned reserved0: 1; unsigned page_code: 6; unchar page_length; unchar disc_style; unchar disc_type; unchar first_track_number; unchar last_track_number; unchar number_of_sessions; unchar reserved1; unchar disc_application_code[4]; unchar last_possible_start[4]; unsigned recordability: 2; unsigned reserved2: 4; unsigned compatibility: 2; unchar number_of_valid_nra; unchar track_number_of_tip; unchar post_gap; unchar disc_identification_code[4]; unchar start_block_lead_in[4]; unchar reserved3[4]; } page22; typedef struct { /* CD-R Track Information Page. */ unsigned ps: 1; unsigned reserved0: 1; unsigned page_code: 6; unchar page_length; unchar reserved1; unchar track_number; unchar data_form; unchar write_method; unchar session_number; unchar track_status; ulong_t starting_lba; ulong_t next_recordable_address; ulong_t capacity_of_blank_area; ulong_t fixed_packet_size; ulong_t starting_msf; ulong_t ending_msf; ulong_t next_recordable_msf; } page23; typedef struct { /* Drive speed Page. */ unsigned ps: 1; unsigned reserved0: 1; unsigned page_code: 6; unchar page_length; unchar speed; unchar reserved; } page31; static struct {sense_header h; block_descriptor bd; page20 p;} page20_sense; static struct {sense_header h; block_descriptor bd; page31 p;} page31_sense; /* utility routines (1). * --------------------- */ static boolean_t check_sony_status(dsreq_t *dsp, char *msg) { if (check_status(dsp, msg)) { if (STATUS(dsp) == STA_CHECK) { unchar key = SENSEKEY(SENSEBUF(dsp)); unchar asc = ADDSENSECODE(SENSEBUF(dsp)); unchar ascq = SENSEBUF(dsp)[13]; char *m = 0; switch ((asc << 16) | (ascq << 8) | key) { case 0x000000: m = "No additional sense information"; break; case 0x001403: m = "Audio play operation stopped due to error"; break; case 0x020003: m = "No seek complete"; break; case 0x040002: m = "Logical unit not ready, cause not reportable"; break; case 0x040102: m = "Logical unit is in progress of becoming ready"; break; case 0x080004: m = "Logical unit communication failure"; break; case 0x090104: m = "Tracking servo failure"; break; case 0x090204: m = "Focus servo failure"; break; case 0x090304: m = "Spindle servo faiure"; break; case 0x110503: m = "L-EC uncorrectable error"; break; case 0x110603: m = "CIRC unrecovered error"; break; case 0x110D03: m = "Subcode ECC unrecovered error"; break; case 0x170101: m = "Recovered data with retries"; break; case 0x180101: m = "Recovered data with error correction & retries applied"; break; case 0x180401: m = "Recovered data with L-EC"; break; case 0x200005: m = "Invalid command operation code"; break; case 0x210005: m = "Logical block addres out of range"; break; case 0x240005: m = "Invalid field in CDB"; break; case 0x250005: m = "Logical unit not supported"; break; case 0x260005: m = "Invalid field in parameter list"; break; case 0x280006: m = "Not read to ready transition"; break; case 0x290006: m = "Power on, reset or bus device reset occured"; break; case 0x2a0106: m = "Mode parameter changed"; break; case 0x3a0002: m = "Medium not present"; break; case 0x400004: m = "Diagnostic failure on component 0 (ROM failure)"; break; case 0x400104: m = "Diagnostic failure on component 1 (RAM failure)"; break; case 0x400204: m = "Diagnostic failure on component 2 (buffer failure)"; break; case 0x400304: m = "Diagnostic failure on component 3 (internal bus failure)"; break; case 0x43000B: m = "Message error"; break; case 0x440004: m = "Internal target failure"; break; case 0x45000B: m = "Select/reselect failure"; break; case 0x48000B: m = "Initiator detected error message received"; break; case 0x49000B: m = "Invalid message error"; break; case 0x4E000B: m = "Overlapped command attempted"; break; case 0x470004: m = "SCSI parity error"; break; case 0x530002: m = "Media load/eject failed"; break; case 0x530205: m = "Medium removal prevent"; break; case 0x570002: m = "Unable to recover table-of-contents"; break; case 0x630005: m = "End of user area encountered on this track"; break; case 0x640005: m = "Illegal mode for this track"; break; case 0x800006: m = "Write complete"; break; case 0x810005: m = "Logical unit is reserved"; break; case 0x850005: m = "Audio address not valid"; break; case 0x880005: m = "Illegal cue sheet"; break; case 0x890005: m = "Inappropriate command"; break; case 0xB60004: m = "Media load mechanism failed"; break; case 0xB9000B: m = "Audio play operation aborted"; break; case 0xBF0005: m = "Buffer overflow for 'read all subcodes' command"; break; case 0xC00005: m = "Unrecordable disc"; break; case 0xC10005: m = "Illegal track status"; break; case 0xC20005: m = "Reserved track present"; break; case 0xC30005: m = "Buffer data size error"; break; case 0xC40005: m = "Illegal reserve length for 'reserve track' command"; break; case 0xC40105: m = "Illegal data form for 'reserve track' command"; break; case 0xC40205: m = "Unable to reserve track, because track mode has been changed"; break; case 0xC50006: m = "Buffer error during at once recording (writer ran out of data, system too slow)"; break; case 0xC60105: m = "Unwritten area encountered"; break; case 0xC60205: m = "Link blocks encountered"; break; case 0xC60305: m = "Nonexistent block encountered"; break; case 0xC70004: m = "Disc style mismatch"; break; case 0xC80005: m = "No table of contents"; break; case 0xC90005: m = "Illegal block length for write command"; break; case 0xCa0003: m = "Power calibration error"; break; case 0xCB0003: m = "Write error"; break; case 0xCB0006: m = "Write error during at once recording"; break; case 0xCB0603: m = "Write error track recovered"; break; case 0xCC0005: m = "Not enough space"; break; case 0xCD0005: m = "No track present to finalize"; break; case 0xCE0005: m = "Unrecoverable tracke descriptor encountered"; break; case 0xCF0005: m = "Damaged track present"; break; case 0xD00005: m = "PMA area full"; break; case 0xD10005: m = "PMA area full"; break; case 0xD20005: m = "Unrecovereable damaged track caused too small writable area"; break; case 0xD30005: m = "No bar code"; break; case 0xD30105: m = "Not enough bar code margin"; break; case 0xD30205: m = "No bar code start pattern"; break; case 0xD30305: m = "Illegal bar code length"; break; case 0xD30405: m = "Illegal bar code format"; break; case 0xD40006: m = "Exit from pseudo track at once recording"; break; } if (m != 0) printf("Sony ASC=0x%.2X/ASCQ=0x%.2X/key=0x%.2X means:\n %s.\n", asc, ascq, key, m); } return B_TRUE; } else return B_FALSE; } /* utility routines (2). * --------------------- */ static boolean_t close_track(dsreq_t *dsp) { fillg1cmd(dsp, (unchar *)CMDBUF(dsp), CLOSE_TRACK, 0, 0, 0, 0, 0, 0, 0, 0, 0); filldsreq(dsp, 0, 0, DSRQ_SENSE); TIME(dsp) = 600 * 1000; /* Set 10 minute timeout */ doscsireq(getfd(dsp), dsp); return check_sony_status(dsp, "Close Track"); } static boolean_t finalize(dsreq_t *dsp) { fillg1cmd(dsp, (unchar *)CMDBUF(dsp), FINALIZE, 0, 0, 0, 0, 0, 0, 0, 0, 0); filldsreq(dsp, 0, 0, DSRQ_SENSE); TIME(dsp) = 600 * 1000; /* Set 10 minute timeout */ doscsireq(getfd(dsp), dsp); return check_sony_status(dsp, "Finalize"); } static boolean_t read_buffer_capacity(dsreq_t *dsp, ulong_t *capacityp, ulong_t *blankp) { struct { unchar reserved1; unsigned total_length: 24; unchar reserved2; unsigned blank_length: 24; } buffer_capacity; fillg1cmd(dsp, (unchar *)CMDBUF(dsp), READ_BUFFER_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0); filldsreq(dsp, (unchar *)&buffer_capacity, sizeof buffer_capacity, DSRQ_READ | DSRQ_SENSE); doscsireq(getfd(dsp), dsp); *capacityp = buffer_capacity.total_length; *blankp = buffer_capacity.blank_length; return check_sony_status(dsp, "Read Buffer Capacity"); } static boolean_t set_track_type(dsreq_t *dsp, boolean_t audio) { struct {select_header h; block_descriptor bd; page22 p;} p22; struct {select_header h; block_descriptor bd; page23 p;} p23; modesense1a(dsp, (caddr_t)&p22, sizeof p22, 0, 0x22, 0); if (check_sony_status(dsp, "set_track_type/Mode Sense Page 22")) return B_TRUE; p22.h.reserved1 = 0; p22.p.track_number_of_tip = p22.p.last_track_number; modeselect15(dsp, (caddr_t)&p22, sizeof p22, 0, 0); if (check_sony_status(dsp, "set_track_type/Mode Select Page 22")) return B_TRUE; modesense1a(dsp, (caddr_t)&p23, sizeof p23, 0, 0x23, 0); if (check_sony_status(dsp, "set_track_type/Mode Sense Page 23")) return B_TRUE; p23.h.reserved1 = 0; if (audio) { if (p23.p.starting_lba > 2*FRAMES_PER_SECOND) p23.p.starting_lba -= 2*FRAMES_PER_SECOND; /* set audio pause length to zero */ p23.p.data_form = DATA_FORM_COPYRIGHT_FREE | DATA_FORM_2CH_AUDIO_WITHOUT_PREEMPHASIS; } else p23.p.data_form = DATA_FORM_COPYRIGHT_FREE | DATA_FORM_CD_ROM_MODE_1; p23.p.write_method = 0; /* track at once */ modeselect15(dsp, (caddr_t)&p23, sizeof p23, 0, 0); return check_sony_status(dsp, "set_track_type/Mode Select Page 23"); } static void setup_audio_cue_sheet(audio_info_t audio_info[99], uint_t n_files, cue_sheet_entry cue_sheet[99+3]) { int i; ulong_t start_block = 2 * FRAMES_PER_SECOND; /* start after initial 2 seconds pause */ /* lead-in. */ cue_sheet[0].control = 0x01; cue_sheet[0].track_number = 0; cue_sheet[0].index = 0; cue_sheet[0].data_form = 0; cue_sheet[0].zero = 0; cue_sheet[0].min = 0; cue_sheet[0].sec = 0; cue_sheet[0].frame = 0; /* 2 second pause at start of first track. */ cue_sheet[1].control = 0x21; cue_sheet[1].track_number = 1; cue_sheet[1].index = 0; cue_sheet[1].data_form = 0x01; /* Music */ cue_sheet[1].zero = 0; cue_sheet[1].min = 0; cue_sheet[1].sec = 0; cue_sheet[1].frame = 0; for (i = 0; i < n_files; i++) /* audio tracks. */ { cue_sheet[i + 2].control = 0x21; /* 00x0xxxx = 2-channel audio track, no pre-emphasis xx1xxxxx = copy permitted, xxxx0001 = always 1 */ cue_sheet[i + 2].track_number = INT2BCD(i + 1); cue_sheet[i + 2].index = 1; cue_sheet[i + 2].data_form = 0x01; /* Music */ cue_sheet[i + 2].zero = 0; cue_sheet[i + 2].min = INT2BCD(MINUTE(start_block)); cue_sheet[i + 2].sec = INT2BCD(SECOND(start_block)); cue_sheet[i + 2].frame = INT2BCD(FRAME(start_block)); start_block += audio_info[i].blocks; } /* lead-out. */ cue_sheet[n_files + 2].control = 0x01; cue_sheet[n_files + 2].track_number = 0xAA; cue_sheet[n_files + 2].index = 1; cue_sheet[n_files + 2].data_form = 0; cue_sheet[n_files + 2].zero = 0; cue_sheet[n_files + 2].min = INT2BCD(MINUTE(start_block)); cue_sheet[n_files + 2].sec = INT2BCD(SECOND(start_block)); cue_sheet[n_files + 2].frame = INT2BCD(FRAME(start_block)); } static void setup_data_cue_sheet(ulong_t total_bytes, cue_sheet_entry cue_sheet[4]) { ulong_t frames = (total_bytes + CDROM_BLOCKSIZE - 1) / CDROM_BLOCKSIZE + 2*FRAMES_PER_SECOND; /* lead-in. */ cue_sheet[0].control = 0x01; cue_sheet[0].track_number = 0; cue_sheet[0].index = 0; cue_sheet[0].data_form = 0; cue_sheet[0].zero = 0; cue_sheet[0].min = 0; cue_sheet[0].sec = 0; cue_sheet[0].frame = 0; /* 2 second pause at start of first track. */ cue_sheet[1].control = 0x61; cue_sheet[1].track_number = 1; cue_sheet[1].index = 0; cue_sheet[1].data_form = 0x10; cue_sheet[1].zero = 0; cue_sheet[1].min = 0; cue_sheet[1].sec = 0; cue_sheet[1].frame = 0; /* data track. */ cue_sheet[2].control = 0x61; /* 01x0xxxx = data track, xx1xxxxx = copy permitted, xxxx0001 = always 1 */ cue_sheet[2].track_number = 1; cue_sheet[2].index = 1; cue_sheet[2].data_form = 0x11; /* CD-ROM mode 1, we send 2048 byte blocks, drive generates Sync and EDC/ECC */ cue_sheet[2].zero = 0; cue_sheet[2].min = 0; cue_sheet[2].sec = 2; /* This track starts after the initial 2 second pause */ cue_sheet[2].frame = 0; /* lead-out. */ cue_sheet[3].control = 0x01; cue_sheet[3].track_number = 0xAA; cue_sheet[3].index = 1; cue_sheet[3].data_form = 0; cue_sheet[3].zero = 0; cue_sheet[3].min = INT2BCD(MINUTE(frames)); cue_sheet[3].sec = INT2BCD(SECOND(frames)); cue_sheet[3].frame = INT2BCD(FRAME(frames)); } static void write_continue(dsreq_t *dsp, unchar *buffer, ulong_t buffer_size) { fillg1cmd(dsp, (unchar *)CMDBUF(dsp), WRITE_CONTINUE, B3(buffer_size), 0, 0, 0, 0, 0, 0); filldsreq(dsp, buffer, buffer_size, DSRQ_WRITE | DSRQ_SENSE); TIME(dsp) = 600 * 1000 + buffer_size / 100; /* 10 minutes + 0.01ms/byte */ doscsireq(getfd(dsp), dsp); } static boolean_t write_start(dsreq_t *dsp, cue_sheet_entry cue_sheet[], ulong_t sheet_size) { fillg1cmd(dsp, (unchar *)CMDBUF(dsp), WRITE_START, B3(sheet_size), 0, 0, 0, 0, 0, 0); filldsreq(dsp, (unchar *)cue_sheet, sheet_size, DSRQ_WRITE | DSRQ_SENSE); TIME(dsp) = 120 * 1000; /* Set 2 minute timeout */ doscsireq(getfd(dsp), dsp); return check_sony_status(dsp, "Write Start"); } static boolean_t write_track(dsreq_t *dsp) { fillg1cmd(dsp, (unchar *)CMDBUF(dsp), WRITE_TRACK, 0, 0, 0, 0, 0, 0, 0, 0, 0); filldsreq(dsp, 0, 0, DSRQ_SENSE); TIME(dsp) = 120 * 1000; /* 2 minutes timeout */ doscsireq(getfd(dsp), dsp); return check_sony_status(dsp, "Write Track"); } /* utility routines (3). * --------------------- */ static boolean_t allocate_buffer(dsreq_t *dsp, uint_t block_size, ulong_t *alloc_size, unchar **data_buffer) { ulong_t buffer_size, buffer_room; /* Allocate a buffer that is about 1/8th of the device's buffer size. */ if (read_buffer_capacity(dsp, &buffer_size, &buffer_room)) return B_TRUE; *alloc_size = (buffer_size / (8*block_size)) * block_size; *data_buffer = (unchar *)malloc(*alloc_size); if (*data_buffer == 0) { fprintf(stderr, "Out of memory.\n"); return B_TRUE; } return B_FALSE; } /* Externally callable routines. * ----------------------------- */ void sony_cleanup_writer(dsreq_t *dsp) { struct {select_header h; block_descriptor bd; page20 p;} page20_select; struct {select_header h; block_descriptor bd; page31 p;} page31_select; if (page20_sense.h.sense_data_length != 0) { bcopy(&page20_sense, &page20_select, sizeof page20_sense); page20_select.h.reserved1 = 0; modeselect15(dsp, (caddr_t)&page20_select, sizeof page20_select, 0, 0); } if (page31_sense.h.sense_data_length != 0) { bcopy(&page31_sense, &page31_select, sizeof page31_sense); page31_select.h.reserved1 = 0; modeselect15(dsp, (caddr_t)&page31_select, sizeof page31_select, 0, 0); } prevent_removal(dsp, B_FALSE); eject_disc(dsp); } boolean_t sony_setup_writer(SETUP_WRITER_ARGS) { struct {select_header h; block_descriptor bd; page20 p;} page20_select; struct {select_header h; block_descriptor bd; page22 p;} p22; struct {select_header h; block_descriptor bd; page31 p;} page31_select; ulong_t capacity; modesense1a(dsp, (caddr_t)&page20_sense, sizeof page20_sense, 0, 0x20, 0); if (check_sony_status(dsp, "Mode Sense Page 20")) return B_TRUE; bcopy(&page20_sense, &page20_select, sizeof page20_sense); page20_select.h.reserved1 = 0; page20_select.bd.block_length = audio? CDDA_BLOCKSIZE : CDROM_BLOCKSIZE; page20_select.p.pseudo = (unsigned)check; if (writer_model < SonyCDU926S) page20_select.p.cue_sheet_option = 1; modeselect15(dsp, (caddr_t)&page20_select, sizeof page20_select, 0, 0); if (check_sony_status(dsp, "Mode Select Page 20")) return B_TRUE; modesense1a(dsp, (caddr_t)&p22, sizeof p22, 0, 0x22, 0); if (check_sony_status(dsp, "Mode Sense Page 22")) return B_TRUE; if (p22.p.recordability != 0) /* blank disc */ { if (p22.p.recordability == 1) fprintf(stderr, "Disc not blank.\n"); else fprintf(stderr, "Disc not recordable.\n"); return B_TRUE; } p22.h.reserved1 = 0; p22.p.disc_style = writer_model < SonyCDU926S? DISC_STYLE_UNINTERRUPTED : DISC_STYLE_INTERRUPTED_DATA; p22.p.disc_type = DISC_TYPE_CD_DA_OR_CD_ROM; p22.p.post_gap = 0; modeselect15(dsp, (caddr_t)&p22, sizeof p22, 0, 0); if (check_sony_status(dsp, "Mode Select Page 22")) return B_TRUE; modesense1a(dsp, (caddr_t)&page31_sense, sizeof page31_sense, 0, 0x31, 0); if (check_sony_status(dsp, "Mode Sense Page 31")) return B_TRUE; if (speed == 0) { speed = page31_sense.p.speed + 1; if (speed > max_speed) speed = max_speed; } else { bcopy(&page31_sense, &page31_select, sizeof page31_sense); page31_select.h.reserved1 = 0; page31_select.p.speed = speed - 1; modeselect15(dsp, (caddr_t)&page31_select, sizeof page31_select, 0, 0); if (check_sony_status(dsp, "Mode Select Page 31")) return B_TRUE; } capacity = ((MSF2INT(p22.p.last_possible_start[1], p22.p.last_possible_start[2], p22.p.last_possible_start[3])) - (2 * FRAMES_PER_SECOND * (audio? (n_files+1) : (writer_model >= SonyCDU926S? 2 : 1)))) * page20_select.bd.block_length; if (verbose > 0) report_sizes(capacity, total_bytes, page20_select.bd.block_length, speed); if (total_bytes > capacity) { fprintf(stderr, "Image data will not fit on disc.\n"); return B_TRUE; } return B_FALSE; } boolean_t sony_write_audio(WRITE_AUDIO_ARGS) { ulong_t alloc_size; ulong_t buffer_size; ulong_t buffer_room; ulong_t total_written = 0; unchar *data_buffer; cue_sheet_entry cue_sheet[99+3]; int fnr, i; if (allocate_buffer(dsp, CDDA_BLOCKSIZE, &alloc_size, &data_buffer)) return B_TRUE; /* Set up for writing. */ setup_audio_cue_sheet(audio_info, n_files, cue_sheet); if (write_start(dsp, cue_sheet, sizeof(cue_sheet[0]) * (n_files + 3))) return B_TRUE; /* write lead-in. */ if (verbose > 0) { printf("\rLead-in.%c", verbose > 1? '\n' : '\r'); fflush(stdout); } bzero(data_buffer, CDDA_BLOCKSIZE); for (i = 0; i < 2*FRAMES_PER_SECOND; i++) { write_continue(dsp, data_buffer, CDDA_BLOCKSIZE); if (check_sony_status(dsp, "Write Continue")) return B_TRUE; } /* write audio tracks. */ for (fnr = 0; fnr < n_files; fnr++) { ulong_t bytes_written = 0; ulong_t track_bytes = audio_info[fnr].blocks*CDDA_BLOCKSIZE; if (verbose > 0) printf("\r Track %d.%c", fnr + 1, verbose > 1? '\n' : '\r'); do { ulong_t read_size = track_bytes - bytes_written; ulong_t frames_read; if (read_size > alloc_size) read_size = alloc_size; frames_read = AFreadframes(audio_info[fnr].file, AF_DEFAULT_TRACK, data_buffer, (int)(read_size / 4)); if (4*frames_read != read_size) bzero(data_buffer + 4*frames_read, (read_size - 4*frames_read)); swap_bytes((ulong_t *)data_buffer, frames_read); if (read_buffer_capacity(dsp, &buffer_size, &buffer_room)) return B_TRUE; if ((total_written > buffer_size) && (buffer_room > buffer_size/4)) fputc('\007', stderr); write_continue(dsp, data_buffer, read_size); bytes_written += read_size; total_written += read_size; display_progress(verbose, total_written, total_bytes, buffer_size, buffer_room); if (total_written == total_bytes) { if (ADDSENSECODE(SENSEBUF(dsp)) != 0x80 /* write complete */) { fprintf(stderr, "\n'write complete' status missing for last block.\n"); check_sony_status(dsp, "Write Continue"); return B_TRUE; } } else if (check_sony_status(dsp, "Write Continue")) return B_TRUE; } while (bytes_written != track_bytes); } return B_FALSE; } boolean_t sony_write_image(WRITE_IMAGE_ARGS) { ulong_t alloc_size; ulong_t buffer_size; ulong_t buffer_room; unchar *data_buffer; ulong_t bytes_written = 0; cue_sheet_entry cue_sheet[4]; if (allocate_buffer(dsp, CDROM_BLOCKSIZE, &alloc_size, &data_buffer)) return B_TRUE; /* Set up for writing. */ setup_data_cue_sheet(total_bytes, cue_sheet); if (write_start(dsp, cue_sheet, sizeof cue_sheet)) return B_TRUE; /* write data track. */ do { ulong_t read_size = total_bytes - bytes_written; if (read_size > alloc_size) read_size = alloc_size; if (read_block(file_list, n_files, read_size, data_buffer)) return B_TRUE; if (read_buffer_capacity(dsp, &buffer_size, &buffer_room)) return B_TRUE; if ((bytes_written > buffer_size) && (buffer_room > buffer_size/4)) fputc('\007', stderr); write_continue(dsp, data_buffer, (read_size + CDROM_BLOCKSIZE - 1) / CDROM_BLOCKSIZE * CDROM_BLOCKSIZE); bytes_written += read_size; display_progress(verbose, bytes_written, total_bytes, buffer_size, buffer_room); if (bytes_written == total_bytes) { if (ADDSENSECODE(SENSEBUF(dsp)) != 0x80 /* write complete */) { fprintf(stderr, "\n'write complete' status missing for last block.\n"); check_sony_status(dsp, "Write Continue"); return B_TRUE; } } else if (check_sony_status(dsp, "Write Continue")) return B_TRUE; } while (bytes_written != total_bytes); return B_FALSE; } boolean_t sony926_write_audio(WRITE_AUDIO_ARGS) { ulong_t alloc_size; ulong_t buffer_size; ulong_t buffer_room; ulong_t total_written = 0; unchar *data_buffer; int fnr; if (allocate_buffer(dsp, CDDA_BLOCKSIZE, &alloc_size, &data_buffer)) return B_TRUE; /* write audio tracks. */ for (fnr = 0; fnr < n_files; fnr++) { ulong_t bytes_written = 0; ulong_t track_bytes = audio_info[fnr].blocks*CDDA_BLOCKSIZE; if (set_track_type(dsp, B_TRUE)) return B_TRUE; if (write_track(dsp)) return B_TRUE; if (verbose > 0) printf("\r Track %d.%c", fnr + 1, verbose > 1? '\n' : '\r'); do { ulong_t read_size = track_bytes - bytes_written; ulong_t frames_read; if (read_size > alloc_size) read_size = alloc_size; frames_read = AFreadframes(audio_info[fnr].file, AF_DEFAULT_TRACK, data_buffer, (int)(read_size / 4)); if (4*frames_read != read_size) bzero(data_buffer + 4*frames_read, (read_size - 4*frames_read)); swap_bytes((ulong_t *)data_buffer, frames_read); if (read_buffer_capacity(dsp, &buffer_size, &buffer_room)) return B_TRUE; if ((bytes_written > buffer_size) && (buffer_room > buffer_size/4)) fputc('\007', stderr); write_continue(dsp, data_buffer, read_size); bytes_written += read_size; total_written += read_size; display_progress(verbose, total_written, total_bytes, buffer_size, buffer_room); if (check_sony_status(dsp, "Write Continue")) return B_TRUE; } while (bytes_written != track_bytes); if (close_track(dsp)) return B_TRUE; testunitready00(dsp); testunitready00(dsp); if (check_sony_status(dsp, "Write Audio / flush")) return B_TRUE; } if (verbose > 0) printf("\nBegin fixation.\n"); return finalize(dsp); } boolean_t sony926_write_image(WRITE_IMAGE_ARGS) { ulong_t alloc_size; ulong_t buffer_size; ulong_t buffer_room; unchar *data_buffer; ulong_t bytes_written = 0; if (allocate_buffer(dsp, CDROM_BLOCKSIZE, &alloc_size, &data_buffer)) return B_TRUE; /* preset for writing. */ if (set_track_type(dsp, B_FALSE)) return B_TRUE; if (write_track(dsp)) return B_TRUE; /* write data. */ do { ulong_t read_size = total_bytes - bytes_written; if (read_size > alloc_size) read_size = alloc_size; if (read_block(file_list, n_files, read_size, data_buffer)) return B_TRUE; if (read_buffer_capacity(dsp, &buffer_size, &buffer_room)) return B_TRUE; if ((bytes_written > buffer_size) && (buffer_room > buffer_size/4)) fputc('\007', stderr); write_continue(dsp, data_buffer, (read_size + CDROM_BLOCKSIZE - 1) / CDROM_BLOCKSIZE * CDROM_BLOCKSIZE); bytes_written += read_size; display_progress(verbose, bytes_written, total_bytes, buffer_size, buffer_room); if (check_sony_status(dsp, "Write Continue")) return B_TRUE; } while (bytes_written != total_bytes); /* close track, finalize disc. */ if (close_track(dsp)) return B_TRUE; testunitready00(dsp); testunitready00(dsp); if (check_sony_status(dsp, "Write Image / flush")) return B_TRUE; if (verbose > 0) printf("\nBegin fixation.\n"); return finalize(dsp); }