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 *
| 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: head/sys/dev/sound/pcm/mixer.c 70680 2001-01-05 07:07:03Z jhb $
| 26 * $FreeBSD: head/sys/dev/sound/pcm/mixer.c 70944 2001-01-11 23:26:16Z jhb $
|
27 */ 28 29#include <dev/sound/pcm/sound.h> 30 31#include "mixer_if.h" 32 33MALLOC_DEFINE(M_MIXER, "mixer", "mixer"); 34 35static 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 51static char* snd_mixernames[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES; 52 53static int 54mixer_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 65static int 66mixer_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 85static int 86mixer_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 93static int 94mixer_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 103static int 104mixer_getrecsrc(snd_mixer *mixer) 105{ 106 return mixer->recsrc; 107} 108 109void 110mix_setdevs(snd_mixer *m, u_int32_t v) 111{ 112 m->devs = v; 113} 114 115void 116mix_setrecdevs(snd_mixer *m, u_int32_t v) 117{ 118 m->recdevs = v; 119} 120 121u_int32_t 122mix_getdevs(snd_mixer *m) 123{ 124 return m->devs; 125} 126 127u_int32_t 128mix_getrecdevs(snd_mixer *m) 129{ 130 return m->recdevs; 131} 132 133void * 134mix_getdevinfo(snd_mixer *m) 135{ 136 return m->devinfo; 137} 138 139int 140mixer_busy(snd_mixer *m, int busy) 141{ 142 m->busy = busy; 143 return 0; 144} 145 146int 147mixer_isbusy(snd_mixer *m) 148{ 149 return m->busy; 150} 151 152int 153mixer_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 180bad: kobj_delete((kobj_t)m, M_MIXER); 181 return -1; 182} 183 184int 185mixer_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 207int 208mixer_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 229int 230mixer_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 271static int 272sysctl_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;
| 27 */ 28 29#include <dev/sound/pcm/sound.h> 30 31#include "mixer_if.h" 32 33MALLOC_DEFINE(M_MIXER, "mixer", "mixer"); 34 35static 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 51static char* snd_mixernames[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES; 52 53static int 54mixer_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 65static int 66mixer_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 85static int 86mixer_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 93static int 94mixer_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 103static int 104mixer_getrecsrc(snd_mixer *mixer) 105{ 106 return mixer->recsrc; 107} 108 109void 110mix_setdevs(snd_mixer *m, u_int32_t v) 111{ 112 m->devs = v; 113} 114 115void 116mix_setrecdevs(snd_mixer *m, u_int32_t v) 117{ 118 m->recdevs = v; 119} 120 121u_int32_t 122mix_getdevs(snd_mixer *m) 123{ 124 return m->devs; 125} 126 127u_int32_t 128mix_getrecdevs(snd_mixer *m) 129{ 130 return m->recdevs; 131} 132 133void * 134mix_getdevinfo(snd_mixer *m) 135{ 136 return m->devinfo; 137} 138 139int 140mixer_busy(snd_mixer *m, int busy) 141{ 142 m->busy = busy; 143 return 0; 144} 145 146int 147mixer_isbusy(snd_mixer *m) 148{ 149 return m->busy; 150} 151 152int 153mixer_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 180bad: kobj_delete((kobj_t)m, M_MIXER); 181 return -1; 182} 183 184int 185mixer_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 207int 208mixer_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 229int 230mixer_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 271static int 272sysctl_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
| 285 else if (dev != m->hwvol_mixer) {
|
286 m->hwvol_mixer = dev;
| 286 m->hwvol_mixer = dev;
|
| 287 m->hwvol_muted = 0; 288 }
|
287 } 288 return error; 289} 290 291int
| 289 } 290 return error; 291} 292 293int
|
292mixer_hwinit(device_t dev)
| 294mixer_hwvol_init(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 309void
| 295{ 296 snddev_info *d; 297 snd_mixer *m; 298 299 d = device_get_softc(dev); 300 m = d->mixer; 301 m->hwvol_mixer = SOUND_MIXER_VOLUME; 302 m->hwvol_step = 5; 303 SYSCTL_ADD_INT(&d->sysctl_tree, SYSCTL_CHILDREN(d->sysctl_tree_top), 304 OID_AUTO, "hwvol_step", CTLFLAG_RW, &m->hwvol_step, 0, ""); 305 SYSCTL_ADD_PROC(&d->sysctl_tree, SYSCTL_CHILDREN(d->sysctl_tree_top), 306 OID_AUTO, "hwvol_mixer", CTLTYPE_STRING | CTLFLAG_RW, m, 0, 307 sysctl_hw_snd_hwvol_mixer, "A", "") 308 return 0; 309} 310 311void
|
310mixer_hwmute(device_t dev)
| 312mixer_hwvol_mute(device_t dev)
|
311{ 312 snddev_info *d; 313 snd_mixer *m; 314 315 d = device_get_softc(dev); 316 m = d->mixer;
| 313{ 314 snddev_info *d; 315 snd_mixer *m; 316 317 d = device_get_softc(dev); 318 m = d->mixer;
|
317 if (m->muted) { 318 m->muted = 0; 319 mixer_set(m, m->hwvol_mixer, m->mute_level);
| 319 if (m->hwvol_muted) { 320 m->hwvol_muted = 0; 321 mixer_set(m, m->hwvol_mixer, m->hwvol_mute_level);
|
320 } else {
| 322 } else {
|
321 m->muted++; 322 m->mute_level = mixer_get(m, m->hwvol_mixer);
| 323 m->hwvol_muted++; 324 m->hwvol_mute_level = mixer_get(m, m->hwvol_mixer);
|
323 mixer_set(m, m->hwvol_mixer, 0); 324 } 325} 326 327void
| 325 mixer_set(m, m->hwvol_mixer, 0); 326 } 327} 328 329void
|
328mixer_hwstep(device_t dev, int left_step, int right_step)
| 330mixer_hwvol_step(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;
| 331{ 332 snddev_info *d; 333 snd_mixer *m; 334 int level, left, right; 335 336 d = device_get_softc(dev); 337 m = d->mixer;
|
336 level = mixer_get(m, m->hwvol_mixer);
| 338 if (m->hwvol_muted) { 339 m->hwvol_muted = 0; 340 level = m->hwvol_mute_level; 341 } else 342 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 358void 359change_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
| 343 if (level != -1) { 344 left = level & 0xff; 345 right = level >> 8; 346 left += left_step * m->hwvol_step; 347 if (left < 0) 348 left = 0; 349 right += right_step * m->hwvol_step; 350 if (right < 0) 351 right = 0; 352 mixer_set(m, m->hwvol_mixer, left | right << 8); 353 } 354} 355 356/* 357 * The various mixers use a variety of bitmasks etc. The Voxware 358 * driver had a very nice technique to describe a mixer and interface 359 * to it. A table defines, for each channel, which register, bits, 360 * offset, polarity to use. This procedure creates the new value 361 * using the table and the old value. 362 */ 363 364void 365change_bits(mixer_tab *t, u_char *regval, int dev, int chn, int newval) 366{ 367 u_char mask; 368 int shift; 369 370 DEB(printf("ch_bits dev %d ch %d val %d old 0x%02x " 371 "r %d p %d bit %d off %d\n", 372 dev, chn, newval, *regval, 373 (*t)[dev][chn].regno, (*t)[dev][chn].polarity, 374 (*t)[dev][chn].nbits, (*t)[dev][chn].bitoffs ) ); 375 376 if ( (*t)[dev][chn].polarity == 1) /* reverse */ 377 newval = 100 - newval ; 378 379 mask = (1 << (*t)[dev][chn].nbits) - 1; 380 newval = (int) ((newval * mask) + 50) / 100; /* Scale it */ 381 shift = (*t)[dev][chn].bitoffs /*- (*t)[dev][LEFT_CHN].nbits + 1*/; 382 383 *regval &= ~(mask << shift); /* Filter out the previous value */ 384 *regval |= (newval & mask) << shift; /* Set the new value */ 385} 386
|