diff --git a/src/kernel/arch/i686/dma.c b/src/kernel/arch/i686/dma.c new file mode 100644 index 0000000..7254da1 --- /dev/null +++ b/src/kernel/arch/i686/dma.c @@ -0,0 +1,94 @@ +#include +#include "dma.h" +#include "io.h" + +void i686_dma_set_address(uint8_t channel, uint16_t addr){ + if(channel > 8) return; + + uint16_t port = 0; + switch(channel){ + case 0: port = i686_DMA0_CHAN0_ADDR_REG; break; + case 1: port = i686_DMA0_CHAN1_ADDR_REG; break; + case 2: port = i686_DMA0_CHAN2_ADDR_REG; break; + case 3: port = i686_DMA0_CHAN3_ADDR_REG; break; + case 4: port = i686_DMA1_CHAN4_ADDR_REG; break; + case 5: port = i686_DMA1_CHAN5_ADDR_REG; break; + case 6: port = i686_DMA1_CHAN6_ADDR_REG; break; + case 7: port = i686_DMA1_CHAN7_ADDR_REG; break; + } + + i686_outw(port, addr); +} + +void i686_dma_set_count(uint8_t channel, uint16_t count){ + if(channel > 8) return; + + uint16_t port = 0; + switch(channel){ + case 0: port = i686_DMA0_CHAN0_COUNT_REG; break; + case 1: port = i686_DMA0_CHAN1_COUNT_REG; break; + case 2: port = i686_DMA0_CHAN2_COUNT_REG; break; + case 3: port = i686_DMA0_CHAN3_COUNT_REG; break; + case 4: port = i686_DMA1_CHAN4_COUNT_REG; break; + case 5: port = i686_DMA1_CHAN5_COUNT_REG; break; + case 6: port = i686_DMA1_CHAN6_COUNT_REG; break; + case 7: port = i686_DMA1_CHAN7_COUNT_REG; break; + } + + i686_outw(port, count); +} + +void i686_dma_set_external_page_register(uint8_t reg, uint8_t val){ + uint16_t port = 0; + + switch(reg){ + case 1: port = i686_DMA_PAGE_CHAN1_ADDRBYTE2; break; + case 2: port = i686_DMA_PAGE_CHAN2_ADDRBYTE2; break; + case 3: port = i686_DMA_PAGE_CHAN3_ADDRBYTE2; break; + // 4 is not valid + case 5: port = i686_DMA_PAGE_CHAN5_ADDRBYTE2; break; + case 6: port = i686_DMA_PAGE_CHAN6_ADDRBYTE2; break; + case 7: port = i686_DMA_PAGE_CHAN7_ADDRBYTE2; break; + default: return; + } +} + +void i686_dma_set_mode(uint8_t channel, uint8_t mode){ + int dma = (channel < 4) ? 0 : 1; + int chan = (dma == 0) ? channel : channel-4; + + i686_dma_mask_channel(channel); + i686_outb((channel < 4) ? i686_DMA0_MODE_REG : i686_DMA1_MODE_REG, chan | mode); + i686_dma_unmask_all(dma); +} + +void i686_dma_set_read(uint8_t channel){ + i686_dma_set_mode(channel, i686_DMA_MODE_READ_TRANSFER | i686_DMA_MODE_TRANSFER_SINGLE | i686_DMA_MODE_MASK_AUTO); +} + +void i686_dma_set_write(uint8_t channel){ + i686_dma_set_mode(channel, i686_DMA_MODE_WRITE_TRANSFER | i686_DMA_MODE_TRANSFER_SINGLE | i686_DMA_MODE_MASK_AUTO); +} + +void i686_dma_mask_channel(uint8_t channel){ + if(channel <= 4) i686_outb(i686_DMA0_CHANMASK_REG, (1 << (channel-1))); + else i686_outb(i686_DMA1_CHANMASK_REG, (1 << (channel-5))); +} + +void i686_dma_unmask_channel(uint8_t channel){ + i686_outb(channel <= 4 ? i686_DMA0_CHANMASK_REG : i686_DMA1_CHANMASK_REG, channel); +} + +void i686_dma_reset_flipflop(int dma){ + if(dma > 2) return; + + i686_outb((dma == 0) ? i686_DMA0_CLEARBYTE_FLIPFLOP_REG : i686_DMA1_CLEARBYTE_FLIPFLOP_REG, 0xFF); +} + +void i686_dma_reset(int dma){ + i686_outb(i686_DMA0_TEMP_REG, 0xFF); +} + +void i686_dma_unmask_all(int dma){ + i686_outb(i686_DMA1_UNMASK_ALL_REG, 0xFF); +} diff --git a/src/kernel/arch/i686/dma.h b/src/kernel/arch/i686/dma.h new file mode 100644 index 0000000..b6635ec --- /dev/null +++ b/src/kernel/arch/i686/dma.h @@ -0,0 +1,85 @@ +#pragma once + +#include + +#define i686_DMA0_STATUS_REG 0x08 +#define i686_DMA0_COMMAND_REG 0x08 +#define i686_DMA0_REQUEST_REG 0x09 +#define i686_DMA0_CHANMASK_REG 0x0A +#define i686_DMA0_MODE_REG 0x0B +#define i686_DMA0_CLEARBYTE_FLIPFLOP_REG 0x0C +#define i686_DMA0_TEMP_REG 0x0D +#define i686_DMA0_MASTER_CLEAR_REG 0x0D +#define i686_DMA0_CLEAR_MASK_REG 0x0E +#define i686_DMA0_MASK_REG 0x0F +#define i686_DMA0_CHAN0_ADDR_REG 0x00 +#define i686_DMA0_CHAN0_COUNT_REG 0x01 +#define i686_DMA0_CHAN1_ADDR_REG 0x02 +#define i686_DMA0_CHAN1_COUNT_REG 0x03 +#define i686_DMA0_CHAN2_ADDR_REG 0x04 +#define i686_DMA0_CHAN2_COUNT_REG 0x05 +#define i686_DMA0_CHAN3_ADDR_REG 0x06 +#define i686_DMA0_CHAN3_COUNT_REG 0x07 +#define i686_DMA1_STATUS_REG 0xD0 +#define i686_DMA1_COMMAND_REG 0xD0 +#define i686_DMA1_REQUEST_REG 0xD2 +#define i686_DMA1_CHANMASK_REG 0xD4 +#define i686_DMA1_MODE_REG 0xD6 +#define i686_DMA1_CLEARBYTE_FLIPFLOP_REG 0xD8 +#define i686_DMA1_INTER_REG 0xDA +#define i686_DMA1_UNMASK_ALL_REG 0xDC +#define i686_DMA1_MASK_REG 0xDE +#define i686_DMA1_CHAN4_ADDR_REG 0xC0 +#define i686_DMA1_CHAN4_COUNT_REG 0xC2 +#define i686_DMA1_CHAN5_ADDR_REG 0xC4 +#define i686_DMA1_CHAN5_COUNT_REG 0xC6 +#define i686_DMA1_CHAN6_ADDR_REG 0xC8 +#define i686_DMA1_CHAN6_COUNT_REG 0xCA +#define i686_DMA1_CHAN7_ADDR_REG 0xCC +#define i686_DMA1_CHAN7_COUNT_REG 0xCE +#define i686_DMA_PAGE_EXTRA0 0x80 +#define i686_DMA_PAGE_CHAN2_ADDRBYTE2 0x81 +#define i686_DMA_PAGE_CHAN3_ADDRBYTE2 0x82 +#define i686_DMA_PAGE_CHAN1_ADDRBYTE2 0x83 +#define i686_DMA_PAGE_EXTRA1 0x84 +#define i686_DMA_PAGE_EXTRA2 0x85 +#define i686_DMA_PAGE_EXTRA3 0x86 +#define i686_DMA_PAGE_CHAN6_ADDRBYTE2 0x87 +#define i686_DMA_PAGE_CHAN7_ADDRBYTE2 0x88 +#define i686_DMA_PAGE_CHAN5_ADDRBYTE2 0x89 +#define i686_DMA_PAGE_EXTRA4 0x8C +#define i686_DMA_PAGE_EXTRA5 0x8D +#define i686_DMA_PAGE_EXTRA6 0x8E +#define i686_DMA_PAGE_DRAM_REFRESH 0x8F +#define i686_DMA_CMD_MASK_MEMTOMEM 0x01 +#define i686_DMA_CMD_MASK_CHAN0ADDRHOLD 0x02 +#define i686_DMA_CMD_MASK_ENABLE 0x04 +#define i686_DMA_CMD_MASK_TIMING 0x08 +#define i686_DMA_CMD_MASK_PRIORITY 0x10 +#define i686_DMA_CMD_MASK_WRITESEL 0x20 +#define i686_DMA_CMD_MASK_DREQ 0x40 +#define i686_DMA_CMD_MASK_DACK 0x80 +#define i686_DMA_MODE_MASK_SEL 0x03 +#define i686_DMA_MODE_MASK_TRA 0x0C +#define i686_DMA_MODE_MASK_TEST 0x00 +#define i686_DMA_MODE_READ_TRANSFER 0x04 +#define i686_DMA_MODE_WRITE_TRANSFER 0x08 +#define i686_DMA_MODE_MASK_AUTO 0x10 +#define i686_DMA_MODE_MASK_IDEC 0x20 +#define i686_DMA_MODE_MASK 0xC0 +#define i686_DMA_MODE_TRANSFER_ON_DEMAND 0x00 +#define i686_DMA_MODE_TRANSFER_SINGLE 0x40 +#define i686_DMA_MODE_TRANSFER_BLOCK 0x80 +#define i686_DMA_MODE_TRANSFER_CASCADE 0xC0 + +void i686_dma_set_address(uint8_t channel, uint16_t addr); +void i686_dma_set_count(uint8_t channel, uint16_t count); +void i686_dma_set_external_page_register(uint8_t reg, uint8_t val); +void i686_dma_set_mode(uint8_t channel, uint8_t mode); +void i686_dma_set_read(uint8_t channel); +void i686_dma_set_write(uint8_t channel); +void i686_dma_mask_channel(uint8_t channel); +void i686_dma_unmask_channel(uint8_t channel); +void i686_dma_reset_flipflop(int dma); +void i686_dma_reset(int dma); +void i686_dma_unmask_all(int dma); diff --git a/src/kernel/arch/i686/fdc.c b/src/kernel/arch/i686/fdc.c index 8c7042b..692d037 100644 --- a/src/kernel/arch/i686/fdc.c +++ b/src/kernel/arch/i686/fdc.c @@ -2,6 +2,7 @@ #include "fdc.h" #include "isr.h" #include "io.h" +#include "dma.h" #include "../../lib/time.h" #include "../../lib/debug.h" @@ -20,7 +21,7 @@ static inline void wait_irq(){ void i686_fdc_initialize_dma(){ i686_outb(0x0A, 0x06); // Mask DMA channel 2 i686_outb(0xD8, 0xFF); // Reset master flip-flop - i686_outw(0x04, 0x1000); // Address = 0x1000 + i686_outw(0x04, i686_FDC_DMA_BUFFER); // Address = 0x1000 i686_outb(0xD8, 0xFF); // Reset master flip-flop i686_outb(0x05, 0xFF); // Count to 0x23FF (bytes in 2.5" floppy disk track) i686_outb(0x05, 0x23); @@ -97,6 +98,9 @@ int i686_fdc_motor(bool b){ void i686_fdc_read_sector_imp(uint8_t head, uint8_t track, uint8_t sector){ uint32_t st0, cyl; + // Initialize the DMA + i686_dma_initialize_floppy((uint8_t *)i686_FDC_DMA_BUFFER, 512); + // Set DMA for read i686_fdc_dma_read(); @@ -239,3 +243,17 @@ void i686_fdc_initialize(){ // Set drive info i686_fdc_drive_data(13, 1, 0x0F, true); } + +void i686_dma_initialize_floppy(uint8_t *buffer, unsigned length){ + i686_dma_reset(1); + i686_dma_mask_channel(i686_FDC_DMA_CHANNEL); + i686_dma_reset_flipflop(1); + + i686_dma_set_address(i686_FDC_DMA_CHANNEL, (unsigned)buffer); + i686_dma_reset_flipflop(1); + + i686_dma_set_count(i686_FDC_DMA_CHANNEL, length); + i686_dma_set_read(i686_FDC_DMA_CHANNEL); + + i686_dma_unmask_all(1); +} diff --git a/src/kernel/arch/i686/fdc.h b/src/kernel/arch/i686/fdc.h index 5d391fa..0da1ff0 100644 --- a/src/kernel/arch/i686/fdc.h +++ b/src/kernel/arch/i686/fdc.h @@ -48,6 +48,8 @@ #define i686_FDC_SECTOR_DTL_512 2 #define i686_FDC_SECTOR_DTL_1024 4 #define i686_FDC_SECTORS_PER_TRACK 18 +#define i686_FDC_DMA_BUFFER 0x1000 +#define i686_FDC_DMA_CHANNEL 2 void i686_fdc_initialize_dma(); void i686_fdc_dma_read(); @@ -68,3 +70,4 @@ void i686_fdc_enable(); void i686_fdc_reset(); void i686_fdc_set_working_drive(int drive); void i686_fdc_initialize(); +void i686_dma_initialize_floppy(uint8_t *buffer, unsigned length);