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

mia_dsp.c (5654B)


      1/****************************************************************************
      2
      3   Copyright Echo Digital Audio Corporation (c) 1998 - 2004
      4   All rights reserved
      5   www.echoaudio.com
      6
      7   This file is part of Echo Digital Audio's generic driver library.
      8
      9   Echo Digital Audio's generic driver library is free software;
     10   you can redistribute it and/or modify it under the terms of
     11   the GNU General Public License as published by the Free Software
     12   Foundation.
     13
     14   This program is distributed in the hope that it will be useful,
     15   but WITHOUT ANY WARRANTY; without even the implied warranty of
     16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17   GNU General Public License for more details.
     18
     19   You should have received a copy of the GNU General Public License
     20   along with this program; if not, write to the Free Software
     21   Foundation, Inc., 59 Temple Place - Suite 330, Boston,
     22   MA  02111-1307, USA.
     23
     24   *************************************************************************
     25
     26 Translation from C++ and adaptation for use in ALSA-Driver
     27 were made by Giuliano Pochini <pochini@shiny.it>
     28
     29****************************************************************************/
     30
     31
     32static int set_input_clock(struct echoaudio *chip, u16 clock);
     33static int set_professional_spdif(struct echoaudio *chip, char prof);
     34static int update_flags(struct echoaudio *chip);
     35static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
     36			   int gain);
     37static int update_vmixer_level(struct echoaudio *chip);
     38
     39
     40static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
     41{
     42	int err;
     43
     44	if (snd_BUG_ON((subdevice_id & 0xfff0) != MIA))
     45		return -ENODEV;
     46
     47	err = init_dsp_comm_page(chip);
     48	if (err) {
     49		dev_err(chip->card->dev,
     50			"init_hw - could not initialize DSP comm page\n");
     51		return err;
     52	}
     53
     54	chip->device_id = device_id;
     55	chip->subdevice_id = subdevice_id;
     56	chip->bad_board = true;
     57	chip->dsp_code_to_load = FW_MIA_DSP;
     58	/* Since this card has no ASIC, mark it as loaded so everything
     59	   works OK */
     60	chip->asic_loaded = true;
     61	if ((subdevice_id & 0x0000f) == MIA_MIDI_REV)
     62		chip->has_midi = true;
     63	chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL |
     64		ECHO_CLOCK_BIT_SPDIF;
     65
     66	err = load_firmware(chip);
     67	if (err < 0)
     68		return err;
     69	chip->bad_board = false;
     70
     71	return err;
     72}
     73
     74
     75
     76static int set_mixer_defaults(struct echoaudio *chip)
     77{
     78	return init_line_levels(chip);
     79}
     80
     81
     82
     83static u32 detect_input_clocks(const struct echoaudio *chip)
     84{
     85	u32 clocks_from_dsp, clock_bits;
     86
     87	/* Map the DSP clock detect bits to the generic driver clock
     88	   detect bits */
     89	clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
     90
     91	clock_bits = ECHO_CLOCK_BIT_INTERNAL;
     92
     93	if (clocks_from_dsp & GLDM_CLOCK_DETECT_BIT_SPDIF)
     94		clock_bits |= ECHO_CLOCK_BIT_SPDIF;
     95
     96	return clock_bits;
     97}
     98
     99
    100
    101/* The Mia has no ASIC. Just do nothing */
    102static int load_asic(struct echoaudio *chip)
    103{
    104	return 0;
    105}
    106
    107
    108
    109static int set_sample_rate(struct echoaudio *chip, u32 rate)
    110{
    111	u32 control_reg;
    112
    113	switch (rate) {
    114	case 96000:
    115		control_reg = MIA_96000;
    116		break;
    117	case 88200:
    118		control_reg = MIA_88200;
    119		break;
    120	case 48000:
    121		control_reg = MIA_48000;
    122		break;
    123	case 44100:
    124		control_reg = MIA_44100;
    125		break;
    126	case 32000:
    127		control_reg = MIA_32000;
    128		break;
    129	default:
    130		dev_err(chip->card->dev,
    131			"set_sample_rate: %d invalid!\n", rate);
    132		return -EINVAL;
    133	}
    134
    135	/* Override the clock setting if this Mia is set to S/PDIF clock */
    136	if (chip->input_clock == ECHO_CLOCK_SPDIF)
    137		control_reg |= MIA_SPDIF;
    138
    139	/* Set the control register if it has changed */
    140	if (control_reg != le32_to_cpu(chip->comm_page->control_register)) {
    141		if (wait_handshake(chip))
    142			return -EIO;
    143
    144		chip->comm_page->sample_rate = cpu_to_le32(rate);	/* ignored by the DSP */
    145		chip->comm_page->control_register = cpu_to_le32(control_reg);
    146		chip->sample_rate = rate;
    147
    148		clear_handshake(chip);
    149		return send_vector(chip, DSP_VC_UPDATE_CLOCKS);
    150	}
    151	return 0;
    152}
    153
    154
    155
    156static int set_input_clock(struct echoaudio *chip, u16 clock)
    157{
    158	dev_dbg(chip->card->dev, "set_input_clock(%d)\n", clock);
    159	if (snd_BUG_ON(clock != ECHO_CLOCK_INTERNAL &&
    160		       clock != ECHO_CLOCK_SPDIF))
    161		return -EINVAL;
    162
    163	chip->input_clock = clock;
    164	return set_sample_rate(chip, chip->sample_rate);
    165}
    166
    167
    168
    169/* This function routes the sound from a virtual channel to a real output */
    170static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
    171			   int gain)
    172{
    173	int index;
    174
    175	if (snd_BUG_ON(pipe >= num_pipes_out(chip) ||
    176		       output >= num_busses_out(chip)))
    177		return -EINVAL;
    178
    179	if (wait_handshake(chip))
    180		return -EIO;
    181
    182	chip->vmixer_gain[output][pipe] = gain;
    183	index = output * num_pipes_out(chip) + pipe;
    184	chip->comm_page->vmixer[index] = gain;
    185
    186	dev_dbg(chip->card->dev,
    187		"set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain);
    188	return 0;
    189}
    190
    191
    192
    193/* Tell the DSP to read and update virtual mixer levels in comm page. */
    194static int update_vmixer_level(struct echoaudio *chip)
    195{
    196	if (wait_handshake(chip))
    197		return -EIO;
    198	clear_handshake(chip);
    199	return send_vector(chip, DSP_VC_SET_VMIXER_GAIN);
    200}
    201
    202
    203
    204/* Tell the DSP to reread the flags from the comm page */
    205static int update_flags(struct echoaudio *chip)
    206{
    207	if (wait_handshake(chip))
    208		return -EIO;
    209	clear_handshake(chip);
    210	return send_vector(chip, DSP_VC_UPDATE_FLAGS);
    211}
    212
    213
    214
    215static int set_professional_spdif(struct echoaudio *chip, char prof)
    216{
    217	dev_dbg(chip->card->dev, "set_professional_spdif %d\n", prof);
    218	if (prof)
    219		chip->comm_page->flags |=
    220			cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
    221	else
    222		chip->comm_page->flags &=
    223			~cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
    224	chip->professional_spdif = prof;
    225	return update_flags(chip);
    226}
    227