3 #include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
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>
21 #define MAX_FLOPPY_CONTROLLER 4
23 struct floppy_controller {
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 */
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 */
45 /* [5:5] Data error */
46 /* [4:4] Time out (data overrun) */
49 /* [1:1] Not writeable */
50 /* [0:0] No address mark */
51 /* Status Register ST2 */
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 */
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 */
91 uint8_t control_cfg; /* last value written to 0x3F7 */
92 /* [1:0] Data transfer rate */
94 /* 10 = 250 kbit/sec */
95 /* 01 = 300 kbit/sec */
96 /* 00 = 500 kbit/sec */
97 uint8_t cylinder; /* last known cylinder position */
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 */
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;
117 /* standard I/O ports for floppy controllers */
118 struct floppy_controller floppy_standard_isa[2] = {
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];
129 struct dma_8237_allocation* floppy_dma = NULL; /* DMA buffer */
131 struct floppy_controller floppy_controllers[MAX_FLOPPY_CONTROLLER];
132 int8_t floppy_controllers_init = -1;
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];
140 int wait_for_enter_or_escape() {
145 if (c == 0) c = getch() << 8;
146 } while (!(c == 13 || c == 27));
151 struct floppy_controller *alloc_floppy_controller() {
154 while (i < MAX_FLOPPY_CONTROLLER) {
155 if (floppy_controllers[i].base_io == 0)
156 return &floppy_controllers[i];
162 void floppy_controller_read_ps2_status(struct floppy_controller *i) {
164 i->ps2_status[0] = inp(i->base_io+0);
165 i->ps2_status[1] = inp(i->base_io+1);
168 i->ps2_status[0] = i->ps2_status[1] = 0xFF;
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;
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 */
181 i->digital_in = 0xFF;
183 return i->digital_in;
186 static inline void floppy_controller_write_DOR(struct floppy_controller *i,unsigned char c) {
188 outp(i->base_io+2,c); /* 0x3F2 Digital Output Register */
191 static inline void floppy_controller_write_CCR(struct floppy_controller *i,unsigned char c) {
193 outp(i->base_io+7,c); /* 0x3F7 Control Configuration Register */
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] */
201 void floppy_controller_drive_select(struct floppy_controller *i,unsigned char drv) {
204 i->digital_out &= ~0x03;
205 i->digital_out |= drv;
206 outp(i->base_io+2,i->digital_out); /* 0x3F2 Digital Output Register */
209 void floppy_controller_set_motor_state(struct floppy_controller *i,unsigned char drv,unsigned char set) {
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 */
217 void floppy_controller_enable_dma(struct floppy_controller *i,unsigned char set) {
218 if (i->dma < 0) set = 0;
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 */
229 void floppy_controller_enable_irq(struct floppy_controller *i,unsigned char set) {
230 if (i->irq < 0) set = 0;
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 */
241 void floppy_controller_enable_irqdma_gate_otr(struct floppy_controller *i,unsigned char set) {
246 c |= (set?0x08:0x00);
247 outp(i->base_io+2,c); /* 0x3F2 Digital Output Register */
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 */
256 struct floppy_controller *floppy_controller_probe(struct floppy_controller *i) {
257 struct floppy_controller *ret = NULL;
260 if (i == NULL) return NULL;
261 if (i->base_io == 0) return NULL;
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;
267 ret = alloc_floppy_controller();
268 if (ret == NULL) return NULL;
269 memset(ret,0,sizeof(*ret));
271 ret->base_io = i->base_io;
272 if (i->irq >= 2 && i->irq <= 15)
277 if (i->dma >= 0 && i->dma <= 7)
282 ret->use_dma = (ret->dma >= 0);
283 ret->use_irq = (ret->irq >= 0);
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 */
290 /* assume controller has ND (Non-DMA) and EIS (implied seek) turned off.
291 * most BIOSes do that. */
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;
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;
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);
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;
314 floppy_controller_read_DIR(ret);
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;
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);
332 floppy_controllers_init = 1;
335 return floppy_controllers_init;
338 void free_floppy_controller_lib() {
341 /*------------------------------------------------------------------------*/
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) */
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;
363 void do_floppy_controller_unhook_irq(struct floppy_controller *fdc);
365 static void interrupt my_floppy_irq() {
368 i = vga_width*(vga_height-1);
371 if (my_floppy_irq_floppy != NULL) {
372 my_floppy_irq_floppy->irq_fired++;
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);
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 */
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 | ' ';
400 floppy_irq_counter++;
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)
407 /* let the IRQ know what floppy controller */
408 my_floppy_irq_floppy = fdc;
410 /* enable on floppy controller */
411 p8259_mask(fdc->irq);
412 floppy_controller_enable_irq(fdc,1);
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;
420 p8259_unmask(fdc->irq);
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)
427 /* disable on floppy controller, then mask at PIC */
428 p8259_mask(fdc->irq);
429 floppy_controller_enable_irq(fdc,0);
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;
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);
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 */
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 */
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 */
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 */
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 */
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 */
468 static inline uint8_t floppy_controller_read_data_byte(struct floppy_controller *fdc) {
469 return inp(fdc->base_io+5);
472 static inline void floppy_controller_write_data_byte(struct floppy_controller *fdc,uint8_t b) {
473 outp(fdc->base_io+5,b);
476 static inline int floppy_controller_wait_data_ready(struct floppy_controller *fdc,unsigned int timeout) {
478 floppy_controller_read_status(fdc);
479 if (floppy_controller_data_io_ready(fdc)) return 1;
480 } while (--timeout != 0);
485 static inline int floppy_controller_wait_data_read_non_dma_ready(struct floppy_controller *fdc,unsigned int timeout) {
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);
495 static inline int floppy_controller_wait_data_write_non_dma_ready(struct floppy_controller *fdc,unsigned int timeout) {
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);
505 static inline void floppy_controller_reset_irq_counter(struct floppy_controller *fdc) {
509 int floppy_controller_wait_busy_in_instruction(struct floppy_controller *fdc,unsigned int timeout) {
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);
519 int floppy_controller_wait_data_ready_ms(struct floppy_controller *fdc,unsigned int timeout) {
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);
529 int floppy_controller_wait_irq(struct floppy_controller *fdc,unsigned int timeout,unsigned int counter) {
531 if (fdc->irq_fired >= counter) break;
532 t8254_wait(t8254_us2ticks(1000));
533 } while (--timeout != 0);
538 int floppy_controller_write_data(struct floppy_controller *fdc,const unsigned char *data,int len) {
539 unsigned int oflags = get_cpu_flags();
542 _cli(); /* clear interrupts so we can focus on talking to the FDC */
544 if (!floppy_controller_wait_data_ready(fdc,1000)) {
545 if (ret == 0) ret = -1;
548 if (!floppy_controller_can_write_data(fdc)) {
549 if (ret == 0) ret = -2;
553 floppy_controller_write_data_byte(fdc,*data++);
557 if (oflags&0x200/*IF interrupt enable was on*/) _sti();
561 #if TARGET_MSDOS == 32
562 int floppy_controller_write_data_ndma(struct floppy_controller *fdc,const unsigned char *data,int len) {
564 int floppy_controller_write_data_ndma(struct floppy_controller *fdc,const unsigned char far *data,int len) {
566 unsigned int oflags = get_cpu_flags();
571 if (!floppy_controller_wait_data_ready(fdc,1000)) {
572 if (ret == 0) ret = -1;
575 if (!floppy_controller_wait_data_write_non_dma_ready(fdc,1000)) {
576 if (ret == 0) ret = -2;
580 floppy_controller_write_data_byte(fdc,*data++);
584 if (oflags&0x200/*IF interrupt enable was on*/) _sti();
588 int floppy_controller_read_data(struct floppy_controller *fdc,unsigned char *data,int len) {
589 unsigned int oflags = get_cpu_flags();
594 if (!floppy_controller_wait_data_ready(fdc,1000)) {
595 if (ret == 0) ret = -1;
598 if (!floppy_controller_can_read_data(fdc)) {
599 if (ret == 0) ret = -2;
603 *data++ = floppy_controller_read_data_byte(fdc);
607 if (oflags&0x200/*IF interrupt enable was on*/) _sti();
611 #if TARGET_MSDOS == 32
612 int floppy_controller_read_data_ndma(struct floppy_controller *fdc,unsigned char *data,int len) {
614 int floppy_controller_read_data_ndma(struct floppy_controller *fdc,unsigned char far *data,int len) {
616 unsigned int oflags = get_cpu_flags();
621 if (!floppy_controller_wait_data_ready(fdc,1000)) {
622 if (ret == 0) ret = -1;
625 if (!floppy_controller_wait_data_read_non_dma_ready(fdc,1000)) {
626 if (ret == 0) ret = -2;
630 *data++ = floppy_controller_read_data_byte(fdc);
634 if (oflags&0x200/*IF interrupt enable was on*/) _sti();
638 void do_floppy_controller_reset(struct floppy_controller *fdc) {
639 struct vga_msg_box vgabox;
641 vga_msg_box_create(&vgabox,"FDC reset in progress",0,0);
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);
649 vga_msg_box_destroy(&vgabox);
652 void do_check_interrupt_status(struct floppy_controller *fdc) {
653 struct vga_msg_box vgabox;
654 char cmd[10],resp[10];
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);
661 /* Check Interrupt Status (x8h)
663 * Byte | 7 6 5 4 3 2 1 0
664 * -----+---------------------------------
665 * 0 | 0 0 0 0 1 0 0 0
670 cmd[0] = 0x08; /* Check interrupt status */
671 wd = floppy_controller_write_data(fdc,cmd,wdo);
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);
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);
684 /* NTS: It's not specified whether this returns 2 bytes if success and 1 if no IRQ pending.. or...? */
687 rd = floppy_controller_read_data(fdc,resp,rdo);
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);
697 /* Check Interrupt Status (x8h) response
699 * Byte | 7 6 5 4 3 2 1 0
700 * -----+---------------------------------
702 * 1 | Current Cylinder
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);
710 /* return value is ST0 and the current cylinder */
711 fdc->st[0] = resp[0];
712 fdc->cylinder = resp[1];
715 void do_spin_up_motor(struct floppy_controller *fdc,unsigned char drv) {
718 if (!(fdc->digital_out & (0x10 << drv))) {
719 struct vga_msg_box vgabox;
721 vga_msg_box_create(&vgabox,"Spinning up motor",0,0);
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 */
727 vga_msg_box_destroy(&vgabox);
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);
737 void do_seek_drive_rel(struct floppy_controller *fdc,int track) {
738 struct vga_msg_box vgabox;
742 do_spin_up_motor(fdc,fdc->digital_out&3);
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);
748 floppy_controller_reset_irq_counter(fdc);
750 /* Seek Relative (1xFh)
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
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 */
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) */;
767 wd = floppy_controller_write_data(fdc,cmd,wdo);
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);
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);
781 /* Seek Relative (1xFh) response
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);
791 /* use Check Interrupt Status */
792 do_check_interrupt_status(fdc);
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);
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];
807 start = prompt_track_number();
808 if (start == (~0UL)) return;
810 end = prompt_track_number();
811 if (start == (~0UL)) return;
812 if (start > end) return;
814 do_spin_up_motor(fdc,fdc->digital_out&3);
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);
823 for (track=start;track <= end;track++) {
826 if (c == 0) c = getch() << 8;
830 sprintf(tmp,"Seeking track %lu",track);
831 vga_msg_box_create(&vgabox,tmp,0,0);
834 do_seek_drive(fdc,(uint8_t)track);
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);
840 for (del=0;del < 1000;del++)
841 t8254_wait(t8254_us2ticks(1000));
843 /* un-draw the box */
844 vga_msg_box_destroy(&vgabox);
848 void do_seek_drive(struct floppy_controller *fdc,uint8_t track) {
849 struct vga_msg_box vgabox;
853 do_spin_up_motor(fdc,fdc->digital_out&3);
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);
859 floppy_controller_reset_irq_counter(fdc);
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
869 * HD = Head select (on PC platform, doesn't matter)
870 * DR1,DR0 = Drive select
871 * Cylinder = Track to move to */
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) */;
877 wd = floppy_controller_write_data(fdc,cmd,wdo);
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);
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);
891 /* Seek (xFh) response
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);
901 /* use Check Interrupt Status */
902 do_check_interrupt_status(fdc);
905 void do_check_drive_status(struct floppy_controller *fdc) {
906 struct vga_msg_box vgabox;
907 char cmd[10],resp[10];
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);
914 /* Check Drive Status (x4h)
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
921 * HD = Head select (on PC platform, doesn't matter)
922 * DR1,DR0 = Drive select */
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);
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);
937 /* wait for data ready. does not fire an IRQ */
938 floppy_controller_wait_data_ready_ms(fdc,1000);
940 /* Check Drive Status (x4h) response
942 * Byte | 7 6 5 4 3 2 1 0
943 * -----+---------------------------------
948 rd = floppy_controller_read_data(fdc,resp,rdo);
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);
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);
963 /* return value is ST3 */
964 fdc->st[3] = resp[0];
967 void do_calibrate_drive(struct floppy_controller *fdc) {
968 struct vga_msg_box vgabox;
972 do_spin_up_motor(fdc,fdc->digital_out&3);
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);
978 floppy_controller_reset_irq_counter(fdc);
980 /* Calibrate Drive (x7h)
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
987 * DR1,DR0 = Drive select */
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);
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);
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);
1006 /* Calibrate Drive (x7h) response
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);
1016 /* use Check Interrupt Status */
1017 do_check_interrupt_status(fdc);
1020 int do_floppy_get_version(struct floppy_controller *fdc) {
1022 char cmd[10],resp[10];
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);
1030 * Byte | 7 6 5 4 3 2 1 0
1031 * -----+---------------------------------
1032 * 0 | 0 0 0 1 0 0 0 0
1037 wd = floppy_controller_write_data(fdc,cmd,wdo);
1039 do_floppy_controller_reset(fdc);
1043 /* wait for data ready. does not fire an IRQ */
1044 floppy_controller_wait_data_ready_ms(fdc,1000);
1047 rd = floppy_controller_read_data(fdc,resp,rdo);
1049 do_floppy_controller_reset(fdc);
1053 /* Version (1x0h) response
1055 * Byte | 7 6 5 4 3 2 1 0
1056 * -----+--------------------------------------
1057 * 0 | Version or error
1059 * Version/Error values:
1060 * 0x80: Not an enhanced controller (we got an invalid opcode)
1061 * 0x90: Enhanced controller
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);
1069 fdc->version = resp[0];
1074 int do_floppy_controller_specify(struct floppy_controller *fdc) {
1080 retry: drv = fdc->digital_out & 3;
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);
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
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);
1101 do_floppy_controller_reset(fdc);
1105 /* wait for data ready. does not fire an IRQ */
1106 floppy_controller_wait_data_ready_ms(fdc,1000);
1108 /* Specify (x3h) response
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);
1118 /* use Check Interrupt Status */
1119 do_check_interrupt_status(fdc);
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);
1134 int do_floppy_dumpreg(struct floppy_controller *fdc) {
1136 char cmd[10],resp[10];
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);
1142 /* Dump Registers (xEh)
1144 * Byte | 7 6 5 4 3 2 1 0
1145 * -----+---------------------------------
1146 * 0 | 0 0 0 0 1 1 1 0
1151 wd = floppy_controller_write_data(fdc,cmd,wdo);
1153 do_floppy_controller_reset(fdc);
1157 /* wait for data ready. does not fire an IRQ */
1158 floppy_controller_wait_data_ready_ms(fdc,1000);
1161 rd = floppy_controller_read_data(fdc,resp,rdo);
1163 do_floppy_controller_reset(fdc);
1167 /* Dump Registers (xEh) response
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-------------->
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.
1197 * 82077AA Drive Control Delays (ms) Table 5-10
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 * +------------------------------------+------------------------------------+
1210 * | 1M 500K 300K 250K |
1211 * ---+------------------------------------+
1212 * 0 | 128 256 426 512 |
1214 * ..........................................
1215 * 7Eh | 126 252 420 504 |
1216 * 7Fh | 127 254 423 508 |
1217 * +------------------------------------+
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);
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;
1233 struct vga_msg_box vgabox;
1237 for (i=0;i < rd;i++) w += sprintf(w,"%02x ",resp[i]);
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",
1254 w += sprintf(w,"GAP=%u WGATE=%u EIS=%u EFIFO=%u POLL=%u\n",
1260 w += sprintf(w,"FIFOTHR=%u PRETRK=%u",
1264 vga_msg_box_create(&vgabox,tmp,0,0);
1265 wait_for_enter_or_escape();
1266 vga_msg_box_destroy(&vgabox);
1272 int do_read_sector_id(unsigned char resp[7],struct floppy_controller *fdc,unsigned char head) {
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);
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
1288 * HD = Head select (on PC platform, doesn't matter)
1289 * DR1,DR0 = Drive select */
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);
1296 do_floppy_controller_reset(fdc);
1300 /* wait for data ready. does not fire an IRQ */
1301 floppy_controller_wait_data_ready_ms(fdc,1000);
1304 rd = floppy_controller_read_data(fdc,resp,rdo);
1306 do_floppy_controller_reset(fdc);
1310 /* Read ID (xAh) response
1312 * Byte | 7 6 5 4 3 2 1 0
1313 * -----+---------------------------------
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);
1328 /* accept ST0..ST2 from response and update */
1330 fdc->st[0] = resp[0];
1331 fdc->st[1] = resp[1];
1332 fdc->st[2] = resp[2];
1335 fdc->cylinder = resp[3];
1341 void do_read_sector_id_demo(struct floppy_controller *fdc) {
1342 unsigned char headsel = current_phys_head;
1347 vga_write_color(0x0E);
1350 vga_write("Read Sector ID demo. Space to switch heads.\n\n");
1355 if (c == 0) c = getch() << 8;
1363 if ((c=do_read_sector_id(resp,fdc,headsel)) == 7) {
1365 vga_write_color(0x0F);
1367 sprintf(tmp,"ST: %02xh %02xh %02xh %02xh\n",fdc->st[0],fdc->st[1],fdc->st[2],fdc->st[3]);
1370 sprintf(tmp,"C/H/S/sz: %-3u/%-3u/%-3u/%-3u \n",resp[3],resp[4],resp[5],resp[6]);
1375 vga_write_color(0x0F);
1377 sprintf(tmp,"ST: --h --h --h --h (ret=%d)\n",c);
1380 sprintf(tmp,"C/H/S/sz: ---/---/---/--- \n");
1386 signed long prompt_signed_track_number() {
1387 signed long track = 0;
1388 struct vga_msg_box box;
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;
1397 if (c == 0) c = getch() << 8;
1406 if (isdigit(temp_str[0]))
1407 track = strtol(temp_str,NULL,0);
1413 else if (isdigit(c) || c == '-') {
1415 sco[i] = c | 0x1E00;
1421 sco[i] = ' ' | 0x1E00;
1424 vga_msg_box_destroy(&box);
1429 unsigned long prompt_track_number() {
1430 unsigned long track = 0;
1431 struct vga_msg_box box;
1436 vga_msg_box_create(&box,"Enter track number:",2,0);
1437 sco = vga_alpha_ram + ((box.y+2) * vga_width) + box.x + 2;
1440 if (c == 0) c = getch() << 8;
1443 track = (int)(~0UL);
1449 if (isdigit(temp_str[0]))
1450 track = strtol(temp_str,NULL,0);
1456 else if (isdigit(c)) {
1458 sco[i] = c | 0x1E00;
1464 sco[i] = ' ' | 0x1E00;
1467 vga_msg_box_destroy(&box);
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;
1479 nsect = current_sectcount;
1482 data_length = nsect * unit_length;
1485 vga_write_color(0x0E);
1489 struct vga_msg_box vgabox;
1493 w += sprintf(w,"I will format the track as having %u sectors/track,\n",
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",
1504 w += sprintf(w,"and formatted on physical head %u\n",
1506 w += sprintf(w,"\n");
1507 w += sprintf(w,"Hit ENTER to continue if this is what you want,\nor ESC to stop now.");
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;
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);
1518 do_spin_up_motor(fdc,fdc->digital_out&3);
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;
1525 if (data_length > floppy_dma->length) return;
1527 /* sector pattern. 4 bytes for each sector to write */
1528 for (rd=0;rd < nsect;rd++) {
1529 wd = rd * unit_length;
1532 * --+---------------------------
1535 * 2 | Sector address
1536 * 3 | Sector size code
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;
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);
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 */
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));
1556 d8237_write_count(fdc->dma,data_length);
1557 d8237_write_base(fdc->dma,floppy_dma->phys);
1559 outp(d8237_ioport(fdc->dma,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(fdc->dma)); /* unmask */
1561 inp(d8237_ioport(fdc->dma,D8237_REG_R_STATUS)); /* read status port to clear TC bits */
1564 /* Format Track (xDh)
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 ---------->
1576 * HD = Head select (on PC platform, doesn't matter)
1577 * DR1,DR0 = Drive select */
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;
1584 cmd[4] = current_phys_fmt_gap;
1585 cmd[5] = 0xAA; /* fill byte */
1586 wd = floppy_controller_write_data(fdc,cmd,wdo);
1588 vga_write("Write data port failed\n");
1589 do_floppy_controller_reset(fdc);
1593 vga_write("Format in progress\n");
1597 if (fdc->use_irq) floppy_controller_wait_irq(fdc,10000,1); /* 10 seconds */
1598 floppy_controller_wait_data_ready_ms(fdc,1000);
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);
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);
1617 returned_length += p;
1618 /* stop on incomplete transfer */
1619 if (p != unit_length) break;
1624 rd = floppy_controller_read_data(fdc,resp,rdo);
1626 vga_write("Write data port failed\n");
1627 do_floppy_controller_reset(fdc);
1631 /* Format Track (xDh) response
1633 * Byte | 7 6 5 4 3 2 1 0
1634 * -----+---------------------------------
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);
1649 /* accept ST0..ST2 from response and update */
1651 fdc->st[0] = resp[0];
1652 fdc->st[1] = resp[1];
1653 fdc->st[2] = resp[2];
1656 fdc->cylinder = resp[3];
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));
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;
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);
1672 sprintf(tmp,"%lu bytes written\n",(unsigned long)returned_length);
1676 wait_for_enter_or_escape();
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;
1686 cyl = current_log_track;
1687 head = current_log_head;
1688 sect = current_log_sect;
1689 nsect = current_sectcount;
1690 ssz = current_sectsize_p2;
1692 if (current_sectsize_p2 > 0)
1693 unit_length = (128 << ssz);
1695 unit_length = current_sectsize_smaller;
1697 data_length = nsect * unit_length;
1700 vga_write_color(0x0E);
1703 sprintf(tmp,"Writing C/H/S/sz/num %u/%u/%u/%u/%u\n",cyl,head,sect,unit_length,nsect);
1706 do_spin_up_motor(fdc,fdc->digital_out&3);
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;
1713 if (data_length > floppy_dma->length) return;
1715 for (x=0;(unsigned int)x < data_length;x++) floppy_dma->lin[x] = x;
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);
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 */
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));
1729 d8237_write_count(fdc->dma,data_length);
1730 d8237_write_base(fdc->dma,floppy_dma->phys);
1732 outp(d8237_ioport(fdc->dma,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(fdc->dma)); /* unmask */
1734 inp(d8237_ioport(fdc->dma,D8237_REG_R_STATUS)); /* read status port to clear TC bits */
1737 /* Write Sector (x5h)
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
1747 * 6 | Track length/last sector
1748 * 7 | Length of GAP3
1753 * HD = Head select (on PC platform, doesn't matter)
1754 * DR1,DR0 = Drive select */
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. */
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);
1774 vga_write("Write data port failed\n");
1775 do_floppy_controller_reset(fdc);
1779 vga_write("Write in progress\n");
1783 if (fdc->use_irq) floppy_controller_wait_irq(fdc,10000,1); /* 10 seconds */
1784 floppy_controller_wait_data_ready_ms(fdc,1000);
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);
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);
1803 returned_length += p;
1804 /* stop on incomplete transfer */
1805 if (p != unit_length) break;
1810 rd = floppy_controller_read_data(fdc,resp,rdo);
1812 vga_write("Write data port failed\n");
1813 do_floppy_controller_reset(fdc);
1817 /* Write Sector (x5h) response
1819 * Byte | 7 6 5 4 3 2 1 0
1820 * -----+---------------------------------
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);
1835 /* accept ST0..ST2 from response and update */
1837 fdc->st[0] = resp[0];
1838 fdc->st[1] = resp[1];
1839 fdc->st[2] = resp[2];
1842 fdc->cylinder = resp[3];
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));
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;
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);
1858 sprintf(tmp,"%lu bytes written\n",(unsigned long)returned_length);
1862 wait_for_enter_or_escape();
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;
1872 cyl = current_log_track;
1873 head = current_log_head;
1874 sect = current_log_sect;
1875 nsect = current_sectcount;
1876 ssz = current_sectsize_p2;
1878 if (current_sectsize_p2 > 0)
1879 unit_length = (128 << ssz);
1881 unit_length = current_sectsize_smaller;
1883 data_length = nsect * unit_length;
1886 vga_write_color(0x0E);
1889 sprintf(tmp,"Reading C/H/S/sz/num %u/%u/%u/%u/%u\n",cyl,head,sect,unit_length,nsect);
1892 do_spin_up_motor(fdc,fdc->digital_out&3);
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;
1899 if (data_length > floppy_dma->length) return;
1901 #if TARGET_MSDOS == 32
1902 memset(floppy_dma->lin,0,data_length);
1904 _fmemset(floppy_dma->lin,0,data_length);
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);
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 */
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));
1919 d8237_write_count(fdc->dma,data_length);
1920 d8237_write_base(fdc->dma,floppy_dma->phys);
1922 outp(d8237_ioport(fdc->dma,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(fdc->dma)); /* unmask */
1924 inp(d8237_ioport(fdc->dma,D8237_REG_R_STATUS)); /* read status port to clear TC bits */
1927 /* Read Sector (x6h)
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
1937 * 6 | Track length/last sector
1938 * 7 | Length of GAP3
1943 * SK = Skip deleted address mark
1944 * HD = Head select (on PC platform, doesn't matter)
1945 * DR1,DR0 = Drive select */
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. */
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);
1965 vga_write("Write data port failed\n");
1966 do_floppy_controller_reset(fdc);
1970 vga_write("Read in progress\n");
1974 if (fdc->use_irq) floppy_controller_wait_irq(fdc,10000,1); /* 10 seconds */
1975 floppy_controller_wait_data_ready_ms(fdc,1000);
1978 while (returned_length < data_length) {
1979 if ((returned_length+unit_length) > data_length) break;
1980 floppy_controller_wait_data_ready_ms(fdc,10000);
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);
1989 returned_length += p;
1990 /* stop on incomplete transfer */
1991 if (p != unit_length) break;
1996 rd = floppy_controller_read_data(fdc,resp,rdo);
1998 vga_write("Read data port failed\n");
1999 do_floppy_controller_reset(fdc);
2003 /* Read Sector (x6h) response
2005 * Byte | 7 6 5 4 3 2 1 0
2006 * -----+---------------------------------
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);
2021 /* accept ST0..ST2 from response and update */
2023 fdc->st[0] = resp[0];
2024 fdc->st[1] = resp[1];
2025 fdc->st[2] = resp[2];
2028 fdc->cylinder = resp[3];
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));
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;
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);
2044 sprintf(tmp,"%lu bytes received\n",(unsigned long)returned_length);
2048 vga_write_color(0x0F);
2049 for (p=0;p == 0 || p < ((returned_length+255)/256);p++) {
2050 for (y=0;y < 16;y++) {
2052 for (x=0;x < 16;x++) {
2053 sprintf(tmp,"%02x ",floppy_dma->lin[((y+(p*16))*16)+x]);
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] = '.';
2066 if (wait_for_enter_or_escape() == 27)
2071 void do_floppy_controller_read_tests(struct floppy_controller *fdc) {
2081 vga = vga_alpha_ram;
2085 for (y=0;y < vga_height;y++) {
2086 for (x=0;x < vga_width;x++) {
2087 *vga++ = 0x1E00 + 177;
2093 vga_write_color(0x1F);
2094 vga_write(" Read tests ");
2095 sprintf(tmp,"@%X",fdc->base_io);
2097 if (fdc->irq >= 0) {
2098 sprintf(tmp," IRQ %d",fdc->irq);
2101 if (fdc->dma >= 0) {
2102 sprintf(tmp," DMA %d",fdc->dma);
2105 if (floppy_dma != NULL) {
2106 sprintf(tmp," phys=%08lxh len=%04lxh",(unsigned long)floppy_dma->phys,(unsigned long)floppy_dma->length);
2109 while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
2115 floppy_controller_read_status(fdc);
2116 floppy_controller_read_DIR(fdc);
2117 floppy_controller_read_ps2_status(fdc);
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,
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]);
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(' ');
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(' ');
2149 if (c == 0) c = getch() << 8;
2158 else if (select == 0) { /* Read Sector */
2159 do_floppy_read_test(fdc);
2163 else if (c == 0x4800) {
2169 else if (c == 0x5000) {
2178 void do_floppy_controller_write_tests(struct floppy_controller *fdc) {
2188 vga = vga_alpha_ram;
2192 for (y=0;y < vga_height;y++) {
2193 for (x=0;x < vga_width;x++) {
2194 *vga++ = 0x1E00 + 177;
2200 vga_write_color(0x1F);
2201 vga_write(" Write tests ");
2202 sprintf(tmp,"@%X",fdc->base_io);
2204 if (fdc->irq >= 0) {
2205 sprintf(tmp," IRQ %d",fdc->irq);
2208 if (fdc->dma >= 0) {
2209 sprintf(tmp," DMA %d",fdc->dma);
2212 if (floppy_dma != NULL) {
2213 sprintf(tmp," phys=%08lxh len=%04lxh",(unsigned long)floppy_dma->phys,(unsigned long)floppy_dma->length);
2216 while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
2222 floppy_controller_read_status(fdc);
2223 floppy_controller_read_DIR(fdc);
2224 floppy_controller_read_ps2_status(fdc);
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,
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]);
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(' ');
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(' ');
2256 if (c == 0) c = getch() << 8;
2265 else if (select == 0) { /* Write Sector */
2266 do_floppy_write_test(fdc);
2270 else if (c == 0x4800) {
2276 else if (c == 0x5000) {
2285 void prompt_position() {
2288 int cyl,head,phead,sect,ssz,sszm,scount,gaprw,gapfmt;
2289 struct vga_msg_box box;
2290 unsigned char redraw=1;
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;
2308 vga_msg_box_create(&box,
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++] = ' ';
2325 vga_write(temp_str);
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++] = ' ';
2334 vga_write(temp_str);
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++] = ' ';
2343 vga_write(temp_str);
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);
2350 i=sprintf(temp_str,"%u",128 << ssz);
2352 i=sprintf(temp_str,"%u",sszm);
2353 while (i < (box.w-4-11)) temp_str[i++] = ' ';
2355 vga_write(temp_str);
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++] = ' ';
2364 vga_write(temp_str);
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++] = ' ';
2373 vga_write(temp_str);
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++] = ' ';
2382 vga_write(temp_str);
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++] = ' ';
2391 vga_write(temp_str);
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++] = ' ';
2400 vga_write(temp_str);
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++] = ' ';
2409 vga_write(temp_str);
2413 if (c == 0) c = getch() << 8;
2415 nextkey: if (c == 27) {
2423 else if (c == 0x4800) {
2424 if (--select < 0) select = 9;
2427 else if (c == 0x5000 || c == 9/*tab*/) {
2428 if (++select > 9) select = 0;
2432 else if (c == 0x4B00) { /* left */
2435 if (cyl == 0) cyl = 255;
2439 if (head == 0) head = 255;
2443 if (sect == 0) sect = 255;
2461 if (phead == 0) phead = 1;
2465 if (scount <= 1) scount = 256;
2475 if (gaprw == 0) gaprw = 255;
2479 if (gapfmt == 0) gapfmt = 255;
2487 else if (c == 0x4D00) { /* right */
2490 if ((++cyl) >= 256) cyl = 0;
2493 if ((++head) >= 256) head = 0;
2496 if ((++sect) >= 256) sect = 0;
2500 if ((++sszm) > 255) {
2513 if ((++phead) >= 2) phead = 0;
2516 if ((++scount) >= 257) scount = 1;
2525 if (gaprw == 255) gaprw = 0;
2529 if (gapfmt == 255) gapfmt = 0;
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;
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;
2554 i = strlen(temp_str) - 1;
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;
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(' ');
2578 if (c == 0) c = getch() << 8;
2586 else if (isdigit(c)) {
2587 if ((i+2) < sizeof(temp_str)) {
2588 temp_str[i++] = (char)c;
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;
2603 tmp=strtoull(temp_str,NULL,0);
2604 if (tmp > 16384ULL) tmp = 16384ULL;
2607 while ((128<<ssz) < (unsigned int)tmp) ssz++;
2611 sszm=(unsigned int)tmp;
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;
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;
2631 vga_msg_box_destroy(&box);
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;
2648 void do_floppy_controller(struct floppy_controller *fdc) {
2656 /* and allocate DMA too */
2657 if (fdc->dma >= 0 && floppy_dma == NULL) {
2658 #if TARGET_MSDOS == 32
2659 uint32_t choice = 65536;
2661 uint32_t choice = 32768;
2665 floppy_dma = dma_8237_alloc_buffer(choice);
2666 if (floppy_dma == NULL) choice -= 4096UL;
2667 } while (floppy_dma == NULL && choice > 4096UL);
2669 if (floppy_dma == NULL) return;
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);
2678 vga = vga_alpha_ram;
2682 for (y=0;y < vga_height;y++) {
2683 for (x=0;x < vga_width;x++) {
2684 *vga++ = 0x1E00 + 177;
2690 vga_write_color(0x1F);
2691 vga_write(" Floppy controller ");
2692 sprintf(tmp,"@%X",fdc->base_io);
2694 if (fdc->irq >= 0) {
2695 sprintf(tmp," IRQ %d",fdc->irq);
2698 if (fdc->dma >= 0) {
2699 sprintf(tmp," DMA %d",fdc->dma);
2702 if (floppy_dma != NULL) {
2703 sprintf(tmp," phys=%08lxh len=%04lxh",(unsigned long)floppy_dma->phys,(unsigned long)floppy_dma->length);
2706 while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
2710 int cx = vga_width / 2;
2714 floppy_controller_read_status(fdc);
2715 floppy_controller_read_DIR(fdc);
2716 floppy_controller_read_ps2_status(fdc);
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);
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]);
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(' ');
2742 vga_write_color((select == 0) ? 0x70 : 0x0F);
2744 vga_write(fdc->use_dma ? "Enabled" : "Disabled");
2745 while (vga_pos_x < cx && vga_pos_x != 0) vga_writec(' ');
2747 vga_write_color((select == 1) ? 0x70 : 0x0F);
2749 vga_write(fdc->use_irq ? "Enabled" : "Disabled");
2750 while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
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(' ');
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(' ');
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(' ');
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(' ');
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);
2779 while (vga_pos_x < cx && vga_pos_x != 0) vga_writec(' ');
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;
2789 while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
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(' ');
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",
2804 current_sectsize_p2 > 0 ? (128 << current_sectsize_p2) : current_sectsize_smaller,
2808 mfm_mode?"MFM":"FM");
2811 while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
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(' ');
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(' ');
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(' ');
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(' ');
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(' ');
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(' ');
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(' ');
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(' ');
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(' ');
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(' ');
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(' ');
2866 if (c == 0) c = getch() << 8;
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) */
2880 fdc->non_dma_mode = !fdc->non_dma_mode;
2884 else if (select == 1) { /* IRQ enable */
2885 do_floppy_controller_enable_irq(fdc,!fdc->use_irq);
2888 else if (select == 2) { /* Drive A motor */
2889 floppy_controller_set_motor_state(fdc,0/*A*/,!(fdc->digital_out&0x10));
2892 else if (select == 3) { /* Drive B motor */
2893 floppy_controller_set_motor_state(fdc,1/*B*/,!(fdc->digital_out&0x20));
2896 else if (select == 4) { /* Drive C motor */
2897 floppy_controller_set_motor_state(fdc,2/*C*/,!(fdc->digital_out&0x40));
2900 else if (select == 5) { /* Drive D motor */
2901 floppy_controller_set_motor_state(fdc,3/*D*/,!(fdc->digital_out&0x80));
2904 else if (select == 6) { /* Drive select */
2905 floppy_controller_drive_select(fdc,((fdc->digital_out&3)+1)&3);
2908 else if (select == 7) { /* Transfer rate */
2909 floppy_controller_set_data_transfer_rate(fdc,((fdc->control_cfg&3)+1)&3);
2912 else if (select == 8) { /* reset */
2913 floppy_controller_set_reset(fdc,!!(fdc->digital_out&0x04)); /* bit is INVERTED 1=normal 0=reset */
2916 else if (select == 9) { /* Position */
2920 else if (select == 10) { /* check drive status */
2921 do_check_drive_status(fdc);
2924 else if (select == 11) { /* calibrate drive */
2925 do_calibrate_drive(fdc);
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);
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);
2942 else if (select == 14) { /* read sector ID */
2943 do_read_sector_id_demo(fdc);
2946 else if (select == 15) { /* read testing */
2947 do_floppy_controller_read_tests(fdc);
2950 else if (select == 16) { /* write testing */
2951 do_floppy_controller_write_tests(fdc);
2954 else if (select == 17) { /* dump registers */
2955 do_floppy_dumpreg(fdc);
2957 else if (select == 18) { /* get version */
2958 do_floppy_get_version(fdc);
2961 else if (select == 19) { /* format track */
2962 do_floppy_format_track(fdc);
2965 else if (select == 20) { /* step through tracks */
2966 do_step_tracks(fdc);
2970 else if (c == 0x4800) {
2976 else if (c == 0x5000) {
2984 if (floppy_dma != NULL) {
2985 dma_8237_free_buffer(floppy_dma);
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);
2994 void do_main_menu() {
2998 struct floppy_controller *floppy;
3005 vga = vga_alpha_ram;
3009 for (y=0;y < vga_height;y++) {
3010 for (x=0;x < vga_width;x++) {
3011 *vga++ = 0x1E00 + 177;
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(' ');
3027 vga_write_color((select == -1) ? 0x70 : 0x0F);
3028 vga_write("Exit program");
3031 for (i=0;i < MAX_FLOPPY_CONTROLLER;i++) {
3032 floppy = floppy_get_controller(i);
3033 if (floppy != NULL) {
3035 vga_write_color((select == (int)i) ? 0x70 : 0x0F);
3037 sprintf(tmp,"Controller @ %04X",floppy->base_io);
3040 if (floppy->irq >= 0) {
3041 sprintf(tmp," IRQ %2d",floppy->irq);
3045 if (floppy->dma >= 0) {
3046 sprintf(tmp," DMA %2d",floppy->dma);
3054 if (c == 0) c = getch() << 8;
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;
3069 else if (c == 0x4800) {
3071 select = MAX_FLOPPY_CONTROLLER - 1;
3075 while (select >= 0 && floppy_get_controller(select) == NULL)
3080 else if (c == 0x5000) {
3082 while (select >= 0 && select < MAX_FLOPPY_CONTROLLER && floppy_get_controller(select) == NULL)
3084 if (select >= MAX_FLOPPY_CONTROLLER)
3092 int main(int argc,char **argv) {
3093 struct floppy_controller *reffdc;
3094 struct floppy_controller *newfdc;
3097 /* we take a GUI-based approach (kind of) */
3099 printf("Cannot init VGA\n");
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");
3110 if (!probe_8259()) {
3111 printf("8259 chip not detected\n");
3114 if (!init_floppy_controller_lib()) {
3115 printf("Failed to init floppy controller\n");
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);
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",
3128 newfdc->digital_out_rw,
3129 newfdc->digital_out,
3131 newfdc->main_status);
3134 printf("\x0D \x0D"); fflush(stdout);
3138 printf("Hit ENTER to continue, ESC to cancel\n");
3139 i = wait_for_enter_or_escape();
3141 free_floppy_controller_lib();
3146 free_floppy_controller_lib();