mmc.c 5.3 KB

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