Page 1 of 1

fdc programming

Posted: Mon Aug 30, 2004 9:05 am
by mblock
hi,

can anybody help me with the following code? i don't know why it isn't working ???

after i send the read-command i should get an irq but this doesn't happen... i don't know why

Code: Select all

volatile BYTE fd_flag = 0;

void init_fd(void)
{   
   k_printfc(VGA_YELLOW, "================================================================================");

   // register interrupt-handler for IRQ6
   irq_register_handler(0x06, fd_handler);
   
   // reset controller
   fd_reset();
   fd_motoron();   
   fd_wait_for_irq();
   
   // determine controller version
   fd_send(0x10);
   if(fd_read() == 0x80) {
      k_printf("fd: NEC765 controller found\n");
   }
   else {
      k_printf("fd: enhanced controller found\n");
   }

   // set data rate
   outportb(FD_BASE + FD_CONF, 0x00);   

   // calibrate drive   
   fd_send(0x07);
   fd_send(0x00);
   fd_wait_for_irq();
   
   ////////////////////
   // TODO TODO TODO //
   ////////////////////   
   dma_block_t dma;
   dma.page    = 1;
   dma.offset    = 0;
   dma.count    = 511;
   dma_start(2, &dma, DMA_MODE_WRITE | DMA_MODE_NOAUTOINIT | DMA_MODE_SINGLE);
   
   fd_send(0x66);
   fd_send(0);
   fd_send(0); // cyl
   fd_send(0); // head
   fd_send(1); // sec number
   fd_send(2); // sec size
   fd_send(0);
   fd_send(0);
   fd_send(0xFF);
   fd_wait_for_irq();
   
   k_printf("ST0: 0x%x\n", fd_read());
   k_printf("ST1: 0x%x\n", fd_read());
   k_printf("ST2: 0x%x\n", fd_read());
   k_printf("Cyl: 0x%x\n", fd_read());
   k_printf("Head: 0x%x\n", fd_read());
   k_printf("Sec num: 0x%x\n", fd_read());
   k_printf("Sec size: 0x%x\n", fd_read());
   
   fd_dump_msr();
   ////////////////////
   // TODO TODO TODO //
   ////////////////////
   
   // turn drive motor off
   fd_motoroff();
   
   // successful
   k_printf("init_fd: done!\n");
   for(;;);
}

void fd_handler(void)
{
   // set interrupt flag
   fd_flag = 1;
   // check interrupt status
   fd_send(0x08);   
   k_printfc(VGA_YELLOW, "fd_handler\n");   
   k_printf("ST0: 0x%x\n", fd_read());
   k_printf("Cyl: 0x%x\n", fd_read());   
}

void fd_reset(void)
{   outportb(FD_BASE + FD_DOR, 0x00);   }

void fd_motoron(void)
{   outportb(FD_BASE + FD_DOR, FD_DOR_RESET | FD_DOR_DMA | FD_DOR_MOTA);   }

void fd_motoroff(void)
{   outportb(FD_BASE + FD_DOR, FD_DOR_RESET | FD_DOR_DMA);   }

void fd_wait_for_irq(void)
{
   fd_flag = 0;
   while(!fd_flag);
   fd_flag = 0;
}

void fd_send(BYTE byte) {
   volatile int msr;
   int tmo;   
   for(tmo=0; tmo<128; tmo++) {
      msr = inportb(FD_BASE + FD_MSR);
      if((msr&0xC0) == 0x80) { // data register ready + CPU to controller
         outportb(FD_BASE + FD_DATA, byte);
         return;
      }
      inportb(0x80); // delay
   }
   k_printfc(VGA_RED, "fd: timeout (send)!\n");
}

BYTE fd_read() {
   volatile int msr;
   int tmo;
    for(tmo=0; tmo<128; tmo++) {
      msr = inportb(FD_BASE + FD_MSR);
      if((msr & 0xD0) == 0xD0) { // data register ready + controller to CPU + busy
         return inportb(FD_BASE + FD_DATA);
      }
      inportb(0x80); // delay
   }
   k_printfc(VGA_RED, "fd: timeout (read)!\n");
   return -1;
}

