From 85ffe77a3241e94f1101e4e3f20a19a2d1acedec Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Tue, 26 Dec 2006 17:07:53 +0000 Subject: [PATCH] New API calls burn_drive_get_speedlist() , burn_drive_free_speedlist() --- cdrskin/cdrskin_timestamp.h | 2 +- libburn/drive.c | 117 +++++++++++++++++++++++++++++++++++- libburn/drive.h | 16 +++++ libburn/libburn.h | 77 +++++++++++++++++++++++- libburn/mmc.c | 36 ++++++++--- libburn/spc.c | 27 ++++++++- libburn/transport.h | 2 + 7 files changed, 261 insertions(+), 16 deletions(-) diff --git a/cdrskin/cdrskin_timestamp.h b/cdrskin/cdrskin_timestamp.h index fca0a93..d03b6a8 100644 --- a/cdrskin/cdrskin_timestamp.h +++ b/cdrskin/cdrskin_timestamp.h @@ -1 +1 @@ -#define Cdrskin_timestamP "2006.12.25.190811" +#define Cdrskin_timestamP "2006.12.26.170459" diff --git a/libburn/drive.c b/libburn/drive.c index f8c87ba..666703d 100644 --- a/libburn/drive.c +++ b/libburn/drive.c @@ -54,6 +54,7 @@ void burn_drive_free(struct burn_drive *d) if (burn_drive_is_open(d)) d->release(d); free((void *) d->idata); + burn_mdata_free_subs(d->mdata); free((void *) d->mdata); if(d->toc_entry != NULL) free((void *) d->toc_entry); @@ -144,6 +145,9 @@ int burn_drive_inquire_media(struct burn_drive *d) int loop_count, old_speed = -1234567890, new_speed = -987654321; int old_erasable = -1234567890, new_erasable = -987654321; + /* ts A61225 : after loading the tray, mode page 2Ah can change */ + d->getcaps(d); + /* ts A61020 : d->status was set to BURN_DISC_BLANK as pure guess */ if (d->mdata->cdr_write || d->mdata->cdrw_write || @@ -152,6 +156,8 @@ int burn_drive_inquire_media(struct burn_drive *d) #ifdef Libburn_grab_release_and_grab_agaiN /* This code demanded the app to release and re-grab. */ + /* ??? ts A61225 : is this safe now (after d->getcaps()) ? */ + d->read_disc_info(d); #else @@ -226,9 +232,6 @@ int burn_drive_grab(struct burn_drive *d, int le) /* ts A61118 */ d->start_unit(d); - /* ts A61225 : after loading the tray, mode page 2Ah can change */ - d->getcaps(d); - /* ts A61202 : gave bit1 of le a meaning */ sose = d->silent_on_scsi_error; if (!le) @@ -1290,3 +1293,111 @@ int burn_drive_wrote_well(struct burn_drive *d) return !d->cancel; } + +/* ts A61226 */ +int burn_speed_descriptor_new(struct burn_speed_descriptor **s, + struct burn_speed_descriptor *prev, + struct burn_speed_descriptor *next, int flag) +{ + struct burn_speed_descriptor *o; + + (*s) = o = malloc(sizeof(struct burn_speed_descriptor)); + if (o == NULL) + return -1; + o->source = 0; + o->profile_loaded = -2; + o->profile_name[0] = 0; + o->wrc = 0; + o->exact = 0; + o->mrw = 0; + o->end_lba = -1; + o->write_speed = 0; + o->read_speed = 0; + + o->prev = prev; + if (prev != NULL) { + next = prev->next; + prev->next = o; + } + o->next = next; + if (next != NULL) + next->prev = o; + return 1; +} + + +/* ts A61226 */ +/* @param flag bit0= destroy whole next-chain of descriptors */ +int burn_speed_descriptor_destroy(struct burn_speed_descriptor **s, int flag) +{ + struct burn_speed_descriptor *next, *o; + + if ((*s) == NULL) + return 0; + if (flag&1) + for (o = (*s); o->prev != NULL; o = o->prev); + else + o = (*s); + next = o->next; + if (next != NULL) + next->prev = o->prev; + if (o->prev != NULL) + o->prev->next = next; + free((char *) (*s)); + (*s) = NULL; + if (flag&1) + return burn_speed_descriptor_destroy(&next, flag&1); + return 1; +} + + +/* ts A61226 */ +int burn_speed_descriptor_copy(struct burn_speed_descriptor *from, + struct burn_speed_descriptor *to, int flag) +{ + to->source = from->source; + to->profile_loaded = from->profile_loaded; + strcpy(to->profile_name, from->profile_name); + to->wrc = from->wrc; + to->exact = from->exact; + to->mrw = from->mrw; + to->end_lba = from->end_lba; + to->write_speed = from->write_speed; + to->read_speed = from->read_speed; + return 1; +} + + +/* ts A61226 : free dynamically allocated sub data of struct scsi_mode_data */ +int burn_mdata_free_subs(struct scsi_mode_data *m) +{ + burn_speed_descriptor_destroy(&(m->speed_descriptors), 1); + return 1; +} + + +/* ts A61226 : API function */ +int burn_drive_get_speedlist(struct burn_drive *d, + struct burn_speed_descriptor **speed_list) +{ + int ret; + struct burn_speed_descriptor *sd, *csd = NULL; + + (*speed_list) = NULL; + for (sd = d->mdata->speed_descriptors; sd != NULL; sd = sd->next) { + ret = burn_speed_descriptor_new(&csd, NULL, csd, 0); + if (ret <= 0) + return -1; + burn_speed_descriptor_copy(sd, csd, 0); + } + (*speed_list) = csd; + return (csd != NULL); +} + + +/* ts A61226 : API function */ +int burn_drive_free_speedlist(struct burn_speed_descriptor **speed_list) +{ + return burn_speed_descriptor_destroy(speed_list, 1); +} + diff --git a/libburn/drive.h b/libburn/drive.h index ca9ca86..794e813 100644 --- a/libburn/drive.h +++ b/libburn/drive.h @@ -10,6 +10,8 @@ struct burn_drive; struct command; struct mempage; +struct scsi_mode_data; +struct burn_speed_descriptor; #define LEAD_IN 1 #define GAP 2 @@ -75,4 +77,18 @@ int burn_drive_inquire_media(struct burn_drive *d); /* ts A61125 : model aspects of burn_drive_release */ int burn_drive_mark_unready(struct burn_drive *d); + +/* ts A61226 */ +int burn_speed_descriptor_new(struct burn_speed_descriptor **s, + struct burn_speed_descriptor *prev, + struct burn_speed_descriptor *next, int flag); + +/* ts A61226 */ +/* @param flag bit0= destroy whole next-chain of descriptors */ +int burn_speed_descriptor_destroy(struct burn_speed_descriptor **s, int flag); + + +/* ts A61226 : free dynamically allocated sub data of struct scsi_mode_data */ +int burn_mdata_free_subs(struct scsi_mode_data *m); + #endif /* __DRIVE */ diff --git a/libburn/libburn.h b/libburn/libburn.h index dd8cc34..20b04a5 100644 --- a/libburn/libburn.h +++ b/libburn/libburn.h @@ -414,6 +414,55 @@ struct burn_progress { unsigned buffer_min_fill; }; + +/* ts A61226 */ +/** Description of a speed capability as reported by the drive in conjunction + with eventually loaded media. There can be more than one such object per + drive. So they are chained via .next and .prev , where NULL marks the end + of the chain. This list is set up by burn_drive_scan() and gets updated + by burn_drive_grab(). + A copy may be obtained by burn_drive_get_speedlist() and disposed by + burn_drive_free_speedlist(). + For technical background info see SCSI specs MMC and SPC: + mode page 2Ah (from SPC 5Ah MODE SENSE) , mmc3r10g.pdf , 6.3.11 Table 364 + ACh GET PERFORMANCE, Type 03h , mmc5r03c.pdf , 6.8.5.3 Table 312 +*/ +struct burn_speed_descriptor { + + /** Where this info comes from : + 0 = misc , 1 = mode page 2Ah , 2 = ACh GET PERFORMANCE */ + int source; + + /** The media type that was reported as current at the time of report + -2 = state unknown, -1 = no media was loaded , else see + burn_disc_get_profile() */ + int profile_loaded; + char profile_name[80]; + + /** The attributed capacity of appropriate media in logical block units + i.e. 2352 raw bytes or 2048 data bytes. -1 = capacity unknown. */ + int end_lba; + + /** Write speed is given in 1000 bytes/s , 0 = invalid. The numbers + are supposed to be usable with burn_drive_set_speed() */ + int write_speed; + int read_speed; + + /** Expert info from ACh GET PERFORMANCE and/or mode page 2Ah. + Expect values other than 0 or 1 to get a meaning in future.*/ + /* Rotational control: 0 = CLV/default , 1 = CAV */ + int wrc; + /* 1 = drive promises reported performance over full media */ + int exact; + /* 1 = suitable for mixture of read and write */ + int mrw; + + /** List chaining. Use .next until NULL to iterate over the list */ + struct burn_speed_descriptor *prev; + struct burn_speed_descriptor *next; +}; + + /** Initialize the library. This must be called before using any other functions in the library. It may be called more than once with no effect. @@ -735,11 +784,12 @@ int burn_disc_track_lba_nwa(struct burn_drive *d, struct burn_write_opts *o, /* ts A61202 */ /** Tells the MMC Profile identifier of the loaded media. The drive must be grabbed in order to get a non-zero result. + libburn currently writes only to profiles 0x09 "CD-R", 0x0a "CD-RW" or + 0x1a "DVD+RW". @param d The drive where the media is inserted. @param pno Profile Number as of mmc5r03c.pdf, table 89 @param name Profile Name (e.g "CD-RW", unknown profiles have empty name) @return 1 profile is valid, 0 no profile info available - Note: libburn currently writes only to profiles 0x09 "CD-R", 0x0a "CD-RW". */ int burn_disc_get_profile(struct burn_drive *d, int *pno, char name[80]); @@ -1177,6 +1227,31 @@ int burn_drive_get_min_write_speed(struct burn_drive *d); */ int burn_drive_get_read_speed(struct burn_drive *d); + +/* ts A61226 */ +/** Obtain a copy of the current speed descriptor list. The drive's list gets + updated on various occasions such as burn_drive_grab() but the copy + obtained here stays untouched. It has to be disposed via + burn_drive_free_speedlist() when it is not longer needed. Speeds + may appear several times in the list. The list content depends much on + drive and media type. It seems that .source == 1 applies mostly to CD media + whereas .source == 2 applies to any media. + @param d Drive to query + @param speed_list The copy. If empty, *speed_list gets returned as NULL. + @return 1=success , 0=list empty , <0 severe error +*/ +int burn_drive_get_speedlist(struct burn_drive *d, + struct burn_speed_descriptor **speed_list); + +/* ts A61226 */ +/** Dispose a speed descriptor list copy which was obtained by + burn_drive_get_speedlist(). + @param speed_list The list copy. *speed_list gets set to NULL. + @return 1=list disposed , 0= *speedlist was already NULL +*/ +int burn_drive_free_speedlist(struct burn_speed_descriptor **speed_list); + + /** Gets a copy of the toc_entry structure associated with a track @param t Track to get the entry from @param entry Struct for the library to fill out diff --git a/libburn/mmc.c b/libburn/mmc.c index 77ededc..38c530f 100644 --- a/libburn/mmc.c +++ b/libburn/mmc.c @@ -910,7 +910,7 @@ int mmc_set_streaming(struct burn_drive *d, int r_speed, int w_speed) if (d->mdata->max_end_lba > 0) end_lba = d->mdata->max_end_lba - 1; - sprintf(msg, "mmc_set_streaming: end_lba=%lu , r=%d , w=%d", + sprintf(msg, "mmc_set_streaming: end_lba=%d , r=%d , w=%d", end_lba, r_speed, w_speed); libdax_msgs_submit(libdax_messenger, d->global_index, 0x00000002, LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO, @@ -1202,7 +1202,7 @@ int mmc_format_unit(struct burn_drive *d) int mmc_get_write_performance(struct burn_drive *d) { struct buffer buf; - int len, i, b, pass, was_exact_bit = 0, max_descr, num_descr; + int len, i, b, max_descr, num_descr, ret; int exact_bit, read_speed, write_speed; /* if this call delivers usable data then they should override previously recorded min/max speed and not compete with them */ @@ -1211,12 +1211,16 @@ int mmc_get_write_performance(struct burn_drive *d) struct command c; unsigned long end_lba; unsigned char *pd; + struct burn_speed_descriptor *sd; /* A61225 : 1 = report about speed descriptors */ static int speed_debug = 0; mmc_function_spy("mmc_get_write_performance"); + if (d->current_profile <= 0) + mmc_get_configuration(d); + memcpy(c.opcode, MMC_GET_PERFORMANCE, sizeof(MMC_GET_PERFORMANCE)); max_descr = ( BUFFER_SIZE - 8 ) / 16 - 1; @@ -1248,7 +1252,7 @@ int mmc_get_write_performance(struct burn_drive *d) num_descr = ( len - 4 ) / 16; if (num_descr > max_descr) num_descr = max_descr; - for (pass = 0; pass < 2; pass++) for (i = 0; i < num_descr; i++) { + for (i = 0; i < num_descr; i++) { exact_bit = !!(pd[8 + i*16] & 2); end_lba = read_speed = write_speed = 0; for (b = 0; b < 4 ; b++) { @@ -1259,16 +1263,30 @@ int mmc_get_write_performance(struct burn_drive *d) if (end_lba > 0x7ffffffe) end_lba = 0x7ffffffe; - if (pass == 0 && speed_debug) + if (speed_debug) fprintf(stderr, "LIBBURN_DEBUG: kB/s: write=%d read=%d end=%lu exact=%d\n", write_speed, read_speed, end_lba, exact_bit); - if (pass == 0 && !exact_bit) - continue; - if (pass == 1 && was_exact_bit) - continue; - was_exact_bit |= exact_bit; + /* ts A61226 */ + ret = burn_speed_descriptor_new(&(d->mdata->speed_descriptors), + NULL, d->mdata->speed_descriptors, 0); + if (ret > 0) { + sd = d->mdata->speed_descriptors; + sd->source = 2; + if (d->current_profile > 0) { + sd->profile_loaded = d->current_profile; + strcpy(sd->profile_name, + d->current_profile_text); + } + sd->wrc = (pd[8 + i*16] >> 3 ) & 3; + sd->exact = exact_bit; + sd->mrw = pd[8 + i*16] & 1; + sd->end_lba = end_lba; + sd->write_speed = write_speed; + sd->read_speed = read_speed; + } + if (end_lba > d->mdata->max_end_lba) d->mdata->max_end_lba = end_lba; if (end_lba < d->mdata->min_end_lba) diff --git a/libburn/spc.c b/libburn/spc.c index 641c4a5..09c9f62 100644 --- a/libburn/spc.c +++ b/libburn/spc.c @@ -15,6 +15,7 @@ #include +#include "libburn.h" #include "transport.h" #include "spc.h" #include "mmc.h" @@ -135,6 +136,7 @@ void spc_sense_caps(struct burn_drive *d) int size, page_length, num_write_speeds = 0, i, speed, ret; unsigned char *page; struct command c; + struct burn_speed_descriptor *sd; /* ts A61225 : 1 = report about post-MMC-1 speed descriptors */ static int speed_debug = 0; @@ -161,6 +163,9 @@ void spc_sense_caps(struct burn_drive *d) */ page_length = page[1]; + m->valid = 0; + burn_mdata_free_subs(m); + m->buffer_size = page[12] * 256 + page[13]; m->dvdram_read = page[2] & 32; m->dvdram_write = page[3] & 32; @@ -192,9 +197,11 @@ void spc_sense_caps(struct burn_drive *d) m->valid = 1; + mmc_get_configuration(d); + /* ts A61225 : end of MMC-1 , begin of MMC-3 */ if (page_length < 32) /* no write speed descriptors ? */ - return; + goto try_mmc_get_performance; m->cur_write_speed = page[28] * 256 + page[29]; @@ -212,6 +219,21 @@ void spc_sense_caps(struct burn_drive *d) "LIBBURN_DEBUG: write speed #%d = %d kB/s (rc %d)\n", i, speed, page[32 + 4*i +1] & 7); + /* ts A61226 */ + ret = burn_speed_descriptor_new(&(d->mdata->speed_descriptors), + NULL, d->mdata->speed_descriptors, 0); + if (ret > 0) { + sd = d->mdata->speed_descriptors; + sd->source = 1; + if (d->current_profile > 0) { + sd->profile_loaded = d->current_profile; + strcpy(sd->profile_name, + d->current_profile_text); + } + sd->wrc = (( page[32 + 4*i +1] & 7 ) == 1 ); + sd->write_speed = speed; + } + if (speed > m->max_write_speed) m->max_write_speed = speed; if (speed < m->min_write_speed) @@ -223,13 +245,13 @@ void spc_sense_caps(struct burn_drive *d) "LIBBURN_DEBUG: 5Ah,2Ah min_write_speed = %d , max_write_speed = %d\n", m->min_write_speed, m->max_write_speed); +try_mmc_get_performance:; ret = mmc_get_write_performance(d); if (ret > 0 && speed_debug) fprintf(stderr, "LIBBURN_DEBUG: ACh min_write_speed = %d , max_write_speed = %d\n", m->min_write_speed, m->max_write_speed); - } @@ -551,6 +573,7 @@ int burn_scsi_setup_drive(struct burn_drive *d, int bus_no, int host_no, d->idata->valid = 0; d->mdata = malloc(sizeof(struct scsi_mode_data)); d->mdata->valid = 0; + d->mdata->speed_descriptors = NULL; /* ts A61007 : obsolete Assert in drive_getcaps() */ if(d->idata == NULL || d->mdata == NULL) { diff --git a/libburn/transport.h b/libburn/transport.h index 3378b79..a703d0f 100644 --- a/libburn/transport.h +++ b/libburn/transport.h @@ -65,6 +65,7 @@ struct burn_scsi_inquiry_data int valid; }; + struct scsi_mode_data { int buffer_size; @@ -88,6 +89,7 @@ struct scsi_mode_data Speed values go into *_*_speed */ int min_end_lba; int max_end_lba; + struct burn_speed_descriptor *speed_descriptors; int cur_read_speed; int cur_write_speed;