diff options
author | cinap_lenrek <cinap_lenrek@localhost> | 2011-04-14 17:27:24 +0000 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@localhost> | 2011-04-14 17:27:24 +0000 |
commit | a150899221a5badff9740703b754f901b4f52762 (patch) | |
tree | 3d6911874b0ee763e40490d04f56fc09d89ccfa6 /acme/bin/source/acd/mmc.c | |
parent | 71cfa9c637386ebe00fc6d1bf6215db6657559f4 (diff) | |
download | plan9front-a150899221a5badff9740703b754f901b4f52762.tar.xz |
fill /acme
Diffstat (limited to 'acme/bin/source/acd/mmc.c')
-rw-r--r-- | acme/bin/source/acd/mmc.c | 303 |
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); + } +} |