Subversion Repositories shark

Rev

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