#include"hwio.h"
#include"dma.h"
const byte _DMA_ADDR_REG[8] = { 0, 2, 4, 6, 0xC0, 0xC4, 0xC8, 0xCC };
const byte _DMA_EXT_ADDR_REG[8] = { 0x83, 0x81, 0x82, 6, 0xC0, 0xC4, 0xC8, 0xCC };
const byte _DMA_COUNT_REG[8] = { 1, 3, 5, 7, 0xC2, 0xC6, 0xCA, 0xCE };
#define DMA_SLAVE_SET_MODE 0x0B
#define DMA_MASTER_SET_MODE 0xD6
#define DMA_MODE_MASK_SEL 3
#define DMA_MODE_MASK_TRA 0xc
#define DMA_MODE_SELF_TEST 0
#define DMA_MODE_READ_TRANSFER 4
#define DMA_MODE_WRITE_TRANSFER 8
#define DMA_MODE_MASK_AUTO 0x10
#define DMA_MODE_MASK_IDEC 0x20
#define DMA_MODE_MASK 0xc0
#define DMA_MODE_TRANSFER_ON_DEMAND 0
#define DMA_MODE_TRANSFER_SINGLE 0x40
#define DMA_MODE_TRANSFER_BLOCK 0x80
#define DMA_MODE_TRANSFER_CASCADE 0xC0
#define DMA_CMD_MASK_MEMTOMEM 1
#define DMA_CMD_MASK_CHAN0ADDRHOLD 2
#define DMA_CMD_MASK_ENABLE 4
#define DMA_CMD_MASK_TIMING 8
#define DMA_CMD_MASK_PRIORITY 0x10
#define DMA_CMD_MASK_WRITESEL 0x20
#define DMA_CMD_MASK_DREQ 0x40
#define DMA_CMD_MASK_DACK 0x80
#define DMA_SLAVE_INTER_REG 0x0D
#define DMA_MASTER_INTER_REG 0xDA
#define DMA_SLAVE_CHMASK 0x0A
#define DMA_MASTER_CHMASK 0xD4
#define DMA_SLAVE_CLEARBYTE_FLIPFLOP_REG 0x0C
#define DMA_MASTER_CLEARBYTE_FLIPFLOP_REG 0xD8
inline void dmaReset(enum DMAC n)
{
	switch (n)
	{
	case Slave_DMA:
		outb(DMA_SLAVE_INTER_REG, 0xFF);
	case Master_DMA:
		outb(DMA_MASTER_INTER_REG, 0xFF);
	default:;
	}
}
inline void dmaAddr(byte channel, void* addr)
{
	byte page = ((dword)addr & 0xFF0000) >> 16;
	outb(_DMA_EXT_ADDR_REG[channel], page);
	outw(_DMA_ADDR_REG[channel], (dword)addr&0xFFFF);
}
inline void dmaCount(byte channel, word n)
{
	outw(_DMA_COUNT_REG[channel], n);
}
inline void dmaMask(byte channel)
{
	if (channel > 3)
		outb(DMA_MASTER_CHMASK, (1 << (channel)));
	else
		outb(DMA_SLAVE_CHMASK, (1 << (channel-4)));
}
inline void dmaUnmask(byte channel)
{
	if (channel > 3)
		outb(DMA_MASTER_CHMASK, channel);
	else
		outb(DMA_SLAVE_CHMASK, channel);
}
void dmaMode(byte channel, byte mode)
{
	byte port=DMA_SLAVE_SET_MODE;
	if (channel > 3)
	{
		//Master DMA
		channel -= 4;
		port += (DMA_MASTER_SET_MODE - DMA_SLAVE_SET_MODE);
	}
	dmaMask(channel);
	outb(port, mode | channel);
	dmaUnmask(channel);
}
inline void dmaRead(byte channel)
{
	dmaMode(channel, DMA_MODE_READ_TRANSFER | DMA_MODE_TRANSFER_SINGLE);
}
inline void dmaWrite(byte channel)
{
	dmaMode(channel, DMA_MODE_WRITE_TRANSFER | DMA_MODE_TRANSFER_SINGLE);
}
inline void dmaClearFlipFlop(enum DMAC n)
{
	switch (n)
	{
	case Master_DMA:
		outb(DMA_MASTER_CLEARBYTE_FLIPFLOP_REG, 0xFF);
	case Slave_DMA:
		outb(DMA_SLAVE_CLEARBYTE_FLIPFLOP_REG, 0xFF);
	default:;
	}
}
