fixed 16bit playback. DMA page reg expects the page unshifted
[dos_auplay] / src / dma.c
1 #include <conio.h>\r
2 #include "dma.h"\r
3 \r
4 #define MODE_CHAN(x)    ((x) & 3)\r
5 #define MODE_WRITE              0x04\r
6 #define MODE_READ               0x08\r
7 #define MODE_AUTO               0x10\r
8 #define MODE_DECR               0x20\r
9 #define MODE_SINGLE             0x40\r
10 #define MODE_BLOCK              0x80\r
11 #define MODE_CASCADE    0xc0\r
12 \r
13 #define MASK_CHAN(x)    ((x) & 3)\r
14 #define MASK_DISABLE    0x04\r
15 \r
16 #define RMASK_CHAN(x)   (1 << ((x) & 3))\r
17 \r
18 #define IS_16BIT(c)     ((c) >= 4)\r
19 \r
20 static void dma_io(int chan, uint32_t phyaddr, int size, unsigned int flags, unsigned int dir);\r
21 static __inline void mask(int chan);\r
22 static __inline void unmask(int chan);\r
23 \r
24 /* DMA register I/O ports for all channels */\r
25 static const int addr_port[] = { 0x00, 0x02, 0x04, 0x06, 0xc0, 0xc4, 0xc8, 0xcc };\r
26 static const int count_port[] = { 0x01, 0x03, 0x05, 0x07, 0xc2, 0xc6, 0xca, 0xce };\r
27 static const int page_port[] = { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };\r
28 static const int mask_port[] = { 0x0a, 0x0a, 0x0a, 0x0a, 0xd4, 0xd4, 0xd4, 0xd4 };\r
29 static const int mode_port[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0xd6, 0xd6, 0xd6, 0xd6 };\r
30 static const int clrff_port[] = { 0x0c, 0x0c, 0x0c, 0x0c, 0xd8, 0xd8, 0xd8, 0xd8 };\r
31 \r
32 void dma_out(int chan, uint32_t phyaddr, int size, unsigned int flags)\r
33 {\r
34         dma_io(chan, phyaddr, size, flags, MODE_READ);\r
35 }\r
36 \r
37 void dma_in(int chan, uint32_t phyaddr, int size, unsigned int flags)\r
38 {\r
39         dma_io(chan, phyaddr, size, flags, MODE_WRITE);\r
40 }\r
41 \r
42 static void dma_io(int chan, uint32_t phyaddr, int size, unsigned int flags, unsigned int dir)\r
43 {\r
44         unsigned int mode;\r
45         unsigned char page;\r
46 \r
47         mask(chan);\r
48         outp(clrff_port[chan], 0);\r
49 \r
50         /* first 2 bits of flags correspond to the mode bits 6,7 */\r
51         mode = ((flags & 3) << 6) | dir | MODE_CHAN(chan);\r
52         if(flags & DMA_DECR) mode |= MODE_DECR;\r
53         if(flags & DMA_AUTO) mode |= MODE_AUTO;\r
54         outp(mode_port[chan], mode);\r
55 \r
56         page = (phyaddr >> 16) & 0xff;\r
57 \r
58         if(IS_16BIT(chan)) {\r
59                 phyaddr >>= 1;\r
60                 size >>= 1;\r
61         }\r
62 \r
63         outp(addr_port[chan], phyaddr & 0xff);\r
64         outp(addr_port[chan], (phyaddr >> 8) & 0xff);\r
65         outp(page_port[chan], page);\r
66 \r
67         size--;\r
68         outp(count_port[chan], size & 0xff);\r
69         outp(count_port[chan], (size >> 8) & 0xff);\r
70 \r
71         unmask(chan);\r
72 }\r
73 \r
74 static __inline void mask(int chan)\r
75 {\r
76         outp(mask_port[chan], MASK_CHAN(chan) | MASK_DISABLE);\r
77 }\r
78 \r
79 static __inline void unmask(int chan)\r
80 {\r
81         outp(mask_port[chan], MASK_CHAN(chan));\r
82 }\r