Logo Search packages:      
Sourcecode: dvd+rw-tools version File versions  Download package

dvd+rw-format.cpp

/*
 * DVD±RW format 7.0 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;
 * 7.0:
 * - Blu-ray Disc support;
 * - Mac OS X 10>=2 support;
 */
#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|XXXm]] /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[])
{ unsigned char   formats[260],dinfo[32],inq[128];
  char            *dev=NULL,*p;
  unsigned int    capacity,lead_out,mmc_profile,err;
  int       len,i;
  int       force=0,full=0,compat=0,blank=0,ssa=0,do_opc=0,gui=0,
            blu_ray=0,not_pow=0;
#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;
#elif defined(__unix) || defined(__unix__)
  pid_t           pid;

    { int fd;
      char *s;

      if ((fd=mkstemp (s=strdup("/tmp/dvd+rw-format.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;

      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);
    }
#endif

    fprintf (stderr,"* BD/DVD%sRW/-RAM format utility by <appro@fy.chalmers.se>, "
                "version 7.0.\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] == 'p')     // -pow
          { not_pow=1;        // minus pow
          }
          else if (argv[i][1] == 's')     // -ssa|-spare
          { force=ssa=1;
            if ((p=strchr(argv[i],'=')))
            {   if (p[1]=='n')      ssa=-1;     // =none
                else if (p[3]=='n') ssa=1;      // =min
                else if (p[1]=='d') ssa=2;      // =default
                else if (p[3]=='x') ssa=3;      // =max
                else if (p[1]=='.' || (p[1]>='0' && p[1]<='9'))
                { char  *s=NULL;
                  double a=strtod(p+1,&s);

                  if (s)
                  {   if      (*s=='g' || *s=='G')    a *= 1e9;
                      else if (*s=='m' || *s=='M')    a *= 1e6;
                      else if (*s=='k' || *s=='K')    a *= 1e3;
                  }
                  ssa = (int)(a/2e3);     // amount of 2K
                }
                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]);

    Scsi_Command  cmd;

    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];

    blu_ray = ((mmc_profile&0xF0)==0x40);

    if (mmc_profile!=0x1A && mmc_profile!=0x2A
      && mmc_profile!=0x14 && mmc_profile!=0x13
      && mmc_profile!=0x12
      && !blu_ray)
      fprintf (stderr,":-( mounted media doesn't appear to be "
                  "DVD%sRW, DVD-RAM or Blu-ray\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 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;
          default:
            i=8;  // just grab the first descriptor?
            break;
      }
    }
    else if (mmc_profile==0x41)           // BD-R
    { unsigned int   max,min,cap;
      unsigned char *f;
      int j;

      switch (ssa)
      {   case -1:      // no spare -> nothing to do
          case 0:
            exit (0);
            break;
          case 1: // min spare <- max capacity
            i=len;
            for (max=0,j=8;j<len;j+=8)
            {   f = formats+4+j;
                if ((f[4]>>2) == 0x32)
                { cap = f[0]<<24|f[1]<<16|f[2]<<8|f[3];
                  if (max < cap) max=cap,i=j;
                }
            }
            break;
          case 2: // default ssa
            i=8;  // just grab first descriptor
            break;
          case 3: // max, ~10GB, is too big to trust user
            fprintf (stderr,"- -ssa=max is not supported for BD-R, "
                        "specify explicit size with -ssa=XXXG\n");
            exit (1);
          default:
            i=len;
            for (max=0,min=0xffffffff,j=8;j<len;j+=8)
            {   f = formats+4+j;
                if ((f[4]>>2) == 0x32)
                { cap = f[0]<<24|f[1]<<16|f[2]<<8|f[3];
                  if (max < cap) max=cap;
                  if (min > cap) min=cap;
                }
            }
            if (max==0) break;
 
            // for simplicity adjust spare size according to DL(!) rules
            ssa += 8192, ssa &= ~16383;   // i.e. in 32MB increments

            f = formats+4;
            capacity = f[0]<<24|f[1]<<16|f[2]<<8|f[3];

            cap = capacity - ssa;
            // place it within given boundaries
            if      (cap < min)     cap = min;
            else if (cap > max)     cap = max;

            i = 8;
            f = formats+4+i;
            f[0] = cap>>24;
            f[1] = cap>>16;
            f[2] = cap>>8;
            f[3] = cap;
            f[4] = 0x32<<2 | not_pow;
            f[5] = 0;
            f[6] = 0;
            f[7] = 0;
            break;
      }
      
      if (i<len)
      {   f = formats+4+i;
          f[4] &= ~3;         // it's either SRM+POW ...
          f[4] |= not_pow;    // ... or SRM-POW
      }
    }
    else if (mmc_profile==0x43)           // BD-RE
    { unsigned int   max,min,cap;
      unsigned char *f;
      int j;

      switch (ssa)
      {   case -1:      // no spare
            for (i=8;i<len;i+=8)    // look for descriptor 0x31
                if ((formats [4+i+4]>>2) == 0x31) break;
            break;
          case 0:
            i = 8;
            if ((formats[4+4]&3)==2)// same capacity for already formatted
            {   f = formats+4+i;
                memcpy (f,formats+4,4);
                f[4] = 0x30<<2;
                f[5] = 0;
                f[6] = 0;
                f[7] = 0;
            }
            break;
          case 1: // min spare <- max capacity
            i=len;
            for (max=0,j=8;j<len;j+=8)
            {   f = formats+4+j;
                if ((f[4]>>2) == 0x30)
                { cap = f[0]<<24|f[1]<<16|f[2]<<8|f[3];
                  if (max < cap) max=cap,i=j;
                }
            }
            break;
          case 2: // default ssa
            i=8;  // just grab first descriptor
            break;
          case 3: // max spare <- min capacity
            i=len;
            for (min=0xffffffff,j=8;j<len;j+=8)
            {   f = formats+4+j;
                if ((f[4]>>2) == 0x30)
                { cap=f[0]<<24|f[1]<<16|f[2]<<8|f[3];
                  if (min > cap) min=cap,i=j;
                }
            }
            break;
          default:
            i=len;
            capacity=0;
            for (max=0,min=0xffffffff,j=8;j<len;j+=8)
            {   f = formats+4+j;
                if ((f[4]>>2) == 0x30)
                { cap = f[0]<<24|f[1]<<16|f[2]<<8|f[3];
                  if (max < cap) max=cap;
                  if (min > cap) min=cap;
                }
                else if ((f[4]>>2) == 0x31)
                  capacity = f[0]<<24|f[1]<<16|f[2]<<8|f[3];
            }
            if (max==0 || capacity==0) break;
 
            // for simplicity adjust spare size according to DL(!) rules
            ssa += 8192, ssa &= ~16383;   // i.e. in 32MB increments

            cap = capacity - ssa;
            // place it within given boundaries
            if      (cap < min)     cap = min;
            else if (cap > max)     cap = max;

            i = 8;
            f = formats+4+i;
            f[0] = cap>>24;
            f[1] = cap>>16;
            f[2] = cap>>8;
            f[3] = cap;
            f[4] = 0x30<<2;
            f[5] = 0;
            f[6] = 0;
            f[7] = 0;
            break;
      }

      if (i<len)
      {   f = formats+4+i;
          f[4] &= ~3;
          if ((f[4]>>2)==0x30)
            f[4] |= full?2:3; // "Full" or "Quick Certification"
      }
    }
    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;
    if (blu_ray)
    { capacity |= formats[4+0], capacity <<= 8;
      capacity |= formats[4+1], capacity <<= 8;
      capacity |= formats[4+2], capacity <<= 8;
      capacity |= formats[4+3];
    }
    else
    { 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 if (blu_ray)                     // BD
      fprintf (stderr,"* %.1fGB BD 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 if (mmc_profile == 0x43)
            fprintf (stderr,"- you have the option to re-run %s with:\n"
                        "  -format=full  to perform (lengthy) Full Certification;\n"
                        "  -ssa[=none|default|max|XXX[GM]]\n"
                        "                to eliminate or adjust Spare Area.\n",
                        argv[0]);
          else if (blu_ray)   // BD-R
            fprintf (stderr,"- BD-R can be pre-formatted only once\n");
          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);
      }
      else if (mmc_profile==041 && !force)
      {   fprintf (stderr,"- media is blank\n");
          fprintf (stderr,"- as BD-R can be pre-formance only once, I've chosen\n"
                      "  to insist on -force option.\n");
      }
      force = 0;
    }

    if (((mmc_profile == 0x1A || mmc_profile == 0x2A) && blank)
      || (mmc_profile != 0x1A && compat)
      || (mmc_profile != 0x12 && mmc_profile != 0x43 && 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__)
    /*
     * 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);
#endif

    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);

    *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
      cmd[1] = 0x11;          // "FmtData"|"Format Code"
      cmd[5] = 0;
      formats[i+1] = 0x82;    // "FOV"|"IMMED"
      if ((formats[i+4+4]>>2) != 0x01 && !full)
          formats[i+1] |= 0x20,// |"DCRT"
          cmd[1] |= 0x08;     // |"CmpLst"
      if ((err=cmd.transport(WRITE,formats+i,12)))
          sperror ("FORMAT UNIT",err), exit(1);

      if (wait_for_unit (cmd,progress)) exit(1);
    }
    else if (mmc_profile==0x43)     // BD-RE
    { cmd[0] = 0x04;          // FORMAT UNIT
      cmd[1] = 0x11;          // "FmtData"|"Format Code"
      cmd[5] = 0;
      formats[i+1] = 0x82;    // "FOV"|"IMMED"
      if (full && (formats[i+4+4]>>2)!=0x31)
          formats[i+4+4] |= 2;// "Full Certificaton"
      else if ((formats[i+4+4]>>2)==0x30)
          formats[i+4+4] |= 3;// "Quick Certification"
      if ((err=cmd.transport(WRITE,formats+i,12)))
          sperror ("FORMAT UNIT",err), exit(1);

      if (wait_for_unit (cmd,progress)) exit(1);
    }
    else if (mmc_profile==0x41)     // BD-R
    { cmd[0] = 0x04;          // FORMAT UNIT
      cmd[1] = 0x11;          // "FmtData"|"Format Code"
      cmd[5] = 0;
      formats[i+1] = 0x2;     // IMMED"
      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;
}

Generated by  Doxygen 1.6.0   Back to index