Skip to main content
  • Home
  • Development
  • Documentation
  • Donate
  • Operational login
  • Browse the archive

swh logo
SoftwareHeritage
Software
Heritage
Archive
Features
  • Search

  • Downloads

  • Save code now

  • Add forge now

  • Help

  • 61acfe9
  • /
  • sound
  • /
  • isa
  • /
  • msnd
  • /
  • msnd_pinnacle_mixer.c
Raw File Download
Permalinks

To reference or cite the objects present in the Software Heritage archive, permalinks based on SoftWare Hash IDentifiers (SWHIDs) must be used.
Select below a type of object currently browsed in order to display its associated SWHID and permalink.

  • content
  • directory
content badge Iframe embedding
swh:1:cnt:b408540798c1648d04a4ec1c36086844326affe1
directory badge Iframe embedding
swh:1:dir:1d34dcc47b219646b0b127bd9e7b953d8e943d12
Citations

This interface enables to generate software citations, provided that the root directory of browsed objects contains a citation.cff or codemeta.json file.
Select below a type of object currently browsed in order to generate citations for them.

  • content
  • directory
Generate software citation in BibTex format (requires biblatex-software package)
Generating citation ...
Generate software citation in BibTex format (requires biblatex-software package)
Generating citation ...
msnd_pinnacle_mixer.c
/***************************************************************************
			  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);

back to top

Software Heritage — Copyright (C) 2015–2025, The Software Heritage developers. License: GNU AGPLv3+.
The source code of Software Heritage itself is available on our development forge.
The source code files archived by Software Heritage are available under their own copyright and licenses.
Terms of use: Archive access, API— Contact— JavaScript license information— Web API