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