📄 sb16_mixer.c
字号:
/* This file contains the driver for the mixer on
* a SoundBlaster 16 (ASP) soundcard.
*
* The driver supports the following operations (using message format m2):
*
* m_type DEVICE PROC_NR COUNT POSITION ADRRESS
* ----------------------------------------------------------------
* | DEV_OPEN | device | proc nr | | | |
* |------------+---------+---------+---------+---------+---------|
* | DEV_CLOSE | device | proc nr | | | |
* |------------+---------+---------+---------+---------+---------|
* | DEV_IOCTL | device | proc nr |func code| | buf_ptr |
* ----------------------------------------------------------------
*
* The file contains one entry point:
*
* mixer_task: main entry when system is brought up
*
* May 20 1995 Author: Michel R. Prevenier
*/
#include "kernel.h"
#include <minix/com.h>
#include <minix/callnr.h>
#include <sys/ioctl.h>
#include <minix/sound.h>
#if __minix_vmd
#include "config.h"
#endif
#include "sb16.h"
#if ENABLE_SB_AUDIO
/* Function prototypes */
FORWARD _PROTOTYPE( int mixer_init, (void));
FORWARD _PROTOTYPE( int mixer_open, (message *m_ptr));
FORWARD _PROTOTYPE( int mixer_close, (message *m_ptr));
FORWARD _PROTOTYPE( int mixer_ioctl, (message *m_ptr));
FORWARD _PROTOTYPE( int mixer_get, (int reg));
FORWARD _PROTOTYPE( int get_set_volume, (message *m_ptr, int flag));
FORWARD _PROTOTYPE( int get_set_input, (message *m_ptr, int flag, int channel));
FORWARD _PROTOTYPE( int get_set_output, (message *m_ptr, int flag));
PRIVATE int mixer_avail = 0; /* Mixer exists? */
/*=========================================================================*
* mixer_task *
*=========================================================================*/
PUBLIC void mixer_task()
{
message mess;
int err, caller, proc_nr;
/* Here is the main loop of the mixer task. It waits for a message, carries
* it out, and sends a reply.
*/
while (TRUE)
{
receive(ANY, &mess);
caller = mess.m_source;
proc_nr = mess.PROC_NR;
switch (caller)
{
case HARDWARE:
/* Leftover interrupt. */
continue;
case FS_PROC_NR:
/* The only legitimate caller. */
break;
default:
printf("sb16: got message from %d\n", caller);
continue;
}
/* Now carry out the work. */
switch(mess.m_type)
{
case DEV_OPEN: err = mixer_open(&mess);break;
case DEV_CLOSE: err = mixer_close(&mess);break;
case DEV_IOCTL: err = mixer_ioctl(&mess);break;
default: err = EINVAL;break;
}
/* Finally, prepare and send the reply message. */
mess.m_type = TASK_REPLY;
mess.REP_PROC_NR = proc_nr;
mess.REP_STATUS = err; /* error code */
send(caller, &mess); /* send reply to caller */
}
}
/*=========================================================================*
* mixer_open *
*=========================================================================*/
PRIVATE int mixer_open(m_ptr)
message *m_ptr;
{
#if SB_DEBUG
printf("mixer_open\n");
#endif
/* try to detect the mixer type */
if (!mixer_avail && !mixer_init() != OK) return EIO;
return OK;
}
/*=========================================================================*
* mixer_close *
*=========================================================================*/
PRIVATE int mixer_close(m_ptr)
message *m_ptr;
{
#if SB_DEBUG
printf("mixer_close\n");
#endif
return OK;
}
/*=========================================================================*
* mixer_ioctl *
*=========================================================================*/
PRIVATE int mixer_ioctl(m_ptr)
message *m_ptr;
{
int status;
#if SB_DEBUG
printf("mixer: got ioctl %d\n", m_ptr->REQUEST);
#endif
switch(m_ptr->REQUEST)
{
case MIXIOGETVOLUME: status = get_set_volume(m_ptr, 0);break;
case MIXIOSETVOLUME: status = get_set_volume(m_ptr, 1);break;
case MIXIOGETINPUTLEFT: status = get_set_input(m_ptr, 0, 0);break;
case MIXIOGETINPUTRIGHT: status = get_set_input(m_ptr, 0, 1);break;
case MIXIOGETOUTPUT: status = get_set_output(m_ptr, 0);break;
case MIXIOSETINPUTLEFT: status = get_set_input(m_ptr, 1, 0);break;
case MIXIOSETINPUTRIGHT: status = get_set_input(m_ptr, 1, 1);break;
case MIXIOSETOUTPUT: status = get_set_output(m_ptr, 1);break;
default: status = ENOTTY;
}
return status;
}
/*=========================================================================*
* mixer_init *
*=========================================================================*/
PRIVATE int mixer_init()
{
/* Try to detect the mixer by writing to MIXER_DAC_LEVEL if the
* value written can be read back the mixer is there
*/
mixer_set(MIXER_DAC_LEVEL, 0x10); /* write something to it */
if (mixer_get(MIXER_DAC_LEVEL) != 0x10)
{
printf("sb16: Mixer not detected\n");
return EIO;
}
/* Enable Automatic Gain Control */
mixer_set(MIXER_AGC, 0x01);
#if SB_DEBUG
printf("Mixer detected\n");
#endif
mixer_avail = 1;
return OK;
}
/*=========================================================================*
* mixer_set *
*=========================================================================*/
PUBLIC int mixer_set(reg, data)
int reg;
int data;
{
int i;
out_byte(MIXER_REG, reg);
for(i=0;i<100;i++);
out_byte(MIXER_DATA, data);
return OK;
}
/*=========================================================================*
* mixer_get *
*=========================================================================*/
PRIVATE int mixer_get(reg)
int reg;
{
int i;
out_byte(MIXER_REG, reg);
for(i=0;i<100;i++);
return (in_byte(MIXER_DATA) & 0xff);
}
/*=========================================================================*
* get_set_volume *
*=========================================================================*/
PRIVATE int get_set_volume(m_ptr, flag)
message *m_ptr;
int flag; /* 0 = get, 1 = set */
{
phys_bytes user_phys;
struct volume_level level;
int cmd_left, cmd_right, shift, max_level;
user_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS,
sizeof(struct volume_level));
if (user_phys == 0) return(EFAULT);
phys_copy(user_phys, vir2phys(&level), (phys_bytes) sizeof(level));
shift = 3;
max_level = 0x1F;
switch (level.device)
{
case Master: { cmd_left = MIXER_MASTER_LEFT;
cmd_right = MIXER_MASTER_RIGHT;
};break;
case Dac: { cmd_left = MIXER_DAC_LEFT;
cmd_right = MIXER_DAC_RIGHT;
};break;
case Fm: { cmd_left = MIXER_FM_LEFT;
cmd_right = MIXER_FM_RIGHT;
};break;
case Cd: { cmd_left = MIXER_CD_LEFT;
cmd_right = MIXER_CD_RIGHT;
};break;
case Line: { cmd_left = MIXER_LINE_LEFT;
cmd_right = MIXER_LINE_RIGHT;
};break;
case Mic: { cmd_left = cmd_right = MIXER_MIC_LEVEL;
};break;
case Speaker: { cmd_left = cmd_right = MIXER_PC_LEVEL;
shift = 6;
max_level = 0x03;
};break;
case Treble: { cmd_left = MIXER_TREBLE_LEFT;
cmd_right = MIXER_TREBLE_RIGHT;
shift = 4;
max_level = 0x0F;
};break;
case Bass: { cmd_left = MIXER_BASS_LEFT;
cmd_right = MIXER_BASS_RIGHT;
shift = 4;
max_level = 0x0F;
};break;
default: return EINVAL;
}
if (flag) /* Set volume level */
{
if (level.right < 0) level.right = 0;
else if (level.right > max_level) level.right = max_level;
if (level.left < 0) level.left = 0;
else if (level.left > max_level) level.left = max_level;
mixer_set(cmd_right, (level.right << shift));
mixer_set(cmd_left, (level.left << shift));
}
else /* Get volume level */
{
level.left = mixer_get(cmd_left);
level.right = mixer_get(cmd_right);
level.left >>= shift;
level.right >>= shift;
/* Copy back to user */
phys_copy(vir2phys(&level), user_phys, (phys_bytes) sizeof(level));
}
return OK;
}
/*=========================================================================*
* get_set_input *
*=========================================================================*/
PRIVATE int get_set_input(m_ptr, flag, channel)
message *m_ptr;
int flag; /* 0 = get, 1 = set */
int channel; /* 0 = left, 1 = right */
{
phys_bytes user_phys;
struct inout_ctrl input;
int input_cmd, input_mask, mask, del_mask, shift;
user_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS,
sizeof(struct inout_ctrl));
if (user_phys == 0) return(EFAULT);
phys_copy(user_phys, vir2phys(&input), (phys_bytes) sizeof(input));
input_cmd = (channel == 0 ? MIXER_IN_LEFT : MIXER_IN_RIGHT);
mask = mixer_get(input_cmd);
switch (input.device)
{
case Fm: { shift = 5;
del_mask = 0x1F;
};break;
case Cd: { shift = 1;
del_mask = 0x79;
};break;
case Line: { shift = 3;
del_mask = 0x67;
};break;
case Mic: { shift = 0;
del_mask = 0x7E;
};break;
default: return EINVAL;
}
if (flag) /* Set input */
{
input_mask =
((input.left == ON ? 1 : 0) << 1) | (input.right == ON ? 1 : 0);
if (shift > 0)
input_mask <<= shift;
else
input_mask >>= 1;
mask &= del_mask;
mask |= input_mask;
mixer_set(input_cmd, mask);
}
else /* Get input */
{
if (shift > 0)
{
input.left = ((mask >> (shift+1)) & 1 == 1 ? ON : OFF);
input.right = ((mask >> shift) & 1 == 1 ? ON : OFF);
}
else
input.left = ((mask & 1) == 1 ? ON : OFF);
/* Copy back to user */
phys_copy(vir2phys(&input), user_phys, (phys_bytes) sizeof(input));
}
return OK;
}
/*=========================================================================*
* get_set_output *
*=========================================================================*/
PRIVATE int get_set_output(m_ptr, flag)
message *m_ptr;
int flag; /* 0 = get, 1 = set */
{
phys_bytes user_phys;
struct inout_ctrl output;
int output_mask, mask, del_mask, shift;
user_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS,
sizeof(struct inout_ctrl));
if (user_phys == 0) return(EFAULT);
phys_copy(user_phys, vir2phys(&output), (phys_bytes) sizeof(output));
mask = mixer_get(MIXER_OUTPUT_CTRL);
switch (output.device)
{
case Cd: { shift = 1;
del_mask = 0x79;
};break;
case Line: { shift = 3;
del_mask = 0x67;
};break;
case Mic: { shift = 0;
del_mask = 0x7E;
};break;
default: return EINVAL;
}
if (flag) /* Set input */
{
output_mask =
((output.left == ON ? 1 : 0) << 1) | (output.right == ON ? 1 : 0);
if (shift > 0)
output_mask <<= shift;
else
output_mask >>= 1;
mask &= del_mask;
mask |= output_mask;
mixer_set(MIXER_OUTPUT_CTRL, mask);
}
else /* Get input */
{
if (shift > 0)
{
output.left = ((mask >> (shift+1)) & 1 == 1 ? ON : OFF);
output.right = ((mask >> shift) & 1 == 1 ? ON : OFF);
}
else
output.left = ((mask & 1) == 1 ? ON : OFF);
/* Copy back to user */
phys_copy(vir2phys(&output), user_phys, (phys_bytes) sizeof(output));
}
return OK;
}
#endif /* ENABLE_AUDIO */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -