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