^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Routines for control of ICS 2101 chip and "mixer" in GF1 chip
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/time.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/wait.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <sound/core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <sound/control.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <sound/gus.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define GF1_SINGLE(xname, xindex, shift, invert) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) .info = snd_gf1_info_single, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) .get = snd_gf1_get_single, .put = snd_gf1_put_single, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) .private_value = shift | (invert << 8) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define snd_gf1_info_single snd_ctl_boolean_mono_info
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static int snd_gf1_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) int shift = kcontrol->private_value & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) int invert = (kcontrol->private_value >> 8) & 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) ucontrol->value.integer.value[0] = (gus->mix_cntrl_reg >> shift) & 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) if (invert)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) ucontrol->value.integer.value[0] ^= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static int snd_gf1_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) int shift = kcontrol->private_value & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) int invert = (kcontrol->private_value >> 8) & 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) int change;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) unsigned char oval, nval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) nval = ucontrol->value.integer.value[0] & 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) if (invert)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) nval ^= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) nval <<= shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) spin_lock_irqsave(&gus->reg_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) oval = gus->mix_cntrl_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) nval = (oval & ~(1 << shift)) | nval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) change = nval != oval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) outb(gus->mix_cntrl_reg = nval, GUSP(gus, MIXCNTRLREG));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) outb(gus->gf1.active_voice = 0, GUSP(gus, GF1PAGE));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) spin_unlock_irqrestore(&gus->reg_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) return change;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define ICS_DOUBLE(xname, xindex, addr) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) .info = snd_ics_info_double, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) .get = snd_ics_get_double, .put = snd_ics_put_double, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) .private_value = addr }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) static int snd_ics_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) uinfo->count = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) uinfo->value.integer.min = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) uinfo->value.integer.max = 127;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) static int snd_ics_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) int addr = kcontrol->private_value & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) unsigned char left, right;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) spin_lock_irqsave(&gus->reg_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) left = gus->gf1.ics_regs[addr][0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) right = gus->gf1.ics_regs[addr][1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) spin_unlock_irqrestore(&gus->reg_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) ucontrol->value.integer.value[0] = left & 127;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) ucontrol->value.integer.value[1] = right & 127;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) static int snd_ics_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) int addr = kcontrol->private_value & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) int change;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) unsigned char val1, val2, oval1, oval2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) val1 = ucontrol->value.integer.value[0] & 127;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) val2 = ucontrol->value.integer.value[1] & 127;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) spin_lock_irqsave(&gus->reg_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) oval1 = gus->gf1.ics_regs[addr][0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) oval2 = gus->gf1.ics_regs[addr][1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) change = val1 != oval1 || val2 != oval2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) gus->gf1.ics_regs[addr][0] = val1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) gus->gf1.ics_regs[addr][1] = val2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (gus->ics_flag && gus->ics_flipped &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) (addr == SNDRV_ICS_GF1_DEV || addr == SNDRV_ICS_MASTER_DEV))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) swap(val1, val2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) addr <<= 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) outb(addr | 0, GUSP(gus, MIXCNTRLPORT));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) outb(1, GUSP(gus, MIXDATAPORT));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) outb(addr | 2, GUSP(gus, MIXCNTRLPORT));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) outb((unsigned char) val1, GUSP(gus, MIXDATAPORT));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) outb(addr | 1, GUSP(gus, MIXCNTRLPORT));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) outb(2, GUSP(gus, MIXDATAPORT));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) outb(addr | 3, GUSP(gus, MIXCNTRLPORT));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) outb((unsigned char) val2, GUSP(gus, MIXDATAPORT));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) spin_unlock_irqrestore(&gus->reg_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) return change;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) static const struct snd_kcontrol_new snd_gf1_controls[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) GF1_SINGLE("Master Playback Switch", 0, 1, 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) GF1_SINGLE("Line Switch", 0, 0, 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) GF1_SINGLE("Mic Switch", 0, 2, 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) static const struct snd_kcontrol_new snd_ics_controls[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) GF1_SINGLE("Master Playback Switch", 0, 1, 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) ICS_DOUBLE("Master Playback Volume", 0, SNDRV_ICS_MASTER_DEV),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) ICS_DOUBLE("Synth Playback Volume", 0, SNDRV_ICS_GF1_DEV),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) GF1_SINGLE("Line Switch", 0, 0, 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) ICS_DOUBLE("Line Playback Volume", 0, SNDRV_ICS_LINE_DEV),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) GF1_SINGLE("Mic Switch", 0, 2, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) ICS_DOUBLE("Mic Playback Volume", 0, SNDRV_ICS_MIC_DEV),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) ICS_DOUBLE("CD Playback Volume", 0, SNDRV_ICS_CD_DEV)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) int snd_gf1_new_mixer(struct snd_gus_card * gus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) struct snd_card *card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) unsigned int idx, max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) if (snd_BUG_ON(!gus))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) card = gus->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) if (snd_BUG_ON(!card))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) if (gus->ics_flag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) snd_component_add(card, "ICS2101");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if (card->mixername[0] == '\0') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) strcpy(card->mixername, gus->ics_flag ? "GF1,ICS2101" : "GF1");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (gus->ics_flag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) strcat(card->mixername, ",ICS2101");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) strcat(card->mixername, ",GF1");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) if (!gus->ics_flag) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) max = gus->ess_flag ? 1 : ARRAY_SIZE(snd_gf1_controls);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) for (idx = 0; idx < max; idx++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_gf1_controls[idx], gus))) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) for (idx = 0; idx < ARRAY_SIZE(snd_ics_controls); idx++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_ics_controls[idx], gus))) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) }