mkfs: symlink support
[minix.git] / drivers / audio / sb16 / mixer.c
blob4dbf5368d509a36557919ff40835a2cc409f6805
1 #include "sb16.h"
2 #include "mixer.h"
6 static int get_set_volume(struct volume_level *level, int flag);
7 static int get_set_input(struct inout_ctrl *input, int flag, int
8 channel);
9 static int get_set_output(struct inout_ctrl *output, int flag);
14 /*=========================================================================*
15 * mixer_ioctl
16 *=========================================================================*/
17 int mixer_ioctl(int request, void *val, int *UNUSED(len)) {
18 int status;
20 switch(request) {
21 case MIXIOGETVOLUME: status = get_set_volume(val, 0); break;
22 case MIXIOSETVOLUME: status = get_set_volume(val, 1); break;
23 case MIXIOGETINPUTLEFT: status = get_set_input(val, 0, 0); break;
24 case MIXIOGETINPUTRIGHT: status = get_set_input(val, 0, 1); break;
25 case MIXIOGETOUTPUT: status = get_set_output(val, 0); break;
26 case MIXIOSETINPUTLEFT: status = get_set_input(val, 1, 0); break;
27 case MIXIOSETINPUTRIGHT: status = get_set_input(val, 1, 1); break;
28 case MIXIOSETOUTPUT: status = get_set_output(val, 1); break;
29 default: status = ENOTTY;
32 return status;
36 /*=========================================================================*
37 * mixer_init
38 *=========================================================================*/
39 int mixer_init() {
40 /* Try to detect the mixer by writing to MIXER_DAC_LEVEL if the
41 * value written can be read back the mixer is there
44 mixer_set(MIXER_DAC_LEVEL, 0x10); /* write something to it */
45 if(mixer_get(MIXER_DAC_LEVEL) != 0x10) {
46 Dprint(("sb16: Mixer not detected\n"));
47 return EIO;
50 /* Enable Automatic Gain Control */
51 mixer_set(MIXER_AGC, 0x01);
53 Dprint(("Mixer detected\n"));
55 return OK;
60 /*=========================================================================*
61 * get_set_volume *
62 *=========================================================================*/
63 static int get_set_volume(struct volume_level *level, int flag) {
64 int cmd_left, cmd_right, shift, max_level;
66 shift = 3;
67 max_level = 0x1F;
68 switch(level->device) {
69 case Master:
70 cmd_left = MIXER_MASTER_LEFT;
71 cmd_right = MIXER_MASTER_RIGHT;
72 break;
73 case Dac:
74 cmd_left = MIXER_DAC_LEFT;
75 cmd_right = MIXER_DAC_RIGHT;
76 break;
77 case Fm:
78 cmd_left = MIXER_FM_LEFT;
79 cmd_right = MIXER_FM_RIGHT;
80 break;
81 case Cd:
82 cmd_left = MIXER_CD_LEFT;
83 cmd_right = MIXER_CD_RIGHT;
84 break;
85 case Line:
86 cmd_left = MIXER_LINE_LEFT;
87 cmd_right = MIXER_LINE_RIGHT;
88 break;
89 case Mic:
90 cmd_left = cmd_right = MIXER_MIC_LEVEL;
91 break;
92 case Speaker:
93 cmd_left = cmd_right = MIXER_PC_LEVEL;
94 shift = 6;
95 max_level = 0x03;
96 break;
97 case Treble:
98 cmd_left = MIXER_TREBLE_LEFT;
99 cmd_right = MIXER_TREBLE_RIGHT;
100 shift = 4;
101 max_level = 0x0F;
102 break;
103 case Bass:
104 cmd_left = MIXER_BASS_LEFT;
105 cmd_right = MIXER_BASS_RIGHT;
106 shift = 4;
107 max_level = 0x0F;
108 break;
109 default:
110 return EINVAL;
113 if(flag) { /* Set volume level */
114 if(level->right < 0) level->right = 0;
115 else if(level->right > max_level) level->right = max_level;
116 if(level->left < 0) level->left = 0;
117 else if(level->left > max_level) level->left = max_level;
119 mixer_set(cmd_right, (level->right << shift));
120 mixer_set(cmd_left, (level->left << shift));
121 } else { /* Get volume level */
122 level->left = mixer_get(cmd_left);
123 level->right = mixer_get(cmd_right);
125 level->left >>= shift;
126 level->right >>= shift;
129 return OK;
133 /*=========================================================================*
134 * get_set_input *
135 *=========================================================================*/
136 static int get_set_input(struct inout_ctrl *input, int flag, int channel) {
137 int input_cmd, input_mask, mask, del_mask, shift;
139 input_cmd = (channel == 0 ? MIXER_IN_LEFT : MIXER_IN_RIGHT);
141 mask = mixer_get(input_cmd);
143 switch (input->device) {
144 case Fm:
145 shift = 5;
146 del_mask = 0x1F;
147 break;
148 case Cd:
149 shift = 1;
150 del_mask = 0x79;
151 break;
152 case Line:
153 shift = 3;
154 del_mask = 0x67;
155 break;
156 case Mic:
157 shift = 0;
158 del_mask = 0x7E;
159 break;
160 default:
161 return EINVAL;
164 if (flag) { /* Set input */
165 input_mask = ((input->left == ON ? 1 : 0) << 1) | (input->right == ON ? 1 : 0);
167 if (shift > 0) input_mask <<= shift;
168 else input_mask >>= 1;
170 mask &= del_mask;
171 mask |= input_mask;
173 mixer_set(input_cmd, mask);
174 } else { /* Get input */
175 if (shift > 0) {
176 input->left = (((mask >> (shift+1)) & 1) == 1 ? ON : OFF);
177 input->right = (((mask >> shift) & 1) == 1 ? ON : OFF);
178 } else {
179 input->left = ((mask & 1) == 1 ? ON : OFF);
183 return OK;
187 /*=========================================================================*
188 * get_set_output *
189 *=========================================================================*/
190 static int get_set_output(struct inout_ctrl *output, int flag) {
191 int output_mask, mask, del_mask, shift;
193 mask = mixer_get(MIXER_OUTPUT_CTRL);
195 switch (output->device) {
196 case Cd:
197 shift = 1;
198 del_mask = 0x79;
199 break;
200 case Line:
201 shift = 3;
202 del_mask = 0x67;
203 break;
204 case Mic:
205 shift = 0;
206 del_mask = 0x7E;
207 break;
208 default:
209 return EINVAL;
212 if (flag) { /* Set input */
213 output_mask = ((output->left == ON ? 1 : 0) << 1) | (output->right == ON ? 1 : 0);
215 if (shift > 0) output_mask <<= shift;
216 else output_mask >>= 1;
218 mask &= del_mask;
219 mask |= output_mask;
221 mixer_set(MIXER_OUTPUT_CTRL, mask);
222 } else { /* Get input */
223 if (shift > 0) {
224 output->left = (((mask >> (shift+1)) & 1) == 1 ? ON : OFF);
225 output->right = (((mask >> shift) & 1) == 1 ? ON : OFF);
226 } else {
227 output->left = ((mask & 1) == 1 ? ON : OFF);
231 return OK;
236 int mixer_set(int reg, int data) {
237 int i;
239 sb16_outb(MIXER_REG, reg);
240 for(i = 0; i < 100; i++);
241 sb16_outb(MIXER_DATA, data);
243 return OK;
248 int mixer_get(int reg) {
249 int i;
251 sb16_outb(MIXER_REG, reg);
252 for(i = 0; i < 100; i++);
253 return sb16_inb(MIXER_DATA) & 0xff;