- Implemented execp*.
[planlOS.git] / system / kernel / ke / dma.c
blob2a1583928b190c8ad2a27c0f8be8d03f60dc4826
1 /*
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.
22 #include "ke/dma.h"
23 #include "ke/errors.h"
24 #include "ke/spinlock.h"
25 #include "ke/ports.h"
26 #include "mm/memory.h"
27 #include <string.h>
29 typedef struct
31 uint8_t channel;
32 uint8_t mode;
33 void *buffer;
34 uint32_t length;
35 uintptr_t dmabuffer_phys;
36 void *dmabuffer;
37 KeSpinlock opened;
38 } KeDMAChannel;
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)
56 // Open channel
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;
64 // Allocate buffer
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);
71 uint32_t i;
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;
79 // Setup DMA
80 // Mask channel
81 outb(dma_channel_mask[channel], channel | 0x4);
82 // Set address
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);
87 // Set size
88 outb(dma_data[channel], 0xFF);
89 outb(dma_size[channel], length & 0xFF);
90 outb(dma_size[channel], (length >> 8) & 0xFF);
91 // Set mode
92 outb(dma_mode[channel], (mode & 0xFC) + (channel & 0x3));
93 // Unmask channel
94 outb(dma_channel_mask[channel], channel);
96 return 0;
98 int keCloseDMA(uint8_t channel)
100 if (channel >= 8) return KE_ERROR_UNKNOWN;
101 // Free buffer
102 uint32_t pagecount = (channels[channel].length + 0xFFF) / 0x1000;
103 mmFreePhysicalMemory(channels[channel].dmabuffer_phys, pagecount * 0x1000);
104 uint32_t i;
105 for (i = 0; i < pagecount; i++)
107 mmMapKernelMemory(0, (uintptr_t)channels[channel].dmabuffer + i * 0x1000, 0);
109 // Close channel
110 keUnlockSpinlock(&channels[channel].opened);
111 return 0;
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);
119 return 0;
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);
126 return 0;