xref: /minix/minix/drivers/audio/sb16/mixer.c (revision 7f5f010b)
1 #include "sb16.h"
2 #include "mixer.h"
3 
4 
5 
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);
10 
11 
12 
13 
14 /*=========================================================================*
15  *				mixer_ioctl
16  *=========================================================================*/
17 int mixer_ioctl(unsigned long request, void *val, int *UNUSED(len)) {
18 	int status;
19 
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;
30 	}
31 
32 	return status;
33 }
34 
35 
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
42 	*/
43 
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;
48 	}
49 
50 	/* Enable Automatic Gain Control */
51 	mixer_set(MIXER_AGC, 0x01);
52 
53 	Dprint(("Mixer detected\n"));
54 
55 	return OK;
56 }
57 
58 
59 
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;
65 
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;
111 	}
112 
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;
118 
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);
124 
125 		level->left >>= shift;
126 		level->right >>= shift;
127 	}
128 
129 	return OK;
130 }
131 
132 
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;
138 
139 	input_cmd = (channel == 0 ? MIXER_IN_LEFT : MIXER_IN_RIGHT);
140 
141 	mask = mixer_get(input_cmd);
142 
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;
162 	}
163 
164 	if (flag) {  /* Set input */
165 		input_mask = ((input->left == ON ? 1 : 0) << 1) | (input->right == ON ? 1 : 0);
166 
167 		if (shift > 0) input_mask <<= shift;
168 		else input_mask >>= 1;
169 
170 		mask &= del_mask;
171 		mask |= input_mask;
172 
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);
180 		}
181 	}
182 
183 	return OK;
184 }
185 
186 
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;
192 
193 	mask = mixer_get(MIXER_OUTPUT_CTRL);
194 
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;
210 	}
211 
212 	if (flag) {  /* Set input */
213 		output_mask = ((output->left == ON ? 1 : 0) << 1) | (output->right == ON ? 1 : 0);
214 
215 		if (shift > 0) output_mask <<= shift;
216 		else output_mask >>= 1;
217 
218 		mask &= del_mask;
219 		mask |= output_mask;
220 
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);
228 		}
229 	}
230 
231 	return OK;
232 }
233 
234 
235 
236 int mixer_set(int reg, int data) {
237 	int i;
238 
239 	sb16_outb(MIXER_REG, reg);
240 	for(i = 0; i < 100; i++);
241 	sb16_outb(MIXER_DATA, data);
242 
243 	return OK;
244 }
245 
246 
247 
248 int mixer_get(int reg) {
249 	int i;
250 
251 	sb16_outb(MIXER_REG, reg);
252 	for(i = 0; i < 100; i++);
253 	return sb16_inb(MIXER_DATA) & 0xff;
254 }
255