From c05d6550cba125515cf66c5a3f9a8b04803bf8da Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Sat, 30 Dec 2006 00:15:07 +0000 Subject: [PATCH] Prepared support for DVD-RW in mode Restricted Overwrite --- cdrskin/cdrskin.c | 9 ++- cdrskin/cdrskin_timestamp.h | 2 +- libburn/libdax_msgs.h | 2 +- libburn/mmc.c | 83 ++++++++++++++++++++++--- libburn/mmc.h | 11 ++++ libburn/spc.c | 26 +++++++- libburn/write.c | 120 ++++++++++++++++++++++++++++++++++-- 7 files changed, 236 insertions(+), 17 deletions(-) diff --git a/cdrskin/cdrskin.c b/cdrskin/cdrskin.c index 619bb4b..f41dd1d 100644 --- a/cdrskin/cdrskin.c +++ b/cdrskin/cdrskin.c @@ -3781,6 +3781,9 @@ int Cdrskin_atip(struct CdrskiN *skin, int flag) } if(strstr(profile_name,"DVD")==profile_name) { printf("book type: %s (emulated booktype)\n", profile_name); + if(profile_number==0x13) + printf( + "cdrskin: for sdvdbackup: \"(growisofs mode Restricted Overwrite)\"\n"); } else { printf("ATIP info from disk:\n"); if(burn_disc_erasable(drive)) { @@ -4293,13 +4296,14 @@ int Cdrskin_activate_write_mode(struct CdrskiN *skin, enum burn_disc_status s, int flag) { int ok, was_still_default= 0, block_type_demand,track_type,sector_size, i; + int profile_number= -1; struct burn_drive_info *drive_info = NULL; char profile_name[80]; profile_name[0]= 0; #ifdef Cdrskin_libburn_has_get_profilE if(skin->grabbed_drive) - burn_disc_get_profile(skin->grabbed_drive,&i,profile_name); + burn_disc_get_profile(skin->grabbed_drive,&profile_number,profile_name); #endif if(strcmp(skin->preskin->write_mode_name,"DEFAULT")==0) { @@ -4308,7 +4312,8 @@ int Cdrskin_activate_write_mode(struct CdrskiN *skin, enum burn_disc_status s, if(s == BURN_DISC_APPENDABLE) { strcpy(skin->preskin->write_mode_name,"TAO"); was_still_default= 2; /*<<< prevents trying of SAO if drive dislikes TAO*/ - } else if(strstr(profile_name,"DVD+RW")==profile_name) { + } else if(strstr(profile_name,"DVD+RW")==profile_name || + profile_number == 0x13) { /* DVD-RW Restricted Overwrite */ strcpy(skin->preskin->write_mode_name,"TAO"); } else { strcpy(skin->preskin->write_mode_name,"SAO"); diff --git a/cdrskin/cdrskin_timestamp.h b/cdrskin/cdrskin_timestamp.h index 195938b..8ebb2d1 100644 --- a/cdrskin/cdrskin_timestamp.h +++ b/cdrskin/cdrskin_timestamp.h @@ -1 +1 @@ -#define Cdrskin_timestamP "2006.12.29.143734" +#define Cdrskin_timestamP "2006.12.30.001343" diff --git a/libburn/libdax_msgs.h b/libburn/libdax_msgs.h index ae81a41..d67e15a 100644 --- a/libburn/libdax_msgs.h +++ b/libburn/libdax_msgs.h @@ -336,7 +336,7 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff 0x0002011c (FATAL,HIGH) = Attempt to read track info from busy drive 0x0002011d (FATAL,HIGH) = SCSI error on write 0x0002011e (SORRY,HIGH) = Unsuitable media detected - 0x0002011f (SORRY,HIGH) = Burning of DVD+RW is restricted to a single track + 0x0002011f (SORRY,HIGH) = Burning is restricted to a single track 0x00020120 (NOTE,HIGH) = FORMAT UNIT ignored 0x00020121 (FATAL,HIGH) = Write preparation setup failed 0x00020122 (FATAL,HIGH) = SCSI error on format_unit diff --git a/libburn/mmc.c b/libburn/mmc.c index 410e02e..3e025df 100644 --- a/libburn/mmc.c +++ b/libburn/mmc.c @@ -37,6 +37,11 @@ extern struct libdax_msgs *libdax_messenger; /* ts A61219 : Based on knowlege from dvd+rw-tools-7.0 and mmc5r03c.pdf */ #define Libburn_support_dvd_plus_rW 1 +/* ts A61229 */ +/* +*/ +#define Libburn_support_dvd_minusrw_overW 1 + /* Progress report (with Libburn_support_dvd_plus_rW defined): ts A61219 : It seems to work with a used (i.e. thoroughly formatted) DVD+RW. Error messages of class DEBUG appear because of inability to @@ -152,7 +157,8 @@ int mmc_get_nwa(struct burn_drive *d, int trackno, int *lba, int *nwa) memcpy(c.opcode, MMC_TRACK_INFO, sizeof(MMC_TRACK_INFO)); c.opcode[1] = 1; if(trackno<=0) { - if (d->current_profile == 0x1a) /* DVD+RW */ + if (d->current_profile == 0x1a || d->current_profile == 0x13) + /* DVD+RW or DVD-RW restricted overwrite*/ c.opcode[5] = 1; else /* mmc5r03c.pdf: valid only for CD, DVD+R, DVD+R DL */ c.opcode[5] = 0xFF; @@ -593,9 +599,10 @@ void mmc_read_disc_info(struct burn_drive *d) */ d->bg_format_status = data[7] & 3; - /* <<< ts A61219 : preliminarily declare all DVD+RW blank, + /* ts A61219 : preliminarily declare all DVD+RW blank, (which is not the same as bg_format_status==0 "blank") */ - if (d->current_profile == 0x1a) + /* ts A61229 : same for DVD-RW Restricted overwrite */ + if (d->current_profile == 0x1a || d->current_profile == 0x13) d->status = BURN_DISC_BLANK; } @@ -1079,6 +1086,10 @@ void mmc_get_configuration(struct burn_drive *d) if (cp == 0x1a) d->current_is_supported_profile = 1; #endif +#ifdef Libburn_support_dvd_minusrw_overW + if (cp == 0x13) + d->current_is_supported_profile = 1; +#endif } @@ -1137,7 +1148,8 @@ int mmc_read_buffer_capacity(struct burn_drive *d) } -/* ts A61219 : learned much from dvd+rw-tools-7.0: plus_rw_format() */ +/* ts A61219 : learned much from dvd+rw-tools-7.0: plus_rw_format() + and mmc5r03c.pdf, 6.5 FORMAT UNIT */ int mmc_format_unit(struct burn_drive *d) { struct buffer buf; @@ -1156,10 +1168,10 @@ int mmc_format_unit(struct burn_drive *d) memset(c.page->data, 0, c.page->bytes); descr[0] = 0; + c.page->data[1] = 0x02; /* Immed */ + c.page->data[3] = 8; /* Format descriptor length */ if (d->current_profile == 0x1a) { /* DVD+RW */ - c.page->data[1] = 0x02; /* Immed */ - c.page->data[3] = 8; /* Format descriptor length */ - /* mmc5r03c.pdf , 6.5.4.2.14 */ + /* mmc5r03c.pdf , 6.5.4.2.14, DVD+RW Basic Format */ c.page->data[8] = 0x26 << 2; /* Format type */ memset(c.page->data + 4, 0xff, 4); /* maximum blocksize */ if (d->bg_format_status == 1) /* is partly formatted */ @@ -1173,6 +1185,11 @@ int mmc_format_unit(struct burn_drive *d) } sprintf(descr, "DVD+RW, BGFS %d", d->bg_format_status); + } else if (d->current_profile == 0x13) {/*DVD-RW restricted overwrite*/ + /* 6.5.4.2.8 , DVD-RW Quick Grow Last Border */ + c.page->data[8] = 0x13 << 2; /* Format type */ + c.page->data[11] = 16; /* Restart bit */ + sprintf(descr, "DVD-RW, quick grow"); } else { /* >>> other formattable types to come */ @@ -1359,3 +1376,55 @@ int mmc_setup_drive(struct burn_drive *d) return 1; } + +/* ts A61229 : outsourced from spc_select_write_params() */ +/* Note: Page data is not zeroed here to allow preset defaults. Thus + memset(pd, 0, 2 + d->mdata->write_page_length); + is the eventual duty of the caller. +*/ +int mmc_compose_mode_page_5(struct burn_drive *d, + const struct burn_write_opts *o, + unsigned char *pd) +{ + pd[0] = 5; + pd[1] = d->mdata->write_page_length; + + /* ts A61229 */ + if (d->current_profile == 0x13) { /* DVD-RW restricted overwrite */ + /* learned from transport.hxx : page05_setup() + and mmc3r10g.pdf table 347 */ + /* BUFE (burnproof), no LS_V (i.e. default Link Size, i hope), + no simulate, write type 0 = packet */ + pd[2] = (1 << 6); + /* no multi, fixed packet, track mode 5 */ + pd[3] = (1 << 5) | 5; + /* Data Block Type */ + pd[4] = 8; + /* Link size dummy */ + pd[5] = 0; + } else { + /* Traditional setup for CD */ + pd[2] = ((!!o->underrun_proof) << 6) + | ((!!o->simulate) << 4) + | (o->write_type & 0x0f); + + /* ts A61106 : MMC-1 table 110 : multi==0 or multi==3 */ + pd[3] = ((3 * !!o->multi) << 6) | (o->control & 0x0f); + + pd[4] = spc_block_type(o->block_type); + + /* ts A61104 */ + if(!(o->control&4)) /* audio (MMC-1 table 61) */ + if(o->write_type == BURN_WRITE_TAO) + pd[4] = 0; /* Data Block Type: Raw Data */ + + pd[14] = 0; /* audio pause length MSB */ + pd[15] = 150; /* audio pause length LSB */ + +/*XXX need session format! */ +/* ts A61229 : but session format (pd[8]) = 0 seems ok */ + + } + return 1; +} + diff --git a/libburn/mmc.h b/libburn/mmc.h index 269d269..ffc76f5 100644 --- a/libburn/mmc.h +++ b/libburn/mmc.h @@ -54,4 +54,15 @@ int mmc_setup_drive(struct burn_drive *d); /* ts A61225 : obtain write speed descriptors via ACh GET PERFORMANCE */ int mmc_get_write_performance(struct burn_drive *d); + +/* ts A61229 : outsourced from spc_select_write_params() */ +/* Note: Page data is not zeroed here to allow preset defaults. Thus + memset(pd, 0, 2 + d->mdata->write_page_length); + is the eventual duty of the caller. +*/ +int mmc_compose_mode_page_5(struct burn_drive *d, + const struct burn_write_opts *o, + unsigned char *pd); + + #endif /*__MMC*/ diff --git a/libburn/spc.c b/libburn/spc.c index 09c9f62..f764402 100644 --- a/libburn/spc.c +++ b/libburn/spc.c @@ -345,6 +345,11 @@ void spc_sense_write_params(struct burn_drive *d) mmc_read_disc_info(d); } + +/* ts A61229 */ +#define Libburn_mmc_compose_mode_page_5 1 + + /* remark ts A61104 : Although command MODE SELECT is SPC, the content of the Write Parameters Mode Page (05h) is MMC (Table 108 in MMC-1). @@ -355,7 +360,9 @@ void spc_select_write_params(struct burn_drive *d, { struct buffer buf; struct command c; +#ifndef Libburn_mmc_compose_mode_page_5 int bufe, sim; +#endif /* ts A61007 : All current callers are safe. */ /* a ssert(o->drive == d); */ @@ -380,11 +387,21 @@ void spc_select_write_params(struct burn_drive *d, memset(c.page->data, 0, 8 + 2 + d->mdata->write_page_length); c.page->bytes = 8 + 2 + d->mdata->write_page_length; - c.page->data[8] = 5; - c.page->data[9] = d->mdata->write_page_length; burn_print(12, "using write page length %d (valid %d)\n", d->mdata->write_page_length, d->mdata->write_page_valid); + +#ifdef Libburn_mmc_compose_mode_page_5 + + /* ts A61229 */ + if (mmc_compose_mode_page_5(d, o, c.page->data + 8) <= 0) + return; + +#else + + c.page->data[8] = 5; + c.page->data[9] = d->mdata->write_page_length; + bufe = o->underrun_proof; sim = o->simulate; c.page->data[10] = (bufe << 6) @@ -403,6 +420,9 @@ void spc_select_write_params(struct burn_drive *d, c.page->data[22] = 0; c.page->data[23] = 150; /* audio pause length */ + +#endif /* ! Libburn_mmc_compose_mode_page_5 */ + /*XXX need session format! */ c.dir = TO_DRIVE; d->issue_command(d, &c); @@ -500,6 +520,8 @@ void spc_probe_write_modes(struct burn_drive *d) } } +/* ( ts A61229 : shouldn't this go to mmc.c too ?) */ + /** @return -1 = error */ int spc_block_type(enum burn_block_types b) { diff --git a/libburn/write.c b/libburn/write.c index 1145781..4072f50 100644 --- a/libburn/write.c +++ b/libburn/write.c @@ -887,6 +887,20 @@ int burn_disc_close_session_dvd_plus_rw(struct burn_write_opts *o, } +/* ts A61228 */ +int burn_disc_close_session_dvd_minus_rw(struct burn_write_opts *o, + struct burn_session *s) +{ + struct burn_drive *d = o->drive; + + d->busy = BURN_DRIVE_CLOSING_SESSION; + if (d->current_profile == 0x13) + d->close_track_session(d, 1, 0); /* CLOSE SESSION */ + d->busy = BURN_DRIVE_WRITING; + return 1; +} + + /* ts A61218 */ int burn_dvd_write_session(struct burn_write_opts *o, struct burn_session *s) @@ -903,6 +917,11 @@ int burn_dvd_write_session(struct burn_write_opts *o, ret = burn_disc_close_session_dvd_plus_rw(o, s); if (ret <= 0) return 0; + } else if (d->current_profile == 0x13) { + /* DVD-RW restricted overwrite */ + ret = burn_disc_close_session_dvd_minus_rw(o, s); + if (ret <= 0) + return 0; } return 1; } @@ -943,6 +962,74 @@ int burn_disc_setup_dvd_plus_rw(struct burn_write_opts *o, } +/* ts A61228 : learned much from dvd+rw-tools-7.0/growisofs_mmc.cpp */ +int burn_disc_setup_dvd_minus_rw(struct burn_write_opts *o, + struct burn_disc *disc) +{ + struct burn_drive *d = o->drive; + char msg[160]; + int ret; + + if (d->current_profile == 0x13) { /* DVD-RW restricted overwrite */ + +#ifdef NIX + /* >>> compose mode page 5 -> spc_select_write_params() */ + /* learned from transport.hxx : page05_setup() + and mmc3r10g.pdf table 347 */ + + o->underrun_proof = 1; + o->write_type = 0; /* packet */ + o->multi = 0; + o->control = (1<<5) | 5; /* Fixed packet, Track mode 5 */ + >>> make controllable in spc_select_write_params() : + >>> c.page->data[10] &= ~(1<<5); /* LS_V = 0 */ + >>> c.page->data[12] = 8; /* Data Block Type */ + >>> .page->data[13] = 0; /* Link size */ + +#endif /* NIX */ + + /* ??? urm ... mmc5r03c.pdf 7.5.2 : + "For DVD-RW media ... If a medium is in Restricted overwrite + mode, this mode page shall not be used." + But growisofs composes a page 5 and sends it. + */ + d->send_write_parameters(d, o); + + d->busy = BURN_DRIVE_FORMATTING; + ret = d->format_unit(d); /* "quick grow" */ + if (ret <= 0) + return 0; + d->busy = BURN_DRIVE_WRITING; + + } else { + sprintf(msg, "Unsuitable media detected. Profile %4.4Xh %s", + d->current_profile, d->current_profile_text); + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x0002011e, + LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, + msg, 0,0); + return 0; + } + + d->nwa = 0; + if (o->start_byte >= 0) { + d->nwa = o->start_byte / 32768; + + sprintf(msg, "Write start address is %d * 32768", d->nwa); + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00020127, + LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH, + msg, 0,0); + } + + /* >>> perform OPC if needed */; + + /* >>> */; + + return 1; +} + + /* ts A61218 */ int burn_dvd_write_sync(struct burn_write_opts *o, struct burn_disc *disc) @@ -966,12 +1053,12 @@ int burn_dvd_write_sync(struct burn_write_opts *o, goto early_failure; } - if (strcmp(d->current_profile_text,"DVD+RW")==0) { - + if (d->current_profile == 0x1a || d->current_profile == 0x13) { + /* DVD+RW or DVD-RW Restricted Overwrite */ if (disc->sessions!=1 || disc->session[0]->tracks>1 || o->multi ) { sprintf(msg, - "Burning of DVD+RW is restricted to a single track and session" + "Burning is restricted to a single track and no multi-session" ); libdax_msgs_submit(libdax_messenger, d->global_index, 0x0002011f, @@ -979,6 +1066,8 @@ int burn_dvd_write_sync(struct burn_write_opts *o, msg, 0,0); goto early_failure; } + } + if (d->current_profile == 0x1a) { /* DVD+RW */ if (o->start_byte >= 0 && (o->start_byte % 2048)) { sprintf(msg, "Write start address not properly aligned to 2048"); @@ -988,7 +1077,6 @@ int burn_dvd_write_sync(struct burn_write_opts *o, msg, 0,0); goto early_failure; } - ret = burn_disc_setup_dvd_plus_rw(o, disc); if (ret <= 0) { sprintf(msg, @@ -1001,6 +1089,30 @@ int burn_dvd_write_sync(struct burn_write_opts *o, } o->obs_pad = 0; /* no filling-up of track's last 32k buffer */ + } else if (d->current_profile == 0x13) { /* DVD-RW Rest. Overwrite */ + if (o->start_byte >= 0 && (o->start_byte % 32768)) { + sprintf(msg, + "Write start address not properly aligned to 32K"); + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00020125, + LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, + msg, 0,0); + goto early_failure; + } + ret = burn_disc_setup_dvd_minus_rw(o, disc); + if (ret <= 0) { + sprintf(msg, + "Write preparation setup failed for DVD-RW"); + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00020121, + LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, + msg, 0,0); + goto early_failure; + } + + /* ??? is this necessary ? */ + o->obs_pad = 1; /* fill-up track's last 32k buffer */ + } else { sprintf(msg, "Unsuitable media detected. Profile %4.4Xh %s", d->current_profile, d->current_profile_text);