Subversion Repositories shark

Rev

Rev 1007 | 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:        Sound.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
/* added by Paolo */
27
#define SOUND_WCET 200
28
 
29
/* Sound generic interface */
30
#include <kernel/kern.h>
31
 
32
#include "blaster.h"
33
#include <drivers/sound.h>
34
#include <drivers/dma.h>
35
 
36
//extern struct proc_des proc_table[MAX_PROC];
37
 
38
extern struct sb_device sb_dev;
39
extern TASK proc_play();
40
extern TASK proc_sample();
41
extern TASK sb_proc();
42
extern void sb_handler(int n);
43
extern struct sound_buffer buff_des;
44
struct rawfuncs f_des;
45
struct dma_buff dma_des;
46
 
47
/*int sound_exc(int err)
48
{
49
    switch (err) {
50
        case SOUND_CARD_NOT_FOUND:
51
            cprintf("SOUND PANIC --> Sound card not found.\n");
52
            return 0;
53
        case SOUND_RAWFUN_NOT_SET:
54
            cprintf("Self-buffering OP error --> User function not set.\n");
55
            return 0;
56
        case SOUND_TICK_TOO_LARGE:
57
            cprintf("PIO mode OP error --> sys_tick too large.\n");
58
            return 0;
59
        case SOUND_ASYNCH_WAIT:
60
            cprintf("Asynchronous OP error --> Wait on asynch operation.\n");
61
            return 1;
62
        default :
63
            return 1;
64
    }
65
} */
66
 
67
/* Set the user's functions for self buffering */
68
void sound_setfun(int (*infun)(void *rawbuff), int (*outfun)(void *rawbuff))
69
{
70
    /* Should be NULL here! Luca: used -1 instead NULL */
71
    if (infun != NULL) {
72
        f_des.infun = infun;
73
        f_des.infunpresent = 1;
74
    }
75
    if(outfun != NULL) {
76
        f_des.outfun = outfun;
77
        f_des.outfunpresent = 1;
78
    }
79
}
80
 
81
/*
82
   This function is called by the sound card driver function when the card
83
   generate an interrupt during a self buffering input operation. The user's
84
   self buffering function is called by this function
85
*/
86
int selfinfun(struct dma_buff *b)
87
{
88
    int res;
89
 
90
    res = f_des.infun(&b->dma_buff[(b->dma_bufflen >> 1) * b->page]);
91
    b->page = !b->page;
92
    return res;
93
}
94
 
95
/*
96
   This function is called by the sound card driver function when the card
97
   generate an interrupt during a self buffering output operation. The user's
98
   self buffering function is called by this function
99
*/
100
int selfoutfun(struct dma_buff *b)
101
{
102
    int res;
103
 
104
    res = f_des.outfun(&b->dma_buff[(b->dma_bufflen >> 1) * b->page]);
105
    b->page = !b->page;
106
    return res;
107
}
108
 
