#if 0
#
# Utility for manipulating Book Type Field of Physical Format Descriptor
# located in lead-in of DVD+RW media. This is 4th version. 2nd version
# added initial support for 2nd generation DVD+RW drives. 3rd version
# adds support for DVD+R unit settings. 4th version checks if the unit
# is of RICOH design and reliably recognizes drive generation.
#
# The code is in public domain.
#
# See http://www.dvdplusrw.org/resources/bitsettings.html
# for further details.
#
/bin/sh << EOS
MODNAME=\`expr "/$0" : '\(.*[^/]\)/*$' : '.*/\(..*\)' : '\(.*\)\..*$'\`
case "`uname -s`" in
SunOS)	(set -x; g++ -fno-exceptions -O -o \$MODNAME "$0" -lvolmgt) ;;
*)	(set -x; g++ -fno-exceptions -O -o \$MODNAME "$0") ;;
esac
EOS
exit
#endif

#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>

#include "transport.hxx"

int main(int argc,char *argv[])
{ Scsi_Command cmd;
  unsigned char page[20],*sense=cmd.sense(),realbook=0,book=0,action=0;
  char *dev,*brand="-*";
  unsigned short profile;
  int i,retries=1;

    for(dev=NULL,i=1;i<argc;i++)
    {	if	(!strncmp (argv[i],"-dvd-rom",7))   book=0x01, brand="-ROM";
	else if (!strncmp (argv[i],"-dvd+rw",7))    book=0x92, brand="+RW";
	else if (!strncmp (argv[i],"-dvd+r",6))     book=0xA1, brand="+R";
	else if (!strncmp (argv[i],"-inq",4))       book=0xFF, action=0x02;
	else if (!strncmp (argv[i],"-unit+rw",8))   action=0x04|0x08;
	else if (!strncmp (argv[i],"-unit+r",7))    action=0x14;
	else if (!strncmp (argv[i],"-unit",3))      action=0x01;
	else if (!strncmp (argv[i],"-media",3))     action=0x02;
	else					    dev=argv[i];
    }

    if (!(dev && book && action))
    {	fprintf (stderr,"Usage: %s "
			"[-dvd-rom-spec|-dvd+rw-spec|-dvd+r-spec|-inq] \\\n"
			"       [-media|-unit|-unit+rw|-unit+r] "
#if defined(_WIN32)
			"d:\n",argv[0]),
	fprintf (stderr,"For further information see http://"
			"www.dvdplusrw.org/resources/bitsettings.html\n");
#else
			"/dev/cdrom\n",argv[0]);
#endif
	return 1;
    }

    if (!cmd.associate(dev))
    {	fprintf (stderr,"%s: unable to open: ",dev), perror (NULL);
	return 1;
    }

    if (book!=0xFF || action!=0x02)	// Make sure it's a RICOH design
    {	cmd[0]=0x5A;
	cmd[2]=0x30;	// RICOH specific page
	cmd[8]=10;
	cmd[9]=0;
	if (cmd.transport(READ,page,10) || page[8] != 0x30)
	{   fprintf (stderr,"This program addresses units of RICOH design.\n"
			    "%s doesn't appear to be one. Exiting.\n",
			    dev);
	    return 1;
	}
    }

    cmd[0]=0x46;
    cmd[1]=2;
    cmd[8]=8;
    cmd[9]=0;
    if (cmd.transport(READ,page,8))
    {	if (sense[0]==0) perror("Unable to ioctl");
	else		 fprintf(stderr,"GET CONFIGURATION failed with "
					"SK=%xh/ASC=%02xh/ASCQ=%02xh\n",
					sense[2]&0xF,sense[12],sense[13]);
	return 1;
    }

    // See if it's 2 gen drive by checking if DVD+R profile is an option
    {	int len=4+(page[0]<<24|page[1]<<16|page[2]<<8|page[3]);
	if (len>264)
	{   fprintf (stderr,"insane profile list length [%d].\n",len);
	    return 1;
	}
	unsigned char *list=new unsigned char[len];

	cmd[0]=0x46;
	cmd[1]=2;
	cmd[7]=len>>8;
	cmd[8]=len;
	cmd[9]=0;
	if (cmd.transport(READ,list,len))
	{   fprintf(stderr,"GET CONFIGURATION failed with "
			   "SK=%xh/ASC=%02xh/ASCQ=%02xh\n",
			   sense[2]&0xF,sense[12],sense[13]);
	    return 1;
	}

	for (i=12;i<list[11];i+=4)
	    if ((list[i]<<8|list[i+1]) == 0x1B)
		break;

	if (i<list[11])		// 2nd gen drive
	{   if (action==0x02)	action|=0x04;		// -media
	    else if (action==0x01 && book!=0xFF)
				action=0x04|0x08;	// -unit+rw
	}
	else			// 1st gen drive
	{   if (action==0x14)
	    {	fprintf(stderr,"-unit+r is not applicable to this unit");
		return 1;
	    }
	    else if (action==(0x04|0x08))
	    	action=0x01;
	}
	delete list;
    }

    profile=page[6]<<8|page[7];

    switch (profile)
    {	case 0x1A:			// DVD+RW media mounted
	    realbook=0x92;
	    break;
	case 0x1B:			// DVD+R media mounted
	    if ((action&0x03)==0x02 && book!=0xFF)
	    {	fprintf (stderr,"Can't manipulate Book Type Field on DVD+R "
				"media, use -unit+r option\n");
		return 1;
	    }
	    realbook=0xA1;
	    break;
	default:
	    if (action&0x02 && book!=0xFF)
	    {	fprintf (stderr,"No DVD+RW media mounted\n");
		return 1;
	    }
	    realbook=0x92;		// defaults to DVD+RW
	    break;
    }

#if 0
    if (profile != 0x00)		// some media mounted
    {	// we can detect if it's 1st or 2nd gen unit
	cmd[0]=0xFA;
	cmd[1]=0x02;
	cmd[8]=6;
	cmd[9]=0;
	if (cmd.transport (READ,page,6))
	{   if (sense[0]&0x70 && sense[12]==0x24)   // 1st gen!
		if (action&0x04) action=0x01;
	}
    }
    else if (book!=0xFF)
    {	// If it's 2nd gen unit+rw command, fall down to 1st gen
	// command. Problem here is that 1st gen units seem to
	// accept 2nd gen commands [probably doing nothing] which
	// makes it impossible to tell the 1st gen unit from 2nd
	// gen. So I let 2nd gen unit reject 1 gen command in order
	// to tell them apart:-)
	if ((action&~0x08)==0x04) action=0x01;
    }
#endif

    if (book!=0xFF) while (retries--)
    {	if (action&0x02)		// media command, both versions
	{   if (book!=0x01 && book!=realbook)
	    {	fprintf (stderr,"Illegal Book Type for this media\n");
		return 1;
	    }
	}
	else if (action&0x04)		// 2nd gen unit command
	{   if (((action&~0x08)==0x14 && book==0x92) || 
		((action&~0x08)==0x04 && book==0xA1))
	    {	fprintf (stderr,"Illegal Book Type for this media\n");
		return 1;
	    }
	}
	else if (action==0x01)		// 1st gen unit command
	{   if (book!=0x01 && book!=0x92 && book!=realbook)
	    {	fprintf (stderr,"Illegal Book Type for this media\n");
		return 1;
	    }
	}

	cmd[0]=0xF9;
	cmd[1]=action;
	cmd[2]=book;
	cmd[3]=action&0x04?0xFF:0;
	cmd[9]=0;
	if (cmd.transport())
	{   //  vvvvvvv this is never true in 4th version or later
	    if (retries && sense[0]&0x70 && sense[12]==0x24) // wrong version?
	    {	if (action==0x01)	// ver 1 unit failed
		{   switch(realbook)
		    {	case 0x92:	action=0x04|0x08; break;
			case 0xA1:	action=0x14|0x08; break;
			default:	fprintf (stderr,"No media mounted\n");
					return 1;
		    }
		}
		else if (action&0x04)	// ver 2 unit failed, never happens?
		    action=0x01, realbook=0x92;
		else			// ver 1 media failed
		    action|=0x04|0x08;
		continue;		// retry another version
	    }
	    else
	    {	fprintf (stderr,"VENDOR_F9h[%02xh] failed with "
				"SK=%xh/ASC=%02xh/ASCQ=%02xh\n",
				action,
				sense[2]&0xF,sense[12],sense[13]);
		return 1;
	    }
	}
	else if (action==0x01)          // ver 1 unit succeeded
	{   printf ("The unit was instructed to format "
		    "DVD%s compliant media\n",brand);
	    return 0;
	}
	else break;
    }

    if (action&0x02)			// media settings
    {	cmd[0]=0xAD;
	cmd[9]=sizeof(page);
	cmd[11]=0;
	if (cmd.transport(READ,page,sizeof(page)))
	{   fprintf (stderr,"READ DVD STRUCTURE failed with "
			    "SK=%xh/ASC=%02xh/ASCQ=%02xh\n",
			    sense[2]&0xF,sense[12],sense[13]);
	    return 1;
	}

	book=page[4];
	switch(book&0xF0)
	{   case 0x00:	brand="-ROM";	break;
	    case 0x10:	brand="-RAM";	break;
	    case 0x20:	brand="-R";	break;
	    case 0x30:	brand="-RW";	break;
	    case 0x90:	brand="+RW";	break;
	    case 0xA0:	brand="+R";	break;
	    default:	brand=NULL;	break;
	}
	printf ("Current media Book Type Field is %02xh: ",book);
	if (brand)  printf ("DVD%s specification [revision %d]\n",
			    brand,book&0xF);
	else	    printf ("unrecognized value\n");
    }
    else				// unit settings
    {	i=0;

	if ((action&~0x08)!=0x14)
	{   cmd[0]=0xFA;
	    cmd[1]=0x00;		// DVD+RW unit settings
	    cmd[8]=6;
	    cmd[9]=0;
	    if (!cmd.transport(READ,page,6))
		printf ("The unit will format DVD+RW media as DVD%s\n",
			page[4]&0xF0?"+RW":"-ROM"), i++;
	}

	if ((action&~0x08)!=0x04)
	{   cmd[0]=0xFA;
	    cmd[1]=0x10;		// DVD+R unit settings
	    cmd[8]=6;
	    cmd[9]=0;
	    if (!cmd.transport(READ,page,6))
		printf ("The unit will brand DVD+R media as DVD%s\n",
			page[4]&0xF0?"+R":"-ROM"), i++;
	}

	if (i==0)
	{   printf ("Unable to determine unit settings. "
		    "Default settings vary from\n"
		    "firmware to firmware. Set "
		    "explicitely to be certain.\n");
	    return 1;
	}
    }

  return 0;
}
