Subversion Repositories shark

Rev

Rev 2 | 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:        Blaster.C                                       */
7
/* Revision:    3.0                                             */
8
 
9
/* Sound Blaster 16 specific functions and structures */
10
 
11
#include <kernel/kern.h>
12
 
13
#include <drivers/dma.h>
14
#include "sbio.h"
15
#include "blaster.h"
16
#include <drivers/sound.h>
17
#include <semaphore.h>
18
 
19
struct sb_device sb_dev;
20
struct sound_buffer buff_des;
21
 
22
void sbmixer_reset(void)
23
{
24
    sbmixer_write(sb_dev.BaseAddress, MIXER_RESET, 0);
25
}
26
 
27
/* Enable or disable specified mixer inputs */
28
void sbmixer_setinput(BYTE in, BYTE onoff)
29
{
30
    BYTE inreg;
31
 
32
    inreg = sbmixer_read(sb_dev.BaseAddress, MIXER_INCTRLEFT);
33
    if (onoff == ENABLE)
34
        inreg = inreg | in;
35
    else inreg = inreg & (!in);
36
    sbmixer_write(sb_dev.BaseAddress, MIXER_INCTRLEFT, inreg);
37
    inreg = sbmixer_read(sb_dev.BaseAddress, MIXER_INCTRRIGHT);
38
    if (onoff == ENABLE)
39
        inreg = inreg | in;
40
    else inreg = inreg & (!in);
41
    sbmixer_write(sb_dev.BaseAddress, MIXER_INCTRRIGHT, inreg);
42
}
43
 
44
/* Enable or disable specified mixer outputs */
45
void sbmixer_setoutput(BYTE in, BYTE onoff)
46
{
47
    BYTE inreg;
48
 
49
    inreg = sbmixer_read(sb_dev.BaseAddress, MIXER_OUTCTR);
50
    if (onoff == ENABLE)
51
        inreg = inreg | in;
52
    else inreg = inreg & (~in);
53
    sbmixer_write(sb_dev.BaseAddress, MIXER_OUTCTR, inreg);
54
}
55
 
56
/* Set the output level */
57
void sbmixer_setmiclev(BYTE level)
58
{
59
    BYTE levreg;
60
 
61
    levreg = sbmixer_read(sb_dev.BaseAddress, MIXER_MICLEV);
62
    levreg = (levreg & 0x07) | (level << 3);
63
    sbmixer_write(sb_dev.BaseAddress, MIXER_MICLEV, levreg);
64
}
65
 
66
/* Set the mixer input level */
67
void sbmixer_setingainlev(BYTE level)
68
{
69
    BYTE gainreg;
70
 
71
    gainreg = sbmixer_read(sb_dev.BaseAddress, MIXER_IGCRIGHT);
72
    gainreg = (gainreg & 0x3F) | (level << 6);
73
    sbmixer_write(sb_dev.BaseAddress, MIXER_IGCRIGHT, gainreg);
74
    gainreg = sbmixer_read(sb_dev.BaseAddress, MIXER_IGCLEFT);
75
    gainreg = (gainreg & 0x3F) | (level << 6);
76
    sbmixer_write(sb_dev.BaseAddress, MIXER_IGCLEFT, gainreg);
77
}
78
 
79
/* Enable or disable the mixer input Automatic Gain Control */
80
void sbmixer_setAGC(BYTE onoff)
81
{
82
    BYTE reg;
83
 
84
    reg = sbmixer_read(sb_dev.BaseAddress, MIXER_AGC);
85
    if (onoff == ENABLE)
86
        reg = reg & 0xFE;
87
    else reg = reg | 0x01;
88
    sbmixer_write(sb_dev.BaseAddress, MIXER_AGC, reg);
89
}
90
 
