1 /* 2 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29 #include <dev/sound/pcm/sound.h> 30 31 static u_int16_t snd_mixerdefaults[SOUND_MIXER_NRDEVICES] = { 32 [SOUND_MIXER_VOLUME] = 75, 33 [SOUND_MIXER_BASS] = 50, 34 [SOUND_MIXER_TREBLE] = 50, 35 [SOUND_MIXER_SYNTH] = 75, 36 [SOUND_MIXER_PCM] = 75, 37 [SOUND_MIXER_SPEAKER] = 75, 38 [SOUND_MIXER_LINE] = 75, 39 [SOUND_MIXER_MIC] = 0, 40 [SOUND_MIXER_CD] = 75, 41 [SOUND_MIXER_LINE1] = 75, 42 [SOUND_MIXER_VIDEO] = 75, 43 [SOUND_MIXER_RECLEV] = 0, 44 [SOUND_MIXER_OGAIN] = 50, 45 }; 46 47 int 48 mixer_init(snddev_info *d, snd_mixer *m, void *devinfo) 49 { 50 if (d == NULL) return -1; 51 d->mixer = *m; 52 d->mixer.devinfo = devinfo; 53 bzero(&d->mixer.level, sizeof d->mixer.level); 54 if (d->mixer.init != NULL && d->mixer.init(&d->mixer) == 0) { 55 int i; 56 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 57 u_int16_t v = snd_mixerdefaults[i]; 58 mixer_set(d, i, v | (v << 8)); 59 } 60 mixer_setrecsrc(d, SOUND_MASK_MIC); 61 return 0; 62 } else return -1; 63 } 64 65 int 66 mixer_reinit(snddev_info *d) 67 { 68 int i; 69 if (d == NULL) return -1; 70 if (d->mixer.init != NULL && d->mixer.init(&d->mixer) == 0) { 71 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 72 mixer_set(d, i, d->mixer.level[i]); 73 mixer_setrecsrc(d, d->mixer.recsrc); 74 return 0; 75 } else return -1; 76 } 77 78 int 79 mixer_set(snddev_info *d, unsigned dev, unsigned lev) 80 { 81 if (d == NULL || d->mixer.set == NULL) return -1; 82 if ((dev < SOUND_MIXER_NRDEVICES) && (d->mixer.devs & (1 << dev))) { 83 unsigned l = min((lev & 0x00ff), 100); 84 unsigned r = min(((lev & 0xff00) >> 8), 100); 85 int v = d->mixer.set(&d->mixer, dev, l, r); 86 if (v >= 0) d->mixer.level[dev] = l | (r << 8); 87 return 0; 88 } else return -1; 89 } 90 91 int 92 mixer_get(snddev_info *d, int dev) 93 { 94 if (d == NULL) return -1; 95 if (dev < SOUND_MIXER_NRDEVICES && (d->mixer.devs & (1 << dev))) 96 return d->mixer.level[dev]; 97 else return -1; 98 } 99 100 int 101 mixer_setrecsrc(snddev_info *d, u_int32_t src) 102 { 103 if (d == NULL || d->mixer.setrecsrc == NULL) return -1; 104 src &= d->mixer.recdevs; 105 if (src == 0) src = SOUND_MASK_MIC; 106 d->mixer.recsrc = d->mixer.setrecsrc(&d->mixer, src); 107 return 0; 108 } 109 110 int 111 mixer_getrecsrc(snddev_info *d) 112 { 113 if (d == NULL) return -1; 114 return d->mixer.recsrc; 115 } 116 117 int 118 mixer_ioctl(snddev_info *d, u_long cmd, caddr_t arg) 119 { 120 int ret, *arg_i = (int *)arg; 121 122 if ((cmd & MIXER_WRITE(0)) == MIXER_WRITE(0)) { 123 int j = cmd & 0xff; 124 125 if (j == SOUND_MIXER_RECSRC) ret = mixer_setrecsrc(d, *arg_i); 126 else ret = mixer_set(d, j, *arg_i); 127 return (ret == 0)? 0 : ENXIO; 128 } 129 130 if ((cmd & MIXER_READ(0)) == MIXER_READ(0)) { 131 int v = -1, j = cmd & 0xff; 132 133 switch (j) { 134 case SOUND_MIXER_DEVMASK: 135 case SOUND_MIXER_CAPS: 136 case SOUND_MIXER_STEREODEVS: 137 v = d->mixer.devs; 138 break; 139 140 case SOUND_MIXER_RECMASK: 141 v = d->mixer.recdevs; 142 break; 143 144 case SOUND_MIXER_RECSRC: 145 v = mixer_getrecsrc(d); 146 break; 147 148 default: 149 v = mixer_get(d, j); 150 } 151 *arg_i = v; 152 return (v != -1)? 0 : ENXIO; 153 } 154 return ENXIO; 155 } 156 157 void 158 mix_setdevs(snd_mixer *m, u_int32_t v) 159 { 160 m->devs = v; 161 } 162 163 void 164 mix_setrecdevs(snd_mixer *m, u_int32_t v) 165 { 166 m->recdevs = v; 167 } 168 169 u_int32_t 170 mix_getdevs(snd_mixer *m) 171 { 172 return m->devs; 173 } 174 175 u_int32_t 176 mix_getrecdevs(snd_mixer *m) 177 { 178 return m->recdevs; 179 } 180 181 void * 182 mix_getdevinfo(snd_mixer *m) 183 { 184 return m->devinfo; 185 } 186 187 /* 188 * The various mixers use a variety of bitmasks etc. The Voxware 189 * driver had a very nice technique to describe a mixer and interface 190 * to it. A table defines, for each channel, which register, bits, 191 * offset, polarity to use. This procedure creates the new value 192 * using the table and the old value. 193 */ 194 195 void 196 change_bits(mixer_tab *t, u_char *regval, int dev, int chn, int newval) 197 { 198 u_char mask; 199 int shift; 200 201 DEB(printf("ch_bits dev %d ch %d val %d old 0x%02x " 202 "r %d p %d bit %d off %d\n", 203 dev, chn, newval, *regval, 204 (*t)[dev][chn].regno, (*t)[dev][chn].polarity, 205 (*t)[dev][chn].nbits, (*t)[dev][chn].bitoffs ) ); 206 207 if ( (*t)[dev][chn].polarity == 1) /* reverse */ 208 newval = 100 - newval ; 209 210 mask = (1 << (*t)[dev][chn].nbits) - 1; 211 newval = (int) ((newval * mask) + 50) / 100; /* Scale it */ 212 shift = (*t)[dev][chn].bitoffs /*- (*t)[dev][LEFT_CHN].nbits + 1*/; 213 214 *regval &= ~(mask << shift); /* Filter out the previous value */ 215 *regval |= (newval & mask) << shift; /* Set the new value */ 216 } 217 218