303 lines
5.1 KiB
C
303 lines
5.1 KiB
C
#include "acd.h"
|
|
|
|
int
|
|
msfconv(Fmt *fp)
|
|
{
|
|
Msf m;
|
|
|
|
m = va_arg(fp->args, Msf);
|
|
fmtprint(fp, "%d.%d.%d", m.m, m.s, m.f);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
status(Drive *d)
|
|
{
|
|
uchar cmd[12];
|
|
|
|
memset(cmd, 0, sizeof cmd);
|
|
cmd[0] = 0xBD;
|
|
return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone);
|
|
}
|
|
|
|
static int
|
|
playmsf(Drive *d, Msf start, Msf end)
|
|
{
|
|
uchar cmd[12];
|
|
|
|
memset(cmd, 0, sizeof cmd);
|
|
cmd[0] = 0x47;
|
|
cmd[3] = start.m;
|
|
cmd[4] = start.s;
|
|
cmd[5] = start.f;
|
|
cmd[6] = end.m;
|
|
cmd[7] = end.s;
|
|
cmd[8] = end.f;
|
|
|
|
return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone);
|
|
}
|
|
|
|
int
|
|
playtrack(Drive *d, int start, int end)
|
|
{
|
|
Toc *t;
|
|
|
|
t = &d->toc;
|
|
|
|
if(t->ntrack == 0)
|
|
return -1;
|
|
|
|
if(start < 0)
|
|
start = 0;
|
|
if(end >= t->ntrack)
|
|
end = t->ntrack-1;
|
|
if(end < start)
|
|
end = start;
|
|
|
|
return playmsf(d, t->track[start].start, t->track[end].end);
|
|
}
|
|
|
|
int
|
|
resume(Drive *d)
|
|
{
|
|
uchar cmd[12];
|
|
|
|
memset(cmd, 0, sizeof cmd);
|
|
cmd[0] = 0x4B;
|
|
cmd[8] = 0x01;
|
|
return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone);
|
|
}
|
|
|
|
int
|
|
pause(Drive *d)
|
|
{
|
|
uchar cmd[12];
|
|
|
|
memset(cmd, 0, sizeof cmd);
|
|
cmd[0] = 0x4B;
|
|
return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone);
|
|
}
|
|
|
|
int
|
|
stop(Drive *d)
|
|
{
|
|
uchar cmd[12];
|
|
|
|
memset(cmd, 0, sizeof cmd);
|
|
cmd[0] = 0x4E;
|
|
return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone);
|
|
}
|
|
|
|
int
|
|
eject(Drive *d)
|
|
{
|
|
uchar cmd[12];
|
|
|
|
memset(cmd, 0, sizeof cmd);
|
|
cmd[0] = 0x1B;
|
|
cmd[1] = 1;
|
|
cmd[4] = 2;
|
|
return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone);
|
|
}
|
|
|
|
int
|
|
ingest(Drive *d)
|
|
{
|
|
uchar cmd[12];
|
|
|
|
memset(cmd, 0, sizeof cmd);
|
|
cmd[0] = 0x1B;
|
|
cmd[1] = 1;
|
|
cmd[4] = 3;
|
|
return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone);
|
|
}
|
|
|
|
static Msf
|
|
rdmsf(uchar *p)
|
|
{
|
|
Msf msf;
|
|
|
|
msf.m = p[0];
|
|
msf.s = p[1];
|
|
msf.f = p[2];
|
|
return msf;
|
|
}
|
|
|
|
static ulong
|
|
rdlba(uchar *p)
|
|
{
|
|
return (p[0]<<16) | (p[1]<<8) | p[2];
|
|
}
|
|
|
|
/* not a Drive, so that we don't accidentally touch Drive.toc */
|
|
int
|
|
gettoc(Scsi *s, Toc *t)
|
|
{
|
|
int i, n;
|
|
uchar cmd[12];
|
|
uchar resp[1024];
|
|
|
|
Again:
|
|
memset(t, 0, sizeof(*t));
|
|
memset(cmd, 0, sizeof cmd);
|
|
cmd[0] = 0x43;
|
|
cmd[1] = 0x02;
|
|
cmd[7] = sizeof(resp)>>8;
|
|
cmd[8] = sizeof(resp);
|
|
|
|
s->changetime = 1;
|
|
/* scsi sets nchange, changetime */
|
|
if(scsi(s, cmd, sizeof cmd, resp, sizeof(resp), Sread) < 4)
|
|
return -1;
|
|
|
|
if(s->changetime == 0) {
|
|
t->ntrack = 0;
|
|
werrstr("no media");
|
|
return -1;
|
|
}
|
|
|
|
if(t->nchange == s->nchange && t->changetime != 0)
|
|
return 0;
|
|
|
|
t->nchange = s->nchange;
|
|
t->changetime = s->changetime;
|
|
|
|
if(t->ntrack > MTRACK)
|
|
t->ntrack = MTRACK;
|
|
|
|
DPRINT(2, "%d %d\n", resp[3], resp[2]);
|
|
t->ntrack = resp[3]-resp[2]+1;
|
|
t->track0 = resp[2];
|
|
|
|
n = ((resp[0]<<8) | resp[1])+2;
|
|
if(n < 4+8*(t->ntrack+1)) {
|
|
werrstr("bad read0 %d %d", n, 4+8*(t->ntrack+1));
|
|
return -1;
|
|
}
|
|
|
|
for(i=0; i<=t->ntrack; i++) /* <=: track[ntrack] = end */
|
|
t->track[i].start = rdmsf(resp+4+i*8+5);
|
|
|
|
for(i=0; i<t->ntrack; i++)
|
|
t->track[i].end = t->track[i+1].start;
|
|
|
|
memset(cmd, 0, sizeof cmd);
|
|
cmd[0] = 0x43;
|
|
cmd[7] = sizeof(resp)>>8;
|
|
cmd[8] = sizeof(resp);
|
|
if(scsi(s, cmd, sizeof cmd, resp, sizeof(resp), Sread) < 4)
|
|
return -1;
|
|
|
|
if(s->changetime != t->changetime || s->nchange != t->nchange) {
|
|
fprint(2, "disk changed underfoot; repeating\n");
|
|
goto Again;
|
|
}
|
|
|
|
n = ((resp[0]<<8) | resp[1])+2;
|
|
if(n < 4+8*(t->ntrack+1)) {
|
|
werrstr("bad read");
|
|
return -1;
|
|
}
|
|
|
|
for(i=0; i<=t->ntrack; i++)
|
|
t->track[i].bstart = rdlba(resp+4+i*8+5);
|
|
|
|
for(i=0; i<t->ntrack; i++)
|
|
t->track[i].bend = t->track[i+1].bstart;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
dumptoc(Toc *t)
|
|
{
|
|
int i;
|
|
|
|
fprint(1, "%d tracks\n", t->ntrack);
|
|
for(i=0; i<t->ntrack; i++)
|
|
print("%d. %M-%M (%lud-%lud)\n", i+1,
|
|
t->track[i].start, t->track[i].end,
|
|
t->track[i].bstart, t->track[i].bend);
|
|
}
|
|
|
|
static void
|
|
ping(Drive *d)
|
|
{
|
|
uchar cmd[12];
|
|
|
|
memset(cmd, 0, sizeof cmd);
|
|
cmd[0] = 0x43;
|
|
scsi(d->scsi, cmd, sizeof(cmd), nil, 0, Snone);
|
|
}
|
|
|
|
static int
|
|
playstatus(Drive *d, Cdstatus *stat)
|
|
{
|
|
uchar cmd[12], resp[16];
|
|
|
|
memset(cmd, 0, sizeof cmd);
|
|
cmd[0] = 0x42;
|
|
cmd[1] = 0x02;
|
|
cmd[2] = 0x40;
|
|
cmd[3] = 0x01;
|
|
cmd[7] = sizeof(resp)>>8;
|
|
cmd[8] = sizeof(resp);
|
|
if(scsi(d->scsi, cmd, sizeof(cmd), resp, sizeof(resp), Sread) < 0)
|
|
return -1;
|
|
|
|
switch(resp[1]){
|
|
case 0x11:
|
|
stat->state = Splaying;
|
|
break;
|
|
case 0x12:
|
|
stat->state = Spaused;
|
|
break;
|
|
case 0x13:
|
|
stat->state = Scompleted;
|
|
break;
|
|
case 0x14:
|
|
stat->state = Serror;
|
|
break;
|
|
case 0x00: /* not supported */
|
|
case 0x15: /* no current status to return */
|
|
default:
|
|
stat->state = Sunknown;
|
|
break;
|
|
}
|
|
|
|
stat->track = resp[6];
|
|
stat->index = resp[7];
|
|
stat->abs = rdmsf(resp+9);
|
|
stat->rel = rdmsf(resp+13);
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
cdstatusproc(void *v)
|
|
{
|
|
Drive *d;
|
|
Toc t;
|
|
Cdstatus s;
|
|
|
|
t.changetime = ~0;
|
|
t.nchange = ~0;
|
|
|
|
threadsetname("cdstatusproc");
|
|
d = v;
|
|
DPRINT(2, "cdstatus %d\n", getpid());
|
|
for(;;) {
|
|
ping(d);
|
|
//DPRINT(2, "d %d %d t %d %d\n", d->scsi->changetime, d->scsi->nchange, t.changetime, t.nchange);
|
|
if(playstatus(d, &s) == 0)
|
|
send(d->cstatus, &s);
|
|
if(d->scsi->changetime != t.changetime || d->scsi->nchange != t.nchange) {
|
|
if(gettoc(d->scsi, &t) == 0) {
|
|
DPRINT(2, "sendtoc...\n");
|
|
if(debug) dumptoc(&t);
|
|
send(d->ctocdisp, &t);
|
|
} else
|
|
DPRINT(2, "error: %r\n");
|
|
}
|
|
sleep(1000);
|
|
}
|
|
}
|