91
int sb_init(void)
92
{
93
    BYTE cfgreg;
94
 
95
    /* Is there a SB16 in the system? */
96
    if((sb_dev.BaseAddress = sb_probe()) == 0)
97
      return ENODEV;
98
 
99
    /* Yes: get the DSP version and the used interrupt and DMA Channels */
100
    sbdsp_write(sb_dev.BaseAddress, DSPCMD_GETVER);
101
    sb_dev.DSPVersionM = sbdsp_read(sb_dev.BaseAddress);
102
    sb_dev.DSPVersionm = sbdsp_read(sb_dev.BaseAddress);
103
    cfgreg = sbmixer_read(sb_dev.BaseAddress, MIXER_IRQREG);
104
    if (cfgreg & 1)
105
        sb_dev.IntLine = 2;
106
    if (cfgreg & 2)
107
        sb_dev.IntLine = 5;
108
    if (cfgreg & 4)
109
        sb_dev.IntLine = 7;
110
    if (cfgreg & 8)
111
        sb_dev.IntLine = 10;
112
 
113
    // force irq line if you use a SB PNP!!!    
114
    // sb_dev.IntLine = 9;
115
 
116
    cfgreg = sbmixer_read(sb_dev.BaseAddress, MIXER_DMAREG);
117
    if (cfgreg & 1)
118
        sb_dev.DMA8Channel= 0;
119
    if (cfgreg & 2)
120
        sb_dev.DMA8Channel = 1;
121
    if (cfgreg & 8)
122
        sb_dev.DMA8Channel = 3;
123
    if (cfgreg & 0x20)
124
        sb_dev.DMA16Channel = 5;
125
    if (cfgreg & 0x40)
126
        sb_dev.DMA16Channel = 6;
127
    if (cfgreg & 0x80)
128
        sb_dev.DMA16Channel = 7;
129
 
130
    return 0;
131
}
132
 
133
/* Show the card informations */
134
void sb_show(void)
135
{
136
    cprintf("        BaseAddress: %x\n", (unsigned int)sb_dev.BaseAddress);
137
    cprintf("        Interrupt Line: %d\n", sb_dev.IntLine);
138
    cprintf("        DSP Version: %d.%d\n", sb_dev.DSPVersionM, sb_dev.DSPVersionm);
139
    cprintf("        8 bit DMA channel: %d\n", sb_dev.DMA8Channel);
140
    cprintf("        16 bit DMA channel: %d\n", sb_dev.DMA16Channel);
141
}
142
 
143
void sb_spkon (void)
144
{
145
    sbdsp_write(sb_dev.BaseAddress, DSPCMD_SPKON);
146
}
147
 
148
void sb_spkoff (void)
149
{
150
    sbdsp_write(sb_dev.BaseAddress, DSPCMD_SPKOFF);
151
}
152
 
153
/* Set the DMA sampling/playing rate */
154
void sb_setrate (int sps, BYTE i_o)
155
{
156
    BYTE cmd;
157
 
158
    if (i_o == IN) cmd = DSPCMD_SETINRATE;
159
    else cmd = DSPCMD_SETOUTRATE;
160
    sbdsp_write(sb_dev.BaseAddress, cmd);
161
    /* MSB...*/
162
    sbdsp_write(sb_dev.BaseAddress, (sps >> 8) & 0xFF);
163
    /*...and then LSB */
164
    sbdsp_write(sb_dev.BaseAddress, sps & 0xFF);
165
}
166
 
