xref: /plan9/acme/bin/source/acd/mmc.c (revision 3ff48bf5ed603850fcd251ddf13025d23d693782)
19a747e4fSDavid du Colombier #include "acd.h"
29a747e4fSDavid du Colombier 
39a747e4fSDavid du Colombier int
msfconv(Fmt * fp)4*3ff48bf5SDavid du Colombier msfconv(Fmt *fp)
59a747e4fSDavid du Colombier {
69a747e4fSDavid du Colombier 	Msf m;
79a747e4fSDavid du Colombier 
8*3ff48bf5SDavid du Colombier 	m = va_arg(fp->args, Msf);
9*3ff48bf5SDavid du Colombier 	fmtprint(fp, "%d.%d.%d", m.m, m.s, m.f);
109a747e4fSDavid du Colombier 	return 0;
119a747e4fSDavid du Colombier }
129a747e4fSDavid du Colombier 
139a747e4fSDavid du Colombier static int
status(Drive * d)149a747e4fSDavid du Colombier status(Drive *d)
159a747e4fSDavid du Colombier {
169a747e4fSDavid du Colombier 	uchar cmd[12];
179a747e4fSDavid du Colombier 
189a747e4fSDavid du Colombier 	memset(cmd, 0, sizeof cmd);
199a747e4fSDavid du Colombier 	cmd[0] = 0xBD;
209a747e4fSDavid du Colombier 	return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone);
219a747e4fSDavid du Colombier }
229a747e4fSDavid du Colombier 
239a747e4fSDavid du Colombier static int
playmsf(Drive * d,Msf start,Msf end)249a747e4fSDavid du Colombier playmsf(Drive *d, Msf start, Msf end)
259a747e4fSDavid du Colombier {
269a747e4fSDavid du Colombier 	uchar cmd[12];
279a747e4fSDavid du Colombier 
289a747e4fSDavid du Colombier 	memset(cmd, 0, sizeof cmd);
299a747e4fSDavid du Colombier 	cmd[0] = 0x47;
309a747e4fSDavid du Colombier 	cmd[3] = start.m;
319a747e4fSDavid du Colombier 	cmd[4] = start.s;
329a747e4fSDavid du Colombier 	cmd[5] = start.f;
339a747e4fSDavid du Colombier 	cmd[6] = end.m;
349a747e4fSDavid du Colombier 	cmd[7] = end.s;
359a747e4fSDavid du Colombier 	cmd[8] = end.f;
369a747e4fSDavid du Colombier 
379a747e4fSDavid du Colombier 	return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone);
389a747e4fSDavid du Colombier }
399a747e4fSDavid du Colombier 
409a747e4fSDavid du Colombier int
playtrack(Drive * d,int start,int end)419a747e4fSDavid du Colombier playtrack(Drive *d, int start, int end)
429a747e4fSDavid du Colombier {
439a747e4fSDavid du Colombier 	Toc *t;
449a747e4fSDavid du Colombier 
459a747e4fSDavid du Colombier 	t = &d->toc;
469a747e4fSDavid du Colombier 
479a747e4fSDavid du Colombier 	if(t->ntrack == 0)
489a747e4fSDavid du Colombier 		return -1;
499a747e4fSDavid du Colombier 
509a747e4fSDavid du Colombier 	if(start < 0)
519a747e4fSDavid du Colombier 		start = 0;
529a747e4fSDavid du Colombier 	if(end >= t->ntrack)
539a747e4fSDavid du Colombier 		end = t->ntrack-1;
549a747e4fSDavid du Colombier 	if(end < start)
559a747e4fSDavid du Colombier 		end = start;
569a747e4fSDavid du Colombier 
579a747e4fSDavid du Colombier 	return playmsf(d, t->track[start].start, t->track[end].end);
589a747e4fSDavid du Colombier }
599a747e4fSDavid du Colombier 
609a747e4fSDavid du Colombier int
resume(Drive * d)619a747e4fSDavid du Colombier resume(Drive *d)
629a747e4fSDavid du Colombier {
639a747e4fSDavid du Colombier 	uchar cmd[12];
649a747e4fSDavid du Colombier 
659a747e4fSDavid du Colombier 	memset(cmd, 0, sizeof cmd);
669a747e4fSDavid du Colombier 	cmd[0] = 0x4B;
679a747e4fSDavid du Colombier 	cmd[8] = 0x01;
689a747e4fSDavid du Colombier 	return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone);
699a747e4fSDavid du Colombier }
709a747e4fSDavid du Colombier 
719a747e4fSDavid du Colombier int
pause(Drive * d)729a747e4fSDavid du Colombier pause(Drive *d)
739a747e4fSDavid du Colombier {
749a747e4fSDavid du Colombier 	uchar cmd[12];
759a747e4fSDavid du Colombier 
769a747e4fSDavid du Colombier 	memset(cmd, 0, sizeof cmd);
779a747e4fSDavid du Colombier 	cmd[0] = 0x4B;
789a747e4fSDavid du Colombier 	return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone);
799a747e4fSDavid du Colombier }
809a747e4fSDavid du Colombier 
819a747e4fSDavid du Colombier int
stop(Drive * d)829a747e4fSDavid du Colombier stop(Drive *d)
839a747e4fSDavid du Colombier {
849a747e4fSDavid du Colombier 	uchar cmd[12];
859a747e4fSDavid du Colombier 
869a747e4fSDavid du Colombier 	memset(cmd, 0, sizeof cmd);
879a747e4fSDavid du Colombier 	cmd[0] = 0x4E;
889a747e4fSDavid du Colombier 	return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone);
899a747e4fSDavid du Colombier }
909a747e4fSDavid du Colombier 
919a747e4fSDavid du Colombier int
eject(Drive * d)929a747e4fSDavid du Colombier eject(Drive *d)
939a747e4fSDavid du Colombier {
949a747e4fSDavid du Colombier 	uchar cmd[12];
959a747e4fSDavid du Colombier 
969a747e4fSDavid du Colombier 	memset(cmd, 0, sizeof cmd);
979a747e4fSDavid du Colombier 	cmd[0] = 0x1B;
989a747e4fSDavid du Colombier 	cmd[1] = 1;
999a747e4fSDavid du Colombier 	cmd[4] = 2;
1009a747e4fSDavid du Colombier 	return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone);
1019a747e4fSDavid du Colombier }
1029a747e4fSDavid du Colombier 
1039a747e4fSDavid du Colombier int
ingest(Drive * d)1049a747e4fSDavid du Colombier ingest(Drive *d)
1059a747e4fSDavid du Colombier {
1069a747e4fSDavid du Colombier 	uchar cmd[12];
1079a747e4fSDavid du Colombier 
1089a747e4fSDavid du Colombier 	memset(cmd, 0, sizeof cmd);
1099a747e4fSDavid du Colombier 	cmd[0] = 0x1B;
1109a747e4fSDavid du Colombier 	cmd[1] = 1;
1119a747e4fSDavid du Colombier 	cmd[4] = 3;
1129a747e4fSDavid du Colombier 	return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone);
1139a747e4fSDavid du Colombier }
1149a747e4fSDavid du Colombier 
1159a747e4fSDavid du Colombier static Msf
rdmsf(uchar * p)1169a747e4fSDavid du Colombier rdmsf(uchar *p)
1179a747e4fSDavid du Colombier {
1189a747e4fSDavid du Colombier 	Msf msf;
1199a747e4fSDavid du Colombier 
1209a747e4fSDavid du Colombier 	msf.m = p[0];
1219a747e4fSDavid du Colombier 	msf.s = p[1];
1229a747e4fSDavid du Colombier 	msf.f = p[2];
1239a747e4fSDavid du Colombier 	return msf;
1249a747e4fSDavid du Colombier }
1259a747e4fSDavid du Colombier 
1269a747e4fSDavid du Colombier static ulong
rdlba(uchar * p)1279a747e4fSDavid du Colombier rdlba(uchar *p)
1289a747e4fSDavid du Colombier {
1299a747e4fSDavid du Colombier 	return (p[0]<<16) | (p[1]<<8) | p[2];
1309a747e4fSDavid du Colombier }
1319a747e4fSDavid du Colombier 
1329a747e4fSDavid du Colombier /* not a Drive, so that we don't accidentally touch Drive.toc */
1339a747e4fSDavid du Colombier int
gettoc(Scsi * s,Toc * t)1349a747e4fSDavid du Colombier gettoc(Scsi *s, Toc *t)
1359a747e4fSDavid du Colombier {
1369a747e4fSDavid du Colombier 	int i, n;
1379a747e4fSDavid du Colombier 	uchar cmd[12];
1389a747e4fSDavid du Colombier 	uchar resp[1024];
1399a747e4fSDavid du Colombier 
1409a747e4fSDavid du Colombier Again:
1419a747e4fSDavid du Colombier 	memset(t, 0, sizeof(*t));
1429a747e4fSDavid du Colombier 	memset(cmd, 0, sizeof cmd);
1439a747e4fSDavid du Colombier 	cmd[0] = 0x43;
1449a747e4fSDavid du Colombier 	cmd[1] = 0x02;
1459a747e4fSDavid du Colombier 	cmd[7] = sizeof(resp)>>8;
1469a747e4fSDavid du Colombier 	cmd[8] = sizeof(resp);
1479a747e4fSDavid du Colombier 
1489a747e4fSDavid du Colombier 	s->changetime = 1;
1499a747e4fSDavid du Colombier 	/* scsi sets nchange, changetime */
1509a747e4fSDavid du Colombier 	if(scsi(s, cmd, sizeof cmd, resp, sizeof(resp), Sread) < 4)
1519a747e4fSDavid du Colombier 		return -1;
1529a747e4fSDavid du Colombier 
1539a747e4fSDavid du Colombier 	if(s->changetime == 0) {
1549a747e4fSDavid du Colombier 		t->ntrack = 0;
1559a747e4fSDavid du Colombier 		werrstr("no media");
1569a747e4fSDavid du Colombier 		return -1;
1579a747e4fSDavid du Colombier 	}
1589a747e4fSDavid du Colombier 
1599a747e4fSDavid du Colombier 	if(t->nchange == s->nchange && t->changetime != 0)
1609a747e4fSDavid du Colombier 		return 0;
1619a747e4fSDavid du Colombier 
1629a747e4fSDavid du Colombier 	t->nchange = s->nchange;
1639a747e4fSDavid du Colombier 	t->changetime = s->changetime;
1649a747e4fSDavid du Colombier 
1659a747e4fSDavid du Colombier 	if(t->ntrack > MTRACK)
1669a747e4fSDavid du Colombier 		t->ntrack = MTRACK;
1679a747e4fSDavid du Colombier 
1689a747e4fSDavid du Colombier DPRINT(2, "%d %d\n", resp[3], resp[2]);
1699a747e4fSDavid du Colombier 	t->ntrack = resp[3]-resp[2]+1;
1709a747e4fSDavid du Colombier 	t->track0 = resp[2];
1719a747e4fSDavid du Colombier 
1729a747e4fSDavid du Colombier 	n = ((resp[0]<<8) | resp[1])+2;
1739a747e4fSDavid du Colombier 	if(n < 4+8*(t->ntrack+1)) {
1749a747e4fSDavid du Colombier 		werrstr("bad read0 %d %d", n, 4+8*(t->ntrack+1));
1759a747e4fSDavid du Colombier 		return -1;
1769a747e4fSDavid du Colombier 	}
1779a747e4fSDavid du Colombier 
1789a747e4fSDavid du Colombier 	for(i=0; i<=t->ntrack; i++)		/* <=: track[ntrack] = end */
1799a747e4fSDavid du Colombier 		t->track[i].start = rdmsf(resp+4+i*8+5);
1809a747e4fSDavid du Colombier 
1819a747e4fSDavid du Colombier 	for(i=0; i<t->ntrack; i++)
1829a747e4fSDavid du Colombier 		t->track[i].end = t->track[i+1].start;
1839a747e4fSDavid du Colombier 
1849a747e4fSDavid du Colombier 	memset(cmd, 0, sizeof cmd);
1859a747e4fSDavid du Colombier 	cmd[0] = 0x43;
1869a747e4fSDavid du Colombier 	cmd[7] = sizeof(resp)>>8;
1879a747e4fSDavid du Colombier 	cmd[8] = sizeof(resp);
1889a747e4fSDavid du Colombier 	if(scsi(s, cmd, sizeof cmd, resp, sizeof(resp), Sread) < 4)
1899a747e4fSDavid du Colombier 		return -1;
1909a747e4fSDavid du Colombier 
1919a747e4fSDavid du Colombier 	if(s->changetime != t->changetime || s->nchange != t->nchange) {
192*3ff48bf5SDavid du Colombier 		fprint(2, "disk changed underfoot; repeating\n");
1939a747e4fSDavid du Colombier 		goto Again;
1949a747e4fSDavid du Colombier 	}
1959a747e4fSDavid du Colombier 
1969a747e4fSDavid du Colombier 	n = ((resp[0]<<8) | resp[1])+2;
1979a747e4fSDavid du Colombier 	if(n < 4+8*(t->ntrack+1)) {
1989a747e4fSDavid du Colombier 		werrstr("bad read");
1999a747e4fSDavid du Colombier 		return -1;
2009a747e4fSDavid du Colombier 	}
2019a747e4fSDavid du Colombier 
2029a747e4fSDavid du Colombier 	for(i=0; i<=t->ntrack; i++)
2039a747e4fSDavid du Colombier 		t->track[i].bstart = rdlba(resp+4+i*8+5);
2049a747e4fSDavid du Colombier 
2059a747e4fSDavid du Colombier 	for(i=0; i<t->ntrack; i++)
2069a747e4fSDavid du Colombier 		t->track[i].bend = t->track[i+1].bstart;
2079a747e4fSDavid du Colombier 
2089a747e4fSDavid du Colombier 	return 0;
2099a747e4fSDavid du Colombier }
2109a747e4fSDavid du Colombier 
2119a747e4fSDavid du Colombier static void
dumptoc(Toc * t)2129a747e4fSDavid du Colombier dumptoc(Toc *t)
2139a747e4fSDavid du Colombier {
2149a747e4fSDavid du Colombier 	int i;
2159a747e4fSDavid du Colombier 
216*3ff48bf5SDavid du Colombier 	fprint(1, "%d tracks\n", t->ntrack);
2179a747e4fSDavid du Colombier 	for(i=0; i<t->ntrack; i++)
2189a747e4fSDavid du Colombier 		print("%d. %M-%M (%lud-%lud)\n", i+1,
2199a747e4fSDavid du Colombier 			t->track[i].start, t->track[i].end,
2209a747e4fSDavid du Colombier 			t->track[i].bstart, t->track[i].bend);
2219a747e4fSDavid du Colombier }
2229a747e4fSDavid du Colombier 
2239a747e4fSDavid du Colombier static void
ping(Drive * d)2249a747e4fSDavid du Colombier ping(Drive *d)
2259a747e4fSDavid du Colombier {
2269a747e4fSDavid du Colombier 	uchar cmd[12];
2279a747e4fSDavid du Colombier 
2289a747e4fSDavid du Colombier 	memset(cmd, 0, sizeof cmd);
2299a747e4fSDavid du Colombier 	cmd[0] = 0x43;
2309a747e4fSDavid du Colombier 	scsi(d->scsi, cmd, sizeof(cmd), nil, 0, Snone);
2319a747e4fSDavid du Colombier }
2329a747e4fSDavid du Colombier 
2339a747e4fSDavid du Colombier static int
playstatus(Drive * d,Cdstatus * stat)2349a747e4fSDavid du Colombier playstatus(Drive *d, Cdstatus *stat)
2359a747e4fSDavid du Colombier {
2369a747e4fSDavid du Colombier 	uchar cmd[12], resp[16];
2379a747e4fSDavid du Colombier 
2389a747e4fSDavid du Colombier 	memset(cmd, 0, sizeof cmd);
2399a747e4fSDavid du Colombier 	cmd[0] = 0x42;
2409a747e4fSDavid du Colombier 	cmd[1] = 0x02;
2419a747e4fSDavid du Colombier 	cmd[2] = 0x40;
2429a747e4fSDavid du Colombier 	cmd[3] = 0x01;
2439a747e4fSDavid du Colombier 	cmd[7] = sizeof(resp)>>8;
2449a747e4fSDavid du Colombier 	cmd[8] = sizeof(resp);
2459a747e4fSDavid du Colombier 	if(scsi(d->scsi, cmd, sizeof(cmd), resp, sizeof(resp), Sread) < 0)
2469a747e4fSDavid du Colombier 		return -1;
2479a747e4fSDavid du Colombier 
2489a747e4fSDavid du Colombier 	switch(resp[1]){
2499a747e4fSDavid du Colombier 	case 0x11:
2509a747e4fSDavid du Colombier 		stat->state = Splaying;
2519a747e4fSDavid du Colombier 		break;
2529a747e4fSDavid du Colombier 	case 0x12:
2539a747e4fSDavid du Colombier 		stat->state = Spaused;
2549a747e4fSDavid du Colombier 		break;
2559a747e4fSDavid du Colombier 	case 0x13:
2569a747e4fSDavid du Colombier 		stat->state = Scompleted;
2579a747e4fSDavid du Colombier 		break;
2589a747e4fSDavid du Colombier 	case 0x14:
2599a747e4fSDavid du Colombier 		stat->state = Serror;
2609a747e4fSDavid du Colombier 		break;
2619a747e4fSDavid du Colombier 	case 0x00:	/* not supported */
2629a747e4fSDavid du Colombier 	case 0x15:	/* no current status to return */
2639a747e4fSDavid du Colombier 	default:
2649a747e4fSDavid du Colombier 		stat->state = Sunknown;
2659a747e4fSDavid du Colombier 		break;
2669a747e4fSDavid du Colombier 	}
2679a747e4fSDavid du Colombier 
2689a747e4fSDavid du Colombier 	stat->track = resp[6];
2699a747e4fSDavid du Colombier 	stat->index = resp[7];
2709a747e4fSDavid du Colombier 	stat->abs = rdmsf(resp+9);
2719a747e4fSDavid du Colombier 	stat->rel = rdmsf(resp+13);
2729a747e4fSDavid du Colombier 	return 0;
2739a747e4fSDavid du Colombier }
2749a747e4fSDavid du Colombier 
2759a747e4fSDavid du Colombier void
cdstatusproc(void * v)2769a747e4fSDavid du Colombier cdstatusproc(void *v)
2779a747e4fSDavid du Colombier {
2789a747e4fSDavid du Colombier 	Drive *d;
2799a747e4fSDavid du Colombier 	Toc t;
2809a747e4fSDavid du Colombier 	Cdstatus s;
2819a747e4fSDavid du Colombier 
2829a747e4fSDavid du Colombier 	t.changetime = ~0;
2839a747e4fSDavid du Colombier 	t.nchange = ~0;
2849a747e4fSDavid du Colombier 
2859a747e4fSDavid du Colombier 	threadsetname("cdstatusproc");
2869a747e4fSDavid du Colombier 	d = v;
2879a747e4fSDavid du Colombier 	DPRINT(2, "cdstatus %d\n", getpid());
2889a747e4fSDavid du Colombier 	for(;;) {
2899a747e4fSDavid du Colombier 		ping(d);
2909a747e4fSDavid du Colombier 	//DPRINT(2, "d %d %d t %d %d\n", d->scsi->changetime, d->scsi->nchange, t.changetime, t.nchange);
2919a747e4fSDavid du Colombier 		if(playstatus(d, &s) == 0)
2929a747e4fSDavid du Colombier 			send(d->cstatus, &s);
2939a747e4fSDavid du Colombier 		if(d->scsi->changetime != t.changetime || d->scsi->nchange != t.nchange) {
2949a747e4fSDavid du Colombier 			if(gettoc(d->scsi, &t) == 0) {
2959a747e4fSDavid du Colombier 				DPRINT(2, "sendtoc...\n");
2969a747e4fSDavid du Colombier 				if(debug) dumptoc(&t);
2979a747e4fSDavid du Colombier 				send(d->ctocdisp, &t);
2989a747e4fSDavid du Colombier 			} else
2999a747e4fSDavid du Colombier 				DPRINT(2, "error: %r\n");
3009a747e4fSDavid du Colombier 		}
3019a747e4fSDavid du Colombier 		sleep(1000);
3029a747e4fSDavid du Colombier 	}
3039a747e4fSDavid du Colombier }
304