Page 1 of 1

FDC driver doesn't work (full source embedded)

Posted: Wed Oct 07, 2009 5:27 pm
by nicesj
hello, OS developers..

I started to write FDC driver for x86 using bochs and intel documents, some tutorials (from this forum)
but I couldn't make it works. I spent few weeks to solve this problem...

would you let me know what I've missed?
I can't understand why it doesn't work. I followed the instruction of manual....

in the fdc_read function, go into the loop until the interrupt occurs, but the interrupt does not generated...


thank you.

Code: Select all

#if !defined(_ARCH_BOOT_X86_FDC)
#define _ARCH_BOOT_X86_FDC

enum { 
        FD_SECTOR_PER_TRACK     = 18,
};

#define LBA_TO_CHS(lba, h, t, s) do { \
        (h) = ((lba) % (FD_SECTOR_PER_TRACK << 1)) / FD_SECTOR_PER_TRACK;\
        (t) = (lba) / (FD_SECTOR_PER_TRACK << 1);                       \
        (s) = (lba) % FD_SECTOR_PER_TRACK + 1;                          \
} while(0)



// 0x3F0 ~ 0x3F7
enum base_address
{
        FDC_PRIMARY     = 0x3F0,
        FDC_SECONDARY   = 0x370,
};

enum bytes_per_sector
{
        SECTOR_128      = 0,
        SECTOR_256      = 1,
        SECTOR_512      = 2,
        SECTOR_1024     = 3,

        SECTOR_16K      = 7,
};


// IDX:0, R - SRA
#define REG_SRA(base)   (base)
#define SRA(reg)        ((SRA_t*)(reg))

typedef struct status_register_a SRA_t;
struct status_register_a
{
#if defined(MODE_PS2)
        unsigned long dir:1;
        unsigned long b_wp:1;
        unsigned long b_idx:1;
        unsigned long hdsel:1;
        unsigned long b_trk0:1;
        unsigned long step:1;
        unsigned long b_drv2:1;
        unsigned long interrupted:1;
#define SRA_RESET_DONE(reg) (!SRA(reg)->interrupted && !SRA(reg)->step && !SRA(reg)->hdsel && !SRA(reg)->dir)
#define SRA_INTERRUPTED(reg)    SRA(reg)->interrupted)

#elif defined(MODE_MODEL30)
        unsigned long b_dir:1;
        unsigned long wp:1;
        unsigned long index:1;
        unsigned long b_hdsel:1;
        unsigned long trk0:1;
        unsigned long step_ff:1;
        unsigned long drq:1;            // DMA Request
        unsigned long interrupted:1;

#define SRA_RESET_DONE(reg)     (!SRA(reg)->step_ff)
#define SRA_INTERRUPTED(reg)    (((SRA_t*)(reg))->interrupted)

#elif defined(MODE_PCAT)
        unsigned char none;
#define SRA_RESET_DONE(reg)             1
#define SRA_INTERRUPTED(reg)            0
#endif
};

// IDX:1, R - SRB
#define REG_SRB(base)   ((base) + 0x01)
#define SRB(reg)        ((SRB_t*)(reg))
typedef struct status_register_b SRB_t;
struct status_register_b
{
#if defined(MODE_PS2)
        unsigned long motor:2;
        unsigned long we:1;
        unsigned long rddata_toggle:1;
        unsigned long wrdata_toggle:1;
        unsigned long drive_sel0:1;
        unsigned long reserved:2;       //! 11

#define SRB_RESET_DONE(reg) (!SRB(reg)->rddata_toggle && !SRB(reg)->wrdata_toggle)

#elif defined(MODE_MODEL30)
        unsigned long b_ds_high:2;
        unsigned long we_ff:1;
        unsigned long rddata_ff:1;
        unsigned long wrdata_ff:1;
        unsigned long b_ds_low:2;
        unsigned long b_drv2:1;

#define SRB_RESET_DONE(reg) (!SRB(reg)->we_ff && !SRB(reg)->rddata_ff && !SRB(reg)->wrdata_ff)
#elif defined(MODE_PCAT)
        unsigned char none;
#define SRB_RESET_DONE(reg)     1
#endif
};

// IDX:2, RW - DOR
#define REG_DOR(base)   ((base) + 0x02)
enum drive_activation_values
{
        DRIVE0  = 0x1C,
        DRIVE1  = 0x2D,
        DRIVE2  = 0x4E,
        DRIVE3  = 0x8F,
};

typedef struct digital_output_register DOR_t;
struct digital_output_register
{
        unsigned long drive:2;
        unsigned long b_reset:1;
        unsigned long b_dma_gate:1;
        unsigned long motor:4;
};

enum dma_state {
        DMA     = 0x01,
        NONDMA  = 0x00,
};

#define DOR_RESET(reg) do {             \
        DOR_t *dor = (DOR_t*)(reg);     \
        dor->b_reset = 0;               \
        dor->drive = 0;                 \
        dor->b_dma_gate = 1;            \
        dor->motor = 0;                 \
} while (0)

#define DOR_ENABLE(reg, drv, dma) do {  \
        DOR_t *dor = (DOR_t*)(reg);     \
        dor->b_reset = 1;               \
        dor->drive = (drv);             \
        dor->b_dma_gate = dma;          \
        dor->motor = 0x01 << (drv);     \
} while (0)

// IDX:3, RW - TDR
#define REG_TDR(base)   ((base) + 0x03)
typedef struct tape_drive_register TDR_t;
struct tape_drive_register
{
        unsigned long tape_sel:2;
        unsigned long none:6;
};

// IDX:4, W - DSR
#define REG_DSR(base)   ((base) + 0x04)
enum precompensation_delays
{
        DELAY_DISABLED  = 0x07,
        DELAY_41_67ns   = 0x01, // -> 1Mbps
        DELAY_83_34ns   = 0x02,
        DELAY_125ns     = 0x03, // -> 500Kbps, 300Kbps, 250Kbps
        DELAY_166_67ns  = 0x04,
        DELAY_208_33ns  = 0x05,
        DELAY_250ns     = 0x06,
        DELAY_DEFAULT   = 0x0,
};
enum data_rates
{
        DRATE_1Mbps     = 0x03, // -> 41.67ns
        DRATE_500Kbps   = 0x00, // -> 125ns
        DRATE_300Kbps   = 0x01, // -> 125ns
        DRATE_250Kbps   = 0x02, // -> 125ns
};
typedef struct datarate_select_register DSR_t;
struct datarate_select_register
{
        unsigned long dratesel:2;
        unsigned long precomp:3;
        unsigned long zeroed:1;
        unsigned long power_down:1;
        unsigned long sw_reset:1;
};

#define SELECT_DRATE(reg, rate) do {            \
        DSR_t *dsr = (DSR_t*)(reg);             \
        dsr->dratesel = rate;                   \
        switch (dsr->dratesel) {                \
        case DRATE_1Mbps:                       \
                dsr->precomp = DELAY_41_67ns;   \
                break;                          \
        case DRATE_500Kbps:                     \
                dsr->precomp = DELAY_125ns;     \
                break;                          \
        case DRATE_300Kbps:                     \
                dsr->precomp = DELAY_125ns;     \
                break;                          \
        case DRATE_250Kbps:                     \
                dsr->precomp = DELAY_125ns;     \
                break;                          \
        default:                                \
                break;                          \
        }                                       \
} while (0)

