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_PCM] = 75, 36 [SOUND_MIXER_SPEAKER] = 75, 37 [SOUND_MIXER_LINE] = 75, 38 [SOUND_MIXER_MIC] = 0, 39 [SOUND_MIXER_CD] = 75, 40 [SOUND_MIXER_LINE1] = 75, 41 [SOUND_MIXER_VIDEO] = 75, 42 [SOUND_MIXER_RECLEV] = 0, 43 [SOUND_MIXER_OGAIN] = 50, 44 }; 45 46 int 47 mixer_init(snddev_info *d, snd_mixer *m, void *devinfo) 48 { 49 if (d == NULL) return -1; 50 d->mixer = *m; 51 d->mixer.devinfo = devinfo; 52 bzero(&d->mixer.level, sizeof d->mixer.level); 53 if (d->mixer.init != NULL && d->mixer.init(&d->mixer) == 0) { 54 int i; 55 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 56 u_int16_t v = snd_mixerdefaults[i]; 57 mixer_set(d, i, v | (v << 8)); 58 } 59 mixer_setrecsrc(d, SOUND_MASK_MIC); 60 return 0; 61 } else return -1; 62 } 63 64 int 65 mixer_set(snddev_info *d, unsigned dev, unsigned lev) 66 { 67 if (d == NULL || d->mixer.set == NULL) return -1; 68 if ((dev < SOUND_MIXER_NRDEVICES) && (d->mixer.devs & (1 << dev))) { 69 unsigned l = min((lev & 0x00ff), 100); 70 unsigned r = min(((lev & 0xff00) >> 8), 100); 71 int v = d->mixer.set(&d->mixer, dev, l, r); 72 if (v >= 0) d->mixer.level[dev] = v; 73 return 0; 74 } else return -1; 75 } 76 77 int 78 mixer_get(snddev_info *d, int dev) 79 { 80 if (d == NULL) return -1; 81 if (dev < SOUND_MIXER_NRDEVICES && (d->mixer.devs & (1 << dev))) 82 return d->mixer.level[dev]; 83 else return -1; 84 } 85 86 int 87 mixer_setrecsrc(snddev_info *d, u_int32_t src) 88 { 89 if (d == NULL || d->mixer.setrecsrc == NULL) return -1; 90 src &= d->mixer.recdevs; 91 if (src == 0) src = SOUND_MASK_MIC; 92 d->mixer.recsrc = d->mixer.setrecsrc(&d->mixer, src); 93 return 0; 94 } 95 96 int 97 mixer_getrecsrc(snddev_info *d) 98 { 99 if (d == NULL) return -1; 100 return d->mixer.recsrc; 101 } 102 103 int 104 mixer_ioctl(snddev_info *d, u_long cmd, caddr_t arg) 105 { 106 int ret, *arg_i = (int *)arg; 107 108 if ((cmd & MIXER_WRITE(0)) == MIXER_WRITE(0)) { 109 int j = cmd & 0xff; 110 111 if (j == SOUND_MIXER_RECSRC) ret = mixer_setrecsrc(d, *arg_i); 112 else ret = mixer_set(d, j, *arg_i); 113 return (ret == 0)? 0 : ENXIO; 114 } 115 116 if ((cmd & MIXER_READ(0)) == MIXER_READ(0)) { 117 int v = -1, j = cmd & 0xff; 118 119 switch (j) { 120 case SOUND_MIXER_DEVMASK: 121 case SOUND_MIXER_CAPS: 122 case SOUND_MIXER_STEREODEVS: 123 v = d->mixer.devs; 124 break; 125 126 case SOUND_MIXER_RECMASK: 127 v = d->mixer.recdevs; 128 break; 129 130 case SOUND_MIXER_RECSRC: 131 v = mixer_getrecsrc(d); 132 break; 133 134 default: 135 v = mixer_get(d, j); 136 } 137 *arg_i = v; 138 return (v != -1)? 0 : ENXIO; 139 } 140 return ENXIO; 141 } 142 143 void 144 mix_setdevs(snd_mixer *m, u_int32_t v) 145 { 146 m->devs = v; 147 } 148 149 void 150 mix_setrecdevs(snd_mixer *m, u_int32_t v) 151 { 152 m->recdevs = v; 153 } 154 155 u_int32_t 156 mix_getdevs(snd_mixer *m) 157 { 158 return m->devs; 159 } 160 161 u_int32_t 162 mix_getrecdevs(snd_mixer *m) 163 { 164 return m->recdevs; 165 } 166 167 void * 168 mix_getdevinfo(snd_mixer *m) 169 { 170 return m->devinfo; 171 } 172 173 /* 174 * The various mixers use a variety of bitmasks etc. The Voxware 175 * driver had a very nice technique to describe a mixer and interface 176 * to it. A table defines, for each channel, which register, bits, 177 * offset, polarity to use. This procedure creates the new value 178 * using the table and the old value. 179 */ 180 181 void 182 change_bits(mixer_tab *t, u_char *regval, int dev, int chn, int newval) 183 { 184 u_char mask; 185 int shift; 186 187 DEB(printf("ch_bits dev %d ch %d val %d old 0x%02x " 188 "r %d p %d bit %d off %d\n", 189 dev, chn, newval, *regval, 190 (*t)[dev][chn].regno, (*t)[dev][chn].polarity, 191 (*t)[dev][chn].nbits, (*t)[dev][chn].bitoffs ) ); 192 193 if ( (*t)[dev][chn].polarity == 1) /* reverse */ 194 newval = 100 - newval ; 195 196 mask = (1 << (*t)[dev][chn].nbits) - 1; 197 newval = (int) ((newval * mask) + 50) / 100; /* Scale it */ 198 shift = (*t)[dev][chn].bitoffs /*- (*t)[dev][LEFT_CHN].nbits + 1*/; 199 200 *regval &= ~(mask << shift); /* Filter out the previous value */ 201 *regval |= (newval & mask) << shift; /* Set the new value */ 202 } 203 204