summaryrefslogtreecommitdiff
path: root/acme/bin/source/acd/mmc.c
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@localhost>2011-04-14 17:27:24 +0000
committercinap_lenrek <cinap_lenrek@localhost>2011-04-14 17:27:24 +0000
commita150899221a5badff9740703b754f901b4f52762 (patch)
tree3d6911874b0ee763e40490d04f56fc09d89ccfa6 /acme/bin/source/acd/mmc.c
parent71cfa9c637386ebe00fc6d1bf6215db6657559f4 (diff)
downloadplan9front-a150899221a5badff9740703b754f901b4f52762.tar.xz
fill /acme
Diffstat (limited to 'acme/bin/source/acd/mmc.c')
-rw-r--r--acme/bin/source/acd/mmc.c303
1 files changed, 303 insertions, 0 deletions
diff --git a/acme/bin/source/acd/mmc.c b/acme/bin/source/acd/mmc.c
new file mode 100644
index 000000000..0a466c488
--- /dev/null
+++ b/acme/bin/source/acd/mmc.c
@@ -0,0 +1,303 @@
+#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);
+ }
+}