// Auto-toggle reset_pin
#define DSR_RESET(reg) do {                     \
        DSR_t *dsr = (DSR_t*)(reg);             \
        dsr->sw_reset = 1;                      \
        dsr->power_down = 1;                    \
} while (0)

// IDX:4, R - MSR
#define REG_MSR(base)   ((base) + 0x04)
enum drive_letter
{
        DRIVE_A         = 0x00,
        DRIVE_B         = 0x01,
        DRIVE_C         = 0x02,
        DRIVE_D         = 0x03,
};
enum dir_of_data
{
        UNDEFINED       = 0x00,
        READ_REQUIRED   = 0x01,
        WRITE_REQUIRED  = 0x02,
};
typedef struct main_status_register MSR_t;
struct main_status_register
{
        unsigned long drive_busy:4;
        unsigned long cmd_busy:1;
        unsigned long non_dma:1;// 1 == durring execution phase
        unsigned long DIO:1;    // 1 == read is required, otherwise(0) write is required
        unsigned long RQM:1;    // 1 == host can transfer data, otherwise 0
};

#define MSR(reg)        ((MSR_t*)(reg))
#define DIR_OF_DATA(reg) (MSR(reg)->RQM ? (MSR(reg)->DIO ? READ_REQUIRED : WRITE_REQUIRED) : UNDEFINED)
#define IN_RESULT_PHASE(reg)    (MSR(reg)->cmd_busy)
#define IN_SEEK_PORTION(reg)    (MSR(reg)->drive_busy)

#define REG_FIFO(base)  ((base) + 0x05)
// IDX:5, RW - FIFO
// NO DATA STRUCTURE

// IDX:6, RESERVED

// IDX:7, R - DIR
#define REG_DIR(base)   ((base) + 0x07)
typedef struct digital_input_register DIR_t;
struct digital_input_register
{
#if defined(MODE_PCAT)
        unsigned long none:7;
        unsigned long disk_change:1;
#define DISK_CHANGED(reg)       (((DIR_t*)(reg))->disk_change)
#elif defined(MODE_PS2)
        unsigned long b_high_dens:1;    // 500 Kbps, 1 Mbps --> set 1
        unsigned long drate_sel:2;
        unsigned long reserved:4;       // set 1
        unsigned long disk_change:1;
#define DISK_CHANGED(reg)       (((DIR_t*)(reg))->disk_change)
#elif defined(MODE_MODEL30)
        unsigned long drate_sel:2;
        unsigned long no_prec:1;
        unsigned long b_dma_gate:1;
        unsigned long reserved:3;       // set 0
        unsigned long b_disk_change:1;
#define DISK_CHANGED(reg)       (!((DIR_t*)(reg))->disk_change)
#else
        unsigned char none;
#endif
};

// IDX:7, W - CCR
#define REG_CCR(base)   ((base) + 0x07)
typedef struct configuration_control_register CCR_t;
struct configuration_control_register
{
#if defined(MODE_PCAT) || defined(MODE_PS2)
        unsigned long drate_sel:2;
        unsigned long none:6;
#elif defined(MODE_MODEL30)
        unsigned long drate_sel:2;
        unsigned long no_prec:1;
        unsigned long none:5;
#endif
};

#define SET_DRATE(reg, drate)   (((CCR_t*)(reg))->drate_sel = (drate))



enum fdc_dma_dir_t
{
        FDC_DMA_READ            = 1,
        FDC_DMA_WRITE           = 2,
};


enum command_set
{
        CMD_READ_DATA           = 0x06,
        CMD_READ_DELETED_DATA   = 0x0C,
        CMD_WRITE_DATA          = 0x05,
        CMD_WRITE_DELETED_DATA  = 0x09,
        CMD_READ_TRACK          = 0x02,
        CMD_VERIFY              = 0x16,
        CMD_VERSION             = 0x10,
        CMD_FORMAT_TRACK        = 0x0D,
        CMD_SCAN_EQUAL          = 0x11,
        CMD_SCAN_LOW_OR_EQUAL   = 0x19,
        CMD_SCAN_HIGH_OR_EQUAL  = 0x1D,
        CMD_RECALIBRATE         = 0x07,
        CMD_SENSE_INTERRUPT     = 0x08,
        CMD_SPECIFY             = 0x03,
        CMD_SEND_DRIVE_STATUS   = 0x04,
        CMD_SEEK                = 0x0F,
        CMD_CONFIGURE           = 0x13,
        CMD_RELATIVE_SEEK       = 0x8F,
        CMD_DUMPREG             = 0x0E,
        CMD_READ_ID             = 0x0A,
        CMD_PERPENDICULAR_MODE  = 0x12,
        CMD_LOCK                = 0x24,

        CMD_EXT_MULTITRACK      = 0x80,
        CMD_EXT_DENSITY         = 0x40,
        CMD_EXT_SKIP            = 0x20,
};



extern void fdc_select_ctrl(enum base_address bsr);
extern void fdc_select_drive(enum drive_letter drv);
extern enum base_address fdc_ctrl(void);
extern enum drive_letter fdc_drive(void);
extern void fdc_reset(void);
extern int fdc_read_deleted_sector(int c, int h, int r);
extern int fdc_read_sector(int c, int h, int r);
extern int fdc_sense_interrupt(unsigned char *st0, unsigned char *cyl);
extern int fdc_write_sector(int c, int h, int r);
extern int fdc_write_deleted_sector(int c, int h, int r);
extern int fdc_read_track(int c, int h, int r);
extern int fdc_verify(int c, int h, int r);
extern int fdc_version(unsigned char *ver);

extern int fdc_read(unsigned long block, void *buf, int size);
extern int fdc_write(unsigned long block, void *buf, int size);
extern int fdc_seek(unsigned long block);

#endif



//! End of a file

Code: Select all

#include <ncloader.h>
#include <port.h>
#include <fdc.h>
#include <libc.h>
#include <resource_str.h>
#include <dma.h>
#include <isr.h>
#include <list.h>
#include <lock.h>
#include <kthread.h>



static enum base_address g_ctrl = FDC_PRIMARY;
static enum drive_letter g_drv  = DRIVE_A;



//static void send_cmd_read_data(unsigned char cyl, int head, int sec);
inline static void
fdc_dma_init(enum fdc_dma_dir_t dir, unsigned long address, int count)
{
        unsigned long mode;

        switch (dir) {
        case FDC_DMA_READ:
                mode = DMA_MODE_SINGLE|DMA_CH2|DMA_MODE_TX_WRITE;
                break;
        case FDC_DMA_WRITE:
                mode = DMA_MODE_SINGLE|DMA_CH2|DMA_MODE_TX_READ;
                break;
        default:
                PANIC("Invalid dir");
                return;
        }

        DbgPrint("dma_init %p %d\n", address, count);
        dma_init(DMA_CH2, mode, address, count);
}



