diff options
| author | Clemens Ladisch <clemens@ladisch.de> | 2008-01-28 02:35:20 -0500 |
|---|---|---|
| committer | Jaroslav Kysela <perex@perex.cz> | 2008-01-31 11:30:17 -0500 |
| commit | a3601560496d7b46d2d1187169824d11570ff63a (patch) | |
| tree | abcb52cdea5f118815994895b2375ad000fc4d24 /sound | |
| parent | 1e821dd2763c97df1a0a451e553d218cb8886cd7 (diff) | |
[ALSA] oxygen: add front panel controls
Add mixer controls for the front panel AC97 codec.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound')
| -rw-r--r-- | sound/pci/oxygen/oxygen.h | 2 | ||||
| -rw-r--r-- | sound/pci/oxygen/oxygen_lib.c | 3 | ||||
| -rw-r--r-- | sound/pci/oxygen/oxygen_mixer.c | 117 | ||||
| -rw-r--r-- | sound/pci/oxygen/virtuoso.c | 4 |
4 files changed, 100 insertions, 26 deletions
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index 55ce2448805d..e71c53498995 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h | |||
| @@ -86,7 +86,7 @@ struct oxygen_model { | |||
| 86 | struct snd_pcm_hw_params *params); | 86 | struct snd_pcm_hw_params *params); |
| 87 | void (*update_dac_volume)(struct oxygen *chip); | 87 | void (*update_dac_volume)(struct oxygen *chip); |
| 88 | void (*update_dac_mute)(struct oxygen *chip); | 88 | void (*update_dac_mute)(struct oxygen *chip); |
| 89 | void (*ac97_switch_hook)(struct oxygen *chip, | 89 | void (*ac97_switch_hook)(struct oxygen *chip, unsigned int codec, |
| 90 | unsigned int reg, int mute); | 90 | unsigned int reg, int mute); |
| 91 | size_t model_data_size; | 91 | size_t model_data_size; |
| 92 | u8 dac_channels; | 92 | u8 dac_channels; |
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index de6bf41c3e96..540e56b75794 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c | |||
| @@ -365,8 +365,7 @@ static void __devinit oxygen_init(struct oxygen *chip) | |||
| 365 | oxygen_write_ac97(chip, 1, AC97_AUX, 0x8808); | 365 | oxygen_write_ac97(chip, 1, AC97_AUX, 0x8808); |
| 366 | oxygen_write_ac97(chip, 1, AC97_PCM, 0x0808); | 366 | oxygen_write_ac97(chip, 1, AC97_PCM, 0x0808); |
| 367 | oxygen_write_ac97(chip, 1, AC97_REC_SEL, 0x0000); | 367 | oxygen_write_ac97(chip, 1, AC97_REC_SEL, 0x0000); |
| 368 | oxygen_write_ac97(chip, 1, AC97_REC_GAIN, 0x8000); | 368 | oxygen_write_ac97(chip, 1, AC97_REC_GAIN, 0x0000); |
| 369 | oxygen_ac97_clear_bits(chip, 1, AC97_REC_GAIN, 0x1c00); | ||
| 370 | oxygen_ac97_set_bits(chip, 1, 0x6a, 0x0040); | 369 | oxygen_ac97_set_bits(chip, 1, 0x6a, 0x0040); |
| 371 | } | 370 | } |
| 372 | } | 371 | } |
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index cf34b1229b0b..a8e4623415d9 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c | |||
| @@ -450,13 +450,14 @@ static int ac97_switch_get(struct snd_kcontrol *ctl, | |||
| 450 | struct snd_ctl_elem_value *value) | 450 | struct snd_ctl_elem_value *value) |
| 451 | { | 451 | { |
| 452 | struct oxygen *chip = ctl->private_data; | 452 | struct oxygen *chip = ctl->private_data; |
| 453 | unsigned int codec = (ctl->private_value >> 24) & 1; | ||
| 453 | unsigned int index = ctl->private_value & 0xff; | 454 | unsigned int index = ctl->private_value & 0xff; |
| 454 | unsigned int bitnr = (ctl->private_value >> 8) & 0xff; | 455 | unsigned int bitnr = (ctl->private_value >> 8) & 0xff; |
| 455 | int invert = ctl->private_value & (1 << 16); | 456 | int invert = ctl->private_value & (1 << 16); |
| 456 | u16 reg; | 457 | u16 reg; |
| 457 | 458 | ||
| 458 | mutex_lock(&chip->mutex); | 459 | mutex_lock(&chip->mutex); |
| 459 | reg = oxygen_read_ac97(chip, 0, index); | 460 | reg = oxygen_read_ac97(chip, codec, index); |
| 460 | mutex_unlock(&chip->mutex); | 461 | mutex_unlock(&chip->mutex); |
| 461 | if (!(reg & (1 << bitnr)) ^ !invert) | 462 | if (!(reg & (1 << bitnr)) ^ !invert) |
| 462 | value->value.integer.value[0] = 1; | 463 | value->value.integer.value[0] = 1; |
| @@ -469,6 +470,7 @@ static int ac97_switch_put(struct snd_kcontrol *ctl, | |||
| 469 | struct snd_ctl_elem_value *value) | 470 | struct snd_ctl_elem_value *value) |
| 470 | { | 471 | { |
| 471 | struct oxygen *chip = ctl->private_data; | 472 | struct oxygen *chip = ctl->private_data; |
| 473 | unsigned int codec = (ctl->private_value >> 24) & 1; | ||
| 472 | unsigned int index = ctl->private_value & 0xff; | 474 | unsigned int index = ctl->private_value & 0xff; |
| 473 | unsigned int bitnr = (ctl->private_value >> 8) & 0xff; | 475 | unsigned int bitnr = (ctl->private_value >> 8) & 0xff; |
| 474 | int invert = ctl->private_value & (1 << 16); | 476 | int invert = ctl->private_value & (1 << 16); |
| @@ -476,7 +478,7 @@ static int ac97_switch_put(struct snd_kcontrol *ctl, | |||
| 476 | int change; | 478 | int change; |
| 477 | 479 | ||
| 478 | mutex_lock(&chip->mutex); | 480 | mutex_lock(&chip->mutex); |
| 479 | oldreg = oxygen_read_ac97(chip, 0, index); | 481 | oldreg = oxygen_read_ac97(chip, codec, index); |
| 480 | newreg = oldreg; | 482 | newreg = oldreg; |
| 481 | if (!value->value.integer.value[0] ^ !invert) | 483 | if (!value->value.integer.value[0] ^ !invert) |
| 482 | newreg |= 1 << bitnr; | 484 | newreg |= 1 << bitnr; |
| @@ -484,9 +486,9 @@ static int ac97_switch_put(struct snd_kcontrol *ctl, | |||
| 484 | newreg &= ~(1 << bitnr); | 486 | newreg &= ~(1 << bitnr); |
| 485 | change = newreg != oldreg; | 487 | change = newreg != oldreg; |
| 486 | if (change) { | 488 | if (change) { |
| 487 | oxygen_write_ac97(chip, 0, index, newreg); | 489 | oxygen_write_ac97(chip, codec, index, newreg); |
| 488 | if (bitnr == 15 && chip->model->ac97_switch_hook) | 490 | if (bitnr == 15 && chip->model->ac97_switch_hook) |
| 489 | chip->model->ac97_switch_hook(chip, index, | 491 | chip->model->ac97_switch_hook(chip, codec, index, |
| 490 | newreg & 0x8000); | 492 | newreg & 0x8000); |
| 491 | } | 493 | } |
| 492 | mutex_unlock(&chip->mutex); | 494 | mutex_unlock(&chip->mutex); |
| @@ -507,11 +509,12 @@ static int ac97_volume_get(struct snd_kcontrol *ctl, | |||
| 507 | struct snd_ctl_elem_value *value) | 509 | struct snd_ctl_elem_value *value) |
| 508 | { | 510 | { |
| 509 | struct oxygen *chip = ctl->private_data; | 511 | struct oxygen *chip = ctl->private_data; |
| 510 | unsigned int index = ctl->private_value; | 512 | unsigned int codec = (ctl->private_value >> 24) & 1; |
| 513 | unsigned int index = ctl->private_value & 0xff; | ||
| 511 | u16 reg; | 514 | u16 reg; |
| 512 | 515 | ||
| 513 | mutex_lock(&chip->mutex); | 516 | mutex_lock(&chip->mutex); |
| 514 | reg = oxygen_read_ac97(chip, 0, index); | 517 | reg = oxygen_read_ac97(chip, codec, index); |
| 515 | mutex_unlock(&chip->mutex); | 518 | mutex_unlock(&chip->mutex); |
| 516 | value->value.integer.value[0] = 31 - (reg & 0x1f); | 519 | value->value.integer.value[0] = 31 - (reg & 0x1f); |
| 517 | value->value.integer.value[1] = 31 - ((reg >> 8) & 0x1f); | 520 | value->value.integer.value[1] = 31 - ((reg >> 8) & 0x1f); |
| @@ -522,12 +525,13 @@ static int ac97_volume_put(struct snd_kcontrol *ctl, | |||
| 522 | struct snd_ctl_elem_value *value) | 525 | struct snd_ctl_elem_value *value) |
| 523 | { | 526 | { |
| 524 | struct oxygen *chip = ctl->private_data; | 527 | struct oxygen *chip = ctl->private_data; |
| 525 | unsigned int index = ctl->private_value; | 528 | unsigned int codec = (ctl->private_value >> 24) & 1; |
| 529 | unsigned int index = ctl->private_value & 0xff; | ||
| 526 | u16 oldreg, newreg; | 530 | u16 oldreg, newreg; |
| 527 | int change; | 531 | int change; |
| 528 | 532 | ||
| 529 | mutex_lock(&chip->mutex); | 533 | mutex_lock(&chip->mutex); |
| 530 | oldreg = oxygen_read_ac97(chip, 0, index); | 534 | oldreg = oxygen_read_ac97(chip, codec, index); |
| 531 | newreg = oldreg; | 535 | newreg = oldreg; |
| 532 | newreg = (newreg & ~0x1f) | | 536 | newreg = (newreg & ~0x1f) | |
| 533 | (31 - (value->value.integer.value[0] & 0x1f)); | 537 | (31 - (value->value.integer.value[0] & 0x1f)); |
| @@ -535,30 +539,77 @@ static int ac97_volume_put(struct snd_kcontrol *ctl, | |||
| 535 | ((31 - (value->value.integer.value[0] & 0x1f)) << 8); | 539 | ((31 - (value->value.integer.value[0] & 0x1f)) << 8); |
| 536 | change = newreg != oldreg; | 540 | change = newreg != oldreg; |
| 537 | if (change) | 541 | if (change) |
| 538 | oxygen_write_ac97(chip, 0, index, newreg); | 542 | oxygen_write_ac97(chip, codec, index, newreg); |
| 539 | mutex_unlock(&chip->mutex); | 543 | mutex_unlock(&chip->mutex); |
| 540 | return change; | 544 | return change; |
| 541 | } | 545 | } |
| 542 | 546 | ||
| 543 | #define AC97_SWITCH(xname, index, bitnr, invert) { \ | 547 | static int ac97_fp_rec_volume_info(struct snd_kcontrol *ctl, |
| 548 | struct snd_ctl_elem_info *info) | ||
| 549 | { | ||
| 550 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 551 | info->count = 2; | ||
| 552 | info->value.integer.min = 0; | ||
| 553 | info->value.integer.max = 7; | ||
| 554 | return 0; | ||
| 555 | } | ||
| 556 | |||
| 557 | static int ac97_fp_rec_volume_get(struct snd_kcontrol *ctl, | ||
| 558 | struct snd_ctl_elem_value *value) | ||
| 559 | { | ||
| 560 | struct oxygen *chip = ctl->private_data; | ||
| 561 | u16 reg; | ||
| 562 | |||
| 563 | mutex_lock(&chip->mutex); | ||
| 564 | reg = oxygen_read_ac97(chip, 1, AC97_REC_GAIN); | ||
| 565 | mutex_unlock(&chip->mutex); | ||
| 566 | value->value.integer.value[0] = reg & 7; | ||
| 567 | value->value.integer.value[1] = (reg >> 8) & 7; | ||
| 568 | return 0; | ||
| 569 | } | ||
| 570 | |||
| 571 | static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl, | ||
| 572 | struct snd_ctl_elem_value *value) | ||
| 573 | { | ||
| 574 | struct oxygen *chip = ctl->private_data; | ||
| 575 | u16 oldreg, newreg; | ||
| 576 | int change; | ||
| 577 | |||
| 578 | mutex_lock(&chip->mutex); | ||
| 579 | oldreg = oxygen_read_ac97(chip, 1, AC97_REC_GAIN); | ||
| 580 | newreg = oldreg & ~0x0707; | ||
| 581 | newreg = newreg | (value->value.integer.value[0] & 7); | ||
| 582 | newreg = newreg | ((value->value.integer.value[0] & 7) << 8); | ||
| 583 | change = newreg != oldreg; | ||
| 584 | if (change) | ||
| 585 | oxygen_write_ac97(chip, 1, AC97_REC_GAIN, newreg); | ||
| 586 | mutex_unlock(&chip->mutex); | ||
| 587 | return change; | ||
| 588 | } | ||
| 589 | |||
| 590 | #define AC97_SWITCH(xname, codec, index, bitnr, invert) { \ | ||
| 544 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | 591 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
| 545 | .name = xname, \ | 592 | .name = xname, \ |
| 546 | .info = snd_ctl_boolean_mono_info, \ | 593 | .info = snd_ctl_boolean_mono_info, \ |
| 547 | .get = ac97_switch_get, \ | 594 | .get = ac97_switch_get, \ |
| 548 | .put = ac97_switch_put, \ | 595 | .put = ac97_switch_put, \ |
| 549 | .private_value = ((invert) << 16) | ((bitnr) << 8) | (index), \ | 596 | .private_value = ((codec) << 24) | ((invert) << 16) | \ |
| 597 | ((bitnr) << 8) | (index), \ | ||
| 550 | } | 598 | } |
| 551 | #define AC97_VOLUME(xname, index) { \ | 599 | #define AC97_VOLUME(xname, codec, index) { \ |
| 552 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | 600 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
| 553 | .name = xname, \ | 601 | .name = xname, \ |
| 602 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
| 603 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
| 554 | .info = ac97_volume_info, \ | 604 | .info = ac97_volume_info, \ |
| 555 | .get = ac97_volume_get, \ | 605 | .get = ac97_volume_get, \ |
| 556 | .put = ac97_volume_put, \ | 606 | .put = ac97_volume_put, \ |
| 557 | .tlv = { .p = ac97_db_scale, }, \ | 607 | .tlv = { .p = ac97_db_scale, }, \ |
| 558 | .private_value = (index), \ | 608 | .private_value = ((codec) << 24) | (index), \ |
| 559 | } | 609 | } |
| 560 | 610 | ||
| 561 | static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0); | 611 | static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0); |
| 612 | static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0); | ||
| 562 | 613 | ||
| 563 | static const struct snd_kcontrol_new controls[] = { | 614 | static const struct snd_kcontrol_new controls[] = { |
| 564 | { | 615 | { |
| @@ -642,15 +693,31 @@ static const struct snd_kcontrol_new controls[] = { | |||
| 642 | }; | 693 | }; |
| 643 | 694 | ||
| 644 | static const struct snd_kcontrol_new ac97_controls[] = { | 695 | static const struct snd_kcontrol_new ac97_controls[] = { |
| 645 | AC97_VOLUME("Mic Capture Volume", AC97_MIC), | 696 | AC97_VOLUME("Mic Capture Volume", 0, AC97_MIC), |
| 646 | AC97_SWITCH("Mic Capture Switch", AC97_MIC, 15, 1), | 697 | AC97_SWITCH("Mic Capture Switch", 0, AC97_MIC, 15, 1), |
| 647 | AC97_SWITCH("Mic Boost (+20dB)", AC97_MIC, 6, 0), | 698 | AC97_SWITCH("Mic Boost (+20dB)", 0, AC97_MIC, 6, 0), |
| 648 | AC97_VOLUME("Line Capture Volume", AC97_LINE), | 699 | AC97_VOLUME("Line Capture Volume", 0, AC97_LINE), |
| 649 | AC97_SWITCH("Line Capture Switch", AC97_LINE, 15, 1), | 700 | AC97_SWITCH("Line Capture Switch", 0, AC97_LINE, 15, 1), |
| 650 | AC97_VOLUME("CD Capture Volume", AC97_CD), | 701 | AC97_VOLUME("CD Capture Volume", 0, AC97_CD), |
| 651 | AC97_SWITCH("CD Capture Switch", AC97_CD, 15, 1), | 702 | AC97_SWITCH("CD Capture Switch", 0, AC97_CD, 15, 1), |
| 652 | AC97_VOLUME("Aux Capture Volume", AC97_AUX), | 703 | AC97_VOLUME("Aux Capture Volume", 0, AC97_AUX), |
| 653 | AC97_SWITCH("Aux Capture Switch", AC97_AUX, 15, 1), | 704 | AC97_SWITCH("Aux Capture Switch", 0, AC97_AUX, 15, 1), |
| 705 | }; | ||
| 706 | |||
| 707 | static const struct snd_kcontrol_new ac97_fp_controls[] = { | ||
| 708 | AC97_VOLUME("Front Panel Playback Volume", 1, AC97_HEADPHONE), | ||
| 709 | AC97_SWITCH("Front Panel Playback Switch", 1, AC97_HEADPHONE, 15, 1), | ||
| 710 | { | ||
| 711 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 712 | .name = "Front Panel Capture Volume", | ||
| 713 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
| 714 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | ||
| 715 | .info = ac97_fp_rec_volume_info, | ||
| 716 | .get = ac97_fp_rec_volume_get, | ||
| 717 | .put = ac97_fp_rec_volume_put, | ||
| 718 | .tlv = { .p = ac97_rec_db_scale, }, | ||
| 719 | }, | ||
| 720 | AC97_SWITCH("Front Panel Capture Switch", 1, AC97_REC_GAIN, 15, 1), | ||
| 654 | }; | 721 | }; |
| 655 | 722 | ||
| 656 | static void oxygen_any_ctl_free(struct snd_kcontrol *ctl) | 723 | static void oxygen_any_ctl_free(struct snd_kcontrol *ctl) |
| @@ -717,5 +784,11 @@ int oxygen_mixer_init(struct oxygen *chip) | |||
| 717 | if (err < 0) | 784 | if (err < 0) |
| 718 | return err; | 785 | return err; |
| 719 | } | 786 | } |
| 787 | if (chip->has_ac97_1) { | ||
| 788 | err = add_controls(chip, ac97_fp_controls, | ||
| 789 | ARRAY_SIZE(ac97_fp_controls)); | ||
| 790 | if (err < 0) | ||
| 791 | return err; | ||
| 792 | } | ||
| 720 | return chip->model->mixer_init ? chip->model->mixer_init(chip) : 0; | 793 | return chip->model->mixer_init ? chip->model->mixer_init(chip) : 0; |
| 721 | } | 794 | } |
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 23bfab448844..2e1a6996fa86 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c | |||
| @@ -247,9 +247,11 @@ static void mute_ac97_ctl(struct oxygen *chip, unsigned int control) | |||
| 247 | } | 247 | } |
| 248 | } | 248 | } |
| 249 | 249 | ||
| 250 | static void xonar_ac97_switch_hook(struct oxygen *chip, | 250 | static void xonar_ac97_switch_hook(struct oxygen *chip, unsigned int codec, |
| 251 | unsigned int reg, int mute) | 251 | unsigned int reg, int mute) |
| 252 | { | 252 | { |
| 253 | if (codec != 0) | ||
| 254 | return; | ||
| 253 | /* line-in is exclusive */ | 255 | /* line-in is exclusive */ |
| 254 | switch (reg) { | 256 | switch (reg) { |
| 255 | case AC97_LINE: | 257 | case AC97_LINE: |
