Subversion Repositories shark

Rev

Rev 3 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 pj 1
/* Project:     HARTIK 3.0 Sound Library                        */
2
/* Description: Hard Real TIme Kernel for 8086 compatible       */
3
/* Author:      Luca Abeni                                      */
4
/* Date:        5/12/1997                                       */
5
 
6
/* File:        DMA.C                                           */
7
/* Revision:    3.0                                             */
8
 
9
/*
10
   DMAC functions and structures. This module was developed for using some
11
   sound card's DMA operations, will become part of the HARTIK Kernel, for
12
   providing support to all applications that needs DMA
13
*/
14
 
15
#include <kernel/kern.h>
16
#include <drivers/dma.h>
17
#include "sbio.h"
18
 
19
#define appl2linear(x) (x)
20
 
21
/* This does not work at 16 bits!! I'm sorry */
22
/* Solution: Place them into a separate segment, perhaps it works... */
23
BYTE buff2[0xFFFF];
24
BYTE buff3[0xFFFF];
25
 
26
void dma_stop(BYTE channel)
27
{
28
    ll_out(0x0A, 0x04 | channel);
29
}
30
 
31
void dma16_stop(BYTE channel)
32
{
33
    ll_out(0xD4, 0x04 | (channel - 4));
34
}
35
 
36
void dma_reset(void)
37
{
38
    ll_out(0x0C,0x00);
39
}
40
 
41
void dma16_reset(void)
42
{
43
    ll_out(0xD8,0x00);
44
}
45
 
46
void dma_start(BYTE channel)
47
{
48
    ll_out(0x0A, channel);
49
}
50
 
51
void dma16_start(BYTE channel)
52
{
53
    ll_out(0xD4, channel- 4);
54
}
55
 
56
void dma_setmode(BYTE channel, BYTE mode)
57
{
58
    ll_out(0x0B,mode | channel);
59
}
60
 
61
void dma16_setmode(BYTE channel, BYTE mode)
62
{
63
    ll_out(0xD6,mode | (channel - 4));
64
}
65
 
66
/*
67
   Program the DMAC to transfert bytes to/from a buffer with logical
68
  address addr and lenght len using the specified DMA channel
69
*/
70
void dma_setbuff(BYTE channel, BYTE *addr, WORD len)
71
{
72
    DWORD ph_addr;
73
    WORD offset_port, page_port, len_port;
74
 
75
    switch (channel) {
76
        case 0: offset_port = 0;
77
                page_port = 0x87;
78
                len_port = 1;
79
                break;
80
        case 1: offset_port = 0x02;
81
                page_port = 0x83;
82
                len_port = 0x03;
83
                break;
84
        case 3: offset_port = 0x06;
85
                page_port = 0x82;
86
                len_port = 0x07;
87
                break;
88
        default: cprintf("dma_setbuff channel error!!!\n");
927 pj 89
                 exit(1);
2 pj 90
                 return;
91
    }
92
    ph_addr = appl2linear(addr);
93
    ll_out(offset_port, (ph_addr & 0xFF));
94
    ll_out(offset_port, (ph_addr >> 8) & 0xFF);
95
    ll_out(page_port, (ph_addr >> 16) & 0xFF);
96
    ll_out(len_port,(BYTE)(len&0xFF));
97
    ll_out(len_port,(BYTE)((len>>8)&0xFF));
98
}
99
 
100
/*
101
   Program the DMAC to transfert words to/from a buffer with logical
102
   address addr and lenght len using the specified DMA channel
103
*/
104
void dma16_setbuff(BYTE channel, BYTE *addr, WORD len)
105
{
106
    DWORD ph_addr;
107
    WORD offset_port, page_port, len_port;
108
 
109
    switch (channel) {
110
        case 5: offset_port = 0xC4;
111
                page_port = 0x8B;
112
                len_port = 0xC6;
113
                break;
114
        case 6: offset_port = 0xC8;
115
                page_port = 0x89;
116
                len_port = 0xCA;
117
                break;
118
        case 7: offset_port = 0xCC;
119
                page_port = 0x8A;
120
                len_port = 0xCE;
121
                break;
122
                /* It does not seem too much clean */
123
        default: cprintf("16 bit DMA?????\n");
927 pj 124
                 exit(1);
2 pj 125
                 return;
126
    }
127
    ph_addr = appl2linear(addr);
128
    ll_out(offset_port, (ph_addr >> 1) & 0xFF);
129
    ll_out(offset_port, (ph_addr >> 9) & 0xFF);
130
    ll_out(page_port, (ph_addr >> 16) & 0xFE);
131
    ll_out(len_port,(BYTE)((len >> 1) & 0xFF));
132
    ll_out(len_port,(BYTE)((len >> 9) & 0xFF));
133
}
134
 
135
/*
136
   Program the 8 bit DMAC to transer bytes from the buffer specified by
137
   dma_buff using double buffering
138
*/
139
void dma_out(BYTE channel, struct dma_buff *buff)
140
{
141
    DWORD len, i;
142
 
143
    buff->page = 0;
144
    len = buff->dma_bufflen -1;
145
    for(i = 0; i < buff->dma_bufflen; i++) {
146
        buff->dma_buff[i] = buff->p[i];
147
    }
148
    buff->count = buff->dma_bufflen;
149
 
150
    dma_stop(channel);
151
    dma_reset();
152
    dma_setmode(channel, 0x58);
153
    dma_setbuff(channel, buff->dma_buff, len);
154
    dma_start(channel);
155
}
156
 
