mmc.c 5.5 KB

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