They can come back when they have someone to support them.
[people/xl0/gpxe.git] / src / drivers / disk / pc_floppy.c
1 #include "etherboot.h"
2 #include "timer.h"
3 #include "disk.h"
4 #include "isa.h"
5
6
7 #undef MDEBUG
8
9 static int FD_BASE = 0x3f0;
10
11 #define FD_DRIVE 0
12
13 #define FD_STATUS_A     (FD_BASE + 0)   /* Status register A */
14 #define FD_STATUS_B     (FD_BASE + 1)   /* Status register B */
15 #define FD_DOR          (FD_BASE + 2)   /* Digital Output Register */
16 #define FD_TDR          (FD_BASE + 3)   /* Tape Drive Register */
17 #define FD_STATUS       (FD_BASE + 4)   /* Main Status Register */
18 #define FD_DSR          (FD_BASE + 4)   /* Data Rate Select Register (old) */
19 #define FD_DATA         (FD_BASE + 5)   /* Data Transfer (FIFO) register */
20 #define FD_DIR          (FD_BASE + 7)   /* Digital Input Register (read) */
21 #define FD_DCR          (FD_BASE + 7)   /* Diskette Control Register (write)*/
22
23 /* Bit of FD_STATUS_A */
24 #define STA_INT_PENDING 0x80            /* Interrupt Pending */
25
26 /* DOR */
27 #define DOR_DRIVE0      0x00
28 #define DOR_DRIVE1      0x01
29 #define DOR_DRIVE2      0x02
30 #define DOR_DRIVE3      0x03
31 #define DOR_DRIVE_MASK  0x03
32 #define DOR_NO_RESET    0x04
33 #define DOR_DMA_EN      0x08
34 #define DOR_MOT_EN0     0x10
35 #define DOR_MOT_EN1     0x20
36 #define DOR_MOT_EN2     0x40
37 #define DOR_MOT_EN3     0x80
38
39 /* Bits of main status register */
40 #define STATUS_BUSYMASK 0x0F            /* drive busy mask */
41 #define STATUS_BUSY     0x10            /* FDC busy */
42 #define STATUS_NON_DMA  0x20            /* 0- DMA mode */
43 #define STATUS_DIR      0x40            /* 0- cpu->fdc */
44 #define STATUS_READY    0x80            /* Data reg ready */
45
46 /* Bits of FD_ST0 */
47 #define ST0_DS          0x03            /* drive select mask */
48 #define ST0_HA          0x04            /* Head (Address) */
49 #define ST0_NR          0x08            /* Not Ready */
50 #define ST0_ECE         0x10            /* Equipment check error */
51 #define ST0_SE          0x20            /* Seek end */
52 #define ST0_INTR        0xC0            /* Interrupt code mask */
53 #define ST0_INTR_OK             (0 << 6)
54 #define ST0_INTR_ERROR          (1 << 6)
55 #define ST0_INTR_INVALID        (2 << 6)
56 #define ST0_INTR_POLL_ERROR     (3 << 6)
57
58 /* Bits of FD_ST1 */
59 #define ST1_MAM         0x01            /* Missing Address Mark */
60 #define ST1_WP          0x02            /* Write Protect */
61 #define ST1_ND          0x04            /* No Data - unreadable */
62 #define ST1_OR          0x10            /* OverRun */
63 #define ST1_CRC         0x20            /* CRC error in data or addr */
64 #define ST1_EOC         0x80            /* End Of Cylinder */
65
66 /* Bits of FD_ST2 */
67 #define ST2_MAM         0x01            /* Missing Address Mark (again) */
68 #define ST2_BC          0x02            /* Bad Cylinder */
69 #define ST2_SNS         0x04            /* Scan Not Satisfied */
70 #define ST2_SEH         0x08            /* Scan Equal Hit */
71 #define ST2_WC          0x10            /* Wrong Cylinder */
72 #define ST2_CRC         0x20            /* CRC error in data field */
73 #define ST2_CM          0x40            /* Control Mark = deleted */
74
75 /* Bits of FD_ST3 */
76 #define ST3_HA          0x04            /* Head (Address) */
77 #define ST3_DS          0x08            /* drive is double-sided */
78 #define ST3_TZ          0x10            /* Track Zero signal (1=track 0) */
79 #define ST3_RY          0x20            /* drive is ready */
80 #define ST3_WP          0x40            /* Write Protect */
81 #define ST3_FT          0x80            /* Drive Fault */
82
83 /* Values for FD_COMMAND */
84 #define FD_RECALIBRATE          0x07    /* move to track 0 */
85 #define FD_SEEK                 0x0F    /* seek track */
86 #define FD_READ                 0xA6    /* read with MT, SKip deleted */
87 #define FD_WRITE                0xC5    /* write with MT, MFM */
88 #define FD_SENSEI               0x08    /* Sense Interrupt Status */
89 #define FD_SPECIFY              0x03    /* specify HUT etc */
90 #define FD_FORMAT               0x4D    /* format one track */
91 #define FD_VERSION              0x10    /* get version code */
92 #define FD_CONFIGURE            0x13    /* configure FIFO operation */
93 #define FD_PERPENDICULAR        0x12    /* perpendicular r/w mode */
94 #define FD_GETSTATUS            0x04    /* read ST3 */
95 #define FD_DUMPREGS             0x0E    /* dump the contents of the fdc regs */
96 #define FD_READID               0xEA    /* prints the header of a sector */
97 #define FD_UNLOCK               0x14    /* Fifo config unlock */
98 #define FD_LOCK                 0x94    /* Fifo config lock */
99 #define FD_RSEEK_OUT            0x8f    /* seek out (i.e. to lower tracks) */
100 #define FD_RSEEK_IN             0xcf    /* seek in (i.e. to higher tracks) */
101
102
103 /* the following commands are new in the 82078. They are not used in the
104  * floppy driver, except the first three. These commands may be useful for apps
105  * which use the FDRAWCMD interface. For doc, get the 82078 spec sheets at
106  * http://www-techdoc.intel.com/docs/periph/fd_contr/datasheets/ */
107
108 #define FD_PARTID               0x18    /* part id ("extended" version cmd) */
109 #define FD_SAVE                 0x2e    /* save fdc regs for later restore */
110 #define FD_DRIVESPEC            0x8e    /* drive specification: Access to the
111                                          * 2 Mbps data transfer rate for tape
112                                          * drives */
113
114 #define FD_RESTORE              0x4e    /* later restore */
115 #define FD_POWERDOWN            0x27    /* configure FDC's powersave features */
116 #define FD_FORMAT_N_WRITE       0xef    /* format and write in one go. */
117 #define FD_OPTION               0x33    /* ISO format (which is a clean way to
118                                          * pack more sectors on a track) */
119
120 /* FDC version return types */
121 #define FDC_NONE        0x00
122 #define FDC_UNKNOWN     0x10    /* DO NOT USE THIS TYPE EXCEPT IF IDENTIFICATION
123                                    FAILS EARLY */
124 #define FDC_8272A       0x20    /* Intel 8272a, NEC 765 */
125 #define FDC_765ED       0x30    /* Non-Intel 1MB-compatible FDC, can't detect */
126 #define FDC_82072       0x40    /* Intel 82072; 8272a + FIFO + DUMPREGS */
127 #define FDC_82072A      0x45    /* 82072A (on Sparcs) */
128 #define FDC_82077_ORIG  0x51    /* Original version of 82077AA, sans LOCK */
129 #define FDC_82077       0x52    /* 82077AA-1 */
130 #define FDC_82078_UNKN  0x5f    /* Unknown 82078 variant */
131 #define FDC_82078       0x60    /* 44pin 82078 or 64pin 82078SL */
132 #define FDC_82078_1     0x61    /* 82078-1 (2Mbps fdc) */
133 #define FDC_S82078B     0x62    /* S82078B (first seen on Adaptec AVA-2825 VLB
134                                  * SCSI/EIDE/Floppy controller) */
135 #define FDC_87306       0x63    /* National Semiconductor PC 87306 */
136
137 /*
138  * Beware: the fdc type list is roughly sorted by increasing features.
139  * Presence of features is tested by comparing the FDC version id with the
140  * "oldest" version that has the needed feature.
141  * If during FDC detection, an obscure test fails late in the sequence, don't
142  * assign FDC_UNKNOWN. Else the FDC will be treated as a dumb 8272a, or worse.
143  * This is especially true if the tests are unneeded.
144  */
145
146 /* Parameters for a 1.44 3.5" disk */
147 #define DISK_H1440_SIZE       2880
148 #define DISK_H1440_SECT       18
149 #define DISK_H1440_HEAD       2
150 #define DISK_H1440_TRACK      80
151 #define DISK_H1440_STRETCH    0
152 #define DISK_H1440_GAP        0x1B
153 #define DISK_H1440_RATE       0x00
154 #define DISK_H1440_SPEC1      0xCF
155 #define DISK_H1440_FMT_GAP    0x6C
156
157 /* Parameters for a 1.44 3.5" drive */
158 #define DRIVE_H1440_MAX_DTR          500
159 #define DRIVE_H1440_HLT              16   /* ms */
160 #define DRIVE_H1440_HUT              16   /* ms */
161 #define DRIVE_H1440_SRT              4000 /* us */
162 #define DRIVE_H1440_SPINUP           400  /* ms */
163 #define DRIVE_H1440_SPINDOWN         3000 /* ms */
164 #define DRIVE_H1440_SPINDOWN_OFFSET  10
165 #define DRIVE_H1440_SELECT_DELAY     20  /* ms */
166 #define DRIVE_H1440_RPS              5
167 #define DRIVE_H1440_TRACKS           83
168 #define DRIVE_H1440_TIMEOUT          3000 /* ms */
169 #define DRIVE_H1440_INTERLEAVE_SECT  20
170
171 /* Floppy drive configuration */
172 #define FIFO_DEPTH            10
173 #define USE_IMPLIED_SEEK      0
174 #define USE_FIFO              1
175 #define FIFO_THRESHOLD        10
176 #define TRACK_PRECOMPENSATION 0
177
178 #define SLOW_FLOPPY 0
179
180 #define FD_RESET_DELAY 20 /* microseconds */
181
182 /*
183  * FDC state
184  */
185 struct drive_state {
186         unsigned track;
187 } drive_state[1];
188
189 struct floppy_fdc_state {       
190         int in_sync;
191         int spec1;              /* spec1 value last used */
192         int spec2;              /* spec2 value last used */
193         unsigned dtr;
194         unsigned char dor;
195         unsigned char version;  /* FDC version code */
196 } fdc_state;
197
198
199
200 /* Synchronization of FDC access. */
201 #define FD_COMMAND_NONE -1
202 #define FD_COMMAND_ERROR 2
203 #define FD_COMMAND_OKAY 3
204
205 /*
206  * globals used by 'result()'
207  */
208 #define MAX_REPLIES 16
209
210 static void show_floppy(void);
211 static void floppy_reset(void);
212
213
214 static int set_dor(char mask, char data)
215 {
216         unsigned char newdor,olddor;
217
218         olddor = fdc_state.dor;
219         newdor =  (olddor & mask) | data;
220         if (newdor != olddor){
221                 fdc_state.dor = newdor;
222                 outb(newdor, FD_DOR);
223         }
224         return olddor;
225 }
226
227
228 static void bounce_motor(void)
229 {
230         /* Bounce the drive motor... */
231         outb(fdc_state.dor & ~(0x10<<FD_DRIVE), FD_DOR);
232         outb(fdc_state.dor, FD_DOR);
233 }
234
235
236 /* waits until the fdc becomes ready */
237 static int wait_til_ready(void)
238 {
239         int counter, status;
240         for (counter = 0; counter < 10000; counter++) {
241 #if 1
242                 poll_interruptions();
243 #endif
244                 status = inb(FD_STATUS);                
245                 if (status & STATUS_READY) {
246                         return status;
247                 }
248         }
249 #ifdef MDEBUG
250         printf("Getstatus times out (%x)\n", status);
251 #endif
252         show_floppy();
253         return -3;
254 }
255
256
257 /* sends a command byte to the fdc */
258 static int output_byte(unsigned char byte)
259 {
260         int status;
261
262         if ((status = wait_til_ready()) < 0)
263                 return status;
264         if ((status & (STATUS_READY|STATUS_DIR|STATUS_NON_DMA)) == STATUS_READY){
265                 outb(byte,FD_DATA);
266                 return 0;
267         }
268 #ifdef MDEBUG
269         printf("Unable to send byte %x to FDC_STATE. Status=%x\n",
270                 byte, status);
271 #endif
272
273         show_floppy();
274         return -2;
275 }
276
277 /* gets the response from the fdc */
278 static int result(unsigned char *reply_buffer, int max_replies)
279 {
280         int i, status=0;
281
282         for(i=0; i < max_replies; i++) {
283                 if ((status = wait_til_ready()) < 0)
284                         break;
285                 status &= STATUS_DIR|STATUS_READY|STATUS_BUSY|STATUS_NON_DMA;
286                 if ((status & ~STATUS_BUSY) == STATUS_READY){
287                         return i;
288                 }
289                 if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY))
290                         reply_buffer[i] = inb(FD_DATA);
291                 else
292                         break;
293         }
294         if (i == max_replies)
295                 return i;
296 #ifdef MDEBUG
297         printf("get result error. Last status=%x Read bytes=%d\n",
298                 status, i);
299 #endif
300         show_floppy();
301         return -1;
302 }
303 #define MORE_OUTPUT -2
304 /* does the fdc need more output? */
305 static int need_more_output(void)
306 {
307         unsigned char reply_buffer[MAX_REPLIES];
308         int status;
309         if ((status = wait_til_ready()) < 0)
310                 return -1;
311         if ((status & (STATUS_READY|STATUS_DIR|STATUS_NON_DMA)) == STATUS_READY)
312                 return MORE_OUTPUT;
313         return result(reply_buffer, MAX_REPLIES);
314 }
315
316 static int output_command(unsigned char *cmd, int count)
317 {
318         int i, status;
319         for(i = 0; i < count; i++) {
320                 if ((status = output_byte(cmd[i])) < 0) {
321                         printf("full command not acceppted, status =%x\n", 
322                                 status);
323                         return -1;
324                 }
325         }
326         return 0;
327 }
328
329 static int output_new_command(unsigned char *cmd, int count)
330 {
331         int i, status;
332         if ((status = output_byte(cmd[0])) < 0)
333                 return -1;
334         if (need_more_output() != MORE_OUTPUT) 
335                 return -1;
336         for(i = 1; i < count; i++) {
337                 if ((status = output_byte(cmd[i])) < 0) {
338                         printf("full new command not acceppted, status =%d\n", 
339                                 status);
340                         return -1;
341                 }
342         }
343         return 0;
344 }
345
346
347 /* Collect pending interrupt status */
348 static unsigned char collect_interrupt(void)
349 {
350         unsigned char pcn = 0xff;
351         unsigned char reply_buffer[MAX_REPLIES];
352         int nr, i, status;
353         nr = result(reply_buffer, MAX_REPLIES);
354         if (nr != 0) {
355 #ifdef MDEBUG
356                 printf("SENSEI\n");
357 #endif
358         }
359         else {
360                 int max_sensei = 4;
361                 do {
362                         if (output_byte(FD_SENSEI) < 0) 
363                                 break;
364                         nr = result(reply_buffer, MAX_REPLIES);
365                         if (nr == 2) {
366                                 pcn = reply_buffer[1];
367 #ifdef MDEBUG
368                                 printf("SENSEI %hx %hx\n", 
369                                         reply_buffer[0], reply_buffer[1]);
370 #endif
371                         }
372 #if 0
373                 }while((nr == 2) && (reply_buffer[0] != 0x80));
374 #else
375                 }while(((reply_buffer[0] & 0x83) != FD_DRIVE) && (nr == 2) && max_sensei);
376 #endif
377                 status = inb(FD_STATUS);
378 #ifdef MDEBUG
379                 printf("status = %x, reply_buffer=", status);
380 #endif
381                 for(i = 0; i < nr; i++) {
382 #ifdef MDEBUG
383                         printf(" %x", reply_buffer[i]);
384 #endif
385                 }
386 #ifdef MDEBUG
387                 printf("\n");
388 #endif
389         }
390
391         return pcn;
392 }
393
394
395 /* selects the fdc and drive, and enables the fdc's input/dma, and it's motor. */
396 static void set_drive(int drive)
397 {
398         int fdc = (drive >> 2) & 1;
399         int status;
400         unsigned new_dor;
401         if (drive > 3) {
402                 printf("bad drive value\n");
403                 return;
404         }
405         if (fdc != 0) {
406                 printf("bad fdc value\n");
407                 return;
408         }
409         drive &= 3;
410 #if 0
411         new_dor = 8; /* Enable the controller */
412 #else
413         new_dor = 0; /* Don't enable DMA on the controller */
414 #endif
415         new_dor |= (1 << (drive + 4)); /* Spinup the selected drive */
416         new_dor |= drive; /* Select the drive for commands as well */
417         set_dor(0xc, new_dor);
418
419         mdelay(DRIVE_H1440_SPINUP);
420
421         status = inb(FD_STATUS);
422 #ifdef MDEBUG
423         printf("set_drive status = %hx, new_dor = %hx\n", status, new_dor);
424 #endif
425         if (status != STATUS_READY) {
426                 printf("set_drive bad status\n");
427         }
428 }
429
430
431 /* Disable the motor for a given floppy drive */
432 static void floppy_motor_off(int drive)
433 {
434         unsigned mask;
435 #ifdef MDEBUG
436         printf("floppy_motor_off\n");
437 #endif
438         /* fix the number of drives */
439         drive &= 3;
440         /* Clear the bit for the drive we care about */
441         mask = 0xff;
442         mask &= ~(1 << (drive +4));
443         /* Now clear the bit in the Digital Output Register */
444         set_dor(mask, 0);
445 }
446
447 /* Set the FDC's data transfer rate on behalf of the specified drive.
448  * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
449  * of the specify command (i.e. using the fdc_specify function).
450  */
451 static void fdc_dtr(unsigned rate)
452 {
453         rate &= 3;
454         /* If data rate not already set to desired value, set it. */
455         if (fdc_state.in_sync && (rate == fdc_state.dtr))
456                 return;
457
458         /* Set dtr */
459         outb(rate, FD_DCR);
460
461         /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
462          * need a stabilization period of several milliseconds to be
463          * enforced after data rate changes before R/W operations.
464          * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
465          */
466         fdc_state.dtr = rate & 3;
467         mdelay(5);
468 } /* fdc_dtr */
469
470 static int fdc_configure(int use_implied_seek, int use_fifo, 
471         unsigned fifo_threshold, unsigned precompensation)
472 {
473         unsigned config_bits;
474         unsigned char cmd[4];
475         /* 0 EIS EFIFO POLL FIFOOTHR[4] */
476
477         /* santize parameters */
478         config_bits = fifo_threshold & 0xf;
479         config_bits |= (1 << 4); /* Always disable background floppy poll */
480         config_bits |= (!use_fifo) << 5;
481         config_bits |= (!!use_implied_seek) << 6;
482
483         precompensation &= 0xff; /* pre-compensation from track 0 upwards */
484
485         cmd[0] = FD_CONFIGURE;
486         cmd[1] = 0;
487         cmd[2] = config_bits;
488         cmd[3] = precompensation;
489
490         /* Turn on FIFO */
491         if (output_new_command(cmd, 4) < 0)
492                 return 0;
493         return 1;
494 }       
495
496 #define NOMINAL_DTR 500
497 /* Issue a "SPECIFY" command to set the step rate time, head unload time,
498  * head load time, and DMA disable flag to values needed by floppy.
499  *
500  * The value "dtr" is the data transfer rate in Kbps.  It is needed
501  * to account for the data rate-based scaling done by the 82072 and 82077
502  * FDC types.  This parameter is ignored for other types of FDCs (i.e.
503  * 8272a).
504  *
505  * Note that changing the data transfer rate has a (probably deleterious)
506  * effect on the parameters subject to scaling for 82072/82077 FDCs, so
507  * fdc_specify is called again after each data transfer rate
508  * change.
509  *
510  * srt: 1000 to 16000 in microseconds
511  * hut: 16 to 240 milliseconds
512  * hlt: 2 to 254 milliseconds
513  *
514  * These values are rounded up to the next highest available delay time.
515  */
516 static void fdc_specify(
517         unsigned head_load_time, unsigned head_unload_time, unsigned step_rate)
518 {
519         unsigned char cmd[3];
520         unsigned long srt, hlt, hut;
521         unsigned long dtr = NOMINAL_DTR;
522         unsigned long scale_dtr = NOMINAL_DTR;
523         int hlt_max_code = 0x7f;
524         int hut_max_code = 0xf;
525
526 #ifdef MDEBUG
527         printf("fdc_specify\n");
528 #endif
529
530         switch (DISK_H1440_RATE & 0x03) {
531                 case 3:
532                         dtr = 1000;
533                         break;
534                 case 1:
535                         dtr = 300;
536                         if (fdc_state.version >= FDC_82078) {
537                                 unsigned char cmd[3];
538                                 /* chose the default rate table, not the one
539                                  * where 1 = 2 Mbps */
540                                 cmd[0] = FD_DRIVESPEC;
541                                 cmd[1] = FD_DRIVE & 3;
542                                 cmd[2] = 0xc0;
543                                 output_new_command(cmd,3);
544                                 /* FIXME how do I handle errors here? */
545                         }
546                         break;
547                 case 2:
548                         dtr = 250;
549                         break;
550         }
551
552
553         if (fdc_state.version >= FDC_82072) {
554                 scale_dtr = dtr;
555                 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
556                 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
557         }
558
559         /* Convert step rate from microseconds to milliseconds and 4 bits */
560         srt = 16 - (step_rate*scale_dtr/1000 + NOMINAL_DTR - 1)/NOMINAL_DTR;
561         if (SLOW_FLOPPY) {
562                 srt = srt / 4;
563         }
564         if (srt > 0xf) {
565                 srt = 0xf;
566         } 
567         if (srt < 0 ) {
568                 srt = 0;
569         }
570
571         hlt = (head_load_time*scale_dtr/2 + NOMINAL_DTR - 1)/NOMINAL_DTR;
572         if (hlt < 0x01)
573                 hlt = 0x01;
574         else if (hlt > 0x7f)
575                 hlt = hlt_max_code;
576
577         hut = (head_unload_time*scale_dtr/16 + NOMINAL_DTR - 1)/NOMINAL_DTR;
578         if (hut < 0x1)
579                 hut = 0x1;
580         else if (hut > 0xf)
581                 hut = hut_max_code;
582
583         cmd[0] = FD_SPECIFY;
584         cmd[1] = (srt << 4) | hut;
585         cmd[2] = (hlt << 1) | 1; /* Always disable DMA */
586
587         /* If these parameters did not change, just return with success */
588         if (!fdc_state.in_sync || fdc_state.spec1 != cmd[1] || fdc_state.spec2 != cmd[2]) {
589                 /* Go ahead and set spec1 and spec2 */
590                 output_command(cmd, 3);
591                 /* FIXME how do I handle errors here... */
592 #ifdef MDEBUG
593                 printf("FD_SPECIFY(%hx, %hx)\n", cmd[1], cmd[2]);
594 #endif
595         }
596 } /* fdc_specify */
597
598
599 /*
600  * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
601  * or by setting the self clearing bit 7 of STATUS (newer FDCs)
602  */
603 static void reset_fdc(void)
604 {
605         unsigned char reply[MAX_REPLIES];
606
607         fdc_state.in_sync = 0;
608
609         /* Pseudo-DMA may intercept 'reset finished' interrupt.  */
610         /* Irrelevant for systems with true DMA (i386).          */
611
612         if (fdc_state.version >= FDC_82072A)
613                 outb(0x80 | (fdc_state.dtr &3), FD_DSR);
614         else {
615                 outb(fdc_state.dor & ~DOR_NO_RESET, FD_DOR);
616                 udelay(FD_RESET_DELAY);
617                 outb(fdc_state.dor, FD_DOR);
618         }
619         result(reply, MAX_REPLIES);
620 }
621
622
623
624 static void show_floppy(void)
625 {
626
627 #ifdef MDEBUG
628         printf("\n");
629         printf("floppy driver state\n");
630         printf("-------------------\n");
631
632         printf("fdc_bytes: %hx %hx xx %hx %hx %hx xx %hx\n",
633                 inb(FD_BASE + 0), inb(FD_BASE + 1),
634                 inb(FD_BASE + 3), inb(FD_BASE + 4), inb(FD_BASE + 5), 
635                 inb(FD_BASE + 7));
636
637         printf("status=%x\n", inb(FD_STATUS));
638         printf("\n");
639 #endif
640 }
641
642 static void floppy_recalibrate(void)
643 {
644         unsigned char cmd[2];
645         unsigned char reply[MAX_REPLIES];
646         int nr, success;
647         success = 0;
648         do {
649 #ifdef MDEBUG
650                 printf("floppy_recalibrate\n");
651 #endif
652                 /* Send the recalibrate command to the controller.
653                  * We don't have interrupts or anything we can poll
654                  * so we have to guess when it is done.
655                  */
656                 cmd[0] = FD_RECALIBRATE;
657                 cmd[1] = 0;
658                 if (output_command(cmd, 2) < 0)
659                         continue;
660
661                 /* Sleep for the maximum time the recalibrate command
662                  * can run.
663                  */
664                 mdelay(80*DRIVE_H1440_SRT/1000);
665
666                 /* Now call FD_SENSEI to end the command
667                  * and collect up the reply.
668                  */
669                 if (output_byte(FD_SENSEI) < 0)
670                         continue;
671                 nr = result(reply, MAX_REPLIES);
672
673                 /* Now see if we have succeeded in our seek */
674                 success = 
675                         /* We have the right size result */
676                         (nr == 2) && 
677                         /* The command didn't terminate in error */
678                         ((reply[0] & ST0_INTR) == ST0_INTR_OK) &&
679                         /* We finished a seek */
680                         (reply[0] & ST0_SE) &&
681                         /* We are at cylinder 0 */
682                         (reply[1] == 0);
683         } while(!success);
684         /* Remember we are at track 0 */
685         drive_state[FD_DRIVE].track = 0;
686 }
687
688
689 static int __floppy_seek(unsigned track)
690 {
691         unsigned char cmd[3];
692         unsigned char reply[MAX_REPLIES];
693         int nr, success;
694         unsigned distance, old_track;
695
696         /* Look up the old track and see if we need to
697          * do anything.
698          */
699         old_track = drive_state[FD_DRIVE].track;
700         if (old_track == track) {
701                 return 1;
702         }
703
704         /* Compute the distance we are about to move,
705          * We need to know this so we know how long to sleep... 
706          */
707         distance = (old_track > track)?(old_track - track):(track - old_track);
708         distance += 1;
709
710        
711         /* Send the seek command to the controller.
712          * We don't have interrupts or anything we can poll
713          * so we have to guess when it is done.
714          */
715         cmd[0] = FD_SEEK;
716         cmd[1] = FD_DRIVE;
717         cmd[2] = track;
718         if (output_command(cmd, 3) < 0)
719                 return 0;
720         
721         /* Sleep for the time it takes to step through distance tracks.
722          */
723         mdelay(distance*DRIVE_H1440_SRT/1000);
724
725         /* Now call FD_SENSEI to end the command
726          * and collect up the reply.
727          */
728         cmd[0] = FD_SENSEI;
729         if (output_command(cmd, 1) < 0)
730                 return 0;
731         nr = result(reply, MAX_REPLIES);
732
733         /* Now see if we have succeeded in our seek */
734         success = 
735                 /* We have the right size result */
736                 (nr == 2) && 
737                 /* The command didn't terminate in error */
738                 ((reply[0] & ST0_INTR) == ST0_INTR_OK) &&
739                 /* We finished a seek */
740                 (reply[0] & ST0_SE) &&
741                 /* We are at cylinder 0 */
742                 (reply[1] == track);
743         if (success)
744                 drive_state[FD_DRIVE].track = track;
745         else {
746 #ifdef MDEBUG
747                 printf("seek failed\n");
748                 printf("nr = %d\n", nr);
749                 printf("ST0 = %hx\n", reply[0]);
750                 printf("PCN = %hx\n", reply[1]);
751                 printf("status = %d\n", inb(FD_STATUS));
752 #endif
753         }
754         return success;
755 }
756
757 static int floppy_seek(unsigned track)
758 {
759         unsigned old_track;
760         int result;
761         /* assume success */
762         result = 1;
763
764         /* Look up the old track and see if we need to
765          * do anything.
766          */
767         old_track = drive_state[FD_DRIVE].track;
768         if (old_track == track) {
769                 return result;
770         }
771         /* For some reason seeking many tracks at once is
772          * problematic so only seek a single track at a time.
773          */
774         while(result && (old_track > track)) {
775                 old_track--;
776                 result = __floppy_seek(old_track);
777         }
778         while(result && (track > old_track)) {
779                 old_track++;
780                 result = __floppy_seek(old_track);
781         }
782         return result;
783 }
784
785 static int read_ok(unsigned head)
786 {
787         unsigned char results[7];
788         int result_ok;
789         int nr;
790
791         /* read back the read results */
792         nr = result(results, 7);
793
794         /* Now see if they say we are o.k. */
795         result_ok = 0;
796         /* Are my result bytes o.k.? */
797         if (nr == 7) {
798                 /* Are we o.k. */
799                 if ((results[0] & ST0_INTR) == ST0_INTR_OK) {
800                         result_ok = 1;
801                 }
802                 /* Or did we get just an overflow error */
803                 else if (((results[0] & ST0_INTR) == ST0_INTR_ERROR) && 
804                         (results[1]== ST1_OR) &&
805                         (results[2] == 0)) {
806                         result_ok = 1;
807                 }
808                 /* Verify the reply had the correct head */
809                 if (((results[0] & ST0_HA) >> 2) != head) {
810                         result_ok = 0;
811                 }
812                 /* Verify the reply had the correct drive */
813                 if (((results[0] & ST0_DS) != FD_DRIVE)) {
814                         result_ok = 0;
815                 }
816         }
817         if (!result_ok) {
818 #ifdef MDEBUG
819                 printf("result_bytes = %d\n", nr);
820                 printf("ST0 = %hx\n", results[0]);
821                 printf("ST1 = %hx\n", results[1]);
822                 printf("ST2 = %hx\n", results[2]);
823                 printf("  C = %hx\n", results[3]);
824                 printf("  H = %hx\n", results[4]);
825                 printf("  R = %hx\n", results[5]);
826                 printf("  N = %hx\n", results[6]);
827 #endif
828         }
829         return result_ok;
830 }
831
832 static int floppy_read_sectors(
833         char *dest, unsigned byte_offset, unsigned length,
834         unsigned sector, unsigned head, unsigned track)
835 {
836         /* MT  == Multitrack */
837         /* MFM == MFM or FM Mode */
838         /* SK  == Skip deleted data addres Mark */
839         /* HDS == Head number select */
840         /* DS0 == Disk Drive Select 0 */
841         /* DS1 == Disk Drive Select 1 */
842         /* C   == Cylinder number 0 - 255 */
843         /* H   == Head number */
844         /* R   == Record */
845         /* N   == The number of data bytes written in a sector */
846         /* EOT == End of Track */
847         /* GPL == Gap Length */
848         /* DTL == Data Length */
849         /* MT MFM  SK  0 1 1   0   0 */
850         /* 0  0    0   0 0 HDS DS1 DS0 */
851         /* C, H, R, N, EOT, GPL, DTL */
852
853         int i, status, result_ok;
854         int max_bytes, bytes_read;
855         int ret;
856         unsigned char cmd[9];
857         unsigned end_offset;
858
859         end_offset = byte_offset + length;
860         max_bytes = 512*(DISK_H1440_SECT - sector + 1);
861
862         if (byte_offset >= max_bytes) {
863                 return 0;
864         }
865         cmd[0] = FD_READ | (((DISK_H1440_HEAD ==2)?1:0) << 6);
866         cmd[1] = (head << 2) | FD_DRIVE;
867         cmd[2] = track;
868         cmd[3] = head;
869         cmd[4] = sector;
870         cmd[5] = 2; /* 2^N *128 == Sector size.  Hard coded to 512 bytes */
871         cmd[6] = DISK_H1440_SECT;
872         cmd[7] = DISK_H1440_GAP;
873         cmd[8] = 0xff;
874
875         /* Output the command bytes */
876         if (output_command(cmd, 9) < 0)
877                 return -1;
878
879         /* The execution stage begins when STATUS_READY&STATUS_NON_DMA is set */
880         do {
881 #if 1
882                 poll_interruptions();
883 #endif
884                 status = inb(FD_STATUS);
885                 status &= STATUS_READY | STATUS_NON_DMA;
886         } while(status != (STATUS_READY|STATUS_NON_DMA));
887
888         for(i = 0; i < max_bytes; i++) {
889                 unsigned char byte;
890                 if ((status = wait_til_ready()) < 0) {
891                         break;
892                 }
893                 status &= STATUS_READY|STATUS_DIR|STATUS_NON_DMA;
894                 if (status != (STATUS_READY|STATUS_DIR|STATUS_NON_DMA)) {
895                         break;
896                 }
897                 byte = inb(FD_DATA);
898                 if ((i >= byte_offset) && (i < end_offset)) {
899                         dest[i - byte_offset] = byte;
900                 }
901         }
902         bytes_read = i;
903         
904         /* The result stage begins when STATUS_NON_DMA is cleared */
905         while((status = inb(FD_STATUS)) & STATUS_NON_DMA) {
906                 /* We get extra bytes in the fifo  past
907                  * the end of the sector and drop them on the floor.
908                  * Otherwise the fifo is polluted.
909                  */
910                 inb(FD_DATA);
911         }
912         /* Did I get an error? */
913         result_ok = read_ok(head);
914         /* Did I read enough bytes? */
915         ret = -1;
916         if (result_ok && (bytes_read == max_bytes)) {
917                 ret = bytes_read - byte_offset;
918                 if (ret > length) {
919                         ret = length;
920                 }
921         }
922         
923         if (ret < 0) {
924 #ifdef MDEBUG
925                 printf("ret = %d\n", ret);
926                 printf("bytes_read = %d\n", bytes_read);
927                 printf("status = %x\n", status);
928 #endif
929         }
930         return ret;
931 }
932
933 static int floppy_read(struct disk *disk, sector_t base_sector)
934 {
935         unsigned head, track, sector, byte_offset;
936         unsigned long block;
937         int ret;
938
939         disk->sector = 0;
940         disk->bytes  = 0;
941
942         block = base_sector;
943         block /= disk->sectors_per_read;
944
945         /* break the offset up into sectors and bytes */
946         byte_offset = 0;
947
948         /* Find the disk block we are starting with... */
949         sector = 1;
950         head = block % DISK_H1440_HEAD;
951         track = (block / DISK_H1440_HEAD)% DISK_H1440_TRACK;
952
953         /* First seek to our start track */
954         if (!floppy_seek(track)) {
955                 return -1;
956         }
957         /* Then read the data */
958         ret = floppy_read_sectors(
959                 disk->buffer, byte_offset, SECTOR_SIZE*disk->sectors_per_read, sector, head, track);
960         if (ret >= 0) {
961                 disk->sector = block * disk->sectors_per_read;
962                 disk->bytes = SECTOR_SIZE * disk->sectors_per_read;
963                 return ret;
964         }
965         /* If we failed reset the fdc... */
966         floppy_reset();
967         return -1;
968 }
969
970 /* Determine the floppy disk controller type */
971 /* This routine was written by David C. Niemi */
972 static char get_fdc_version(void)
973 {
974         int bytes, ret;
975         unsigned char reply_buffer[MAX_REPLIES];
976         
977         ret = output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
978         if (ret < 0)
979                 return FDC_NONE;
980         if ((bytes = result(reply_buffer, MAX_REPLIES)) <= 0x00)
981                 return FDC_NONE;        /* No FDC present ??? */
982         if ((bytes==1) && (reply_buffer[0] == 0x80)){
983                 printf("FDC %d is an 8272A\n");
984                 return FDC_8272A;       /* 8272a/765 don't know DUMPREGS */
985         }
986         if (bytes != 10) {
987 #ifdef MDEBUG
988                 printf("init: DUMPREGS: unexpected return of %d bytes.\n",
989                         bytes);
990 #endif
991                 return FDC_UNKNOWN;
992         }
993         if (!fdc_configure(USE_IMPLIED_SEEK, USE_FIFO, FIFO_THRESHOLD,
994                 TRACK_PRECOMPENSATION)) {
995                 printf("FDC is an 82072\n");
996                 return FDC_82072;       /* 82072 doesn't know CONFIGURE */
997         }
998
999         output_byte(FD_PERPENDICULAR);
1000         if (need_more_output() == MORE_OUTPUT) {
1001                 output_byte(0);
1002         } else {
1003                 printf("FDC is an 82072A\n");
1004                 return FDC_82072A;      /* 82072A as found on Sparcs. */
1005         }
1006
1007         output_byte(FD_UNLOCK);
1008         bytes = result(reply_buffer, MAX_REPLIES);
1009         if ((bytes == 1) && (reply_buffer[0] == 0x80)){
1010                 printf("FDC is a pre-1991 82077\n");
1011                 return FDC_82077_ORIG;  /* Pre-1991 82077, doesn't know 
1012                                          * LOCK/UNLOCK */
1013         }
1014         if ((bytes != 1) || (reply_buffer[0] != 0x00)) {
1015 #ifdef MDEBUG
1016                 printf("FDC init: UNLOCK: unexpected return of %d bytes.\n", 
1017                         bytes);
1018 #endif
1019                 return FDC_UNKNOWN;
1020         }
1021         output_byte(FD_PARTID);
1022         bytes = result(reply_buffer, MAX_REPLIES);
1023         if (bytes != 1) {
1024 #ifdef MDEBUG
1025                 printf("FDC init: PARTID: unexpected return of %d bytes.\n",
1026                         bytes);
1027 #endif
1028                 return FDC_UNKNOWN;
1029         }
1030         if (reply_buffer[0] == 0x80) {
1031                 printf("FDC is a post-1991 82077\n");
1032                 return FDC_82077;       /* Revised 82077AA passes all the tests */
1033         }
1034         switch (reply_buffer[0] >> 5) {
1035         case 0x0:
1036                 /* Either a 82078-1 or a 82078SL running at 5Volt */
1037                 printf("FDC is an 82078.\n");
1038                 return FDC_82078;
1039         case 0x1:
1040                 printf("FDC is a 44pin 82078\n");
1041                 return FDC_82078;
1042         case 0x2:
1043                 printf("FDC is a S82078B\n");
1044                 return FDC_S82078B;
1045         case 0x3:
1046                 printf("FDC is a National Semiconductor PC87306\n");
1047                 return FDC_87306;
1048         default:
1049                 printf("FDC init: 82078 variant with unknown PARTID=%d.\n",
1050                         reply_buffer[0] >> 5);
1051                 return FDC_82078_UNKN;
1052         }
1053 } /* get_fdc_version */
1054
1055
1056 static int floppy_init(void)
1057 {
1058 #ifdef MDEBUG
1059         printf("floppy_init\n");
1060 #endif
1061         fdc_state.in_sync = 0;
1062         fdc_state.spec1 = -1;
1063         fdc_state.spec2 = -1;
1064         fdc_state.dtr = -1;
1065         fdc_state.dor = DOR_NO_RESET;
1066         fdc_state.version = FDC_UNKNOWN;
1067         reset_fdc();
1068         /* Try to determine the floppy controller type */
1069         fdc_state.version = get_fdc_version();
1070         if (fdc_state.version == FDC_NONE) {
1071                 return -1;
1072         }
1073         floppy_reset();
1074 #ifdef MDEBUG
1075         printf("fdc_state.version = %x\n", fdc_state.version);
1076 #endif
1077         return 0;
1078 }
1079
1080 static void floppy_reset(void)
1081 {
1082 #ifdef MDEBUG
1083         printf("floppy_reset\n");
1084 #endif
1085         floppy_motor_off(FD_DRIVE);
1086         reset_fdc();
1087         fdc_dtr(DISK_H1440_RATE);
1088         /* program data rate via ccr */
1089         collect_interrupt();
1090         fdc_configure(USE_IMPLIED_SEEK, USE_FIFO, FIFO_THRESHOLD, 
1091                 TRACK_PRECOMPENSATION);
1092         fdc_specify(DRIVE_H1440_HLT, DRIVE_H1440_HUT, DRIVE_H1440_SRT);
1093         set_drive(FD_DRIVE);
1094         floppy_recalibrate();
1095         fdc_state.in_sync = 1;
1096 }
1097
1098 static void floppy_fini(struct dev *dev __unused)
1099 {
1100         /* Disable the floppy and the floppy drive controller */
1101         set_dor(0, 0);
1102 }
1103
1104 static int floppy_probe(struct dev *dev, unsigned short *probe_addrs)
1105 {
1106         struct disk *disk = (struct disk *)dev;
1107         unsigned short addr;
1108         int index;
1109
1110         if (!probe_addrs || !*probe_addrs)
1111                 return 0;
1112         index = dev->index +1;
1113         if (dev->how_probe == PROBE_AWAKE) {
1114                 index--;
1115         }
1116         for(; (index >= 0) && (addr = probe_addrs[index]); index++) {
1117                 /* FIXME handle multiple drives per controller */
1118                 /* FIXME test to see if I have a drive or a disk in
1119                  * the driver during the probe routine.
1120                  */
1121                 /* FIXME make this work under the normal bios */
1122                 FD_BASE = addr;
1123                 if (floppy_init() != 0) {
1124                         /* nothing at this address */
1125                         continue;
1126                 }
1127                 /* O.k. I have a floppy controller */
1128                 disk->hw_sector_size   = SECTOR_SIZE;
1129                 disk->sectors_per_read = DISK_H1440_SECT;
1130                 disk->sectors          = DISK_H1440_HEAD*DISK_H1440_TRACK*DISK_H1440_SECT;
1131                 dev->index             = index;
1132                 dev->disable           = floppy_fini;
1133                 disk->read             = floppy_read;
1134                 return 1;
1135         }
1136         dev->index = -1;
1137         return 0;
1138 }
1139
1140 static unsigned short floppy_ioaddrs[] =
1141 {
1142         0x3F0, 0x370, 0
1143 };
1144 ISA_ROM("pc_floppy", "Generic PC Floppy support")
1145
1146 static struct isa_driver floppy_isa_driver __isa_driver = {
1147         .type    = FLOPPY_DRIVER,
1148         .name    = "PC flopyy",
1149         .probe   = floppy_probe,
1150         .ioaddrs = floppy_ioaddrs,
1151 };