167
/* Start an 8 bit sampling/playing operation */
168
void sb_dmaop(BYTE i_o)
169
{
170
    DWORD len;
171
    BYTE cmd;
172
    BYTE *buff;
173
 
174
    buff = buff_des.sound_dma->p;
175
    len = buff_des.sound_dma->len;
176
    cmd = DSPCMD_8BITIO;
177
 
178
    /* Stop any previous operation and reset the DMAC */
179
    dma_stop(sb_dev.DMA8Channel);
180
    dma_reset();
181
    /* Prepare the DMAC for the operation */
182
    if (i_o == OUT) {
183
        cmd |= SBIO_OUT;
184
        dma_setmode(sb_dev.DMA8Channel, 0x48);
185
    } else {
186
        cmd |= SBIO_IN;
187
        dma_setmode(sb_dev.DMA8Channel, 0x44);
188
    }
189
    dma_setbuff(sb_dev.DMA8Channel, buff, len);
190
    dma_start(sb_dev.DMA8Channel);
191
    /*...and start it!!! */
192
    sbdsp_write(sb_dev.BaseAddress, cmd);
193
    sbdsp_write(sb_dev.BaseAddress, IOMODE_UNSIGNED | IOMODE_MONO);
194
    /* LSB...*/
195
    sbdsp_write(sb_dev.BaseAddress, (BYTE)(len & 0xFF));
196
    /*...and then MSB */
197
    sbdsp_write(sb_dev.BaseAddress, (BYTE)((len >> 8) & 0xFF));
198
}
199
 
200
/* Start a 16 bit sampling/playing operation */
201
void sb_dma16op(BYTE i_o)
202
{
203
    DWORD len;
204
    BYTE cmd;
205
    BYTE *buff;
206
 
207
    buff = buff_des.sound_dma->p;
208
    len = buff_des.sound_dma->len;
209
    cmd = DSPCMD_16BITIO;
210
 
211
    /* Stop any previous operation and reset the DMAC */
212
    dma16_stop(sb_dev.DMA16Channel);
213
    dma16_reset();
214
    if (i_o == OUT) {
215
        cmd |= SBIO_OUT;
216
        dma16_setmode(sb_dev.DMA16Channel, 0x48);
217
    } else {
218
        cmd |= SBIO_IN;
219
        dma16_setmode(sb_dev.DMA16Channel, 0x44);
220
    }
221
    dma16_setbuff(sb_dev.DMA16Channel, buff, len);
222
    dma16_start(sb_dev.DMA16Channel);
223
    /*...and start it!!! */
224
    sbdsp_write(sb_dev.BaseAddress, cmd);
225
    sbdsp_write(sb_dev.BaseAddress, IOMODE_SIGNED | IOMODE_MONO);
226
    /* LSB...*/
227
    sbdsp_write(sb_dev.BaseAddress, (BYTE)(len & 0xFF));
228
    /*...and then MSB */
229
    sbdsp_write(sb_dev.BaseAddress, (BYTE)((len >> 8) & 0xFF));
230
}
231
 
232
/* Start an 8 bit sampling/playing operation using double buffer */
233
void sb_dmabuffop(BYTE i_o)
234
{
235
    DWORD len;
236
    BYTE cmd;
237
    struct dma_buff *buff;
238
 
239
    buff = buff_des.sound_dma;
240
    cmd = DSPCMD_8BITIO | SBIO_AUTOINIT;
241
    len = buff->len;
242
    if (i_o == OUT) {
243
        cmd |= SBIO_OUT;
244
        dma_out(sb_dev.DMA8Channel, buff);
245
    } else {
246
        cmd |= SBIO_IN;
247
        dma_in(sb_dev.DMA8Channel, buff);
248
    }
249
    sbdsp_write(sb_dev.BaseAddress, cmd);
250
    sbdsp_write(sb_dev.BaseAddress, IOMODE_UNSIGNED | IOMODE_MONO);
251
    sbdsp_write(sb_dev.BaseAddress, (BYTE)(((buff->dma_bufflen >> 1) - 1) & 0xFF));
252
    sbdsp_write(sb_dev.BaseAddress, (BYTE)((((buff->dma_bufflen >> 1) - 1) >> 8) & 0xFF));
253
}
254
 