109
/*
110
   Play a sample: this function calls the adeguate low-level playing function
111
   with the correct parameters
112
 
113
   the task model in the last parameter is used for the sb_player task.
114
   it must be a periodic task with a correct period. if not specified (NULL),
115
   a soft task is used instead.
116
 
117
   it returns 0 if all ok,
118
     EINVAL if the outfun isn't specified
119
     ESRCH if the sb_player can not be created
120
*/
121
int sound_play(BYTE *buff, DWORD sps, DWORD len, BYTE t, TASK_MODEL *m)
122
{
123
    double rate;
124
    PID p_pl;
125
//    WORD s1, p;
126
 
127
    /* Self Buffering?*/
128
    if (t & MYFUN) {
129
        /*Yes */
130
        if (f_des.outfunpresent != 0) {
131
            buff_des.fun = selfoutfun;
132
        }
133
        else
134
            return EINVAL;
135
    }
136
    else {
137
        /* No: set the standard double-buffering output function (module dma.c) */
138
        buff_des.fun = outfun;
139
    }
140
    /* set the operation parameters...*/
141
    buff_des.synch = !(t & SYNCH);
142
    dma_des.len = len;
143
    dma_des.p = buff;
144
    if (t & DMA_OP) {
145
        /* DMA op */
146
        sb_setrate(sps, OUT);
147
        /*
148
        if (t & DYNBUFF) {
149
            s1 = (sps / 1000) * ((t & PCM16) ? 2 : 1);
150
            p = ((dma_des.dma_bufflen >> 1) * 1000 ) / (sound_tick * s1);
151
            if(p < 1) {
152
                sb_dev.pwarning = 1;
153
                p = 1;
154
            } else sb_dev.pwarning = 0;
155
            / * Adjust the driver task's minimum interarrival time */ /*
156
            kern_cli();
157
            proc_table[p_sb].period = p;
158
            proc_table[p_sb].drel = p;
159
            kern_sti();
160
            sb_dev.period = p;
161
        } */
162
        if (!(t & NOBUFF)) {
163
            if (t & PCM16) sb_dma16buffop(OUT);
164
            else sb_dmabuffop(OUT);
165
        } else {
166
            /* Double buffering operation */
167
            buff_des.fun = dummyfun2;
168
            if (t & PCM16) sb_dma16op(OUT);
169
            else sb_dmaop(OUT);
170
        }
171
    } else {
172
        /* Non DMA op: create the playing process */
173
        SOFT_TASK_MODEL m_soft;
174
        if (!m) {
175
          rate = (999999 / sps) + 1;
176
          soft_task_default_model(m_soft);
177
          soft_task_def_system(m_soft);
178
          soft_task_def_nokill(m_soft);
179
          soft_task_def_period(m_soft,rate);
180
          soft_task_def_met(m_soft,rate);
181
          soft_task_def_wcet(m_soft,SOUND_WCET);
182
          m = (TASK_MODEL *)&m_soft;
183
        }
184
        p_pl = task_create("sb_Player",proc_play, &m, NULL);
185
        if (p_pl == NIL) {
186
            cprintf("Sound.c: Cannot create sb_Player\n");
927 pj 187
            exit(1);
2 pj 188
            return ESRCH;
189
        }
190
        task_activate(p_pl);
191
    }
192
 
193
    return 0;
194
}
195
 
196
/*
197
   Sample: this function calls the adeguate low-level sampling function
198
   with the correct parameters. It is similar to sound_play (see it for the
199
   comments
200
 
201
   the task model in the last parameter is used for the sb_player task.
202
   it must be a periodic task with a correct period. if not specified (NULL),
203
   a soft task is used instead.
204
 
205
   it returns 0 if all ok,
206
     EINVAL if the outfun isn't specified
207
     ESRCH if the sb_player can not be created
208
*/
209
int sound_sample(BYTE *buff, DWORD sps, DWORD len, BYTE t, TASK_MODEL *m)
210
{
211
    double rate;
212
    PID p_sample;
213
//    WORD s1, p;
214
//    MODEL m = BASE_MODEL;
215
 
216
    if (t & MYFUN) {
217
        if (f_des.infunpresent != 0) {
218
            buff_des.fun = selfinfun;
219
        }
220
        else
221
            return EINVAL;
222
    }
223
    else
224
        buff_des.fun = infun;
225
 
226
    buff_des.synch = !(t & SYNCH);
227
    dma_des.len = len;
228
    dma_des.p = buff;
229
    if (t & DMA_OP) {
230
        sb_setrate(sps, IN);
231
        /*
232
        if (t & DYNBUFF) {
233
            p_sb = task_pid("sb_EndDMA");
234
            s1 = (sps / 100) * ((t & PCM16) ? 2 : 1);
235
            p = ((dma_des.dma_bufflen >> 1) * 1000 ) / (sound_tick * s1);
236
            if(p < 1) {
237
                sb_dev.pwarning = 1;
238
                p = 1;
239
            } else sb_dev.pwarning = 0;
240
            kern_cli();
241
            proc_table[p_sb].period = p;
242
            proc_table[p_sb].drel = p;
243
            kern_sti();
244
            sb_dev.period = p;
245
        } */
246
        if (!(t & NOBUFF)) {
247
            if (t & PCM16) sb_dma16buffop(IN);
248
            else sb_dmabuffop(IN);
249
        } else {
250
            buff_des.fun = dummyfun2;
251
            if (t & PCM16) sb_dma16op(IN);
252
            else sb_dmaop(IN);
253
        }
254
    } else {
255
        /* Non DMA op: create the playing process */
256
        SOFT_TASK_MODEL m_soft;
257
        if (!m) {
258
          rate = (999999 / sps) + 1;
259
          soft_task_default_model(m_soft);
260
          soft_task_def_system(m_soft);
261
          soft_task_def_nokill(m_soft);
262
          soft_task_def_period(m_soft,rate);
263
          soft_task_def_met(m_soft,rate);
264
          soft_task_def_wcet(m_soft,SOUND_WCET);
265
          m = (TASK_MODEL *)&m_soft;
266
        }
267
        p_sample = task_create("sb_Sampler",proc_sample, &m, NULL);
268
        if (p_sample == NIL) {
269
            cprintf("Sound.c: Cannot create sb_Sampler\n");
927 pj 270
            exit(1);
2 pj 271
            return ESRCH;
272
        }
273
        task_activate(p_sample);
274
    }
275
    return 0;
276
}
277
 
