mixer_kern.diff (20929B)
1 diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c 2 index 38c578ba828..4d56eee6847 100644 3 --- a/sys/dev/sound/pcm/channel.c 4 +++ b/sys/dev/sound/pcm/channel.c 5 @@ -1223,6 +1223,8 @@ chn_init(struct pcm_channel *c, void *devinfo, int dir, int direction) 6 c->volume[SND_VOL_C_MASTER][SND_CHN_T_VOL_0DB] = SND_VOL_0DB_MASTER; 7 c->volume[SND_VOL_C_PCM][SND_CHN_T_VOL_0DB] = chn_vol_0db_pcm; 8 9 + memset(c->muted, 0, sizeof(c->muted)); 10 + 11 chn_vpc_reset(c, SND_VOL_C_PCM, 1); 12 13 ret = ENODEV; 14 @@ -1394,6 +1396,75 @@ chn_getvolume_matrix(struct pcm_channel *c, int vc, int vt) 15 return (c->volume[vc][vt]); 16 } 17 18 +int 19 +chn_setmute_multi(struct pcm_channel *c, int vc, int mute) 20 +{ 21 + int i, ret; 22 + 23 + ret = 0; 24 + 25 + for (i = 0; i < SND_CHN_T_MAX; i++) { 26 + if ((1 << i) & SND_CHN_LEFT_MASK) 27 + ret |= chn_setmute_matrix(c, vc, i, mute); 28 + else if ((1 << i) & SND_CHN_RIGHT_MASK) 29 + ret |= chn_setmute_matrix(c, vc, i, mute) << 8; 30 + else 31 + ret |= chn_setmute_matrix(c, vc, i, mute) << 16; 32 + } 33 + return (ret); 34 +} 35 + 36 +int 37 +chn_setmute_matrix(struct pcm_channel *c, int vc, int vt, int mute) 38 +{ 39 + int i; 40 + 41 + KASSERT(c != NULL && vc >= SND_VOL_C_MASTER && vc < SND_VOL_C_MAX && 42 + (vc == SND_VOL_C_MASTER || (vc & 1)) && 43 + (vt == SND_CHN_T_VOL_0DB || (vt >= SND_CHN_T_BEGIN && vt <= SND_CHN_T_END)), 44 + ("%s(): invalid mute matrix c=%p vc=%d vt=%d mute=%d", 45 + __func__, c, vc, vt, mute)); 46 + 47 + CHN_LOCKASSERT(c); 48 + 49 + mute = (mute != 0); 50 + 51 + c->muted[vc][vt] = mute; 52 + 53 + /* 54 + * Do relative calculation here and store it into class + 1 55 + * to ease the job of feeder_volume. 56 + */ 57 + if (vc == SND_VOL_C_MASTER) { 58 + for (vc = SND_VOL_C_BEGIN; vc <= SND_VOL_C_END; 59 + vc += SND_VOL_C_STEP) 60 + c->muted[SND_VOL_C_VAL(vc)][vt] = mute; 61 + } else if (vc & 1) { 62 + if (vt == SND_CHN_T_VOL_0DB) { 63 + for (i = SND_CHN_T_BEGIN; i <= SND_CHN_T_END; 64 + i += SND_CHN_T_STEP) { 65 + c->muted[SND_VOL_C_VAL(vc)][i] = mute; 66 + } 67 + } else { 68 + c->muted[SND_VOL_C_VAL(vc)][vt] = mute; 69 + } 70 + } 71 + return (mute); 72 +} 73 + 74 +int 75 +chn_getmute_matrix(struct pcm_channel *c, int vc, int vt) 76 +{ 77 + KASSERT(c != NULL && vc >= SND_VOL_C_MASTER && vc < SND_VOL_C_MAX && 78 + (vt == SND_CHN_T_VOL_0DB || 79 + (vt >= SND_CHN_T_BEGIN && vt <= SND_CHN_T_END)), 80 + ("%s(): invalid mute matrix c=%p vc=%d vt=%d", 81 + __func__, c, vc, vt)); 82 + CHN_LOCKASSERT(c); 83 + 84 + return (c->muted[vc][vt]); 85 +} 86 + 87 struct pcmchan_matrix * 88 chn_getmatrix(struct pcm_channel *c) 89 { 90 diff --git a/sys/dev/sound/pcm/channel.h b/sys/dev/sound/pcm/channel.h 91 index 34d62f4e15c..60b7b3416cc 100644 92 --- a/sys/dev/sound/pcm/channel.h 93 +++ b/sys/dev/sound/pcm/channel.h 94 @@ -166,7 +166,8 @@ struct pcm_channel { 95 struct pcmchan_matrix matrix; 96 struct pcmchan_matrix matrix_scratch; 97 98 - int volume[SND_VOL_C_MAX][SND_CHN_T_VOL_MAX]; 99 + int16_t volume[SND_VOL_C_MAX][SND_CHN_T_VOL_MAX]; 100 + int8_t muted[SND_VOL_C_MAX][SND_CHN_T_VOL_MAX]; 101 102 void *data1, *data2; 103 }; 104 @@ -271,6 +272,9 @@ int chn_setvolume_multi(struct pcm_channel *c, int vc, int left, int right, 105 int center); 106 int chn_setvolume_matrix(struct pcm_channel *c, int vc, int vt, int val); 107 int chn_getvolume_matrix(struct pcm_channel *c, int vc, int vt); 108 +int chn_setmute_multi(struct pcm_channel *c, int vc, int mute); 109 +int chn_setmute_matrix(struct pcm_channel *c, int vc, int vt, int mute); 110 +int chn_getmute_matrix(struct pcm_channel *c, int vc, int vt); 111 void chn_vpc_reset(struct pcm_channel *c, int vc, int force); 112 int chn_setparam(struct pcm_channel *c, uint32_t format, uint32_t speed); 113 int chn_setspeed(struct pcm_channel *c, uint32_t speed); 114 @@ -307,6 +311,8 @@ int chn_syncdestroy(struct pcm_channel *c); 115 #define CHN_GETVOLUME(x, y, z) ((x)->volume[y][z]) 116 #endif 117 118 +#define CHN_GETMUTE(x, y, z) ((x)->muted[y][z]) 119 + 120 #ifdef OSSV4_EXPERIMENT 121 int chn_getpeaks(struct pcm_channel *c, int *lpeak, int *rpeak); 122 #endif 123 diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c 124 index 0593a585b0f..15f437b8627 100644 125 --- a/sys/dev/sound/pcm/dsp.c 126 +++ b/sys/dev/sound/pcm/dsp.c 127 @@ -965,6 +965,7 @@ dsp_ioctl_channel(struct cdev *dev, struct pcm_channel *volch, u_long cmd, 128 struct snddev_info *d; 129 struct pcm_channel *rdch, *wrch; 130 int j, devtype, ret; 131 + int left, right, center, mute; 132 133 d = dsp_get_info(dev); 134 if (!PCM_REGISTERED(d) || !(dsp_get_flags(dev) & SD_F_VPC)) 135 @@ -1003,67 +1004,95 @@ dsp_ioctl_channel(struct cdev *dev, struct pcm_channel *volch, u_long cmd, 136 } 137 138 /* Final validation */ 139 - if (volch != NULL) { 140 - CHN_LOCK(volch); 141 - if (!(volch->feederflags & (1 << FEEDER_VOLUME))) { 142 - CHN_UNLOCK(volch); 143 - return (-1); 144 - } 145 - if (volch->direction == PCMDIR_PLAY) 146 - wrch = volch; 147 - else 148 - rdch = volch; 149 - } 150 - 151 - ret = EINVAL; 152 + if (volch == NULL) 153 + return (EINVAL); 154 155 - if (volch != NULL && 156 - ((j == SOUND_MIXER_PCM && volch->direction == PCMDIR_PLAY) || 157 - (j == SOUND_MIXER_RECLEV && volch->direction == PCMDIR_REC))) { 158 - if ((cmd & ~0xff) == MIXER_WRITE(0)) { 159 - int left, right, center; 160 + CHN_LOCK(volch); 161 + if (!(volch->feederflags & (1 << FEEDER_VOLUME))) { 162 + CHN_UNLOCK(volch); 163 + return (EINVAL); 164 + } 165 166 + switch (cmd & ~0xff) { 167 + case MIXER_WRITE(0): 168 + switch (j) { 169 + case SOUND_MIXER_MUTE: 170 + if (volch->direction == PCMDIR_REC) { 171 + chn_setmute_multi(volch, SND_VOL_C_PCM, (*(int *)arg & SOUND_MASK_RECLEV) != 0); 172 + } else { 173 + chn_setmute_multi(volch, SND_VOL_C_PCM, (*(int *)arg & SOUND_MASK_PCM) != 0); 174 + } 175 + break; 176 + case SOUND_MIXER_PCM: 177 + if (volch->direction != PCMDIR_PLAY) 178 + break; 179 left = *(int *)arg & 0x7f; 180 right = ((*(int *)arg) >> 8) & 0x7f; 181 center = (left + right) >> 1; 182 - chn_setvolume_multi(volch, SND_VOL_C_PCM, left, right, 183 - center); 184 - } else if ((cmd & ~0xff) == MIXER_READ(0)) { 185 - *(int *)arg = CHN_GETVOLUME(volch, 186 - SND_VOL_C_PCM, SND_CHN_T_FL); 187 - *(int *)arg |= CHN_GETVOLUME(volch, 188 - SND_VOL_C_PCM, SND_CHN_T_FR) << 8; 189 + chn_setvolume_multi(volch, SND_VOL_C_PCM, 190 + left, right, center); 191 + break; 192 + case SOUND_MIXER_RECLEV: 193 + if (volch->direction != PCMDIR_REC) 194 + break; 195 + left = *(int *)arg & 0x7f; 196 + right = ((*(int *)arg) >> 8) & 0x7f; 197 + center = (left + right) >> 1; 198 + chn_setvolume_multi(volch, SND_VOL_C_PCM, 199 + left, right, center); 200 + break; 201 + default: 202 + /* ignore all other mixer writes */ 203 + break; 204 } 205 - ret = 0; 206 - } else if (rdch != NULL || wrch != NULL) { 207 + break; 208 + 209 + case MIXER_READ(0): 210 switch (j) { 211 + case SOUND_MIXER_MUTE: 212 + mute = CHN_GETMUTE(volch, SND_VOL_C_PCM, SND_CHN_T_FL) || 213 + CHN_GETMUTE(volch, SND_VOL_C_PCM, SND_CHN_T_FR); 214 + if (volch->direction == PCMDIR_REC) { 215 + *(int *)arg = mute << SOUND_MIXER_RECLEV; 216 + } else { 217 + *(int *)arg = mute << SOUND_MIXER_PCM; 218 + } 219 + break; 220 + case SOUND_MIXER_PCM: 221 + if (volch->direction != PCMDIR_PLAY) 222 + break; 223 + *(int *)arg = CHN_GETVOLUME(volch, 224 + SND_VOL_C_PCM, SND_CHN_T_FL); 225 + *(int *)arg |= CHN_GETVOLUME(volch, 226 + SND_VOL_C_PCM, SND_CHN_T_FR) << 8; 227 + break; 228 + case SOUND_MIXER_RECLEV: 229 + if (volch->direction != PCMDIR_REC) 230 + break; 231 + *(int *)arg = CHN_GETVOLUME(volch, 232 + SND_VOL_C_PCM, SND_CHN_T_FL); 233 + *(int *)arg |= CHN_GETVOLUME(volch, 234 + SND_VOL_C_PCM, SND_CHN_T_FR) << 8; 235 + break; 236 case SOUND_MIXER_DEVMASK: 237 case SOUND_MIXER_CAPS: 238 case SOUND_MIXER_STEREODEVS: 239 - if ((cmd & ~0xff) == MIXER_READ(0)) { 240 - *(int *)arg = 0; 241 - if (rdch != NULL) 242 - *(int *)arg |= SOUND_MASK_RECLEV; 243 - if (wrch != NULL) 244 - *(int *)arg |= SOUND_MASK_PCM; 245 - } 246 - ret = 0; 247 - break; 248 - case SOUND_MIXER_RECMASK: 249 - case SOUND_MIXER_RECSRC: 250 - if ((cmd & ~0xff) == MIXER_READ(0)) 251 - *(int *)arg = 0; 252 - ret = 0; 253 + if (volch->direction == PCMDIR_REC) 254 + *(int *)arg = SOUND_MASK_RECLEV; 255 + else 256 + *(int *)arg = SOUND_MASK_PCM; 257 break; 258 default: 259 + *(int *)arg = 0; 260 break; 261 } 262 - } 263 - 264 - if (volch != NULL) 265 - CHN_UNLOCK(volch); 266 + break; 267 268 - return (ret); 269 + default: 270 + break; 271 + } 272 + CHN_UNLOCK(volch); 273 + return (0); 274 } 275 276 static int 277 @@ -2294,8 +2323,7 @@ dsp_stdclone(char *name, char *namep, char *sep, int use_sep, int *u, int *c) 278 size_t len; 279 280 len = strlen(namep); 281 - 282 - if (bcmp(name, namep, len) != 0) 283 + if (strncmp(name, namep, len) != 0) 284 return (ENODEV); 285 286 name += len; 287 diff --git a/sys/dev/sound/pcm/feeder_volume.c b/sys/dev/sound/pcm/feeder_volume.c 288 index 322d7f6b2c8..2312bd89c9d 100644 289 --- a/sys/dev/sound/pcm/feeder_volume.c 290 +++ b/sys/dev/sound/pcm/feeder_volume.c 291 @@ -237,10 +237,13 @@ static int 292 feed_volume_feed(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, 293 uint32_t count, void *source) 294 { 295 + int temp_vol[SND_CHN_T_VOL_MAX]; 296 struct feed_volume_info *info; 297 uint32_t j, align; 298 - int i, *vol, *matrix; 299 + int i, *matrix; 300 uint8_t *dst; 301 + const int16_t *vol; 302 + const int8_t *muted; 303 304 /* 305 * Fetch filter data operation. 306 @@ -251,6 +254,7 @@ feed_volume_feed(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, 307 return (FEEDER_FEED(f->source, c, b, count, source)); 308 309 vol = c->volume[SND_VOL_C_VAL(info->volume_class)]; 310 + muted = c->muted[SND_VOL_C_VAL(info->volume_class)]; 311 matrix = info->matrix; 312 313 /* 314 @@ -258,17 +262,22 @@ feed_volume_feed(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, 315 */ 316 j = 0; 317 i = info->channels; 318 - do { 319 - if (vol[matrix[--i]] != SND_VOL_FLAT) { 320 + while (i--) { 321 + if (vol[matrix[i]] != SND_VOL_FLAT || 322 + muted[matrix[i]] != 0) { 323 j = 1; 324 break; 325 } 326 - } while (i != 0); 327 + } 328 329 /* Nope, just bypass entirely. */ 330 if (j == 0) 331 return (FEEDER_FEED(f->source, c, b, count, source)); 332 333 + /* Check if any controls are muted. */ 334 + for (j = 0; j != SND_CHN_T_VOL_MAX; j++) 335 + temp_vol[j] = muted[j] ? 0 : vol[j]; 336 + 337 dst = b; 338 align = info->bps * info->channels; 339 340 @@ -281,7 +290,7 @@ feed_volume_feed(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, 341 if (j == 0) 342 break; 343 344 - info->apply(vol, matrix, info->channels, dst, j); 345 + info->apply(temp_vol, matrix, info->channels, dst, j); 346 347 j *= align; 348 dst += j; 349 diff --git a/sys/dev/sound/pcm/mixer.c b/sys/dev/sound/pcm/mixer.c 350 index 09b0bb8ab14..89e78b036e9 100644 351 --- a/sys/dev/sound/pcm/mixer.c 352 +++ b/sys/dev/sound/pcm/mixer.c 353 @@ -51,16 +51,16 @@ struct snd_mixer { 354 KOBJ_FIELDS; 355 void *devinfo; 356 int busy; 357 - int hwvol_muted; 358 int hwvol_mixer; 359 int hwvol_step; 360 int type; 361 device_t dev; 362 - u_int32_t hwvol_mute_level; 363 u_int32_t devs; 364 + u_int32_t mutedevs; 365 u_int32_t recdevs; 366 u_int32_t recsrc; 367 u_int16_t level[32]; 368 + u_int16_t level_muted[32]; 369 u_int8_t parent[32]; 370 u_int32_t child[32]; 371 u_int8_t realdev[32]; 372 @@ -244,7 +244,7 @@ mixer_set_eq(struct snd_mixer *m, struct snddev_info *d, 373 } 374 375 static int 376 -mixer_set(struct snd_mixer *m, u_int dev, u_int lev) 377 +mixer_set(struct snd_mixer *m, u_int dev, u_int32_t muted, u_int lev) 378 { 379 struct snddev_info *d; 380 u_int l, r, tl, tr; 381 @@ -254,7 +254,7 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev) 382 383 if (m == NULL || dev >= SOUND_MIXER_NRDEVICES || 384 (0 == (m->devs & (1 << dev)))) 385 - return -1; 386 + return (-1); 387 388 l = min((lev & 0x00ff), 100); 389 r = min(((lev & 0xff00) >> 8), 100); 390 @@ -262,7 +262,7 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev) 391 392 d = device_get_softc(m->dev); 393 if (d == NULL) 394 - return -1; 395 + return (-1); 396 397 /* It is safe to drop this mutex due to Giant. */ 398 if (!(d->flags & SD_F_MPSAFE) && mtx_owned(m->lock) != 0) 399 @@ -270,6 +270,11 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev) 400 else 401 dropmtx = 0; 402 403 + /* Allow the volume to be "changed" while muted. */ 404 + if (muted & (1 << dev)) { 405 + m->level_muted[dev] = l | (r << 8); 406 + return (0); 407 + } 408 MIXER_SET_UNLOCK(m, dropmtx); 409 410 /* TODO: recursive handling */ 411 @@ -287,7 +292,7 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev) 412 else if (realdev != SOUND_MIXER_NONE && 413 MIXER_SET(m, realdev, tl, tr) < 0) { 414 MIXER_SET_LOCK(m, dropmtx); 415 - return -1; 416 + return (-1); 417 } 418 } else if (child != 0) { 419 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 420 @@ -305,8 +310,8 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev) 421 realdev = m->realdev[dev]; 422 if (realdev != SOUND_MIXER_NONE && 423 MIXER_SET(m, realdev, l, r) < 0) { 424 - MIXER_SET_LOCK(m, dropmtx); 425 - return -1; 426 + MIXER_SET_LOCK(m, dropmtx); 427 + return (-1); 428 } 429 } else { 430 if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL)) 431 @@ -317,7 +322,7 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev) 432 else if (realdev != SOUND_MIXER_NONE && 433 MIXER_SET(m, realdev, l, r) < 0) { 434 MIXER_SET_LOCK(m, dropmtx); 435 - return -1; 436 + return (-1); 437 } 438 } 439 440 @@ -326,16 +331,42 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev) 441 m->level[dev] = l | (r << 8); 442 m->modify_counter++; 443 444 - return 0; 445 + return (0); 446 } 447 448 static int 449 mixer_get(struct snd_mixer *mixer, int dev) 450 { 451 - if ((dev < SOUND_MIXER_NRDEVICES) && (mixer->devs & (1 << dev))) 452 - return mixer->level[dev]; 453 - else 454 - return -1; 455 + if ((dev < SOUND_MIXER_NRDEVICES) && (mixer->devs & (1 << dev))) { 456 + if (mixer->mutedevs & (1 << dev)) 457 + return (mixer->level_muted[dev]); 458 + else 459 + return (mixer->level[dev]); 460 + } else { 461 + return (-1); 462 + } 463 +} 464 + 465 +void 466 +mix_setmutedevs(struct snd_mixer *mixer, u_int32_t mutedevs) 467 +{ 468 + u_int32_t delta; 469 + 470 + /* Filter out invalid values. */ 471 + mutedevs &= mixer->devs; 472 + delta = (mixer->mutedevs ^ mutedevs) & mixer->devs; 473 + mixer->mutedevs = mutedevs; 474 + 475 + for (int i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 476 + if (!(delta & (1 << i))) 477 + continue; 478 + if (mutedevs & (1 << i)) { 479 + mixer->level_muted[i] = mixer->level[i]; 480 + mixer_set(mixer, i, 0, 0); 481 + } else { 482 + mixer_set(mixer, i, 0, mixer->level_muted[i]); 483 + } 484 + } 485 } 486 487 static int 488 @@ -598,6 +629,12 @@ mix_getdevs(struct snd_mixer *m) 489 return m->devs; 490 } 491 492 +u_int32_t 493 +mix_getmutedevs(struct snd_mixer *m) 494 +{ 495 + return m->mutedevs; 496 +} 497 + 498 u_int32_t 499 mix_getrecdevs(struct snd_mixer *m) 500 { 501 @@ -721,7 +758,7 @@ mixer_init(device_t dev, kobj_class_t cls, void *devinfo) 502 } 503 } 504 505 - mixer_set(m, i, v | (v << 8)); 506 + mixer_set(m, i, 0, v | (v << 8)); 507 } 508 509 mixer_setrecsrc(m, 0); /* Set default input. */ 510 @@ -799,7 +836,7 @@ mixer_uninit(device_t dev) 511 snd_mtxlock(m->lock); 512 513 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 514 - mixer_set(m, i, 0); 515 + mixer_set(m, i, 0, 0); 516 517 mixer_setrecsrc(m, SOUND_MASK_MIC); 518 519 @@ -836,8 +873,12 @@ mixer_reinit(device_t dev) 520 return i; 521 } 522 523 - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 524 - mixer_set(m, i, m->level[i]); 525 + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 526 + if (m->mutedevs & (1 << i)) 527 + mixer_set(m, i, 0, 0); 528 + else 529 + mixer_set(m, i, 0, m->level[i]); 530 + } 531 532 mixer_setrecsrc(m, m->recsrc); 533 snd_mtxunlock(m->lock); 534 @@ -863,10 +904,8 @@ sysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS) 535 if (dev == -1) { 536 snd_mtxunlock(m->lock); 537 return EINVAL; 538 - } 539 - else if (dev != m->hwvol_mixer) { 540 + } else { 541 m->hwvol_mixer = dev; 542 - m->hwvol_muted = 0; 543 } 544 } 545 snd_mtxunlock(m->lock); 546 @@ -897,14 +936,7 @@ mixer_hwvol_init(device_t dev) 547 void 548 mixer_hwvol_mute_locked(struct snd_mixer *m) 549 { 550 - if (m->hwvol_muted) { 551 - m->hwvol_muted = 0; 552 - mixer_set(m, m->hwvol_mixer, m->hwvol_mute_level); 553 - } else { 554 - m->hwvol_muted++; 555 - m->hwvol_mute_level = mixer_get(m, m->hwvol_mixer); 556 - mixer_set(m, m->hwvol_mixer, 0); 557 - } 558 + mix_setmutedevs(m, m->mutedevs ^ (1 << m->hwvol_mixer)); 559 } 560 561 void 562 @@ -925,11 +957,8 @@ mixer_hwvol_step_locked(struct snd_mixer *m, int left_step, int right_step) 563 { 564 int level, left, right; 565 566 - if (m->hwvol_muted) { 567 - m->hwvol_muted = 0; 568 - level = m->hwvol_mute_level; 569 - } else 570 - level = mixer_get(m, m->hwvol_mixer); 571 + level = mixer_get(m, m->hwvol_mixer); 572 + 573 if (level != -1) { 574 left = level & 0xff; 575 right = (level >> 8) & 0xff; 576 @@ -943,7 +972,8 @@ mixer_hwvol_step_locked(struct snd_mixer *m, int left_step, int right_step) 577 right = 0; 578 else if (right > 100) 579 right = 100; 580 - mixer_set(m, m->hwvol_mixer, left | right << 8); 581 + 582 + mixer_set(m, m->hwvol_mixer, m->mutedevs, left | right << 8); 583 } 584 } 585 586 @@ -976,7 +1006,7 @@ mix_set(struct snd_mixer *m, u_int dev, u_int left, u_int right) 587 KASSERT(m != NULL, ("NULL snd_mixer")); 588 589 snd_mtxlock(m->lock); 590 - ret = mixer_set(m, dev, left | (right << 8)); 591 + ret = mixer_set(m, dev, m->mutedevs, left | (right << 8)); 592 snd_mtxunlock(m->lock); 593 594 return ((ret != 0) ? ENXIO : 0); 595 @@ -1304,10 +1334,18 @@ mixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, 596 goto done; 597 } 598 if ((cmd & ~0xff) == MIXER_WRITE(0)) { 599 - if (j == SOUND_MIXER_RECSRC) 600 + switch (j) { 601 + case SOUND_MIXER_RECSRC: 602 ret = mixer_setrecsrc(m, *arg_i); 603 - else 604 - ret = mixer_set(m, j, *arg_i); 605 + break; 606 + case SOUND_MIXER_MUTE: 607 + mix_setmutedevs(m, *arg_i); 608 + ret = 0; 609 + break; 610 + default: 611 + ret = mixer_set(m, j, m->mutedevs, *arg_i); 612 + break; 613 + } 614 snd_mtxunlock(m->lock); 615 return ((ret == 0) ? 0 : ENXIO); 616 } 617 @@ -1318,6 +1356,9 @@ mixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, 618 case SOUND_MIXER_STEREODEVS: 619 v = mix_getdevs(m); 620 break; 621 + case SOUND_MIXER_MUTE: 622 + v = mix_getmutedevs(m); 623 + break; 624 case SOUND_MIXER_RECMASK: 625 v = mix_getrecdevs(m); 626 break; 627 @@ -1326,6 +1367,7 @@ mixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, 628 break; 629 default: 630 v = mixer_get(m, j); 631 + break; 632 } 633 *arg_i = v; 634 snd_mtxunlock(m->lock); 635 @@ -1554,5 +1596,5 @@ mix_set_locked(struct snd_mixer *m, u_int dev, int left, int right) 636 637 level = (left & 0xFF) | ((right & 0xFF) << 8); 638 639 - return (mixer_set(m, dev, level)); 640 + return (mixer_set(m, dev, m->mutedevs, level)); 641 } 642 diff --git a/sys/dev/sound/pcm/mixer.h b/sys/dev/sound/pcm/mixer.h 643 index 8e11d553a3e..7857609b289 100644 644 --- a/sys/dev/sound/pcm/mixer.h 645 +++ b/sys/dev/sound/pcm/mixer.h 646 @@ -60,8 +60,10 @@ device_t mix_get_dev(struct snd_mixer *m); 647 648 void mix_setdevs(struct snd_mixer *m, u_int32_t v); 649 void mix_setrecdevs(struct snd_mixer *m, u_int32_t v); 650 +void mix_setmutedevs(struct snd_mixer *m, u_int32_t v); 651 u_int32_t mix_getdevs(struct snd_mixer *m); 652 u_int32_t mix_getrecdevs(struct snd_mixer *m); 653 +u_int32_t mix_getmutedevs(struct snd_mixer *m); 654 void mix_setparentchild(struct snd_mixer *m, u_int32_t parent, u_int32_t childs); 655 void mix_setrealdev(struct snd_mixer *m, u_int32_t dev, u_int32_t realdev); 656 u_int32_t mix_getparent(struct snd_mixer *m, u_int32_t dev); 657 diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c 658 index 299e4937f8e..663ec84f93b 100644 659 --- a/sys/dev/sound/pcm/sound.c 660 +++ b/sys/dev/sound/pcm/sound.c 661 @@ -1015,12 +1015,30 @@ SYSCTL_PROC(_hw_snd, OID_AUTO, clone_gc, 662 "global clone garbage collector"); 663 #endif 664 665 +static u_int8_t 666 +pcm_mode_init(struct snddev_info *d) 667 +{ 668 + u_int8_t mode = 0; 669 + 670 + if (d->playcount > 0) 671 + mode |= PCM_MODE_PLAY; 672 + if (d->reccount > 0) 673 + mode |= PCM_MODE_REC; 674 + if (d->mixer_dev != NULL) 675 + mode |= PCM_MODE_MIXER; 676 + 677 + return (mode); 678 +} 679 + 680 static void 681 pcm_sysinit(device_t dev) 682 { 683 struct snddev_info *d = device_get_softc(dev); 684 + u_int8_t mode; 685 + 686 + mode = pcm_mode_init(d); 687 688 - /* XXX: an user should be able to set this with a control tool, the 689 + /* XXX: a user should be able to set this with a control tool, the 690 sysadmin then needs min+max sysctls for this */ 691 SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 692 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 693 @@ -1030,6 +1048,11 @@ pcm_sysinit(device_t dev) 694 "bitperfect", CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, d, 695 sizeof(d), sysctl_dev_pcm_bitperfect, "I", 696 "bit-perfect playback/recording (0=disable, 1=enable)"); 697 + SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 698 + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 699 + OID_AUTO, "mode", CTLFLAG_RD, NULL, mode, 700 + "mode (1=mixer, 2=play, 4=rec. The values are OR'ed if more than one" 701 + "mode is supported)"); 702 #ifdef SND_DEBUG 703 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 704 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 705 @@ -1133,7 +1156,7 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec) 706 sysctl_ctx_init(&d->rec_sysctl_ctx); 707 d->rec_sysctl_tree = SYSCTL_ADD_NODE(&d->rec_sysctl_ctx, 708 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "rec", 709 - CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "record channels node"); 710 + CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "recording channels node"); 711 712 if (numplay > 0 || numrec > 0) 713 d->flags |= SD_F_AUTOVCHAN; 714 diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h 715 index cdae5e837cd..62787a3e689 100644 716 --- a/sys/dev/sound/pcm/sound.h 717 +++ b/sys/dev/sound/pcm/sound.h 718 @@ -411,6 +411,10 @@ struct snddev_info { 719 void sound_oss_sysinfo(oss_sysinfo *); 720 int sound_oss_card_info(oss_card_info *); 721 722 +#define PCM_MODE_MIXER 0x01 723 +#define PCM_MODE_PLAY 0x02 724 +#define PCM_MODE_REC 0x04 725 + 726 #define PCM_LOCKOWNED(d) mtx_owned((d)->lock) 727 #define PCM_LOCK(d) mtx_lock((d)->lock) 728 #define PCM_UNLOCK(d) mtx_unlock((d)->lock)