Subversion Repositories shark

Rev

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