#include <stdio.h> /* printf() */ #include "sound.h" /* bool */ static const unsigned short _single_reg[8] = { 0x0A, 0x0A, 0x0A, 0x0A, 0xD4, 0xD4, 0xD4, 0xD4 }; static const unsigned char _disable_cmd[8] = { 0x04, 0x05, 0x06, 0x07, 0x04, 0x05, 0x06, 0x07, }; static const unsigned short _mode_reg[8] = { 0x0B, 0x0B, 0x0B, 0x0B, 0xD6, 0xD6, 0xD6, 0xD6 }; static const unsigned short _ff_reg[8] = { 0x0C, 0x0C, 0x0C, 0x0C, 0xD8, 0xD8, 0xD8, 0xD8 }; static const unsigned short _adr_reg[8] = { 0x00, 0x02, 0x04, 0x06, 0xC0, 0xC4, 0xC8, 0xCC }; static const unsigned short _page_reg[8] = { 0x87, 0x83, 0x81, 0x82, 0x8F, 0x8B, 0x89, 0x8A }; static const unsigned short _count_reg[8] = { 0x01, 0x03, 0x05, 0x07, 0xC2, 0xC6, 0xCA, 0xCE }; static const unsigned char _enable_cmd[8] = { 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03, }; /***************************************************************************** *****************************************************************************/ int dma_from_mem(unsigned char chan, unsigned long adr, unsigned long count, bool auto_init) { static const unsigned char write_cmd[8] = { 0x48, 0x49, 0x4A, 0x4B, 0x48, 0x49, 0x4A, 0x4B }; /* validate chan */ if(chan > 7) { wprintf(L"dma_from_mem: DMA channel (%u) > 7\n", chan); return -1; } /* 16 bit data is halved */ if(chan >= 4) { adr >>= 1; count >>= 1; } count--; /* make sure transfer doesn't exceed max or cross a 64K boundary */ if(adr + count >= 0x100000L) /* real mode; 1 meg */ // if(adr + count >= 0x1000000L) /* pmode; 16 meg */ { wprintf(L"dma_from_mem: end adr (0x%lX) exceeds max\n", adr + count); return -2; } if((adr & 0x10000L) != ((adr + count) & 0x10000L)) { wprintf(L"dma_from_mem: DMA from adrs 0x%lX - 0x%lX " "crosses 64K boundary\n", adr, adr + count); return -3; } /* disable channel */ out(_single_reg[chan], _disable_cmd[chan]); /* set mode */ out(_mode_reg[chan], auto_init ? (write_cmd[chan] | 0x10) : write_cmd[chan]); /* clear flip-flop, for LSB of address */ out(_ff_reg[chan], 0); /* address LSB */ out(_adr_reg[chan], adr); adr >>= 8; /* address MSB */ out(_adr_reg[chan], adr); adr >>= 8; /* page */ out(_page_reg[chan], adr); /* clear flip-flop, for LSB of count */ out(_ff_reg[chan], 0); /* count LSB */ out(_count_reg[chan], count); count >>= 8; /* count MSB */ out(_count_reg[chan], count); /* enable channel */ out(_single_reg[chan], _enable_cmd[chan]); return 0; }