diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 78a5dfb66796..7d46bee828c7 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -361,7 +361,8 @@ struct _snd_via82xx { unsigned int mpu_port_saved; #endif - unsigned char playback_volume[2]; /* for VIA8233/C/8235; default = 0 */ + unsigned char playback_volume[4][2]; /* for VIA8233/C/8235; default = 0 */ + unsigned char playback_volume_c[2]; /* for VIA8233/C/8235; default = 0 */ unsigned int intr_mask; /* SGD_SHADOW mask to check interrupts */ @@ -937,8 +938,8 @@ static int snd_via8233_playback_prepare(snd_pcm_substream_t *substream) snd_assert((rbits & ~0xfffff) == 0, return -EINVAL); snd_via82xx_channel_reset(chip, viadev); snd_via82xx_set_table_ptr(chip, viadev); - outb(chip->playback_volume[0], VIADEV_REG(viadev, OFS_PLAYBACK_VOLUME_L)); - outb(chip->playback_volume[1], VIADEV_REG(viadev, OFS_PLAYBACK_VOLUME_R)); + outb(chip->playback_volume[viadev->reg_offset / 0x10][0], VIADEV_REG(viadev, OFS_PLAYBACK_VOLUME_L)); + outb(chip->playback_volume[viadev->reg_offset / 0x10][1], VIADEV_REG(viadev, OFS_PLAYBACK_VOLUME_R)); outl((runtime->format == SNDRV_PCM_FORMAT_S16_LE ? VIA8233_REG_TYPE_16BIT : 0) | /* format */ (runtime->channels > 1 ? VIA8233_REG_TYPE_STEREO : 0) | /* stereo */ rbits | /* rate */ @@ -1498,12 +1499,44 @@ static int snd_via8233_dxs_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_in static int snd_via8233_dxs_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { via82xx_t *chip = snd_kcontrol_chip(kcontrol); - ucontrol->value.integer.value[0] = VIA_DXS_MAX_VOLUME - chip->playback_volume[0]; - ucontrol->value.integer.value[1] = VIA_DXS_MAX_VOLUME - chip->playback_volume[1]; + unsigned int idx = snd_ctl_get_ioff(kcontrol, &ucontrol->id); + + ucontrol->value.integer.value[0] = VIA_DXS_MAX_VOLUME - chip->playback_volume[idx][0]; + ucontrol->value.integer.value[1] = VIA_DXS_MAX_VOLUME - chip->playback_volume[idx][1]; + return 0; +} + +static int snd_via8233_pcmdxs_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + via82xx_t *chip = snd_kcontrol_chip(kcontrol); + ucontrol->value.integer.value[0] = VIA_DXS_MAX_VOLUME - chip->playback_volume_c[0]; + ucontrol->value.integer.value[1] = VIA_DXS_MAX_VOLUME - chip->playback_volume_c[1]; return 0; } static int snd_via8233_dxs_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + via82xx_t *chip = snd_kcontrol_chip(kcontrol); + unsigned int idx = snd_ctl_get_ioff(kcontrol, &ucontrol->id); + unsigned long port = chip->port + 0x10 * idx; + unsigned char val; + int i, change = 0; + + for (i = 0; i < 2; i++) { + val = ucontrol->value.integer.value[i]; + if (val > VIA_DXS_MAX_VOLUME) + val = VIA_DXS_MAX_VOLUME; + val = VIA_DXS_MAX_VOLUME - val; + change |= val != chip->playback_volume[idx][i]; + if (change) { + chip->playback_volume[idx][i] = val; + outb(val, port + VIA_REG_OFS_PLAYBACK_VOLUME_L + i); + } + } + return change; +} + +static int snd_via8233_pcmdxs_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { via82xx_t *chip = snd_kcontrol_chip(kcontrol); unsigned int idx; @@ -1515,11 +1548,12 @@ static int snd_via8233_dxs_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_val if (val > VIA_DXS_MAX_VOLUME) val = VIA_DXS_MAX_VOLUME; val = VIA_DXS_MAX_VOLUME - val; - if (val != chip->playback_volume[i]) { + if (val != chip->playback_volume_c[i]) { change = 1; - chip->playback_volume[i] = val; + chip->playback_volume_c[i] = val; for (idx = 0; idx < 4; idx++) { unsigned long port = chip->port + 0x10 * idx; + chip->playback_volume[idx][i] = val; outb(val, port + VIA_REG_OFS_PLAYBACK_VOLUME_L + i); } } @@ -1527,10 +1561,19 @@ static int snd_via8233_dxs_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_val return change; } -static snd_kcontrol_new_t snd_via8233_dxs_volume_control __devinitdata = { +static snd_kcontrol_new_t snd_via8233_pcmdxs_volume_control __devinitdata = { .name = "PCM Playback Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .info = snd_via8233_dxs_volume_info, + .get = snd_via8233_pcmdxs_volume_get, + .put = snd_via8233_pcmdxs_volume_put, +}; + +static snd_kcontrol_new_t snd_via8233_dxs_volume_control __devinitdata = { + .name = "VIA DXS Playback Volume", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .count = 4, + .info = snd_via8233_dxs_volume_info, .get = snd_via8233_dxs_volume_get, .put = snd_via8233_dxs_volume_put, }; @@ -1723,12 +1766,19 @@ static int __devinit snd_via8233_init_misc(via82xx_t *chip) strcpy(sid.name, "PCM Playback Volume"); sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; if (! snd_ctl_find_id(chip->card, &sid)) { + snd_printd(KERN_INFO "Using DXS as PCM Playback\n"); + err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_pcmdxs_volume_control, chip)); + if (err < 0) + return err; + } + else /* Using DXS when PCM emulation is enabled is really weird */ + { + /* Standalone DXS controls */ err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_dxs_volume_control, chip)); if (err < 0) return err; } } - /* select spdif data slot 10/11 */ pci_read_config_byte(chip->pci, VIA8233_SPDIF_CTRL, &val); val = (val & ~VIA8233_SPDIF_SLOT_MASK) | VIA8233_SPDIF_SLOT_1011; @@ -1941,8 +1991,10 @@ static int snd_via82xx_chip_init(via82xx_t *chip) int i, idx; for (idx = 0; idx < 4; idx++) { unsigned long port = chip->port + 0x10 * idx; - for (i = 0; i < 2; i++) - outb(chip->playback_volume[i], port + VIA_REG_OFS_PLAYBACK_VOLUME_L + i); + for (i = 0; i < 2; i++) { + chip->playback_volume[idx][i]=chip->playback_volume_c[i]; + outb(chip->playback_volume_c[i], port + VIA_REG_OFS_PLAYBACK_VOLUME_L + i); + } } }