00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <const.h>
00011
00012 #include <arch/i386.h>
00013 #include <arch/mem.h>
00014 #include <arch/paging.h>
00015
00016 #include <kernel/kernel_map.h>
00017 #include <kernel/kmalloc.h>
00018 #include <kernel/task.h>
00019
00020 #include <kernel/dma.h>
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 static dma_channel_t dmainfo[] =
00033 {
00034 { 0x87, 0x00, 0x01 },
00035 { 0x83, 0x02, 0x03 },
00036 { 0x81, 0x04, 0x05 },
00037 { 0x82, 0x06, 0x07 }
00038 };
00039
00040
00041
00042
00043
00044
00045
00046
00047 void dma_xfer(unsigned channel, addr_t physaddr, size_t length, bool read)
00048 {
00049 int page, offset;
00050
00051 if (channel > 3) return;
00052
00053
00054 page = physaddr >> 16;
00055 offset = physaddr & 0xFFFF;
00056 length -= 1;
00057
00058 disable();
00059
00060
00061 outportb(0x0A, channel | 0x04);
00062
00063
00064 outportb(0x0C, 0x00);
00065
00066
00067 outportb(0x0B, (read ? 0x48 : 0x44) + channel);
00068
00069
00070 outportb(dmainfo[channel].page, page);
00071
00072
00073 outportb(dmainfo[channel].offset, offset & 0xFF);
00074 outportb(dmainfo[channel].offset, offset >> 8);
00075
00076
00077 outportb(dmainfo[channel].length, length & 0xFF);
00078 outportb(dmainfo[channel].length, length >> 8);
00079
00080
00081 outportb(0x0A, channel);
00082
00083 enable();
00084 }
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097 #define DMA_MEMORY_DIM (DMA_MEMORY_END-DMA_MEMORY_START)
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108 byte *dma_free_frames;
00109
00110
00111 #define DMA_FREE_FRAME 0
00112
00113 #define DMA_BUSY_FRAME 1
00114
00115
00116 void dma_alloc_init()
00117 {
00118 uint32_t i;
00119 extern dword *K_VIR_END;
00120
00121
00122 dma_free_frames = kmalloc(DMA_MEMORY_DIM/PAGE_SIZE);
00123 memset(dma_free_frames, DMA_FREE_FRAME, DMA_MEMORY_DIM/PAGE_SIZE);
00124
00125
00126 for (i=0; i<=(uint32_t)K_VIR_END-K_VIR_START; i+=PAGE_SIZE)
00127 dma_free_frames[K_PHYS_ADDR+i] = DMA_BUSY_FRAME;
00128 }
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141 void *dma_phys_alloc(size_t len)
00142 {
00143 dword i, j, ret;
00144 char flag=0;
00145
00146
00147 if (!len) return(NULL);
00148
00149
00150 len = PAGE_ALIGN_UP(len);
00151
00152 sched_enter_critical_region();
00153
00154
00155 for(i=0; i<(DMA_MEMORY_DIM/PAGE_SIZE); i++)
00156 {
00157 if (dma_free_frames[i] == DMA_FREE_FRAME)
00158 {
00159
00160
00161
00162 for(j=1, flag=0; j<len/PAGE_SIZE; j++)
00163 {
00164 if (dma_free_frames[i+j] == DMA_BUSY_FRAME)
00165 {
00166
00167 flag = 1;
00168 break;
00169 }
00170 }
00171 if (flag == 1)
00172 {
00173
00174
00175 i += j;
00176 }
00177 else
00178 {
00179
00180
00181 for(j=0; j<len/PAGE_SIZE; j++)
00182 dma_free_frames[i+j] = DMA_BUSY_FRAME;
00183 break;
00184 }
00185 }
00186 }
00187
00188 if (flag == 0)
00189
00190 ret = (i * PAGE_SIZE + DMA_MEMORY_START);
00191 else
00192
00193 ret = NULL;
00194
00195 sched_leave_critical_region();
00196 return((void *)ret);
00197 }
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210 bool dma_phys_free(size_t dma_start, size_t len)
00211 {
00212 int i;
00213
00214 if (!len) return(FALSE);
00215
00216
00217 len = PAGE_ALIGN_UP(len);
00218
00219 if (
00220 (dma_start >= DMA_MEMORY_START) && (dma_start < DMA_MEMORY_END) &&
00221 ((dma_start + len) < DMA_MEMORY_END)
00222 )
00223 {
00224 sched_enter_critical_region();
00225
00226
00227 for(i=(dma_start-DMA_MEMORY_START)/PAGE_SIZE; i<DMA_MEMORY_DIM/PAGE_SIZE; i++)
00228 dma_free_frames[i] = DMA_FREE_FRAME;
00229
00230 sched_leave_critical_region();
00231
00232 return(TRUE);
00233 }
00234 else
00235
00236 return(FALSE);
00237 }
00238
00239