cdfs: pull updates from sources
This commit is contained in:
parent
c7ad44a048
commit
9b5b68a302
|
@ -30,6 +30,17 @@ enum {
|
|||
TypeDisk,
|
||||
TypeBlank,
|
||||
|
||||
/* disc writability classes */
|
||||
Readonly = 0, /* -ROM */
|
||||
Write1, /* -R: write once only */
|
||||
Erasewrite, /* -R[WE]: erase then write */
|
||||
Ram, /* -RAM: read & write unrestricted */
|
||||
|
||||
/* tri-state flags */
|
||||
Unset = -1,
|
||||
No,
|
||||
Yes,
|
||||
|
||||
/* offsets in Pagcapmechsts mode page; see MMC-3 §5.5.10 */
|
||||
Capread = 2,
|
||||
Capwrite = 3,
|
||||
|
@ -129,11 +140,12 @@ enum {
|
|||
};
|
||||
|
||||
typedef struct Buf Buf;
|
||||
typedef struct Drive Drive;
|
||||
typedef struct Track Track;
|
||||
typedef struct Otrack Otrack;
|
||||
typedef struct Dev Dev;
|
||||
typedef struct Drive Drive;
|
||||
typedef struct Msf Msf; /* minute, second, frame */
|
||||
typedef struct Otrack Otrack;
|
||||
typedef struct Track Track;
|
||||
typedef schar Tristate;
|
||||
|
||||
struct Msf {
|
||||
int m;
|
||||
|
@ -196,23 +208,24 @@ struct Drive
|
|||
QLock;
|
||||
Scsi;
|
||||
|
||||
int type; /* scsi peripheral device type */
|
||||
int type; /* scsi peripheral device type: Type?? */
|
||||
|
||||
/* disc characteristics */
|
||||
int mmctype;
|
||||
char *dvdtype;
|
||||
int mmctype; /* cd, dvd, or bd */
|
||||
char *dvdtype; /* name of dvd flavour */
|
||||
int firsttrack;
|
||||
int invistrack;
|
||||
int ntrack;
|
||||
int nchange; /* compare with the members in Scsi */
|
||||
ulong changetime; /* " */
|
||||
int nameok;
|
||||
int writeok;
|
||||
int blank; /* (not used for anything yet) */
|
||||
int blankset;
|
||||
int recordable; /* writable by burning? */
|
||||
int recordableset;
|
||||
int erasable; /* rewritable? */
|
||||
int erasableset;
|
||||
int writeok; /* writable disc? */
|
||||
/*
|
||||
* we could combine these attributes into a single variable except
|
||||
* that we discover them separately sometimes.
|
||||
*/
|
||||
Tristate recordable; /* writable by burning? */
|
||||
Tristate erasable; /* writable after erasing? */
|
||||
|
||||
Track track[Ntrack];
|
||||
ulong cap; /* drive capabilities */
|
||||
|
|
|
@ -4,6 +4,7 @@ void bterm(Buf*);
|
|||
long bufread(Otrack*, void*, long, vlong);
|
||||
long bufwrite(Otrack*, void*, long);
|
||||
long bwrite(Buf*, void*, long);
|
||||
char* disctype(Drive *drive);
|
||||
void *emalloc(ulong);
|
||||
char* geterrstr(void);
|
||||
Drive* mmcprobe(Scsi*);
|
||||
|
|
|
@ -192,7 +192,7 @@ fsremove(Req *r)
|
|||
case Qwd:
|
||||
if(drive->fixate(drive) < 0)
|
||||
respond(r, geterrstr());
|
||||
// let us see if it can figure this out: drive->writeok = 0;
|
||||
// let us see if it can figure this out: drive->writeok = No;
|
||||
else
|
||||
respond(r, nil);
|
||||
checktoc(drive);
|
||||
|
@ -204,7 +204,7 @@ fsremove(Req *r)
|
|||
}
|
||||
|
||||
/* result is one word, so it can be used as a uid in Dir structs */
|
||||
static char *
|
||||
char *
|
||||
disctype(Drive *drive)
|
||||
{
|
||||
char *type, *rw;
|
||||
|
@ -229,9 +229,9 @@ disctype(Drive *drive)
|
|||
}
|
||||
rw = "";
|
||||
if (drive->mmctype != Mmcnone && drive->dvdtype == nil)
|
||||
if (drive->erasable)
|
||||
if (drive->erasable == Yes)
|
||||
rw = drive->mmctype == Mmcbd? "re": "rw";
|
||||
else if (drive->recordable)
|
||||
else if (drive->recordable == Yes)
|
||||
rw = "r";
|
||||
else
|
||||
rw = "rom";
|
||||
|
@ -271,7 +271,7 @@ fillstat(ulong qid, Dir *d)
|
|||
break;
|
||||
|
||||
case Qwa:
|
||||
if(drive->writeok == 0 ||
|
||||
if(drive->writeok == No ||
|
||||
drive->mmctype != Mmcnone &&
|
||||
drive->mmctype != Mmccd)
|
||||
return 0;
|
||||
|
@ -281,7 +281,7 @@ fillstat(ulong qid, Dir *d)
|
|||
break;
|
||||
|
||||
case Qwd:
|
||||
if(drive->writeok == 0)
|
||||
if(drive->writeok == No)
|
||||
return 0;
|
||||
d->name = "wd";
|
||||
d->qid.type = QTDIR;
|
||||
|
@ -340,6 +340,7 @@ static void
|
|||
readctl(Req *r)
|
||||
{
|
||||
int i, isaudio;
|
||||
ulong nwa;
|
||||
char *p, *e, *ty;
|
||||
char s[1024];
|
||||
Msf *m;
|
||||
|
@ -375,9 +376,14 @@ readctl(Req *r)
|
|||
ty = disctype(drive);
|
||||
p = seprint(p, e, "%s", ty);
|
||||
free(ty);
|
||||
if (drive->mmctype != Mmcnone)
|
||||
p = seprint(p, e, " next writable sector %lud",
|
||||
getnwa(drive));
|
||||
if (drive->mmctype != Mmcnone) {
|
||||
nwa = getnwa(drive);
|
||||
p = seprint(p, e, " next writable sector ");
|
||||
if (nwa == ~0ul)
|
||||
p = seprint(p, e, "none; disc full");
|
||||
else
|
||||
p = seprint(p, e, "%lud", nwa);
|
||||
}
|
||||
seprint(p, e, "\n");
|
||||
}
|
||||
readstr(r, s);
|
||||
|
@ -718,6 +724,7 @@ main(int argc, char **argv)
|
|||
if(dev == nil || mtpt == nil || argc > 0)
|
||||
usage();
|
||||
|
||||
werrstr("");
|
||||
if((s = openscsi(dev)) == nil)
|
||||
sysfatal("openscsi '%s': %r", dev);
|
||||
if((drive = mmcprobe(s)) == nil)
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
enum
|
||||
{
|
||||
Desperate = 0, /* non-zero grubs around in inquiry string */
|
||||
|
||||
Pagesz = 255,
|
||||
|
||||
Pagwrparams = 5, /* (cd|dvd)-r(w) device write parameters */
|
||||
|
@ -33,7 +35,7 @@ struct Mmcaux {
|
|||
int pagecmdsz;
|
||||
|
||||
/* disc characteristics */
|
||||
ulong mmcnwa;
|
||||
long mmcnwa; /* next writable address (block #) */
|
||||
int nropen;
|
||||
int nwopen;
|
||||
vlong ntotby;
|
||||
|
@ -60,6 +62,8 @@ static char *dvdtype[] = {
|
|||
"type-15-unknown",
|
||||
};
|
||||
|
||||
static int getinvistrack(Drive *drive);
|
||||
|
||||
static ulong
|
||||
bige(void *p)
|
||||
{
|
||||
|
@ -110,16 +114,6 @@ initcdb(uchar *cdb, int len, int cmd)
|
|||
cdb[0] = cmd;
|
||||
}
|
||||
|
||||
//static uchar *
|
||||
//newcdb(int len, int cmd)
|
||||
//{
|
||||
// uchar *cdb;
|
||||
//
|
||||
// cdb = emalloc(len);
|
||||
// cdb[0] = cmd;
|
||||
// return cdb;
|
||||
//}
|
||||
|
||||
/*
|
||||
* SCSI CDBs (cmd arrays) are 6, 10, 12, 16 or 32 bytes long.
|
||||
* The mode sense/select commands implicitly refer to
|
||||
|
@ -162,14 +156,9 @@ mmcgetpage10(Drive *drive, int page, void *v)
|
|||
uchar cmd[10], resp[512];
|
||||
int n, r;
|
||||
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
cmd[0] = ScmdMsense10;
|
||||
initcdb(cmd, sizeof cmd, ScmdMsense10);
|
||||
cmd[2] = page;
|
||||
cmd[8] = 255; /* allocation length: buffer size */
|
||||
|
||||
// print("get: sending cmd\n");
|
||||
// hexdump(cmd, 10);
|
||||
|
||||
n = scsi(drive, cmd, sizeof(cmd), resp, sizeof(resp), Sread);
|
||||
if(n < Mode10parmhdrlen)
|
||||
return -1;
|
||||
|
@ -183,12 +172,6 @@ mmcgetpage10(Drive *drive, int page, void *v)
|
|||
n = Pagesz;
|
||||
|
||||
memmove(v, &resp[Mode10parmhdrlen + r], n);
|
||||
|
||||
// print("get: got cmd\n");
|
||||
// hexdump(cmd, 10);
|
||||
// print("page\n");
|
||||
// hexdump(v, n);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
@ -198,8 +181,7 @@ mmcgetpage6(Drive *drive, int page, void *v)
|
|||
uchar cmd[6], resp[512];
|
||||
int n;
|
||||
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
cmd[0] = ScmdMsense6;
|
||||
initcdb(cmd, sizeof cmd, ScmdMsense6);
|
||||
cmd[2] = page;
|
||||
cmd[4] = 255; /* allocation length */
|
||||
|
||||
|
@ -234,8 +216,7 @@ mmcsetpage10(Drive *drive, int page, void *v)
|
|||
p[1] = len - 2;
|
||||
|
||||
/* set up CDB */
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
cmd[0] = ScmdMselect10;
|
||||
initcdb(cmd, sizeof cmd, ScmdMselect10);
|
||||
cmd[1] = 0x10; /* format not vendor-specific */
|
||||
cmd[8] = len;
|
||||
|
||||
|
@ -271,8 +252,7 @@ mmcsetpage6(Drive *drive, int page, void *v)
|
|||
p = emalloc(len);
|
||||
memmove(p + Mode6parmhdrlen, pagedata, pagedata[1]);
|
||||
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
cmd[0] = ScmdMselect6;
|
||||
initcdb(cmd, sizeof cmd, ScmdMselect6);
|
||||
cmd[1] = 0x10; /* format not vendor-specific */
|
||||
cmd[4] = len;
|
||||
|
||||
|
@ -388,11 +368,16 @@ mmcprobe(Scsi *scsi)
|
|||
|
||||
if (vflag)
|
||||
print("mmcprobe: inquiry: %s\n", scsi->inquire);
|
||||
|
||||
drive = emalloc(sizeof(Drive));
|
||||
drive->Scsi = *scsi;
|
||||
drive->Dev = mmcdev;
|
||||
drive->invistrack = -1;
|
||||
getinvistrack(drive);
|
||||
|
||||
aux = emalloc(sizeof(Mmcaux));
|
||||
drive->aux = aux;
|
||||
|
||||
scsiready(drive);
|
||||
drive->type = getdevtype(drive);
|
||||
if (drive->type != TypeCD) {
|
||||
|
@ -480,14 +465,14 @@ static int
|
|||
mmctrackinfo(Drive *drive, int t, int i)
|
||||
{
|
||||
int n, type, bs;
|
||||
long newnwa;
|
||||
ulong beg, size;
|
||||
uchar tmode;
|
||||
uchar cmd[10], resp[255];
|
||||
Mmcaux *aux;
|
||||
|
||||
aux = drive->aux;
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
cmd[0] = ScmdRtrackinfo;
|
||||
initcdb(cmd, sizeof cmd, ScmdRtrackinfo);
|
||||
cmd[1] = 1; /* address below is logical track # */
|
||||
cmd[2] = t>>24;
|
||||
cmd[3] = t>>16;
|
||||
|
@ -545,20 +530,32 @@ mmctrackinfo(Drive *drive, int t, int i)
|
|||
|
||||
if(resp[6] & (1<<6)) { /* blank? */
|
||||
drive->track[i].type = TypeBlank;
|
||||
drive->writeok = 1;
|
||||
drive->writeok = Yes;
|
||||
}
|
||||
|
||||
/*
|
||||
* figure out the first writable block, if we can
|
||||
*/
|
||||
if(vflag)
|
||||
print(" start %lud end %lud", beg, beg + size - 1);
|
||||
/* resp[6] & (1<<7) of zero: invisible track */
|
||||
/* t == getinvistrack(): invisible track */
|
||||
if(t == Invistrack || resp[7] & 1) { /* invis or nwa valid? */
|
||||
aux->mmcnwa = bige(&resp[12]);
|
||||
if ((long)aux->mmcnwa < 0) /* implausible? */
|
||||
aux->mmcnwa = 0;
|
||||
if (vflag)
|
||||
print(" nwa %lud", aux->mmcnwa);
|
||||
if(resp[7] & 1) { /* nwa valid? */
|
||||
newnwa = bige(&resp[12]);
|
||||
if (newnwa >= 0)
|
||||
if (aux->mmcnwa < 0)
|
||||
aux->mmcnwa = newnwa;
|
||||
else if (aux->mmcnwa != newnwa)
|
||||
fprint(2, "nwa is %ld but invis track starts blk %ld\n",
|
||||
newnwa, aux->mmcnwa);
|
||||
}
|
||||
/* resp[6] & (1<<7) of zero: invisible track */
|
||||
if(t == Invistrack || t == drive->invistrack)
|
||||
if (aux->mmcnwa < 0)
|
||||
aux->mmcnwa = beg;
|
||||
else if (aux->mmcnwa != beg)
|
||||
fprint(2, "invis track starts blk %ld but nwa is %ld\n",
|
||||
beg, aux->mmcnwa);
|
||||
if (vflag && aux->mmcnwa >= 0)
|
||||
print(" nwa %lud", aux->mmcnwa);
|
||||
if (vflag)
|
||||
print("\n");
|
||||
return 0;
|
||||
|
@ -570,8 +567,7 @@ mmcreadtoc(Drive *drive, int type, int track, void *data, int nbytes)
|
|||
{
|
||||
uchar cmd[10];
|
||||
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
cmd[0] = ScmdRTOC;
|
||||
initcdb(cmd, sizeof cmd, ScmdRTOC);
|
||||
cmd[1] = type; /* msf bit & reserved */
|
||||
cmd[2] = Tocfmttoc;
|
||||
cmd[6] = track; /* track/session */
|
||||
|
@ -586,26 +582,6 @@ mmcreadtoc(Drive *drive, int type, int track, void *data, int nbytes)
|
|||
return scsi(drive, cmd, sizeof(cmd), data, nbytes, Sread);
|
||||
}
|
||||
|
||||
static int
|
||||
mmcreaddiscinfo(Drive *drive, void *data, int nbytes)
|
||||
{
|
||||
uchar cmd[10];
|
||||
int n;
|
||||
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
cmd[0] = ScmdRdiscinfo;
|
||||
cmd[7] = nbytes>>8;
|
||||
cmd[8] = nbytes;
|
||||
n = scsi(drive, cmd, sizeof(cmd), data, nbytes, Sread);
|
||||
if(n < 24) {
|
||||
if(n >= 0)
|
||||
werrstr("rdiscinfo returns %d", n);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static Msf
|
||||
rdmsf(uchar *p)
|
||||
{
|
||||
|
@ -621,18 +597,104 @@ static int
|
|||
getdiscinfo(Drive *drive, uchar resp[], int resplen)
|
||||
{
|
||||
int n;
|
||||
uchar cmd[10];
|
||||
|
||||
n = mmcreaddiscinfo(drive, resp, resplen);
|
||||
if(n < 3) {
|
||||
if (vflag)
|
||||
initcdb(cmd, sizeof cmd, ScmdRdiscinfo);
|
||||
cmd[7] = resplen>>8;
|
||||
cmd[8] = resplen;
|
||||
n = scsi(drive, cmd, sizeof(cmd), resp, resplen, Sread);
|
||||
if(n < 24) {
|
||||
if(n >= 0)
|
||||
werrstr("rdiscinfo returns %d", n);
|
||||
else if (vflag)
|
||||
fprint(2, "read disc info failed\n");
|
||||
return n;
|
||||
return -1;
|
||||
}
|
||||
if (vflag)
|
||||
fprint(2, "read disc info succeeded\n");
|
||||
assert((resp[2] & 0340) == 0); /* data type 0 */
|
||||
drive->erasable = ((resp[2] & 0x10) != 0); /* -RW? */
|
||||
drive->erasableset = 1;
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
getconf(Drive *drive)
|
||||
{
|
||||
int n;
|
||||
ushort prof;
|
||||
ulong datalen;
|
||||
uchar cmd[10];
|
||||
uchar resp[2*1024]; /* 64k-8 ok, 2k often enough, 400 typical */
|
||||
|
||||
initcdb(cmd, sizeof cmd, Scmdgetconf);
|
||||
cmd[3] = 1; /* start with core feature */
|
||||
cmd[7] = sizeof resp >> 8;
|
||||
cmd[8] = sizeof resp;
|
||||
n = scsi(drive, cmd, sizeof(cmd), resp, sizeof resp, Sread);
|
||||
if (n < 0) {
|
||||
if(vflag)
|
||||
fprint(2, "get config cmd failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (n < 4)
|
||||
return -1;
|
||||
datalen = GETBELONG(resp+0);
|
||||
if (datalen < 8)
|
||||
return -1;
|
||||
/*
|
||||
* features start with an 8-byte header:
|
||||
* ulong datalen, ushort reserved, ushort current profile.
|
||||
* profile codes (table 92) are: 0 reserved, 1-7 legacy, 8-0xf cd,
|
||||
* 0x10-0x1f 0x2a-0x2b dvd*, 0x40-0x4f bd, 0x50-0x5f hd dvd,
|
||||
* 0xffff whacko.
|
||||
*
|
||||
* this is followed by multiple feature descriptors:
|
||||
* ushort code, uchar bits, uchar addnl_len, addnl_len bytes.
|
||||
*/
|
||||
prof = resp[6]<<8 | resp[7];
|
||||
if(prof == 0 || prof == 0xffff) /* none or whacko? */
|
||||
return n;
|
||||
if(drive->mmctype != Mmcnone)
|
||||
return n;
|
||||
switch (prof >> 4) {
|
||||
case 0:
|
||||
drive->mmctype = Mmccd;
|
||||
break;
|
||||
case 1:
|
||||
if (prof == 0x1a || prof == 0x1b)
|
||||
drive->mmctype = Mmcdvdplus;
|
||||
else
|
||||
drive->mmctype = Mmcdvdminus;
|
||||
break;
|
||||
case 2:
|
||||
drive->mmctype = Mmcdvdplus; /* dual layer */
|
||||
break;
|
||||
case 4:
|
||||
drive->mmctype = Mmcbd;
|
||||
/*
|
||||
* further decode prof to set writability flags.
|
||||
* mostly for Pioneer BDR-206M. there may be unnecessary
|
||||
* future profiles for dual, triple and quad layer;
|
||||
* let's hope not.
|
||||
*/
|
||||
switch (prof) {
|
||||
case 0x40:
|
||||
drive->erasable = drive->recordable = No;
|
||||
case 0x41:
|
||||
case 0x42:
|
||||
drive->erasable = No;
|
||||
drive->recordable = Yes;
|
||||
break;
|
||||
case 0x43:
|
||||
drive->erasable = Yes;
|
||||
drive->recordable = No;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
drive->mmctype = Mmcdvdminus; /* hd dvd, obs. */
|
||||
break;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
@ -648,11 +710,11 @@ getdvdstruct(Drive *drive)
|
|||
cmd[8] = sizeof resp >> 8; /* allocation length */
|
||||
cmd[9] = sizeof resp;
|
||||
n = scsi(drive, cmd, sizeof(cmd), resp, sizeof resp, Sread);
|
||||
if (n < 7)
|
||||
if (n < 7) {
|
||||
if(vflag)
|
||||
fprint(2, "read disc structure (dvd) cmd failed\n");
|
||||
return -1;
|
||||
|
||||
// print("dvd structure:\n");
|
||||
// hexdump(resp, n);
|
||||
}
|
||||
|
||||
/* resp[0..1] is resp length */
|
||||
cat = (resp[4] & 0xf0) >> 4; /* disk category, MMC-6 §6.22.3.2.1 */
|
||||
|
@ -660,65 +722,115 @@ getdvdstruct(Drive *drive)
|
|||
fprint(2, "dvd type is %s\n", dvdtype[cat]);
|
||||
drive->dvdtype = dvdtype[cat];
|
||||
/* write parameters mode page may suffice to compute writeok for dvd */
|
||||
drive->erasable = drive->recordable = 0;
|
||||
drive->erasable = drive->recordable = No;
|
||||
/*
|
||||
* the layer-type field is a *bit array*,
|
||||
* though an enumeration of types would make more sense,
|
||||
* since the types are exclusive, not orthogonal.
|
||||
*/
|
||||
if (resp[6] & (1<<2)) /* rewritable? */
|
||||
drive->erasable = 1;
|
||||
drive->erasable = Yes;
|
||||
else if (resp[6] & (1<<1)) /* recordable once? */
|
||||
drive->recordable = 1;
|
||||
else { /* factory-pressed disk */
|
||||
drive->blank = 0;
|
||||
drive->blankset = 1;
|
||||
}
|
||||
drive->erasableset = drive->recordableset = 1;
|
||||
drive->recordable = Yes;
|
||||
/* else it's a factory-pressed disk */
|
||||
drive->mmctype = (cat >= 8? Mmcdvdplus: Mmcdvdminus);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ugly hack to divine device type from inquiry string as last resort.
|
||||
* mostly for Pioneer BDR-206M.
|
||||
*/
|
||||
static int
|
||||
bdguess(Drive *drive)
|
||||
{
|
||||
if (drive->mmctype == Mmcnone) {
|
||||
if (strstr(drive->Scsi.inquire, "BD") == nil)
|
||||
return -1;
|
||||
if (vflag)
|
||||
fprint(2, "drive probably a BD (from inquiry string)\n");
|
||||
drive->mmctype = Mmcbd;
|
||||
} else if (drive->mmctype == Mmcbd) {
|
||||
if (drive->erasable != Unset && drive->recordable != Unset)
|
||||
return 0;
|
||||
} else
|
||||
return -1;
|
||||
|
||||
drive->recordable = drive->writeok = No;
|
||||
if (strstr(drive->Scsi.inquire, "RW") != nil) {
|
||||
if (vflag)
|
||||
fprint(2, "drive probably a burner (from inquiry string)\n");
|
||||
drive->recordable = drive->writeok = Yes;
|
||||
if (drive->erasable == Unset) { /* set by getdiscinfo perhaps */
|
||||
drive->erasable = No; /* no way to tell, alas */
|
||||
if (vflag)
|
||||
fprint(2, "\tassuming -r not -rw\n");
|
||||
}
|
||||
} else {
|
||||
if (drive->erasable == Unset)
|
||||
drive->erasable = No;
|
||||
}
|
||||
if (drive->erasable == Yes)
|
||||
drive->recordable = No; /* mutually exclusive */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
getbdstruct(Drive *drive)
|
||||
{
|
||||
int n;
|
||||
uchar cmd[12], resp[4100];
|
||||
uchar cmd[12], resp[4+4096];
|
||||
uchar *di, *body;
|
||||
|
||||
initcdb(cmd, sizeof cmd, ScmdReadDVD); /* actually, read disc structure */
|
||||
cmd[1] = 1; /* media type: bd */
|
||||
/* cmd[6] is layer #, 0 is first */
|
||||
cmd[7] = 0; /* format code: disc info */
|
||||
cmd[8] = sizeof resp >> 8; /* allocation length */
|
||||
cmd[9] = sizeof resp;
|
||||
n = scsi(drive, cmd, sizeof(cmd), resp, sizeof resp, Sread);
|
||||
if(n < 0) {
|
||||
if(vflag)
|
||||
fprint(2, "read disc structure (bd) cmd failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* resp[0..1] is resp length.
|
||||
* resp[4+8..4+8+2] is bd type (disc type identifier):
|
||||
* BDO|BDW|BDR, MMC-6 §6.22.3.3.1. The above command should
|
||||
* resp[0..1] is resp length (4100); 2 & 3 are reserved.
|
||||
* there may be multiple disc info structs of 112 bytes each.
|
||||
* disc info (di) starts at 4. di[0..7] are header, followed by body.
|
||||
* body[0..2] is bd type (disc type identifier):
|
||||
* BDO|BDW|BDR, MMC-6 §6.22.3.3.1. The above scsi command should
|
||||
* fail on DVD drives, but some seem to ignore media type
|
||||
* and return successfully, so verify that it's a BD drive.
|
||||
*/
|
||||
if (n < 4+8+3 || resp[4+8] != 'B' || resp[4+8+1] != 'D')
|
||||
return -1;
|
||||
if (vflag)
|
||||
fprint(2, "read disc structure (bd) succeeded\n");
|
||||
drive->erasable = drive->recordable = 0;
|
||||
switch (resp[4+8+2]) {
|
||||
case 'O':
|
||||
drive->blank = 0;
|
||||
drive->blankset = 1;
|
||||
break;
|
||||
case 'R': /* Recordable */
|
||||
drive->recordable = 1;
|
||||
break;
|
||||
case 'W': /* reWritable */
|
||||
drive->erasable = 1;
|
||||
break;
|
||||
default:
|
||||
fprint(2, "%s: unknown bd type BD%c\n", argv0, resp[4+8+2]);
|
||||
di = resp + 4;
|
||||
body = di + 8;
|
||||
n -= 4 + 8;
|
||||
if (n < 3 || di[0] != 'D' || di[1] != 'I' ||
|
||||
body[0] != 'B' || body[1] != 'D') {
|
||||
if(vflag)
|
||||
fprint(2, "it's not a bd\n");
|
||||
return -1;
|
||||
}
|
||||
if (vflag)
|
||||
fprint(2, "read disc structure (bd) succeeded; di format %d\n",
|
||||
di[2]);
|
||||
|
||||
drive->erasable = drive->recordable = No;
|
||||
switch (body[2]) {
|
||||
case 'O': /* read-Only */
|
||||
break;
|
||||
case 'R': /* Recordable */
|
||||
drive->recordable = Yes;
|
||||
break;
|
||||
case 'W': /* reWritable */
|
||||
drive->erasable = Yes;
|
||||
break;
|
||||
default:
|
||||
fprint(2, "%s: unknown bd type BD%c\n", argv0, body[2]);
|
||||
return -1;
|
||||
}
|
||||
drive->erasableset = drive->recordableset = 1;
|
||||
drive->mmctype = Mmcbd;
|
||||
return 0;
|
||||
}
|
||||
|
@ -809,10 +921,11 @@ mmcgettoc(Drive *drive)
|
|||
drive->nameok = 0;
|
||||
drive->nchange = drive->Scsi.nchange;
|
||||
drive->changetime = drive->Scsi.changetime;
|
||||
drive->writeok = drive->erasable = drive->recordable = drive->blank = 0;
|
||||
drive->erasableset = drive->recordableset = drive->blankset = 0;
|
||||
drive->writeok = No;
|
||||
drive->erasable = drive->recordable = Unset;
|
||||
getinvistrack(drive);
|
||||
aux = drive->aux;
|
||||
aux->mmcnwa = 0;
|
||||
aux->mmcnwa = -1;
|
||||
aux->nropen = aux->nwopen = 0;
|
||||
aux->ntotby = aux->ntotbk = 0;
|
||||
|
||||
|
@ -822,7 +935,7 @@ mmcgettoc(Drive *drive)
|
|||
}
|
||||
|
||||
/*
|
||||
* TODO: set read ahead, MMC-6 §6.37, seems to control caching.
|
||||
* should set read ahead, MMC-6 §6.37, seems to control caching.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -830,8 +943,8 @@ mmcgettoc(Drive *drive)
|
|||
*/
|
||||
if((n = mmcreadtoc(drive, Msfbit, 0, resp, sizeof(resp))) < 4) {
|
||||
/*
|
||||
* on a blank disc in a cd-rw, use readdiscinfo
|
||||
* to find the track info.
|
||||
* it could be a blank disc. in case it's a blank disc in a
|
||||
* cd-rw drive, use readdiscinfo to try to find the track info.
|
||||
*/
|
||||
if(getdiscinfo(drive, resp, sizeof(resp)) < 7)
|
||||
return -1;
|
||||
|
@ -841,9 +954,8 @@ mmcgettoc(Drive *drive)
|
|||
first = resp[3];
|
||||
last = resp[6];
|
||||
if(vflag)
|
||||
print("blank disc %d %d\n", first, last);
|
||||
/* the assumption of blankness may be unwarranted */
|
||||
drive->writeok = drive->blank = drive->blankset = 1;
|
||||
print("tracks %d-%d\n", first, last);
|
||||
drive->writeok = Yes;
|
||||
} else {
|
||||
first = resp[2];
|
||||
last = resp[3];
|
||||
|
@ -858,26 +970,28 @@ mmcgettoc(Drive *drive)
|
|||
}
|
||||
}
|
||||
|
||||
/* deduce disc type */
|
||||
drive->mmctype = Mmcnone;
|
||||
drive->dvdtype = nil;
|
||||
getdvdstruct(drive);
|
||||
getconf(drive);
|
||||
getbdstruct(drive);
|
||||
if (Desperate)
|
||||
bdguess(drive);
|
||||
if (drive->mmctype == Mmcnone)
|
||||
drive->mmctype = Mmccd; /* by default */
|
||||
if (drive->recordable || drive->erasable)
|
||||
drive->writeok = 1;
|
||||
if (drive->recordable == Yes || drive->erasable == Yes)
|
||||
drive->writeok = Yes;
|
||||
|
||||
if (vflag) {
|
||||
fprint(2, "writeok %d", drive->writeok);
|
||||
/* drive->blank is never used and hard to figure out */
|
||||
// if (drive->blankset)
|
||||
// fprint(2, " blank %d", drive->blank);
|
||||
if (drive->recordableset)
|
||||
if (drive->recordable != Unset)
|
||||
fprint(2, " recordable %d", drive->recordable);
|
||||
if (drive->erasableset)
|
||||
if (drive->erasable != Unset)
|
||||
fprint(2, " erasable %d", drive->erasable);
|
||||
fprint(2, "\n");
|
||||
print("first %d last %d\n", first, last);
|
||||
fprint(2, "first %d last %d\n", first, last);
|
||||
fprint(2, "it's a %s disc.\n\n", disctype(drive)); /* leak */
|
||||
}
|
||||
|
||||
if(first == 0 && last == 0)
|
||||
|
@ -954,7 +1068,7 @@ mmcsetbs(Drive *drive, int bs)
|
|||
switch(bs){
|
||||
case BScdda:
|
||||
/* 2 audio channels without pre-emphasis */
|
||||
settrkmode(p, Tmcdda); /* TODO: should be Tm2audio? */
|
||||
settrkmode(p, Tmcdda); /* should be Tm2audio? */
|
||||
p[Wpdatblktype] = Dbraw;
|
||||
break;
|
||||
case BScdrom:
|
||||
|
@ -1023,9 +1137,8 @@ mmcread(Buf *buf, void *v, long nblock, ulong off)
|
|||
* a cd drive with a cd in it and we're not reading data
|
||||
* (e.g., reading audio).
|
||||
*/
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
if (drive->type == TypeCD && drive->mmctype == Mmccd && bs != BScdrom) {
|
||||
cmd[0] = ScmdReadcd;
|
||||
initcdb(cmd, sizeof cmd, ScmdReadcd);
|
||||
cmd[2] = off>>24;
|
||||
cmd[3] = off>>16;
|
||||
cmd[4] = off>>8;
|
||||
|
@ -1049,7 +1162,7 @@ mmcread(Buf *buf, void *v, long nblock, ulong off)
|
|||
return -1;
|
||||
}
|
||||
} else { /* e.g., TypeDA */
|
||||
cmd[0] = ScmdRead12;
|
||||
initcdb(cmd, sizeof cmd, ScmdRead12);
|
||||
cmd[2] = off>>24;
|
||||
cmd[3] = off>>16;
|
||||
cmd[4] = off>>8;
|
||||
|
@ -1111,7 +1224,7 @@ format(Drive *drive)
|
|||
uchar *fmtdesc;
|
||||
uchar cmd[6], parms[4+8];
|
||||
|
||||
if (drive->recordable && drive->mmctype != Mmcbd) {
|
||||
if (drive->recordable == Yes && drive->mmctype != Mmcbd) {
|
||||
werrstr("don't format write-once cd or dvd media");
|
||||
return -1;
|
||||
}
|
||||
|
@ -1154,20 +1267,20 @@ format(Drive *drive)
|
|||
static long
|
||||
mmcxwrite(Otrack *o, void *v, long nblk)
|
||||
{
|
||||
int r;
|
||||
uchar cmd[10];
|
||||
Mmcaux *aux;
|
||||
|
||||
assert(o->omode == OWRITE);
|
||||
aux = o->drive->aux;
|
||||
if (aux->mmcnwa == 0 && scsiready(o->drive) < 0) {
|
||||
if (aux->mmcnwa == -1 && scsiready(o->drive) < 0) {
|
||||
werrstr("device not ready to write");
|
||||
return -1;
|
||||
}
|
||||
aux->ntotby += nblk*o->track->bs;
|
||||
aux->ntotbk += nblk;
|
||||
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
cmd[0] = ScmdExtwrite; /* write (10) */
|
||||
initcdb(cmd, sizeof cmd, ScmdExtwrite); /* write (10) */
|
||||
cmd[2] = aux->mmcnwa>>24;
|
||||
cmd[3] = aux->mmcnwa>>16;
|
||||
cmd[4] = aux->mmcnwa>>8;
|
||||
|
@ -1177,8 +1290,14 @@ mmcxwrite(Otrack *o, void *v, long nblk)
|
|||
if(vflag)
|
||||
print("%lld ns: write %ld at 0x%lux\n",
|
||||
nsec(), nblk, aux->mmcnwa);
|
||||
r = scsi(o->drive, cmd, sizeof(cmd), v, nblk*o->track->bs, Swrite);
|
||||
if (r < 0)
|
||||
fprint(2, "%s: write error at blk offset %,ld = "
|
||||
"offset %,lld / bs %ld: %r\n",
|
||||
argv0, aux->mmcnwa, (vlong)aux->mmcnwa * o->track->bs,
|
||||
o->track->bs);
|
||||
aux->mmcnwa += nblk;
|
||||
return scsi(o->drive, cmd, sizeof(cmd), v, nblk*o->track->bs, Swrite);
|
||||
return r;
|
||||
}
|
||||
|
||||
static long
|
||||
|
@ -1241,13 +1360,14 @@ getinvistrack(Drive *drive)
|
|||
if(vflag)
|
||||
print("getinvistrack: track #%d session #%d\n",
|
||||
resp[2], resp[3]);
|
||||
drive->invistrack = resp[2];
|
||||
return resp[2];
|
||||
}
|
||||
|
||||
static Otrack*
|
||||
mmccreate(Drive *drive, int type)
|
||||
{
|
||||
int bs, invis;
|
||||
int bs;
|
||||
Mmcaux *aux;
|
||||
Track *t;
|
||||
Otrack *o;
|
||||
|
@ -1271,15 +1391,11 @@ mmccreate(Drive *drive, int type)
|
|||
return nil;
|
||||
}
|
||||
|
||||
invis = getinvistrack(drive);
|
||||
if (invis < 0)
|
||||
invis = Invistrack;
|
||||
|
||||
/* comment out the returns for now; it should be no big deal - geoff */
|
||||
if(mmctrackinfo(drive, invis, Maxtrack)) {
|
||||
if(mmctrackinfo(drive, drive->invistrack, Maxtrack)) {
|
||||
if (vflag)
|
||||
fprint(2, "mmccreate: mmctrackinfo for invis track %d"
|
||||
" failed: %r\n", invis);
|
||||
" failed: %r\n", drive->invistrack);
|
||||
werrstr("disc not writable");
|
||||
// return nil;
|
||||
}
|
||||
|
@ -1287,20 +1403,20 @@ mmccreate(Drive *drive, int type)
|
|||
werrstr("cannot set bs mode");
|
||||
// return nil;
|
||||
}
|
||||
if(mmctrackinfo(drive, invis, Maxtrack)) {
|
||||
if(mmctrackinfo(drive, drive->invistrack, Maxtrack)) {
|
||||
if (vflag)
|
||||
fprint(2, "mmccreate: mmctrackinfo for invis track %d"
|
||||
" (2) failed: %r\n", invis);
|
||||
" (2) failed: %r\n", drive->invistrack);
|
||||
werrstr("disc not writable 2");
|
||||
// return nil;
|
||||
}
|
||||
|
||||
/* special hack for dvd-r: reserve the invisible track */
|
||||
if (drive->mmctype == Mmcdvdminus && drive->writeok &&
|
||||
drive->recordable && reserve(drive, invis) < 0) {
|
||||
drive->recordable == Yes && reserve(drive, drive->invistrack) < 0) {
|
||||
if (vflag)
|
||||
fprint(2, "mmcreate: reserving track %d for dvd-r "
|
||||
"failed: %r\n", invis);
|
||||
"failed: %r\n", drive->invistrack);
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
@ -1339,8 +1455,7 @@ mmcxclose(Drive *drive, int clf, int trackno)
|
|||
{
|
||||
uchar cmd[10];
|
||||
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
cmd[0] = ScmdClosetracksess;
|
||||
initcdb(cmd, sizeof cmd, ScmdClosetracksess);
|
||||
/* cmd[1] & 1 is the immediate bit */
|
||||
cmd[2] = clf; /* close function */
|
||||
if(clf == Closetrack)
|
||||
|
@ -1352,7 +1467,6 @@ mmcxclose(Drive *drive, int clf, int trackno)
|
|||
void
|
||||
mmcsynccache(Drive *drive)
|
||||
{
|
||||
int invis;
|
||||
uchar cmd[10];
|
||||
Mmcaux *aux;
|
||||
|
||||
|
@ -1364,7 +1478,7 @@ mmcsynccache(Drive *drive)
|
|||
if (vflag) {
|
||||
fprint(2, "syncing cache");
|
||||
if (drive->mmctype == Mmcdvdminus && drive->writeok &&
|
||||
drive->recordable)
|
||||
drive->recordable == Yes)
|
||||
fprint(2, "; dvd-r burning rest of track reservation, "
|
||||
"will be slow");
|
||||
fprint(2, "\n");
|
||||
|
@ -1376,21 +1490,19 @@ mmcsynccache(Drive *drive)
|
|||
aux->ntotby, aux->ntotbk, aux->mmcnwa);
|
||||
}
|
||||
|
||||
invis = getinvistrack(drive);
|
||||
if (invis < 0)
|
||||
invis = Invistrack;
|
||||
/*
|
||||
* rsc: seems not to work on some drives.
|
||||
* so ignore return code & don't issue on dvd+rw.
|
||||
*/
|
||||
if(drive->mmctype != Mmcdvdplus || !drive->erasable) {
|
||||
if(drive->mmctype != Mmcdvdplus || drive->erasable == No) {
|
||||
if (vflag)
|
||||
fprint(2, "closing invisible track %d (not dvd+rw)...\n",
|
||||
invis);
|
||||
mmcxclose(drive, Closetrack, invis);
|
||||
drive->invistrack);
|
||||
mmcxclose(drive, Closetrack, drive->invistrack);
|
||||
if (vflag)
|
||||
fprint(2, "... done.\n");
|
||||
}
|
||||
getinvistrack(drive); /* track # has probably changed */
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1445,7 +1557,7 @@ mmcfixate(Drive *drive)
|
|||
setonesess(drive);
|
||||
|
||||
/* skip explicit close session on bd-r */
|
||||
if (drive->mmctype != Mmcbd || drive->erasable) {
|
||||
if (drive->mmctype != Mmcbd || drive->erasable == Yes) {
|
||||
if (vflag)
|
||||
fprint(2, "closing session and maybe finalizing...\n");
|
||||
r = mmcxclose(drive, Closesessfinal, 0);
|
||||
|
@ -1459,7 +1571,7 @@ mmcfixate(Drive *drive)
|
|||
* Closedvdrbdfinal closes & finalizes dvd+r and bd-r.
|
||||
*/
|
||||
if ((drive->mmctype == Mmcdvdplus || drive->mmctype == Mmcbd) &&
|
||||
!drive->erasable) {
|
||||
drive->erasable == No) {
|
||||
if (vflag)
|
||||
fprint(2, "finalizing dvd+r or bd-r... "
|
||||
"(won't print `done').\n");
|
||||
|
@ -1475,8 +1587,7 @@ mmcblank(Drive *drive, int quick)
|
|||
|
||||
drive->nchange = -1; /* force reread toc */
|
||||
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
cmd[0] = ScmdBlank; /* blank cd-rw media */
|
||||
initcdb(cmd, sizeof cmd, ScmdBlank); /* blank cd-rw media */
|
||||
/* immediate bit is 0x10 */
|
||||
/* cmd[1] = 0 means blank the whole disc; = 1 just the header */
|
||||
cmd[1] = quick ? 0x01 : 0x00;
|
||||
|
@ -1519,8 +1630,7 @@ mmcsetspeed(Drive *drive, int r, int w)
|
|||
char *rv;
|
||||
uchar cmd[12];
|
||||
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
cmd[0] = ScmdSetcdspeed;
|
||||
initcdb(cmd, sizeof cmd, ScmdSetcdspeed);
|
||||
cmd[2] = r>>8;
|
||||
cmd[3] = r;
|
||||
cmd[4] = w>>8;
|
||||
|
|
Loading…
Reference in a new issue