255
/* Start a 16 bit sampling/playing operation using double buffer */
256
void sb_dma16buffop(BYTE i_o)
257
{
258
    DWORD len;
259
    BYTE cmd;
260
    struct dma_buff *buff;
261
 
262
    buff = buff_des.sound_dma;
263
    cmd = DSPCMD_16BITIO | SBIO_AUTOINIT;
264
    len = buff->len;
265
    if (i_o == OUT) {
266
        cmd |= SBIO_OUT;
267
        dma16_out(sb_dev.DMA16Channel, buff);
268
    } else {
269
        cmd |= SBIO_IN;
270
        dma16_in(sb_dev.DMA16Channel, buff);
271
    }
272
    sbdsp_write(sb_dev.BaseAddress, cmd);
273
    sbdsp_write(sb_dev.BaseAddress, IOMODE_SIGNED | IOMODE_MONO);
274
    sbdsp_write(sb_dev.BaseAddress, (BYTE)(((buff->dma_bufflen >> 2) - 1) & 0xFF));
275
    sbdsp_write(sb_dev.BaseAddress, (BYTE)((((buff->dma_bufflen >> 2) - 1) >> 8) & 0xFF));
276
}
277
 
278
void sb_stopdsp(BYTE bit)
279
{
280
    if (bit == 8)
281
        sbdsp_write(sb_dev.BaseAddress, DSPCMD_EXIT8);
282
    else if (bit == 16)
283
        sbdsp_write(sb_dev.BaseAddress, DSPCMD_EXIT16);
284
    else cprintf("How many bits?\n");
285
}
286
 
287
/* Sound Blaster 16 interrupt's Fast Handler */
288
void sb_handler(int n)
289
{
290
    switch(sbmixer_read(sb_dev.BaseAddress, MIXER_INTSTATUS) & 3) {
291
        case 1: ll_in(sb_dev.BaseAddress + ACK8);
292
                break;
293
        case 2: ll_in(sb_dev.BaseAddress + ACK16);
294
                break;
295
        default: cprintf("Unknown int: %x\n", sbmixer_read(sb_dev.BaseAddress, 0x82));
296
    }
297
}
298
 
299
/*
300
   This process is activated when the sound card generates an interrupt:
301
   it calls the function to copy data from/to the sound buffer (this function
302
   can be the double buffering-function or the user's self-buffering function
303
*/
304
TASK sb_proc(void)
305
{
306
    for(;;) {
307
        /* call the copy function */
308
        switch(buff_des.fun(buff_des.sound_dma)) {
309
            /* the operation will finish with the next interrupt */
310
            case 1: buff_des.fun = dummyfun1;
311
                    break;
312
            /* operation finished */
313
            case 2: dummyfun2(buff_des.sound_dma);
314
                    buff_des.fun = dummyfun2;
315
                    break;
316
            default: break;
317
        }
318
        task_endcycle();
319
    }
320
    return 0;
321
}
322
 
323
/* PIO mode sampling process */
324
TASK proc_sample()
325
{
326
    DWORD i;
327
 
328
    sbdsp_reset(sb_dev.BaseAddress);
329
    for(i = 0; i < buff_des.sound_dma->len; i++) {
330
        sbdsp_write(sb_dev.BaseAddress, DSPCMD_DIRECTIN);
331
        buff_des.sound_dma->p[i] = sbdsp_read(sb_dev.BaseAddress);
332
        task_endcycle();
333
    }
334
    /* Operation finished: if it was blocking signal */
335
    if (buff_des.synch) sem_post(&buff_des.synchr);
336
    //task_abort();
337
    return 0;
338
}
339
 
340
/* PIO mode playing process */
341
TASK proc_play()
342
{
343
    DWORD i;
344
 
345
    sbdsp_reset(sb_dev.BaseAddress);
346
    for(i = 0; i < buff_des.sound_dma->len; i++) {
347
        sbdsp_write(sb_dev.BaseAddress, DSPCMD_DIRECTOUT);
348
        sbdsp_write(sb_dev.BaseAddress, buff_des.sound_dma->p[i]);
349
        task_endcycle();
350
    }
351
    /* Operation finished: if it was blocking signal */
352
    if (buff_des.synch) sem_post(&buff_des.synchr);
353
    //task_abort();
354
    return 0;
355
}