|
|
1.1 root 1: #include <u.h>
2:
3: #include "lib.h"
4: #include "mem.h"
5: #include "dat.h"
6: #include "fns.h"
7: #include "io.h"
8: #include "ureg.h"
9:
10: #define DPRINT if(0)print
11:
12: typedef struct Drive Drive;
13: typedef struct Floppy Floppy;
14: typedef struct Type Type;
15:
16: enum
17: {
18: Pdor= 0x3f2, /* motor port */
19: Fintena= 0x8, /* enable floppy interrupt */
20: Fena= 0x4, /* 0 == reset controller */
21:
22: Pmsr= 0x3f4, /* controller main status port */
23: Fready= 0x80, /* ready to be touched */
24: Ffrom= 0x40, /* data from controller */
25: Fbusy= 0x10, /* operation not over */
26:
27: Pdata= 0x3f5, /* controller data port */
28: Frecal= 0x7, /* recalibrate cmd */
29: Fseek= 0xf, /* seek cmd */
30: Fsense= 0x8, /* sense cmd */
31: Fread= 0x66, /* read cmd */
32: Fwrite= 0x45, /* write cmd */
33: Fmulti= 0x80, /* or'd with Fread or Fwrite for multi-head */
34:
35: /* digital input register */
36: Pdir= 0x3F7, /* disk changed port (read only) */
37: Pdsr= 0x3F7, /* data rate select port (write only) */
38: Fchange= 0x80, /* disk has changed */
39:
40: DMAmode0= 0xb,
41: DMAmode1= 0xc,
42: DMAaddr= 0x4,
43: DMAtop= 0x81,
44: DMAinit= 0xa,
45: DMAcount= 0x5,
46:
47: Maxfloppy= 4, /* floppies/controller */
48:
49: /* sector size encodings */
50: S128= 0,
51: S256= 1,
52: S512= 2,
53: S1024= 3,
54:
55: /* status 0 byte */
56: Drivemask= 3<<0,
57: Seekend= 1<<5,
58: Codemask= (3<<6)|(3<<3),
59: };
60:
61: #define MOTORBIT(i) (1<<((i)+4))
62:
63: /*
64: * types of drive (from PC equipment byte)
65: */
66: enum
67: {
68: Tnone= 0,
69: T360kb= 1,
70: T1200kb= 2,
71: T720kb= 3,
72: T1440kb= 4,
73: };
74:
75: /*
76: * floppy types (all MFM encoding)
77: */
78: struct Type
79: {
80: char *name;
81: int dt; /* compatible drive type */
82: int bytes; /* bytes/sector */
83: int sectors; /* sectors/track */
84: int heads; /* number of heads */
85: int steps; /* steps per cylinder */
86: int tracks; /* tracks/disk */
87: int gpl; /* intersector gap length for read/write */
88: int fgpl; /* intersector gap length for format */
89: int rate; /* rate code */
90:
91: /*
92: * these depend on previous entries and are set filled in
93: * by floppyinit
94: */
95: int bcode; /* coded version of bytes for the controller */
96: long cap; /* drive capacity in bytes */
97: long tsize; /* track size in bytes */
98: };
99: Type floppytype[] =
100: {
101: { "3½HD", T1440kb, 512, 18, 2, 1, 80, 0x1B, 0x54, 0, },
102: { "3½DD", T1440kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, },
103: { "3½DD", T720kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, },
104: { "5¼HD", T1200kb, 512, 15, 2, 1, 80, 0x2A, 0x50, 0, },
105: { "5¼DD", T1200kb, 512, 9, 2, 2, 40, 0x2A, 0x50, 1, },
106: { "5¼DD", T360kb, 512, 9, 2, 1, 40, 0x2A, 0x50, 2, },
107: };
108: #define NTYPES (sizeof(floppytype)/sizeof(Type))
109:
110: /*
111: * bytes per sector encoding for the controller.
112: * - index for b2c is is (bytes per sector/128).
113: * - index for c2b is code from b2c
114: */
115: static int b2c[] =
116: {
117: [1] 0,
118: [2] 1,
119: [4] 2,
120: [8] 3,
121: };
122: static int c2b[] =
123: {
124: 128,
125: 256,
126: 512,
127: 1024,
128: };
129:
130: /*
131: * a floppy drive
132: */
133: struct Drive
134: {
135: Type *t;
136: int dt;
137: int dev;
138:
139: ulong lasttouched; /* time last touched */
140: int cyl; /* current cylinder */
141: int confused; /* needs to be recalibrated (or worse) */
142: long offset; /* current offset */
143:
144: int tcyl; /* target cylinder */
145: int thead; /* target head */
146: int tsec; /* target sector */
147: long len;
148: int maxtries;
149: };
150:
151: /*
152: * NEC PD765A controller for 4 floppys
153: */
154: struct Floppy
155: {
156: Drive d[Maxfloppy]; /* the floppy drives */
157: int rw; /* true if a read or write in progress */
158: int seek; /* one bit for each seek in progress */
159: uchar stat[8]; /* status of an operation */
160: int intr;
161: int confused;
162: int motor;
163: Drive *selected;
164: int rate;
165:
166: int cdev;
167: uchar *ccache; /* cylinder cache */
168: int ccyl;
169: int chead;
170: };
171:
172: Floppy fl;
173:
174: static void floppyalarm(Alarm*);
175: static int floppysend(int);
176: static int floppyrcv(void);
177: static int floppyrdstat(int);
178: static void floppypos(Drive*, long);
179: static void floppywait(char*);
180: static int floppysense(Drive*);
181: static int floppyrecal(Drive*);
182: static void floppyon(Drive*);
183: static long floppyxfer(Drive*, int, void*, long);
184: static void floppyrevive(void);
185: static void floppystop(Drive*);
186:
187: static void
188: timedsleep(int ms)
189: {
190: ulong end;
191:
192: end = m->ticks + 1 + MS2TK(ms);
193: while(m->ticks < end)
194: ;
195: }
196:
197: /*
198: * set floppy drive to its default type
199: */
200: static void
201: setdef(Drive *dp)
202: {
203: Type *t;
204:
205: for(t = floppytype; t < &floppytype[NTYPES]; t++)
206: if(dp->dt == t->dt){
207: dp->t = t;
208: break;
209: }
210: }
211:
212: static void
213: floppyintr(Ureg*, void*)
214: {
215: fl.intr = 1;
216: }
217:
218: int
219: floppyinit(void)
220: {
221: Drive *dp;
222: uchar equip;
223: int mask;
224: Type *t;
225: char debstr[256];
226:
227: setvec(Floppyvec, floppyintr, 0);
228:
229: /* reset the interface chip */
230: sprint(debstr, "resetting floppy interface\n");
231: delay(50);
232: outb(Pdor, 0);
233: delay(50);
234: outb(Pdor, Fintena | Fena);
235: delay(50);
236: sprint(debstr, "floppy interface reset\n");
237:
238: /*
239: * init dependent parameters
240: */
241: for(t = floppytype; t < &floppytype[NTYPES]; t++){
242: t->cap = t->bytes * t->heads * t->sectors * t->tracks;
243: t->bcode = b2c[t->bytes/128];
244: t->tsize = t->bytes * t->sectors;
245: }
246:
247: /*
248: * init drive parameters
249: */
250: for(dp = fl.d; dp < &fl.d[Maxfloppy]; dp++){
251: dp->cyl = -1;
252: dp->dev = dp - fl.d;
253: dp->maxtries = 1;
254: }
255:
256: /*
257: * read nvram for types of floppies 0 & 1
258: */
259: mask = 0;
260: equip = nvramread(0x10);
261: if(Maxfloppy > 0 && (fl.d[0].dt = ((equip>>4) & 0xF))){
262: setdef(&fl.d[0]);
263: mask |= 0x01;
264: }
265: if(Maxfloppy > 1 && (fl.d[1].dt = (equip & 0xF))){
266: setdef(&fl.d[1]);
267: mask |= 0x02;
268: }
269:
270: fl.rate = -1;
271: fl.motor = 0;
272: fl.confused = 1;
273: fl.ccyl = -1;
274: fl.chead = -1;
275: fl.cdev = -1;
276: fl.ccache = (uchar*)ialloc(18*2*512, 1);
277:
278: /* to turn the motor off when inactive */
279: alarm(5*1000, floppyalarm, (void *)0);
280:
281: return mask;
282: }
283:
284: static void
285: floppyon(Drive *dp)
286: {
287: int alreadyon;
288: int tries;
289:
290: if(fl.confused)
291: floppyrevive();
292:
293: alreadyon = fl.motor & MOTORBIT(dp->dev);
294: fl.motor |= MOTORBIT(dp->dev);
295: outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
296:
297: /* get motor going */
298: if(!alreadyon)
299: timedsleep(750);
300:
301: /* set transfer rate */
302: if(fl.rate != dp->t->rate){
303: fl.rate = dp->t->rate;
304: outb(Pdsr, fl.rate);
305: }
306:
307: /* get drive to a known cylinder */
308: if(dp->confused)
309: for(tries = 0; tries < 4; tries++)
310: if(floppyrecal(dp) >= 0)
311: break;
312:
313: dp->lasttouched = m->ticks;
314: fl.selected = dp;
315: }
316:
317: static void
318: floppyrevive(void)
319: {
320: Drive *dp;
321:
322: /*
323: * reset the controller if it's confused
324: */
325: if(fl.confused){
326: /* reset controller and turn all motors off */
327: fl.intr = 0;
328: splhi();
329: outb(Pdor, 0);
330: delay(1);
331: outb(Pdor, Fintena|Fena);
332: spllo();
333: for(dp = fl.d; dp < &fl.d[Maxfloppy]; dp++)
334: dp->confused = 1;
335: fl.motor = 0;
336: floppywait("revive");
337: fl.confused = 0;
338: outb(Pdsr, 0);
339: }
340: }
341:
342: static void
343: floppystop(Drive *dp)
344: {
345: fl.motor &= ~MOTORBIT(dp->dev);
346: outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
347: fl.selected = dp;
348: }
349:
350: static void
351: floppyalarm(Alarm* a)
352: {
353: Drive *dp;
354:
355: for(dp = fl.d; dp < &fl.d[Maxfloppy]; dp++){
356: if((fl.motor&MOTORBIT(dp->dev)) && TK2SEC(m->ticks - dp->lasttouched) > 5)
357: floppystop(dp);
358: }
359:
360: alarm(5*1000, floppyalarm, 0);
361: cancel(a);
362: }
363:
364: static int
365: floppysend(int data)
366: {
367: int tries;
368: uchar c;
369:
370: for(tries = 0; tries < 100; tries++){
371: /*
372: * see if its ready for data
373: */
374: c = inb(Pmsr);
375: if((c&(Ffrom|Fready)) != Fready)
376: continue;
377:
378: /*
379: * send the data
380: */
381: outb(Pdata, data);
382: return 0;
383: }
384: return -1;
385: }
386:
387: static int
388: floppyrcv(void)
389: {
390: int tries;
391: uchar c;
392:
393: for(tries = 0; tries < 100; tries++){
394: /*
395: * see if its ready for data
396: */
397: c = inb(Pmsr);
398: if((c&(Ffrom|Fready)) != (Ffrom|Fready))
399: continue;
400:
401: /*
402: * get data
403: */
404: return inb(Pdata)&0xff;
405: }
406: DPRINT("floppyrcv returns -1 status = %lux\n", c);
407: return -1;
408: }
409:
410: static int
411: floppyrdstat(int n)
412: {
413: int i;
414: int c;
415:
416: for(i = 0; i < n; i++){
417: c = floppyrcv();
418: if(c < 0)
419: return -1;
420: fl.stat[i] = c;
421: }
422: return 0;
423: }
424:
425: static void
426: floppypos(Drive *dp, long off)
427: {
428: int lsec;
429: int cyl;
430:
431: lsec = off/dp->t->bytes;
432: dp->tcyl = lsec/(dp->t->sectors*dp->t->heads);
433: dp->tsec = (lsec % dp->t->sectors) + 1;
434: dp->thead = (lsec/dp->t->sectors) % dp->t->heads;
435:
436: /*
437: * can't read across cylinder boundaries.
438: * if so, decrement the bytes to be read.
439: */
440: lsec = (off+dp->len)/dp->t->bytes;
441: cyl = lsec/(dp->t->sectors*dp->t->heads);
442: if(cyl != dp->tcyl){
443: dp->len -= (lsec % dp->t->sectors)*dp->t->bytes;
444: dp->len -= ((lsec/dp->t->sectors) % dp->t->heads)*dp->t->bytes
445: *dp->t->sectors;
446: }
447:
448: dp->lasttouched = m->ticks;
449: fl.intr = 0;
450: }
451:
452: static void
453: floppywait(char *cmd)
454: {
455: ulong start;
456:
457: for(start = m->ticks; TK2SEC(m->ticks - start) < 1 && fl.intr == 0;)
458: ;
459: if(TK2SEC(m->ticks - start) >= 1)
460: DPRINT("floppy timed out, cmd=%s\n", cmd);
461: fl.intr = 0;
462: }
463:
464: static int
465: floppysense(Drive *dp)
466: {
467: /*
468: * ask for floppy status
469: */
470: if(floppysend(Fsense) < 0){
471: fl.confused = 1;
472: return -1;
473: }
474: if(floppyrdstat(2) < 0){
475: fl.confused = 1;
476: dp->confused = 1;
477: return -1;
478: }
479:
480: /*
481: * make sure it's the right drive
482: */
483: if((fl.stat[0] & Drivemask) != dp->dev){
484: DPRINT("sense failed, %lux %lux\n", fl.stat[0], fl.stat[1]);
485: dp->confused = 1;
486: return -1;
487: }
488: return 0;
489: }
490:
491: static int
492: floppyrecal(Drive *dp)
493: {
494: fl.intr = 0;
495: if(floppysend(Frecal) < 0
496: || floppysend(dp - fl.d) < 0){
497: DPRINT("recalibrate rejected\n");
498: fl.confused = 0;
499: return -1;
500: }
501: floppywait("recal");
502:
503: /*
504: * get return values
505: */
506: if(floppysense(dp) < 0)
507: return -1;
508:
509: /*
510: * see what cylinder we got to
511: */
512: dp->tcyl = 0;
513: dp->cyl = fl.stat[1]/dp->t->steps;
514: if(dp->cyl != dp->tcyl){
515: DPRINT("recalibrate went to wrong cylinder %d\n", dp->cyl);
516: dp->confused = 1;
517: return -1;
518: }
519:
520: dp->confused = 0;
521: return 0;
522: }
523:
524: long
525: floppyseek(int dev, long off)
526: {
527: Drive *dp;
528:
529: dp = &fl.d[dev];
530: floppyon(dp);
531: floppypos(dp, off);
532: if(dp->cyl == dp->tcyl){
533: dp->offset = off;
534: return off;
535: }
536:
537: /*
538: * tell floppy to seek
539: */
540: if(floppysend(Fseek) < 0
541: || floppysend((dp->thead<<2) | dp->dev) < 0
542: || floppysend(dp->tcyl * dp->t->steps) < 0){
543: DPRINT("seek cmd failed\n");
544: fl.confused = 1;
545: return -1;
546: }
547:
548: /*
549: * wait for interrupt
550: */
551: floppywait("seek");
552:
553: /*
554: * get floppy status
555: */
556: if(floppysense(dp) < 0)
557: return -1;
558:
559: /*
560: * see if it worked
561: */
562: if((fl.stat[0] & (Codemask|Seekend)) != Seekend){
563: DPRINT("seek failed\n");
564: dp->confused = 1;
565: return -1;
566: }
567:
568: /*
569: * see what cylinder we got to
570: */
571: dp->cyl = fl.stat[1]/dp->t->steps;
572: if(dp->cyl != dp->tcyl){
573: DPRINT("seek went to wrong cylinder %d instead of %d\n",
574: dp->cyl, dp->tcyl);
575: dp->confused = 1;
576: return -1;
577: }
578:
579: dp->offset = off;
580: DPRINT("seek to %d succeeded\n", dp->offset);
581: return dp->offset;
582: }
583:
584: static long
585: floppyxfer(Drive *dp, int cmd, void *a, long n)
586: {
587: ulong addr;
588: long offset;
589:
590: addr = (ulong)a;
591:
592: /*
593: * dma can't cross 64 k boundaries
594: */
595: if((addr & 0xffff0000) != ((addr+n) & 0xffff0000))
596: n -= (addr+n)&0xffff;
597:
598: dp->len = n;
599: if(floppyseek(dp->dev, dp->offset) < 0){
600: DPRINT("xfer seek failed\n");
601: return -1;
602: }
603:
604: DPRINT("floppy %d tcyl %d, thead %d, tsec %d, addr %lux, n %d\n",
605: dp->dev, dp->tcyl, dp->thead, dp->tsec, addr, n);/**/
606:
607: /*
608: * set up the dma
609: */
610: outb(DMAmode1, cmd==Fread ? 0x46 : 0x4a);
611: outb(DMAmode0, cmd==Fread ? 0x46 : 0x4a);
612: outb(DMAaddr, addr);
613: outb(DMAaddr, addr>>8);
614: outb(DMAtop, addr>>16);
615: outb(DMAcount, n-1);
616: outb(DMAcount, (n-1)>>8);
617: outb(DMAinit, 2);
618:
619: /*
620: * tell floppy to go
621: */
622: cmd = cmd | (dp->t->heads > 1 ? Fmulti : 0);
623: if(floppysend(cmd) < 0
624: || floppysend((dp->thead<<2) | dp->dev) < 0
625: || floppysend(dp->tcyl * dp->t->steps) < 0
626: || floppysend(dp->thead) < 0
627: || floppysend(dp->tsec) < 0
628: || floppysend(dp->t->bcode) < 0
629: || floppysend(dp->t->sectors) < 0
630: || floppysend(dp->t->gpl) < 0
631: || floppysend(0xFF) < 0){
632: DPRINT("xfer cmd failed\n");
633: fl.confused = 1;
634: return -1;
635: }
636:
637: floppywait("xfer");
638:
639: /*
640: * get status
641: */
642: if(floppyrdstat(7) < 0){
643: DPRINT("xfer status failed\n");
644: fl.confused = 1;
645: return -1;
646: }
647:
648: if((fl.stat[0] & Codemask)!=0 || fl.stat[1] || fl.stat[2]){
649: DPRINT("xfer failed %lux %lux %lux\n", fl.stat[0],
650: fl.stat[1], fl.stat[2]);
651: dp->confused = 1;
652: return -1;
653: }
654:
655: offset = (fl.stat[3]/dp->t->steps) * dp->t->heads + fl.stat[4];
656: offset = offset*dp->t->sectors + fl.stat[5] - 1;
657: offset = offset * c2b[fl.stat[6]];
658: if(offset != dp->offset+n){
659: DPRINT("new offset %d instead of %d\n", offset, dp->offset+dp->len);
660: dp->confused = 1;
661: return -1;/**/
662: }
663: dp->offset += dp->len;
664: return dp->len;
665: }
666:
667: long
668: floppyread(int dev, void *a, long n)
669: {
670: Drive *dp;
671: long rv, i, nn, offset, sec;
672: uchar *aa;
673: int tries;
674:
675: dp = &fl.d[dev];
676:
677: dp->len = n;
678: floppypos(dp, dp->offset);
679: offset = dp->offset;
680: sec = dp->tsec + dp->t->sectors*dp->thead;
681: n = dp->len;
682: if(fl.ccyl==dp->tcyl && fl.cdev==dev)
683: goto out;
684:
685: fl.ccyl = -1;
686: fl.cdev = dev;
687: aa = fl.ccache;
688: nn = dp->t->bytes*dp->t->sectors*dp->t->heads;
689: dp->offset = dp->tcyl*nn;
690: for(rv = 0; rv < nn; rv += i){
691: i = 0;
692: for(tries = 0; tries < dp->maxtries; tries++){
693: i = floppyxfer(dp, Fread, aa+rv, nn-rv);
694: if(i > 0)
695: break;
696: }
697: if(tries == dp->maxtries)
698: break;
699: }
700: if(rv != nn){
701: dp->confused = 1;
702: return -1;
703: }
704: fl.ccyl = dp->tcyl;
705: out:
706: memmove(a, fl.ccache + dp->t->bytes*(sec-1), n);
707: dp->offset = offset + n;
708: dp->maxtries = 3;
709: return n;
710: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.