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