cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

gus_mixer.c (5442B)


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