278
/*
279
   Wait for the end of a synchronous sound op: it is implemented with a
280
   simple semaphore
281
   It returns  0 if all ok,
282
              -1 if no sinchronous operation was called before
283
*/
284
int sound_wait(void)
285
{
286
    if (buff_des.synch) {
287
        sem_wait(&buff_des.synchr);
288
        buff_des.synch = 0;
289
        return 0;
290
    }
291
    else
292
      return -1;
293
}
294
 
295
 
296
/* returns 0 if all ok,
297
   ENOSPC if a problem occurs when creating the semaphores structures
298
   ESRCH if the Enddma task cn not be created
299
*/
300
int sound_init(WORD rawbuffsize, TASK_MODEL *m)
301
{
302
    PID p_sb;
303
    int period;
304
    SOFT_TASK_MODEL m_soft;
305
 
306
    /* Semaphore for synchronous ops */
307
    if (sem_init(&buff_des.synchr,0,0))
308
      return ENOSPC;
309
 
310
    /* Init the card */
311
    sb_init();
312
    sbmixer_reset();
313
    sbmixer_setinput(0x01, ENABLE);
314
    sbmixer_setoutput(0x01, DISABLE);
315
    sbmixer_setmiclev(0x1F);
316
    sbmixer_setAGC(ENABLE);
317
    sbmixer_setingainlev(0);
318
 
319
    f_des.infun = 0;
320
    f_des.infunpresent = 0;
321
    f_des.outfun = 0;
322
    f_des.outfunpresent = 0;
323
    /* init the buffers for DMA ops */
324
    dma_getalignbuff(&dma_des, rawbuffsize);
325
    buff_des.sound_dma = &dma_des;
326
 
327
    if (!m) {
328
      period = (rawbuffsize * 1000000) / 48000;
329
      kern_printf("period=%d\n",period);
330
      soft_task_default_model(m_soft);
331
      soft_task_def_system(m_soft);
332
      soft_task_def_nokill(m_soft);
333
      soft_task_def_period(m_soft,period);
334
      soft_task_def_met(m_soft,SOUND_WCET);
335
      soft_task_def_wcet(m_soft,SOUND_WCET);
336
      soft_task_def_aperiodic(m_soft);
337
      m = (TASK_MODEL *)&m_soft;
338
    }
339
 
340
    /* create the driver process and set it and the Fast Handler */
341
    p_sb = task_create("sb_EndDMA", sb_proc, m, NULL);
342
    if (p_sb == NIL) {
343
        cprintf("Sound.c: Cannot create sb_EndDMA\n");
344
        cprintf("errno=%d\n",errno);
927 pj 345
        exit(1);
2 pj 346
        return ESRCH;
347
    }
348
    //sb_dev.period = period;
1007 mauro 349
    handler_set(sb_dev.IntLine, sb_handler, FALSE, p_sb, NULL);
2 pj 350
 
351
    return 0;
352
}
353
 
354
/* Obvious... */
355
void sound_info(void)
356
{
357
    cprintf("Hartik Sound lib [V 3.2]:\n");
358
    cprintf("Sound Blaster 16 or clone found:\n");
359
    sb_show();
360
}
361
 
362
/*
363
   This function is called by the driver process on the last transfert of an
364
   operation
365
*/
366
int dummyfun1(struct dma_buff *d)
367
{
368
    buff_des.fun = dummyfun2;
369
    return 0;
370
}
371
 
372
/*
373
   This function is called by the driver process when the next transfert
374
   will be the last of the current operation
375
*/
376
int dummyfun2(struct dma_buff *d)
377
{
378
    if (buff_des.synch) sem_post(&buff_des.synchr);
379
    sb_stopdsp(8);
380
    sb_stopdsp(16);
381
    dma_stop(sb_dev.DMA8Channel);
382
    dma16_stop(sb_dev.DMA16Channel);
383
    return 0;
384
}
385
 
386
/* Obvious... */
387
void sound_stop(void)
388
{
389
    if (!buff_des.synch) {
390
        sb_stopdsp(8);
391
        sb_stopdsp(16);
392
        dma_stop(sb_dev.DMA8Channel);
393
        dma16_stop(sb_dev.DMA16Channel);
394
    }
395
}