void fdc_select_ctrl(enum base_address bsr)
{
        g_ctrl = bsr;
}



void fdc_select_drive(enum drive_letter drv)
{
        g_drv = drv;
}
enum base_address fdc_ctrl(void)
{
        return g_ctrl;
}



enum drive_letter fdc_drive(void)
{
        return g_drv;
}



inline static int send_byte(unsigned char byte)
{
        unsigned char reg;

        reg = inb(REG_MSR(g_ctrl));
        if (DIR_OF_DATA(&reg) != WRITE_REQUIRED) {
                DbgPrint("Impossible to send a command\n");
                return -1;
        }

        outb(REG_FIFO(g_ctrl), byte);
        return 0;
}



inline static int read_byte(unsigned char *byte)
{
        unsigned char reg;
        reg = inb(REG_MSR(g_ctrl));
        if (DIR_OF_DATA(&reg) != READ_REQUIRED) {
                DbgPrint("Not read states\n");
                return -1;
        }

        *byte = inb(REG_FIFO(g_ctrl));
        return 0;
}



inline static int calibrate(void)
{
        unsigned char st0;
        unsigned char cyl;

        if (send_byte(CMD_RECALIBRATE) < 0) {
                int ret;
                unsigned char byte;
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(g_drv) < 0) {
                int ret;
                unsigned char byte;
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        wait_irq(WAIT_IRQ_FLOPPY);
        if (fdc_sense_interrupt(&st0, &cyl) < 0) {
                DbgPrint("Failed to sense the interrupt\n");
                return -1;
        }

        return cyl ? -1 : 0;
}



inline static int fdc_specify(void)
{
        int srt = 3;   // 3 ms
        int hut = 240; // 240 ms
        int hlt = 16;  // 16 ms

        if (send_byte(CMD_SPECIFY) < 0) {
                int ret;
                unsigned char byte;
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        // TODO: set srt/hut/hlt
        if (send_byte(((srt & 0x0f) << 4) | (hut & 0xf)) < 0) {
                int ret;
                unsigned char byte;
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte((hlt << 1) | DMA) < 0) {
                int ret;
                unsigned char byte;
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        return 0;
}


int fdc_read_deleted_sector(int c, int h, int r)
{
        unsigned char byte;
        int ret;

        if (send_byte(CMD_READ_DELETED_DATA | CMD_EXT_MULTITRACK | CMD_EXT_DENSITY | CMD_EXT_SKIP) < 0)
        {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte((h << 2) | g_drv) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(c) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(h) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(r) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(SECTOR_512) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(80) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(27) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(0xFF) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        wait_irq(WAIT_IRQ_FLOPPY);

        if (read_byte(&byte) < 0) {
                return -1;
        }; // ST0
        if (read_byte(&byte) < 0) {
                return -1;
        }; // ST1
        if (read_byte(&byte) < 0) {
                return -1;
        }; // ST2
        if (read_byte(&byte) < 0) {
                return -1;
        }; // C
        if (read_byte(&byte) < 0) {
                return -1;
        }; // H
        if (read_byte(&byte) < 0) {
                return -1;
        }; // R
        if (read_byte(&byte) < 0) {
                return -1;
        }; // N

        return 0;
}



int fdc_read_sector(int c, int h, int r)
{
        unsigned char byte;
        int ret;

        if (send_byte(CMD_READ_DATA | CMD_EXT_MULTITRACK | CMD_EXT_DENSITY | CMD_EXT_SKIP) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte((h << 2) | g_drv) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(c) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(h) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(r) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(SECTOR_512) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(80) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(27) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(0xFF) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        wait_irq(WAIT_IRQ_FLOPPY);

        if (read_byte(&byte) < 0) {
                return -1;
        }; // ST0
        if (read_byte(&byte) < 0) {
                return -1;
        }; // ST1
        if (read_byte(&byte) < 0) {
                return -1;
        }; // ST2
        if (read_byte(&byte) < 0) {
                return -1;
        }; // C
        if (read_byte(&byte) < 0) {
                return -1;
        }; // H
        if (read_byte(&byte) < 0) {
                return -1;
        }; // R
        if (read_byte(&byte) < 0) {
                return -1;
        }; // N

        return 0;
}



int fdc_sense_interrupt(unsigned char *st0, unsigned char *cyl)
{
        if (send_byte(CMD_SENSE_INTERRUPT) < 0) {
                int ret;
                unsigned char byte;
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (read_byte(st0) < 0) {
                return -1;
        }
        if (*st0 == 0x80) {
                DbgPrint("Invalid command\n");
                return -1;
        }

        if (read_byte(cyl) < 0) {
                return -1;
        }

        return 0;
}



int fdc_write_sector(int c, int h, int r)
{
        int ret;
        unsigned char byte;

        if (send_byte(CMD_WRITE_DATA | CMD_EXT_MULTITRACK | CMD_EXT_DENSITY) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte((h<<2) | g_drv) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(c) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(h) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(r) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(SECTOR_512) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }
        if (send_byte(80) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(27) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(0xFF) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        wait_irq(WAIT_IRQ_FLOPPY);

        if (read_byte(&byte) < 0) {
                return -1;
        }; // ST0
        if (read_byte(&byte) < 0) {
                return -1;
        }; // ST1
        if (read_byte(&byte) < 0) {
                return -1;
        }; // ST2
        if (read_byte(&byte) < 0) {
                return -1;
        }; // C
        if (read_byte(&byte) < 0) {
                return -1;
        }; // H
        if (read_byte(&byte) < 0) {
                return -1;
        }; // R
        if (read_byte(&byte) < 0) {
                return -1;
        }; // N

        return 0;
}


int fdc_write_deleted_sector(int c, int h, int r)
{
        int ret;
        unsigned char byte;

        if (send_byte(CMD_WRITE_DELETED_DATA | CMD_EXT_MULTITRACK | CMD_EXT_DENSITY) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte((h<<2) | g_drv) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(c) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(h) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(r) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(SECTOR_512) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(80) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(27) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(0xFF) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        wait_irq(WAIT_IRQ_FLOPPY);

        if (read_byte(&byte) < 0) {
                return -1;
        }; // ST0
        if (read_byte(&byte) < 0) {
                return -1;
        }; // ST1
        if (read_byte(&byte) < 0) {
                return -1;
        }; // ST2
        if (read_byte(&byte) < 0) {
                return -1;
        }; // C
        if (read_byte(&byte) < 0) {
                return -1;
        }; // H
        if (read_byte(&byte) < 0) {
                return -1;
        }; // R
        if (read_byte(&byte) < 0) {
                return -1;
        }; // N

        return 0;
}



int fdc_read_track(int c, int h, int r)
{
        int ret;
        unsigned char byte;

        if (send_byte(CMD_READ_TRACK | CMD_EXT_DENSITY) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }


        if (send_byte((h<<2) | g_drv) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(c) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(h) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(r) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(SECTOR_512) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(80) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(27) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(0xFF) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        wait_irq(WAIT_IRQ_FLOPPY);

        if (read_byte(&byte) < 0) {
                return -1;
        }; // ST0
        if (read_byte(&byte) < 0) {
                return -1;
        }; // ST1
        if (read_byte(&byte) < 0) {
                return -1;
        }; // ST2
        if (read_byte(&byte) < 0) {
                return -1;
        }; // C
        if (read_byte(&byte) < 0) {
                return -1;
        }; // H
        if (read_byte(&byte) < 0) {
                return -1;
        }; // R
        if (read_byte(&byte) < 0) {
                return -1;
        }; // N

        return 0;
}



int fdc_verify(int c, int h, int r)
{
        int ret;
        unsigned char byte;

        if (send_byte(CMD_VERIFY | CMD_EXT_DENSITY | CMD_EXT_MULTITRACK | CMD_EXT_SKIP) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte((h<<2) | g_drv) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(c) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(h) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(r) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(SECTOR_512) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(80) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(27) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(0xFF) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        wait_irq(WAIT_IRQ_FLOPPY);

        if (read_byte(&byte) < 0) {
                return -1;
        }; // ST0
        if (read_byte(&byte) < 0) {
                return -1;
        }; // ST1
        if (read_byte(&byte) < 0) {
                return -1;
        }; // ST2
        if (read_byte(&byte) < 0) {
                return -1;
        }; // C
        if (read_byte(&byte) < 0) {
                return -1;
        }; // H
        if (read_byte(&byte) < 0) {
                return -1;
        }; // R
        if (read_byte(&byte) < 0) {
                return -1;
        }; // N

        return 0;
}



int fdc_version(unsigned char *ver)
{
        int ret;
        unsigned char byte;

        if (send_byte(CMD_VERSION) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (read_byte(&byte) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        return 0;
}


void fdc_reset(void)
{
        unsigned char reg;
        unsigned char st0;
        unsigned char cyl;
        int i;

        DOR_RESET(&reg);
        outb(REG_DOR(g_ctrl), reg);

        DOR_ENABLE(&reg, g_drv, DMA);
        outb(REG_DOR(g_ctrl), reg);

        outb(REG_CCR(g_ctrl), DRATE_500Kbps);

        wait_irq(WAIT_IRQ_FLOPPY);

        // for DRIVE_A, DRIVE_B, DRIVE_C, DRIVE_D
        for (i = 0; i < 4; i ++) {
                if (fdc_sense_interrupt(&st0, &cyl) < 0) {
                        PANIC("Faield to sense the interrupt\n");
                        return;
                }
        }

        // NOTE:
        // IF PARAMTERS DIFFERENT FROM DEFALT
        //  - CONFIGURE COMMAND
        // ELSE ..

        if (fdc_specify() < 0) {
                PANIC("Failed to specify");
                return;
        }

        if (calibrate() < 0) {
                PANIC("Failed to do calibration\n");
                return;
        }

        /*
        unsigned char sra;
        unsigned char srb;
        do {
                sra = inb(REG_SRA(g_ctrl));
                srb = inb(REG_SRB(g_ctrl));

                DbgPrint("SRA = %d, SRB = %d\f", sra, srb);
        } while (!SRA_RESET_DONE(&sra) || !SRB_RESET_DONE(&srb));
        */
}


static inline int seek(int cyl, int head)
{
        int ret;
        unsigned char byte;

        if (send_byte(CMD_SEEK) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte((head << 2) | g_drv) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        if (send_byte(cyl) < 0) {
                ret = read_byte(&byte);
                if (ret < 0 || byte == 0x80) {
                        DbgPrint("Failed to read\n");
                }
                return -1;
        }

        wait_irq(WAIT_IRQ_FLOPPY);

        return 0;
}



int fdc_read(unsigned long block, void *buf, int size)
{
        int c;
        int h;
        int s;

        LBA_TO_CHS(block, c, h, s);

        seek(c, h);

        fdc_dma_init(FDC_DMA_READ, (unsigned long)buf, size);
        fdc_read_sector(c, h, s);
        return 0;
}



int fdc_write(unsigned long block, void *buf, int size)
{
        int c;
        int h;
        int s;

        LBA_TO_CHS(block, c, h, s);

        seek(c, h);

        fdc_dma_init(FDC_DMA_WRITE, (unsigned long)buf, size);
        fdc_write_sector(c, h, s);
        return 0;
}



int fdc_seek(unsigned long block)
{
        int c;
        int h;
        int s;

        LBA_TO_CHS(block, c, h, s);
        seek(c, h);
        return 0;
}
//! End of a file

Re: FDC driver doesn't work (full source embedded)

Posted: Wed Oct 07, 2009 5:42 pm
by nicesj
Here is a ISR code for handling the FDC interrupt

Code: Select all

//static struct list_head irq_event[MAX_IRQ_WAIT];
enum irq_idx_t {
        WAIT_IRQ_FLOPPY = 6,
        MAX_IRQ_WAIT    = 16,
};

volatile static int irq_event[MAX_IRQ_WAIT] = { 0, };

void wait_irq(int idx)
{
#if 0
        kthread_t *kthread;
        if (idx >= MAX_IRQ_WAIT) PANIC("Invalid IRQ");
        
        DbgPrint("ok\n");
        
        cli();
        kthread = kthread_get_current();
        ASSERT(kthread);
        list_add_tail(&kthread->wait, irq_event+idx);
        kthread->wait_irq = idx;        
        sti();
        asm volatile("int $0x30;");
#endif 

        DbgPrint("Wait------- for interrupt\n");
        while (!irq_event[idx]);
        reset_irq(idx);
        DbgPrint("WAKE_UP\n");
//      irq_event[idx] = 0;
}
...
//! This function will be invoked by isr, so
//! we don't need to disable interrupt
void wakeup_irq(int idx)
{
#if 0
        struct list_head *pos;
        struct list_head *n;
        kthread_t *kthread;

        DbgPrint("Invoked\n");

        if (idx >= MAX_IRQ_WAIT) PANIC("Invalid IRQ");

        DbgPrint("ok\n");

        list_for_each_safe(pos, n, irq_event + idx) {
                kthread = list_entry(pos, kthread_t, wait);
                ASSERT(kthread);

                list_del(pos);
                kthread->wait_irq = -1;

                list_add(&kthread->head, &kthread_get_current()->head);
        }
#endif 

        DbgPrint("Let's WAKEUP\n");
        irq_event[idx] = 1;
}
void reset_irq(int idx)
{
        irq_event[idx] = 0;
}

void isr_fdc(void)
{
        DbgPrint("Do I invoked?\n");
        wakeup_irq(WAIT_IRQ_FLOPPY);
}




This is a test code.

Code: Select all

        void *dma;
        boot_t *boot;

//      fdc_init();

        DbgPrint("---------------------------------- 1\n");
        fdc_reset();
        DbgPrint("---------------------------------- 2\n");

        dma = pmalloc(ZONE_DMA, 1);

//      fdc_read_data(1, dma, 4);

        boot = (boot_t*)dma;

/*
        printk("Jump Instruction : 0x%X 0x%X\n", boot->jmp[0], boot->jmp[1]);
        printk("NOP Instructrion : 0x%X\n", boot->nop);
        printk("OEM : %*s\n", 8, boot->oem);
        printk("Sector size : %d\n", boot->sector_size);
        printk("Sector per cluster : %d\n", boot->sector_per_cluster);
        printk("Reserved sector count : %d\n", boot->reserved_sector);
        printk("Number of FATs : %d\n", boot->number_fat);
        printk("Number of Root Entry : %d\n", boot->number_root_entry);
        printk("Total sector : %d\n", boot->total_sector16);
        printk("Media type : %X (? F0 : Removal)\n", boot->media_type);
        printk("Size of a FAT : %d\n", boot->size_of_fat);
        printk("Sectors per a track : %d\n", boot->sector_per_track);
        printk("Number of heads : %d\n", boot->number_head);
        printk("Hidden sectors : %d\n", boot->hidden_sector);
        printk("Total sectors : %d\n", boot->total_sector);
        printk("Boot drive : %d\n", boot->boot_drive);
        printk("Reserved : %X\n", boot->reserved);
        printk("Boot signature : %X\n", boot->boot_signature);
        printk("Volume ID : %X\n", boot->volume_id);
        printk("Volume label : %11s\n", boot->volume_label);
        printk("FS type : %8s\n", boot->fs_type);
*/
        pfree(ZONE_DMA, dma);


Re: FDC driver doesn't work (full source embedded)

Posted: Thu Oct 08, 2009 1:25 am
by hailstorm
I just finished my work on my own floppy driver and I must say that programming the FDC can be a pain in the @ss.
But with the help of Bochs you can quickly figure out what's going wrong with your commands.

One of your mistake, which I almost missed, is that you don't enable the drive motor when calibrating, seeking, writing
or reading! If you don't do this, the fdc doesn't accept commands for the selected drive! [-X

I have a few hints... First of all, you assume the track length is 80, which is wrong. It should be 18. Further more,
if you wish to read or write a sector, you instruct the fdc that the track length is requested sector + 1, unless the requested
sector is 18. In that case, the track length is just 18. I don't know for sure if that is a must, but it works for me and I see
a lot in other people sources.
The next thing is, you don't give the controller a chance to react on your read and write commands. The controller doesn't
have to be ready all the time, so you have to give it a few tries before you really know whether the controller is ready or
not. You can use while or for loop for this. Should the controller not be ready after, let's say 200-500 tries, give it a punch
by resetting the fdc.

Use the bochs debugger to intercept the fdc debug messages. You can enable log messages for the fdc via config, clicking
log options, click "specify log options per device", select fdd in the list of the devices. For Debug events you choose "log".
Reset the machine, wait until your error occurs and take a look at bochsout.txt

Re: FDC driver doesn't work (full source embedded)

Posted: Sun Oct 11, 2009 4:56 am
by nicesj
Ok, I fixed some codes what you mentioned.
but I couldn't find the problem of codes.
(fdc.c)
http://nicesj.com/main.php?pass=false&c ... 01852396ee
(fdc.h)
http://nicesj.com/main.php?pass=false&c ... e49658c712

so I attach bochs log to here.

What I have to do more for FDC?

Code: Select all

00046360438d[FDD  ] read(): during command 0xfe, port 0x03f2 returns 0x00
..
00046937720d[CPU0 ] interrupt(): vector = 20, TYPE = 0, EXT = 1
00046937720d[CPU0 ] interrupt(): INTERRUPT TO SAME PRIVILEGE
00046937727d[PIC  ] IO write to 0020 = 20
00046941176d[CLVGA] 8-bit write to 03d4 = 0e
00046941194d[CLVGA] 8-bit write to 03d5 = 07
00046941209d[CLVGA] 8-bit write to 03d4 = 0f
00046941226d[CLVGA] 8-bit write to 03d5 = 80
00046941279d[FDD  ] write access to port 0x03f2, value=0x08
00046941279d[FDD  ] io_write: digital output register
00046941279d[FDD  ]   motor on, drive1 = 0
00046941279d[FDD  ]   motor on, drive0 = 0
00046941279d[FDD  ]   dma_and_interrupt_enable=08
00046941279d[FDD  ]   normal_operation=00
00046941279d[FDD  ]   drive_select=00
00046941330d[FDD  ] write access to port 0x03f2, value=0x1c
00046941330d[FDD  ] io_write: digital output register
00046941330d[FDD  ]   motor on, drive1 = 0
00046941330d[FDD  ]   motor on, drive0 = 1
00046941330d[FDD  ]   dma_and_interrupt_enable=08
00046941330d[FDD  ]   normal_operation=04
00046941330d[FDD  ]   drive_select=00
00046941348d[FDD  ] read(): during command 0xfe, port 0x03f4 returns 0x00
00046943830i[FDD  ] controller reset in software
00046943830d[IOAP ] set_irq_level(): INTIN6: level=0
00046943830d[IOAP ] set_irq_level(): INTIN6: level=1
00046943830d[IOAP ] IOAPIC: servicing
00046943830d[IOAP ] service_ioapic(): INTIN0 is masked
00046943830d[IOAP ] service_ioapic(): INTIN6 is masked
00046943830d[PIC  ] IRQ line 6 now high
00046943830d[PIC  ] signalling IRQ(6)
00046943830d[CPU0 ] interrupt(): vector = 26, TYPE = 0, EXT = 1
00046943830d[CPU0 ] interrupt(): INTERRUPT TO SAME PRIVILEGE
00046943837d[PIC  ] IO write to 0020 = 20
...
00047735789d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0x80
...
00048336129d[FDD  ] write access to port 0x03f7, value=0x00
00048336129i[FDD  ] io_write: config control register: 0x00
00048336129d[FDD  ]   500 Kbps
...
00048663533d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0x80
00048663565d[FDD  ] write access to port 0x03f5, value=0x08
00048663565d[FDD  ] command = 0x08
00048663565d[FDD  ] COMMAND: [08]
00048663565d[FDD  ] sense interrupt status
00048663565d[FDD  ] RESULT: [c0] [00]
00048663565d[FDD  ] io_write: diskette controller data
00048663590d[FDD  ] read(): during command 0x08, port 0x03f4 returns 0xd0
00048663617d[IOAP ] set_irq_level(): INTIN6: level=0
00048663617d[PIC  ] IRQ line 6 now low
00048663617d[FDD  ] read(): during command 0x08, port 0x03f5 returns 0xc0
00048663651d[FDD  ] read(): during command 0x08, port 0x03f4 returns 0xd0
00048663678d[FDD  ] read(): during command 0x08, port 0x03f5 returns 0x00
00048663726d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0x80
00048663758d[FDD  ] write access to port 0x03f5, value=0x08
00048663758d[FDD  ] command = 0x08
00048663758d[FDD  ] COMMAND: [08]
00048663758d[FDD  ] sense interrupt status
00048663758d[FDD  ] RESULT: [c1] [00]
00048663758d[FDD  ] io_write: diskette controller data
00048663783d[FDD  ] read(): during command 0x08, port 0x03f4 returns 0xd0
00048663810d[FDD  ] read(): during command 0x08, port 0x03f5 returns 0xc1
00048663844d[FDD  ] read(): during command 0x08, port 0x03f4 returns 0xd0
00048663871d[FDD  ] read(): during command 0x08, port 0x03f5 returns 0x00
00048663919d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0x80
00048663951d[FDD  ] write access to port 0x03f5, value=0x08
00048663951d[FDD  ] command = 0x08
00048663951d[FDD  ] COMMAND: [08]
00048663951d[FDD  ] sense interrupt status
00048663951d[FDD  ] RESULT: [c2] [00]
00048663951d[FDD  ] io_write: diskette controller data
00048663976d[FDD  ] read(): during command 0x08, port 0x03f4 returns 0xd0
00048664003d[FDD  ] read(): during command 0x08, port 0x03f5 returns 0xc2
00048664037d[FDD  ] read(): during command 0x08, port 0x03f4 returns 0xd0
00048664064d[FDD  ] read(): during command 0x08, port 0x03f5 returns 0x00
00048664112d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0x80
00048664144d[FDD  ] write access to port 0x03f5, value=0x08
00048664144d[FDD  ] command = 0x08
00048664144d[FDD  ] COMMAND: [08]
00048664144d[FDD  ] sense interrupt status
00048664144d[FDD  ] RESULT: [c3] [00]
00048664144d[FDD  ] io_write: diskette controller data
00048664169d[FDD  ] read(): during command 0x08, port 0x03f4 returns 0xd0
00048664196d[FDD  ] read(): during command 0x08, port 0x03f5 returns 0xc3
00048664230d[FDD  ] read(): during command 0x08, port 0x03f4 returns 0xd0
00048664257d[FDD  ] read(): during command 0x08, port 0x03f5 returns 0x00
00048664304d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0x80
00048664336d[FDD  ] write access to port 0x03f5, value=0x03
00048664336d[FDD  ] command = 0x03
00048664336d[FDD  ] io_write: diskette controller data
00048664369d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0x90
00048664401d[FDD  ] write access to port 0x03f5, value=0x30
00048664401d[FDD  ] command = 0x30
00048664401d[FDD  ] io_write: diskette controller data
00048664431d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0x90
00048664463d[FDD  ] write access to port 0x03f5, value=0x21
00048664463d[FDD  ] command = 0x21
00048664463d[FDD  ] COMMAND: [03] [30] [21]
00048664463e[FDD  ] non DMA mode not fully implemented yet
00048664463d[FDD  ] io_write: diskette controller data
00048664499d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0xa0
00048664531d[FDD  ] write access to port 0x03f5, value=0x07
00048664531d[FDD  ] command = 0x07
00048664531d[FDD  ] io_write: diskette controller data
00048664559d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0xb0
00048664591d[FDD  ] write access to port 0x03f5, value=0x00
00048664591d[FDD  ] command = 0x00
00048664591d[FDD  ] COMMAND: [07] [00]
00048664591d[FDD  ] floppy_command(): recalibrate drive 0
00048664591d[FDD  ] io_write: diskette controller data
...

00049182171d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0xa1
00049182203d[FDD  ] write access to port 0x03f5, value=0x08
00049182203d[FDD  ] command = 0x08
00049182203d[FDD  ] COMMAND: [08]
00049182203d[FDD  ] sense interrupt status
00049182203d[FDD  ] RESULT: [20] [00]
00049182203d[FDD  ] io_write: diskette controller data
00049182228d[FDD  ] read(): during command 0x08, port 0x03f4 returns 0xf1
00049182255d[IOAP ] set_irq_level(): INTIN6: level=0
00049182255d[PIC  ] IRQ line 6 now low
00049182255d[FDD  ] read(): during command 0x08, port 0x03f5 returns 0x20
00049182289d[FDD  ] read(): during command 0x08, port 0x03f4 returns 0xf0
00049182316d[FDD  ] read(): during command 0x08, port 0x03f5 returns 0x00
...
00049750337d[FDD  ] write access to port 0x03f2, value=0x1c
00049750337d[FDD  ] io_write: digital output register
00049750337d[FDD  ]   motor on, drive1 = 0
00049750337d[FDD  ]   motor on, drive0 = 1
00049750337d[FDD  ]   dma_and_interrupt_enable=08
00049750337d[FDD  ]   normal_operation=04
00049750337d[FDD  ]   drive_select=00
00049750355d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0xa0
00049765520d[PIT  ] entering timer handler
...
00050337490d[CPU0 ] interrupt(): vector = 20, TYPE = 0, EXT = 1
00050337490d[CPU0 ] interrupt(): INTERRUPT TO SAME PRIVILEGE
00050337497d[PIC  ] IO write to 0020 = 20
00050350706d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0xa0
00050350738d[FDD  ] write access to port 0x03f5, value=0x0f
00050350738d[FDD  ] command = 0x0f
00050350738d[FDD  ] io_write: diskette controller data
00050350769d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0xb0
00050350801d[FDD  ] write access to port 0x03f5, value=0x00
00050350801d[FDD  ] command = 0x00
00050350801d[FDD  ] io_write: diskette controller data
00050350829d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0xb0
00050350861d[FDD  ] write access to port 0x03f5, value=0x00
00050350861d[FDD  ] command = 0x00
00050350861d[FDD  ] COMMAND: [0f] [00] [00]
00050350861d[FDD  ] io_write: diskette controller data
...
00050934714d[DMA  ] write: address=000a value=06
00050934714d[DMA  ] DMA-1: set_mask_bit=4, channel=2, mask now=01h
00050934743d[DMA  ] write: address=000b value=46
00050934743d[DMA  ] DMA-1: mode register[2] = 46
00050934767d[DMA  ] write: address=000c value=00
00050934767d[DMA  ] DMA-1: clear flip/flop
00050934792d[UNMP ] unmapped: 8-bit write to ff81 = 10
00050934817d[UNMP ] unmapped: 8-bit write to ff81 = 00
00050934841d[DMA  ] write: address=0004 value=00
00050934841d[DMA  ]   DMA-1 base and current address, channel 2
00050934867d[DMA  ] write: address=0004 value=00
00050934867d[DMA  ]   DMA-1 base and current address, channel 2
00050934867d[DMA  ]     base = 0000
00050934867d[DMA  ]     curr = 0000
00050934891d[DMA  ] write: address=0005 value=00
00050934891d[DMA  ]   DMA-1 base and current count, channel 2
00050934916d[DMA  ] write: address=0005 value=02
00050934916d[DMA  ]   DMA-1 base and current count, channel 2
00050934916d[DMA  ]     base = 0200
00050934916d[DMA  ]     curr = 0200
00050934942d[DMA  ] write: address=000a value=02
00050934942d[DMA  ] DMA-1: set_mask_bit=0, channel=2, mask now=00h
00050934977d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0xa1
00050935009d[FDD  ] write access to port 0x03f5, value=0xe6
00050935009d[FDD  ] command = 0xe6
00050935009d[FDD  ] io_write: diskette controller data
00050935040d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0xb1
00050935072d[FDD  ] write access to port 0x03f5, value=0x00
00050935072d[FDD  ] command = 0x00
00050935072d[FDD  ] io_write: diskette controller data
00050935100d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0xb1
00050935132d[FDD  ] write access to port 0x03f5, value=0x00
00050935132d[FDD  ] command = 0x00
00050935132d[FDD  ] io_write: diskette controller data
00050935160d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0xb1
00050935192d[FDD  ] write access to port 0x03f5, value=0x00
00050935192d[FDD  ] command = 0x00
00050935192d[FDD  ] io_write: diskette controller data
00050935220d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0xb1
00050935252d[FDD  ] write access to port 0x03f5, value=0x01
00050935252d[FDD  ] command = 0x01
00050935252d[FDD  ] io_write: diskette controller data
00050935278d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0xb1
00050935310d[FDD  ] write access to port 0x03f5, value=0x02
00050935310d[FDD  ] command = 0x02
00050935310d[FDD  ] io_write: diskette controller data
00050935338d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0xb1
00050935370d[FDD  ] write access to port 0x03f5, value=0x01
00050935370d[FDD  ] command = 0x01
00050935370d[FDD  ] io_write: diskette controller data
00050935396d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0xb1
00050935428d[FDD  ] write access to port 0x03f5, value=0x00
00050935428d[FDD  ] command = 0x00
00050935428d[FDD  ] io_write: diskette controller data
00050935454d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0xb1
00050935486d[FDD  ] write access to port 0x03f5, value=0xff
00050935486d[FDD  ] command = 0xff
00050935486d[FDD  ] COMMAND: [e6] [00] [00] [00] [01] [02] [01] [00] [ff]
00050935486d[FDD  ] read/write normal data
00050935486d[FDD  ] BEFORE
00050935486d[FDD  ]   drive    = 0
00050935486d[FDD  ]   head     = 0
00050935486d[FDD  ]   cylinder = 0
00050935486d[FDD  ]   sector   = 1
00050935486d[FDD  ]   eot      = 1
00050935486d[FDD  ] floppy_xfer: drive=0, offset=0, bytes=512, direction=from floppy
00050935486d[FDD  ] io_write: diskette controller data
after this line, the FDD doesn't write any log for me...
help me,
This is my first time to write the device driver.

How can I figure this out? I already spend a month for this..ㅜㅠ

Please.. help me..
Thank you..

Re: FDC driver doesn't work (full source embedded)

Posted: Sun Oct 11, 2009 4:44 pm
by djsilence

Re: FDC driver doesn't work (full source embedded)

Posted: Mon Oct 12, 2009 12:57 am
by hailstorm
My guess is that you are very, very close. It only depends on "one" byte.
Do you know how the DMA controller works? If you answer yes, you should know that the DMA controller
is incapable of transferring zero bytes (well, it can, but it is inactive then). So, when you program the
DMA controller, you notice that the minimum amount of units you can transfer is 1. The maximum
amount of units that you can transfer is 65536. For 8 bit mode, the unitsize is in bytes.
Now, you probably have noticed that you can't pass the number 65536 as the count value to the controller,
since it exceeds the maximum value of a word. Therefore, the smart architects of the dma-controller
said; which nutcase wants to transfer zero bytes of memory? Let's start counting at 1. When you pass
the value 0, 1 byte is transferred. When you pass value 1, 2 bytes are transferred, etc...

You pass 0x200 as count, which is one too many. Try to pass the value 0x1ff and the fdc will probably
fire an interrupt, since the dma is not waiting for one extra byte anymore.

Re: FDC driver doesn't work (full source embedded)

Posted: Mon Oct 12, 2009 7:06 pm
by nicesj
Ah,.

I subtract one byte from the read size, and fix the SPECIFY command handling function.
I have mistake in that function. Enabling DMA is not correctly done, so I fixed it.

I have received the interrupt after the read command and got the "READ DONE" message (bochs log).

However the buffer contains strange (maybe garbage?) data.
I still missed something,.

Thank you..

Re: FDC driver doesn't work (full source embedded)

Posted: Tue Oct 13, 2009 2:37 am
by hailstorm
The only thing that I saw was that the GAP3 length in the bochs log wasn't correct. It said 00, while it should be 1B (27). Maybe you should take a look at that.

Re: FDC driver doesn't work (full source embedded)

Posted: Fri Oct 16, 2009 10:56 am
by nicesj
fdc.c
http://nicesj.com/main.php?pass=false&c ... 8c9b82505a
fdc.h
http://nicesj.com/main.php?pass=false&c ... f7cc00e63c

Uh., I update fdc codes but it still couldn't read data from the fdc.
Could you help me to fix this problem?

Code: Select all

00049348418d[DMA  ] write: address=000a value=06
00049348418d[DMA  ] DMA-1: set_mask_bit=4, channel=2, mask now=01h
00049348441d[DMA  ] write: address=000c value=00
00049348441d[DMA  ] DMA-1: clear flip/flop
00049348464d[DMA  ] write: address=0004 value=00
00049348464d[DMA  ]   DMA-1 base and current address, channel 2
00049348489d[DMA  ] write: address=0004 value=00
00049348489d[DMA  ]   DMA-1 base and current address, channel 2
00049348489d[DMA  ]     base = 0000
00049348489d[DMA  ]     curr = 0000
00049348513d[DMA  ] write: address=0081 value=10
00049348513d[DMA  ] DMA-1: page register 2 = 10
00049348537d[DMA  ] write: address=0081 value=00
00049348537d[DMA  ] DMA-1: page register 2 = 00
00049348560d[DMA  ] write: address=000c value=00
00049348560d[DMA  ] DMA-1: clear flip/flop
00049348584d[DMA  ] write: address=0005 value=ff
00049348584d[DMA  ]   DMA-1 base and current count, channel 2
00049348609d[DMA  ] write: address=0005 value=01
00049348609d[DMA  ]   DMA-1 base and current count, channel 2
00049348609d[DMA  ]     base = 01ff
00049348609d[DMA  ]     curr = 01ff
00049348637d[DMA  ] write: address=000b value=46
00049348637d[DMA  ] DMA-1: mode register[2] = 46
00049348662d[DMA  ] write: address=000a value=02
00049348662d[DMA  ] DMA-1: set_mask_bit=0, channel=2, mask now=00h
00049348698d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0x80
00049348730d[FDD  ] write access to port 0x03f5, value=0xe6
00049348730d[FDD  ] command = 0xe6
00049348730d[FDD  ] io_write: diskette controller data
00049348761d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0x90
00049348793d[FDD  ] write access to port 0x03f5, value=0x00
00049348793d[FDD  ] command = 0x00
00049348793d[FDD  ] io_write: diskette controller data
00049348821d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0x90
00049348853d[FDD  ] write access to port 0x03f5, value=0x00
00049348853d[FDD  ] command = 0x00
00049348853d[FDD  ] io_write: diskette controller data
00049348881d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0x90
00049348913d[FDD  ] write access to port 0x03f5, value=0x00
00049348913d[FDD  ] command = 0x00
00049348913d[FDD  ] io_write: diskette controller data
00049348941d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0x90
00049348973d[FDD  ] write access to port 0x03f5, value=0x01
00049348973d[FDD  ] command = 0x01
00049348973d[FDD  ] io_write: diskette controller data
00049348999d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0x90
00049349031d[FDD  ] write access to port 0x03f5, value=0x02
00049349031d[FDD  ] command = 0x02
00049349031d[FDD  ] io_write: diskette controller data
00049349059d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0x90
00049349091d[FDD  ] write access to port 0x03f5, value=0x01
00049349091d[FDD  ] command = 0x01
00049349091d[FDD  ] io_write: diskette controller data
00049349117d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0x90
00049349149d[FDD  ] write access to port 0x03f5, value=0x1b
00049349149d[FDD  ] command = 0x1b
00049349149d[FDD  ] io_write: diskette controller data
00049349175d[FDD  ] read(): during command 0x00, port 0x03f4 returns 0x90
00049349207d[FDD  ] write access to port 0x03f5, value=0xff
00049349207d[FDD  ] command = 0xff
00049349207d[FDD  ] COMMAND: [e6] [00] [00] [00] [01] [02] [01] [1b] [ff]
00049349207d[FDD  ] read/write normal data
00049349207d[FDD  ] BEFORE
00049349207d[FDD  ]   drive    = 0
00049349207d[FDD  ]   head     = 0
00049349207d[FDD  ]   cylinder = 0
00049349207d[FDD  ]   sector   = 1
00049349207d[FDD  ]   eot      = 1
00049349207d[FDD  ] floppy_xfer: drive=0, offset=0, bytes=512, direction=from floppy
00049349207d[FDD  ] io_write: diskette controller data
00049365550d[PIT  ] entering timer handler
00049365550d[PIT81] clock_all:  cycles=3340
00049365550d[PIT  ] RESETting timer
00049365550d[PIT  ] deactivated timer
00049365550d[PIT  ] activated timer
00049365550d[PIT  ] s.last_usec=4936555
00049365550d[PIT  ] s.timer_id=1
00049365550d[PIT  ] s.timer.get_next_event_time=218e
00049365550d[PIT  ] s.last_next_event_time=8590
00049365560d[PIT  ] entering timer handler
00049365560d[PIT81] clock_all:  cycles=1
00049365560d[PIT  ] RESETting timer
00049365560d[PIT  ] deactivated timer
00049365560d[PIT  ] activated timer
00049365560d[PIT  ] s.last_usec=4936556
00049365560d[PIT  ] s.timer_id=1
00049365560d[PIT  ] s.timer.get_next_event_time=218d
00049365560d[PIT  ] s.last_next_event_time=8589
00049401540d[PIT  ] entering timer handler
00049401540d[PIT81] clock_all:  cycles=4293
00049401540d[PIT  ] RESETting timer
00049401540d[PIT  ] deactivated timer
00049401540d[PIT  ] activated timer
00049401540d[PIT  ] s.last_usec=4940154
00049401540d[PIT  ] s.timer_id=1
00049401540d[PIT  ] s.timer.get_next_event_time=10c8
00049401540d[PIT  ] s.last_next_event_time=4296
00049401550d[PIT  ] entering timer handler
00049401550d[PIT81] clock_all:  cycles=2
00049401550d[PIT  ] RESETting timer
00049401550d[PIT  ] deactivated timer
00049401550d[PIT  ] activated timer
00049401550d[PIT  ] s.last_usec=4940155
00049401550d[PIT  ] s.timer_id=1
00049401550d[PIT  ] s.timer.get_next_event_time=10c6
00049401550d[PIT  ] s.last_next_event_time=4294
00049437530d[PIT  ] entering timer handler
00049437530d[PIT81] clock_all:  cycles=4293
00049437530d[PIT  ] RESETting timer
00049437530d[PIT  ] deactivated timer
00049437530d[PIT  ] activated timer
00049437530d[PIT  ] s.last_usec=4943753
00049437530d[PIT  ] s.timer_id=1
00049437530d[PIT  ] s.timer.get_next_event_time=1
00049437530d[PIT  ] s.last_next_event_time=1
00049437540d[PIT  ] entering timer handler
00049437540d[PIT81] clock_all:  cycles=1
00049437540d[IOAP ] set_irq_level(): INTIN0: level=0
00049437540d[PIC  ] IRQ line 0 now low
00049437540d[PIT  ] RESETting timer
00049437540d[PIT  ] deactivated timer
00049437540d[PIT  ] activated timer
00049437540d[PIT  ] s.last_usec=4943754
00049437540d[PIT  ] s.timer_id=1
00049437540d[PIT  ] s.timer.get_next_event_time=1
00049437540d[PIT  ] s.last_next_event_time=1
00049437550d[PIT  ] entering timer handler
00049437550d[PIT81] clock_all:  cycles=1
00049437550d[IOAP ] set_irq_level(): INTIN0: level=1
00049437550d[IOAP ] IOAPIC: servicing
00049437550d[IOAP ] service_ioapic(): INTIN0 is masked
00049437550d[IOAP ] service_ioapic(): INTIN6 is masked
00049437550d[PIC  ] IRQ line 0 now high
00049437550d[PIC  ] signalling IRQ(0)
00049437550d[PIT  ] RESETting timer
00049437550d[PIT  ] deactivated timer
00049437550d[PIT  ] activated timer
00049437550d[PIT  ] s.last_usec=4943755
00049437550d[PIT  ] s.timer_id=1
00049437550d[PIT  ] s.timer.get_next_event_time=2e9a
00049437550d[PIT  ] s.last_next_event_time=11930
00049437550d[CPU0 ] interrupt(): vector = 20, TYPE = 0, EXT = 1
00049437550d[CPU0 ] interrupt(): INTERRUPT TO SAME PRIVILEGE
00049437557d[PIC  ] IO write to 0020 = 20
00049460828d[FDD  ] <<READ DONE>>
00049460828d[FDD  ] AFTER
00049460828d[FDD  ]   drive    = 0
00049460828d[FDD  ]   head     = 1
00049460828d[FDD  ]   cylinder = 0
00049460828d[FDD  ]   sector   = 1
00049460828d[IOAP ] set_irq_level(): INTIN6: level=1
00049460828d[IOAP ] IOAPIC: servicing
00049460828d[IOAP ] service_ioapic(): INTIN0 is masked
00049460828d[IOAP ] service_ioapic(): INTIN6 is masked

Re: FDC driver doesn't work (full source embedded)

Posted: Sun Oct 18, 2009 7:10 am
by nicesj
Finally, I found What's going wrong.
The DMAC write data on 0x00000000 when it done read from the FDC.

I could not setup the DMAC correctly,
Because I couldn't understand how it works. :oops:

The DMAC can only understand lower 24 bits for writing/reading something from the I/O devices. (address line)

Thank you for helping me, Now, I have to start new journey~ :D