|
|
1.1 root 1: #include "u.h"
2: #include "../port/lib.h"
3: #include "mem.h"
4: #include "dat.h"
5: #include "fns.h"
6: #include "../port/error.h"
7: #include "devtab.h"
8: #include "io.h"
9: /*
10: * CD-ROM driver for Panasonic and Mitsumi drives on SB16 and SBPRO cards
11: */
12:
13:
14: typedef struct Drive Drive;
15:
16: enum
17: {
18: FRAMESIZE = 2048, /* max in a transfer */
19: Panasonic = 1,
20: Mitsumi = 2,
21:
22: Qdir = 0,
23: Qcd,
24: Qcdctl,
25:
26: CMDLEN = 7,
27:
28: DTEN = 0x02, /* Status register */
29: STEN = 0x04,
30:
31: DRIVE0 = 0,
32:
33: CMD = 0, /* Ports */
34: DATA = 0,
35: PHASE = 1,
36: STATUS = 1,
37: RESET = 2,
38: SELECT = 3,
39:
40: ABORT = 0x08,
41: BLOCKPARAM = 0x00,
42: DOORCLOSE = 0x07,
43: DOOROPEN = 0x06,
44: LOCK = 0x0c,
45: MODESELECT = 0x09,
46: NOP = 0x05,
47: PAUSE = 0x0d,
48: PLAYBLOCKS = 0x0e,
49: PLAYTRKS = 0x0f,
50: READ = 0x10,
51: READDINFO = 0x8b,
52: READERROR = 0x82,
53: READID = 0x83,
54: RESUME = 0x80,
55:
56: ST_DOOROPEN = 0x80,
57: ST_DSKIN = 0x40,
58: ST_SPIN = 0x20,
59: ST_ERROR = 0x10,
60: ST_BUSY = 0x04,
61: ST_AUDIOBSY = 0x02,
62:
63: MEDIA_CHANGED = 0x11,
64: NOT_READY = 0x03,
65: HARD_RESET = 0x12,
66: DISC_OUT = 0x15,
67:
68: MST_CMD_CHECK = 0x01, /* command error */
69: MST_BUSY = 0x02, /* now playing */
70: MST_READ_ERR = 0x04, /* read error */
71: MST_DSK_TYPE = 0x08, /* cdda */
72: MST_SERVO_CHECK = 0x10,
73: MST_DSK_CHG = 0x20, /* disk removed or changed */
74: MST_READY = 0x40, /* disk in the drive */
75: MST_DOOR_OPEN = 0x80, /* door is open */
76:
77: MFL_DATA = 0x02, /* data available */
78: MFL_STATUS = 0x04, /* status available */
79:
80: MCMD_RESET = 0x00,
81: MCMD_GET_DISK_INFO = 0x10, /* read info from disk */
82: MCMD_GET_Q_CHANNEL = 0x20, /* read info from q channel */
83: MCMD_GET_STATUS = 0x40,
84: MCMD_SET_MODE = 0x50,
85: MCMD_SOFT_RESET = 0x60,
86: MCMD_STOP = 0x70, /* stop play */
87: MCMD_CONFIG_DRIVE = 0x90,
88: MCMD_SET_VOLUME = 0xAE, /* set audio level */
89: MCMD_PLAY_READ = 0xC0, /* play or read data */
90: MCMD_GET_VERSION = 0xDC,
91: MCMD_EJECT = 0xF6, /* eject (FX drive) */
92:
93: MSTAT_DOOR = 1,
94: MSTAT_CHNG,
95: MSTAT_CDDA,
96: MSTAT_READY,
97: MSTAT_ERROR,
98: };
99:
100: static char *etable[] =
101: {
102: "no error",
103: "soft read error after retry",
104: "soft read error after error correction",
105: "not ready",
106: "unable to read TOC",
107: "hard read error of data track",
108: "seek failed",
109: "tracking servo failure",
110: "drive RAM failure",
111: "drive self-test failed",
112: "focusing servo failure",
113: "spindle servo failure",
114: "data path failure",
115: "illegal logical block address",
116: "illegal field in CDB",
117: "end of user encountered on this track",
118: "illegal data mode for this track",
119: "media changed",
120: "power-on or drive reset occurred",
121: "drive ROM failure",
122: "illegal drive command received from host",
123: "disc removed during operation",
124: "drive Hardware error",
125: "illegal request from host"
126: };
127:
128: static char *metable[] =
129: {
130: [MSTAT_DOOR] = "cdrom door is open",
131: [MSTAT_CHNG] = "cdrom media changed",
132: [MSTAT_CDDA] = "cd is not a cdrom",
133: [MSTAT_READY] = "cdrom is not ready",
134: [MSTAT_ERROR] = "cannot get cd status",
135: };
136:
137: struct Drive
138: {
139: int type;
140: Ref opens;
141: QLock;
142: Rendez rendez;
143: ulong blocks; /* blocks on disk */
144: int port;
145: uchar buf[FRAMESIZE];
146:
147: void (*sbcdio)(int, ulong);
148: void (*initdrive)(int);
149: };
150:
151: Dirtab
152: cdtab[] =
153: {
154: "cd", {Qcd}, 0, 0666,
155: "cdctl", {Qcdctl}, 0, 0666,
156: };
157: #define Ncdtab (sizeof cdtab/sizeof(Dirtab))
158: #define CDFILE 0 /* Array index of Qcd direntry */
159:
160: static Drive sbcd;
161:
162: static void pansbcdio(int, ulong);
163: static void mitsbcdio(int, ulong);
164: static void paninitdrive(int);
165: static void mitinitdrive(int);
166:
167: static void
168: drain(int port)
169: {
170: outb(port+STATUS, 1);
171: while((inb(port+STATUS) & (DTEN|STEN)) == STEN)
172: inb(port+DATA);
173: outb(port+STATUS,0);
174: }
175:
176: static int
177: status(int port)
178: {
179: int sr;
180:
181: sr = inb(port+DATA);
182:
183: for(;;) {
184: if(inb(port+STATUS) == 0xff)
185: break;
186: if((sr&DTEN|STEN) == STEN)
187: drain(port);
188:
189: print("devsbcd: busy for sr\n");
190: sr = inb(port+DATA);
191: }
192:
193: return sr;
194: }
195:
196: static void
197: issue(int port, uchar *cmd)
198: {
199: ulong s;
200: uchar sr;
201: int i, len;
202:
203: i = inb(port+STATUS);
204: if(i != 0xff) {
205: if ((i & DTEN|STEN) == STEN)
206: drain(port);
207: i = status(port);
208: USED(i);
209: sr = inb(port+STATUS);
210: if(sr != 0xff) {
211: print("devsbcd: device wedged, sr=%2.2ux\n", inb(port+STATUS));
212: outb(port+RESET, 0);
213: tsleep(&sbcd.rendez, return0, 0, 500);
214: }
215: }
216:
217: outb(port+SELECT, DRIVE0);
218:
219: len = CMDLEN;
220: if(cmd[0] == ABORT)
221: len=1;
222:
223: s = splhi();
224: for (i = 0; i < len; i++)
225: outb(port+CMD,*cmd++);
226: splx(s);
227: }
228:
229: void
230: sbcdreset(void)
231: {
232: }
233:
234: void
235: sbcdinit(void)
236: {
237: ISAConf sbconf;
238:
239: sbconf.port = 0;
240: if(isaconfig("cdrom", 0, &sbconf) == 0)
241: return;
242: if(strcmp(sbconf.type, "panasonic") == 0 || strcmp(sbconf.type, "matsushita") == 0) {
243: sbcd.sbcdio = pansbcdio;
244: sbcd.initdrive = paninitdrive;
245: if(sbconf.port == 0)
246: sbconf.port = 0x230;
247: }
248: else
249: if(strcmp(sbconf.type, "mitsumi") == 0) {
250: sbcd.sbcdio = mitsbcdio;
251: sbcd.initdrive = mitinitdrive;
252: if(sbconf.port == 0)
253: sbconf.port = 0x340;
254: }
255: if(sbcd.sbcdio == 0) {
256: print("devsbcd: %s is not a valid cd-rom type\n", sbconf.type);
257: return;
258: }
259: switch(sbconf.port) {
260: case 0x230:
261: case 0x250:
262: case 0x270:
263: case 0x290:
264: case 0x340:
265: break;
266: default:
267: print("devsbcd: bad port 0x%x\n", sbconf.port);
268: return;
269: }
270: sbcd.port = sbconf.port;
271: }
272:
273: Chan*
274: sbcdattach(char *param)
275: {
276: if(sbcd.port == 0)
277: error("no cd-rom configured");
278:
279: return devattach('m', param);
280: }
281:
282: Chan*
283: sbcdclone(Chan *c, Chan *nc)
284: {
285: return devclone(c, nc);
286: }
287:
288: int
289: sbcdwalk(Chan *c, char *name)
290: {
291: return devwalk(c, name, cdtab, Ncdtab, devgen);
292: }
293:
294: void
295: sbcdstat(Chan *c, char *dp)
296: {
297: devstat(c, dp, cdtab, Ncdtab, devgen);
298: }
299:
300: static int
301: poll(int timeo, int state, int port, int delay)
302: {
303: int i, sr;
304:
305: sr = 0;
306: for(i = 0; i < timeo; i++) {
307: sr = inb(port+STATUS) & (STEN|DTEN);
308: if(sr != (STEN|DTEN))
309: break;
310: if(delay != 0)
311: tsleep(&sbcd.rendez, return0, 0, TK2MS(1));
312: }
313: return sr != state;
314: }
315:
316: static int
317: reqsense(int port)
318: {
319: int i;
320: uchar cmd[CMDLEN], data[12];
321:
322: memset(cmd, 0, sizeof(cmd));
323: cmd[0] = READERROR;
324: issue(port, cmd);
325: i = poll(2000, DTEN, port, 0);
326: if(i < 0) {
327: print("devsbcd: get error failed\n");
328: error(Eio);
329: }
330: insb(port, data, 8);
331: status(port);
332:
333: return data[2];
334: }
335:
336: static void
337: getcap(Drive *d)
338: {
339: int port, i, sr, retry;
340: uchar cmd[CMDLEN], data[12];
341:
342: port = d->port;
343:
344: for(retry = 0; retry < 10; retry++) {
345: memset(cmd, 0, sizeof(cmd));
346: cmd[0] = READDINFO;
347: issue(port, cmd);
348: i = poll(10, DTEN, port, 1);
349: if(i < 0) {
350: print("devsbcd: cmd error, sr=%2.2ux\n", status(port));
351: error(Eio);
352: }
353: insb(port, data, 6);
354: sr = status(port);
355:
356: sbcd.blocks = (data[3]*4500) + (data[4]*75) + data[5];
357: sbcd.blocks -= 150;
358: cdtab[CDFILE].length = sbcd.blocks*FRAMESIZE;
359:
360: if((sr & ST_ERROR) == 0)
361: break;
362: }
363: if(retry >= 10)
364: error(Eio);
365: }
366:
367: Chan*
368: sbcdopen(Chan *c, int omode)
369: {
370: switch(c->qid.path) {
371: case Qcd:
372: if(incref(&sbcd.opens) == 1) {
373: if(waserror()) {
374: decref(&sbcd.opens);
375: nexterror();
376: }
377: sbcd.initdrive(sbcd.port);
378: poperror();
379: }
380: break;
381: }
382: return devopen(c, omode, cdtab, Ncdtab, devgen);
383: }
384:
385: void
386: sbcdcreate(Chan *c, char *name, int omode, ulong perm)
387: {
388: USED(c, name, omode, perm);
389: error(Eperm);
390: }
391:
392: void
393: sbcdclose(Chan *c)
394: {
395: switch(c->qid.path) {
396: default:
397: break;
398: case Qcd:
399: if(c->flag & COPEN)
400: decref(&sbcd.opens);
401: break;
402: }
403: }
404:
405: void
406: sbcdremove(Chan *c)
407: {
408: USED(c);
409: error(Eperm);
410: }
411:
412: void
413: sbcdwstat(Chan *c, char *dp)
414: {
415: USED(c, dp);
416: error(Eperm);
417: }
418:
419: long
420: sbcdread(Chan *c, char *a, long n, ulong offset)
421: {
422: char *t, buf[64];
423: long m, o, n0, bn;
424:
425: if(c->qid.path & CHDIR)
426: return devdirread(c, a, n, cdtab, Ncdtab, devgen);
427:
428: n0 = n;
429: switch(c->qid.path) {
430: case Qcdctl:
431: t = "panasonic";
432: if(sbcd.sbcdio != pansbcdio)
433: t = "mitsumi";
434: sprint(buf, "port=0x%ux drive=%s\n", sbcd.port, t);
435: return readstr(offset, a, n, buf);
436: case Qcd:
437: qlock(&sbcd);
438: if(waserror()) {
439: qunlock(&sbcd);
440: nexterror();
441: }
442: while(n > 0) {
443: bn = offset / FRAMESIZE;
444: o = offset % FRAMESIZE;
445: m = FRAMESIZE - o;
446: if(m > n)
447: m = n;
448: if(bn >= sbcd.blocks)
449: break;
450: sbcd.sbcdio(sbcd.port, bn);
451: memmove(a, sbcd.buf+o, m);
452: n -= m;
453: offset += m;
454: a += m;
455: }
456: qunlock(&sbcd);
457: poperror();
458: break;
459: }
460: return n0-n;
461: }
462:
463: long
464: sbcdwrite(Chan *c, char *a, long n, ulong offset)
465: {
466:
467: USED(c, a, n, offset);
468: error(Eperm);
469: return 0;
470: }
471:
472: static void
473: bin2bcd(uchar *p)
474: {
475: int u, t;
476:
477: u = *p % 10;
478: t = *p / 10;
479: *p = u | (t << 4);
480: }
481:
482: static void
483: bin2msf(uchar *msf, long addr)
484: {
485: addr += 150;
486: msf[0] = addr / 4500;
487: addr %= 4500;
488: msf[1] = addr / 75;
489: msf[2] = addr % 75;
490: }
491:
492: static int
493: bcd2bin(uchar bcd)
494: {
495: return (bcd >> 4) * 10 + (bcd & 0xF);
496: }
497:
498: /*
499: * panasonic specific
500: */
501: static void
502: paninitdrive(int port)
503: {
504: int i, sr;
505: uchar cmd[CMDLEN];
506:
507: qlock(&sbcd);
508: if(waserror()) {
509: qunlock(&sbcd);
510: nexterror();
511: }
512:
513: memset(cmd, 0, sizeof(cmd));
514: cmd[0] = NOP;
515: issue(port, cmd);
516: i = poll(10, DTEN, port, 1);
517: if(i < 0)
518: error("cd not responding");
519:
520: sr = status(port);
521: if((sr&ST_DSKIN) == 0)
522: error("no cd in drive");
523:
524: if(sr&ST_ERROR) {
525: i = reqsense(port);
526: switch(i) {
527: case NOT_READY: /* Just media changes */
528: case MEDIA_CHANGED:
529: case HARD_RESET:
530: case DISC_OUT:
531: break;
532: default:
533: error(etable[i]); /* Real errors */
534: }
535: }
536:
537: getcap(&sbcd);
538:
539: qunlock(&sbcd);
540: poperror();
541: }
542:
543: static void
544: pansbcdio(int port, ulong adr)
545: {
546: int sr, i, try, errno;
547: uchar *p, msf[3], cmd[CMDLEN];
548:
549: bin2msf(msf, adr);
550:
551: retry:
552: memset(cmd, 0, sizeof(cmd));
553: cmd[0] = READ;
554: cmd[1] = msf[0];
555: cmd[2] = msf[1];
556: cmd[3] = msf[2];
557: cmd[6] = 1;
558: issue(port, cmd);
559:
560: for(try = 0; try < 100; try++) {
561: sr = inb(port+STATUS) & (STEN|DTEN);
562: switch(sr) {
563: case DTEN|STEN:
564: tsleep(&sbcd.rendez, return0, 0, TK2MS(1));
565: break;
566:
567: case 0:
568: case STEN:
569: outb(port+STATUS, 1);
570: p = sbcd.buf;
571: for(i = 0; i < sizeof(sbcd.buf); i++) {
572: if(inb(port+STATUS) != 0xfd)
573: break;
574: *p++ = inb(port+DATA);
575: }
576: outb(port+STATUS,0);
577: while((inb(port+STATUS)&(DTEN|STEN)) != DTEN)
578: ;
579: sr = status(port);
580: if(sr & ST_ERROR) {
581: errno = reqsense(port);
582: error(etable[errno]);
583: }
584: return;
585:
586: case DTEN:
587: i = status(port);
588: errno = reqsense(port);
589: print("devsbcd: %s reading block %d\n", etable[errno], adr);
590:
591: switch(errno) {
592: case NOT_READY:
593: case MEDIA_CHANGED:
594: case HARD_RESET:
595: case DISC_OUT:
596: error(etable[i]);
597: }
598: goto retry;
599: }
600: }
601: }
602:
603: /*
604: * mitsumi specific
605: */
606: static int
607: statmap(int s)
608: {
609: if(s & MST_DOOR_OPEN)
610: return MSTAT_DOOR; /* door is open */
611: if(s & MST_DSK_CHG)
612: return MSTAT_CHNG; /* disk was changed */
613: if(s & MST_DSK_TYPE)
614: return MSTAT_CDDA; /* not cdrom type disk */
615: if((s & MST_READY) == 0)
616: return MSTAT_READY; /* not ready */
617: return 0;
618: }
619:
620: static int
621: mitdata(int port, uchar *d, long n)
622: {
623: int j, f;
624:
625: for(j=500; j; j--) {
626: f = inb(port+1) & (MFL_DATA|MFL_STATUS);
627: if(f == (MFL_DATA|MFL_STATUS)) {
628: if(j > 400)
629: sched();
630: else
631: tsleep(&sbcd.rendez, return0, 0, TK2MS(1));
632: continue;
633: }
634: if(f == MFL_STATUS) {
635: *d++ = inb(port+0);
636: if(n == 1)
637: return 0;
638: n--;
639: j = 500;
640: continue;
641: }
642: break;
643: }
644: return MSTAT_ERROR;
645: }
646:
647: static int
648: mitstatus(int port, uchar *d, long n)
649: {
650: int j, f;
651:
652: for(j=500; j; j--) {
653: f = inb(port+1) & (MFL_DATA|MFL_STATUS);
654: if(f == (MFL_DATA|MFL_STATUS)) {
655: if(j > 400)
656: sched();
657: else
658: tsleep(&sbcd.rendez, return0, 0, TK2MS(1));
659: continue;
660: }
661: if(f == MFL_DATA) {
662: *d++ = inb(port+0);
663: if(n == 1)
664: return 0;
665: n--;
666: j = 500;
667: continue;
668: }
669: break;
670: }
671: return MSTAT_ERROR;
672: }
673:
674: static void
675: mitinitdrive(int port)
676: {
677: int i, e;
678: uchar dat[10];
679:
680: qlock(&sbcd);
681: if(waserror()) {
682: qunlock(&sbcd);
683: nexterror();
684: }
685:
686: sbcd.blocks = 0;
687: for(i=0; i<5; i++) {
688: outb(port+0, MCMD_GET_DISK_INFO);
689: if(mitstatus(port, dat, 9))
690: continue;
691: e = statmap(dat[0]);
692: if(e)
693: continue;
694: sbcd.blocks = bcd2bin(dat[3])*4500 +
695: bcd2bin(dat[4])*75 +
696: bcd2bin(dat[5]) -
697: 150;
698: cdtab[CDFILE].length = sbcd.blocks*FRAMESIZE;
699:
700: break;
701: }
702: if(sbcd.blocks == 0)
703: error("cant issue capacity");
704:
705: qunlock(&sbcd);
706: poperror();
707: }
708:
709: static void
710: del(void)
711: {
712: int i;
713:
714: for(i=0; i<10; i++)
715: ;
716: }
717:
718: static void
719: mitsbcdio(int port, ulong adr)
720: {
721: int i, e;
722: ulong s;
723: uchar status, msf[3];
724:
725: bin2msf(msf, adr);
726: bin2bcd(msf+0); /* convert to BCD */
727: bin2bcd(msf+1);
728: bin2bcd(msf+2);
729:
730: e = 0;
731: for(i=0; i<5; i++) {
732:
733: s = splhi();
734: outb(port+0, MCMD_SET_MODE);
735: outb(port+0, 1); /* cooked data */
736: splx(s);
737:
738: if(mitstatus(port, &status, 1))
739: continue;
740: e = statmap(status);
741: if(e)
742: continue;
743:
744: s = splhi();
745: outb(port+0, MCMD_PLAY_READ);
746: outb(port+0, msf[0]);
747: outb(port+0, msf[1]);
748: outb(port+0, msf[2]);
749: outb(port+0, 0);
750: outb(port+0, 0);
751: outb(port+0, 1);
752: splx(s);
753:
754: if(mitdata(port, sbcd.buf, FRAMESIZE) == 0) {
755: if(mitstatus(port, &status, 1))
756: continue;
757: e = statmap(status);
758: if(e)
759: continue;
760: return;
761: }
762: }
763: if(e == 0)
764: e = MSTAT_ERROR;
765: error(metable[e]);
766: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.