Rev 3 |
Go to most recent revision |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/* Project: HARTIK 3.0 Sound Library */
/* Description: Hard Real TIme Kernel for 8086 compatible */
/* Author: Luca Abeni */
/* Date: 5/12/1997 */
/* File: Sound.C */
/* Revision: 3.0 */
/* added by Paolo */
#define SOUND_WCET 200
/* Sound generic interface */
#include <kernel/kern.h>
#include "blaster.h"
#include <drivers/sound.h>
#include <drivers/dma.h>
//extern struct proc_des proc_table[MAX_PROC];
extern struct sb_device sb_dev;
extern TASK proc_play();
extern TASK proc_sample();
extern TASK sb_proc();
extern void sb_handler(int n);
extern struct sound_buffer buff_des;
struct rawfuncs f_des;
struct dma_buff dma_des;
/*int sound_exc(int err)
{
switch (err) {
case SOUND_CARD_NOT_FOUND:
cprintf("SOUND PANIC --> Sound card not found.\n");
return 0;
case SOUND_RAWFUN_NOT_SET:
cprintf("Self-buffering OP error --> User function not set.\n");
return 0;
case SOUND_TICK_TOO_LARGE:
cprintf("PIO mode OP error --> sys_tick too large.\n");
return 0;
case SOUND_ASYNCH_WAIT:
cprintf("Asynchronous OP error --> Wait on asynch operation.\n");
return 1;
default :
return 1;
}
} */
/* Set the user's functions for self buffering */
void sound_setfun(int (*infun)(void *rawbuff), int (*outfun)(void *rawbuff))
{
/* Should be NULL here! Luca: used -1 instead NULL */
if (infun != NULL) {
f_des.infun = infun;
f_des.infunpresent = 1;
}
if(outfun != NULL) {
f_des.outfun = outfun;
f_des.outfunpresent = 1;
}
}
/*
This function is called by the sound card driver function when the card
generate an interrupt during a self buffering input operation. The user's
self buffering function is called by this function
*/
int selfinfun(struct dma_buff *b)
{
int res;
res = f_des.infun(&b->dma_buff[(b->dma_bufflen >> 1) * b->page]);
b->page = !b->page;
return res;
}
/*
This function is called by the sound card driver function when the card
generate an interrupt during a self buffering output operation. The user's
self buffering function is called by this function
*/
int selfoutfun(struct dma_buff *b)
{
int res;
res = f_des.outfun(&b->dma_buff[(b->dma_bufflen >> 1) * b->page]);
b->page = !b->page;
return res;
}
/*
Play a sample: this function calls the adeguate low-level playing function
with the correct parameters
the task model in the last parameter is used for the sb_player task.
it must be a periodic task with a correct period. if not specified (NULL),
a soft task is used instead.
it returns 0 if all ok,
EINVAL if the outfun isn't specified
ESRCH if the sb_player can not be created
*/
int sound_play(BYTE *buff, DWORD sps, DWORD len, BYTE t, TASK_MODEL *m)
{
double rate;
PID p_pl;
// WORD s1, p;
/* Self Buffering?*/
if (t & MYFUN) {
/*Yes */
if (f_des.outfunpresent != 0) {
buff_des.fun = selfoutfun;
}
else
return EINVAL;
}
else {
/* No: set the standard double-buffering output function (module dma.c) */
buff_des.fun = outfun;
}
/* set the operation parameters...*/
buff_des.synch = !(t & SYNCH);
dma_des.len = len;
dma_des.p = buff;
if (t & DMA_OP) {
/* DMA op */
sb_setrate(sps, OUT);
/*
if (t & DYNBUFF) {
s1 = (sps / 1000) * ((t & PCM16) ? 2 : 1);
p = ((dma_des.dma_bufflen >> 1) * 1000 ) / (sound_tick * s1);
if(p < 1) {
sb_dev.pwarning = 1;
p = 1;
} else sb_dev.pwarning = 0;
/ * Adjust the driver task's minimum interarrival time */ /*
kern_cli();
proc_table[p_sb].period = p;
proc_table[p_sb].drel = p;
kern_sti();
sb_dev.period = p;
} */
if (!(t & NOBUFF)) {
if (t & PCM16) sb_dma16buffop(OUT);
else sb_dmabuffop(OUT);
} else {
/* Double buffering operation */
buff_des.fun = dummyfun2;
if (t & PCM16) sb_dma16op(OUT);
else sb_dmaop(OUT);
}
} else {
/* Non DMA op: create the playing process */
SOFT_TASK_MODEL m_soft;
if (!m) {
rate = (999999 / sps) + 1;
soft_task_default_model(m_soft);
soft_task_def_system(m_soft);
soft_task_def_nokill(m_soft);
soft_task_def_period(m_soft,rate);
soft_task_def_met(m_soft,rate);
soft_task_def_wcet(m_soft,SOUND_WCET);
m = (TASK_MODEL *)&m_soft;
}
p_pl = task_create("sb_Player",proc_play, &m, NULL);
if (p_pl == NIL) {
cprintf("Sound.c: Cannot create sb_Player\n");
sys_end();
return ESRCH;
}
task_activate(p_pl);
}
return 0;
}
/*
Sample: this function calls the adeguate low-level sampling function
with the correct parameters. It is similar to sound_play (see it for the
comments
the task model in the last parameter is used for the sb_player task.
it must be a periodic task with a correct period. if not specified (NULL),
a soft task is used instead.
it returns 0 if all ok,
EINVAL if the outfun isn't specified
ESRCH if the sb_player can not be created
*/
int sound_sample(BYTE *buff, DWORD sps, DWORD len, BYTE t, TASK_MODEL *m)
{
double rate;
PID p_sample;
// WORD s1, p;
// MODEL m = BASE_MODEL;
if (t & MYFUN) {
if (f_des.infunpresent != 0) {
buff_des.fun = selfinfun;
}
else
return EINVAL;
}
else
buff_des.fun = infun;
buff_des.synch = !(t & SYNCH);
dma_des.len = len;
dma_des.p = buff;
if (t & DMA_OP) {
sb_setrate(sps, IN);
/*
if (t & DYNBUFF) {
p_sb = task_pid("sb_EndDMA");
s1 = (sps / 100) * ((t & PCM16) ? 2 : 1);
p = ((dma_des.dma_bufflen >> 1) * 1000 ) / (sound_tick * s1);
if(p < 1) {
sb_dev.pwarning = 1;
p = 1;
} else sb_dev.pwarning = 0;
kern_cli();
proc_table[p_sb].period = p;
proc_table[p_sb].drel = p;
kern_sti();
sb_dev.period = p;
} */
if (!(t & NOBUFF)) {
if (t & PCM16) sb_dma16buffop(IN);
else sb_dmabuffop(IN);
} else {
buff_des.fun = dummyfun2;
if (t & PCM16) sb_dma16op(IN);
else sb_dmaop(IN);
}
} else {
/* Non DMA op: create the playing process */
SOFT_TASK_MODEL m_soft;
if (!m) {
rate = (999999 / sps) + 1;
soft_task_default_model(m_soft);
soft_task_def_system(m_soft);
soft_task_def_nokill(m_soft);
soft_task_def_period(m_soft,rate);
soft_task_def_met(m_soft,rate);
soft_task_def_wcet(m_soft,SOUND_WCET);
m = (TASK_MODEL *)&m_soft;
}
p_sample = task_create("sb_Sampler",proc_sample, &m, NULL);
if (p_sample == NIL) {
cprintf("Sound.c: Cannot create sb_Sampler\n");
sys_end();
return ESRCH;
}
task_activate(p_sample);
}
return 0;
}
/*
Wait for the end of a synchronous sound op: it is implemented with a
simple semaphore
It returns 0 if all ok,
-1 if no sinchronous operation was called before
*/
int sound_wait(void)
{
if (buff_des.synch) {
sem_wait(&buff_des.synchr);
buff_des.synch = 0;
return 0;
}
else
return -1;
}
/* returns 0 if all ok,
ENOSPC if a problem occurs when creating the semaphores structures
ESRCH if the Enddma task cn not be created
*/
int sound_init(WORD rawbuffsize, TASK_MODEL *m)
{
PID p_sb;
int period;
SOFT_TASK_MODEL m_soft;
/* Semaphore for synchronous ops */
if (sem_init(&buff_des.synchr,0,0))
return ENOSPC;
/* Init the card */
sb_init();
sbmixer_reset();
sbmixer_setinput(0x01, ENABLE);
sbmixer_setoutput(0x01, DISABLE);
sbmixer_setmiclev(0x1F);
sbmixer_setAGC(ENABLE);
sbmixer_setingainlev(0);
f_des.infun = 0;
f_des.infunpresent = 0;
f_des.outfun = 0;
f_des.outfunpresent = 0;
/* init the buffers for DMA ops */
dma_getalignbuff(&dma_des, rawbuffsize);
buff_des.sound_dma = &dma_des;
if (!m) {
period = (rawbuffsize * 1000000) / 48000;
kern_printf("period=%d\n",period);
soft_task_default_model(m_soft);
soft_task_def_system(m_soft);
soft_task_def_nokill(m_soft);
soft_task_def_period(m_soft,period);
soft_task_def_met(m_soft,SOUND_WCET);
soft_task_def_wcet(m_soft,SOUND_WCET);
soft_task_def_aperiodic(m_soft);
m = (TASK_MODEL *)&m_soft;
}
/* create the driver process and set it and the Fast Handler */
p_sb = task_create("sb_EndDMA", sb_proc, m, NULL);
if (p_sb == NIL) {
cprintf("Sound.c: Cannot create sb_EndDMA\n");
cprintf("errno=%d\n",errno);
sys_end();
return ESRCH;
}
//sb_dev.period = period;
handler_set(sb_dev.IntLine, sb_handler, p_sb);
return 0;
}
/* Obvious... */
void sound_info(void)
{
cprintf("Hartik Sound lib [V 3.2]:\n");
cprintf("Sound Blaster 16 or clone found:\n");
sb_show();
}
/*
This function is called by the driver process on the last transfert of an
operation
*/
int dummyfun1(struct dma_buff *d)
{
buff_des.fun = dummyfun2;
return 0;
}
/*
This function is called by the driver process when the next transfert
will be the last of the current operation
*/
int dummyfun2(struct dma_buff *d)
{
if (buff_des.synch) sem_post(&buff_des.synchr);
sb_stopdsp(8);
sb_stopdsp(16);
dma_stop(sb_dev.DMA8Channel);
dma16_stop(sb_dev.DMA16Channel);
return 0;
}
/* Obvious... */
void sound_stop(void)
{
if (!buff_des.synch) {
sb_stopdsp(8);
sb_stopdsp(16);
dma_stop(sb_dev.DMA8Channel);
dma16_stop(sb_dev.DMA16Channel);
}
}