662 lines
18 KiB
C++
662 lines
18 KiB
C++
/*
|
|
* DVD±RW format 6.1 by Andy Polyakov <appro@fy.chalmers.se>.
|
|
*
|
|
* Use-it-on-your-own-risk, GPL bless...
|
|
*
|
|
* For further details see http://fy.chalmers.se/~appro/linux/DVD+RW/.
|
|
*
|
|
* Revision history:
|
|
*
|
|
* 2.0:
|
|
* - deploy "IMMED" bit in "FORMAT UNIT";
|
|
* 2.1:
|
|
* - LP64 fix;
|
|
* - USB workaround;
|
|
* 3.0:
|
|
* - C++-fication for better portability;
|
|
* - SYSV signals for better portability;
|
|
* - -lead-out option for improved DVD+RW compatibility;
|
|
* - tested with SONY DRU-500A;
|
|
* 4.0:
|
|
* - support for DVD-RW formatting and blanking, tool name becomes
|
|
* overloaded...
|
|
* 4.1:
|
|
* - re-make it work under Linux 2.2 kernel;
|
|
* 4.2:
|
|
* - attempt to make DVD-RW Quick Format truly quick, upon release
|
|
* is verified to work with Pioneer DVR-x05;
|
|
* - media reload is moved to growisofs where is actually belongs;
|
|
* 4.3:
|
|
* - -blank to imply -force;
|
|
* - reject -blank in DVD+RW context and -lead-out in DVD-RW;
|
|
* 4.4:
|
|
* - support for -force=full in DVD-RW context;
|
|
* - ask unit to perform OPC if READ DISC INFORMATION doesn't return
|
|
* any OPC descriptors;
|
|
* 4.5:
|
|
* - increase timeout for OPC, NEC multi-format derivatives might
|
|
* require more time to fulfill the OPC procedure;
|
|
* 4.6:
|
|
* - -force to ignore error from READ DISC INFORMATION;
|
|
* - -force was failing under FreeBSD with 'unable to unmount';
|
|
* - undocumented -gui flag to ease progress indicator parsing for
|
|
* GUI front-ends;
|
|
* 4.7:
|
|
* - when formatting DVD+RW, Pioneer DVR-x06 remained unaccessible for
|
|
* over 2 minutes after dvd+rw-format exited and user was frustrated
|
|
* to poll the unit himself, now dvd+rw-format does it for user;
|
|
* 4.8:
|
|
* - DVD-RW format fails if preceeded by dummy recording;
|
|
* - make sure we talk to MMC unit, be less intrusive;
|
|
* - unify error reporting;
|
|
* - permit for -lead-out even for blank DVD+RW, needed(?) for SANYO
|
|
* derivatives;
|
|
* 4.9:
|
|
* - permit for DVD-RW blank even if format descriptors are not present;
|
|
* 4.10:
|
|
* - add support for DVD-RAM;
|
|
* 6.0:
|
|
* - versioning harmonization;
|
|
* - WIN32 port;
|
|
* - Initial DVD+RW Double Layer support;
|
|
* - Ignore "WRITE PROTECTED" error in OPC;
|
|
* 6.1:
|
|
* - ± localization;
|
|
* - Treat only x73xx OPC errors as fatal;
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#if defined(__unix) || defined(__unix__)
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <sys/mman.h>
|
|
#include <signal.h>
|
|
#include <setjmp.h>
|
|
#include <sys/wait.h>
|
|
#endif
|
|
|
|
#include "transport.hxx"
|
|
|
|
static void usage (char *prog)
|
|
{ fprintf (stderr,"- usage: %s [-force[=full]] [-lead-out|-blank[=full]]\n"
|
|
" [-ssa[=none|default|max]] /dev/dvd\n",prog),
|
|
exit(1);
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
#include <process.h>
|
|
|
|
# if defined(__GNUC__)
|
|
# define __shared__ __attribute__((section(".shared"),shared))
|
|
# elif defined(_MSC_VER)
|
|
# define __shared__
|
|
# pragma data_seg(".shared")
|
|
# pragma comment(linker,"/section:.shared,rws")
|
|
# endif
|
|
static volatile int shared_progress_indicator __shared__ = 0;
|
|
# if defined(_MSC_VER)
|
|
# pragma data_seg()
|
|
# endif
|
|
|
|
static volatile int *progress = &shared_progress_indicator;
|
|
static HANDLE Process = NULL;
|
|
|
|
BOOL WINAPI GoBackground (DWORD code)
|
|
{ if (*progress)
|
|
{ FreeConsole(); /* detach from console upon ctrl-c or window close */
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void KillForeground (void)
|
|
{ fprintf(stderr,"\n");
|
|
TerminateProcess(Process,0);
|
|
}
|
|
#else
|
|
static volatile int *progress;
|
|
#endif
|
|
|
|
static const char *gui_action=NULL;
|
|
static const char *str = "|/-\\",*backspaces="\b\b\b\b\b\b\b\b\b\b";
|
|
|
|
#if defined(__unix) || defined(__unix__)
|
|
extern "C" void alarm_handler (int no)
|
|
{ static int i=0,len=1,old_progress=0;
|
|
int new_progress = *progress;
|
|
|
|
if (gui_action)
|
|
{ fprintf (stderr,"* %s %.1f%%\n",gui_action,
|
|
100.0*new_progress/65536.0);
|
|
alarm(3);
|
|
return;
|
|
}
|
|
|
|
if (new_progress != old_progress)
|
|
len = fprintf (stderr,"%.*s%.1f%%",len,backspaces,
|
|
100.0*new_progress/65536.0) - len,
|
|
old_progress = new_progress;
|
|
else
|
|
fprintf (stderr,"\b%c",str[i]),
|
|
i++, i&=3;
|
|
|
|
alarm(1);
|
|
}
|
|
#endif
|
|
|
|
int main (int argc, char *argv[])
|
|
{ Scsi_Command cmd;
|
|
unsigned char formats[260],dinfo[32],inq[128];
|
|
char *dev=NULL,*p;
|
|
unsigned int capacity,lead_out,mmc_profile,err;
|
|
int force=0,full=0,compat=0,blank=0,ssa=0,do_opc=0,gui=0,len,i;
|
|
#if defined(__unix) || defined(__unix__)
|
|
pid_t pid;
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
DWORD ppid;
|
|
char filename[MAX_PATH],*progname;
|
|
|
|
/*
|
|
* Foreground process spawns itself and simply waits for shared
|
|
* progress indicator to increment...
|
|
*/
|
|
if (sscanf(argv[0],":%u:",&ppid) != 1)
|
|
{ int i=0,len=1,old_progress=0,new_progress;
|
|
|
|
sprintf (filename,":%u:",GetCurrentProcessId());
|
|
progname = argv[0];
|
|
argv[0] = filename;
|
|
Process = (HANDLE)_spawnv (_P_NOWAIT,progname,argv);
|
|
if (Process == (HANDLE)-1)
|
|
perror("_spawnv"), ExitProcess(errno);
|
|
|
|
while(1)
|
|
{ if (WaitForSingleObject(Process,1000) == WAIT_OBJECT_0)
|
|
{ ppid = 0; /* borrow DWORD variable */
|
|
GetExitCodeProcess(Process,&ppid);
|
|
ExitProcess(ppid);
|
|
}
|
|
|
|
new_progress = *progress;
|
|
if (new_progress != old_progress)
|
|
len = fprintf (stderr,"%.*s%.1f%%",len,backspaces,
|
|
100.0*new_progress/65536.0) - len,
|
|
old_progress = new_progress;
|
|
else if (new_progress)
|
|
fprintf (stderr,"\b%c",str[i]),
|
|
i++, i&=3;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ... while background process does *all* the job...
|
|
*/
|
|
Process = OpenProcess (PROCESS_TERMINATE,FALSE,ppid);
|
|
if (Process == NULL)
|
|
perror("OpenProcess"), ExitProcess(errno);
|
|
|
|
atexit (KillForeground);
|
|
SetConsoleCtrlHandler (GoBackground,TRUE);
|
|
|
|
GetModuleFileName (NULL,filename,sizeof(filename));
|
|
progname = strrchr(filename,'\\');
|
|
if (progname) argv[0] = progname+1;
|
|
else argv[0] = filename;
|
|
#endif
|
|
|
|
fprintf (stderr,"* DVD%sRW/-RAM format utility by <appro@fy.chalmers.se>, "
|
|
"version 6.1.\n",plusminus_locale());
|
|
|
|
for (i=1;i<argc;i++) {
|
|
if (*argv[i] == '-')
|
|
if (argv[i][1] == 'f') // -format|-force
|
|
{ force = 1;
|
|
if ((p=strchr(argv[i],'=')) && p[1]=='f') full=1;
|
|
}
|
|
else if (argv[i][1] == 'l') // -lead-out
|
|
force = compat = 1;
|
|
else if (argv[i][1] == 'b') // -blank
|
|
{ blank=0x11;
|
|
if ((p=strchr(argv[i],'=')) && p[1]=='f') blank=0x10;
|
|
force=1;
|
|
}
|
|
else if (argv[i][1] == 's') // -ssa
|
|
{ force=ssa=1;
|
|
if ((p=strchr(argv[i],'=')))
|
|
{ if (p[1]=='n') ssa=-1; // =none
|
|
else if (p[1]=='d') ssa=2; // =default
|
|
else if (p[3]=='x') ssa=3; // =max
|
|
else ssa=0; // invalid
|
|
}
|
|
}
|
|
else if (argv[i][1] == 'g') gui=1;
|
|
else usage(argv[0]);
|
|
#ifdef _WIN32
|
|
else if (argv[i][1] == ':')
|
|
#else
|
|
else if (*argv[i] == '/')
|
|
#endif
|
|
dev = argv[i];
|
|
else
|
|
usage (argv[0]);
|
|
}
|
|
|
|
if (dev==NULL) usage (argv[0]);
|
|
|
|
if (!cmd.associate(dev))
|
|
fprintf (stderr,":-( unable to open(\"%s\"): ",dev), perror (NULL),
|
|
exit(1);
|
|
|
|
cmd[0] = 0x12; // INQUIRY
|
|
cmd[4] = 36;
|
|
cmd[5] = 0;
|
|
if ((err=cmd.transport(READ,inq,36)))
|
|
sperror ("INQUIRY",err), exit (1);
|
|
|
|
if ((inq[0]&0x1F) != 5)
|
|
fprintf (stderr,":-( not an MMC unit!\n"),
|
|
exit (1);
|
|
|
|
cmd[0] = 0x46; // GET CONFIGURATION
|
|
cmd[8] = 8;
|
|
cmd[9] = 0;
|
|
if ((err=cmd.transport(READ,formats,8)))
|
|
sperror ("GET CONFIGURATION",err), exit (1);
|
|
|
|
mmc_profile = formats[6]<<8|formats[7];
|
|
|
|
if (mmc_profile!=0x1A && mmc_profile!=0x2A
|
|
&& mmc_profile!=0x14 && mmc_profile!=0x13
|
|
&& mmc_profile!=0x12)
|
|
fprintf (stderr,":-( mounted media doesn't appear to be "
|
|
"DVD%sRW or DVD-RAM\n",plusminus_locale()),
|
|
exit (1);
|
|
|
|
/*
|
|
* First figure out how long the actual list is. Problem here is
|
|
* that (at least Linux) USB units absolutely insist on accurate
|
|
* cgc.buflen and you can't just set buflen to arbitrary value
|
|
* larger than actual transfer length.
|
|
*/
|
|
int once=1;
|
|
do
|
|
{ cmd[0] = 0x23; // READ FORMAT CAPACITIES
|
|
cmd[8] = 4;
|
|
cmd[9] = 0;
|
|
if ((err=cmd.transport(READ,formats,4)))
|
|
{ if (err==0x62800 && once) // "MEDIUM MAY HAVE CHANGED"
|
|
{ cmd[0] = 0; // TEST UNIT READY
|
|
cmd[5] = 0;
|
|
cmd.transport(); // just swallow it...
|
|
continue;
|
|
}
|
|
sperror ("READ FORMAT CAPACITIES",err), exit (1);
|
|
}
|
|
} while (once--);
|
|
|
|
len = formats[3];
|
|
if (len&7 || len<8)
|
|
fprintf (stderr,":-( allocation length isn't sane\n"),
|
|
exit(1);
|
|
|
|
cmd[0] = 0x23; // READ FORMAT CAPACITIES
|
|
cmd[7] = (4+len)>>8; // now with real length...
|
|
cmd[8] = (4+len)&0xFF;
|
|
cmd[9] = 0;
|
|
if ((err=cmd.transport(READ,formats,4+len)))
|
|
sperror ("READ FORMAT CAPACITIES",err), exit (1);
|
|
|
|
if (len != formats[3])
|
|
fprintf (stderr,":-( parameter length inconsistency\n"),
|
|
exit(1);
|
|
|
|
if (mmc_profile==0x1A || mmc_profile==0x2A) // DVD+RW
|
|
{ for (i=8;i<len;i+=8) // look for "DVD+RW Full" descriptor
|
|
if ((formats [4+i+4]>>2) == 0x26) break;
|
|
}
|
|
else if (mmc_profile==0x12) // DVD-RAM
|
|
{ unsigned int v,ref;
|
|
unsigned char *f,descr=0x01;
|
|
int j;
|
|
|
|
switch (ssa)
|
|
{ case -1: // no ssa
|
|
for (ref=0,i=len,j=8;j<len;j+=8)
|
|
{ f = formats+4+j;
|
|
if ((f[4]>>2) == 0x00)
|
|
{ v=f[0]<<24|f[1]<<16|f[2]<<8|f[3];
|
|
if (v>ref) ref=v,i=j;
|
|
}
|
|
}
|
|
break;
|
|
case 0:
|
|
i=8; // just grab the first descriptor?
|
|
break;
|
|
case 1: // first ssa
|
|
for (i=8;i<len;i+=8)
|
|
if ((formats[4+i+4]>>2) == 0x01) break;
|
|
break;
|
|
case 2: // default ssa
|
|
descr=0x00;
|
|
case 3: // max ssa
|
|
for (ref=0xFFFFFFFF,i=len,j=8;j<len;j+=8)
|
|
{ f = formats+4+j;
|
|
if ((f[4]>>2) == descr)
|
|
{ v=f[0]<<24|f[1]<<16|f[2]<<8|f[3];
|
|
if (v<ref) ref=v,i=j;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else // DVD-RW
|
|
{ int descr=full?0x10:0x15;
|
|
for (i=8;i<len;i+=8) // look for "DVD-RW Quick" descriptor
|
|
if ((formats [4+i+4]>>2) == descr) break;
|
|
if (descr==0x15 && i==len)
|
|
{ fprintf (stderr,":-( failed to locate \"Quick Format\" descriptor.\n");
|
|
for (i=8;i<len;i+=8)// ... alternatively for "DVD-RW Full"
|
|
if ((formats [4+i+4]>>2) == 0x10) break;
|
|
}
|
|
}
|
|
|
|
if (i==len)
|
|
{ fprintf (stderr,":-( can't locate appropriate format descriptor\n");
|
|
if (blank) i=0;
|
|
else exit(1);
|
|
}
|
|
|
|
capacity = 0;
|
|
capacity |= formats[4+i+0], capacity <<= 8;
|
|
capacity |= formats[4+i+1], capacity <<= 8;
|
|
capacity |= formats[4+i+2], capacity <<= 8;
|
|
capacity |= formats[4+i+3];
|
|
|
|
if (mmc_profile==0x1A || mmc_profile==0x2A) // DVD+RW
|
|
fprintf (stderr,"* %.1fGB DVD+RW media detected.\n",
|
|
2048.0*capacity/1e9);
|
|
else if (mmc_profile==0x12) // DVD-RAM
|
|
fprintf (stderr,"* %.1fGB DVD-RAM media detected.\n",
|
|
2048.0*capacity/1e9);
|
|
else // DVD-RW
|
|
fprintf (stderr,"* %.1fGB DVD-RW media in %s mode detected.\n",
|
|
2048.0*capacity/1e9,
|
|
mmc_profile==0x13?"Restricted Overwrite":"Sequential");
|
|
|
|
lead_out = 0;
|
|
lead_out |= formats[4+0], lead_out <<= 8;
|
|
lead_out |= formats[4+1], lead_out <<= 8;
|
|
lead_out |= formats[4+2], lead_out <<= 8;
|
|
lead_out |= formats[4+3];
|
|
|
|
cmd[0] = 0x51; // READ DISC INFORMATION
|
|
cmd[8] = sizeof(dinfo);
|
|
cmd[9] = 0;
|
|
if ((err=cmd.transport(READ,dinfo,sizeof(dinfo))))
|
|
{ sperror ("READ DISC INFORMATION",err);
|
|
if (!force) exit(1);
|
|
memset (dinfo,0xff,sizeof(dinfo));
|
|
cmd[0] = 0x35;
|
|
cmd[9] = 0;
|
|
cmd.transport();
|
|
}
|
|
|
|
do_opc = ((dinfo[0]<<8|dinfo[1])<=0x20);
|
|
|
|
if (dinfo[2]&3) // non-blank media
|
|
{ if (!force)
|
|
{ if (mmc_profile==0x1A || mmc_profile==0x2A || mmc_profile==0x13 || mmc_profile==0x12)
|
|
fprintf (stderr,"- media is already formatted, lead-out is currently at\n"
|
|
" %d KiB which is %.1f%% of total capacity.\n",
|
|
lead_out*2,(100.0*lead_out)/capacity);
|
|
else
|
|
fprintf (stderr,"- media is not blank\n");
|
|
offer_options:
|
|
if (mmc_profile == 0x1A || mmc_profile == 0x2A)
|
|
fprintf (stderr,"- you have the option to re-run %s with:\n"
|
|
" -lead-out to elicit lead-out relocation for better\n"
|
|
" DVD-ROM compatibility, data is not affected;\n"
|
|
" -force to enforce new format (not recommended)\n"
|
|
" and wipe the data.\n",
|
|
argv[0]);
|
|
else if (mmc_profile == 0x12)
|
|
fprintf (stderr,"- you have the option to re-run %s with:\n"
|
|
" -format=full to perform full (lengthy) reformat;\n"
|
|
" -ssa[=none|default|max]\n"
|
|
" to grow, eliminate, reset to default or\n"
|
|
" maximize Supplementary Spare Area.\n",
|
|
argv[0]);
|
|
else
|
|
{ fprintf (stderr,"- you have the option to re-run %s with:\n",
|
|
argv[0]);
|
|
if (i) fprintf (stderr,
|
|
" -force[=full] to enforce new format or mode transition\n"
|
|
" and wipe the data;\n");
|
|
fprintf (stderr," -blank[=full] to change to Sequential mode.\n");
|
|
}
|
|
exit (0);
|
|
}
|
|
else if (cmd.umount())
|
|
perror (errno==EBUSY ? ":-( unable to proceed with format" :
|
|
":-( unable to umount"),
|
|
exit (1);
|
|
}
|
|
else
|
|
{ if (mmc_profile==0x14 && blank==0 && !force)
|
|
{ fprintf (stderr,"- media is blank\n");
|
|
fprintf (stderr,"- given the time to apply full blanking procedure I've chosen\n"
|
|
" to insist on -force option upon mode transition.\n");
|
|
exit (0);
|
|
}
|
|
force = 0;
|
|
}
|
|
|
|
if (((mmc_profile == 0x1A || mmc_profile == 0x2A) && blank)
|
|
|| (mmc_profile != 0x1A && compat)
|
|
|| (mmc_profile != 0x12 && ssa) )
|
|
{ fprintf (stderr,"- illegal command-line option for this media.\n");
|
|
goto offer_options;
|
|
}
|
|
else if ((mmc_profile == 0x1A || mmc_profile == 0x2A) && full)
|
|
{ fprintf (stderr,"- unimplemented command-line option for this media.\n");
|
|
goto offer_options;
|
|
}
|
|
|
|
#if defined(__unix) || defined(__unix__)
|
|
{ int fd;
|
|
char *s;
|
|
|
|
if ((fd=mkstemp (s=strdup("/tmp/dvd+rw.XXXXXX"))) < 0)
|
|
fprintf (stderr,":-( unable to mkstemp(\"%s\")",s),
|
|
exit(1);
|
|
|
|
ftruncate(fd,sizeof(*progress));
|
|
unlink(s);
|
|
|
|
progress = (int *)mmap(NULL,sizeof(*progress),PROT_READ|PROT_WRITE,
|
|
MAP_SHARED,fd,0);
|
|
close (fd);
|
|
if (progress == MAP_FAILED)
|
|
perror (":-( unable to mmap anonymously"),
|
|
exit(1);
|
|
}
|
|
*progress = 0;
|
|
|
|
if ((pid=fork()) == (pid_t)-1)
|
|
perror (":-( unable to fork()"),
|
|
exit(1);
|
|
|
|
if (pid)
|
|
{ struct sigaction sa;
|
|
const char *str;
|
|
|
|
cmd.~Scsi_Command();
|
|
if (compat && force) str="relocating lead-out";
|
|
else if (blank) str="blanking";
|
|
else str="formatting";
|
|
if (gui) gui_action=str;
|
|
else fprintf (stderr,"* %s .",str);
|
|
|
|
sigaction (SIGALRM,NULL,&sa);
|
|
sa.sa_flags &= ~SA_RESETHAND;
|
|
sa.sa_flags |= SA_RESTART;
|
|
sa.sa_handler = alarm_handler;
|
|
sigaction (SIGALRM,&sa,NULL);
|
|
alarm(1);
|
|
while ((waitpid(pid,&i,0) != pid) && !WIFEXITED(i)) ;
|
|
if (WEXITSTATUS(i) == 0) fprintf (stderr,"\n");
|
|
exit (0);
|
|
}
|
|
|
|
/*
|
|
* You can suspend, terminate, etc. the parent. We will keep on
|
|
* working in background...
|
|
*/
|
|
setsid();
|
|
signal(SIGHUP,SIG_IGN);
|
|
signal(SIGINT,SIG_IGN);
|
|
signal(SIGTERM,SIG_IGN);
|
|
#else
|
|
if (compat && force) str="relocating lead-out";
|
|
else if (blank) str="blanking";
|
|
else str="formatting";
|
|
if (gui) gui_action=str;
|
|
else fprintf (stderr,"* %s .",str);
|
|
#endif
|
|
|
|
*progress = 1;
|
|
|
|
// formats[i] becomes "Format Unit Parameter List"
|
|
formats[i+0] = 0; // "Reserved"
|
|
formats[i+1] = 2; // "IMMED" flag
|
|
formats[i+2] = 0; // "Descriptor Length" (MSB)
|
|
formats[i+3] = 8; // "Descriptor Length" (LSB)
|
|
|
|
handle_events(cmd);
|
|
|
|
if (mmc_profile==0x1A || mmc_profile==0x2A) // DVD+RW
|
|
{ if (compat && force && (dinfo[2]&3))
|
|
formats[i+4+0]=formats[i+4+1]=formats[i+4+2]=formats[i+4+3]=0,
|
|
formats[i+4+7] = 1; // "Restart format"
|
|
|
|
cmd[0] = 0x04; // FORMAT UNIT
|
|
cmd[1] = 0x11; // "FmtData" and "Format Code"
|
|
cmd[5] = 0;
|
|
if ((err=cmd.transport(WRITE,formats+i,12)))
|
|
sperror ("FORMAT UNIT",err), exit(1);
|
|
|
|
if (wait_for_unit (cmd,progress)) exit (1);
|
|
|
|
if (!compat)
|
|
{ cmd[0] = 0x5B; // CLOSE TRACK/SESSION
|
|
cmd[1] = 1; // "IMMED" flag on
|
|
cmd[2] = 0; // "Stop De-Icing"
|
|
cmd[9] = 0;
|
|
if ((err=cmd.transport()))
|
|
sperror ("STOP DE-ICING",err), exit(1);
|
|
|
|
if (wait_for_unit (cmd,progress)) exit (1);
|
|
}
|
|
|
|
cmd[0] = 0x5B; // CLOSE TRACK/SESSION
|
|
cmd[1] = 1; // "IMMED" flag on
|
|
cmd[2] = 2; // "Close Session"
|
|
cmd[9] = 0;
|
|
if ((err=cmd.transport()))
|
|
sperror ("CLOSE SESSION",err), exit(1);
|
|
|
|
if (wait_for_unit (cmd,progress)) exit (1);
|
|
}
|
|
else if (mmc_profile==0x12) // DVD-RAM
|
|
{ cmd[0] = 0x04; // FORMAT UNIT
|
|
if ((formats[i+4+4]>>2) == 0x01)
|
|
formats[i+1] = 0,
|
|
cmd[1] = 0x11; // "FmtData"|"Format Code"
|
|
else if (full)
|
|
formats[i+1] = 0x82,// "FOV"|"IMMED"
|
|
cmd[1] = 0x11; // "FmtData"|"Format Code"
|
|
else
|
|
formats[i+1] = 0xA2,// "FOV"|"DCRT"|"IMMED"
|
|
cmd[1] = 0x19; // "FmtData"|"CmpLst"|"Format Code"
|
|
cmd[5] = 0;
|
|
if ((err=cmd.transport(WRITE,formats+i,12)))
|
|
sperror ("FORMAT UNIT",err), exit(1);
|
|
|
|
if (wait_for_unit (cmd,progress)) exit(1);
|
|
}
|
|
else // DVD-RW
|
|
{ page05_setup (cmd,mmc_profile);
|
|
|
|
if (do_opc)
|
|
{ cmd[0] = 0x54; // SEND OPC INFORMATION
|
|
cmd[1] = 1; // "Perform OPC"
|
|
cmd[9] = 0;
|
|
cmd.timeout(120); // NEC units can be slooo...w
|
|
if ((err=cmd.transport()))
|
|
{ if (err==0x17301) // "POWER CALIBRATION AREA ALMOST FULL"
|
|
fprintf (stderr,":-! WARNING: Power Calibration Area "
|
|
"is almost full\n");
|
|
else
|
|
{ sperror ("PERFORM OPC",err);
|
|
if ((err&0x0FF00)==0x07300) exit (1);
|
|
/* The rest of errors are ignored, see groisofs_mmc.cpp
|
|
* for further details... */
|
|
}
|
|
}
|
|
}
|
|
|
|
if (blank) // DVD-RW blanking procedure
|
|
{ cmd[0] = 0xA1; // BLANK
|
|
cmd[1] = blank;
|
|
cmd[11] = 0;
|
|
if ((err=cmd.transport()))
|
|
sperror ("BLANK",err), exit(1);
|
|
|
|
if (wait_for_unit (cmd,progress)) exit (1);
|
|
}
|
|
else // DVD-RW format
|
|
{ if ((formats[i+4+4]>>2)==0x15) // make it really quick
|
|
formats[i+4+0]=formats[i+4+1]=formats[i+4+2]=formats[i+4+3]=0;
|
|
|
|
cmd[0] = 0x04; // FORMAT UNIT
|
|
cmd[1] = 0x11; // "FmtData" and "Format Code"
|
|
cmd[5] = 0;
|
|
if ((err=cmd.transport(WRITE,formats+i,12)))
|
|
sperror ("FORMAT UNIT",err), exit(1);
|
|
|
|
if (wait_for_unit (cmd,progress)) exit (1);
|
|
|
|
cmd[0] = 0x35; // FLUSH CACHE
|
|
cmd[9] = 0;
|
|
cmd.transport ();
|
|
}
|
|
}
|
|
|
|
pioneer_stop (cmd,progress);
|
|
|
|
#if 0
|
|
cmd[0] = 0x1E; // ALLOW MEDIA REMOVAL
|
|
cmd[5] = 0;
|
|
if (cmd.transport ()) return 1;
|
|
|
|
cmd[0] = 0x1B; // START/STOP UNIT
|
|
cmd[4] = 0x2; // "Eject"
|
|
cmd[5] = 0;
|
|
if (cmd.transport()) return 1;
|
|
|
|
cmd[0] = 0x1B; // START/STOP UNIT
|
|
cmd[1] = 0x1; // "IMMED"
|
|
cmd[4] = 0x3; // "Load"
|
|
cmd[5] = 0;
|
|
cmd.transport ();
|
|
#endif
|
|
|
|
return 0;
|
|
}
|