]> 4ch.mooo.com Git - 16.git/blob - src/lib/doslib/hw/floppy/test.c
added a bunch of things~ and midi stuff~
[16.git] / src / lib / doslib / hw / floppy / test.c
1
2 #include <stdio.h>
3 #include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
4 #include <stdlib.h>
5 #include <string.h>
6 #include <unistd.h>
7 #include <malloc.h>
8 #include <ctype.h>
9 #include <fcntl.h>
10 #include <dos.h>
11
12 #include <hw/vga/vga.h>
13 #include <hw/dos/dos.h>
14 #include <hw/8237/8237.h>               /* DMA controller */
15 #include <hw/8254/8254.h>               /* 8254 timer */
16 #include <hw/8259/8259.h>               /* 8259 PIC interrupts */
17 #include <hw/vga/vgagui.h>
18 #include <hw/vga/vgatty.h>
19 #include <hw/dos/doswin.h>
20
21 #define MAX_FLOPPY_CONTROLLER 4
22
23 struct floppy_controller {
24         uint16_t                base_io;
25         int8_t                  irq;
26         int8_t                  dma;
27
28         /* known state */
29         uint8_t                 ps2_status[2];          /* 0x3F0-0x3F1 */
30         uint8_t                 st[4];                  /* ST0...ST3 */
31                                                         /*  Status Register ST0 */
32                                                         /*     [7:6] IC (Interrupt code) */
33                                                         /*            00 = normal termination, no errors */
34                                                         /*            01 = abnormal termination */
35                                                         /*            10 = invalid command */
36                                                         /*            11 = abnormal termination by polling */
37                                                         /*     [5:5] Seek end */
38                                                         /*     [4:4] Unit check */
39                                                         /*     [3:3] Drive not ready */
40                                                         /*     [2:2] Head currently active */
41                                                         /*     [1:0] Currently selected drive */
42                                                         /*  Status Register ST1 */
43                                                         /*     [7:7] End of Cylinder */
44                                                         /*     [6:6] always 0 */
45                                                         /*     [5:5] Data error */
46                                                         /*     [4:4] Time out (data overrun) */
47                                                         /*     [3:3] always 0 */
48                                                         /*     [2:2] No data */
49                                                         /*     [1:1] Not writeable */
50                                                         /*     [0:0] No address mark */
51                                                         /*  Status Register ST2 */
52                                                         /*     [7:7] always 0 */
53                                                         /*     [6:6] Deleted Address Mark */
54                                                         /*     [5:5] CRC error in data field */
55                                                         /*     [4:4] Wrong Cylinder */
56                                                         /*     [3:3] Seek equal */
57                                                         /*     [2:2] Seek error */
58                                                         /*     [1:1] Bad cylinder */
59                                                         /*     [0:0] Not data address mark DAM */
60                                                         /*  Status Register ST3 */
61                                                         /*     [7:7] Error, drive error signal is active */
62                                                         /*     [6:6] Write protection */
63                                                         /*     [5:5] Ready, drive ready signal is active */
64                                                         /*     [4:4] Track 0 */
65                                                         /*     [3:3] Double sided drive */
66                                                         /*     [2:2] HDSEL (head select) signal from drive */
67                                                         /*     [1:0] Drive select */
68         uint8_t                 digital_out;            /* last value written to 0x3F2 */
69                                                         /*     [7:7] MOTD (Motor control, drive D) */
70                                                         /*     [6:6] MOTC (Motor control, drive C) */
71                                                         /*     [5:5] MOTB (Motor control, drive B) */
72                                                         /*     [4:4] MOTA (Motor control, drive A) */
73                                                         /*     [3:3] DMA (DMA+IRQ enable) */
74                                                         /*     [2:2] !REST (Controller reset) 1=enable 0=reset */
75                                                         /*     [1:0] Drive select (0=A 1=B 2=C 3=D) */
76         uint8_t                 main_status;            /* last value read from 0x3F4 */
77                                                         /*     [7:7] MRQ (Main request) 1=data register ready */
78                                                         /*     [6:6] DIO (Data input/output) 1=expecting CPU read 0=expecting CPU write */
79                                                         /*     [5:5] NDMA (non-DMA mode) 1=not in DMA mode */
80                                                         /*     [4:4] BUSY (instruction, device busy) 1=active */
81                                                         /*     [3:3] ACTD Drive D in positioning mode */
82                                                         /*     [2:2] ACTC Drive C in positioning mode */
83                                                         /*     [1:1] ACTB Drive B in positioning mode */
84                                                         /*     [0:0] ACTA Drive A in positioning mode */
85         uint8_t                 digital_in;             /* last value read from 0x3F7 */
86                                                         /*     [7:7] CHAN (Disk Change) 1=disk changed since last command  (PS/2 model 30 bit is inverted) */
87                                                         /* * PS/2 except Model 30 */
88                                                         /*     [6:3] all 1's */
89                                                         /* * PS/2 Model 30 */
90                                                         /*     [6:4] all 0's */
91         uint8_t                 control_cfg;            /* last value written to 0x3F7 */
92                                                         /*     [1:0] Data transfer rate */
93                                                         /*            11 = 1 mbit/sec */
94                                                         /*            10 = 250 kbit/sec */
95                                                         /*            01 = 300 kbit/sec */
96                                                         /*            00 = 500 kbit/sec */
97         uint8_t                 cylinder;               /* last known cylinder position */
98         uint16_t                irq_fired;
99
100         /* desired state */
101         uint8_t                 use_irq:1;              /* if set, use IRQ. else. ??? */
102         uint8_t                 use_dma:1;              /* if set, use DMA. else, use PIO data transfer */
103         uint8_t                 use_implied_seek:1;     /* if set, act like controller has Implied Seek enabled */
104
105         /* what we know about the controller */
106         uint8_t                 version;                /* result of command 0x10 (determine controller version) or 0x00 if not yet queried */
107         uint8_t                 ps2_mode:1;             /* controller is in PS/2 mode (has status registers A and B I/O ports) */
108         uint8_t                 at_mode:1;              /* controller is in AT mode (has Digital Input Register and Control Config Reg) */
109         uint8_t                 digital_out_rw:1;       /* digital out (0x3F2) is readable */
110         uint8_t                 non_dma_mode:1;         /* "ND" bit in Dump Regs */
111         uint8_t                 implied_seek:1;         /* "EIS" bit in Dump Regs */
112         uint8_t                 current_srt:4;
113         uint8_t                 current_hut:4;
114         uint8_t                 current_hlt;
115 };
116
117 /* standard I/O ports for floppy controllers */
118 struct floppy_controller                floppy_standard_isa[2] = {
119         /*base, IRQ, DMA*/
120         {0x3F0, 6,   2},
121         {0x370, 6,   2}
122 };
123
124 struct floppy_controller *floppy_get_standard_isa_port(int x) {
125         if (x < 0 || x >= (sizeof(floppy_standard_isa)/sizeof(floppy_standard_isa[0]))) return NULL;
126         return &floppy_standard_isa[x];
127 }
128
129 struct dma_8237_allocation*             floppy_dma = NULL; /* DMA buffer */
130
131 struct floppy_controller                floppy_controllers[MAX_FLOPPY_CONTROLLER];
132 int8_t                                  floppy_controllers_init = -1;
133
134 struct floppy_controller *floppy_get_controller(int x) {
135         if (x < 0 || x >= MAX_FLOPPY_CONTROLLER) return NULL;
136         if (floppy_controllers[x].base_io == 0) return NULL;
137         return &floppy_controllers[x];
138 }
139
140 int wait_for_enter_or_escape() {
141         int c;
142
143         do {
144                 c = getch();
145                 if (c == 0) c = getch() << 8;
146         } while (!(c == 13 || c == 27));
147
148         return c;
149 }
150
151 struct floppy_controller *alloc_floppy_controller() {
152         unsigned int i=0;
153
154         while (i < MAX_FLOPPY_CONTROLLER) {
155                 if (floppy_controllers[i].base_io == 0)
156                         return &floppy_controllers[i];
157         }
158
159         return NULL;
160 }
161
162 void floppy_controller_read_ps2_status(struct floppy_controller *i) {
163         if (i->ps2_mode) {
164                 i->ps2_status[0] = inp(i->base_io+0);
165                 i->ps2_status[1] = inp(i->base_io+1);
166         }
167         else {
168                 i->ps2_status[0] = i->ps2_status[1] = 0xFF;
169         }
170 }
171
172 static inline uint8_t floppy_controller_read_status(struct floppy_controller *i) {
173         i->main_status = inp(i->base_io+4); /* 0x3F4 main status */
174         return i->main_status;
175 }
176
177 static inline uint8_t floppy_controller_read_DIR(struct floppy_controller *i) {
178         if (i->at_mode || i->ps2_mode)
179                 i->digital_in = inp(i->base_io+7); /* 0x3F7 */
180         else
181                 i->digital_in = 0xFF;
182
183         return i->digital_in;
184 }
185
186 static inline void floppy_controller_write_DOR(struct floppy_controller *i,unsigned char c) {
187         i->digital_out = c;
188         outp(i->base_io+2,c);   /* 0x3F2 Digital Output Register */
189 }
190
191 static inline void floppy_controller_write_CCR(struct floppy_controller *i,unsigned char c) {
192         i->control_cfg = c;
193         outp(i->base_io+7,c);   /* 0x3F7 Control Configuration Register */
194 }
195
196 void floppy_controller_set_data_transfer_rate(struct floppy_controller *i,unsigned char rsel) {
197         if (rsel > 3) return;
198         floppy_controller_write_CCR(i,(i->control_cfg & ~3) + rsel); /* change bits [1:0] */
199 }
200
201 void floppy_controller_drive_select(struct floppy_controller *i,unsigned char drv) {
202         if (drv > 3) return;
203
204         i->digital_out &= ~0x03;
205         i->digital_out |= drv;
206         outp(i->base_io+2,i->digital_out);      /* 0x3F2 Digital Output Register */
207 }
208
209 void floppy_controller_set_motor_state(struct floppy_controller *i,unsigned char drv,unsigned char set) {
210         if (drv > 3) return;
211
212         i->digital_out &= ~(0x10 << drv);
213         i->digital_out |= (set?(0x10 << drv):0x00);
214         outp(i->base_io+2,i->digital_out);      /* 0x3F2 Digital Output Register */
215 }
216
217 void floppy_controller_enable_dma(struct floppy_controller *i,unsigned char set) {
218         if (i->dma < 0) set = 0;
219         i->use_dma = !!set;
220
221         /* 82077AA refers to this bit as "!DMAGATE", and only in AT mode.
222          * Setting it gates both the IRQ and DMA. It says it has no effect
223          * in PS/2 mode. Doh! */
224         i->digital_out &= ~0x08;
225         i->digital_out |= ((i->use_irq || i->use_dma)?0x08:0x00);
226         outp(i->base_io+2,i->digital_out);      /* 0x3F2 Digital Output Register */
227 }
228
229 void floppy_controller_enable_irq(struct floppy_controller *i,unsigned char set) {
230         if (i->irq < 0) set = 0;
231         i->use_irq = !!set;
232
233         /* 82077AA refers to this bit as "!DMAGATE", and only in AT mode.
234          * Setting it gates both the IRQ and DMA. It says it has no effect
235          * in PS/2 mode. Doh! */
236         i->digital_out &= ~0x08;
237         i->digital_out |= ((i->use_irq || i->use_dma)?0x08:0x00);
238         outp(i->base_io+2,i->digital_out);      /* 0x3F2 Digital Output Register */
239 }
240
241 void floppy_controller_enable_irqdma_gate_otr(struct floppy_controller *i,unsigned char set) {
242         unsigned char c;
243
244         c = i->digital_out;
245         c &= ~0x08;
246         c |= (set?0x08:0x00);
247         outp(i->base_io+2,c);                   /* 0x3F2 Digital Output Register */
248 }
249
250 void floppy_controller_set_reset(struct floppy_controller *i,unsigned char set) {
251         i->digital_out &= ~0x04;
252         i->digital_out |= (set?0x00:0x04);      /* bit is INVERTED (0=reset 1=normal) */
253         outp(i->base_io+2,i->digital_out);      /* 0x3F2 Digital Output Register */
254 }
255
256 struct floppy_controller *floppy_controller_probe(struct floppy_controller *i) {
257         struct floppy_controller *ret = NULL;
258         uint8_t t1;
259
260         if (i == NULL) return NULL;
261         if (i->base_io == 0) return NULL;
262
263         /* is anything there? the best we can hope for is to probe the I/O port range and see if SOMETHING responds */
264         t1 = inp(i->base_io+4); /* main status register (we can't assume the ability to read the digital output register, the data reg might be 0xFF) */
265         if (t1 == 0xFF) return NULL;
266
267         ret = alloc_floppy_controller();
268         if (ret == NULL) return NULL;
269         memset(ret,0,sizeof(*ret));
270
271         ret->base_io = i->base_io;
272         if (i->irq >= 2 && i->irq <= 15)
273                 ret->irq = i->irq;
274         else
275                 ret->irq = -1;
276
277         if (i->dma >= 0 && i->dma <= 7)
278                 ret->dma = i->dma;
279         else
280                 ret->dma = -1;
281
282         ret->use_dma = (ret->dma >= 0);
283         ret->use_irq = (ret->irq >= 0);
284
285         /* assume middle-of-the-road defaults */
286         ret->current_srt = 8;           /* 4/8/14/16ms for 1M/500K/300K/250K */
287         ret->current_hut = 8;           /* 64/128/213/256 for 1M/500K/300K/250K */
288         ret->current_hlt = 0x40;        /* 64/128/213/256 for 1M/500K/300K/250K */
289
290         /* assume controller has ND (Non-DMA) and EIS (implied seek) turned off.
291          * most BIOSes do that. */
292
293         /* if something appears at 0x3F0-0x3F1, assume "PS/2 mode".
294          * there are finer intricate details where the meaning of some bits
295          * completely change or invert their meaning between PS/2 and Model 30,
296          * so we don't concern ourself with them, we only care that there's
297          * something there and we can let the program using this lib figure it out. */
298         t1 = inp(ret->base_io+0);
299         t1 &= inp(ret->base_io+1);
300         if (t1 != 0xFF) ret->ps2_mode = 1;
301
302         /* what about the AT & PS/2 style CCR & DIR */
303         t1 = inp(ret->base_io+7);
304         if (t1 != 0xFF) ret->at_mode = 1;
305
306         /* and ... guess */
307         floppy_controller_write_DOR(ret,0x04+(ret->use_irq?0x08:0x00)); /* most BIOSes: DMA/IRQ enable, !reset, motor off, drive A select */
308         floppy_controller_read_status(ret);
309
310         /* is the Digital Out port readable? */
311         t1 = inp(ret->base_io+2);
312         if (t1 == ret->digital_out) ret->digital_out_rw = 1;
313
314         floppy_controller_read_DIR(ret);
315
316         return ret;
317 }
318
319 int init_floppy_controller_lib() {
320         if (floppy_controllers_init < 0) {
321                 memset(floppy_controllers,0,sizeof(floppy_controllers));
322                 floppy_controllers_init = 0;
323
324                 cpu_probe();
325                 probe_dos();
326                 detect_windows();
327
328                 /* do NOT under any circumstances talk directly to the floppy from under Windows! */
329                 if (windows_mode != WINDOWS_NONE) return (floppy_controllers_init=0);
330
331                 /* init OK */
332                 floppy_controllers_init = 1;
333         }
334
335         return floppy_controllers_init;
336 }
337
338 void free_floppy_controller_lib() {
339 }
340
341 /*------------------------------------------------------------------------*/
342
343 char    tmp[1024];
344
345 /* "current position" */
346 static int current_log_sect = 1;
347 static int current_log_head = 0;
348 static int current_phys_head = 0;
349 static int current_log_track = 0;
350 static int current_phys_rw_gap = 0x1B;          /* gap size for read/write commands */
351 static int current_phys_fmt_gap = 0x54;         /* gap size when formatting */
352 static int current_sectsize_p2 = 2;             /* NTS: 128 << N, 128 << 2 = 512 */
353 static int current_sectsize_smaller = 0xFF;     /* if sectsize_p2 == 0 */
354 static int current_sectcount = 2;               /* two sectors */
355 static unsigned char allow_multitrack = 1;      /* set MT bit */
356 static unsigned char mfm_mode = 1;              /* set bit to indicate MFM (not FM) */
357
358 static void (interrupt *my_floppy_old_irq)() = NULL;
359 static struct floppy_controller *my_floppy_irq_floppy = NULL;
360 static unsigned long floppy_irq_counter = 0;
361 static int my_floppy_irq_number = -1;
362
363 void do_floppy_controller_unhook_irq(struct floppy_controller *fdc);
364
365 static void interrupt my_floppy_irq() {
366         int i;
367
368         i = vga_width*(vga_height-1);
369
370         _cli();
371         if (my_floppy_irq_floppy != NULL) {
372                 my_floppy_irq_floppy->irq_fired++;
373
374                 /* ack PIC */
375                 if (my_floppy_irq_floppy->irq >= 8) p8259_OCW2(8,P8259_OCW2_NON_SPECIFIC_EOI);
376                 p8259_OCW2(0,P8259_OCW2_NON_SPECIFIC_EOI);
377
378                 /* If too many IRQs fired, then unhook the IRQ and use polling from now on. */
379                 if (my_floppy_irq_floppy->irq_fired >= 0xFFFEU) {
380                         do_floppy_controller_unhook_irq(my_floppy_irq_floppy);
381                         vga_alpha_ram[i+12] = 0x1C00 | '!';
382                         my_floppy_irq_floppy->irq_fired = ~0; /* make sure the IRQ counter is as large as possible */
383                 }
384         }
385
386         /* we CANNOT use sprintf() here. sprintf() doesn't work to well from within an interrupt handler,
387          * and can cause crashes in 16-bit realmode builds. */
388         vga_alpha_ram[i++] = 0x1F00 | 'I';
389         vga_alpha_ram[i++] = 0x1F00 | 'R';
390         vga_alpha_ram[i++] = 0x1F00 | 'Q';
391         vga_alpha_ram[i++] = 0x1F00 | ':';
392         vga_alpha_ram[i++] = 0x1F00 | ('0' + ((floppy_irq_counter / 100000UL) % 10UL));
393         vga_alpha_ram[i++] = 0x1F00 | ('0' + ((floppy_irq_counter /  10000UL) % 10UL));
394         vga_alpha_ram[i++] = 0x1F00 | ('0' + ((floppy_irq_counter /   1000UL) % 10UL));
395         vga_alpha_ram[i++] = 0x1F00 | ('0' + ((floppy_irq_counter /    100UL) % 10UL));
396         vga_alpha_ram[i++] = 0x1F00 | ('0' + ((floppy_irq_counter /     10UL) % 10UL));
397         vga_alpha_ram[i++] = 0x1F00 | ('0' + ((floppy_irq_counter /       1L) % 10UL));
398         vga_alpha_ram[i++] = 0x1F00 | ' ';
399
400         floppy_irq_counter++;
401 }
402
403 void do_floppy_controller_hook_irq(struct floppy_controller *fdc) {
404         if (my_floppy_irq_number >= 0 || my_floppy_old_irq != NULL || fdc->irq < 0)
405                 return;
406
407         /* let the IRQ know what floppy controller */
408         my_floppy_irq_floppy = fdc;
409
410         /* enable on floppy controller */
411         p8259_mask(fdc->irq);
412         floppy_controller_enable_irq(fdc,1);
413
414         /* hook IRQ */
415         my_floppy_old_irq = _dos_getvect(irq2int(fdc->irq));
416         _dos_setvect(irq2int(fdc->irq),my_floppy_irq);
417         my_floppy_irq_number = fdc->irq;
418
419         /* enable at PIC */
420         p8259_unmask(fdc->irq);
421 }
422
423 void do_floppy_controller_unhook_irq(struct floppy_controller *fdc) {
424         if (my_floppy_irq_number < 0 || my_floppy_old_irq == NULL || fdc->irq < 0)
425                 return;
426
427         /* disable on floppy controller, then mask at PIC */
428         p8259_mask(fdc->irq);
429         floppy_controller_enable_irq(fdc,0);
430
431         /* restore the original vector */
432         _dos_setvect(irq2int(fdc->irq),my_floppy_old_irq);
433         my_floppy_irq_number = -1;
434         my_floppy_old_irq = NULL;
435 }
436
437 void do_floppy_controller_enable_irq(struct floppy_controller *fdc,unsigned char en) {
438         if (!en || fdc->irq < 0 || fdc->irq != my_floppy_irq_number)
439                 do_floppy_controller_unhook_irq(fdc);
440         if (en && fdc->irq >= 0)
441                 do_floppy_controller_hook_irq(fdc);
442 }
443
444 static inline uint8_t floppy_controller_busy_in_instruction(struct floppy_controller *fdc) {
445         return ((fdc->main_status & 0x10) == 0x10)?1:0; /* busy == 1 */
446 }
447
448 static inline uint8_t floppy_controller_data_io_ready(struct floppy_controller *fdc) {
449         return ((fdc->main_status & 0x80) == 0x80)?1:0; /* data ready == 1 */
450 }
451
452 static inline uint8_t floppy_controller_can_read_data(struct floppy_controller *fdc) {
453         return ((fdc->main_status & 0xC0) == 0xC0)?1:0; /* data ready == 1 and data i/o == 1 */
454 }
455
456 static inline uint8_t floppy_controller_can_read_data_non_dma(struct floppy_controller *fdc) {
457         return ((fdc->main_status & 0xE0) == 0xE0)?1:0; /* data ready == 1 and data i/o == 1 and NDMA == 1 */
458 }
459
460 static inline uint8_t floppy_controller_can_write_data(struct floppy_controller *fdc) {
461         return ((fdc->main_status & 0xC0) == 0x80)?1:0; /* data ready == 1 and data i/o == 0 */
462 }
463
464 static inline uint8_t floppy_controller_can_write_data_non_dma(struct floppy_controller *fdc) {
465         return ((fdc->main_status & 0xE0) == 0xA0)?1:0; /* data ready == 1 and data i/o == 0 AND NDMA == 1 */
466 }
467
468 static inline uint8_t floppy_controller_read_data_byte(struct floppy_controller *fdc) {
469         return inp(fdc->base_io+5);
470 }
471
472 static inline void floppy_controller_write_data_byte(struct floppy_controller *fdc,uint8_t b) {
473         outp(fdc->base_io+5,b);
474 }
475
476 static inline int floppy_controller_wait_data_ready(struct floppy_controller *fdc,unsigned int timeout) {
477         do {
478                 floppy_controller_read_status(fdc);
479                 if (floppy_controller_data_io_ready(fdc)) return 1;
480         } while (--timeout != 0);
481
482         return 0;
483 }
484
485 static inline int floppy_controller_wait_data_read_non_dma_ready(struct floppy_controller *fdc,unsigned int timeout) {
486         do {
487                 floppy_controller_read_status(fdc);
488                 if (floppy_controller_can_read_data_non_dma(fdc)) return 1;
489                 t8254_wait(t8254_us2ticks(1000));
490         } while (--timeout != 0);
491
492         return 0;
493 }
494
495 static inline int floppy_controller_wait_data_write_non_dma_ready(struct floppy_controller *fdc,unsigned int timeout) {
496         do {
497                 floppy_controller_read_status(fdc);
498                 if (floppy_controller_can_write_data_non_dma(fdc)) return 1;
499                 t8254_wait(t8254_us2ticks(1000));
500         } while (--timeout != 0);
501
502         return 0;
503 }
504
505 static inline void floppy_controller_reset_irq_counter(struct floppy_controller *fdc) {
506         fdc->irq_fired = 0;
507 }
508
509 int floppy_controller_wait_busy_in_instruction(struct floppy_controller *fdc,unsigned int timeout) {
510         do {
511                 floppy_controller_read_status(fdc);
512                 if (!floppy_controller_busy_in_instruction(fdc)) return 1;
513                 t8254_wait(t8254_us2ticks(1000));
514         } while (--timeout != 0);
515
516         return 0;
517 }
518
519 int floppy_controller_wait_data_ready_ms(struct floppy_controller *fdc,unsigned int timeout) {
520         do {
521                 floppy_controller_read_status(fdc);
522                 if (floppy_controller_data_io_ready(fdc)) return 1;
523                 t8254_wait(t8254_us2ticks(1000));
524         } while (--timeout != 0);
525
526         return 0;
527 }
528
529 int floppy_controller_wait_irq(struct floppy_controller *fdc,unsigned int timeout,unsigned int counter) {
530         do {
531                 if (fdc->irq_fired >= counter) break;
532                 t8254_wait(t8254_us2ticks(1000));
533         } while (--timeout != 0);
534
535         return 0;
536 }
537
538 int floppy_controller_write_data(struct floppy_controller *fdc,const unsigned char *data,int len) {
539         unsigned int oflags = get_cpu_flags();
540         int ret = 0;
541
542         _cli(); /* clear interrupts so we can focus on talking to the FDC */
543         while (len > 0) {
544                 if (!floppy_controller_wait_data_ready(fdc,1000)) {
545                         if (ret == 0) ret = -1;
546                         break;
547                 }
548                 if (!floppy_controller_can_write_data(fdc)) {
549                         if (ret == 0) ret = -2;
550                         break;
551                 }
552
553                 floppy_controller_write_data_byte(fdc,*data++);
554                 len--; ret++;
555         }
556
557         if (oflags&0x200/*IF interrupt enable was on*/) _sti();
558         return ret;
559 }
560
561 #if TARGET_MSDOS == 32
562 int floppy_controller_write_data_ndma(struct floppy_controller *fdc,const unsigned char *data,int len) {
563 #else
564 int floppy_controller_write_data_ndma(struct floppy_controller *fdc,const unsigned char far *data,int len) {
565 #endif
566         unsigned int oflags = get_cpu_flags();
567         int ret = 0;
568
569         _cli();
570         while (len > 0) {
571                 if (!floppy_controller_wait_data_ready(fdc,1000)) {
572                         if (ret == 0) ret = -1;
573                         break;
574                 }
575                 if (!floppy_controller_wait_data_write_non_dma_ready(fdc,1000)) {
576                         if (ret == 0) ret = -2;
577                         break;
578                 }
579
580                 floppy_controller_write_data_byte(fdc,*data++);
581                 len--; ret++;
582         }
583
584         if (oflags&0x200/*IF interrupt enable was on*/) _sti();
585         return ret;
586 }
587
588 int floppy_controller_read_data(struct floppy_controller *fdc,unsigned char *data,int len) {
589         unsigned int oflags = get_cpu_flags();
590         int ret = 0;
591
592         _cli();
593         while (len > 0) {
594                 if (!floppy_controller_wait_data_ready(fdc,1000)) {
595                         if (ret == 0) ret = -1;
596                         break;
597                 }
598                 if (!floppy_controller_can_read_data(fdc)) {
599                         if (ret == 0) ret = -2;
600                         break;
601                 }
602
603                 *data++ = floppy_controller_read_data_byte(fdc);
604                 len--; ret++;
605         }
606
607         if (oflags&0x200/*IF interrupt enable was on*/) _sti();
608         return ret;
609 }
610
611 #if TARGET_MSDOS == 32
612 int floppy_controller_read_data_ndma(struct floppy_controller *fdc,unsigned char *data,int len) {
613 #else
614 int floppy_controller_read_data_ndma(struct floppy_controller *fdc,unsigned char far *data,int len) {
615 #endif
616         unsigned int oflags = get_cpu_flags();
617         int ret = 0;
618
619         _cli();
620         while (len > 0) {
621                 if (!floppy_controller_wait_data_ready(fdc,1000)) {
622                         if (ret == 0) ret = -1;
623                         break;
624                 }
625                 if (!floppy_controller_wait_data_read_non_dma_ready(fdc,1000)) {
626                         if (ret == 0) ret = -2;
627                         break;
628                 }
629
630                 *data++ = floppy_controller_read_data_byte(fdc);
631                 len--; ret++;
632         }
633
634         if (oflags&0x200/*IF interrupt enable was on*/) _sti();
635         return ret;
636 }
637
638 void do_floppy_controller_reset(struct floppy_controller *fdc) {
639         struct vga_msg_box vgabox;
640
641         vga_msg_box_create(&vgabox,"FDC reset in progress",0,0);
642
643         floppy_controller_set_reset(fdc,1);
644         t8254_wait(t8254_us2ticks(1000000));
645         floppy_controller_set_reset(fdc,0);
646         floppy_controller_wait_data_ready_ms(fdc,1000);
647         floppy_controller_read_status(fdc);
648
649         vga_msg_box_destroy(&vgabox);
650 }
651
652 void do_check_interrupt_status(struct floppy_controller *fdc) {
653         struct vga_msg_box vgabox;
654         char cmd[10],resp[10];
655         int rd,wd,rdo,wdo;
656
657         floppy_controller_read_status(fdc);
658         if (!floppy_controller_can_write_data(fdc) || floppy_controller_busy_in_instruction(fdc))
659                 do_floppy_controller_reset(fdc);
660
661         /* Check Interrupt Status (x8h)
662          *
663          *   Byte |  7   6   5   4   3   2   1   0
664          *   -----+---------------------------------
665          *      0 |  0   0   0   0   1   0   0   0
666          *
667          */
668
669         wdo = 1;
670         cmd[0] = 0x08;  /* Check interrupt status */
671         wd = floppy_controller_write_data(fdc,cmd,wdo);
672         if (wd < 1) {
673                 sprintf(tmp,"Failed to write data to FDC, %u/%u",wd,wdo);
674                 vga_msg_box_create(&vgabox,tmp,0,0);
675                 wait_for_enter_or_escape();
676                 vga_msg_box_destroy(&vgabox);
677                 do_floppy_controller_reset(fdc);
678                 return;
679         }
680
681         /* wait for data ready. does not fire an IRQ (because you use this to clear IRQ status!) */
682         floppy_controller_wait_data_ready_ms(fdc,1000);
683
684         /* NTS: It's not specified whether this returns 2 bytes if success and 1 if no IRQ pending.. or...? */
685         rdo = 2;
686         resp[1] = 0;
687         rd = floppy_controller_read_data(fdc,resp,rdo);
688         if (rd < 1) {
689                 sprintf(tmp,"Failed to read data from the FDC, %u/%u",rd,rdo);
690                 vga_msg_box_create(&vgabox,tmp,0,0);
691                 wait_for_enter_or_escape();
692                 vga_msg_box_destroy(&vgabox);
693                 do_floppy_controller_reset(fdc);
694                 return;
695         }
696
697         /* Check Interrupt Status (x8h) response
698          *
699          *   Byte |  7   6   5   4   3   2   1   0
700          *   -----+---------------------------------
701          *      0 |              ST0
702          *      1 |        Current Cylinder
703          */
704
705         /* the command SHOULD terminate */
706         floppy_controller_wait_data_ready(fdc,20);
707         if (!floppy_controller_wait_busy_in_instruction(fdc,1000))
708                 do_floppy_controller_reset(fdc);
709
710         /* return value is ST0 and the current cylinder */
711         fdc->st[0] = resp[0];
712         fdc->cylinder = resp[1];
713 }
714
715 void do_spin_up_motor(struct floppy_controller *fdc,unsigned char drv) {
716         if (drv > 3) return;
717
718         if (!(fdc->digital_out & (0x10 << drv))) {
719                 struct vga_msg_box vgabox;
720
721                 vga_msg_box_create(&vgabox,"Spinning up motor",0,0);
722
723                 /* if the motor isn't on, then turn it on, and then wait for motor to stabilize */
724                 floppy_controller_set_motor_state(fdc,drv,1);
725                 t8254_wait(t8254_us2ticks(500000)); /* 500ms */
726
727                 vga_msg_box_destroy(&vgabox);
728         }
729         else {
730                 /* some controllers auto-timeout the motor against our will.
731                  * perhaps this is what the Linux kernel means by "twaddling" the motor bit */
732                 floppy_controller_set_motor_state(fdc,drv,0);
733                 floppy_controller_set_motor_state(fdc,drv,1);
734         }
735 }
736
737 void do_seek_drive_rel(struct floppy_controller *fdc,int track) {
738         struct vga_msg_box vgabox;
739         char cmd[10];
740         int wd,wdo;
741
742         do_spin_up_motor(fdc,fdc->digital_out&3);
743
744         floppy_controller_read_status(fdc);
745         if (!floppy_controller_can_write_data(fdc) || floppy_controller_busy_in_instruction(fdc))
746                 do_floppy_controller_reset(fdc);
747
748         floppy_controller_reset_irq_counter(fdc);
749
750         /* Seek Relative (1xFh)
751          *
752          *   Byte |  7   6   5   4   3   2   1   0
753          *   -----+---------------------------------
754          *      0 |  1 DIR   0   0   1   1   1   1
755          *      1 |  x   x   x   x   x  HD DR1 DR0
756          *      2 |         Cylinder Step
757          *
758          *         HD = Head select (on PC platform, doesn't matter)
759          *    DR1,DR0 = Drive select
760          *        DIR = Step direction (1=inward increasing, 0=outward decreasing)
761          *  Cyl. step = How many tracks to step */
762
763         wdo = 3;
764         cmd[0] = 0x8F + (track < 0 ? 0x40 : 0x00); /* Seek rel [6:6] = DIR */
765         cmd[1] = (fdc->digital_out&3)+(current_phys_head?0x04:0x00)/* [1:0] = DR1,DR0 [2:2] HD (doesn't matter) */;
766         cmd[2] = abs(track);
767         wd = floppy_controller_write_data(fdc,cmd,wdo);
768         if (wd < 3) {
769                 sprintf(tmp,"Failed to write data to FDC, %u/%u",wd,wdo);
770                 vga_msg_box_create(&vgabox,tmp,0,0);
771                 wait_for_enter_or_escape();
772                 vga_msg_box_destroy(&vgabox);
773                 do_floppy_controller_reset(fdc);
774                 return;
775         }
776
777         /* fires an IRQ. doesn't return state */
778         if (fdc->use_irq) floppy_controller_wait_irq(fdc,1000,1);
779         floppy_controller_wait_data_ready_ms(fdc,1000);
780
781         /* Seek Relative (1xFh) response
782          *
783          * (none)
784          */
785
786         /* the command SHOULD terminate */
787         floppy_controller_wait_data_ready(fdc,20);
788         if (!floppy_controller_wait_busy_in_instruction(fdc,1000))
789                 do_floppy_controller_reset(fdc);
790
791         /* use Check Interrupt Status */
792         do_check_interrupt_status(fdc);
793 }
794
795 unsigned long prompt_track_number();
796 void do_seek_drive(struct floppy_controller *fdc,uint8_t track);
797 void do_calibrate_drive(struct floppy_controller *fdc);
798 int do_read_sector_id(unsigned char resp[7],struct floppy_controller *fdc,unsigned char head);
799
800 void do_step_tracks(struct floppy_controller *fdc) {
801         unsigned long start,end,track;
802         struct vga_msg_box vgabox;
803         unsigned char resp[7];
804         char tmp[64];
805         int del,c;
806
807         start = prompt_track_number();
808         if (start == (~0UL)) return;
809
810         end = prompt_track_number();
811         if (start == (~0UL)) return;
812         if (start > end) return;
813
814         do_spin_up_motor(fdc,fdc->digital_out&3);
815
816         vga_msg_box_create(&vgabox,"Seeking to track 0",0,0);
817         do_calibrate_drive(fdc);
818         do_calibrate_drive(fdc);
819         do_calibrate_drive(fdc);
820         vga_msg_box_destroy(&vgabox);
821
822         /* step! */
823         for (track=start;track <= end;track++) {
824                 if (kbhit()) {
825                         c = getch();
826                         if (c == 0) c = getch() << 8;
827                         if (c == 27) break;
828                 }
829
830                 sprintf(tmp,"Seeking track %lu",track);
831                 vga_msg_box_create(&vgabox,tmp,0,0);
832
833                 /* move head */
834                 do_seek_drive(fdc,(uint8_t)track);
835
836                 /* read sector ID to try and force head select if FDC doesn't do it from seek command */
837                 do_read_sector_id(resp,fdc,current_phys_head);
838
839                 /* delay 1 second */
840                 for (del=0;del < 1000;del++)
841                         t8254_wait(t8254_us2ticks(1000));
842
843                 /* un-draw the box */
844                 vga_msg_box_destroy(&vgabox);
845         }
846 }
847
848 void do_seek_drive(struct floppy_controller *fdc,uint8_t track) {
849         struct vga_msg_box vgabox;
850         char cmd[10];
851         int wd,wdo;
852
853         do_spin_up_motor(fdc,fdc->digital_out&3);
854
855         floppy_controller_read_status(fdc);
856         if (!floppy_controller_can_write_data(fdc) || floppy_controller_busy_in_instruction(fdc))
857                 do_floppy_controller_reset(fdc);
858
859         floppy_controller_reset_irq_counter(fdc);
860
861         /* Seek (xFh)
862          *
863          *   Byte |  7   6   5   4   3   2   1   0
864          *   -----+---------------------------------
865          *      0 |  0   0   0   0   1   1   1   1
866          *      1 |  x   x   x   x   x  HD DR1 DR0
867          *      2 |            Cylinder
868          *
869          *         HD = Head select (on PC platform, doesn't matter)
870          *    DR1,DR0 = Drive select
871          *   Cylinder = Track to move to */
872
873         wdo = 3;
874         cmd[0] = 0x0F;  /* Seek */
875         cmd[1] = (fdc->digital_out&3)+(current_phys_head?0x04:0x00)/* [1:0] = DR1,DR0 [2:2] HD (doesn't matter) */;
876         cmd[2] = track;
877         wd = floppy_controller_write_data(fdc,cmd,wdo);
878         if (wd < 3) {
879                 sprintf(tmp,"Failed to write data to FDC, %u/%u",wd,wdo);
880                 vga_msg_box_create(&vgabox,tmp,0,0);
881                 wait_for_enter_or_escape();
882                 vga_msg_box_destroy(&vgabox);
883                 do_floppy_controller_reset(fdc);
884                 return;
885         }
886
887         /* fires an IRQ. doesn't return state */
888         if (fdc->use_irq) floppy_controller_wait_irq(fdc,1000,1);
889         floppy_controller_wait_data_ready_ms(fdc,1000);
890
891         /* Seek (xFh) response
892          *
893          * (none)
894          */
895
896         /* the command SHOULD terminate */
897         floppy_controller_wait_data_ready(fdc,20);
898         if (!floppy_controller_wait_busy_in_instruction(fdc,1000))
899                 do_floppy_controller_reset(fdc);
900
901         /* use Check Interrupt Status */
902         do_check_interrupt_status(fdc);
903 }
904
905 void do_check_drive_status(struct floppy_controller *fdc) {
906         struct vga_msg_box vgabox;
907         char cmd[10],resp[10];
908         int rd,wd,rdo,wdo;
909
910         floppy_controller_read_status(fdc);
911         if (!floppy_controller_can_write_data(fdc) || floppy_controller_busy_in_instruction(fdc))
912                 do_floppy_controller_reset(fdc);
913
914         /* Check Drive Status (x4h)
915          *
916          *   Byte |  7   6   5   4   3   2   1   0
917          *   -----+---------------------------------
918          *      0 |  0   0   0   0   0   1   0   0
919          *      1 |  x   x   x   x   x  HD DR1 DR0
920          *
921          *       HD = Head select (on PC platform, doesn't matter)
922          *  DR1,DR0 = Drive select */
923
924         wdo = 2;
925         cmd[0] = 0x04;  /* Check drive status */
926         cmd[1] = (fdc->digital_out&3)+(current_phys_head?0x04:0x00)/* [1:0] = DR1,DR0 [2:2] = HD = 0 */;
927         wd = floppy_controller_write_data(fdc,cmd,wdo);
928         if (wd < 2) {
929                 sprintf(tmp,"Failed to write data to FDC, %u/%u",wd,wdo);
930                 vga_msg_box_create(&vgabox,tmp,0,0);
931                 wait_for_enter_or_escape();
932                 vga_msg_box_destroy(&vgabox);
933                 do_floppy_controller_reset(fdc);
934                 return;
935         }
936
937         /* wait for data ready. does not fire an IRQ */
938         floppy_controller_wait_data_ready_ms(fdc,1000);
939
940         /* Check Drive Status (x4h) response
941          *
942          *   Byte |  7   6   5   4   3   2   1   0
943          *   -----+---------------------------------
944          *      0 |              ST3
945          */
946
947         rdo = 1;
948         rd = floppy_controller_read_data(fdc,resp,rdo);
949         if (rd < 1) {
950                 sprintf(tmp,"Failed to read data from the FDC, %u/%u",rd,rdo);
951                 vga_msg_box_create(&vgabox,tmp,0,0);
952                 wait_for_enter_or_escape();
953                 vga_msg_box_destroy(&vgabox);
954                 do_floppy_controller_reset(fdc);
955                 return;
956         }
957
958         /* the command SHOULD terminate */
959         floppy_controller_wait_data_ready(fdc,20);
960         if (!floppy_controller_wait_busy_in_instruction(fdc,1000))
961                 do_floppy_controller_reset(fdc);
962
963         /* return value is ST3 */
964         fdc->st[3] = resp[0];
965 }
966
967 void do_calibrate_drive(struct floppy_controller *fdc) {
968         struct vga_msg_box vgabox;
969         char cmd[10];
970         int wd,wdo;
971
972         do_spin_up_motor(fdc,fdc->digital_out&3);
973
974         floppy_controller_read_status(fdc);
975         if (!floppy_controller_can_write_data(fdc) || floppy_controller_busy_in_instruction(fdc))
976                 do_floppy_controller_reset(fdc);
977
978         floppy_controller_reset_irq_counter(fdc);
979
980         /* Calibrate Drive (x7h)
981          *
982          *   Byte |  7   6   5   4   3   2   1   0
983          *   -----+---------------------------------
984          *      0 |  0   0   0   0   0   1   1   1
985          *      1 |  x   x   x   x   x   0 DR1 DR0
986          *
987          *  DR1,DR0 = Drive select */
988
989         wdo = 2;
990         cmd[0] = 0x07;  /* Calibrate */
991         cmd[1] = (fdc->digital_out&3)/* [1:0] = DR1,DR0 */;
992         wd = floppy_controller_write_data(fdc,cmd,wdo);
993         if (wd < 2) {
994                 sprintf(tmp,"Failed to write data to FDC, %u/%u",wd,wdo);
995                 vga_msg_box_create(&vgabox,tmp,0,0);
996                 wait_for_enter_or_escape();
997                 vga_msg_box_destroy(&vgabox);
998                 do_floppy_controller_reset(fdc);
999                 return;
1000         }
1001
1002         /* fires an IRQ. doesn't return state */
1003         if (fdc->use_irq) floppy_controller_wait_irq(fdc,1000,1);
1004         floppy_controller_wait_data_ready_ms(fdc,1000);
1005
1006         /* Calibrate Drive (x7h) response
1007          *
1008          * (none)
1009          */
1010
1011         /* the command SHOULD terminate */
1012         floppy_controller_wait_data_ready(fdc,20);
1013         if (!floppy_controller_wait_busy_in_instruction(fdc,1000))
1014                 do_floppy_controller_reset(fdc);
1015
1016         /* use Check Interrupt Status */
1017         do_check_interrupt_status(fdc);
1018 }
1019
1020 int do_floppy_get_version(struct floppy_controller *fdc) {
1021         int rd,wd,rdo,wdo;
1022         char cmd[10],resp[10];
1023
1024         floppy_controller_read_status(fdc);
1025         if (!floppy_controller_can_write_data(fdc) || floppy_controller_busy_in_instruction(fdc))
1026                 do_floppy_controller_reset(fdc);
1027
1028         /* Version (1x0h)
1029          *
1030          *   Byte |  7   6   5   4   3   2   1   0
1031          *   -----+---------------------------------
1032          *      0 |  0   0   0   1   0   0   0   0
1033          */
1034
1035         wdo = 1;
1036         cmd[0] = 0x10;
1037         wd = floppy_controller_write_data(fdc,cmd,wdo);
1038         if (wd < 1) {
1039                 do_floppy_controller_reset(fdc);
1040                 return 0;
1041         }
1042
1043         /* wait for data ready. does not fire an IRQ */
1044         floppy_controller_wait_data_ready_ms(fdc,1000);
1045
1046         rdo = 1;
1047         rd = floppy_controller_read_data(fdc,resp,rdo);
1048         if (rd < 1) {
1049                 do_floppy_controller_reset(fdc);
1050                 return 0;
1051         }
1052
1053         /* Version (1x0h) response
1054          *
1055          *   Byte |  7    6    5    4    3    2    1    0
1056          *   -----+--------------------------------------
1057          *      0 |            Version or error
1058          *
1059          * Version/Error values:
1060          *     0x80: Not an enhanced controller (we got an invalid opcode)
1061          *     0x90: Enhanced controller
1062          */
1063
1064         /* the command SHOULD terminate */
1065         floppy_controller_wait_data_ready(fdc,20);
1066         if (!floppy_controller_wait_busy_in_instruction(fdc,1000))
1067                 do_floppy_controller_reset(fdc);
1068
1069         fdc->version = resp[0];
1070         return 1;
1071
1072 }
1073
1074 int do_floppy_controller_specify(struct floppy_controller *fdc) {
1075         int retry_count=0;
1076         char cmd[10];
1077         int wd,wdo;
1078         int drv;
1079
1080 retry:  drv = fdc->digital_out & 3;
1081
1082         floppy_controller_read_status(fdc);
1083         if (!floppy_controller_can_write_data(fdc) || floppy_controller_busy_in_instruction(fdc))
1084                 do_floppy_controller_reset(fdc);
1085
1086         /* Specify (x3h)
1087          *
1088          *   Byte |  7   6   5   4   3   2   1   0
1089          *   -----+---------------------------------
1090          *      0 |  0   0   0   0   0   0   1   1
1091          *      1 |  <--- SRT --->   <----HUT---->
1092          *      2 |  <-----------HLT--------->  ND
1093          */
1094
1095         wdo = 3;
1096         cmd[0] = 0x03;
1097         cmd[1] = (fdc->current_srt << 4) | (fdc->current_hut & 0xF);
1098         cmd[2] = (fdc->current_hlt << 1) | (fdc->non_dma_mode & 1);
1099         wd = floppy_controller_write_data(fdc,cmd,wdo);
1100         if (wd < 3) {
1101                 do_floppy_controller_reset(fdc);
1102                 return 0;
1103         }
1104
1105         /* wait for data ready. does not fire an IRQ */
1106         floppy_controller_wait_data_ready_ms(fdc,1000);
1107
1108         /* Specify (x3h) response
1109          *
1110          * (none)
1111          */
1112
1113         /* the command SHOULD terminate */
1114         floppy_controller_wait_data_ready(fdc,20);
1115         if (!floppy_controller_wait_busy_in_instruction(fdc,1000))
1116                 do_floppy_controller_reset(fdc);
1117
1118         /* use Check Interrupt Status */
1119         do_check_interrupt_status(fdc);
1120
1121         /* if it failed, try again */
1122         if ((fdc->st[0]&0xC0) == 0xC0 || (fdc->st[0]&0xC0) == 0x40) {
1123                 if ((++retry_count) < 8) { /* what the hell VirtualBox? */
1124                         floppy_controller_drive_select(fdc,drv);
1125                         goto retry;
1126                 }
1127
1128                 return 0;
1129         }
1130
1131         return 1;
1132 }
1133
1134 int do_floppy_dumpreg(struct floppy_controller *fdc) {
1135         int rd,wd,rdo,wdo;
1136         char cmd[10],resp[10];
1137
1138         floppy_controller_read_status(fdc);
1139         if (!floppy_controller_can_write_data(fdc) || floppy_controller_busy_in_instruction(fdc))
1140                 do_floppy_controller_reset(fdc);
1141
1142         /* Dump Registers (xEh)
1143          *
1144          *   Byte |  7   6   5   4   3   2   1   0
1145          *   -----+---------------------------------
1146          *      0 |  0   0   0   0   1   1   1   0
1147          */
1148
1149         wdo = 1;
1150         cmd[0] = 0x0E;
1151         wd = floppy_controller_write_data(fdc,cmd,wdo);
1152         if (wd < 1) {
1153                 do_floppy_controller_reset(fdc);
1154                 return 0;
1155         }
1156
1157         /* wait for data ready. does not fire an IRQ */
1158         floppy_controller_wait_data_ready_ms(fdc,1000);
1159
1160         rdo = 10;
1161         rd = floppy_controller_read_data(fdc,resp,rdo);
1162         if (rd < 1) {
1163                 do_floppy_controller_reset(fdc);
1164                 return 0;
1165         }
1166
1167         /* Dump Registers (xEh) response
1168          *
1169          *   Byte |  7    6    5    4    3    2    1    0
1170          *   -----+--------------------------------------
1171          *      0 |       Current Cylinder (drive 0)             <- Also known as PCN0
1172          *      1 |       Current Cylinder (drive 1)             <- Also known as PCN1
1173          *      2 |       Current Cylinder (drive 2)             <- Also known as PCN2
1174          *      3 |       Current Cylinder (drive 3)             <- Also known as PCN3
1175          *      4 |  <------SRT----->    <------HUT----->
1176          *      5 |  <------------HLT-------------->   ND
1177          *      6 |  <--------------SC/EOT-------------->
1178          *      7 |LOCK   0   D3   D2   D1   D0   GAP WGATE
1179          *      8 |  0   EIS EFIFO POLL  <---FIFOTHR---->
1180          *      9 |  <--------------PRETRK-------------->
1181          *
1182          *          SRT = Step rate interval (0.5 to 8ms in 0.5 steps at 1mbit/sec, affected by data rate)
1183          *          HUT = Head unload time (affected by data rate)
1184          *          HLT = Head load time (affected by data rate)
1185          *           ND = Non-DMA mode flag. If set, the controller should operate in the non-DMA mode.
1186          *       SC/EOT = Sector count/End of track
1187          *      D3...D0 = Drive Select 3..0, which ones are in Perpendicular Mode
1188          *          GAP = Alter Gap 2 length in Perpendicular Mode
1189          *        WGATE = Write gate alters timing of WE, to allow for pre-erase loads in perpendicular drives.
1190          *          EIS = Enable Implied Seek
1191          *        EFIFO = Enable FIFO. When 0, FIFO is enabled. When 1, FIFO is disabled.
1192          *         POLL = Polling disable. When set, internal polling routine is disabled.
1193          *      FIFOTHR = FIFO threshold - 1 in the execution phase of read/write commands. 0h to Fh maps to 1...16 bytes.
1194          *       PRETRK = Precompensation start track number.
1195          *
1196          *
1197          *      82077AA Drive Control Delays (ms) Table 5-10
1198          *
1199          *        |                HUT                 |                 SRT                |
1200          *        |   1M     500K     300K     250K    |   1M     500K     300K     250K    |
1201          *     ---+------------------------------------+------------------------------------+
1202          *      0 |  128      256      426      512    |  8.0       16     26.7       32    |
1203          *      1 |    8       16     26.7       32    |  7.5       15       25       30    |
1204          *     ...............................................................................
1205          *     Eh |  112      224      373      448    |  1.0        2     3.33        4    |
1206          *     Fh |  120      240      400      480    |  0.5        1     1.67        2    |
1207          *        +------------------------------------+------------------------------------+
1208          *
1209          *        |                HLT                 |
1210          *        |   1M     500K     300K     250K    |
1211          *     ---+------------------------------------+
1212          *      0 |  128      256      426      512    |
1213          *      1 |    1        2      3.3        4    |
1214          *     ..........................................
1215          *    7Eh |  126      252      420      504    |
1216          *    7Fh |  127      254      423      508    |
1217          *        +------------------------------------+
1218          */
1219
1220         /* the command SHOULD terminate */
1221         floppy_controller_wait_data_ready(fdc,20);
1222         if (!floppy_controller_wait_busy_in_instruction(fdc,1000))
1223                 do_floppy_controller_reset(fdc);
1224
1225         /* copy down info we want to keep track of */
1226         fdc->current_srt = resp[4] >> 4;
1227         fdc->current_hut = resp[4] & 0x0F;
1228         fdc->current_hlt = resp[5] >> 1;
1229         fdc->non_dma_mode = resp[5] & 0x01;
1230         fdc->implied_seek = (resp[8] >> 6) & 1;
1231
1232         {
1233                 struct vga_msg_box vgabox;
1234                 char *w=tmp;
1235                 int i;
1236
1237                 for (i=0;i < rd;i++) w += sprintf(w,"%02x ",resp[i]);
1238                 *w++ = '\n';
1239                 *w++ = '\n';
1240                 *w = 0;
1241
1242                 w += sprintf(w,"PCN[0-3](physical track) = %u,%u,%u,%u\n",
1243                         resp[0],resp[1],resp[2],resp[3]);
1244                 w += sprintf(w,"SRT=%u  HUT=%u  HLT=%u  ND=%u\n",
1245                         resp[4]>>4,resp[4]&0xF,
1246                         resp[5]>>1,resp[5]&1);
1247                 w += sprintf(w,"SC/EOT=%u  LOCK=%u  D[0-3](perpendicular)=%u,%u,%u,%u\n",
1248                         resp[6],
1249                         (resp[7]>>7)&1,
1250                         (resp[7]>>5)&1,
1251                         (resp[7]>>4)&1,
1252                         (resp[7]>>3)&1,
1253                         (resp[7]>>2)&1);
1254                 w += sprintf(w,"GAP=%u  WGATE=%u  EIS=%u  EFIFO=%u  POLL=%u\n",
1255                         (resp[7]>>1)&1,
1256                         (resp[7]>>0)&1,
1257                         (resp[8]>>6)&1,
1258                         (resp[8]>>5)&1,
1259                         (resp[8]>>4)&1);
1260                 w += sprintf(w,"FIFOTHR=%u  PRETRK=%u",
1261                         (resp[8]>>0)&0xF,
1262                         resp[9]);
1263
1264                 vga_msg_box_create(&vgabox,tmp,0,0);
1265                 wait_for_enter_or_escape();
1266                 vga_msg_box_destroy(&vgabox);
1267         }
1268
1269         return 1;
1270 }
1271
1272 int do_read_sector_id(unsigned char resp[7],struct floppy_controller *fdc,unsigned char head) {
1273         int rd,wd,rdo,wdo;
1274         char cmd[10];
1275
1276         floppy_controller_read_status(fdc);
1277         if (!floppy_controller_can_write_data(fdc) || floppy_controller_busy_in_instruction(fdc))
1278                 do_floppy_controller_reset(fdc);
1279
1280         /* Read ID (xAh)
1281          *
1282          *   Byte |  7   6   5   4   3   2   1   0
1283          *   -----+---------------------------------
1284          *      0 |  0  MF   0   0   1   0   1   0
1285          *      1 |  x   x   x   x   x  HD DR1 DR0
1286          *
1287          *         MF = MFM/FM
1288          *         HD = Head select (on PC platform, doesn't matter)
1289          *    DR1,DR0 = Drive select */
1290
1291         wdo = 2;
1292         cmd[0] = 0x0A + (mfm_mode?0x40:0x00); /* Read sector ID [6:6] MFM */
1293         cmd[1] = (fdc->digital_out&3)+(head<<2)/* [1:0] = DR1,DR0 [2:2] = HD */;
1294         wd = floppy_controller_write_data(fdc,cmd,wdo);
1295         if (wd < 2) {
1296                 do_floppy_controller_reset(fdc);
1297                 return 0;
1298         }
1299
1300         /* wait for data ready. does not fire an IRQ */
1301         floppy_controller_wait_data_ready_ms(fdc,1000);
1302
1303         rdo = 7;
1304         rd = floppy_controller_read_data(fdc,resp,rdo);
1305         if (rd < 1) {
1306                 do_floppy_controller_reset(fdc);
1307                 return 0;
1308         }
1309
1310         /* Read ID (xAh) response
1311          *
1312          *   Byte |  7   6   5   4   3   2   1   0
1313          *   -----+---------------------------------
1314          *      0 |              ST0
1315          *      1 |              ST1
1316          *      2 |              ST2
1317          *      3 |           Cylinder
1318          *      4 |             Head
1319          *      5 |        Sector Number
1320          *      6 |         Sector Size
1321          */
1322
1323         /* the command SHOULD terminate */
1324         floppy_controller_wait_data_ready(fdc,20);
1325         if (!floppy_controller_wait_busy_in_instruction(fdc,1000))
1326                 do_floppy_controller_reset(fdc);
1327
1328         /* accept ST0..ST2 from response and update */
1329         if (rd >= 3) {
1330                 fdc->st[0] = resp[0];
1331                 fdc->st[1] = resp[1];
1332                 fdc->st[2] = resp[2];
1333         }
1334         if (rd >= 4) {
1335                 fdc->cylinder = resp[3];
1336         }
1337
1338         return rd;
1339 }
1340
1341 void do_read_sector_id_demo(struct floppy_controller *fdc) {
1342         unsigned char headsel = current_phys_head;
1343         char resp[10];
1344         int c;
1345
1346         vga_moveto(0,0);
1347         vga_write_color(0x0E);
1348         vga_clear();
1349
1350         vga_write("Read Sector ID demo. Space to switch heads.\n\n");
1351
1352         do {
1353                 if (kbhit()) {
1354                         c = getch();
1355                         if (c == 0) c = getch() << 8;
1356
1357                         if (c == 27)
1358                                 break;
1359                         else if (c == ' ')
1360                                 headsel ^= 1;
1361                 }
1362
1363                 if ((c=do_read_sector_id(resp,fdc,headsel)) == 7) {
1364                         vga_moveto(0,2);
1365                         vga_write_color(0x0F);
1366
1367                         sprintf(tmp,"ST: %02xh %02xh %02xh %02xh\n",fdc->st[0],fdc->st[1],fdc->st[2],fdc->st[3]);
1368                         vga_write(tmp);
1369
1370                         sprintf(tmp,"C/H/S/sz: %-3u/%-3u/%-3u/%-3u       \n",resp[3],resp[4],resp[5],resp[6]);
1371                         vga_write(tmp);
1372                 }
1373                 else {
1374                         vga_moveto(0,2);
1375                         vga_write_color(0x0F);
1376
1377                         sprintf(tmp,"ST: --h --h --h --h (ret=%d)\n",c);
1378                         vga_write(tmp);
1379
1380                         sprintf(tmp,"C/H/S/sz: ---/---/---/---       \n");
1381                         vga_write(tmp);
1382                 }
1383         } while (1);
1384 }
1385
1386 signed long prompt_signed_track_number() {
1387         signed long track = 0;
1388         struct vga_msg_box box;
1389         VGA_ALPHA_PTR sco;
1390         char temp_str[16];
1391         int c,i=0;
1392
1393         vga_msg_box_create(&box,"Enter relative track number:",2,0);
1394         sco = vga_alpha_ram + ((box.y+2) * vga_width) + box.x + 2;
1395         while (1) {
1396                 c = getch();
1397                 if (c == 0) c = getch() << 8;
1398
1399                 if (c == 27) {
1400                         track = 0;
1401                         break;
1402                 }
1403                 else if (c == 13) {
1404                         if (i == 0) break;
1405                         temp_str[i] = 0;
1406                         if (isdigit(temp_str[0]))
1407                                 track = strtol(temp_str,NULL,0);
1408                         else
1409                                 track = 0;
1410
1411                         break;
1412                 }
1413                 else if (isdigit(c) || c == '-') {
1414                         if (i < 15) {
1415                                 sco[i] = c | 0x1E00;
1416                                 temp_str[i++] = c;
1417                         }
1418                 }
1419                 else if (c == 8) {
1420                         if (i > 0) i--;
1421                         sco[i] = ' ' | 0x1E00;
1422                 }
1423         }
1424         vga_msg_box_destroy(&box);
1425
1426         return track;
1427 }
1428
1429 unsigned long prompt_track_number() {
1430         unsigned long track = 0;
1431         struct vga_msg_box box;
1432         VGA_ALPHA_PTR sco;
1433         char temp_str[16];
1434         int c,i=0;
1435
1436         vga_msg_box_create(&box,"Enter track number:",2,0);
1437         sco = vga_alpha_ram + ((box.y+2) * vga_width) + box.x + 2;
1438         while (1) {
1439                 c = getch();
1440                 if (c == 0) c = getch() << 8;
1441
1442                 if (c == 27) {
1443                         track = (int)(~0UL);
1444                         break;
1445                 }
1446                 else if (c == 13) {
1447                         if (i == 0) break;
1448                         temp_str[i] = 0;
1449                         if (isdigit(temp_str[0]))
1450                                 track = strtol(temp_str,NULL,0);
1451                         else
1452                                 track = 0;
1453
1454                         break;
1455                 }
1456                 else if (isdigit(c)) {
1457                         if (i < 15) {
1458                                 sco[i] = c | 0x1E00;
1459                                 temp_str[i++] = c;
1460                         }
1461                 }
1462                 else if (c == 8) {
1463                         if (i > 0) i--;
1464                         sco[i] = ' ' | 0x1E00;
1465                 }
1466         }
1467         vga_msg_box_destroy(&box);
1468
1469         return track;
1470 }
1471
1472 void do_floppy_format_track(struct floppy_controller *fdc) {
1473         unsigned int data_length,unit_length;
1474         unsigned int returned_length = 0;
1475         char cmd[10],resp[10];
1476         int rd,rdo,wd,wdo,p;
1477         uint8_t nsect;
1478
1479         nsect = current_sectcount;
1480
1481         unit_length = 4;
1482         data_length = nsect * unit_length;
1483
1484         vga_moveto(0,0);
1485         vga_write_color(0x0E);
1486         vga_clear();
1487
1488         {
1489                 struct vga_msg_box vgabox;
1490                 char *w=tmp;
1491                 int i;
1492
1493                 w += sprintf(w,"I will format the track as having %u sectors/track,\n",
1494                         nsect);
1495                 w += sprintf(w,"first sector %u, logical track %u, %u bytes/sector.\n",
1496                         current_log_sect,current_log_track,128 << current_sectsize_p2);
1497                 w += sprintf(w,"I am using the sector number count for sectors/track.\n");
1498                 w += sprintf(w,"Since (last I checked) the head is currently located at\n");
1499                 w += sprintf(w,"track %u, physical track %u will be formatted logical\n",
1500                         fdc->cylinder,fdc->cylinder);
1501                 w += sprintf(w,"track %u. The track will be marked as having logical head %u\n",
1502                         current_log_track,
1503                         current_log_head);
1504                 w += sprintf(w,"and formatted on physical head %u\n",
1505                         current_phys_head);
1506                 w += sprintf(w,"\n");
1507                 w += sprintf(w,"Hit ENTER to continue if this is what you want,\nor ESC to stop now.");
1508
1509                 vga_msg_box_create(&vgabox,tmp,0,0);
1510                 i = wait_for_enter_or_escape();
1511                 vga_msg_box_destroy(&vgabox);
1512                 if (i == 27) return;
1513         }
1514
1515         sprintf(tmp,"Formatting C/H/S/sz/num %u/%u/%u/%u/%u\n",current_log_track,current_log_head,current_log_sect,128 << current_sectsize_p2,nsect);
1516         vga_write(tmp);
1517
1518         do_spin_up_motor(fdc,fdc->digital_out&3);
1519
1520         if (floppy_dma == NULL) return;
1521         if (data_length > floppy_dma->length) {
1522                 nsect = floppy_dma->length / unit_length;
1523                 data_length = nsect * unit_length;
1524         }
1525         if (data_length > floppy_dma->length) return;
1526
1527         /* sector pattern. 4 bytes for each sector to write */
1528         for (rd=0;rd < nsect;rd++) {
1529                 wd = rd * unit_length;
1530
1531                 /*   |
1532                  * --+---------------------------
1533                  * 0 | Cylinder
1534                  * 1 | Head
1535                  * 2 | Sector address
1536                  * 3 | Sector size code
1537                  */
1538                 floppy_dma->lin[wd++] = current_log_track;
1539                 floppy_dma->lin[wd++] = current_log_head;
1540                 floppy_dma->lin[wd++] = current_log_sect + rd;
1541                 floppy_dma->lin[wd++] = current_sectsize_p2;
1542         }
1543
1544         floppy_controller_read_status(fdc);
1545         if (!floppy_controller_can_write_data(fdc) || floppy_controller_busy_in_instruction(fdc))
1546                 do_floppy_controller_reset(fdc);
1547
1548         if (fdc->dma >= 0 && fdc->use_dma) {
1549                 outp(d8237_ioport(fdc->dma,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(fdc->dma) | D8237_MASK_SET); /* mask */
1550
1551                 outp(d8237_ioport(fdc->dma,D8237_REG_W_WRITE_MODE),
1552                         D8237_MODER_CHANNEL(fdc->dma) |
1553                         D8237_MODER_TRANSFER(D8237_MODER_XFER_READ) |
1554                         D8237_MODER_MODESEL(D8237_MODER_MODESEL_SINGLE));
1555
1556                 d8237_write_count(fdc->dma,data_length);
1557                 d8237_write_base(fdc->dma,floppy_dma->phys);
1558
1559                 outp(d8237_ioport(fdc->dma,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(fdc->dma)); /* unmask */
1560
1561                 inp(d8237_ioport(fdc->dma,D8237_REG_R_STATUS)); /* read status port to clear TC bits */
1562         }
1563
1564         /* Format Track (xDh)
1565          *
1566          *   Byte |  7   6   5   4   3   2   1   0
1567          *   -----+---------------------------------
1568          *      0 |  0  MF   0   0   1   1   0   1
1569          *      1 |  0   0   0   0   0  HD DR1 DR0
1570          *      2 |  <------ bytes/sector ------->
1571          *      3 |  <----- sectors/track ------->
1572          *      4 |  <--------- GAP3 ------------>
1573          *      5 |  <------ Fill byte ---------->
1574          *
1575          *         MF = MFM/FM
1576          *         HD = Head select (on PC platform, doesn't matter)
1577          *    DR1,DR0 = Drive select */
1578
1579         wdo = 6;
1580         cmd[0] = (mfm_mode?0x40:0x00)/* MFM */ + 0x0D/* FORMAT TRACK */;
1581         cmd[1] = (fdc->digital_out&3)+(current_phys_head&1?0x04:0x00)/* [1:0] = DR1,DR0 [2:2] = HD */;
1582         cmd[2] = current_sectsize_p2;
1583         cmd[3] = nsect;
1584         cmd[4] = current_phys_fmt_gap;
1585         cmd[5] = 0xAA;                  /* fill byte */
1586         wd = floppy_controller_write_data(fdc,cmd,wdo);
1587         if (wd < 2) {
1588                 vga_write("Write data port failed\n");
1589                 do_floppy_controller_reset(fdc);
1590                 return;
1591         }
1592
1593         vga_write("Format in progress\n");
1594
1595         /* fires an IRQ */
1596         if (fdc->use_dma) {
1597                 if (fdc->use_irq) floppy_controller_wait_irq(fdc,10000,1); /* 10 seconds */
1598                 floppy_controller_wait_data_ready_ms(fdc,1000);
1599         }
1600         else {
1601                 /* NOTES:
1602                  *
1603                  * Sun/Oracle VirtualBox floppy emulation bug: PIO mode doesn't seem to be supported properly on write
1604                  * for more than one sector. It will SEEM like it works, but when you read the data back only the first
1605                  * sector was ever written. On the same configuration, READ works fine using the same PIO mode. */
1606                 while (returned_length < data_length) {
1607                         if ((returned_length+unit_length) > data_length) break;
1608                         floppy_controller_wait_data_ready_ms(fdc,10000);
1609
1610                         p = floppy_controller_write_data_ndma(fdc,floppy_dma->lin + returned_length,unit_length);
1611                         if (p < 0 || p > unit_length) {
1612                                 sprintf(tmp,"NDMA write failed %d (%02xh)\n",p,fdc->main_status);
1613                                 vga_write(tmp);
1614                                 p = 0;
1615                         }
1616
1617                         returned_length += p;
1618                         /* stop on incomplete transfer */
1619                         if (p != unit_length) break;
1620                 }
1621         }
1622
1623         rdo = 7;
1624         rd = floppy_controller_read_data(fdc,resp,rdo);
1625         if (rd < 1) {
1626                 vga_write("Write data port failed\n");
1627                 do_floppy_controller_reset(fdc);
1628                 return;
1629         }
1630
1631         /* Format Track (xDh) response
1632          *
1633          *   Byte |  7   6   5   4   3   2   1   0
1634          *   -----+---------------------------------
1635          *      0 |              ST0
1636          *      1 |              ST1
1637          *      2 |              ST2
1638          *      3 |               ?
1639          *      4 |               ?
1640          *      5 |               ?
1641          *      6 |               ?
1642          */
1643
1644         /* the command SHOULD terminate */
1645         floppy_controller_wait_data_ready(fdc,20);
1646         if (!floppy_controller_wait_busy_in_instruction(fdc,1000))
1647                 do_floppy_controller_reset(fdc);
1648
1649         /* accept ST0..ST2 from response and update */
1650         if (rd >= 3) {
1651                 fdc->st[0] = resp[0];
1652                 fdc->st[1] = resp[1];
1653                 fdc->st[2] = resp[2];
1654         }
1655         if (rd >= 4) {
1656                 fdc->cylinder = resp[3];
1657         }
1658
1659         /* (if DMA) did we get any data? */
1660         if (fdc->dma >= 0 && fdc->use_dma) {
1661                 uint32_t dma_len = d8237_read_count(fdc->dma);
1662                 uint8_t status = inp(d8237_ioport(fdc->dma,D8237_REG_R_STATUS));
1663
1664                 /* some DMA controllers reset the count back to the original value on terminal count.
1665                  * so if the DMA controller says terminal count, the true count is zero */
1666                 if (status&D8237_STATUS_TC(fdc->dma)) dma_len = 0;
1667
1668                 if (dma_len > (uint32_t)data_length) dma_len = (uint32_t)data_length;
1669                 returned_length = (unsigned int)((uint32_t)data_length - dma_len);
1670         }
1671
1672         sprintf(tmp,"%lu bytes written\n",(unsigned long)returned_length);
1673         vga_write(tmp);
1674         vga_write("\n");
1675
1676         wait_for_enter_or_escape();
1677 }
1678
1679 void do_floppy_write_test(struct floppy_controller *fdc) {
1680         unsigned int data_length,unit_length;
1681         unsigned int returned_length = 0;
1682         char cmd[10],resp[10];
1683         uint8_t cyl,head,sect,ssz,nsect;
1684         int rd,rdo,wd,wdo,x,p;
1685
1686         cyl = current_log_track;
1687         head = current_log_head;
1688         sect = current_log_sect;
1689         nsect = current_sectcount;
1690         ssz = current_sectsize_p2;
1691
1692         if (current_sectsize_p2 > 0)
1693                 unit_length = (128 << ssz);
1694         else
1695                 unit_length = current_sectsize_smaller;
1696
1697         data_length = nsect * unit_length;
1698
1699         vga_moveto(0,0);
1700         vga_write_color(0x0E);
1701         vga_clear();
1702
1703         sprintf(tmp,"Writing C/H/S/sz/num %u/%u/%u/%u/%u\n",cyl,head,sect,unit_length,nsect);
1704         vga_write(tmp);
1705
1706         do_spin_up_motor(fdc,fdc->digital_out&3);
1707
1708         if (floppy_dma == NULL) return;
1709         if (data_length > floppy_dma->length) {
1710                 nsect = floppy_dma->length / unit_length;
1711                 data_length = nsect * unit_length;
1712         }
1713         if (data_length > floppy_dma->length) return;
1714
1715         for (x=0;(unsigned int)x < data_length;x++) floppy_dma->lin[x] = x;
1716
1717         floppy_controller_read_status(fdc);
1718         if (!floppy_controller_can_write_data(fdc) || floppy_controller_busy_in_instruction(fdc))
1719                 do_floppy_controller_reset(fdc);
1720
1721         if (fdc->dma >= 0 && fdc->use_dma) {
1722                 outp(d8237_ioport(fdc->dma,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(fdc->dma) | D8237_MASK_SET); /* mask */
1723
1724                 outp(d8237_ioport(fdc->dma,D8237_REG_W_WRITE_MODE),
1725                         D8237_MODER_CHANNEL(fdc->dma) |
1726                         D8237_MODER_TRANSFER(D8237_MODER_XFER_READ) |
1727                         D8237_MODER_MODESEL(D8237_MODER_MODESEL_SINGLE));
1728
1729                 d8237_write_count(fdc->dma,data_length);
1730                 d8237_write_base(fdc->dma,floppy_dma->phys);
1731
1732                 outp(d8237_ioport(fdc->dma,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(fdc->dma)); /* unmask */
1733
1734                 inp(d8237_ioport(fdc->dma,D8237_REG_R_STATUS)); /* read status port to clear TC bits */
1735         }
1736
1737         /* Write Sector (x5h)
1738          *
1739          *   Byte |  7   6   5   4   3   2   1   0
1740          *   -----+---------------------------------
1741          *      0 | MT  MF   0   0   0   1   0   1
1742          *      1 |  x   x   x   x   x  HD DR1 DR0
1743          *      2 |            Cylinder
1744          *      3 |              Head
1745          *      4 |         Sector Number
1746          *      5 |          Sector Size
1747          *      6 |    Track length/last sector
1748          *      7 |        Length of GAP3
1749          *      8 |          Data Length
1750          *
1751          *         MT = Multi-track
1752          *         MF = MFM/FM
1753          *         HD = Head select (on PC platform, doesn't matter)
1754          *    DR1,DR0 = Drive select */
1755
1756         /* NTS: To ensure we read only one sector, Track length/last sector must equal
1757          * Sector Number field. The floppy controller stops reading on error or when
1758          * sector number matches. This is very important for the PIO mode of this code,
1759          * else we'll never complete reading properly and never get to reading back
1760          * the status bytes. */
1761
1762         wdo = 9;
1763         cmd[0] = (allow_multitrack?0x80:0x00)/*Multitrack*/ + (mfm_mode?0x40:0x00)/* MFM */ + 0x05/* WRITE DATA */;
1764         cmd[1] = (fdc->digital_out&3)+(current_phys_head&1?0x04:0x00)/* [1:0] = DR1,DR0 [2:2] = HD */;
1765         cmd[2] = cyl;   /* cyl=0 */
1766         cmd[3] = head;  /* head=0 */
1767         cmd[4] = sect;  /* sector=1 */
1768         cmd[5] = ssz;   /* sector size=2 (512 bytes) */
1769         cmd[6] = sect+nsect-1; /* last sector of the track (what sector to stop at). */
1770         cmd[7] = current_phys_rw_gap;
1771         cmd[8] = current_sectsize_smaller; /* DTL (not used if 256 or larger) */
1772         wd = floppy_controller_write_data(fdc,cmd,wdo);
1773         if (wd < 2) {
1774                 vga_write("Write data port failed\n");
1775                 do_floppy_controller_reset(fdc);
1776                 return;
1777         }
1778
1779         vga_write("Write in progress\n");
1780
1781         /* fires an IRQ */
1782         if (fdc->use_dma) {
1783                 if (fdc->use_irq) floppy_controller_wait_irq(fdc,10000,1); /* 10 seconds */
1784                 floppy_controller_wait_data_ready_ms(fdc,1000);
1785         }
1786         else {
1787                 /* NOTES:
1788                  *
1789                  * Sun/Oracle VirtualBox floppy emulation bug: PIO mode doesn't seem to be supported properly on write
1790                  * for more than one sector. It will SEEM like it works, but when you read the data back only the first
1791                  * sector was ever written. On the same configuration, READ works fine using the same PIO mode. */
1792                 while (returned_length < data_length) {
1793                         if ((returned_length+unit_length) > data_length) break;
1794                         floppy_controller_wait_data_ready_ms(fdc,10000);
1795
1796                         p = floppy_controller_write_data_ndma(fdc,floppy_dma->lin + returned_length,unit_length);
1797                         if (p < 0 || p > unit_length) {
1798                                 sprintf(tmp,"NDMA write failed %d (%02xh)\n",p,fdc->main_status);
1799                                 vga_write(tmp);
1800                                 p = 0;
1801                         }
1802
1803                         returned_length += p;
1804                         /* stop on incomplete transfer */
1805                         if (p != unit_length) break;
1806                 }
1807         }
1808
1809         rdo = 7;
1810         rd = floppy_controller_read_data(fdc,resp,rdo);
1811         if (rd < 1) {
1812                 vga_write("Write data port failed\n");
1813                 do_floppy_controller_reset(fdc);
1814                 return;
1815         }
1816
1817         /* Write Sector (x5h) response
1818          *
1819          *   Byte |  7   6   5   4   3   2   1   0
1820          *   -----+---------------------------------
1821          *      0 |              ST0
1822          *      1 |              ST1
1823          *      2 |              ST2
1824          *      3 |           Cylinder
1825          *      4 |             Head
1826          *      5 |        Sector Number
1827          *      6 |         Sector Size
1828          */
1829
1830         /* the command SHOULD terminate */
1831         floppy_controller_wait_data_ready(fdc,20);
1832         if (!floppy_controller_wait_busy_in_instruction(fdc,1000))
1833                 do_floppy_controller_reset(fdc);
1834
1835         /* accept ST0..ST2 from response and update */
1836         if (rd >= 3) {
1837                 fdc->st[0] = resp[0];
1838                 fdc->st[1] = resp[1];
1839                 fdc->st[2] = resp[2];
1840         }
1841         if (rd >= 4) {
1842                 fdc->cylinder = resp[3];
1843         }
1844
1845         /* (if DMA) did we get any data? */
1846         if (fdc->dma >= 0 && fdc->use_dma) {
1847                 uint32_t dma_len = d8237_read_count(fdc->dma);
1848                 uint8_t status = inp(d8237_ioport(fdc->dma,D8237_REG_R_STATUS));
1849
1850                 /* some DMA controllers reset the count back to the original value on terminal count.
1851                  * so if the DMA controller says terminal count, the true count is zero */
1852                 if (status&D8237_STATUS_TC(fdc->dma)) dma_len = 0;
1853
1854                 if (dma_len > (uint32_t)data_length) dma_len = (uint32_t)data_length;
1855                 returned_length = (unsigned int)((uint32_t)data_length - dma_len);
1856         }
1857
1858         sprintf(tmp,"%lu bytes written\n",(unsigned long)returned_length);
1859         vga_write(tmp);
1860         vga_write("\n");
1861
1862         wait_for_enter_or_escape();
1863 }
1864
1865 void do_floppy_read_test(struct floppy_controller *fdc) {
1866         unsigned int data_length,unit_length;
1867         unsigned int returned_length = 0;
1868         char cmd[10],resp[10];
1869         uint8_t cyl,head,sect,ssz,nsect;
1870         int rd,rdo,wd,wdo,x,y,p;
1871
1872         cyl = current_log_track;
1873         head = current_log_head;
1874         sect = current_log_sect;
1875         nsect = current_sectcount;
1876         ssz = current_sectsize_p2;
1877
1878         if (current_sectsize_p2 > 0)
1879                 unit_length = (128 << ssz);
1880         else
1881                 unit_length = current_sectsize_smaller;
1882
1883         data_length = nsect * unit_length;
1884
1885         vga_moveto(0,0);
1886         vga_write_color(0x0E);
1887         vga_clear();
1888
1889         sprintf(tmp,"Reading C/H/S/sz/num %u/%u/%u/%u/%u\n",cyl,head,sect,unit_length,nsect);
1890         vga_write(tmp);
1891
1892         do_spin_up_motor(fdc,fdc->digital_out&3);
1893
1894         if (floppy_dma == NULL) return;
1895         if (data_length > floppy_dma->length) {
1896                 nsect = floppy_dma->length / unit_length;
1897                 data_length = nsect * unit_length;
1898         }
1899         if (data_length > floppy_dma->length) return;
1900
1901 #if TARGET_MSDOS == 32
1902         memset(floppy_dma->lin,0,data_length);
1903 #else
1904         _fmemset(floppy_dma->lin,0,data_length);
1905 #endif
1906
1907         floppy_controller_read_status(fdc);
1908         if (!floppy_controller_can_write_data(fdc) || floppy_controller_busy_in_instruction(fdc))
1909                 do_floppy_controller_reset(fdc);
1910
1911         if (fdc->dma >= 0 && fdc->use_dma) {
1912                 outp(d8237_ioport(fdc->dma,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(fdc->dma) | D8237_MASK_SET); /* mask */
1913
1914                 outp(d8237_ioport(fdc->dma,D8237_REG_W_WRITE_MODE),
1915                         D8237_MODER_CHANNEL(fdc->dma) |
1916                         D8237_MODER_TRANSFER(D8237_MODER_XFER_WRITE) |
1917                         D8237_MODER_MODESEL(D8237_MODER_MODESEL_SINGLE));
1918
1919                 d8237_write_count(fdc->dma,data_length);
1920                 d8237_write_base(fdc->dma,floppy_dma->phys);
1921
1922                 outp(d8237_ioport(fdc->dma,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(fdc->dma)); /* unmask */
1923
1924                 inp(d8237_ioport(fdc->dma,D8237_REG_R_STATUS)); /* read status port to clear TC bits */
1925         }
1926
1927         /* Read Sector (x6h)
1928          *
1929          *   Byte |  7   6   5   4   3   2   1   0
1930          *   -----+---------------------------------
1931          *      0 | MT  MF  SK   0   0   1   1   0
1932          *      1 |  x   x   x   x   x  HD DR1 DR0
1933          *      2 |            Cylinder
1934          *      3 |              Head
1935          *      4 |         Sector Number
1936          *      5 |          Sector Size
1937          *      6 |    Track length/last sector
1938          *      7 |        Length of GAP3
1939          *      8 |          Data Length
1940          *
1941          *         MT = Multi-track
1942          *         MF = MFM/FM
1943          *         SK = Skip deleted address mark
1944          *         HD = Head select (on PC platform, doesn't matter)
1945          *    DR1,DR0 = Drive select */
1946
1947         /* NTS: To ensure we read only one sector, Track length/last sector must equal
1948          * Sector Number field. The floppy controller stops reading on error or when
1949          * sector number matches. This is very important for the PIO mode of this code,
1950          * else we'll never complete reading properly and never get to reading back
1951          * the status bytes. */
1952
1953         wdo = 9;
1954         cmd[0] = (allow_multitrack?0x80:0x00)/*Multitrack*/ + (mfm_mode?0x40:0x00)/* MFM */ + 0x06/* READ DATA */;
1955         cmd[1] = (fdc->digital_out&3)+(current_phys_head&1?0x04:0x00)/* [1:0] = DR1,DR0 [2:2] = HD */;
1956         cmd[2] = cyl;   /* cyl=0 */
1957         cmd[3] = head;  /* head=0 */
1958         cmd[4] = sect;  /* sector=1 */
1959         cmd[5] = ssz;   /* sector size=2 (512 bytes) */
1960         cmd[6] = sect+nsect-1; /* last sector of the track (what sector to stop at). */
1961         cmd[7] = current_phys_rw_gap;
1962         cmd[8] = current_sectsize_smaller; /* DTL (not used if 256 or larger) */
1963         wd = floppy_controller_write_data(fdc,cmd,wdo);
1964         if (wd < 2) {
1965                 vga_write("Write data port failed\n");
1966                 do_floppy_controller_reset(fdc);
1967                 return;
1968         }
1969
1970         vga_write("Read in progress\n");
1971
1972         /* fires an IRQ */
1973         if (fdc->use_dma) {
1974                 if (fdc->use_irq) floppy_controller_wait_irq(fdc,10000,1); /* 10 seconds */
1975                 floppy_controller_wait_data_ready_ms(fdc,1000);
1976         }
1977         else {
1978                 while (returned_length < data_length) {
1979                         if ((returned_length+unit_length) > data_length) break;
1980                         floppy_controller_wait_data_ready_ms(fdc,10000);
1981
1982                         p = floppy_controller_read_data_ndma(fdc,floppy_dma->lin + returned_length,unit_length);
1983                         if (p < 0 || p > unit_length) {
1984                                 sprintf(tmp,"NDMA read failed %d (%02xh)\n",p,fdc->main_status);
1985                                 vga_write(tmp);
1986                                 p = 0;
1987                         }
1988
1989                         returned_length += p;
1990                         /* stop on incomplete transfer */
1991                         if (p != unit_length) break;
1992                 }
1993         }
1994
1995         rdo = 7;
1996         rd = floppy_controller_read_data(fdc,resp,rdo);
1997         if (rd < 1) {
1998                 vga_write("Read data port failed\n");
1999                 do_floppy_controller_reset(fdc);
2000                 return;
2001         }
2002
2003         /* Read Sector (x6h) response
2004          *
2005          *   Byte |  7   6   5   4   3   2   1   0
2006          *   -----+---------------------------------
2007          *      0 |              ST0
2008          *      1 |              ST1
2009          *      2 |              ST2
2010          *      3 |           Cylinder
2011          *      4 |             Head
2012          *      5 |        Sector Number
2013          *      6 |         Sector Size
2014          */
2015
2016         /* the command SHOULD terminate */
2017         floppy_controller_wait_data_ready(fdc,20);
2018         if (!floppy_controller_wait_busy_in_instruction(fdc,1000))
2019                 do_floppy_controller_reset(fdc);
2020
2021         /* accept ST0..ST2 from response and update */
2022         if (rd >= 3) {
2023                 fdc->st[0] = resp[0];
2024                 fdc->st[1] = resp[1];
2025                 fdc->st[2] = resp[2];
2026         }
2027         if (rd >= 4) {
2028                 fdc->cylinder = resp[3];
2029         }
2030
2031         /* (if DMA) did we get any data? */
2032         if (fdc->dma >= 0 && fdc->use_dma) {
2033                 uint32_t dma_len = d8237_read_count(fdc->dma);
2034                 uint8_t status = inp(d8237_ioport(fdc->dma,D8237_REG_R_STATUS));
2035
2036                 /* some DMA controllers reset the count back to the original value on terminal count.
2037                  * so if the DMA controller says terminal count, the true count is zero */
2038                 if (status&D8237_STATUS_TC(fdc->dma)) dma_len = 0;
2039
2040                 if (dma_len > (uint32_t)data_length) dma_len = (uint32_t)data_length;
2041                 returned_length = (unsigned int)((uint32_t)data_length - dma_len);
2042         }
2043
2044         sprintf(tmp,"%lu bytes received\n",(unsigned long)returned_length);
2045         vga_write(tmp);
2046         vga_write("\n");
2047
2048         vga_write_color(0x0F);
2049         for (p=0;p == 0 || p < ((returned_length+255)/256);p++) {
2050                 for (y=0;y < 16;y++) {
2051                         vga_moveto(0,6+y);
2052                         for (x=0;x < 16;x++) {
2053                                 sprintf(tmp,"%02x ",floppy_dma->lin[((y+(p*16))*16)+x]);
2054                                 vga_write(tmp);
2055                         }
2056
2057                         vga_moveto(50,6+y);
2058                         for (x=0;x < 16;x++) {
2059                                 tmp[0] = floppy_dma->lin[((y+(p*16))*16)+x];
2060                                 if (tmp[0] < 32) tmp[0] = '.';
2061                                 tmp[1] = 0;
2062                                 vga_write(tmp);
2063                         }
2064                 }
2065
2066                 if (wait_for_enter_or_escape() == 27)
2067                         break;
2068         }
2069 }
2070
2071 void do_floppy_controller_read_tests(struct floppy_controller *fdc) {
2072         char backredraw=1;
2073         VGA_ALPHA_PTR vga;
2074         unsigned int x,y;
2075         char redraw=1;
2076         int select=-1;
2077         int c;
2078
2079         while (1) {
2080                 if (backredraw) {
2081                         vga = vga_alpha_ram;
2082                         backredraw = 0;
2083                         redraw = 1;
2084
2085                         for (y=0;y < vga_height;y++) {
2086                                 for (x=0;x < vga_width;x++) {
2087                                         *vga++ = 0x1E00 + 177;
2088                                 }
2089                         }
2090
2091                         vga_moveto(0,0);
2092
2093                         vga_write_color(0x1F);
2094                         vga_write("        Read tests ");
2095                         sprintf(tmp,"@%X",fdc->base_io);
2096                         vga_write(tmp);
2097                         if (fdc->irq >= 0) {
2098                                 sprintf(tmp," IRQ %d",fdc->irq);
2099                                 vga_write(tmp);
2100                         }
2101                         if (fdc->dma >= 0) {
2102                                 sprintf(tmp," DMA %d",fdc->dma);
2103                                 vga_write(tmp);
2104                         }
2105                         if (floppy_dma != NULL) {
2106                                 sprintf(tmp," phys=%08lxh len=%04lxh",(unsigned long)floppy_dma->phys,(unsigned long)floppy_dma->length);
2107                                 vga_write(tmp);
2108                         }
2109                         while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
2110                 }
2111
2112                 if (redraw) {
2113                         redraw = 0;
2114
2115                         floppy_controller_read_status(fdc);
2116                         floppy_controller_read_DIR(fdc);
2117                         floppy_controller_read_ps2_status(fdc);
2118
2119                         y = 2;
2120                         vga_moveto(8,y++);
2121                         vga_write_color(0x0F);
2122                         sprintf(tmp,"DOR %02xh DIR %02xh Stat %02xh CCR %02xh cyl=%-3u",
2123                                 fdc->digital_out,fdc->digital_in,
2124                                 fdc->main_status,fdc->control_cfg,
2125                                 fdc->cylinder);
2126                         vga_write(tmp);
2127
2128                         vga_moveto(8,y++);
2129                         vga_write_color(0x0F);
2130                         sprintf(tmp,"ST0..3: %02x %02x %02x %02x PS/2 %02x %02x",
2131                                 fdc->st[0],fdc->st[1],fdc->st[2],fdc->st[3],
2132                                 fdc->ps2_status[0],fdc->ps2_status[1]);
2133                         vga_write(tmp);
2134
2135                         y = 5;
2136                         vga_moveto(8,y++);
2137                         vga_write_color((select == -1) ? 0x70 : 0x0F);
2138                         vga_write("FDC menu");
2139                         while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
2140                         y++;
2141
2142                         vga_moveto(8,y++);
2143                         vga_write_color((select == 0) ? 0x70 : 0x0F);
2144                         vga_write("Read sector");
2145                         while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
2146                 }
2147
2148                 c = getch();
2149                 if (c == 0) c = getch() << 8;
2150
2151                 if (c == 27) {
2152                         break;
2153                 }
2154                 else if (c == 13) {
2155                         if (select == -1) {
2156                                 break;
2157                         }
2158                         else if (select == 0) { /* Read Sector */
2159                                 do_floppy_read_test(fdc);
2160                                 backredraw = 1;
2161                         }
2162                 }
2163                 else if (c == 0x4800) {
2164                         if (--select < -1)
2165                                 select = 0;
2166
2167                         redraw = 1;
2168                 }
2169                 else if (c == 0x5000) {
2170                         if (++select > 0)
2171                                 select = -1;
2172
2173                         redraw = 1;
2174                 }
2175         }
2176 }
2177
2178 void do_floppy_controller_write_tests(struct floppy_controller *fdc) {
2179         char backredraw=1;
2180         VGA_ALPHA_PTR vga;
2181         unsigned int x,y;
2182         char redraw=1;
2183         int select=-1;
2184         int c;
2185
2186         while (1) {
2187                 if (backredraw) {
2188                         vga = vga_alpha_ram;
2189                         backredraw = 0;
2190                         redraw = 1;
2191
2192                         for (y=0;y < vga_height;y++) {
2193                                 for (x=0;x < vga_width;x++) {
2194                                         *vga++ = 0x1E00 + 177;
2195                                 }
2196                         }
2197
2198                         vga_moveto(0,0);
2199
2200                         vga_write_color(0x1F);
2201                         vga_write("        Write tests ");
2202                         sprintf(tmp,"@%X",fdc->base_io);
2203                         vga_write(tmp);
2204                         if (fdc->irq >= 0) {
2205                                 sprintf(tmp," IRQ %d",fdc->irq);
2206                                 vga_write(tmp);
2207                         }
2208                         if (fdc->dma >= 0) {
2209                                 sprintf(tmp," DMA %d",fdc->dma);
2210                                 vga_write(tmp);
2211                         }
2212                         if (floppy_dma != NULL) {
2213                                 sprintf(tmp," phys=%08lxh len=%04lxh",(unsigned long)floppy_dma->phys,(unsigned long)floppy_dma->length);
2214                                 vga_write(tmp);
2215                         }
2216                         while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
2217                 }
2218
2219                 if (redraw) {
2220                         redraw = 0;
2221
2222                         floppy_controller_read_status(fdc);
2223                         floppy_controller_read_DIR(fdc);
2224                         floppy_controller_read_ps2_status(fdc);
2225
2226                         y = 2;
2227                         vga_moveto(8,y++);
2228                         vga_write_color(0x0F);
2229                         sprintf(tmp,"DOR %02xh DIR %02xh Stat %02xh CCR %02xh cyl=%-3u",
2230                                 fdc->digital_out,fdc->digital_in,
2231                                 fdc->main_status,fdc->control_cfg,
2232                                 fdc->cylinder);
2233                         vga_write(tmp);
2234
2235                         vga_moveto(8,y++);
2236                         vga_write_color(0x0F);
2237                         sprintf(tmp,"ST0..3: %02x %02x %02x %02x PS/2 %02x %02x",
2238                                 fdc->st[0],fdc->st[1],fdc->st[2],fdc->st[3],
2239                                 fdc->ps2_status[0],fdc->ps2_status[1]);
2240                         vga_write(tmp);
2241
2242                         y = 5;
2243                         vga_moveto(8,y++);
2244                         vga_write_color((select == -1) ? 0x70 : 0x0F);
2245                         vga_write("FDC menu");
2246                         while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
2247                         y++;
2248
2249                         vga_moveto(8,y++);
2250                         vga_write_color((select == 0) ? 0x70 : 0x0F);
2251                         vga_write("Write sector");
2252                         while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
2253                 }
2254
2255                 c = getch();
2256                 if (c == 0) c = getch() << 8;
2257
2258                 if (c == 27) {
2259                         break;
2260                 }
2261                 else if (c == 13) {
2262                         if (select == -1) {
2263                                 break;
2264                         }
2265                         else if (select == 0) { /* Write Sector */
2266                                 do_floppy_write_test(fdc);
2267                                 backredraw = 1;
2268                         }
2269                 }
2270                 else if (c == 0x4800) {
2271                         if (--select < -1)
2272                                 select = 0;
2273
2274                         redraw = 1;
2275                 }
2276                 else if (c == 0x5000) {
2277                         if (++select > 0)
2278                                 select = -1;
2279
2280                         redraw = 1;
2281                 }
2282         }
2283 }
2284
2285 void prompt_position() {
2286         uint64_t tmp;
2287         int en_mfm,en_mt;
2288         int cyl,head,phead,sect,ssz,sszm,scount,gaprw,gapfmt;
2289         struct vga_msg_box box;
2290         unsigned char redraw=1;
2291         unsigned char ok=1;
2292         char temp_str[64];
2293         int select=0;
2294         int c,i=0;
2295
2296         en_mfm = mfm_mode;
2297         en_mt = allow_multitrack;
2298         sszm = current_sectsize_smaller;
2299         gapfmt = current_phys_fmt_gap;
2300         gaprw = current_phys_rw_gap;
2301         scount = current_sectcount;
2302         phead = current_phys_head;
2303         ssz = current_sectsize_p2;
2304         cyl = current_log_track;
2305         sect = current_log_sect;
2306         head = current_log_head;
2307
2308         vga_msg_box_create(&box,
2309                 "Edit position:                  ",
2310                 2+10,0);
2311         while (1) {
2312                 char recalc = 0;
2313                 char rekey = 0;
2314
2315                 if (redraw) {
2316                         redraw = 0;
2317
2318                         vga_moveto(box.x+2,box.y+2+1 + 0);
2319                         vga_write_color(0x1E);
2320                         vga_write("Cylinder:  ");
2321                         vga_write_color(select == 0 ? 0x70 : 0x1E);
2322                         i=sprintf(temp_str,"%u",cyl);
2323                         while (i < (box.w-4-11)) temp_str[i++] = ' ';
2324                         temp_str[i] = 0;
2325                         vga_write(temp_str);
2326
2327                         vga_moveto(box.x+2,box.y+2+1 + 1);
2328                         vga_write_color(0x1E);
2329                         vga_write("Head:      ");
2330                         vga_write_color(select == 1 ? 0x70 : 0x1E);
2331                         i=sprintf(temp_str,"%u",head);
2332                         while (i < (box.w-4-11)) temp_str[i++] = ' ';
2333                         temp_str[i] = 0;
2334                         vga_write(temp_str);
2335
2336                         vga_moveto(box.x+2,box.y+2+1 + 2);
2337                         vga_write_color(0x1E);
2338                         vga_write("Sector:    ");
2339                         vga_write_color(select == 2 ? 0x70 : 0x1E);
2340                         i=sprintf(temp_str,"%u",sect);
2341                         while (i < (box.w-4-11)) temp_str[i++] = ' ';
2342                         temp_str[i] = 0;
2343                         vga_write(temp_str);
2344
2345                         vga_moveto(box.x+2,box.y+2+1 + 3);
2346                         vga_write_color(0x1E);
2347                         vga_write("Sect. size:");
2348                         vga_write_color(select == 3 ? 0x70 : 0x1E);
2349                         if (ssz > 0)
2350                                 i=sprintf(temp_str,"%u",128 << ssz);
2351                         else
2352                                 i=sprintf(temp_str,"%u",sszm);
2353                         while (i < (box.w-4-11)) temp_str[i++] = ' ';
2354                         temp_str[i] = 0;
2355                         vga_write(temp_str);
2356
2357                         vga_moveto(box.x+2,box.y+2+1 + 4);
2358                         vga_write_color(0x1E);
2359                         vga_write("Phys. Head:");
2360                         vga_write_color(select == 4 ? 0x70 : 0x1E);
2361                         i=sprintf(temp_str,"%u",phead);
2362                         while (i < (box.w-4-11)) temp_str[i++] = ' ';
2363                         temp_str[i] = 0;
2364                         vga_write(temp_str);
2365
2366                         vga_moveto(box.x+2,box.y+2+1 + 5);
2367                         vga_write_color(0x1E);
2368                         vga_write("Sect count:");
2369                         vga_write_color(select == 5 ? 0x70 : 0x1E);
2370                         i=sprintf(temp_str,"%u",scount);
2371                         while (i < (box.w-4-11)) temp_str[i++] = ' ';
2372                         temp_str[i] = 0;
2373                         vga_write(temp_str);
2374
2375                         vga_moveto(box.x+2,box.y+2+1 + 6);
2376                         vga_write_color(0x1E);
2377                         vga_write("Multitrack:");
2378                         vga_write_color(select == 6 ? 0x70 : 0x1E);
2379                         i=sprintf(temp_str,"%s",en_mt?"On":"Off");
2380                         while (i < (box.w-4-11)) temp_str[i++] = ' ';
2381                         temp_str[i] = 0;
2382                         vga_write(temp_str);
2383
2384                         vga_moveto(box.x+2,box.y+2+1 + 7);
2385                         vga_write_color(0x1E);
2386                         vga_write("FM/MFM:    ");
2387                         vga_write_color(select == 7 ? 0x70 : 0x1E);
2388                         i=sprintf(temp_str,"%s",en_mfm?"MFM":"FM");
2389                         while (i < (box.w-4-11)) temp_str[i++] = ' ';
2390                         temp_str[i] = 0;
2391                         vga_write(temp_str);
2392
2393                         vga_moveto(box.x+2,box.y+2+1 + 8);
2394                         vga_write_color(0x1E);
2395                         vga_write("R/W gap:   ");
2396                         vga_write_color(select == 8 ? 0x70 : 0x1E);
2397                         i=sprintf(temp_str,"%u",gaprw);
2398                         while (i < (box.w-4-11)) temp_str[i++] = ' ';
2399                         temp_str[i] = 0;
2400                         vga_write(temp_str);
2401
2402                         vga_moveto(box.x+2,box.y+2+1 + 9);
2403                         vga_write_color(0x1E);
2404                         vga_write("Fmt gap:   ");
2405                         vga_write_color(select == 9 ? 0x70 : 0x1E);
2406                         i=sprintf(temp_str,"%u",gapfmt);
2407                         while (i < (box.w-4-11)) temp_str[i++] = ' ';
2408                         temp_str[i] = 0;
2409                         vga_write(temp_str);
2410                 }
2411
2412                 c = getch();
2413                 if (c == 0) c = getch() << 8;
2414
2415 nextkey:        if (c == 27) {
2416                         ok = 0;
2417                         break;
2418                 }
2419                 else if (c == 13) {
2420                         ok = 1;
2421                         break;
2422                 }
2423                 else if (c == 0x4800) {
2424                         if (--select < 0) select = 9;
2425                         redraw = 1;
2426                 }
2427                 else if (c == 0x5000 || c == 9/*tab*/) {
2428                         if (++select > 9) select = 0;
2429                         redraw = 1;
2430                 }
2431
2432                 else if (c == 0x4B00) { /* left */
2433                         switch (select) {
2434                                 case 0:
2435                                         if (cyl == 0) cyl = 255;
2436                                         else cyl--;
2437                                         break;
2438                                 case 1:
2439                                         if (head == 0) head = 255;
2440                                         else head--;
2441                                         break;
2442                                 case 2:
2443                                         if (sect == 0) sect = 255;
2444                                         else sect--;
2445                                         break;
2446                                 case 3:
2447                                         if (ssz == 0) {
2448                                                 if (sszm <= 1) {
2449                                                         sszm = 0xFF;
2450                                                         ssz = 7;
2451                                                 }
2452                                                 else {
2453                                                         sszm--;
2454                                                 }
2455                                         }
2456                                         else {
2457                                                 ssz--;
2458                                         }
2459                                         break;
2460                                 case 4:
2461                                         if (phead == 0) phead = 1;
2462                                         else phead--;
2463                                         break;
2464                                 case 5:
2465                                         if (scount <= 1) scount = 256;
2466                                         else scount--;
2467                                         break;
2468                                 case 6:
2469                                         en_mt = !en_mt;
2470                                         break;
2471                                 case 7:
2472                                         en_mfm = !en_mfm;
2473                                         break;
2474                                 case 8:
2475                                         if (gaprw == 0) gaprw = 255;
2476                                         else gaprw--;
2477                                         break;
2478                                 case 9:
2479                                         if (gapfmt == 0) gapfmt = 255;
2480                                         else gapfmt--;
2481                                         break;
2482                         };
2483
2484                         recalc = 1;
2485                         redraw = 1;
2486                 }
2487                 else if (c == 0x4D00) { /* right */
2488                         switch (select) {
2489                                 case 0:
2490                                         if ((++cyl) >= 256) cyl = 0;
2491                                         break;
2492                                 case 1:
2493                                         if ((++head) >= 256) head = 0;
2494                                         break;
2495                                 case 2:
2496                                         if ((++sect) >= 256) sect = 0;
2497                                         break;
2498                                 case 3:
2499                                         if (ssz == 0) {
2500                                                 if ((++sszm) > 255) {
2501                                                         sszm = 0xFF;
2502                                                         ssz = 1;
2503                                                 }
2504                                         }
2505                                         else {
2506                                                 if ((++ssz) > 7) {
2507                                                         ssz = 0;
2508                                                         sszm = 1;
2509                                                 }
2510                                         }
2511                                         break;
2512                                 case 4:
2513                                         if ((++phead) >= 2) phead = 0;
2514                                         break;
2515                                 case 5:
2516                                         if ((++scount) >= 257) scount = 1;
2517                                         break;
2518                                 case 6:
2519                                         en_mt = !en_mt;
2520                                         break;
2521                                 case 7:
2522                                         en_mfm = !en_mfm;
2523                                         break;
2524                                 case 8:
2525                                         if (gaprw == 255) gaprw = 0;
2526                                         else gaprw++;
2527                                         break;
2528                                 case 9:
2529                                         if (gapfmt == 255) gapfmt = 0;
2530                                         else gapfmt++;
2531                                         break;
2532                         };
2533
2534                         recalc = 1;
2535                         redraw = 1;
2536                 }
2537
2538                 else if ((c == 8 || isdigit(c)) && (select != 6 && select != 7)) {
2539                         unsigned int sy = box.y+2+1 + select;
2540                         unsigned int sx = box.x+2+11;
2541
2542                         switch (select) {
2543                                 case 0: sprintf(temp_str,"%u",cyl); break;
2544                                 case 1: sprintf(temp_str,"%u",head); break;
2545                                 case 2: sprintf(temp_str,"%u",sect); break;
2546                                 case 3: sprintf(temp_str,"%u",ssz != 0 ? (128 << ssz) : sszm); break;
2547                                 case 4: sprintf(temp_str,"%u",phead); break;
2548                                 case 5: sprintf(temp_str,"%u",scount); break;
2549                                 case 8: sprintf(temp_str,"%u",gaprw); break;
2550                                 case 9: sprintf(temp_str,"%u",gapfmt); break;
2551                         }
2552
2553                         if (c == 8) {
2554                                 i = strlen(temp_str) - 1;
2555                                 if (i < 0) i = 0;
2556                                 temp_str[i] = 0;
2557                         }
2558                         else {
2559                                 i = strlen(temp_str);
2560                                 if (i == 1 && temp_str[0] == '0') i--;
2561                                 if ((i+2) < sizeof(temp_str)) {
2562                                         temp_str[i++] = (char)c;
2563                                         temp_str[i] = 0;
2564                                 }
2565                         }
2566
2567                         redraw = 1;
2568                         while (1) {
2569                                 if (redraw) {
2570                                         redraw = 0;
2571                                         vga_moveto(sx,sy);
2572                                         vga_write_color(0x70);
2573                                         vga_write(temp_str);
2574                                         while (vga_pos_x < (box.x+box.w-4) && vga_pos_x != 0) vga_writec(' ');
2575                                 }
2576
2577                                 c = getch();
2578                                 if (c == 0) c = getch() << 8;
2579
2580                                 if (c == 8) {
2581                                         if (i > 0) {
2582                                                 temp_str[--i] = 0;
2583                                                 redraw = 1;
2584                                         }
2585                                 }
2586                                 else if (isdigit(c)) {
2587                                         if ((i+2) < sizeof(temp_str)) {
2588                                                 temp_str[i++] = (char)c;
2589                                                 temp_str[i] = 0;
2590                                                 redraw = 1;
2591                                         }
2592                                 }
2593                                 else {
2594                                         break;
2595                                 }
2596                         }
2597
2598                         switch (select) {
2599                                 case 0: tmp=strtoull(temp_str,NULL,0);  cyl=(tmp > 255ULL ? 255ULL : tmp); break;
2600                                 case 1: tmp=strtoull(temp_str,NULL,0); head=(tmp > 255ULL ? 255ULL : tmp); break;
2601                                 case 2: tmp=strtoull(temp_str,NULL,0); sect=(tmp > 255ULL ? 255ULL : tmp); break;
2602                                 case 3:
2603                                         tmp=strtoull(temp_str,NULL,0);
2604                                         if (tmp > 16384ULL) tmp = 16384ULL;
2605                                         if (tmp >= 256UL) {
2606                                                 ssz=1; /* 256 */
2607                                                 while ((128<<ssz) < (unsigned int)tmp) ssz++;
2608                                         }
2609                                         else {
2610                                                 ssz=0;
2611                                                 sszm=(unsigned int)tmp;
2612                                         }
2613                                         break;
2614                                 case 4: tmp=strtoull(temp_str,NULL,0); phead=(tmp >  1ULL ?   1ULL : tmp); break;
2615                                 case 5: tmp=strtoull(temp_str,NULL,0); scount=(tmp > 256ULL ? 256ULL : tmp);
2616                                         if (scount == 0) scount = 1;
2617                                         break;
2618                                 case 8: tmp=strtoull(temp_str,NULL,0); gaprw=(tmp > 255ULL ? 255ULL : tmp); break;
2619                                 case 9: tmp=strtoull(temp_str,NULL,0); gapfmt=(tmp > 255ULL ? 255ULL : tmp); break;
2620                         }
2621
2622                         rekey = 1;
2623                         recalc = 1;
2624                 }
2625
2626                 if (rekey) {
2627                         rekey = 0;
2628                         goto nextkey;
2629                 }
2630         }
2631         vga_msg_box_destroy(&box);
2632
2633         if (ok) {
2634                 mfm_mode = en_mfm;
2635                 allow_multitrack = en_mt;
2636                 current_sectsize_smaller = sszm;
2637                 current_phys_fmt_gap = gapfmt;
2638                 current_phys_rw_gap = gaprw;
2639                 current_sectcount = scount;
2640                 current_phys_head = phead;
2641                 current_sectsize_p2 = ssz;
2642                 current_log_track = cyl;
2643                 current_log_sect = sect;
2644                 current_log_head = head;
2645         }
2646 }
2647
2648 void do_floppy_controller(struct floppy_controller *fdc) {
2649         char backredraw=1;
2650         VGA_ALPHA_PTR vga;
2651         unsigned int x,y;
2652         char redraw=1;
2653         int select=-1;
2654         int c;
2655
2656         /* and allocate DMA too */
2657         if (fdc->dma >= 0 && floppy_dma == NULL) {
2658 #if TARGET_MSDOS == 32
2659                 uint32_t choice = 65536;
2660 #else
2661                 uint32_t choice = 32768;
2662 #endif
2663
2664                 do {
2665                         floppy_dma = dma_8237_alloc_buffer(choice);
2666                         if (floppy_dma == NULL) choice -= 4096UL;
2667                 } while (floppy_dma == NULL && choice > 4096UL);
2668
2669                 if (floppy_dma == NULL) return;
2670         }
2671
2672         /* if the floppy struct says to use interrupts, then do it */
2673         do_floppy_controller_enable_irq(fdc,fdc->use_irq);
2674         floppy_controller_enable_dma(fdc,fdc->use_dma);
2675
2676         while (1) {
2677                 if (backredraw) {
2678                         vga = vga_alpha_ram;
2679                         backredraw = 0;
2680                         redraw = 1;
2681
2682                         for (y=0;y < vga_height;y++) {
2683                                 for (x=0;x < vga_width;x++) {
2684                                         *vga++ = 0x1E00 + 177;
2685                                 }
2686                         }
2687
2688                         vga_moveto(0,0);
2689
2690                         vga_write_color(0x1F);
2691                         vga_write("        Floppy controller ");
2692                         sprintf(tmp,"@%X",fdc->base_io);
2693                         vga_write(tmp);
2694                         if (fdc->irq >= 0) {
2695                                 sprintf(tmp," IRQ %d",fdc->irq);
2696                                 vga_write(tmp);
2697                         }
2698                         if (fdc->dma >= 0) {
2699                                 sprintf(tmp," DMA %d",fdc->dma);
2700                                 vga_write(tmp);
2701                         }
2702                         if (floppy_dma != NULL) {
2703                                 sprintf(tmp," phys=%08lxh len=%04lxh",(unsigned long)floppy_dma->phys,(unsigned long)floppy_dma->length);
2704                                 vga_write(tmp);
2705                         }
2706                         while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
2707                 }
2708
2709                 if (redraw) {
2710                         int cx = vga_width / 2;
2711
2712                         redraw = 0;
2713
2714                         floppy_controller_read_status(fdc);
2715                         floppy_controller_read_DIR(fdc);
2716                         floppy_controller_read_ps2_status(fdc);
2717
2718                         y = 2;
2719                         vga_moveto(8,y++);
2720                         vga_write_color(0x0F);
2721                         sprintf(tmp,"DOR %02xh DIR %02xh Stat %02xh CCR %02xh cyl=%-3u ver=%02xh",
2722                                 fdc->digital_out,fdc->digital_in,
2723                                 fdc->main_status,fdc->control_cfg,
2724                                 fdc->cylinder,   fdc->version);
2725                         vga_write(tmp);
2726
2727                         vga_moveto(8,y++);
2728                         vga_write_color(0x0F);
2729                         sprintf(tmp,"ST0..3: %02x %02x %02x %02x PS/2 %02x %02x",
2730                                 fdc->st[0],fdc->st[1],fdc->st[2],fdc->st[3],
2731                                 fdc->ps2_status[0],fdc->ps2_status[1]);
2732                         vga_write(tmp);
2733
2734                         y = 5;
2735                         vga_moveto(8,y++);
2736                         vga_write_color((select == -1) ? 0x70 : 0x0F);
2737                         vga_write("Main menu");
2738                         while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
2739                         y++;
2740
2741                         vga_moveto(8,y++);
2742                         vga_write_color((select == 0) ? 0x70 : 0x0F);
2743                         vga_write("DMA: ");
2744                         vga_write(fdc->use_dma ? "Enabled" : "Disabled");
2745                         while (vga_pos_x < cx && vga_pos_x != 0) vga_writec(' ');
2746
2747                         vga_write_color((select == 1) ? 0x70 : 0x0F);
2748                         vga_write("IRQ: ");
2749                         vga_write(fdc->use_irq ? "Enabled" : "Disabled");
2750                         while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
2751
2752                         vga_moveto(8,y++);
2753                         vga_write_color((select == 2) ? 0x70 : 0x0F);
2754                         vga_write("Drive A motor: ");
2755                         vga_write((fdc->digital_out&0x10) ? "On" : "Off");
2756                         while (vga_pos_x < cx && vga_pos_x != 0) vga_writec(' ');
2757
2758                         vga_write_color((select == 3) ? 0x70 : 0x0F);
2759                         vga_write("Drive B motor: ");
2760                         vga_write((fdc->digital_out&0x20) ? "On" : "Off");
2761                         while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
2762
2763                         vga_moveto(8,y++);
2764                         vga_write_color((select == 4) ? 0x70 : 0x0F);
2765                         vga_write("Drive C motor: ");
2766                         vga_write((fdc->digital_out&0x40) ? "On" : "Off");
2767                         while (vga_pos_x < cx && vga_pos_x != 0) vga_writec(' ');
2768
2769                         vga_write_color((select == 5) ? 0x70 : 0x0F);
2770                         vga_write("Drive D motor: ");
2771                         vga_write((fdc->digital_out&0x80) ? "On" : "Off");
2772                         while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
2773
2774                         vga_moveto(8,y++);
2775                         vga_write_color((select == 6) ? 0x70 : 0x0F);
2776                         vga_write("Drive select: ");
2777                         sprintf(tmp,"%c(%u)",(fdc->digital_out&3)+'A',fdc->digital_out&3);
2778                         vga_write(tmp);
2779                         while (vga_pos_x < cx && vga_pos_x != 0) vga_writec(' ');
2780
2781                         vga_write_color((select == 7) ? 0x70 : 0x0F);
2782                         vga_write("Data rate: ");
2783                         switch (fdc->control_cfg&3) {
2784                                 case 0: vga_write("500kbit/sec"); break;
2785                                 case 1: vga_write("300kbit/sec"); break;
2786                                 case 2: vga_write("250kbit/sec"); break;
2787                                 case 3: vga_write("1mbit/sec"); break;
2788                         };
2789                         while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
2790
2791                         vga_moveto(8,y++);
2792                         vga_write_color((select == 8) ? 0x70 : 0x0F);
2793                         vga_write("Reset signal: ");
2794                         vga_write((fdc->digital_out&0x04) ? "Off" : "On");
2795                         while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
2796
2797                         vga_moveto(8,y++);
2798                         vga_write_color((select == 9) ? 0x70 : 0x0F);
2799                         vga_write("Pos log C/H/S/sz/cnt: ");
2800                         sprintf(tmp,"%u/%u/%u/%u/%u  phyH=%u  MT=%u %s",
2801                                 current_log_track,
2802                                 current_log_head,
2803                                 current_log_sect,
2804                                 current_sectsize_p2 > 0 ? (128 << current_sectsize_p2) : current_sectsize_smaller,
2805                                 current_sectcount,
2806                                 current_phys_head,
2807                                 allow_multitrack,
2808                                 mfm_mode?"MFM":"FM");
2809
2810                         vga_write(tmp);
2811                         while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
2812                         y++;
2813
2814                         vga_moveto(8,y++);
2815                         vga_write_color((select == 10) ? 0x70 : 0x0F);
2816                         vga_write("Check drive status (x4h)");
2817                         while (vga_pos_x < cx && vga_pos_x != 0) vga_writec(' ');
2818
2819                         vga_write_color((select == 11) ? 0x70 : 0x0F);
2820                         vga_write("Calibrate (x7h)");
2821                         while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
2822
2823                         vga_moveto(8,y++);
2824                         vga_write_color((select == 12) ? 0x70 : 0x0F);
2825                         vga_write("Seek (xFh)");
2826                         while (vga_pos_x < cx && vga_pos_x != 0) vga_writec(' ');
2827
2828                         vga_write_color((select == 13) ? 0x70 : 0x0F);
2829                         vga_write("Seek relative (1xFh)");
2830                         while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
2831
2832                         vga_moveto(8,y++);
2833                         vga_write_color((select == 14) ? 0x70 : 0x0F);
2834                         vga_write("Read sector ID (xAh)");
2835                         while (vga_pos_x < cx && vga_pos_x != 0) vga_writec(' ');
2836
2837                         vga_write_color((select == 15) ? 0x70 : 0x0F);
2838                         vga_write("Read testing >>");
2839                         while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
2840
2841                         vga_moveto(8,y++);
2842                         vga_write_color((select == 16) ? 0x70 : 0x0F);
2843                         vga_write("Write testing >>");
2844                         while (vga_pos_x < cx && vga_pos_x != 0) vga_writec(' ');
2845
2846                         vga_write_color((select == 17) ? 0x70 : 0x0F);
2847                         vga_write("Dump Registers (xEh)");
2848                         while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
2849
2850                         vga_moveto(8,y++);
2851                         vga_write_color((select == 18) ? 0x70 : 0x0F);
2852                         vga_write("Get Version (1x0h)");
2853                         while (vga_pos_x < cx && vga_pos_x != 0) vga_writec(' ');
2854
2855                         vga_write_color((select == 19) ? 0x70 : 0x0F);
2856                         vga_write("Format Track (xDh)");
2857                         while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
2858
2859                         vga_moveto(8,y++);
2860                         vga_write_color((select == 20) ? 0x70 : 0x0F);
2861                         vga_write("Step through tracks");
2862                         while (vga_pos_x < cx && vga_pos_x != 0) vga_writec(' ');
2863                 }
2864
2865                 c = getch();
2866                 if (c == 0) c = getch() << 8;
2867
2868                 if (c == 27) {
2869                         break;
2870                 }
2871                 else if (c == 13) {
2872                         if (select == -1) {
2873                                 break;
2874                         }
2875                         else if (select == 0) { /* DMA enable */
2876                                 fdc->non_dma_mode = !fdc->non_dma_mode;
2877                                 if (do_floppy_controller_specify(fdc)) /* if specify fails, don't change DMA flag */
2878                                         floppy_controller_enable_dma(fdc,!fdc->non_dma_mode); /* enable DMA = !(non-dma-mode) */
2879                                 else
2880                                         fdc->non_dma_mode = !fdc->non_dma_mode;
2881
2882                                 redraw = 1;
2883                         }
2884                         else if (select == 1) { /* IRQ enable */
2885                                 do_floppy_controller_enable_irq(fdc,!fdc->use_irq);
2886                                 redraw = 1;
2887                         }
2888                         else if (select == 2) { /* Drive A motor */
2889                                 floppy_controller_set_motor_state(fdc,0/*A*/,!(fdc->digital_out&0x10));
2890                                 redraw = 1;
2891                         }
2892                         else if (select == 3) { /* Drive B motor */
2893                                 floppy_controller_set_motor_state(fdc,1/*B*/,!(fdc->digital_out&0x20));
2894                                 redraw = 1;
2895                         }
2896                         else if (select == 4) { /* Drive C motor */
2897                                 floppy_controller_set_motor_state(fdc,2/*C*/,!(fdc->digital_out&0x40));
2898                                 redraw = 1;
2899                         }
2900                         else if (select == 5) { /* Drive D motor */
2901                                 floppy_controller_set_motor_state(fdc,3/*D*/,!(fdc->digital_out&0x80));
2902                                 redraw = 1;
2903                         }
2904                         else if (select == 6) { /* Drive select */
2905                                 floppy_controller_drive_select(fdc,((fdc->digital_out&3)+1)&3);
2906                                 redraw = 1;
2907                         }
2908                         else if (select == 7) { /* Transfer rate */
2909                                 floppy_controller_set_data_transfer_rate(fdc,((fdc->control_cfg&3)+1)&3);
2910                                 redraw = 1;
2911                         }
2912                         else if (select == 8) { /* reset */
2913                                 floppy_controller_set_reset(fdc,!!(fdc->digital_out&0x04)); /* bit is INVERTED 1=normal 0=reset */
2914                                 redraw = 1;
2915                         }
2916                         else if (select == 9) { /* Position */
2917                                 prompt_position();
2918                                 redraw = 1;
2919                         }
2920                         else if (select == 10) { /* check drive status */
2921                                 do_check_drive_status(fdc);
2922                                 redraw = 1;
2923                         }
2924                         else if (select == 11) { /* calibrate drive */
2925                                 do_calibrate_drive(fdc);
2926                                 redraw = 1;
2927                         }
2928                         else if (select == 12) { /* seek */
2929                                 unsigned long track = prompt_track_number();
2930                                 if (track != (~0UL) && track < 256) {
2931                                         do_seek_drive(fdc,(uint8_t)track);
2932                                         redraw = 1;
2933                                 }
2934                         }
2935                         else if (select == 13) { /* seek relative */
2936                                 signed long track = prompt_signed_track_number();
2937                                 if (track >= -255L && track <= 255L) {
2938                                         do_seek_drive_rel(fdc,(int)track);
2939                                         redraw = 1;
2940                                 }
2941                         }
2942                         else if (select == 14) { /* read sector ID */
2943                                 do_read_sector_id_demo(fdc);
2944                                 backredraw = 1;
2945                         }
2946                         else if (select == 15) { /* read testing */
2947                                 do_floppy_controller_read_tests(fdc);
2948                                 backredraw = 1;
2949                         }
2950                         else if (select == 16) { /* write testing */
2951                                 do_floppy_controller_write_tests(fdc);
2952                                 backredraw = 1;
2953                         }
2954                         else if (select == 17) { /* dump registers */
2955                                 do_floppy_dumpreg(fdc);
2956                         }
2957                         else if (select == 18) { /* get version */
2958                                 do_floppy_get_version(fdc);
2959                                 redraw = 1;
2960                         }
2961                         else if (select == 19) { /* format track */
2962                                 do_floppy_format_track(fdc);
2963                                 backredraw = 1;
2964                         }
2965                         else if (select == 20) { /* step through tracks */
2966                                 do_step_tracks(fdc);
2967                                 backredraw = 1;
2968                         }
2969                 }
2970                 else if (c == 0x4800) {
2971                         if (--select < -1)
2972                                 select = 20;
2973
2974                         redraw = 1;
2975                 }
2976                 else if (c == 0x5000) {
2977                         if (++select > 20)
2978                                 select = -1;
2979
2980                         redraw = 1;
2981                 }
2982         }
2983
2984         if (floppy_dma != NULL) {
2985                 dma_8237_free_buffer(floppy_dma);
2986                 floppy_dma = NULL;
2987         }
2988
2989         do_floppy_controller_enable_irq(fdc,0);
2990         floppy_controller_enable_irqdma_gate_otr(fdc,1); /* because BIOSes probably won't */
2991         p8259_unmask(fdc->irq);
2992 }
2993
2994 void do_main_menu() {
2995         char redraw=1;
2996         char backredraw=1;
2997         VGA_ALPHA_PTR vga;
2998         struct floppy_controller *floppy;
2999         unsigned int x,y,i;
3000         int select=-1;
3001         int c;
3002
3003         while (1) {
3004                 if (backredraw) {
3005                         vga = vga_alpha_ram;
3006                         backredraw = 0;
3007                         redraw = 1;
3008
3009                         for (y=0;y < vga_height;y++) {
3010                                 for (x=0;x < vga_width;x++) {
3011                                         *vga++ = 0x1E00 + 177;
3012                                 }
3013                         }
3014
3015                         vga_moveto(0,0);
3016
3017                         vga_write_color(0x1F);
3018                         vga_write("        Floppy controller test program");
3019                         while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
3020                 }
3021
3022                 if (redraw) {
3023                         redraw = 0;
3024
3025                         y = 5;
3026                         vga_moveto(8,y++);
3027                         vga_write_color((select == -1) ? 0x70 : 0x0F);
3028                         vga_write("Exit program");
3029                         y++;
3030
3031                         for (i=0;i < MAX_FLOPPY_CONTROLLER;i++) {
3032                                 floppy = floppy_get_controller(i);
3033                                 if (floppy != NULL) {
3034                                         vga_moveto(8,y++);
3035                                         vga_write_color((select == (int)i) ? 0x70 : 0x0F);
3036
3037                                         sprintf(tmp,"Controller @ %04X",floppy->base_io);
3038                                         vga_write(tmp);
3039
3040                                         if (floppy->irq >= 0) {
3041                                                 sprintf(tmp," IRQ %2d",floppy->irq);
3042                                                 vga_write(tmp);
3043                                         }
3044
3045                                         if (floppy->dma >= 0) {
3046                                                 sprintf(tmp," DMA %2d",floppy->dma);
3047                                                 vga_write(tmp);
3048                                         }
3049                                 }
3050                         }
3051                 }
3052
3053                 c = getch();
3054                 if (c == 0) c = getch() << 8;
3055
3056                 if (c == 27) {
3057                         break;
3058                 }
3059                 else if (c == 13) {
3060                         if (select == -1) {
3061                                 break;
3062                         }
3063                         else if (select >= 0 && select < MAX_FLOPPY_CONTROLLER) {
3064                                 floppy = floppy_get_controller(select);
3065                                 if (floppy != NULL) do_floppy_controller(floppy);
3066                                 backredraw = redraw = 1;
3067                         }
3068                 }
3069                 else if (c == 0x4800) {
3070                         if (select <= -1)
3071                                 select = MAX_FLOPPY_CONTROLLER - 1;
3072                         else
3073                                 select--;
3074
3075                         while (select >= 0 && floppy_get_controller(select) == NULL)
3076                                 select--;
3077
3078                         redraw = 1;
3079                 }
3080                 else if (c == 0x5000) {
3081                         select++;
3082                         while (select >= 0 && select < MAX_FLOPPY_CONTROLLER && floppy_get_controller(select) == NULL)
3083                                 select++;
3084                         if (select >= MAX_FLOPPY_CONTROLLER)
3085                                 select = -1;
3086
3087                         redraw = 1;
3088                 }
3089         }
3090 }
3091
3092 int main(int argc,char **argv) {
3093         struct floppy_controller *reffdc;
3094         struct floppy_controller *newfdc;
3095         int i;
3096
3097         /* we take a GUI-based approach (kind of) */
3098         if (!probe_vga()) {
3099                 printf("Cannot init VGA\n");
3100                 return 1;
3101         }
3102         if (!probe_8237())
3103                 printf("WARNING: Cannot init 8237 DMA\n");
3104         /* the floppy code has some timing requirements and we'll use the 8254 to do it */
3105         /* newer motherboards don't even have a floppy controller and it's probable they'll stop implementing the 8254 at some point too */
3106         if (!probe_8254()) {
3107                 printf("8254 chip not detected\n");
3108                 return 1;
3109         }
3110         if (!probe_8259()) {
3111                 printf("8259 chip not detected\n");
3112                 return 1;
3113         }
3114         if (!init_floppy_controller_lib()) {
3115                 printf("Failed to init floppy controller\n");
3116                 return 1;
3117         }
3118
3119         printf("Probing standard FDC ports...\n");
3120         for (i=0;(reffdc = (struct floppy_controller*)floppy_get_standard_isa_port(i)) != NULL;i++) {
3121                 printf("   %3X IRQ %d DMA %d: ",reffdc->base_io,reffdc->irq,reffdc->dma); fflush(stdout);
3122
3123                 if ((newfdc = floppy_controller_probe(reffdc)) != NULL) {
3124                         printf("FOUND. PS/2=%u AT=%u dma=%u DOR/RW=%u DOR=%02xh DIR=%02xh mst=%02xh\n",
3125                                 newfdc->ps2_mode,
3126                                 newfdc->at_mode,
3127                                 newfdc->use_dma,
3128                                 newfdc->digital_out_rw,
3129                                 newfdc->digital_out,
3130                                 newfdc->digital_in,
3131                                 newfdc->main_status);
3132                 }
3133                 else {
3134                         printf("\x0D                             \x0D"); fflush(stdout);
3135                 }
3136         }
3137
3138         printf("Hit ENTER to continue, ESC to cancel\n");
3139         i = wait_for_enter_or_escape();
3140         if (i == 27) {
3141                 free_floppy_controller_lib();
3142                 return 0;
3143         }
3144
3145         do_main_menu();
3146         free_floppy_controller_lib();
3147         return 0;
3148 }
3149