xref: /plan9/acme/bin/source/acd/mmc.c (revision 3ff48bf5ed603850fcd251ddf13025d23d693782)
1 #include "acd.h"
2 
3 int
msfconv(Fmt * fp)4 msfconv(Fmt *fp)
5 {
6 	Msf m;
7 
8 	m = va_arg(fp->args, Msf);
9 	fmtprint(fp, "%d.%d.%d", m.m, m.s, m.f);
10 	return 0;
11 }
12 
13 static int
status(Drive * d)14 status(Drive *d)
15 {
16 	uchar cmd[12];
17 
18 	memset(cmd, 0, sizeof cmd);
19 	cmd[0] = 0xBD;
20 	return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone);
21 }
22 
23 static int
playmsf(Drive * d,Msf start,Msf end)24 playmsf(Drive *d, Msf start, Msf end)
25 {
26 	uchar cmd[12];
27 
28 	memset(cmd, 0, sizeof cmd);
29 	cmd[0] = 0x47;
30 	cmd[3] = start.m;
31 	cmd[4] = start.s;
32 	cmd[5] = start.f;
33 	cmd[6] = end.m;
34 	cmd[7] = end.s;
35 	cmd[8] = end.f;
36 
37 	return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone);
38 }
39 
40 int
playtrack(Drive * d,int start,int end)41 playtrack(Drive *d, int start, int end)
42 {
43 	Toc *t;
44 
45 	t = &d->toc;
46 
47 	if(t->ntrack == 0)
48 		return -1;
49 
50 	if(start < 0)
51 		start = 0;
52 	if(end >= t->ntrack)
53 		end = t->ntrack-1;
54 	if(end < start)
55 		end = start;
56 
57 	return playmsf(d, t->track[start].start, t->track[end].end);
58 }
59 
60 int
resume(Drive * d)61 resume(Drive *d)
62 {
63 	uchar cmd[12];
64 
65 	memset(cmd, 0, sizeof cmd);
66 	cmd[0] = 0x4B;
67 	cmd[8] = 0x01;
68 	return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone);
69 }
70 
71 int
pause(Drive * d)72 pause(Drive *d)
73 {
74 	uchar cmd[12];
75 
76 	memset(cmd, 0, sizeof cmd);
77 	cmd[0] = 0x4B;
78 	return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone);
79 }
80 
81 int
stop(Drive * d)82 stop(Drive *d)
83 {
84 	uchar cmd[12];
85 
86 	memset(cmd, 0, sizeof cmd);
87 	cmd[0] = 0x4E;
88 	return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone);
89 }
90 
91 int
eject(Drive * d)92 eject(Drive *d)
93 {
94 	uchar cmd[12];
95 
96 	memset(cmd, 0, sizeof cmd);
97 	cmd[0] = 0x1B;
98 	cmd[1] = 1;
99 	cmd[4] = 2;
100 	return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone);
101 }
102 
103 int
ingest(Drive * d)104 ingest(Drive *d)
105 {
106 	uchar cmd[12];
107 
108 	memset(cmd, 0, sizeof cmd);
109 	cmd[0] = 0x1B;
110 	cmd[1] = 1;
111 	cmd[4] = 3;
112 	return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone);
113 }
114 
115 static Msf
rdmsf(uchar * p)116 rdmsf(uchar *p)
117 {
118 	Msf msf;
119 
120 	msf.m = p[0];
121 	msf.s = p[1];
122 	msf.f = p[2];
123 	return msf;
124 }
125 
126 static ulong
rdlba(uchar * p)127 rdlba(uchar *p)
128 {
129 	return (p[0]<<16) | (p[1]<<8) | p[2];
130 }
131 
132 /* not a Drive, so that we don't accidentally touch Drive.toc */
133 int
gettoc(Scsi * s,Toc * t)134 gettoc(Scsi *s, Toc *t)
135 {
136 	int i, n;
137 	uchar cmd[12];
138 	uchar resp[1024];
139 
140 Again:
141 	memset(t, 0, sizeof(*t));
142 	memset(cmd, 0, sizeof cmd);
143 	cmd[0] = 0x43;
144 	cmd[1] = 0x02;
145 	cmd[7] = sizeof(resp)>>8;
146 	cmd[8] = sizeof(resp);
147 
148 	s->changetime = 1;
149 	/* scsi sets nchange, changetime */
150 	if(scsi(s, cmd, sizeof cmd, resp, sizeof(resp), Sread) < 4)
151 		return -1;
152 
153 	if(s->changetime == 0) {
154 		t->ntrack = 0;
155 		werrstr("no media");
156 		return -1;
157 	}
158 
159 	if(t->nchange == s->nchange && t->changetime != 0)
160 		return 0;
161 
162 	t->nchange = s->nchange;
163 	t->changetime = s->changetime;
164 
165 	if(t->ntrack > MTRACK)
166 		t->ntrack = MTRACK;
167 
168 DPRINT(2, "%d %d\n", resp[3], resp[2]);
169 	t->ntrack = resp[3]-resp[2]+1;
170 	t->track0 = resp[2];
171 
172 	n = ((resp[0]<<8) | resp[1])+2;
173 	if(n < 4+8*(t->ntrack+1)) {
174 		werrstr("bad read0 %d %d", n, 4+8*(t->ntrack+1));
175 		return -1;
176 	}
177 
178 	for(i=0; i<=t->ntrack; i++)		/* <=: track[ntrack] = end */
179 		t->track[i].start = rdmsf(resp+4+i*8+5);
180 
181 	for(i=0; i<t->ntrack; i++)
182 		t->track[i].end = t->track[i+1].start;
183 
184 	memset(cmd, 0, sizeof cmd);
185 	cmd[0] = 0x43;
186 	cmd[7] = sizeof(resp)>>8;
187 	cmd[8] = sizeof(resp);
188 	if(scsi(s, cmd, sizeof cmd, resp, sizeof(resp), Sread) < 4)
189 		return -1;
190 
191 	if(s->changetime != t->changetime || s->nchange != t->nchange) {
192 		fprint(2, "disk changed underfoot; repeating\n");
193 		goto Again;
194 	}
195 
196 	n = ((resp[0]<<8) | resp[1])+2;
197 	if(n < 4+8*(t->ntrack+1)) {
198 		werrstr("bad read");
199 		return -1;
200 	}
201 
202 	for(i=0; i<=t->ntrack; i++)
203 		t->track[i].bstart = rdlba(resp+4+i*8+5);
204 
205 	for(i=0; i<t->ntrack; i++)
206 		t->track[i].bend = t->track[i+1].bstart;
207 
208 	return 0;
209 }
210 
211 static void
dumptoc(Toc * t)212 dumptoc(Toc *t)
213 {
214 	int i;
215 
216 	fprint(1, "%d tracks\n", t->ntrack);
217 	for(i=0; i<t->ntrack; i++)
218 		print("%d. %M-%M (%lud-%lud)\n", i+1,
219 			t->track[i].start, t->track[i].end,
220 			t->track[i].bstart, t->track[i].bend);
221 }
222 
223 static void
ping(Drive * d)224 ping(Drive *d)
225 {
226 	uchar cmd[12];
227 
228 	memset(cmd, 0, sizeof cmd);
229 	cmd[0] = 0x43;
230 	scsi(d->scsi, cmd, sizeof(cmd), nil, 0, Snone);
231 }
232 
233 static int
playstatus(Drive * d,Cdstatus * stat)234 playstatus(Drive *d, Cdstatus *stat)
235 {
236 	uchar cmd[12], resp[16];
237 
238 	memset(cmd, 0, sizeof cmd);
239 	cmd[0] = 0x42;
240 	cmd[1] = 0x02;
241 	cmd[2] = 0x40;
242 	cmd[3] = 0x01;
243 	cmd[7] = sizeof(resp)>>8;
244 	cmd[8] = sizeof(resp);
245 	if(scsi(d->scsi, cmd, sizeof(cmd), resp, sizeof(resp), Sread) < 0)
246 		return -1;
247 
248 	switch(resp[1]){
249 	case 0x11:
250 		stat->state = Splaying;
251 		break;
252 	case 0x12:
253 		stat->state = Spaused;
254 		break;
255 	case 0x13:
256 		stat->state = Scompleted;
257 		break;
258 	case 0x14:
259 		stat->state = Serror;
260 		break;
261 	case 0x00:	/* not supported */
262 	case 0x15:	/* no current status to return */
263 	default:
264 		stat->state = Sunknown;
265 		break;
266 	}
267 
268 	stat->track = resp[6];
269 	stat->index = resp[7];
270 	stat->abs = rdmsf(resp+9);
271 	stat->rel = rdmsf(resp+13);
272 	return 0;
273 }
274 
275 void
cdstatusproc(void * v)276 cdstatusproc(void *v)
277 {
278 	Drive *d;
279 	Toc t;
280 	Cdstatus s;
281 
282 	t.changetime = ~0;
283 	t.nchange = ~0;
284 
285 	threadsetname("cdstatusproc");
286 	d = v;
287 	DPRINT(2, "cdstatus %d\n", getpid());
288 	for(;;) {
289 		ping(d);
290 	//DPRINT(2, "d %d %d t %d %d\n", d->scsi->changetime, d->scsi->nchange, t.changetime, t.nchange);
291 		if(playstatus(d, &s) == 0)
292 			send(d->cstatus, &s);
293 		if(d->scsi->changetime != t.changetime || d->scsi->nchange != t.nchange) {
294 			if(gettoc(d->scsi, &t) == 0) {
295 				DPRINT(2, "sendtoc...\n");
296 				if(debug) dumptoc(&t);
297 				send(d->ctocdisp, &t);
298 			} else
299 				DPRINT(2, "error: %r\n");
300 		}
301 		sleep(1000);
302 	}
303 }
304