Implemented some ATIP functionality
This commit is contained in:
parent
4718ad99f9
commit
b6a04cb493
@ -172,6 +172,7 @@ or
|
|||||||
#define Cdrskin_libburn_has_audioxtR 1
|
#define Cdrskin_libburn_has_audioxtR 1
|
||||||
#define Cdrskin_libburn_has_get_start_end_lbA 1
|
#define Cdrskin_libburn_has_get_start_end_lbA 1
|
||||||
#define Cdrskin_libburn_has_burn_disc_unsuitablE 1
|
#define Cdrskin_libburn_has_burn_disc_unsuitablE 1
|
||||||
|
#define Cdrskin_libburn_has_read_atiP 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef Cdrskin_libburn_versioN
|
#ifndef Cdrskin_libburn_versioN
|
||||||
@ -3326,7 +3327,7 @@ ex:;
|
|||||||
int Cdrskin_atip(struct CdrskiN *skin, int flag)
|
int Cdrskin_atip(struct CdrskiN *skin, int flag)
|
||||||
{
|
{
|
||||||
int ret,is_not_really_erasable= 0;
|
int ret,is_not_really_erasable= 0;
|
||||||
double x_speed;
|
double x_speed_max, x_speed_min= -1.0;
|
||||||
enum burn_disc_status s;
|
enum burn_disc_status s;
|
||||||
struct burn_drive *drive;
|
struct burn_drive *drive;
|
||||||
|
|
||||||
@ -3400,10 +3401,26 @@ int Cdrskin_atip(struct CdrskiN *skin, int flag)
|
|||||||
|
|
||||||
#endif /* Cdrskin_atip_speed_brokeN */
|
#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);
|
ret= burn_drive_get_write_speed(drive);
|
||||||
x_speed= ((double) ret)/Cdrskin_libburn_cd_speed_factoR;
|
x_speed_max= ((double) ret)/Cdrskin_libburn_cd_speed_factoR;
|
||||||
printf("cdrskin: burn_drive_get_write_speed = %d (%.1fx)\n",ret,x_speed);
|
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(skin->verbosity>=Cdrskin_verbose_progresS) {
|
||||||
if(burn_disc_erasable(drive))
|
if(burn_disc_erasable(drive))
|
||||||
printf("Current: CD-RW\n");
|
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);
|
ret= burn_drive_get_start_end_lba(drive,&start_lba,&end_lba,0);
|
||||||
if(ret>0) {
|
if(ret>0) {
|
||||||
burn_lba_to_msf(start_lba,&min,&sec,&fr);
|
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);
|
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 */
|
#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;
|
ret= 1;
|
||||||
ex:;
|
ex:;
|
||||||
Cdrskin_release_drive(skin,0);
|
Cdrskin_release_drive(skin,0);
|
||||||
|
@ -1 +1 @@
|
|||||||
#define Cdrskin_timestamP "2006.10.20.151602"
|
#define Cdrskin_timestamP "2006.10.21.103352"
|
||||||
|
@ -663,6 +663,12 @@ int burn_drive_get_write_speed(struct burn_drive *d)
|
|||||||
return d->mdata->max_write_speed;
|
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 */
|
/* ts A51221 */
|
||||||
static char *enumeration_whitelist[BURN_DRIVE_WHITELIST_LEN];
|
static char *enumeration_whitelist[BURN_DRIVE_WHITELIST_LEN];
|
||||||
@ -1136,3 +1142,19 @@ int burn_disc_pretend_blank(struct burn_drive *d)
|
|||||||
return 1;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -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.
|
failed to declare themselves either blank or (partially) filled.
|
||||||
@return 1 drive status has been set , 0 = unsuitable drive status
|
@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 */
|
/* 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)
|
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||||
@return 1 if lba values are valid , 0 if invalid
|
@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);
|
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);
|
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
|
/** Gets the maximum read speed for a drive
|
||||||
@param d Drive to query
|
@param d Drive to query
|
||||||
@return Maximum read speed in K/s
|
@return Maximum read speed in K/s
|
||||||
|
@ -319,7 +319,7 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff
|
|||||||
0x0002010b (FATAL,HIGH) = Burn run failed
|
0x0002010b (FATAL,HIGH) = Burn run failed
|
||||||
0x0002010c (FATAL,HIGH) = Failed to transfer command to drive
|
0x0002010c (FATAL,HIGH) = Failed to transfer command to drive
|
||||||
0x0002010d (DEBUG,HIGH) = Could not inquire TOC
|
0x0002010d (DEBUG,HIGH) = Could not inquire TOC
|
||||||
0x0002010e
|
0x0002010e (FATAL,HIGH) = Attempt to read ATIP from ungrabbed drive
|
||||||
0x0002010f
|
0x0002010f
|
||||||
0x00020110 (FATAL,HIGH) = Persistent drive address too long
|
0x00020110 (FATAL,HIGH) = Persistent drive address too long
|
||||||
0x00020111 (FATAL,HIGH) = Could not allocate new auxiliary object
|
0x00020111 (FATAL,HIGH) = Could not allocate new auxiliary object
|
||||||
|
130
libburn/mmc.c
130
libburn/mmc.c
@ -439,6 +439,17 @@ void mmc_read_atip(struct burn_drive *d)
|
|||||||
struct buffer buf;
|
struct buffer buf;
|
||||||
struct command c;
|
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");
|
mmc_function_spy("mmc_read_atip");
|
||||||
memcpy(c.opcode, MMC_GET_ATIP, sizeof(MMC_GET_ATIP));
|
memcpy(c.opcode, MMC_GET_ATIP, sizeof(MMC_GET_ATIP));
|
||||||
c.retry = 1;
|
c.retry = 1;
|
||||||
@ -450,6 +461,125 @@ void mmc_read_atip(struct burn_drive *d)
|
|||||||
c.dir = FROM_DRIVE;
|
c.dir = FROM_DRIVE;
|
||||||
d->issue_command(d, &c);
|
d->issue_command(d, &c);
|
||||||
burn_print(1, "atip shit for you\n");
|
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,
|
void mmc_read_sectors(struct burn_drive *d,
|
||||||
|
@ -208,6 +208,7 @@ static void enumerate_common(char *fname, int bus_no, int host_no,
|
|||||||
|
|
||||||
out.start_lba= -2000000000;
|
out.start_lba= -2000000000;
|
||||||
out.end_lba= -2000000000;
|
out.end_lba= -2000000000;
|
||||||
|
out.read_atip = mmc_read_atip;
|
||||||
|
|
||||||
out.grab = sg_grab;
|
out.grab = sg_grab;
|
||||||
out.release = sg_release;
|
out.release = sg_release;
|
||||||
|
@ -443,6 +443,7 @@ static void enumerate_common(char *fname, int bus_no, int host_no,
|
|||||||
/* ts A61020 */
|
/* ts A61020 */
|
||||||
out.start_lba= -2000000000;
|
out.start_lba= -2000000000;
|
||||||
out.end_lba= -2000000000;
|
out.end_lba= -2000000000;
|
||||||
|
out.read_atip = mmc_read_atip;
|
||||||
|
|
||||||
out.grab = sg_grab;
|
out.grab = sg_grab;
|
||||||
out.release = sg_release;
|
out.release = sg_release;
|
||||||
|
@ -157,10 +157,24 @@ void spc_sense_caps(struct burn_drive *d)
|
|||||||
m->cdrw_write = page[3] & 2;
|
m->cdrw_write = page[3] & 2;
|
||||||
m->cdr_read = page[2] & 1;
|
m->cdr_read = page[2] & 1;
|
||||||
m->cdr_write = page[3] & 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->max_read_speed = page[8] * 256 + page[9];
|
||||||
m->cur_read_speed = page[14] * 256 + page[15];
|
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];
|
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];
|
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->c2_pointers = page[5] & 16;
|
||||||
m->valid = 1;
|
m->valid = 1;
|
||||||
m->underrun_proof = page[4] & 128;
|
m->underrun_proof = page[4] & 128;
|
||||||
|
@ -79,6 +79,10 @@ struct scsi_mode_data
|
|||||||
int simulate;
|
int simulate;
|
||||||
int max_read_speed;
|
int max_read_speed;
|
||||||
int max_write_speed;
|
int max_write_speed;
|
||||||
|
|
||||||
|
/* ts A61021 */
|
||||||
|
int min_write_speed;
|
||||||
|
|
||||||
int cur_read_speed;
|
int cur_read_speed;
|
||||||
int cur_write_speed;
|
int cur_write_speed;
|
||||||
int retry_page_length;
|
int retry_page_length;
|
||||||
@ -146,6 +150,10 @@ struct burn_drive
|
|||||||
/* lower level functions */
|
/* lower level functions */
|
||||||
void (*erase) (struct burn_drive *, int);
|
void (*erase) (struct burn_drive *, int);
|
||||||
void (*getcaps) (struct burn_drive *);
|
void (*getcaps) (struct burn_drive *);
|
||||||
|
|
||||||
|
/* ts A61021 */
|
||||||
|
void (*read_atip) (struct burn_drive *);
|
||||||
|
|
||||||
int (*write) (struct burn_drive *, int, struct buffer *);
|
int (*write) (struct burn_drive *, int, struct buffer *);
|
||||||
void (*read_toc) (struct burn_drive *);
|
void (*read_toc) (struct burn_drive *);
|
||||||
void (*lock) (struct burn_drive *);
|
void (*lock) (struct burn_drive *);
|
||||||
|
Loading…
Reference in New Issue
Block a user