157
/*
158
   Program the 8 bit DMAC to transer bytes to the buffer specified by
159
   dma_buff using double buffering
160
*/
161
void dma_in(BYTE channel, struct dma_buff *buff)
162
{
163
    DWORD len;
164
 
165
    buff->page = 0;
166
    len = buff->dma_bufflen - 1;
167
    buff->count = 0;
168
 
169
    dma_stop(channel);
170
    dma_reset();
171
    dma_setmode(channel, 0x54);
172
    dma_setbuff(channel, buff->dma_buff, len);
173
    dma_start(channel);
174
}
175
 
176
/*
177
   Program the 8 bit DMAC to transer bytes from the buffer specified by
178
   dma_buff using double buffering
179
*/
180
void dma16_out(BYTE channel, struct dma_buff *buff)
181
{
182
    DWORD len, i;
183
 
184
    buff->page = 0;
185
    len = buff->dma_bufflen - 1;
186
    for(i = 0; i < buff->dma_bufflen; i++) {
187
        buff->dma_buff[i] = buff->p[i];
188
    }
189
    buff->count = buff->dma_bufflen;
190
 
191
    dma16_stop(channel);
192
    dma16_reset();
193
    dma16_setmode(channel, 0x58);
194
    dma16_setbuff(channel, buff->dma_buff, len);
195
    dma16_start(channel);
196
}
197
 
198
/*
199
   Program the 8 bit DMAC to transer bytes to the buffer specified by
200
   dma_buff using double buffering
201
*/
202
void dma16_in(BYTE channel, struct dma_buff *buff)
203
{
204
    DWORD len;
205
 
206
    buff->page = 0;
207
    len = buff->dma_bufflen -1;
208
    buff->count = 0;
209
 
210
    dma16_stop(channel);
211
    dma16_reset();
212
    dma16_setmode(channel, 0x54);
213
    dma16_setbuff(channel, buff->dma_buff, len);
214
    dma16_start(channel);
215
}
216
 
217
/*
218
   The DMAC can use only buffers that don't cross a 64K boundary (the
219
   value (0xFFFF0000 & address) must be the same for every address in the
220
   buffer). We call this kind of buffers "aligned buffers": it can be a
221
   problem to allocate an aligned buffer, so we provide the dma_getalignbuff
222
   function
223
*/
224
 
225
/* Allocate an aligned buffer for DMA transfer */
226
void dma_getalignbuff(struct dma_buff *buff, WORD len)
227
{
228
//    BYTE *p;
229
//    DWORD phys;
230
//    BYTE done = 0;
231
 
232
    if (len > 0x8000) {
233
        cprintf("Don' t allocate too big buffers!!!!!\n");
234
/*      exc_raise(TOO_BIG_BUFFER);*/
235
    }
236
    buff->dma_bufflen = len;
237
 
238
//    while (!done)
239
//    {
240
        /* get a buffer */
241
//      p = VM_alloc(len);
242
        /* compute its phisical address */
243
//      phys = appl2linear(p);
244
        /* Is it aligned? */
245
//      if ((phys & 0x0F0000) != ((phys + len) & 0x0F0000))
246
        /* If no, try again */
247
//          done = 0;
248
//      else done = 1;
249
//    }
250
//    buff->dma_buff = p;
251
 
252
    /* NB this function returns a page aligned on a 64k boundary
253
       ... this is not what it have to be, but it works */
254
    buff->dma_buff = kern_alloc_aligned(len, MEMORY_UNDER_16M, 16, 0);
255
}
256
 
257
/*
258
   Allocate a buffer starting from an address with the rightmost 16 bits equal
259
   to 0 (it's the simpler way to obtain an aligned buffer
260
*/
261
BYTE *dma_getpage(DWORD dim)
262
{
263
    /* Get a buffer of dimension dim+64K...*/
264
    return kern_alloc_aligned(dim, MEMORY_UNDER_16M, 16, 0);
265
}
266
 
267
/*
268
   Copy a part of the user buffer in half DMA buffer (used for
269
   double buffering)
270
*/
271
int outfun(struct dma_buff *b)
272
{
273
    int i;
274
    int result = 0;
275
 
276
    /* Is this the last cycle of the DMA output operation?*/
277
    if (b->len > (b->dma_bufflen >> 1) + b->count) {
278
        /*No */
279
        for(i = 0; i < (b->dma_bufflen >> 1); i++)
280
            b->dma_buff[i+ ((b->dma_bufflen>>1) * b->page)] = b->p[b->count + i];
281
    } else {
282
        /* Yes */
283
        for(i = 0; i < (b->len - b->count); i++)
284
            b->dma_buff[i + ((b->dma_bufflen>>1) * b->page)] = b->p[b->count + i];
285
            /* return 1 to comunicate that the operation is finished */
286
        result = 1;
287
    }
288
    b->count += (b->dma_bufflen >> 1);
289
    b->page = !b->page;
290
    return result;
291
}
292
 
293
/* Copy half DMA buffer in the user buffer (used for double buffering) */
294
int infun(struct dma_buff *b)
295
{
296
    int i;
297
    int result = 0;
298
 
299
    /* Is this the last cycle of the DMA outpu operation? */
300
    if (b->len > (b->dma_bufflen >> 1) + b->count) {
301
        for(i = 0; i < (b->dma_bufflen >> 1); i++)
302
            b->p[b->count+ i] = b->dma_buff[i + ((b->dma_bufflen>>1) * b->page)];
303
    } else {
304
        for(i = 0; i < (b->len - b->count); i++)
305
            b->p[b->count+ i] = b->dma_buff[i+ ((b->dma_bufflen>>1) * b->page)];
306
            /* return 2 to comunicate that the operation is finished */
307
        result = 2;
308
    }
309
    b->count += (b->dma_bufflen >> 1);
310
    b->page = !b->page;
311
    return result;
312
}