2 Copyright (C) 2008 Mathias Gottschlag
4 Permission is hereby granted, free of charge, to any person obtaining a copy of
5 this software and associated documentation files (the "Software"), to deal in the
6 Software without restriction, including without limitation the rights to use,
7 copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
8 Software, and to permit persons to whom the Software is furnished to do so,
9 subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16 PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 #include "ke/errors.h"
24 #include "ke/spinlock.h"
26 #include "mm/memory.h"
35 uintptr_t dmabuffer_phys
;
40 static KeDMAChannel channels
[8];
42 //static uint16_t dma_status[8] = {0x08, 0x08, 0x08, 0x08, 0xD0, 0xD0, 0xD0, 0xD0};
43 //static uint16_t dma_command[8] = {0x08, 0x08, 0x08, 0x08, 0xD0, 0xD0, 0xD0, 0xD0};
44 //static uint16_t dma_request[8] = {0x09, 0x09, 0x09, 0x09, 0xD2, 0xD2, 0xD2, 0xD2};
45 static uint16_t dma_channel_mask
[8] = {0x0A, 0x0A, 0x0A, 0x0A, 0xD4, 0xD4, 0xD4, 0xD4};
46 static uint16_t dma_mode
[8] = {0x0B, 0x0B, 0x0B, 0x0B, 0xD6, 0xD6, 0xD6, 0xD6};
47 static uint16_t dma_data
[8] = {0x0C, 0x0C, 0x0C, 0x0C, 0xD8, 0xD8, 0xD8, 0xD8};
48 //static uint16_t dma_intermediate[8] = {0x0D, 0x0D, 0x0D, 0x0D, 0xDA, 0xDA, 0xDA, 0xDA};
49 //static uint16_t dma_mask[8] = {0x0F, 0x0F, 0x0F, 0x0F, 0xDE, 0xDE, 0xDE, 0xDE};
50 static uint16_t dma_addr
[8] = {0x00, 0x02, 0x04, 0x06, 0xC0, 0xC4, 0xC8, 0xCC};
51 static uint16_t dma_page
[8] = {0x87, 0x83, 0x81, 0x82, 0x8F, 0x8B, 0x89, 0x8A};
52 static uint16_t dma_size
[8] = {0x01, 0x03, 0x05, 0x07, 0xC2, 0xC6, 0xCA, 0xCE};
54 int keOpenDMA(uint8_t channel
, uint8_t mode
, void *buffer
, uint32_t length
)
57 if (channel
>= 8) return KE_ERROR_UNKNOWN
;
58 if (keTryLockSpinlock(&channels
[channel
].opened
)) return KE_ERROR_UNKNOWN
;
59 channels
[channel
].channel
= channel
;
60 channels
[channel
].mode
= mode
;
61 channels
[channel
].buffer
= buffer
;
62 channels
[channel
].length
= length
;
65 uint32_t pagecount
= (length
+ 0xFFF) / 0x1000;
66 uintptr_t dmabuffer_phys
= mmAllocPhysicalMemory(MM_MEMORY_ALLOC_DMA
,
67 0, pagecount
* 0x1000);
68 channels
[channel
].dmabuffer_phys
= dmabuffer_phys
;
69 uintptr_t dmabuffer
= mmFindFreeKernelPages(MM_MAX_KERNEL_PAGE
,
70 MM_MIN_KERNEL_PAGE
, 1, pagecount
* 0x1000);
72 for (i
= 0; i
< pagecount
; i
++)
74 mmMapKernelMemory(dmabuffer_phys
+ i
* 0x1000, dmabuffer
+ i
* 0x1000,
75 MM_MAP_READ
| MM_MAP_WRITE
);
77 memset((void*)dmabuffer
, 0, length
);
78 channels
[channel
].dmabuffer
= (void*)dmabuffer
;
81 outb(dma_channel_mask
[channel
], channel
| 0x4);
83 outb(dma_data
[channel
], 0xFF);
84 outb(dma_addr
[channel
], dmabuffer_phys
& 0xFF);
85 outb(dma_addr
[channel
], (dmabuffer_phys
>> 8) & 0xFF);
86 outb(dma_page
[channel
], (dmabuffer_phys
>> 16) & 0xFF);
88 outb(dma_data
[channel
], 0xFF);
89 outb(dma_size
[channel
], length
& 0xFF);
90 outb(dma_size
[channel
], (length
>> 8) & 0xFF);
92 outb(dma_mode
[channel
], (mode
& 0xFC) + (channel
& 0x3));
94 outb(dma_channel_mask
[channel
], channel
);
98 int keCloseDMA(uint8_t channel
)
100 if (channel
>= 8) return KE_ERROR_UNKNOWN
;
102 uint32_t pagecount
= (channels
[channel
].length
+ 0xFFF) / 0x1000;
103 mmFreePhysicalMemory(channels
[channel
].dmabuffer_phys
, pagecount
* 0x1000);
105 for (i
= 0; i
< pagecount
; i
++)
107 mmMapKernelMemory(0, (uintptr_t)channels
[channel
].dmabuffer
+ i
* 0x1000, 0);
110 keUnlockSpinlock(&channels
[channel
].opened
);
114 int keReadDMA(uint8_t channel
)
116 if (channel
>= 8) return KE_ERROR_UNKNOWN
;
117 memcpy(channels
[channel
].buffer
, channels
[channel
].dmabuffer
,
118 channels
[channel
].length
);
121 int keWriteDMA(uint8_t channel
)
123 if (channel
>= 8) return KE_ERROR_UNKNOWN
;
124 memcpy(channels
[channel
].dmabuffer
, channels
[channel
].buffer
,
125 channels
[channel
].length
);