From b6a04cb49384622bae37d3a16f337e2aae2ad8e4 Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Sat, 21 Oct 2006 10:34:15 +0000 Subject: [PATCH] Implemented some ATIP functionality --- cdrskin/cdrskin.c | 31 +++++++-- cdrskin/cdrskin_timestamp.h | 2 +- libburn/drive.c | 22 ++++++ libburn/libburn.h | 24 ++++++- libburn/libdax_msgs.h | 2 +- libburn/mmc.c | 130 ++++++++++++++++++++++++++++++++++++ libburn/sg-freebsd.c | 1 + libburn/sg-linux.c | 1 + libburn/spc.c | 14 ++++ libburn/transport.h | 8 +++ 10 files changed, 225 insertions(+), 10 deletions(-) diff --git a/cdrskin/cdrskin.c b/cdrskin/cdrskin.c index 9abe478..a05e86a 100644 --- a/cdrskin/cdrskin.c +++ b/cdrskin/cdrskin.c @@ -172,6 +172,7 @@ or #define Cdrskin_libburn_has_audioxtR 1 #define Cdrskin_libburn_has_get_start_end_lbA 1 #define Cdrskin_libburn_has_burn_disc_unsuitablE 1 +#define Cdrskin_libburn_has_read_atiP 1 #endif #ifndef Cdrskin_libburn_versioN @@ -3326,7 +3327,7 @@ ex:; int Cdrskin_atip(struct CdrskiN *skin, int flag) { int ret,is_not_really_erasable= 0; - double x_speed; + double x_speed_max, x_speed_min= -1.0; enum burn_disc_status s; struct burn_drive *drive; @@ -3400,10 +3401,26 @@ int Cdrskin_atip(struct CdrskiN *skin, int flag) #endif /* Cdrskin_atip_speed_brokeN */ +#ifdef Cdrskin_libburn_has_read_atiP + ret= burn_disc_read_atip(drive); + if(ret>0) { + ret= burn_drive_get_min_write_speed(drive); + x_speed_min= ((double) ret)/Cdrskin_libburn_cd_speed_factoR; + } +#endif + +#ifdef Cdrskin_libburn_has_burn_disc_unsuitablE + if(burn_disc_get_status(drive) == BURN_DISC_UNSUITABLE) { + printf("Current: UNSUITABLE MEDIA\n"); + {ret= 0; goto ex;} + } +#endif ret= burn_drive_get_write_speed(drive); - x_speed= ((double) ret)/Cdrskin_libburn_cd_speed_factoR; - printf("cdrskin: burn_drive_get_write_speed = %d (%.1fx)\n",ret,x_speed); + x_speed_max= ((double) ret)/Cdrskin_libburn_cd_speed_factoR; + if(x_speed_min<0) + x_speed_min= x_speed_max; + printf("cdrskin: burn_drive_get_write_speed = %d (%.1fx)\n",ret,x_speed_max); if(skin->verbosity>=Cdrskin_verbose_progresS) { if(burn_disc_erasable(drive)) printf("Current: CD-RW\n"); @@ -3425,14 +3442,16 @@ int Cdrskin_atip(struct CdrskiN *skin, int flag) ret= burn_drive_get_start_end_lba(drive,&start_lba,&end_lba,0); if(ret>0) { burn_lba_to_msf(start_lba,&min,&sec,&fr); - printf(" ATIP start of lead in: %d (%d:%d/%d)\n",start_lba,min,sec,fr); + printf(" ATIP start of lead in: %d (%-2.2d:%-2.2d/%-2.2d)\n", + start_lba,min,sec,fr); burn_lba_to_msf(end_lba,&min,&sec,&fr); - printf(" ATIP start of lead out: %d (%d:%d/%d)\n",end_lba,min,sec,fr); + printf(" ATIP start of lead out: %d (%-2.2d:%-2.2d/%-2.2d)\n", + end_lba,min,sec,fr); } } #endif /* Cdrskin_libburn_has_get_start_end_lbA */ - printf(" 1T speed low: %.f 1T speed high: %.f\n",x_speed,x_speed); + printf(" 1T speed low: %.f 1T speed high: %.f\n",x_speed_min,x_speed_max); ret= 1; ex:; Cdrskin_release_drive(skin,0); diff --git a/cdrskin/cdrskin_timestamp.h b/cdrskin/cdrskin_timestamp.h index d9f61e8..83ba4f8 100644 --- a/cdrskin/cdrskin_timestamp.h +++ b/cdrskin/cdrskin_timestamp.h @@ -1 +1 @@ -#define Cdrskin_timestamP "2006.10.20.151602" +#define Cdrskin_timestamP "2006.10.21.103352" diff --git a/libburn/drive.c b/libburn/drive.c index e9aae94..e42dfb0 100644 --- a/libburn/drive.c +++ b/libburn/drive.c @@ -663,6 +663,12 @@ int burn_drive_get_write_speed(struct burn_drive *d) return d->mdata->max_write_speed; } +/* ts A61021 : New API function */ +int burn_drive_get_min_write_speed(struct burn_drive *d) +{ + return d->mdata->min_write_speed; +} + /* ts A51221 */ static char *enumeration_whitelist[BURN_DRIVE_WHITELIST_LEN]; @@ -1136,3 +1142,19 @@ int burn_disc_pretend_blank(struct burn_drive *d) return 1; } +/* ts A61021: new API function */ +int burn_disc_read_atip(struct burn_drive *d) +{ + if (burn_drive_is_released(d)) { + libdax_msgs_submit(libdax_messenger, + d->global_index, 0x0002010e, + LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, + "Attempt to read ATIP from ungrabbed drive", + 0, 0); + return -1; + } + d->read_atip(d); + /* >>> some control of success would be nice :) */ + return 1; +} + diff --git a/libburn/libburn.h b/libburn/libburn.h index 4a4ec1f..a16b640 100644 --- a/libburn/libburn.h +++ b/libburn/libburn.h @@ -639,7 +639,17 @@ enum burn_disc_status burn_disc_get_status(struct burn_drive *drive); failed to declare themselves either blank or (partially) filled. @return 1 drive status has been set , 0 = unsuitable drive status */ -int burn_disc_pretend_blank(struct burn_drive *d); +int burn_disc_pretend_blank(struct burn_drive *drive); + + +/* ts A61021 */ +/** Reads ATIP information from inserted media. To be obtained via + burn_drive_get_write_speed(), burn_drive_get_min_write_speed(), + burn_drive_get_start_end_lba(). The drive must be grabbed for this call. + @param drive The drive to query. + @return 1=sucess, 0=no valid ATIP info read, -1 severe error +*/ +int burn_disc_read_atip(struct burn_drive *drive); /* ts A61020 */ @@ -652,7 +662,7 @@ int burn_disc_pretend_blank(struct burn_drive *d); @param flag Bitfield for control purposes (unused yet, submit 0) @return 1 if lba values are valid , 0 if invalid */ -int burn_drive_get_start_end_lba(struct burn_drive *d, +int burn_drive_get_start_end_lba(struct burn_drive *drive, int *start_lba, int *end_lba, int flag); @@ -1019,6 +1029,16 @@ void burn_read_opts_set_hardware_error_retries(struct burn_read_opts *opts, */ int burn_drive_get_write_speed(struct burn_drive *d); + +/* ts A61021 */ +/** Gets the minimum write speed for a drive. This might differ from + burn_drive_get_write_speed() only after burn_disc_read_atip() + @param d Drive to query + @return Minimum write speed in K/s +*/ +int burn_drive_get_min_write_speed(struct burn_drive *d); + + /** Gets the maximum read speed for a drive @param d Drive to query @return Maximum read speed in K/s diff --git a/libburn/libdax_msgs.h b/libburn/libdax_msgs.h index 3a4da4e..1578ef5 100644 --- a/libburn/libdax_msgs.h +++ b/libburn/libdax_msgs.h @@ -319,7 +319,7 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff 0x0002010b (FATAL,HIGH) = Burn run failed 0x0002010c (FATAL,HIGH) = Failed to transfer command to drive 0x0002010d (DEBUG,HIGH) = Could not inquire TOC - 0x0002010e + 0x0002010e (FATAL,HIGH) = Attempt to read ATIP from ungrabbed drive 0x0002010f 0x00020110 (FATAL,HIGH) = Persistent drive address too long 0x00020111 (FATAL,HIGH) = Could not allocate new auxiliary object diff --git a/libburn/mmc.c b/libburn/mmc.c index b7dec26..80d5c82 100644 --- a/libburn/mmc.c +++ b/libburn/mmc.c @@ -439,6 +439,17 @@ void mmc_read_atip(struct burn_drive *d) struct buffer buf; struct command c; + /* ts A61021 */ + unsigned char *data; + /* Speed values from A1: + With 4 cdrecord tells 10 or 8 where MMC-1 says 8. + cdrecord 8 appear on 4xCD-RW and thus seem to be quite invalid. + My CD-R (>=24 speed) tell no A1. + The higher non-MMC-1 values are hearsay. + */ + static int speed_value[16]= { 0, 2, 4, 6, 10, -5, 16, -7, + 24, 32, 40, 48, -12, -13, -14, -15}; + mmc_function_spy("mmc_read_atip"); memcpy(c.opcode, MMC_GET_ATIP, sizeof(MMC_GET_ATIP)); c.retry = 1; @@ -450,6 +461,125 @@ void mmc_read_atip(struct burn_drive *d) c.dir = FROM_DRIVE; d->issue_command(d, &c); burn_print(1, "atip shit for you\n"); + + + /* ts A61021 */ + data = c.page->data; + d->erasable= !!(data[6]&64); + d->start_lba= burn_msf_to_lba(data[8],data[9],data[10]); + d->end_lba= burn_msf_to_lba(data[12],data[13],data[14]); + if (data[6]&4) { + if (speed_value[(data[16]>>4)&7] > 0) + d->mdata->min_write_speed = + speed_value[(data[16]>>4)&7]*176; + if (speed_value[(data[16])&15] > 0) + d->mdata->max_write_speed = + speed_value[(data[16])&15]*176; + } + +#ifdef Burn_mmc_be_verbous_about_atiP + { int i; + fprintf(stderr,"libburn_experimental: Returned ATIP Data\n"); + for(i= 0; i<28; i++) + fprintf(stderr,"%3.3d (0x%2.2x)%s", + data[i],data[i],((i+1)%5 ? " ":"\n")); + fprintf(stderr,"\n"); + + fprintf(stderr, + "libburn_experimental: Indicative Target Writing Power= %d\n", + (data[4]>>4)&7); + fprintf(stderr, + "libburn_experimental: Reference speed= %d ->%d\n", + data[4]&7, speed_value[data[4]&7]); + fprintf(stderr, + "libburn_experimental: Is %sunrestricted\n", + (data[5]&64?"":"not ")); + fprintf(stderr, + "libburn_experimental: Is %serasable, sub-type %d\n", + (data[6]&64?"":"not "),(data[6]>>3)&3); + fprintf(stderr, + "libburn_experimental: lead in: %d (%-2.2d:%-2.2d/%-2.2d)\n", + burn_msf_to_lba(data[8],data[9],data[10]), + data[8],data[9],data[10]); + fprintf(stderr, + "libburn_experimental: lead out: %d (%-2.2d:%-2.2d/%-2.2d)\n", + burn_msf_to_lba(data[12],data[13],data[14]), + data[12],data[13],data[14]); + if(data[6]&4) + fprintf(stderr, + "libburn_experimental: A1 speed low %d speed high %d\n", + speed_value[(data[16]>>4)&7], speed_value[(data[16])&7]); + if(data[6]&2) + fprintf(stderr, + "libburn_experimental: A2 speed low %d speed high %d\n", + speed_value[(data[20]>>4)&7], speed_value[(data[20])&7]); + if(data[6]&1) + fprintf(stderr, + "libburn_experimental: A3 speed low %d speed high %d\n", + speed_value[(data[24]>>4)&7], speed_value[(data[24])&7]); + } + +#endif /* Burn_mmc_be_verbous_about_atiP */ + +/* ts A61020 +http://www.t10.org/ftp/t10/drafts/mmc/mmc-r10a.pdf , table 77 : + + 0 ATIP Data Length MSB + 1 ATIP Data Length LSB + 2 Reserved + 3 Reserved + 4 bit7=1, bit4-6="Indicative Target Writing Power", bit3=reserved , + bit0-2="Reference speed" + 5 bit7=0, bit6="URU" , bit0-5=reserved + 6 bit7=1, bit6="Disc Type", bit3-4="Disc Sub-Type", + bit2="A1", bit1="A2", bit0="A3" + 7 reserved + 8 ATIP Start Time of lead-in (Min) + 9 ATIP Start Time of lead-in (Sec) +10 ATIP Start Time of lead-in (Frame) +11 reserved +12 ATIP Last Possible Start Time of lead-out (Min) +13 ATIP Last Possible Start Time of lead-out (Sec) +14 ATIP Last Possible Start Time of lead-out (Frame) +15 reserved +16 bit7=0, bit4-6="Lowest Usable CLV Recording speed" + bit0-3="Highest Usable CLV Recording speed" +17 bit7=0, bit4-6="Power Multiplication Factor p", + bit1-3="Target y value of the Modulation/Power function", bit0=reserved +18 bit7=1, bit4-6="Recommended Erase/Write Power Ratio (P(inf)/W(inf))" + bit0-3=reserved +19 reserved +20-22 A2 Values +23 reserved +24-26 A3 Values +27 reserved + +Disc Type - zero indicates CD-R media; one indicates CD-RW media. + +Disc Sub-Type - shall be set to zero. + +A1 - when set to one, indicates that bytes 16-18 are valid. + +Lowest Usable CLV Recording Speed +000b Reserved +001b 2X +010b - 111b Reserved + +Highest CLV Recording Speeds +000b Reserved +001b 2X +010b 4X +011b 6X +100b 8X +101b - 111b Reserved + +MMC-3 seems to recommend MODE SENSE (5Ah) page 2Ah rather than A1, A2, A3. +This page is loaded in libburn function spc_sense_caps() . +Speed is given in kbytes/sec there. But i suspect this to be independent +of media. So one would habe to associate the speed descriptor blocks with +the ATIP media characteristics ? How ? + +*/ } void mmc_read_sectors(struct burn_drive *d, diff --git a/libburn/sg-freebsd.c b/libburn/sg-freebsd.c index 8a9422a..f353fba 100644 --- a/libburn/sg-freebsd.c +++ b/libburn/sg-freebsd.c @@ -208,6 +208,7 @@ static void enumerate_common(char *fname, int bus_no, int host_no, out.start_lba= -2000000000; out.end_lba= -2000000000; + out.read_atip = mmc_read_atip; out.grab = sg_grab; out.release = sg_release; diff --git a/libburn/sg-linux.c b/libburn/sg-linux.c index 9b6eaef..336454f 100644 --- a/libburn/sg-linux.c +++ b/libburn/sg-linux.c @@ -443,6 +443,7 @@ static void enumerate_common(char *fname, int bus_no, int host_no, /* ts A61020 */ out.start_lba= -2000000000; out.end_lba= -2000000000; + out.read_atip = mmc_read_atip; out.grab = sg_grab; out.release = sg_release; diff --git a/libburn/spc.c b/libburn/spc.c index d90ab60..9b9b0bf 100644 --- a/libburn/spc.c +++ b/libburn/spc.c @@ -157,10 +157,24 @@ void spc_sense_caps(struct burn_drive *d) m->cdrw_write = page[3] & 2; m->cdr_read = page[2] & 1; m->cdr_write = page[3] & 1; + + /* ts A61021 : these fields are marked obsolete in MMC 3 */ m->max_read_speed = page[8] * 256 + page[9]; m->cur_read_speed = page[14] * 256 + page[15]; + + /* in MMC-3 : see [30-31] and blocks beginning at [32] */ m->max_write_speed = page[18] * 256 + page[19]; + /* New field to be set by atip */ + m->min_write_speed = m->max_write_speed; + + /* in MMC-3 : [28-29] */ m->cur_write_speed = page[20] * 256 + page[21]; + + /* >>> ts A61021 : iterate over all speeds : + data[30-31]: number of speed performance descriptor blocks + data[32-35]: block 0 : [+2-3] speed in kbytes/sec + */ + m->c2_pointers = page[5] & 16; m->valid = 1; m->underrun_proof = page[4] & 128; diff --git a/libburn/transport.h b/libburn/transport.h index 808364c..42839b5 100644 --- a/libburn/transport.h +++ b/libburn/transport.h @@ -79,6 +79,10 @@ struct scsi_mode_data int simulate; int max_read_speed; int max_write_speed; + + /* ts A61021 */ + int min_write_speed; + int cur_read_speed; int cur_write_speed; int retry_page_length; @@ -146,6 +150,10 @@ struct burn_drive /* lower level functions */ void (*erase) (struct burn_drive *, int); void (*getcaps) (struct burn_drive *); + + /* ts A61021 */ + void (*read_atip) (struct burn_drive *); + int (*write) (struct burn_drive *, int, struct buffer *); void (*read_toc) (struct burn_drive *); void (*lock) (struct burn_drive *);