Experiments about list of features and profiles

This commit is contained in:
Thomas Schmitt 2007-01-29 17:57:31 +00:00
parent ff7028d1fc
commit bda139f390
5 changed files with 354 additions and 32 deletions

View File

@ -1 +1 @@
#define Cdrskin_timestamP "2007.01.26.173236" #define Cdrskin_timestamP "2007.01.29.175822"

View File

@ -347,6 +347,9 @@ int burn_drive_mark_unready(struct burn_drive *d)
/* ts A61202 */ /* ts A61202 */
d->current_profile = -1; d->current_profile = -1;
d->current_has_feat21h = 0;
d->current_feat2fh_byte4 = -1;
d->status = BURN_DISC_UNREADY; d->status = BURN_DISC_UNREADY;
if (d->toc_entry != NULL) if (d->toc_entry != NULL)
free(d->toc_entry); free(d->toc_entry);

View File

@ -44,6 +44,11 @@ extern struct libdax_msgs *libdax_messenger;
#define Libburn_support_dvd_raM 1 #define Libburn_support_dvd_raM 1
/* ts A70129 >>> EXPERIMENTAL
#define Libburn_support_dvd_r_seQ 1
*/
/* Progress report (with Libburn_support_dvd_plus_rW defined): /* Progress report (with Libburn_support_dvd_plus_rW defined):
ts A61219 : It seems to work with a used (i.e. thoroughly formatted) DVD+RW. 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 Error messages of class DEBUG appear because of inability to
@ -590,6 +595,7 @@ void mmc_read_disc_info(struct burn_drive *d)
*/ */
d->status = BURN_DISC_BLANK; d->status = BURN_DISC_BLANK;
d->last_track_no = 0;
break; break;
case 1: case 1:
d->status = BURN_DISC_APPENDABLE; d->status = BURN_DISC_APPENDABLE;
@ -613,6 +619,14 @@ void mmc_read_disc_info(struct burn_drive *d)
*/ */
d->bg_format_status = data[7] & 3; d->bg_format_status = data[7] & 3;
if (d->status == BURN_DISC_BLANK)
d->last_track_no = 1; /* The "incomplete track" */
else
/* ts A70129 : mmc5r03c.pdf 6.22.3.1.7
This includes the "incomplete track" if the disk is
appendable. I.e number of complete tracks + 1. */
d->last_track_no = (data[11] << 8) | data[6];
/* Preliminarily declare blank: /* Preliminarily declare blank:
ts A61219 : DVD+RW (is not bg_format_status==0 "blank") ts A61219 : DVD+RW (is not bg_format_status==0 "blank")
ts A61229 : same for DVD-RW Restricted overwrite ts A61229 : same for DVD-RW Restricted overwrite
@ -1066,13 +1080,17 @@ static char *mmc_obtain_profile_name(int profile_number)
void mmc_get_configuration(struct burn_drive *d) void mmc_get_configuration(struct burn_drive *d)
{ {
struct buffer buf; struct buffer buf;
int len, cp; int len, cp, descr_len = 0, feature_code, prf_number, only_current = 1;
unsigned char *descr, *prf, *up_to, *prf_end;
struct command c; struct command c;
d->current_profile = 0; d->current_profile = 0;
d->current_profile_text[0] = 0; d->current_profile_text[0] = 0;
d->current_is_cd_profile = 0; d->current_is_cd_profile = 0;
d->current_is_supported_profile = 0; d->current_is_supported_profile = 0;
d->current_has_feat21h = 0;
d->current_feat21h_link_size = -1;
d->current_feat2fh_byte4 = -1;
mmc_function_spy("mmc_get_configuration"); mmc_function_spy("mmc_get_configuration");
memcpy(c.opcode, MMC_GET_CONFIGURATION, sizeof(MMC_GET_CONFIGURATION)); memcpy(c.opcode, MMC_GET_CONFIGURATION, sizeof(MMC_GET_CONFIGURATION));
@ -1087,9 +1105,9 @@ void mmc_get_configuration(struct burn_drive *d)
if (c.error) if (c.error)
return; return;
len = (c.page->data[0] << 24) len = (c.page->data[0] << 24)
+ (c.page->data[1] << 16) | (c.page->data[1] << 16)
+ (c.page->data[2] << 8) | (c.page->data[2] << 8)
+ c.page->data[3]; | c.page->data[3];
if (len<8) if (len<8)
return; return;
@ -1112,10 +1130,133 @@ void mmc_get_configuration(struct burn_drive *d)
d->current_is_supported_profile = 1; d->current_is_supported_profile = 1;
#endif #endif
/* >>> see mmc5r03c.pdf 5.2 /* Enable this to get loud and repeated reports about the feature set :
Interpret list of profile and feature descriptors. #define Libburn_print_feature_descriptorS 1
*/ */
/* ts A70127 : Interpret list of profile and feature descriptors.
see mmc5r03c.pdf 5.2
>>> Ouch: What to do if list is larger than buffer size.
Specs state that the call has to be repeated.
*/
up_to = c.page->data + (len < BUFFER_SIZE ? len : BUFFER_SIZE);
#ifdef Libburn_print_feature_descriptorS
fprintf(stderr,
"-----------------------------------------------------------------\n");
fprintf(stderr,
"LIBBURN_EXPERIMENTAL : feature list length = %d , shown = %d\n",
len, up_to - c.page->data);
#endif /* Libburn_print_feature_descriptorS */
for (descr = c.page->data + 8; descr + 3 < up_to; descr += descr_len) {
descr_len = 4 + descr[3];
feature_code = (descr[0] << 8) | descr[1];
if (only_current && !(descr[2] & 1))
continue;
#ifdef Libburn_print_feature_descriptorS
fprintf(stderr,
"LIBBURN_EXPERIMENTAL : %s feature %4.4Xh\n",
descr[2] & 1 ? "+" : "-",
feature_code);
#endif /* Libburn_print_feature_descriptorS */
if (feature_code == 0x0) {
prf_end = descr + 4 + descr[3];
for (prf = descr + 4; prf + 2 < prf_end; prf += 4) {
if (only_current && !(prf[2] & 1))
continue;
prf_number = (prf[0] << 8) | prf[1];
#ifdef Libburn_print_feature_descriptorS
fprintf(stderr,
"LIBBURN_EXPERIMENTAL : %s profile %4.4Xh \"%s\"\n",
prf[2] & 1 ? "+" : "-",
prf_number,
mmc_obtain_profile_name(prf_number));
#endif /* Libburn_print_feature_descriptorS */
}
} else if (feature_code == 0x21) {
int i;
d->current_has_feat21h = (descr[2] & 1);
for (i = 0; i < descr[7]; i++) {
if (i == 0 || descr[8 + i] == 16)
d->current_feat21h_link_size =
descr[8 + i];
#ifdef Libburn_print_feature_descriptorS
fprintf(stderr,
"LIBBURN_EXPERIMENTAL : + Link Size = %d\n",
descr[8 + i]);
#endif /* Libburn_print_feature_descriptorS */
}
} else if (feature_code == 0x2F) {
if (descr[2] & 1)
d->current_feat2fh_byte4 = descr[4];
#ifdef Libburn_print_feature_descriptorS
fprintf(stderr, "LIBBURN_EXPERIMENTAL : BUF = %d , Test Write = %d , DVD-RW = %d\n",
!!(descr[4] & 64), !!(descr[4] & 4),
!!(descr[4] & 2));
#endif /* Libburn_print_feature_descriptorS */
#ifdef Libburn_print_feature_descriptorS
} else if (feature_code == 0x01) {
int pys_if_std = 0;
char *phys_name = "";
pys_if_std = (descr[4] << 24) | (descr[5] << 16) |
(descr[6] << 8) | descr[9];
if (pys_if_std == 1)
phys_name = "SCSI Family";
else if(pys_if_std == 2)
phys_name = "ATAPI";
else if(pys_if_std == 3 || pys_if_std == 4 ||
pys_if_std == 6)
phys_name = "IEEE 1394 FireWire";
else if(pys_if_std == 7)
phys_name = "Serial ATAPI";
else if(pys_if_std == 7)
phys_name = "USB";
fprintf(stderr,
"LIBBURN_EXPERIMENTAL : Phys. Interface Standard %Xh \"%s\"\n",
pys_if_std, phys_name);
} else if (feature_code == 0x107) {
fprintf(stderr, "LIBBURN_EXPERIMENTAL : CD SPEED = %d , page 2Ah = %d , SET STREAMING = %d\n",
!!(descr[4] & 8), !!(descr[4] & 4),
!!(descr[4] & 2));
} else if (feature_code == 0x108 || feature_code == 0x10c) {
int i, c_limit;
fprintf(stderr, "LIBBURN_EXPERIMENTAL : %s = ",
feature_code == 0x108 ?
"Drive Serial Number" : "Drive Firmware Date");
c_limit = descr[3] - 2 * (feature_code == 0x10c);
for (i = 0; i < c_limit; i++)
if (descr[4 + i] < 0x20 || descr[4 + i] > 0x7e
|| descr[4 + i] == '\\')
fprintf(stderr,"\\%2.2X",descr[4 + i]);
else
fprintf(stderr, "%c", descr[4 + i]);
fprintf(stderr, "\n");
#endif /* Libburn_print_feature_descriptorS */
}
}
#ifdef Libburn_support_dvd_r_seQ
if ((cp == 0x11 || cp == 0x14) && d->current_has_feat21h)
d->current_is_supported_profile = 1;
#endif
} }
@ -1663,15 +1804,19 @@ int mmc_setup_drive(struct burn_drive *d)
d->start_lba = -2000000000; d->start_lba = -2000000000;
d->end_lba = -2000000000; d->end_lba = -2000000000;
/* ts A61201 */ /* ts A61201 - A70128 */
d->erasable = 0; d->erasable = 0;
d->current_profile = -1; d->current_profile = -1;
d->current_profile_text[0] = 0; d->current_profile_text[0] = 0;
d->current_is_cd_profile = 0; d->current_is_cd_profile = 0;
d->current_is_supported_profile = 0; d->current_is_supported_profile = 0;
d->current_has_feat21h = 0;
d->current_feat21h_link_size = -1;
d->current_feat2fh_byte4 = -1;
d->needs_close_session = 0; d->needs_close_session = 0;
d->bg_format_status = -1; d->bg_format_status = -1;
d->num_format_descr = 0; d->num_format_descr = 0;
d->last_track_no = 0;
return 1; return 1;
} }
@ -1702,6 +1847,38 @@ int mmc_compose_mode_page_5(struct burn_drive *d,
pd[4] = 8; pd[4] = 8;
/* Link size dummy */ /* Link size dummy */
pd[5] = 0; pd[5] = 0;
} else if ((d->current_profile == 0x14 || d->current_profile == 0x11)
&& d->current_has_feat21h == 1) { /* ts A70128 */
/* learned from transport.hxx : page05_setup()
and mmc5r03c.pdf 7.5, 4.2.3.4 Table 17
and spc3r23.pdf 6.8, 7.4.3 */
/* BUFE , LS_V = 1, Test Write, Write Type = 00h Incremental */
pd[2] = ((!!o->underrun_proof) << 6)
| (1 << 5)
| ((!!o->simulate) << 4);
/* Multi-session , FP = 1 , Track Mode = 5 */
pd[3] = ((3 * !!o->multi) << 6) | (1 << 5) | 5;
/* Data Block Type = 8 */
pd[4] = 8;
/* Link Size */
if (d->current_feat21h_link_size >= 0)
pd[5] = d->current_feat21h_link_size;
else
pd[5] = 16;
if (d->current_feat21h_link_size != 16) {
char msg[80];
sprintf(msg,
"Feature 21h Link Size = %d (expected 16)\n",
d->current_feat21h_link_size);
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
msg, 0, 0);
}
/* Packet Size */
pd[13] = 16;
} else { } else {
/* Traditional setup for CD */ /* Traditional setup for CD */
pd[2] = ((!!o->underrun_proof) << 6) pd[2] = ((!!o->underrun_proof) << 6)

View File

@ -152,11 +152,28 @@ struct burn_drive
int current_is_cd_profile; int current_is_cd_profile;
int current_is_supported_profile; int current_is_supported_profile;
/* ts A70128 : MMC-to-MMC feature info from 46h for DVD-RW.
Quite internal. Regard as opaque :)
*/
/* 1 = incremental recording available, 0 = not available */
int current_has_feat21h;
/* Link Size item number 0 from feature 0021h descriptor */
int current_feat21h_link_size;
/* Flags from feature 002Fh feature descriptor mmc5r03c.pdf 5.3.25 :
bit1= DVD-RW supported
bit2= Test Write available
bit3= DVD-R DL supported
bit6= Buffer Under-run Free recording available (page 05h BUFE)
*/
int current_feat2fh_byte4;
/* ts A70114 : wether a DVD-RW media holds an incomplete session /* ts A70114 : wether a DVD-RW media holds an incomplete session
(which could need closing after write) */ (which could need closing after write) */
int needs_close_session; int needs_close_session;
/* ts A61218 from 46h GET CONFIGURATION */ /* ts A61218 from 51h READ DISC INFORMATION */
int bg_format_status; /* 0=needs format start, 1=needs format restart*/ int bg_format_status; /* 0=needs format start, 1=needs format restart*/
/* ts A70108 from 23h READ FORMAT CAPACITY mmc5r03c.pdf 6.24 */ /* ts A70108 from 23h READ FORMAT CAPACITY mmc5r03c.pdf 6.24 */
@ -181,6 +198,11 @@ struct burn_drive
int rlba; /* relative lba in section */ int rlba; /* relative lba in section */
int start_lba; int start_lba;
int end_lba; int end_lba;
/* ts A70129 :
from 51h READ DISC INFORMATION Last Track Number in Last Session */
int last_track_no;
int toc_temp; int toc_temp;
struct burn_disc *disc; /* disc structure */ struct burn_disc *disc; /* disc structure */
int block_types[4]; int block_types[4];

View File

@ -195,7 +195,11 @@ int burn_write_close_track(struct burn_write_opts *o, struct burn_session *s,
/* MMC-1 mentions track number 0xFF for "the incomplete track", /* MMC-1 mentions track number 0xFF for "the incomplete track",
MMC-3 does not. I tried both. 0xFF was in effect when other MMC-3 does not. I tried both. 0xFF was in effect when other
bugs finally gave up and made way for readable tracks. */ bugs finally gave up and made way for readable tracks. */
d->close_track_session(o->drive, 0, 0xff); /* tnum+1); */ /* ts A70129
Probably the right value would be d->last_track_no+tnum for
appendables
*/
d->close_track_session(o->drive, 0, 0xff);
/* ts A61102 */ /* ts A61102 */
d->busy = BURN_DRIVE_WRITING; d->busy = BURN_DRIVE_WRITING;
@ -676,7 +680,7 @@ int burn_write_track(struct burn_write_opts *o, struct burn_session *s,
/* ts A70121 : This is not possible because /* ts A70121 : This is not possible because
track 1 cannot have a pregap at all. track 1 cannot have a pregap at all.
MMC-5 6.33.3.2 precribes a mandatoy pause MMC-5 6.33.3.2 precribes a mandatory pause
prior to any track 1. Pre-gap is prescribed prior to any track 1. Pre-gap is prescribed
for mode changes like audio-to-data. for mode changes like audio-to-data.
To set burn_track.pregap1 for track 1 is To set burn_track.pregap1 for track 1 is
@ -865,7 +869,50 @@ int burn_disc_init_write_status(struct burn_write_opts *o,
} }
/* ts A61218 */ /* ts A70129 : learned much from dvd+rw-tools-7.0/growisofs_mmc.cpp */
int burn_disc_open_track_dvd_minus_r(struct burn_write_opts *o, int tnum)
{
struct burn_drive *d = o->drive;
char msg[160];
int ret, lba, nwa;
d->send_write_parameters(d, o);
ret = d->get_nwa(d, -1, &lba, &nwa);
sprintf(msg,
"DVD pre-track %2.2d : get_nwa(%d), ret= %d , d->nwa= %d\n",
tnum+1, nwa, ret, d->nwa);
libdax_msgs_submit(libdax_messenger, d->global_index, 0x000002,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
msg,0,0);
if (nwa > d->nwa)
d->nwa = nwa;
return 1;
}
/* ts A70129 */
int burn_disc_close_track_dvd_minus_r(struct burn_write_opts *o,
struct burn_session *s, int tnum)
{
struct burn_drive *d = o->drive;
/* only DVD-R or sequential DVD-RW */
if (d->current_has_feat21h != 1) /* only with Incremental writing */
return 2;
d->busy = BURN_DRIVE_CLOSING_SESSION;
/* 0xff was a name for the last track in MMC-1 but later
it vanished. One would need to determine the absolute
logical track number in multi-session situations.
Probably: d->last_track_no+tnum
*/
d->close_track_session(d, 0, 0xff); /* CLOSE TRACK, 001b */
d->busy = BURN_DRIVE_WRITING;
return 1;
}
/* ts A61218 - A70129 */
int burn_dvd_write_track(struct burn_write_opts *o, int burn_dvd_write_track(struct burn_write_opts *o,
struct burn_session *s, int tnum) struct burn_session *s, int tnum)
{ {
@ -873,12 +920,17 @@ int burn_dvd_write_track(struct burn_write_opts *o,
struct burn_drive *d = o->drive; struct burn_drive *d = o->drive;
struct buffer *out = d->buffer; struct buffer *out = d->buffer;
int sectors; int sectors;
int i, open_ended = 0, ret= 0; int i, open_ended = 0, ret= 0, is_flushed = 0;
sectors = burn_track_get_sectors(t); sectors = burn_track_get_sectors(t);
open_ended = burn_track_is_open_ended(t); open_ended = burn_track_is_open_ended(t);
/* >>> any type specific track preparations */; if (d->current_profile == 0x11 || d->current_profile == 0x14) {
/* DVD-R, DVD-RW Sequential */
ret = burn_disc_open_track_dvd_minus_r(o, tnum);
if (ret <= 0)
goto ex;
}
burn_disc_init_track_status(o, s, tnum, sectors); burn_disc_init_track_status(o, s, tnum, sectors);
for (i = 0; open_ended || i < sectors; i++) { for (i = 0; open_ended || i < sectors; i++) {
@ -910,14 +962,19 @@ int burn_dvd_write_track(struct burn_write_opts *o,
ret = burn_write_flush(o, t); ret = burn_write_flush(o, t);
if (ret <= 0) if (ret <= 0)
goto ex; goto ex;
is_flushed = 1;
/* >>> any other normal track finalizing */; /* Eventually finalize track */
if (d->current_profile == 0x11 || d->current_profile == 0x14) {
/* DVD-R, DVD-RW Sequential */
ret = burn_disc_close_track_dvd_minus_r(o, s, tnum);
if (ret != 2)
goto ex;
}
ret = 1; ret = 1;
ex:; ex:;
if (ret<=0) { if (!is_flushed)
d->sync_cache(d); /* burn_write_flush() was not called */ d->sync_cache(d); /* burn_write_flush() was not called */
}
return ret; return ret;
} }
@ -961,6 +1018,22 @@ int burn_disc_close_session_dvd_minus_rw(struct burn_write_opts *o,
} }
/* ts A70129 : for profile 0x11 DVD-R and 0x14 DVD-RW Sequential */
int burn_disc_close_session_dvd_minus_r(struct burn_write_opts *o,
struct burn_session *s)
{
struct burn_drive *d = o->drive;
if (d->current_has_feat21h != 1) /* only for Incremental writing */
return 2;
d->busy = BURN_DRIVE_CLOSING_SESSION;
d->close_track_session(d, 1, 0); /* CLOSE SESSION, 010b */
d->busy = BURN_DRIVE_WRITING;
return 1;
}
/* ts A61218 */ /* ts A61218 */
int burn_dvd_write_session(struct burn_write_opts *o, int burn_dvd_write_session(struct burn_write_opts *o,
struct burn_session *s) struct burn_session *s)
@ -968,18 +1041,21 @@ int burn_dvd_write_session(struct burn_write_opts *o,
int i,ret; int i,ret;
struct burn_drive *d = o->drive; struct burn_drive *d = o->drive;
/* >>> open_session ? (maybe with DAO) */
for (i = 0; i < s->tracks; i++) { for (i = 0; i < s->tracks; i++) {
ret = burn_dvd_write_track(o, s, i); ret = burn_dvd_write_track(o, s, i);
if (ret <= 0) if (ret <= 0)
break; break;
} }
if (d->current_profile == 0x1a) { if ((d->current_profile == 0x11 || d->current_profile == 0x14)) {
/* DVD+RW */ /* DVD-R , DVD-RW Sequential */
if (d->needs_close_session) { ret = burn_disc_close_session_dvd_minus_r(o, s);
ret = burn_disc_close_session_dvd_plus_rw(o, s);
if (ret <= 0) if (ret <= 0)
return 0; return 0;
} } else if (d->current_profile == 0x12) {
/* DVD-RAM */
/* ??? any finalization needed ? */;
} else if (d->current_profile == 0x13) { } else if (d->current_profile == 0x13) {
/* DVD-RW restricted overwrite */ /* DVD-RW restricted overwrite */
if (d->needs_close_session) { if (d->needs_close_session) {
@ -987,9 +1063,13 @@ int burn_dvd_write_session(struct burn_write_opts *o,
if (ret <= 0) if (ret <= 0)
return 0; return 0;
} }
} else if (d->current_profile == 0x12) { } else if (d->current_profile == 0x1a) {
/* DVD-RAM */ /* DVD+RW */
/* ??? any finalization needed ? */; if (d->needs_close_session) {
ret = burn_disc_close_session_dvd_plus_rw(o, s);
if (ret <= 0)
return 0;
}
} }
return 1; return 1;
} }
@ -1097,7 +1177,24 @@ int burn_disc_setup_dvd_minus_rw(struct burn_write_opts *o,
} }
/* ts A61218 */ /* ts A70129 */
int burn_disc_setup_dvd_minus_r(struct burn_write_opts *o,
struct burn_disc *disc)
{
struct burn_drive *d = o->drive;
if (d->current_has_feat21h) {
/* most setup is in burn_disc_setup_track_dvd_minus_r() */;
} else {
return 0; /* >>> no DAO for now */
}
d->nwa = 0;
return 1;
}
/* ts A61218 - A70129 */
int burn_dvd_write_sync(struct burn_write_opts *o, int burn_dvd_write_sync(struct burn_write_opts *o,
struct burn_disc *disc) struct burn_disc *disc)
{ {
@ -1161,7 +1258,8 @@ int burn_dvd_write_sync(struct burn_write_opts *o,
} }
o->obs_pad = 0; /* no filling-up of track's last 32k buffer */ o->obs_pad = 0; /* no filling-up of track's last 32k buffer */
} else if (d->current_profile == 0x13) { /* DVD-RW Rest. Overwrite */ } else if (d->current_profile == 0x13) {
/* DVD-RW Restricted Overwrite */
if (o->start_byte >= 0 && (o->start_byte % 32768)) { if (o->start_byte >= 0 && (o->start_byte % 32768)) {
sprintf(msg, sprintf(msg,
"Write start address not properly aligned to 32K"); "Write start address not properly aligned to 32K");
@ -1182,9 +1280,31 @@ int burn_dvd_write_sync(struct burn_write_opts *o,
goto early_failure; goto early_failure;
} }
/* ??? is this necessary ? */ /* _Rigid_ Restricted Overwrite demands this */
o->obs_pad = 1; /* fill-up track's last 32k buffer */ o->obs_pad = 1; /* fill-up track's last 32k buffer */
} else if ((d->current_profile == 0x11 || d->current_profile == 0x14)
&& d->current_has_feat21h == 1) {
/* DVD-R , DVD-RW Sequential (for now only Incremental) */
if (o->start_byte >= 0) {
sprintf(msg, "Write start address not supported");
libdax_msgs_submit(libdax_messenger, d->global_index,
0x00020124,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
msg, 0,0);
goto early_failure;
}
ret = burn_disc_setup_dvd_minus_r(o, disc);
if (ret <= 0) {
sprintf(msg,
"Write preparation setup failed for DVD-R[W]");
libdax_msgs_submit(libdax_messenger, d->global_index,
0x00020121,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
msg, 0,0);
goto early_failure;
}
} else { } else {
sprintf(msg, "Unsuitable media detected. Profile %4.4Xh %s", sprintf(msg, "Unsuitable media detected. Profile %4.4Xh %s",
d->current_profile, d->current_profile_text); d->current_profile, d->current_profile_text);