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 #include "mixer_if.h" 32 33 MALLOC_DEFINE(M_MIXER, "mixer", "mixer"); 34 35 static u_int16_t snd_mixerdefaults[SOUND_MIXER_NRDEVICES] = { 36 [SOUND_MIXER_VOLUME] = 75, 37 [SOUND_MIXER_BASS] = 50, 38 [SOUND_MIXER_TREBLE] = 50, 39 [SOUND_MIXER_SYNTH] = 75, 40 [SOUND_MIXER_PCM] = 75, 41 [SOUND_MIXER_SPEAKER] = 75, 42 [SOUND_MIXER_LINE] = 75, 43 [SOUND_MIXER_MIC] = 0, 44 [SOUND_MIXER_CD] = 75, 45 [SOUND_MIXER_LINE1] = 75, 46 [SOUND_MIXER_VIDEO] = 75, 47 [SOUND_MIXER_RECLEV] = 0, 48 [SOUND_MIXER_OGAIN] = 50, 49 }; 50 51 static char* snd_mixernames[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES; 52 53 static int 54 mixer_lookup(char *devname) 55 { 56 int i; 57 58 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 59 if (strncmp(devname, snd_mixernames[i], 60 strlen(snd_mixernames[i])) == 0) 61 return i; 62 return -1; 63 } 64 65 static int 66 mixer_set(snd_mixer *mixer, unsigned dev, unsigned lev) 67 { 68 unsigned l, r; 69 int v; 70 71 if ((dev >= SOUND_MIXER_NRDEVICES) || (0 == (mixer->devs & (1 << dev)))) 72 return -1; 73 74 l = min((lev & 0x00ff), 100); 75 r = min(((lev & 0xff00) >> 8), 100); 76 77 v = MIXER_SET(mixer, dev, l, r); 78 if (v < 0) 79 return -1; 80 81 mixer->level[dev] = l | (r << 8); 82 return 0; 83 } 84 85 static int 86 mixer_get(snd_mixer *mixer, int dev) 87 { 88 if ((dev < SOUND_MIXER_NRDEVICES) && (mixer->devs & (1 << dev))) 89 return mixer->level[dev]; 90 else return -1; 91 } 92 93 static int 94 mixer_setrecsrc(snd_mixer *mixer, u_int32_t src) 95 { 96 src &= mixer->recdevs; 97 if (src == 0) 98 src = SOUND_MASK_MIC; 99 mixer->recsrc = MIXER_SETRECSRC(mixer, src); 100 return 0; 101 } 102 103 static int 104 mixer_getrecsrc(snd_mixer *mixer) 105 { 106 return mixer->recsrc; 107 } 108 109 void 110 mix_setdevs(snd_mixer *m, u_int32_t v) 111 { 112 m->devs = v; 113 } 114 115 void 116 mix_setrecdevs(snd_mixer *m, u_int32_t v) 117 { 118 m->recdevs = v; 119 } 120 121 u_int32_t 122 mix_getdevs(snd_mixer *m) 123 { 124 return m->devs; 125 } 126 127 u_int32_t 128 mix_getrecdevs(snd_mixer *m) 129 { 130 return m->recdevs; 131 } 132 133 void * 134 mix_getdevinfo(snd_mixer *m) 135 { 136 return m->devinfo; 137 } 138 139 int 140 mixer_busy(snd_mixer *m, int busy) 141 { 142 m->busy = busy; 143 return 0; 144 } 145 146 int 147 mixer_isbusy(snd_mixer *m) 148 { 149 return m->busy; 150 } 151 152 int 153 mixer_init(device_t dev, kobj_class_t cls, void *devinfo) 154 { 155 snddev_info *d; 156 snd_mixer *m; 157 u_int16_t v; 158 int i; 159 160 d = device_get_softc(dev); 161 m = (snd_mixer *)kobj_create(cls, M_MIXER, M_WAITOK | M_ZERO); 162 163 m->name = cls->name; 164 m->devinfo = devinfo; 165 166 if (MIXER_INIT(m)) 167 goto bad; 168 169 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 170 v = snd_mixerdefaults[i]; 171 mixer_set(m, i, v | (v << 8)); 172 } 173 174 mixer_setrecsrc(m, SOUND_MASK_MIC); 175 176 d->mixer = m; 177 178 return 0; 179 180 bad: kobj_delete((kobj_t)m, M_MIXER); 181 return -1; 182 } 183 184 int 185 mixer_uninit(device_t dev) 186 { 187 int i; 188 snddev_info *d; 189 snd_mixer *m; 190 191 d = device_get_softc(dev); 192 m = d->mixer; 193 194 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 195 mixer_set(m, i, 0); 196 197 mixer_setrecsrc(m, SOUND_MASK_MIC); 198 199 MIXER_UNINIT(m); 200 201 kobj_delete((kobj_t)m, M_MIXER); 202 d->mixer = NULL; 203 204 return 0; 205 } 206 207 int 208 mixer_reinit(device_t dev) 209 { 210 int i; 211 snddev_info *d; 212 snd_mixer *m; 213 214 d = device_get_softc(dev); 215 m = d->mixer; 216 217 i = MIXER_REINIT(m); 218 if (i) 219 return i; 220 221 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 222 mixer_set(m, i, m->level[i]); 223 224 mixer_setrecsrc(m, m->recsrc); 225 226 return 0; 227 } 228 229 int 230 mixer_ioctl(snddev_info *d, u_long cmd, caddr_t arg) 231 { 232 int ret, *arg_i = (int *)arg; 233 int v = -1, j = cmd & 0xff; 234 snd_mixer *m; 235 236 m = d->mixer; 237 238 if ((cmd & MIXER_WRITE(0)) == MIXER_WRITE(0)) { 239 if (j == SOUND_MIXER_RECSRC) 240 ret = mixer_setrecsrc(m, *arg_i); 241 else 242 ret = mixer_set(m, j, *arg_i); 243 return (ret == 0)? 0 : ENXIO; 244 } 245 246 if ((cmd & MIXER_READ(0)) == MIXER_READ(0)) { 247 switch (j) { 248 case SOUND_MIXER_DEVMASK: 249 case SOUND_MIXER_CAPS: 250 case SOUND_MIXER_STEREODEVS: 251 v = mix_getdevs(m); 252 break; 253 254 case SOUND_MIXER_RECMASK: 255 v = mix_getrecdevs(m); 256 break; 257 258 case SOUND_MIXER_RECSRC: 259 v = mixer_getrecsrc(m); 260 break; 261 262 default: 263 v = mixer_get(m, j); 264 } 265 *arg_i = v; 266 return (v != -1)? 0 : ENXIO; 267 } 268 return ENXIO; 269 } 270 271 static int 272 sysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS) 273 { 274 char devname[32]; 275 int error, dev; 276 snd_mixer *m; 277 278 m = oidp->oid_arg1; 279 strncpy(devname, snd_mixernames[m->hwvol_mixer], sizeof(devname)); 280 error = sysctl_handle_string(oidp, &devname[0], sizeof(devname), req); 281 if (error == 0 && req->newptr != NULL) { 282 dev = mixer_lookup(devname); 283 if (dev == -1) 284 return EINVAL; 285 else 286 m->hwvol_mixer = dev; 287 } 288 return error; 289 } 290 291 int 292 mixer_hwinit(device_t dev) 293 { 294 snddev_info *d; 295 snd_mixer *m; 296 297 d = device_get_softc(dev); 298 m = d->mixer; 299 m->hwvol_mixer = SOUND_MIXER_VOLUME; 300 m->hwvol_step = 5; 301 SYSCTL_ADD_INT(&d->sysctl_tree, SYSCTL_CHILDREN(d->sysctl_tree_top), 302 OID_AUTO, "hwvol_step", CTLFLAG_RW, &m->hwvol_step, 0, ""); 303 SYSCTL_ADD_PROC(&d->sysctl_tree, SYSCTL_CHILDREN(d->sysctl_tree_top), 304 OID_AUTO, "hwvol_mixer", CTLTYPE_STRING | CTLFLAG_RW, m, 0, 305 sysctl_hw_snd_hwvol_mixer, "A", "") 306 return 0; 307 } 308 309 void 310 mixer_hwmute(device_t dev) 311 { 312 snddev_info *d; 313 snd_mixer *m; 314 315 d = device_get_softc(dev); 316 m = d->mixer; 317 if (m->muted) { 318 m->muted = 0; 319 mixer_set(m, m->hwvol_mixer, m->mute_level); 320 } else { 321 m->muted++; 322 m->mute_level = mixer_get(m, m->hwvol_mixer); 323 mixer_set(m, m->hwvol_mixer, 0); 324 } 325 } 326 327 void 328 mixer_hwstep(device_t dev, int left_step, int right_step) 329 { 330 snddev_info *d; 331 snd_mixer *m; 332 int level, left, right; 333 334 d = device_get_softc(dev); 335 m = d->mixer; 336 level = mixer_get(m, m->hwvol_mixer); 337 if (level != -1) { 338 left = level & 0xff; 339 right = level >> 8; 340 left += left_step * m->hwvol_step; 341 if (left < 0) 342 left = 0; 343 right += right_step * m->hwvol_step; 344 if (right < 0) 345 right = 0; 346 mixer_set(m, m->hwvol_mixer, left | right << 8); 347 } 348 } 349 350 /* 351 * The various mixers use a variety of bitmasks etc. The Voxware 352 * driver had a very nice technique to describe a mixer and interface 353 * to it. A table defines, for each channel, which register, bits, 354 * offset, polarity to use. This procedure creates the new value 355 * using the table and the old value. 356 */ 357 358 void 359 change_bits(mixer_tab *t, u_char *regval, int dev, int chn, int newval) 360 { 361 u_char mask; 362 int shift; 363 364 DEB(printf("ch_bits dev %d ch %d val %d old 0x%02x " 365 "r %d p %d bit %d off %d\n", 366 dev, chn, newval, *regval, 367 (*t)[dev][chn].regno, (*t)[dev][chn].polarity, 368 (*t)[dev][chn].nbits, (*t)[dev][chn].bitoffs ) ); 369 370 if ( (*t)[dev][chn].polarity == 1) /* reverse */ 371 newval = 100 - newval ; 372 373 mask = (1 << (*t)[dev][chn].nbits) - 1; 374 newval = (int) ((newval * mask) + 50) / 100; /* Scale it */ 375 shift = (*t)[dev][chn].bitoffs /*- (*t)[dev][LEFT_CHN].nbits + 1*/; 376 377 *regval &= ~(mask << shift); /* Filter out the previous value */ 378 *regval |= (newval & mask) << shift; /* Set the new value */ 379 } 380 381