123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- /***************************************************************************
- msnd_pinnacle_mixer.c - description
- -------------------
- begin : Fre Jun 7 2002
- copyright : (C) 2002 by karsten wiese
- email : annabellesgarden@yahoo.de
- ***************************************************************************/
- /***************************************************************************
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- ***************************************************************************/
- #include <linux/io.h>
- #include <linux/export.h>
- #include <sound/core.h>
- #include <sound/control.h>
- #include "msnd.h"
- #include "msnd_pinnacle.h"
- #define MSND_MIXER_VOLUME 0
- #define MSND_MIXER_PCM 1
- #define MSND_MIXER_AUX 2 /* Input source 1 (aux1) */
- #define MSND_MIXER_IMIX 3 /* Recording monitor */
- #define MSND_MIXER_SYNTH 4
- #define MSND_MIXER_SPEAKER 5
- #define MSND_MIXER_LINE 6
- #define MSND_MIXER_MIC 7
- #define MSND_MIXER_RECLEV 11 /* Recording level */
- #define MSND_MIXER_IGAIN 12 /* Input gain */
- #define MSND_MIXER_OGAIN 13 /* Output gain */
- #define MSND_MIXER_DIGITAL 17 /* Digital (input) 1 */
- /* Device mask bits */
- #define MSND_MASK_VOLUME (1 << MSND_MIXER_VOLUME)
- #define MSND_MASK_SYNTH (1 << MSND_MIXER_SYNTH)
- #define MSND_MASK_PCM (1 << MSND_MIXER_PCM)
- #define MSND_MASK_SPEAKER (1 << MSND_MIXER_SPEAKER)
- #define MSND_MASK_LINE (1 << MSND_MIXER_LINE)
- #define MSND_MASK_MIC (1 << MSND_MIXER_MIC)
- #define MSND_MASK_IMIX (1 << MSND_MIXER_IMIX)
- #define MSND_MASK_RECLEV (1 << MSND_MIXER_RECLEV)
- #define MSND_MASK_IGAIN (1 << MSND_MIXER_IGAIN)
- #define MSND_MASK_OGAIN (1 << MSND_MIXER_OGAIN)
- #define MSND_MASK_AUX (1 << MSND_MIXER_AUX)
- #define MSND_MASK_DIGITAL (1 << MSND_MIXER_DIGITAL)
- static int snd_msndmix_info_mux(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
- {
- static const char * const texts[3] = {
- "Analog", "MASS", "SPDIF",
- };
- struct snd_msnd *chip = snd_kcontrol_chip(kcontrol);
- unsigned items = test_bit(F_HAVEDIGITAL, &chip->flags) ? 3 : 2;
- return snd_ctl_enum_info(uinfo, 1, items, texts);
- }
- static int snd_msndmix_get_mux(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct snd_msnd *chip = snd_kcontrol_chip(kcontrol);
- /* MSND_MASK_IMIX is the default */
- ucontrol->value.enumerated.item[0] = 0;
- if (chip->recsrc & MSND_MASK_SYNTH) {
- ucontrol->value.enumerated.item[0] = 1;
- } else if ((chip->recsrc & MSND_MASK_DIGITAL) &&
- test_bit(F_HAVEDIGITAL, &chip->flags)) {
- ucontrol->value.enumerated.item[0] = 2;
- }
- return 0;
- }
- static int snd_msndmix_set_mux(struct snd_msnd *chip, int val)
- {
- unsigned newrecsrc;
- int change;
- unsigned char msndbyte;
- switch (val) {
- case 0:
- newrecsrc = MSND_MASK_IMIX;
- msndbyte = HDEXAR_SET_ANA_IN;
- break;
- case 1:
- newrecsrc = MSND_MASK_SYNTH;
- msndbyte = HDEXAR_SET_SYNTH_IN;
- break;
- case 2:
- newrecsrc = MSND_MASK_DIGITAL;
- msndbyte = HDEXAR_SET_DAT_IN;
- break;
- default:
- return -EINVAL;
- }
- change = newrecsrc != chip->recsrc;
- if (change) {
- change = 0;
- if (!snd_msnd_send_word(chip, 0, 0, msndbyte))
- if (!snd_msnd_send_dsp_cmd(chip, HDEX_AUX_REQ)) {
- chip->recsrc = newrecsrc;
- change = 1;
- }
- }
- return change;
- }
- static int snd_msndmix_put_mux(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
- return snd_msndmix_set_mux(msnd, ucontrol->value.enumerated.item[0]);
- }
- static int snd_msndmix_volume_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
- {
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 2;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 100;
- return 0;
- }
- static int snd_msndmix_volume_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
- int addr = kcontrol->private_value;
- unsigned long flags;
- spin_lock_irqsave(&msnd->mixer_lock, flags);
- ucontrol->value.integer.value[0] = msnd->left_levels[addr] * 100;
- ucontrol->value.integer.value[0] /= 0xFFFF;
- ucontrol->value.integer.value[1] = msnd->right_levels[addr] * 100;
- ucontrol->value.integer.value[1] /= 0xFFFF;
- spin_unlock_irqrestore(&msnd->mixer_lock, flags);
- return 0;
- }
- #define update_volm(a, b) \
- do { \
- writew((dev->left_levels[a] >> 1) * \
- readw(dev->SMA + SMA_wCurrMastVolLeft) / 0xffff, \
- dev->SMA + SMA_##b##Left); \
- writew((dev->right_levels[a] >> 1) * \
- readw(dev->SMA + SMA_wCurrMastVolRight) / 0xffff, \
- dev->SMA + SMA_##b##Right); \
- } while (0);
- #define update_potm(d, s, ar) \
- do { \
- writeb((dev->left_levels[d] >> 8) * \
- readw(dev->SMA + SMA_wCurrMastVolLeft) / 0xffff, \
- dev->SMA + SMA_##s##Left); \
- writeb((dev->right_levels[d] >> 8) * \
- readw(dev->SMA + SMA_wCurrMastVolRight) / 0xffff, \
- dev->SMA + SMA_##s##Right); \
- if (snd_msnd_send_word(dev, 0, 0, ar) == 0) \
- snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ); \
- } while (0);
- #define update_pot(d, s, ar) \
- do { \
- writeb(dev->left_levels[d] >> 8, \
- dev->SMA + SMA_##s##Left); \
- writeb(dev->right_levels[d] >> 8, \
- dev->SMA + SMA_##s##Right); \
- if (snd_msnd_send_word(dev, 0, 0, ar) == 0) \
- snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ); \
- } while (0);
- static int snd_msndmix_set(struct snd_msnd *dev, int d, int left, int right)
- {
- int bLeft, bRight;
- int wLeft, wRight;
- int updatemaster = 0;
- if (d >= LEVEL_ENTRIES)
- return -EINVAL;
- bLeft = left * 0xff / 100;
- wLeft = left * 0xffff / 100;
- bRight = right * 0xff / 100;
- wRight = right * 0xffff / 100;
- dev->left_levels[d] = wLeft;
- dev->right_levels[d] = wRight;
- switch (d) {
- /* master volume unscaled controls */
- case MSND_MIXER_LINE: /* line pot control */
- /* scaled by IMIX in digital mix */
- writeb(bLeft, dev->SMA + SMA_bInPotPosLeft);
- writeb(bRight, dev->SMA + SMA_bInPotPosRight);
- if (snd_msnd_send_word(dev, 0, 0, HDEXAR_IN_SET_POTS) == 0)
- snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ);
- break;
- case MSND_MIXER_MIC: /* mic pot control */
- if (dev->type == msndClassic)
- return -EINVAL;
- /* scaled by IMIX in digital mix */
- writeb(bLeft, dev->SMA + SMA_bMicPotPosLeft);
- writeb(bRight, dev->SMA + SMA_bMicPotPosRight);
- if (snd_msnd_send_word(dev, 0, 0, HDEXAR_MIC_SET_POTS) == 0)
- snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ);
- break;
- case MSND_MIXER_VOLUME: /* master volume */
- writew(wLeft, dev->SMA + SMA_wCurrMastVolLeft);
- writew(wRight, dev->SMA + SMA_wCurrMastVolRight);
- /* fall through */
- case MSND_MIXER_AUX: /* aux pot control */
- /* scaled by master volume */
- /* fall through */
- /* digital controls */
- case MSND_MIXER_SYNTH: /* synth vol (dsp mix) */
- case MSND_MIXER_PCM: /* pcm vol (dsp mix) */
- case MSND_MIXER_IMIX: /* input monitor (dsp mix) */
- /* scaled by master volume */
- updatemaster = 1;
- break;
- default:
- return -EINVAL;
- }
- if (updatemaster) {
- /* update master volume scaled controls */
- update_volm(MSND_MIXER_PCM, wCurrPlayVol);
- update_volm(MSND_MIXER_IMIX, wCurrInVol);
- if (dev->type == msndPinnacle)
- update_volm(MSND_MIXER_SYNTH, wCurrMHdrVol);
- update_potm(MSND_MIXER_AUX, bAuxPotPos, HDEXAR_AUX_SET_POTS);
- }
- return 0;
- }
- static int snd_msndmix_volume_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
- int change, addr = kcontrol->private_value;
- int left, right;
- unsigned long flags;
- left = ucontrol->value.integer.value[0] % 101;
- right = ucontrol->value.integer.value[1] % 101;
- spin_lock_irqsave(&msnd->mixer_lock, flags);
- change = msnd->left_levels[addr] != left
- || msnd->right_levels[addr] != right;
- snd_msndmix_set(msnd, addr, left, right);
- spin_unlock_irqrestore(&msnd->mixer_lock, flags);
- return change;
- }
- #define DUMMY_VOLUME(xname, xindex, addr) \
- { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
- .info = snd_msndmix_volume_info, \
- .get = snd_msndmix_volume_get, .put = snd_msndmix_volume_put, \
- .private_value = addr }
- static struct snd_kcontrol_new snd_msnd_controls[] = {
- DUMMY_VOLUME("Master Volume", 0, MSND_MIXER_VOLUME),
- DUMMY_VOLUME("PCM Volume", 0, MSND_MIXER_PCM),
- DUMMY_VOLUME("Aux Volume", 0, MSND_MIXER_AUX),
- DUMMY_VOLUME("Line Volume", 0, MSND_MIXER_LINE),
- DUMMY_VOLUME("Mic Volume", 0, MSND_MIXER_MIC),
- DUMMY_VOLUME("Monitor", 0, MSND_MIXER_IMIX),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Capture Source",
- .info = snd_msndmix_info_mux,
- .get = snd_msndmix_get_mux,
- .put = snd_msndmix_put_mux,
- }
- };
- int snd_msndmix_new(struct snd_card *card)
- {
- struct snd_msnd *chip = card->private_data;
- unsigned int idx;
- int err;
- if (snd_BUG_ON(!chip))
- return -EINVAL;
- spin_lock_init(&chip->mixer_lock);
- strcpy(card->mixername, "MSND Pinnacle Mixer");
- for (idx = 0; idx < ARRAY_SIZE(snd_msnd_controls); idx++) {
- err = snd_ctl_add(card,
- snd_ctl_new1(snd_msnd_controls + idx, chip));
- if (err < 0)
- return err;
- }
- return 0;
- }
- EXPORT_SYMBOL(snd_msndmix_new);
- void snd_msndmix_setup(struct snd_msnd *dev)
- {
- update_pot(MSND_MIXER_LINE, bInPotPos, HDEXAR_IN_SET_POTS);
- update_potm(MSND_MIXER_AUX, bAuxPotPos, HDEXAR_AUX_SET_POTS);
- update_volm(MSND_MIXER_PCM, wCurrPlayVol);
- update_volm(MSND_MIXER_IMIX, wCurrInVol);
- if (dev->type == msndPinnacle) {
- update_pot(MSND_MIXER_MIC, bMicPotPos, HDEXAR_MIC_SET_POTS);
- update_volm(MSND_MIXER_SYNTH, wCurrMHdrVol);
- }
- }
- EXPORT_SYMBOL(snd_msndmix_setup);
- int snd_msndmix_force_recsrc(struct snd_msnd *dev, int recsrc)
- {
- dev->recsrc = -1;
- return snd_msndmix_set_mux(dev, recsrc);
- }
- EXPORT_SYMBOL(snd_msndmix_force_recsrc);
|