int dma_start(int channel, dma_block_t *block, BYTE mode)
{
   if(channel>=8) return -1;

   // disable hardware interrupts
   disable();
   
   // mask channel
   outportb(dma_mask[channel], DMA_MASKBIT | channel);
   
   // clear channel
   outportb(dma_clear[channel], 0);
   
   // write mode
   outportb(dma_mode[channel], mode | channel);

   // write page
   outportb(dma_page[channel], block->page);      
   
   // write offset
   outportb(dma_addr[channel], (block->offset&0x00FF));
   outportb(dma_addr[channel], (block->offset&0xFF00)>>8);

   // write count
   outportb(dma_count[channel], (block->count&0x00FF));
   outportb(dma_count[channel], (block->count&0xFF00)>>8);
   
   // unmask
   outportb(dma_mask[channel], channel);

   // enable hardware interrupts
   enable();

   return 0;
}
i hope i forgot nothing :)

thx for any help

mfg marcl

Re:fdc programming

Posted: Mon Aug 30, 2004 9:02 pm
by Brendan
Hi,

Selected quotes From a floppy disk controller datasheet:
"Parameters set by the SPECIFY command are undefined after a system reset and will need to be reinitialized. CONFIGURE command parameters default to a known state after a system reset but will need to be reinitialized if the system requirements are different from the default settings."

"The non-DMA mode flag, step rate (SRT), head load (HLT), and head unload times (HUT) programmed by the SPECIFY command do not default to a known state after a reset. This behavior is consistent with the 8272A and has been preserved here for compatibility. Thus, it is necessary to always issue a SPECIFY command in the initialization routine."

"The CONFIGURE command should also be issued if the system requirements are different from the default settings. For example, the CONFIGURE command can be used to enable the FIFO, set the threshold, and enable Implied Seeks."

"CONFIGURE DEFAULT VALUES:
- EIS No Implied Seeks
- EFIFO FIFO Disabled
- POLL Polling Enabled
- FIFOTHR FIFO Threshold Set to 1 Byte
- PRETRK Pre-Compensation Set to Track 0"

"Since polling is enabled after a reset of the 82077AA, four SENSE INTERRUPT STATUS commands need to be issued afterwards to clear the status flags for each drive. The flowchart in Figure 8-3 illustrates how the software clears each of the four interrupt status flags internally queued by the 82077AA. It should be noted that although four SENSE INTERRUPT STATUS commands are issued, the INT pin is only active until the first SENSE
INTERRUPT STATUS command is executed."

"As a note, if the CONFIGURE command is issued within 250 ms of the trailing edge of reset (@ 1 Mbps), the polling mode of the 82077AA can be disabled before the polling initiated interrupt occurs. Since polling stops when the 82077AA enters the command phase, it is only time critical up to the first byte of the CONFIGURE command. If disabled in time, the system software no longer needs to issue the four SENSE INTERRUPT STATUS commands to clear the internal interrupt flags normally caused by polling."

Ok, so you're in polling mode (no IRQs), and your floppy driver probably won't get past the first "fd_wait_for_irq()", just after the "fd_reset()". Also without the specify command you wouldn't be able to do much anyway (all the timing would probably be wrong).

Also when you send the read command you have to tell it the gap length (0 shouldn't work) and the EOT (End Of Track). The EOT is used to set the last sector you want to read. Currently you're telling it to read from sector 1 but to stop at sector 0, in which case you would get an end of track/cylinder error (returned as bit 7 set in ST1) before it attempts to read any data. Because you haven't set the gap length properly you'd probably get a missing address mark error (returned as bit 0 set in ST1) if it actually did try to read a sector.

It might be a good idea to download and read one or more floppy datasheets in entirety - I'd recommend reading several datasheets for different chips as there are subtle differences. Here's some:
http://support.intel.com/design/archive ... 046803.pdf
http://www.osdever.net/documents/82077A ... ?the_id=41
http://www.smsc.com/main/datasheets/37c78.pdf

Cheers,

Brendan