[ALSA] Add echoaudio sound drivers
From: Giuliano Pochini <pochini@shiny.it>Add echoaudio sound drivers (darla20, darla24, echo3g, gina20, gina24, indigo, indigodj, indigoio, layla20, lala24, mia, mona) Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
This commit is contained in:
Родитель
cb9d24e434
Коммит
dd7b254d8d
|
@ -472,6 +472,22 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
|||
|
||||
The power-management is supported.
|
||||
|
||||
Module snd-darla20
|
||||
------------------
|
||||
|
||||
Module for Echoaudio Darla20
|
||||
|
||||
This module supports multiple cards.
|
||||
The driver requires the firmware loader support on kernel.
|
||||
|
||||
Module snd-darla24
|
||||
------------------
|
||||
|
||||
Module for Echoaudio Darla24
|
||||
|
||||
This module supports multiple cards.
|
||||
The driver requires the firmware loader support on kernel.
|
||||
|
||||
Module snd-dt019x
|
||||
-----------------
|
||||
|
||||
|
@ -499,6 +515,14 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
|||
|
||||
The power-management is supported.
|
||||
|
||||
Module snd-echo3g
|
||||
-----------------
|
||||
|
||||
Module for Echoaudio 3G cards (Gina3G/Layla3G)
|
||||
|
||||
This module supports multiple cards.
|
||||
The driver requires the firmware loader support on kernel.
|
||||
|
||||
Module snd-emu10k1
|
||||
------------------
|
||||
|
||||
|
@ -657,6 +681,22 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
|||
|
||||
The power-management is supported.
|
||||
|
||||
Module snd-gina20
|
||||
-----------------
|
||||
|
||||
Module for Echoaudio Gina20
|
||||
|
||||
This module supports multiple cards.
|
||||
The driver requires the firmware loader support on kernel.
|
||||
|
||||
Module snd-gina24
|
||||
-----------------
|
||||
|
||||
Module for Echoaudio Gina24
|
||||
|
||||
This module supports multiple cards.
|
||||
The driver requires the firmware loader support on kernel.
|
||||
|
||||
Module snd-gusclassic
|
||||
---------------------
|
||||
|
||||
|
@ -937,6 +977,30 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
|||
driver isn't configured properly or you want to try another
|
||||
type for testing.
|
||||
|
||||
Module snd-indigo
|
||||
-----------------
|
||||
|
||||
Module for Echoaudio Indigo
|
||||
|
||||
This module supports multiple cards.
|
||||
The driver requires the firmware loader support on kernel.
|
||||
|
||||
Module snd-indigodj
|
||||
-------------------
|
||||
|
||||
Module for Echoaudio Indigo DJ
|
||||
|
||||
This module supports multiple cards.
|
||||
The driver requires the firmware loader support on kernel.
|
||||
|
||||
Module snd-indigoio
|
||||
-------------------
|
||||
|
||||
Module for Echoaudio Indigo IO
|
||||
|
||||
This module supports multiple cards.
|
||||
The driver requires the firmware loader support on kernel.
|
||||
|
||||
Module snd-intel8x0
|
||||
-------------------
|
||||
|
||||
|
@ -1036,6 +1100,22 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
|||
|
||||
This module supports multiple cards.
|
||||
|
||||
Module snd-layla20
|
||||
------------------
|
||||
|
||||
Module for Echoaudio Layla20
|
||||
|
||||
This module supports multiple cards.
|
||||
The driver requires the firmware loader support on kernel.
|
||||
|
||||
Module snd-layla24
|
||||
------------------
|
||||
|
||||
Module for Echoaudio Layla24
|
||||
|
||||
This module supports multiple cards.
|
||||
The driver requires the firmware loader support on kernel.
|
||||
|
||||
Module snd-maestro3
|
||||
-------------------
|
||||
|
||||
|
@ -1056,6 +1136,14 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
|||
|
||||
The power-management is supported.
|
||||
|
||||
Module snd-mia
|
||||
---------------
|
||||
|
||||
Module for Echoaudio Mia
|
||||
|
||||
This module supports multiple cards.
|
||||
The driver requires the firmware loader support on kernel.
|
||||
|
||||
Module snd-miro
|
||||
---------------
|
||||
|
||||
|
@ -1088,6 +1176,14 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
|||
When no hotplug fw loader is available, you need to load the
|
||||
firmware via mixartloader utility in alsa-tools package.
|
||||
|
||||
Module snd-mona
|
||||
---------------
|
||||
|
||||
Module for Echoaudio Mona
|
||||
|
||||
This module supports multiple cards.
|
||||
The driver requires the firmware loader support on kernel.
|
||||
|
||||
Module snd-mpu401
|
||||
-----------------
|
||||
|
||||
|
|
|
@ -233,6 +233,143 @@ config SND_CS5535AUDIO
|
|||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-cs5535audio.
|
||||
|
||||
config SND_DARLA20
|
||||
tristate "(Echoaudio) Darla20"
|
||||
depends on SND
|
||||
depends on FW_LOADER
|
||||
select SND_PCM
|
||||
help
|
||||
Say 'Y' or 'M' to include support for Echoaudio Darla.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-darla20
|
||||
|
||||
config SND_GINA20
|
||||
tristate "(Echoaudio) Gina20"
|
||||
depends on SND
|
||||
depends on FW_LOADER
|
||||
select SND_PCM
|
||||
help
|
||||
Say 'Y' or 'M' to include support for Echoaudio Gina.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-gina20
|
||||
|
||||
config SND_LAYLA20
|
||||
tristate "(Echoaudio) Layla20"
|
||||
depends on SND
|
||||
depends on FW_LOADER
|
||||
select SND_RAWMIDI
|
||||
select SND_PCM
|
||||
help
|
||||
Say 'Y' or 'M' to include support for Echoaudio Layla.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-layla20
|
||||
|
||||
config SND_DARLA24
|
||||
tristate "(Echoaudio) Darla24"
|
||||
depends on SND
|
||||
depends on FW_LOADER
|
||||
select SND_PCM
|
||||
help
|
||||
Say 'Y' or 'M' to include support for Echoaudio Darla24.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-darla24
|
||||
|
||||
config SND_GINA24
|
||||
tristate "(Echoaudio) Gina24"
|
||||
depends on SND
|
||||
depends on FW_LOADER
|
||||
select SND_PCM
|
||||
help
|
||||
Say 'Y' or 'M' to include support for Echoaudio Gina24.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-gina24
|
||||
|
||||
config SND_LAYLA24
|
||||
tristate "(Echoaudio) Layla24"
|
||||
depends on SND
|
||||
depends on FW_LOADER
|
||||
select SND_RAWMIDI
|
||||
select SND_PCM
|
||||
help
|
||||
Say 'Y' or 'M' to include support for Echoaudio Layla24.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-layla24
|
||||
|
||||
config SND_MONA
|
||||
tristate "(Echoaudio) Mona"
|
||||
depends on SND
|
||||
depends on FW_LOADER
|
||||
select SND_RAWMIDI
|
||||
select SND_PCM
|
||||
help
|
||||
Say 'Y' or 'M' to include support for Echoaudio Mona.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-mona
|
||||
|
||||
config SND_MIA
|
||||
tristate "(Echoaudio) Mia"
|
||||
depends on SND
|
||||
depends on FW_LOADER
|
||||
select SND_RAWMIDI
|
||||
select SND_PCM
|
||||
help
|
||||
Say 'Y' or 'M' to include support for Echoaudio Mia and Mia-midi.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-mia
|
||||
|
||||
config SND_ECHO3G
|
||||
tristate "(Echoaudio) 3G cards"
|
||||
depends on SND
|
||||
depends on FW_LOADER
|
||||
select SND_RAWMIDI
|
||||
select SND_PCM
|
||||
help
|
||||
Say 'Y' or 'M' to include support for Echoaudio Gina3G and Layla3G.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-echo3g
|
||||
|
||||
config SND_INDIGO
|
||||
tristate "(Echoaudio) Indigo"
|
||||
depends on SND
|
||||
depends on FW_LOADER
|
||||
select SND_PCM
|
||||
help
|
||||
Say 'Y' or 'M' to include support for Echoaudio Indigo.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-indigo
|
||||
|
||||
config SND_INDIGOIO
|
||||
tristate "(Echoaudio) Indigo IO"
|
||||
depends on SND
|
||||
depends on FW_LOADER
|
||||
select SND_PCM
|
||||
help
|
||||
Say 'Y' or 'M' to include support for Echoaudio Indigo IO.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-indigoio
|
||||
|
||||
config SND_INDIGODJ
|
||||
tristate "(Echoaudio) Indigo DJ"
|
||||
depends on SND
|
||||
depends on FW_LOADER
|
||||
select SND_PCM
|
||||
help
|
||||
Say 'Y' or 'M' to include support for Echoaudio Indigo DJ.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-indigodj
|
||||
|
||||
config SND_EMU10K1
|
||||
tristate "Emu10k1 (SB Live!, Audigy, E-mu APS)"
|
||||
depends on SND
|
||||
|
|
|
@ -57,6 +57,7 @@ obj-$(CONFIG_SND) += \
|
|||
ca0106/ \
|
||||
cs46xx/ \
|
||||
cs5535audio/ \
|
||||
echoaudio/ \
|
||||
emu10k1/ \
|
||||
hda/ \
|
||||
ice1712/ \
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
#
|
||||
# Makefile for ALSA Echoaudio soundcard drivers
|
||||
# Copyright (c) 2003 by Giuliano Pochini <pochini@shiny.it>
|
||||
#
|
||||
|
||||
snd-darla20-objs := darla20.o
|
||||
snd-gina20-objs := gina20.o
|
||||
snd-layla20-objs := layla20.o
|
||||
snd-darla24-objs := darla24.o
|
||||
snd-gina24-objs := gina24.o
|
||||
snd-layla24-objs := layla24.o
|
||||
snd-mona-objs := mona.o
|
||||
snd-mia-objs := mia.o
|
||||
snd-echo3g-objs := echo3g.o
|
||||
snd-indigo-objs := indigo.o
|
||||
snd-indigoio-objs := indigoio.o
|
||||
snd-indigodj-objs := indigodj.o
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* ALSA driver for Echoaudio soundcards.
|
||||
* Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.it>
|
||||
*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#define ECHOGALS_FAMILY
|
||||
#define ECHOCARD_DARLA20
|
||||
#define ECHOCARD_NAME "Darla20"
|
||||
#define ECHOCARD_HAS_MONITOR
|
||||
|
||||
/* Pipe indexes */
|
||||
#define PX_ANALOG_OUT 0 /* 8 */
|
||||
#define PX_DIGITAL_OUT 8 /* 0 */
|
||||
#define PX_ANALOG_IN 8 /* 2 */
|
||||
#define PX_DIGITAL_IN 10 /* 0 */
|
||||
#define PX_NUM 10
|
||||
|
||||
/* Bus indexes */
|
||||
#define BX_ANALOG_OUT 0 /* 8 */
|
||||
#define BX_DIGITAL_OUT 8 /* 0 */
|
||||
#define BX_ANALOG_IN 8 /* 2 */
|
||||
#define BX_DIGITAL_IN 10 /* 0 */
|
||||
#define BX_NUM 10
|
||||
|
||||
|
||||
#include <sound/driver.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/info.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/initval.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/atomic.h>
|
||||
#include "echoaudio.h"
|
||||
|
||||
#define FW_DARLA20_DSP 0
|
||||
|
||||
static const struct firmware card_fw[] = {
|
||||
{0, "darla20_dsp.fw"}
|
||||
};
|
||||
|
||||
static struct pci_device_id snd_echo_ids[] = {
|
||||
{0x1057, 0x1801, 0xECC0, 0x0010, 0, 0, 0}, /* DSP 56301 Darla20 rev.0 */
|
||||
{0,}
|
||||
};
|
||||
|
||||
static struct snd_pcm_hardware pcm_hardware_skel = {
|
||||
.info = SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_SYNC_START,
|
||||
.formats = SNDRV_PCM_FMTBIT_U8 |
|
||||
SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_3LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_BE,
|
||||
.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
|
||||
.rate_min = 44100,
|
||||
.rate_max = 48000,
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.buffer_bytes_max = 262144,
|
||||
.period_bytes_min = 32,
|
||||
.period_bytes_max = 131072,
|
||||
.periods_min = 2,
|
||||
.periods_max = 220,
|
||||
/* One page (4k) contains 512 instructions. I don't know if the hw
|
||||
supports lists longer than this. In this case periods_max=220 is a
|
||||
safe limit to make sure the list never exceeds 512 instructions. */
|
||||
};
|
||||
|
||||
|
||||
#include "darla20_dsp.c"
|
||||
#include "echoaudio_dsp.c"
|
||||
#include "echoaudio.c"
|
|
@ -0,0 +1,125 @@
|
|||
/***************************************************************************
|
||||
|
||||
Copyright Echo Digital Audio Corporation (c) 1998 - 2004
|
||||
All rights reserved
|
||||
www.echoaudio.com
|
||||
|
||||
This file is part of Echo Digital Audio's generic driver library.
|
||||
|
||||
Echo Digital Audio's generic driver library 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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA.
|
||||
|
||||
*************************************************************************
|
||||
|
||||
Translation from C++ and adaptation for use in ALSA-Driver
|
||||
were made by Giuliano Pochini <pochini@shiny.it>
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
|
||||
{
|
||||
int err;
|
||||
|
||||
DE_INIT(("init_hw() - Darla20\n"));
|
||||
snd_assert((subdevice_id & 0xfff0) == DARLA20, return -ENODEV);
|
||||
|
||||
if ((err = init_dsp_comm_page(chip))) {
|
||||
DE_INIT(("init_hw - could not initialize DSP comm page\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
chip->device_id = device_id;
|
||||
chip->subdevice_id = subdevice_id;
|
||||
chip->bad_board = TRUE;
|
||||
chip->dsp_code_to_load = &card_fw[FW_DARLA20_DSP];
|
||||
chip->spdif_status = GD_SPDIF_STATUS_UNDEF;
|
||||
chip->clock_state = GD_CLOCK_UNDEF;
|
||||
/* Since this card has no ASIC, mark it as loaded so everything
|
||||
works OK */
|
||||
chip->asic_loaded = TRUE;
|
||||
chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL;
|
||||
|
||||
if ((err = load_firmware(chip)) < 0)
|
||||
return err;
|
||||
chip->bad_board = FALSE;
|
||||
|
||||
if ((err = init_line_levels(chip)) < 0)
|
||||
return err;
|
||||
|
||||
DE_INIT(("init_hw done\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* The Darla20 has no external clock sources */
|
||||
static u32 detect_input_clocks(const struct echoaudio *chip)
|
||||
{
|
||||
return ECHO_CLOCK_BIT_INTERNAL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* The Darla20 has no ASIC. Just do nothing */
|
||||
static int load_asic(struct echoaudio *chip)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int set_sample_rate(struct echoaudio *chip, u32 rate)
|
||||
{
|
||||
u8 clock_state, spdif_status;
|
||||
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
|
||||
switch (rate) {
|
||||
case 44100:
|
||||
clock_state = GD_CLOCK_44;
|
||||
spdif_status = GD_SPDIF_STATUS_44;
|
||||
break;
|
||||
case 48000:
|
||||
clock_state = GD_CLOCK_48;
|
||||
spdif_status = GD_SPDIF_STATUS_48;
|
||||
break;
|
||||
default:
|
||||
clock_state = GD_CLOCK_NOCHANGE;
|
||||
spdif_status = GD_SPDIF_STATUS_NOCHANGE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (chip->clock_state == clock_state)
|
||||
clock_state = GD_CLOCK_NOCHANGE;
|
||||
if (spdif_status == chip->spdif_status)
|
||||
spdif_status = GD_SPDIF_STATUS_NOCHANGE;
|
||||
|
||||
chip->comm_page->sample_rate = cpu_to_le32(rate);
|
||||
chip->comm_page->gd_clock_state = clock_state;
|
||||
chip->comm_page->gd_spdif_status = spdif_status;
|
||||
chip->comm_page->gd_resampler_state = 3; /* magic number - should always be 3 */
|
||||
|
||||
/* Save the new audio state if it changed */
|
||||
if (clock_state != GD_CLOCK_NOCHANGE)
|
||||
chip->clock_state = clock_state;
|
||||
if (spdif_status != GD_SPDIF_STATUS_NOCHANGE)
|
||||
chip->spdif_status = spdif_status;
|
||||
chip->sample_rate = rate;
|
||||
|
||||
clear_handshake(chip);
|
||||
return send_vector(chip, DSP_VC_SET_GD_AUDIO_STATE);
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* ALSA driver for Echoaudio soundcards.
|
||||
* Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.it>
|
||||
*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#define ECHOGALS_FAMILY
|
||||
#define ECHOCARD_DARLA24
|
||||
#define ECHOCARD_NAME "Darla24"
|
||||
#define ECHOCARD_HAS_MONITOR
|
||||
#define ECHOCARD_HAS_INPUT_NOMINAL_LEVEL
|
||||
#define ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL
|
||||
#define ECHOCARD_HAS_EXTERNAL_CLOCK
|
||||
#define ECHOCARD_HAS_SUPER_INTERLEAVE
|
||||
|
||||
/* Pipe indexes */
|
||||
#define PX_ANALOG_OUT 0 /* 8 */
|
||||
#define PX_DIGITAL_OUT 8 /* 0 */
|
||||
#define PX_ANALOG_IN 8 /* 2 */
|
||||
#define PX_DIGITAL_IN 10 /* 0 */
|
||||
#define PX_NUM 10
|
||||
|
||||
/* Bus indexes */
|
||||
#define BX_ANALOG_OUT 0 /* 8 */
|
||||
#define BX_DIGITAL_OUT 8 /* 0 */
|
||||
#define BX_ANALOG_IN 8 /* 2 */
|
||||
#define BX_DIGITAL_IN 10 /* 0 */
|
||||
#define BX_NUM 10
|
||||
|
||||
|
||||
#include <sound/driver.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/info.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/initval.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/atomic.h>
|
||||
#include "echoaudio.h"
|
||||
|
||||
#define FW_DARLA24_DSP 0
|
||||
|
||||
static const struct firmware card_fw[] = {
|
||||
{0, "darla24_dsp.fw"}
|
||||
};
|
||||
|
||||
static struct pci_device_id snd_echo_ids[] = {
|
||||
{0x1057, 0x1801, 0xECC0, 0x0040, 0, 0, 0}, /* DSP 56301 Darla24 rev.0 */
|
||||
{0x1057, 0x1801, 0xECC0, 0x0041, 0, 0, 0}, /* DSP 56301 Darla24 rev.1 */
|
||||
{0,}
|
||||
};
|
||||
|
||||
static struct snd_pcm_hardware pcm_hardware_skel = {
|
||||
.info = SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_SYNC_START,
|
||||
.formats = SNDRV_PCM_FMTBIT_U8 |
|
||||
SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_3LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_BE,
|
||||
.rates = SNDRV_PCM_RATE_8000_48000 |
|
||||
SNDRV_PCM_RATE_88200 |
|
||||
SNDRV_PCM_RATE_96000,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 96000,
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.buffer_bytes_max = 262144,
|
||||
.period_bytes_min = 32,
|
||||
.period_bytes_max = 131072,
|
||||
.periods_min = 2,
|
||||
.periods_max = 220,
|
||||
/* One page (4k) contains 512 instructions. I don't know if the hw
|
||||
supports lists longer than this. In this case periods_max=220 is a
|
||||
safe limit to make sure the list never exceeds 512 instructions. */
|
||||
};
|
||||
|
||||
|
||||
#include "darla24_dsp.c"
|
||||
#include "echoaudio_dsp.c"
|
||||
#include "echoaudio.c"
|
|
@ -0,0 +1,156 @@
|
|||
/***************************************************************************
|
||||
|
||||
Copyright Echo Digital Audio Corporation (c) 1998 - 2004
|
||||
All rights reserved
|
||||
www.echoaudio.com
|
||||
|
||||
This file is part of Echo Digital Audio's generic driver library.
|
||||
|
||||
Echo Digital Audio's generic driver library 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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA.
|
||||
|
||||
*************************************************************************
|
||||
|
||||
Translation from C++ and adaptation for use in ALSA-Driver
|
||||
were made by Giuliano Pochini <pochini@shiny.it>
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
|
||||
{
|
||||
int err;
|
||||
|
||||
DE_INIT(("init_hw() - Darla24\n"));
|
||||
snd_assert((subdevice_id & 0xfff0) == DARLA24, return -ENODEV);
|
||||
|
||||
if ((err = init_dsp_comm_page(chip))) {
|
||||
DE_INIT(("init_hw - could not initialize DSP comm page\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
chip->device_id = device_id;
|
||||
chip->subdevice_id = subdevice_id;
|
||||
chip->bad_board = TRUE;
|
||||
chip->dsp_code_to_load = &card_fw[FW_DARLA24_DSP];
|
||||
/* Since this card has no ASIC, mark it as loaded so everything
|
||||
works OK */
|
||||
chip->asic_loaded = TRUE;
|
||||
chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL |
|
||||
ECHO_CLOCK_BIT_ESYNC;
|
||||
|
||||
if ((err = load_firmware(chip)) < 0)
|
||||
return err;
|
||||
chip->bad_board = FALSE;
|
||||
|
||||
if ((err = init_line_levels(chip)) < 0)
|
||||
return err;
|
||||
|
||||
DE_INIT(("init_hw done\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static u32 detect_input_clocks(const struct echoaudio *chip)
|
||||
{
|
||||
u32 clocks_from_dsp, clock_bits;
|
||||
|
||||
/* Map the DSP clock detect bits to the generic driver clock
|
||||
detect bits */
|
||||
clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
|
||||
|
||||
clock_bits = ECHO_CLOCK_BIT_INTERNAL;
|
||||
|
||||
if (clocks_from_dsp & GLDM_CLOCK_DETECT_BIT_ESYNC)
|
||||
clock_bits |= ECHO_CLOCK_BIT_ESYNC;
|
||||
|
||||
return clock_bits;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* The Darla24 has no ASIC. Just do nothing */
|
||||
static int load_asic(struct echoaudio *chip)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int set_sample_rate(struct echoaudio *chip, u32 rate)
|
||||
{
|
||||
u8 clock;
|
||||
|
||||
switch (rate) {
|
||||
case 96000:
|
||||
clock = GD24_96000;
|
||||
break;
|
||||
case 88200:
|
||||
clock = GD24_88200;
|
||||
break;
|
||||
case 48000:
|
||||
clock = GD24_48000;
|
||||
break;
|
||||
case 44100:
|
||||
clock = GD24_44100;
|
||||
break;
|
||||
case 32000:
|
||||
clock = GD24_32000;
|
||||
break;
|
||||
case 22050:
|
||||
clock = GD24_22050;
|
||||
break;
|
||||
case 16000:
|
||||
clock = GD24_16000;
|
||||
break;
|
||||
case 11025:
|
||||
clock = GD24_11025;
|
||||
break;
|
||||
case 8000:
|
||||
clock = GD24_8000;
|
||||
break;
|
||||
default:
|
||||
DE_ACT(("set_sample_rate: Error, invalid sample rate %d\n",
|
||||
rate));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
|
||||
DE_ACT(("set_sample_rate: %d clock %d\n", rate, clock));
|
||||
chip->sample_rate = rate;
|
||||
|
||||
/* Override the sample rate if this card is set to Echo sync. */
|
||||
if (chip->input_clock == ECHO_CLOCK_ESYNC)
|
||||
clock = GD24_EXT_SYNC;
|
||||
|
||||
chip->comm_page->sample_rate = cpu_to_le32(rate); /* ignored by the DSP ? */
|
||||
chip->comm_page->gd_clock_state = clock;
|
||||
clear_handshake(chip);
|
||||
return send_vector(chip, DSP_VC_SET_GD_AUDIO_STATE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int set_input_clock(struct echoaudio *chip, u16 clock)
|
||||
{
|
||||
snd_assert(clock == ECHO_CLOCK_INTERNAL ||
|
||||
clock == ECHO_CLOCK_ESYNC, return -EINVAL);
|
||||
chip->input_clock = clock;
|
||||
return set_sample_rate(chip, chip->sample_rate);
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* ALSA driver for Echoaudio soundcards.
|
||||
* Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.it>
|
||||
*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#define ECHO3G_FAMILY
|
||||
#define ECHOCARD_ECHO3G
|
||||
#define ECHOCARD_NAME "Echo3G"
|
||||
#define ECHOCARD_HAS_MONITOR
|
||||
#define ECHOCARD_HAS_ASIC
|
||||
#define ECHOCARD_HAS_INPUT_NOMINAL_LEVEL
|
||||
#define ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL
|
||||
#define ECHOCARD_HAS_SUPER_INTERLEAVE
|
||||
#define ECHOCARD_HAS_DIGITAL_IO
|
||||
#define ECHOCARD_HAS_DIGITAL_MODE_SWITCH
|
||||
#define ECHOCARD_HAS_ADAT 6
|
||||
#define ECHOCARD_HAS_EXTERNAL_CLOCK
|
||||
#define ECHOCARD_HAS_STEREO_BIG_ENDIAN32
|
||||
#define ECHOCARD_HAS_MIDI
|
||||
#define ECHOCARD_HAS_PHANTOM_POWER
|
||||
|
||||
/* Pipe indexes */
|
||||
#define PX_ANALOG_OUT 0
|
||||
#define PX_DIGITAL_OUT chip->px_digital_out
|
||||
#define PX_ANALOG_IN chip->px_analog_in
|
||||
#define PX_DIGITAL_IN chip->px_digital_in
|
||||
#define PX_NUM chip->px_num
|
||||
|
||||
/* Bus indexes */
|
||||
#define BX_ANALOG_OUT 0
|
||||
#define BX_DIGITAL_OUT chip->bx_digital_out
|
||||
#define BX_ANALOG_IN chip->bx_analog_in
|
||||
#define BX_DIGITAL_IN chip->bx_digital_in
|
||||
#define BX_NUM chip->bx_num
|
||||
|
||||
|
||||
#include <sound/driver.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/info.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/rawmidi.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/atomic.h>
|
||||
#include "echoaudio.h"
|
||||
|
||||
#define FW_361_LOADER 0
|
||||
#define FW_ECHO3G_DSP 1
|
||||
#define FW_3G_ASIC 2
|
||||
|
||||
static const struct firmware card_fw[] = {
|
||||
{0, "loader_dsp.fw"},
|
||||
{0, "echo3g_dsp.fw"},
|
||||
{0, "3g_asic.fw"}
|
||||
};
|
||||
|
||||
static struct pci_device_id snd_echo_ids[] = {
|
||||
{0x1057, 0x3410, 0xECC0, 0x0100, 0, 0, 0}, /* Echo 3G */
|
||||
{0,}
|
||||
};
|
||||
|
||||
static struct snd_pcm_hardware pcm_hardware_skel = {
|
||||
.info = SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_SYNC_START,
|
||||
.formats = SNDRV_PCM_FMTBIT_U8 |
|
||||
SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_3LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_BE,
|
||||
.rates = SNDRV_PCM_RATE_32000 |
|
||||
SNDRV_PCM_RATE_44100 |
|
||||
SNDRV_PCM_RATE_48000 |
|
||||
SNDRV_PCM_RATE_88200 |
|
||||
SNDRV_PCM_RATE_96000 |
|
||||
SNDRV_PCM_RATE_CONTINUOUS,
|
||||
.rate_min = 32000,
|
||||
.rate_max = 100000,
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.buffer_bytes_max = 262144,
|
||||
.period_bytes_min = 32,
|
||||
.period_bytes_max = 131072,
|
||||
.periods_min = 2,
|
||||
.periods_max = 220,
|
||||
};
|
||||
|
||||
#include "echo3g_dsp.c"
|
||||
#include "echoaudio_dsp.c"
|
||||
#include "echoaudio_3g.c"
|
||||
#include "echoaudio.c"
|
||||
#include "midi.c"
|
|
@ -0,0 +1,131 @@
|
|||
/****************************************************************************
|
||||
|
||||
Copyright Echo Digital Audio Corporation (c) 1998 - 2004
|
||||
All rights reserved
|
||||
www.echoaudio.com
|
||||
|
||||
This file is part of Echo Digital Audio's generic driver library.
|
||||
|
||||
Echo Digital Audio's generic driver library 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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA.
|
||||
|
||||
*************************************************************************
|
||||
|
||||
Translation from C++ and adaptation for use in ALSA-Driver
|
||||
were made by Giuliano Pochini <pochini@shiny.it>
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
static int load_asic(struct echoaudio *chip);
|
||||
static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode);
|
||||
static int set_digital_mode(struct echoaudio *chip, u8 mode);
|
||||
static int check_asic_status(struct echoaudio *chip);
|
||||
static int set_sample_rate(struct echoaudio *chip, u32 rate);
|
||||
static int set_input_clock(struct echoaudio *chip, u16 clock);
|
||||
static int set_professional_spdif(struct echoaudio *chip, char prof);
|
||||
static int set_phantom_power(struct echoaudio *chip, char on);
|
||||
static int write_control_reg(struct echoaudio *chip, u32 ctl, u32 frq,
|
||||
char force);
|
||||
|
||||
#include <linux/irq.h>
|
||||
|
||||
static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
|
||||
{
|
||||
int err;
|
||||
|
||||
local_irq_enable();
|
||||
DE_INIT(("init_hw() - Echo3G\n"));
|
||||
snd_assert((subdevice_id & 0xfff0) == ECHO3G, return -ENODEV);
|
||||
|
||||
if ((err = init_dsp_comm_page(chip))) {
|
||||
DE_INIT(("init_hw - could not initialize DSP comm page\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
chip->comm_page->e3g_frq_register =
|
||||
__constant_cpu_to_le32((E3G_MAGIC_NUMBER / 48000) - 2);
|
||||
chip->device_id = device_id;
|
||||
chip->subdevice_id = subdevice_id;
|
||||
chip->bad_board = TRUE;
|
||||
chip->has_midi = TRUE;
|
||||
chip->dsp_code_to_load = &card_fw[FW_ECHO3G_DSP];
|
||||
|
||||
/* Load the DSP code and the ASIC on the PCI card and get
|
||||
what type of external box is attached */
|
||||
err = load_firmware(chip);
|
||||
|
||||
if (err < 0) {
|
||||
return err;
|
||||
} else if (err == E3G_GINA3G_BOX_TYPE) {
|
||||
chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL |
|
||||
ECHO_CLOCK_BIT_SPDIF |
|
||||
ECHO_CLOCK_BIT_ADAT;
|
||||
chip->card_name = "Gina3G";
|
||||
chip->px_digital_out = chip->bx_digital_out = 6;
|
||||
chip->px_analog_in = chip->bx_analog_in = 14;
|
||||
chip->px_digital_in = chip->bx_digital_in = 16;
|
||||
chip->px_num = chip->bx_num = 24;
|
||||
chip->has_phantom_power = TRUE;
|
||||
chip->hasnt_input_nominal_level = TRUE;
|
||||
} else if (err == E3G_LAYLA3G_BOX_TYPE) {
|
||||
chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL |
|
||||
ECHO_CLOCK_BIT_SPDIF |
|
||||
ECHO_CLOCK_BIT_ADAT |
|
||||
ECHO_CLOCK_BIT_WORD;
|
||||
chip->card_name = "Layla3G";
|
||||
chip->px_digital_out = chip->bx_digital_out = 8;
|
||||
chip->px_analog_in = chip->bx_analog_in = 16;
|
||||
chip->px_digital_in = chip->bx_digital_in = 24;
|
||||
chip->px_num = chip->bx_num = 32;
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
chip->digital_modes = ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA |
|
||||
ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL |
|
||||
ECHOCAPS_HAS_DIGITAL_MODE_ADAT;
|
||||
chip->digital_mode = DIGITAL_MODE_SPDIF_RCA;
|
||||
chip->professional_spdif = FALSE;
|
||||
chip->non_audio_spdif = FALSE;
|
||||
chip->bad_board = FALSE;
|
||||
|
||||
if ((err = init_line_levels(chip)) < 0)
|
||||
return err;
|
||||
err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA);
|
||||
snd_assert(err >= 0, return err);
|
||||
err = set_phantom_power(chip, 0);
|
||||
snd_assert(err >= 0, return err);
|
||||
err = set_professional_spdif(chip, TRUE);
|
||||
|
||||
DE_INIT(("init_hw done\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int set_phantom_power(struct echoaudio *chip, char on)
|
||||
{
|
||||
u32 control_reg = le32_to_cpu(chip->comm_page->control_register);
|
||||
|
||||
if (on)
|
||||
control_reg |= E3G_PHANTOM_POWER;
|
||||
else
|
||||
control_reg &= ~E3G_PHANTOM_POWER;
|
||||
|
||||
chip->phantom_power = on;
|
||||
return write_control_reg(chip, control_reg,
|
||||
le32_to_cpu(chip->comm_page->e3g_frq_register),
|
||||
0);
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,590 @@
|
|||
/****************************************************************************
|
||||
|
||||
Copyright Echo Digital Audio Corporation (c) 1998 - 2004
|
||||
All rights reserved
|
||||
www.echoaudio.com
|
||||
|
||||
This file is part of Echo Digital Audio's generic driver library.
|
||||
|
||||
Echo Digital Audio's generic driver library 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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA.
|
||||
|
||||
****************************************************************************
|
||||
|
||||
Translation from C++ and adaptation for use in ALSA-Driver
|
||||
were made by Giuliano Pochini <pochini@shiny.it>
|
||||
|
||||
****************************************************************************
|
||||
|
||||
|
||||
Here's a block diagram of how most of the cards work:
|
||||
|
||||
+-----------+
|
||||
record | |<-------------------- Inputs
|
||||
<-------| | |
|
||||
PCI | Transport | |
|
||||
bus | engine | \|/
|
||||
------->| | +-------+
|
||||
play | |--->|monitor|-------> Outputs
|
||||
+-----------+ | mixer |
|
||||
+-------+
|
||||
|
||||
The lines going to and from the PCI bus represent "pipes". A pipe performs
|
||||
audio transport - moving audio data to and from buffers on the host via
|
||||
bus mastering.
|
||||
|
||||
The inputs and outputs on the right represent input and output "busses."
|
||||
A bus is a physical, real connection to the outside world. An example
|
||||
of a bus would be the 1/4" analog connectors on the back of Layla or
|
||||
an RCA S/PDIF connector.
|
||||
|
||||
For most cards, there is a one-to-one correspondence between outputs
|
||||
and busses; that is, each individual pipe is hard-wired to a single bus.
|
||||
|
||||
Cards that work this way are Darla20, Gina20, Layla20, Darla24, Gina24,
|
||||
Layla24, Mona, and Indigo.
|
||||
|
||||
|
||||
Mia has a feature called "virtual outputs."
|
||||
|
||||
|
||||
+-----------+
|
||||
record | |<----------------------------- Inputs
|
||||
<-------| | |
|
||||
PCI | Transport | |
|
||||
bus | engine | \|/
|
||||
------->| | +------+ +-------+
|
||||
play | |-->|vmixer|-->|monitor|-------> Outputs
|
||||
+-----------+ +------+ | mixer |
|
||||
+-------+
|
||||
|
||||
|
||||
Obviously, the difference here is the box labeled "vmixer." Vmixer is
|
||||
short for "virtual output mixer." For Mia, pipes are *not* hard-wired
|
||||
to a single bus; the vmixer lets you mix any pipe to any bus in any
|
||||
combination.
|
||||
|
||||
Note, however, that the left-hand side of the diagram is unchanged.
|
||||
Transport works exactly the same way - the difference is in the mixer stage.
|
||||
|
||||
|
||||
Pipes and busses are numbered starting at zero.
|
||||
|
||||
|
||||
|
||||
Pipe index
|
||||
==========
|
||||
|
||||
A number of calls in CEchoGals refer to a "pipe index". A pipe index is
|
||||
a unique number for a pipe that unambiguously refers to a playback or record
|
||||
pipe. Pipe indices are numbered starting with analog outputs, followed by
|
||||
digital outputs, then analog inputs, then digital inputs.
|
||||
|
||||
Take Gina24 as an example:
|
||||
|
||||
Pipe index
|
||||
|
||||
0-7 Analog outputs (0 .. FirstDigitalBusOut-1)
|
||||
8-15 Digital outputs (FirstDigitalBusOut .. NumBussesOut-1)
|
||||
16-17 Analog inputs
|
||||
18-25 Digital inputs
|
||||
|
||||
|
||||
You get the pipe index by calling CEchoGals::OpenAudio; the other transport
|
||||
functions take the pipe index as a parameter. If you need a pipe index for
|
||||
some other reason, use the handy Makepipe_index method.
|
||||
|
||||
|
||||
Some calls take a CChannelMask parameter; CChannelMask is a handy way to
|
||||
group pipe indices.
|
||||
|
||||
|
||||
|
||||
Digital mode switch
|
||||
===================
|
||||
|
||||
Some cards (right now, Gina24, Layla24, and Mona) have a Digital Mode Switch
|
||||
or DMS. Cards with a DMS can be set to one of three mutually exclusive
|
||||
digital modes: S/PDIF RCA, S/PDIF optical, or ADAT optical.
|
||||
|
||||
This may create some confusion since ADAT optical is 8 channels wide and
|
||||
S/PDIF is only two channels wide. Gina24, Layla24, and Mona handle this
|
||||
by acting as if they always have 8 digital outs and ins. If you are in
|
||||
either S/PDIF mode, the last 6 channels don't do anything - data sent
|
||||
out these channels is thrown away and you will always record zeros.
|
||||
|
||||
Note that with Gina24, Layla24, and Mona, sample rates above 50 kHz are
|
||||
only available if you have the card configured for S/PDIF optical or S/PDIF
|
||||
RCA.
|
||||
|
||||
|
||||
|
||||
Double speed mode
|
||||
=================
|
||||
|
||||
Some of the cards support 88.2 kHz and 96 kHz sampling (Darla24, Gina24,
|
||||
Layla24, Mona, Mia, and Indigo). For these cards, the driver sometimes has
|
||||
to worry about "double speed mode"; double speed mode applies whenever the
|
||||
sampling rate is above 50 kHz.
|
||||
|
||||
For instance, Mona and Layla24 support word clock sync. However, they
|
||||
actually support two different word clock modes - single speed (below
|
||||
50 kHz) and double speed (above 50 kHz). The hardware detects if a single
|
||||
or double speed word clock signal is present; the generic code uses that
|
||||
information to determine which mode to use.
|
||||
|
||||
The generic code takes care of all this for you.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _ECHOAUDIO_H_
|
||||
#define _ECHOAUDIO_H_
|
||||
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
#include "echoaudio_dsp.h"
|
||||
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
|
||||
PCI configuration space
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
/*
|
||||
* PCI vendor ID and device IDs for the hardware
|
||||
*/
|
||||
#define VENDOR_ID 0x1057
|
||||
#define DEVICE_ID_56301 0x1801
|
||||
#define DEVICE_ID_56361 0x3410
|
||||
#define SUBVENDOR_ID 0xECC0
|
||||
|
||||
|
||||
/*
|
||||
* Valid Echo PCI subsystem card IDs
|
||||
*/
|
||||
#define DARLA20 0x0010
|
||||
#define GINA20 0x0020
|
||||
#define LAYLA20 0x0030
|
||||
#define DARLA24 0x0040
|
||||
#define GINA24 0x0050
|
||||
#define LAYLA24 0x0060
|
||||
#define MONA 0x0070
|
||||
#define MIA 0x0080
|
||||
#define INDIGO 0x0090
|
||||
#define INDIGO_IO 0x00a0
|
||||
#define INDIGO_DJ 0x00b0
|
||||
#define ECHO3G 0x0100
|
||||
|
||||
|
||||
/************************************************************************
|
||||
|
||||
Array sizes and so forth
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
/*
|
||||
* Sizes
|
||||
*/
|
||||
#define ECHO_MAXAUDIOINPUTS 32 /* Max audio input channels */
|
||||
#define ECHO_MAXAUDIOOUTPUTS 32 /* Max audio output channels */
|
||||
#define ECHO_MAXAUDIOPIPES 32 /* Max number of input and output
|
||||
* pipes */
|
||||
#define E3G_MAX_OUTPUTS 16
|
||||
#define ECHO_MAXMIDIJACKS 1 /* Max MIDI ports */
|
||||
#define ECHO_MIDI_QUEUE_SZ 512 /* Max MIDI input queue entries */
|
||||
#define ECHO_MTC_QUEUE_SZ 32 /* Max MIDI time code input queue
|
||||
* entries */
|
||||
|
||||
/*
|
||||
* MIDI activity indicator timeout
|
||||
*/
|
||||
#define MIDI_ACTIVITY_TIMEOUT_USEC 200000
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
|
||||
Clocks
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Clock numbers
|
||||
*/
|
||||
#define ECHO_CLOCK_INTERNAL 0
|
||||
#define ECHO_CLOCK_WORD 1
|
||||
#define ECHO_CLOCK_SUPER 2
|
||||
#define ECHO_CLOCK_SPDIF 3
|
||||
#define ECHO_CLOCK_ADAT 4
|
||||
#define ECHO_CLOCK_ESYNC 5
|
||||
#define ECHO_CLOCK_ESYNC96 6
|
||||
#define ECHO_CLOCK_MTC 7
|
||||
#define ECHO_CLOCK_NUMBER 8
|
||||
#define ECHO_CLOCKS 0xffff
|
||||
|
||||
/*
|
||||
* Clock bit numbers - used to report capabilities and whatever clocks
|
||||
* are being detected dynamically.
|
||||
*/
|
||||
#define ECHO_CLOCK_BIT_INTERNAL (1 << ECHO_CLOCK_INTERNAL)
|
||||
#define ECHO_CLOCK_BIT_WORD (1 << ECHO_CLOCK_WORD)
|
||||
#define ECHO_CLOCK_BIT_SUPER (1 << ECHO_CLOCK_SUPER)
|
||||
#define ECHO_CLOCK_BIT_SPDIF (1 << ECHO_CLOCK_SPDIF)
|
||||
#define ECHO_CLOCK_BIT_ADAT (1 << ECHO_CLOCK_ADAT)
|
||||
#define ECHO_CLOCK_BIT_ESYNC (1 << ECHO_CLOCK_ESYNC)
|
||||
#define ECHO_CLOCK_BIT_ESYNC96 (1 << ECHO_CLOCK_ESYNC96)
|
||||
#define ECHO_CLOCK_BIT_MTC (1<<ECHO_CLOCK_MTC)
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
Digital modes
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Digital modes for Mona, Layla24, and Gina24
|
||||
*/
|
||||
#define DIGITAL_MODE_NONE 0xFF
|
||||
#define DIGITAL_MODE_SPDIF_RCA 0
|
||||
#define DIGITAL_MODE_SPDIF_OPTICAL 1
|
||||
#define DIGITAL_MODE_ADAT 2
|
||||
#define DIGITAL_MODE_SPDIF_CDROM 3
|
||||
#define DIGITAL_MODES 4
|
||||
|
||||
/*
|
||||
* Digital mode capability masks
|
||||
*/
|
||||
#define ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA (1 << DIGITAL_MODE_SPDIF_RCA)
|
||||
#define ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL (1 << DIGITAL_MODE_SPDIF_OPTICAL)
|
||||
#define ECHOCAPS_HAS_DIGITAL_MODE_ADAT (1 << DIGITAL_MODE_ADAT)
|
||||
#define ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_CDROM (1 << DIGITAL_MODE_SPDIF_CDROM)
|
||||
|
||||
|
||||
#define EXT_3GBOX_NC 0x01 /* 3G box not connected */
|
||||
#define EXT_3GBOX_NOT_SET 0x02 /* 3G box not detected yet */
|
||||
|
||||
|
||||
#define ECHOGAIN_MUTED (-128) /* Minimum possible gain */
|
||||
#define ECHOGAIN_MINOUT (-128) /* Min output gain (dB) */
|
||||
#define ECHOGAIN_MAXOUT (6) /* Max output gain (dB) */
|
||||
#define ECHOGAIN_MININP (-50) /* Min input gain (0.5 dB) */
|
||||
#define ECHOGAIN_MAXINP (50) /* Max input gain (0.5 dB) */
|
||||
|
||||
#define PIPE_STATE_STOPPED 0 /* Pipe has been reset */
|
||||
#define PIPE_STATE_PAUSED 1 /* Pipe has been stopped */
|
||||
#define PIPE_STATE_STARTED 2 /* Pipe has been started */
|
||||
#define PIPE_STATE_PENDING 3 /* Pipe has pending start */
|
||||
|
||||
|
||||
/* Debug initialization */
|
||||
#ifdef CONFIG_SND_DEBUG
|
||||
#define DE_INIT(x) snd_printk x
|
||||
#else
|
||||
#define DE_INIT(x)
|
||||
#endif
|
||||
|
||||
/* Debug hw_params callbacks */
|
||||
#ifdef CONFIG_SND_DEBUG
|
||||
#define DE_HWP(x) snd_printk x
|
||||
#else
|
||||
#define DE_HWP(x)
|
||||
#endif
|
||||
|
||||
/* Debug normal activity (open, start, stop...) */
|
||||
#ifdef CONFIG_SND_DEBUG
|
||||
#define DE_ACT(x) snd_printk x
|
||||
#else
|
||||
#define DE_ACT(x)
|
||||
#endif
|
||||
|
||||
/* Debug midi activity */
|
||||
#ifdef CONFIG_SND_DEBUG
|
||||
#define DE_MID(x) snd_printk x
|
||||
#else
|
||||
#define DE_MID(x)
|
||||
#endif
|
||||
|
||||
|
||||
struct audiopipe {
|
||||
volatile u32 *dma_counter; /* Commpage register that contains
|
||||
* the current dma position
|
||||
* (lower 32 bits only)
|
||||
*/
|
||||
u32 last_counter; /* The last position, which is used
|
||||
* to compute...
|
||||
*/
|
||||
u32 position; /* ...the number of bytes tranferred
|
||||
* by the DMA engine, modulo the
|
||||
* buffer size
|
||||
*/
|
||||
short index; /* Index of the first channel or <0
|
||||
* if hw is not configured yet
|
||||
*/
|
||||
short interleave;
|
||||
struct snd_dma_buffer sgpage; /* Room for the scatter-gather list */
|
||||
struct snd_pcm_hardware hw;
|
||||
struct snd_pcm_hw_constraint_list constr;
|
||||
short sglist_head;
|
||||
char state; /* pipe state */
|
||||
};
|
||||
|
||||
|
||||
struct audioformat {
|
||||
u8 interleave; /* How the data is arranged in memory:
|
||||
* mono = 1, stereo = 2, ...
|
||||
*/
|
||||
u8 bits_per_sample; /* 8, 16, 24, 32 (24 bits left aligned) */
|
||||
char mono_to_stereo; /* Only used if interleave is 1 and
|
||||
* if this is an output pipe.
|
||||
*/
|
||||
char data_are_bigendian; /* 1 = big endian, 0 = little endian */
|
||||
};
|
||||
|
||||
|
||||
struct echoaudio {
|
||||
spinlock_t lock;
|
||||
struct snd_pcm_substream *substream[DSP_MAXPIPES];
|
||||
int last_period[DSP_MAXPIPES];
|
||||
struct semaphore mode_mutex;
|
||||
u16 num_digital_modes, digital_mode_list[6];
|
||||
u16 num_clock_sources, clock_source_list[10];
|
||||
atomic_t opencount;
|
||||
struct snd_kcontrol *clock_src_ctl;
|
||||
struct snd_pcm *analog_pcm, *digital_pcm;
|
||||
struct snd_card *card;
|
||||
const char *card_name;
|
||||
struct pci_dev *pci;
|
||||
unsigned long dsp_registers_phys;
|
||||
struct resource *iores;
|
||||
struct snd_dma_buffer commpage_dma_buf;
|
||||
int irq;
|
||||
#ifdef ECHOCARD_HAS_MIDI
|
||||
struct snd_rawmidi *rmidi;
|
||||
struct snd_rawmidi_substream *midi_in, *midi_out;
|
||||
#endif
|
||||
struct timer_list timer;
|
||||
char tinuse; /* Timer in use */
|
||||
char midi_full; /* MIDI output buffer is full */
|
||||
char can_set_rate;
|
||||
char rate_set;
|
||||
|
||||
/* This stuff is used mainly by the lowlevel code */
|
||||
struct comm_page *comm_page; /* Virtual address of the memory
|
||||
* seen by DSP
|
||||
*/
|
||||
u32 pipe_alloc_mask; /* Bitmask of allocated pipes */
|
||||
u32 pipe_cyclic_mask; /* Bitmask of pipes with cyclic
|
||||
* buffers
|
||||
*/
|
||||
u32 sample_rate; /* Card sample rate in Hz */
|
||||
u8 digital_mode; /* Current digital mode
|
||||
* (see DIGITAL_MODE_*)
|
||||
*/
|
||||
u8 spdif_status; /* Gina20, Darla20, Darla24 - only */
|
||||
u8 clock_state; /* Gina20, Darla20, Darla24 - only */
|
||||
u8 input_clock; /* Currently selected sample clock
|
||||
* source
|
||||
*/
|
||||
u8 output_clock; /* Layla20 only */
|
||||
char meters_enabled; /* VU-meters status */
|
||||
char asic_loaded; /* Set TRUE when ASIC loaded */
|
||||
char bad_board; /* Set TRUE if DSP won't load */
|
||||
char professional_spdif; /* 0 = consumer; 1 = professional */
|
||||
char non_audio_spdif; /* 3G - only */
|
||||
char digital_in_automute; /* Gina24, Layla24, Mona - only */
|
||||
char has_phantom_power;
|
||||
char hasnt_input_nominal_level; /* Gina3G */
|
||||
char phantom_power; /* Gina3G - only */
|
||||
char has_midi;
|
||||
char midi_input_enabled;
|
||||
|
||||
#ifdef ECHOCARD_ECHO3G
|
||||
/* External module -dependent pipe and bus indexes */
|
||||
char px_digital_out, px_analog_in, px_digital_in, px_num;
|
||||
char bx_digital_out, bx_analog_in, bx_digital_in, bx_num;
|
||||
#endif
|
||||
|
||||
char nominal_level[ECHO_MAXAUDIOPIPES]; /* True == -10dBV
|
||||
* False == +4dBu */
|
||||
s8 input_gain[ECHO_MAXAUDIOINPUTS]; /* Input level -50..+50
|
||||
* unit is 0.5dB */
|
||||
s8 output_gain[ECHO_MAXAUDIOOUTPUTS]; /* Output level -128..+6 dB
|
||||
* (-128=muted) */
|
||||
s8 monitor_gain[ECHO_MAXAUDIOOUTPUTS][ECHO_MAXAUDIOINPUTS];
|
||||
/* -128..+6 dB */
|
||||
s8 vmixer_gain[ECHO_MAXAUDIOOUTPUTS][ECHO_MAXAUDIOOUTPUTS];
|
||||
/* -128..+6 dB */
|
||||
|
||||
u16 digital_modes; /* Bitmask of supported modes
|
||||
* (see ECHOCAPS_HAS_DIGITAL_MODE_*) */
|
||||
u16 input_clock_types; /* Suppoted input clock types */
|
||||
u16 output_clock_types; /* Suppoted output clock types -
|
||||
* Layla20 only */
|
||||
u16 device_id, subdevice_id;
|
||||
u16 *dsp_code; /* Current DSP code loaded,
|
||||
* NULL if nothing loaded */
|
||||
const struct firmware *dsp_code_to_load;/* DSP code to load */
|
||||
const struct firmware *asic_code; /* Current ASIC code */
|
||||
u32 comm_page_phys; /* Physical address of the
|
||||
* memory seen by DSP */
|
||||
volatile u32 __iomem *dsp_registers; /* DSP's register base */
|
||||
u32 active_mask; /* Chs. active mask or
|
||||
* punks out */
|
||||
|
||||
#ifdef ECHOCARD_HAS_MIDI
|
||||
u16 mtc_state; /* State for MIDI input parsing state machine */
|
||||
u8 midi_buffer[MIDI_IN_BUFFER_SIZE];
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
static int init_dsp_comm_page(struct echoaudio *chip);
|
||||
static int init_line_levels(struct echoaudio *chip);
|
||||
static int free_pipes(struct echoaudio *chip, struct audiopipe *pipe);
|
||||
static int load_firmware(struct echoaudio *chip);
|
||||
static int wait_handshake(struct echoaudio *chip);
|
||||
static int send_vector(struct echoaudio *chip, u32 command);
|
||||
static int get_firmware(const struct firmware **fw_entry,
|
||||
const struct firmware *frm, struct echoaudio *chip);
|
||||
static void free_firmware(const struct firmware *fw_entry);
|
||||
|
||||
#ifdef ECHOCARD_HAS_MIDI
|
||||
static int enable_midi_input(struct echoaudio *chip, char enable);
|
||||
static int midi_service_irq(struct echoaudio *chip);
|
||||
static int __devinit snd_echo_midi_create(struct snd_card *card,
|
||||
struct echoaudio *chip);
|
||||
#endif
|
||||
|
||||
|
||||
static inline void clear_handshake(struct echoaudio *chip)
|
||||
{
|
||||
chip->comm_page->handshake = 0;
|
||||
}
|
||||
|
||||
static inline u32 get_dsp_register(struct echoaudio *chip, u32 index)
|
||||
{
|
||||
return readl(&chip->dsp_registers[index]);
|
||||
}
|
||||
|
||||
static inline void set_dsp_register(struct echoaudio *chip, u32 index,
|
||||
u32 value)
|
||||
{
|
||||
writel(value, &chip->dsp_registers[index]);
|
||||
}
|
||||
|
||||
|
||||
/* Pipe and bus indexes. PX_* and BX_* are defined as chip->px_* and chip->bx_*
|
||||
for 3G cards because they depend on the external box. They are integer
|
||||
constants for all other cards.
|
||||
Never use those defines directly, use the following functions instead. */
|
||||
|
||||
static inline int px_digital_out(const struct echoaudio *chip)
|
||||
{
|
||||
return PX_DIGITAL_OUT;
|
||||
}
|
||||
|
||||
static inline int px_analog_in(const struct echoaudio *chip)
|
||||
{
|
||||
return PX_ANALOG_IN;
|
||||
}
|
||||
|
||||
static inline int px_digital_in(const struct echoaudio *chip)
|
||||
{
|
||||
return PX_DIGITAL_IN;
|
||||
}
|
||||
|
||||
static inline int px_num(const struct echoaudio *chip)
|
||||
{
|
||||
return PX_NUM;
|
||||
}
|
||||
|
||||
static inline int bx_digital_out(const struct echoaudio *chip)
|
||||
{
|
||||
return BX_DIGITAL_OUT;
|
||||
}
|
||||
|
||||
static inline int bx_analog_in(const struct echoaudio *chip)
|
||||
{
|
||||
return BX_ANALOG_IN;
|
||||
}
|
||||
|
||||
static inline int bx_digital_in(const struct echoaudio *chip)
|
||||
{
|
||||
return BX_DIGITAL_IN;
|
||||
}
|
||||
|
||||
static inline int bx_num(const struct echoaudio *chip)
|
||||
{
|
||||
return BX_NUM;
|
||||
}
|
||||
|
||||
static inline int num_pipes_out(const struct echoaudio *chip)
|
||||
{
|
||||
return px_analog_in(chip);
|
||||
}
|
||||
|
||||
static inline int num_pipes_in(const struct echoaudio *chip)
|
||||
{
|
||||
return px_num(chip) - px_analog_in(chip);
|
||||
}
|
||||
|
||||
static inline int num_busses_out(const struct echoaudio *chip)
|
||||
{
|
||||
return bx_analog_in(chip);
|
||||
}
|
||||
|
||||
static inline int num_busses_in(const struct echoaudio *chip)
|
||||
{
|
||||
return bx_num(chip) - bx_analog_in(chip);
|
||||
}
|
||||
|
||||
static inline int num_analog_busses_out(const struct echoaudio *chip)
|
||||
{
|
||||
return bx_digital_out(chip);
|
||||
}
|
||||
|
||||
static inline int num_analog_busses_in(const struct echoaudio *chip)
|
||||
{
|
||||
return bx_digital_in(chip) - bx_analog_in(chip);
|
||||
}
|
||||
|
||||
static inline int num_digital_busses_out(const struct echoaudio *chip)
|
||||
{
|
||||
return num_busses_out(chip) - num_analog_busses_out(chip);
|
||||
}
|
||||
|
||||
static inline int num_digital_busses_in(const struct echoaudio *chip)
|
||||
{
|
||||
return num_busses_in(chip) - num_analog_busses_in(chip);
|
||||
}
|
||||
|
||||
/* The monitor array is a one-dimensional array; compute the offset
|
||||
* into the array */
|
||||
static inline int monitor_index(const struct echoaudio *chip, int out, int in)
|
||||
{
|
||||
return out * num_busses_in(chip) + in;
|
||||
}
|
||||
|
||||
|
||||
#ifndef pci_device
|
||||
#define pci_device(chip) (&chip->pci->dev)
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _ECHOAUDIO_H_ */
|
|
@ -0,0 +1,431 @@
|
|||
/****************************************************************************
|
||||
|
||||
Copyright Echo Digital Audio Corporation (c) 1998 - 2004
|
||||
All rights reserved
|
||||
www.echoaudio.com
|
||||
|
||||
This file is part of Echo Digital Audio's generic driver library.
|
||||
|
||||
Echo Digital Audio's generic driver library 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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA.
|
||||
|
||||
*************************************************************************
|
||||
|
||||
Translation from C++ and adaptation for use in ALSA-Driver
|
||||
were made by Giuliano Pochini <pochini@shiny.it>
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* These functions are common for all "3G" cards */
|
||||
|
||||
|
||||
static int check_asic_status(struct echoaudio *chip)
|
||||
{
|
||||
u32 box_status;
|
||||
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
|
||||
chip->comm_page->ext_box_status =
|
||||
__constant_cpu_to_le32(E3G_ASIC_NOT_LOADED);
|
||||
chip->asic_loaded = FALSE;
|
||||
clear_handshake(chip);
|
||||
send_vector(chip, DSP_VC_TEST_ASIC);
|
||||
|
||||
if (wait_handshake(chip)) {
|
||||
chip->dsp_code = NULL;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
box_status = le32_to_cpu(chip->comm_page->ext_box_status);
|
||||
DE_INIT(("box_status=%x\n", box_status));
|
||||
if (box_status == E3G_ASIC_NOT_LOADED)
|
||||
return -ENODEV;
|
||||
|
||||
chip->asic_loaded = TRUE;
|
||||
return box_status & E3G_BOX_TYPE_MASK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static inline u32 get_frq_reg(struct echoaudio *chip)
|
||||
{
|
||||
return le32_to_cpu(chip->comm_page->e3g_frq_register);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Most configuration of 3G cards is accomplished by writing the control
|
||||
register. write_control_reg sends the new control register value to the DSP. */
|
||||
static int write_control_reg(struct echoaudio *chip, u32 ctl, u32 frq,
|
||||
char force)
|
||||
{
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
|
||||
DE_ACT(("WriteControlReg: Setting 0x%x, 0x%x\n", ctl, frq));
|
||||
|
||||
ctl = cpu_to_le32(ctl);
|
||||
frq = cpu_to_le32(frq);
|
||||
|
||||
if (ctl != chip->comm_page->control_register ||
|
||||
frq != chip->comm_page->e3g_frq_register || force) {
|
||||
chip->comm_page->e3g_frq_register = frq;
|
||||
chip->comm_page->control_register = ctl;
|
||||
clear_handshake(chip);
|
||||
return send_vector(chip, DSP_VC_WRITE_CONTROL_REG);
|
||||
}
|
||||
|
||||
DE_ACT(("WriteControlReg: not written, no change\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Set the digital mode - currently for Gina24, Layla24, Mona, 3G */
|
||||
static int set_digital_mode(struct echoaudio *chip, u8 mode)
|
||||
{
|
||||
u8 previous_mode;
|
||||
int err, i, o;
|
||||
|
||||
/* All audio channels must be closed before changing the digital mode */
|
||||
snd_assert(!chip->pipe_alloc_mask, return -EAGAIN);
|
||||
|
||||
snd_assert(chip->digital_modes & (1 << mode), return -EINVAL);
|
||||
|
||||
previous_mode = chip->digital_mode;
|
||||
err = dsp_set_digital_mode(chip, mode);
|
||||
|
||||
/* If we successfully changed the digital mode from or to ADAT,
|
||||
* then make sure all output, input and monitor levels are
|
||||
* updated by the DSP comm object. */
|
||||
if (err >= 0 && previous_mode != mode &&
|
||||
(previous_mode == DIGITAL_MODE_ADAT || mode == DIGITAL_MODE_ADAT)) {
|
||||
spin_lock_irq(&chip->lock);
|
||||
for (o = 0; o < num_busses_out(chip); o++)
|
||||
for (i = 0; i < num_busses_in(chip); i++)
|
||||
set_monitor_gain(chip, o, i,
|
||||
chip->monitor_gain[o][i]);
|
||||
|
||||
#ifdef ECHOCARD_HAS_INPUT_GAIN
|
||||
for (i = 0; i < num_busses_in(chip); i++)
|
||||
set_input_gain(chip, i, chip->input_gain[i]);
|
||||
update_input_line_level(chip);
|
||||
#endif
|
||||
|
||||
for (o = 0; o < num_busses_out(chip); o++)
|
||||
set_output_gain(chip, o, chip->output_gain[o]);
|
||||
update_output_line_level(chip);
|
||||
spin_unlock_irq(&chip->lock);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static u32 set_spdif_bits(struct echoaudio *chip, u32 control_reg, u32 rate)
|
||||
{
|
||||
control_reg &= E3G_SPDIF_FORMAT_CLEAR_MASK;
|
||||
|
||||
switch (rate) {
|
||||
case 32000 :
|
||||
control_reg |= E3G_SPDIF_SAMPLE_RATE0 | E3G_SPDIF_SAMPLE_RATE1;
|
||||
break;
|
||||
case 44100 :
|
||||
if (chip->professional_spdif)
|
||||
control_reg |= E3G_SPDIF_SAMPLE_RATE0;
|
||||
break;
|
||||
case 48000 :
|
||||
control_reg |= E3G_SPDIF_SAMPLE_RATE1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (chip->professional_spdif)
|
||||
control_reg |= E3G_SPDIF_PRO_MODE;
|
||||
|
||||
if (chip->non_audio_spdif)
|
||||
control_reg |= E3G_SPDIF_NOT_AUDIO;
|
||||
|
||||
control_reg |= E3G_SPDIF_24_BIT | E3G_SPDIF_TWO_CHANNEL |
|
||||
E3G_SPDIF_COPY_PERMIT;
|
||||
|
||||
return control_reg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Set the S/PDIF output format */
|
||||
static int set_professional_spdif(struct echoaudio *chip, char prof)
|
||||
{
|
||||
u32 control_reg;
|
||||
|
||||
control_reg = le32_to_cpu(chip->comm_page->control_register);
|
||||
chip->professional_spdif = prof;
|
||||
control_reg = set_spdif_bits(chip, control_reg, chip->sample_rate);
|
||||
return write_control_reg(chip, control_reg, get_frq_reg(chip), 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* detect_input_clocks() returns a bitmask consisting of all the input clocks
|
||||
currently connected to the hardware; this changes as the user connects and
|
||||
disconnects clock inputs. You should use this information to determine which
|
||||
clocks the user is allowed to select. */
|
||||
static u32 detect_input_clocks(const struct echoaudio *chip)
|
||||
{
|
||||
u32 clocks_from_dsp, clock_bits;
|
||||
|
||||
/* Map the DSP clock detect bits to the generic driver clock
|
||||
* detect bits */
|
||||
clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
|
||||
|
||||
clock_bits = ECHO_CLOCK_BIT_INTERNAL;
|
||||
|
||||
if (clocks_from_dsp & E3G_CLOCK_DETECT_BIT_WORD)
|
||||
clock_bits |= ECHO_CLOCK_BIT_WORD;
|
||||
|
||||
switch(chip->digital_mode) {
|
||||
case DIGITAL_MODE_SPDIF_RCA:
|
||||
case DIGITAL_MODE_SPDIF_OPTICAL:
|
||||
if (clocks_from_dsp & E3G_CLOCK_DETECT_BIT_SPDIF)
|
||||
clock_bits |= ECHO_CLOCK_BIT_SPDIF;
|
||||
break;
|
||||
case DIGITAL_MODE_ADAT:
|
||||
if (clocks_from_dsp & E3G_CLOCK_DETECT_BIT_ADAT)
|
||||
clock_bits |= ECHO_CLOCK_BIT_ADAT;
|
||||
break;
|
||||
}
|
||||
|
||||
return clock_bits;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int load_asic(struct echoaudio *chip)
|
||||
{
|
||||
int box_type, err;
|
||||
|
||||
if (chip->asic_loaded)
|
||||
return 0;
|
||||
|
||||
/* Give the DSP a few milliseconds to settle down */
|
||||
mdelay(2);
|
||||
|
||||
err = load_asic_generic(chip, DSP_FNC_LOAD_3G_ASIC,
|
||||
&card_fw[FW_3G_ASIC]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
chip->asic_code = &card_fw[FW_3G_ASIC];
|
||||
|
||||
/* Now give the new ASIC a little time to set up */
|
||||
mdelay(2);
|
||||
/* See if it worked */
|
||||
box_type = check_asic_status(chip);
|
||||
|
||||
/* Set up the control register if the load succeeded -
|
||||
* 48 kHz, internal clock, S/PDIF RCA mode */
|
||||
if (box_type >= 0) {
|
||||
err = write_control_reg(chip, E3G_48KHZ,
|
||||
E3G_FREQ_REG_DEFAULT, TRUE);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
return box_type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int set_sample_rate(struct echoaudio *chip, u32 rate)
|
||||
{
|
||||
u32 control_reg, clock, base_rate, frq_reg;
|
||||
|
||||
/* Only set the clock for internal mode. */
|
||||
if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
|
||||
DE_ACT(("set_sample_rate: Cannot set sample rate - "
|
||||
"clock not set to CLK_CLOCKININTERNAL\n"));
|
||||
/* Save the rate anyhow */
|
||||
chip->comm_page->sample_rate = cpu_to_le32(rate);
|
||||
chip->sample_rate = rate;
|
||||
set_input_clock(chip, chip->input_clock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
snd_assert(rate < 50000 || chip->digital_mode != DIGITAL_MODE_ADAT,
|
||||
return -EINVAL);
|
||||
|
||||
clock = 0;
|
||||
control_reg = le32_to_cpu(chip->comm_page->control_register);
|
||||
control_reg &= E3G_CLOCK_CLEAR_MASK;
|
||||
|
||||
switch (rate) {
|
||||
case 96000:
|
||||
clock = E3G_96KHZ;
|
||||
break;
|
||||
case 88200:
|
||||
clock = E3G_88KHZ;
|
||||
break;
|
||||
case 48000:
|
||||
clock = E3G_48KHZ;
|
||||
break;
|
||||
case 44100:
|
||||
clock = E3G_44KHZ;
|
||||
break;
|
||||
case 32000:
|
||||
clock = E3G_32KHZ;
|
||||
break;
|
||||
default:
|
||||
clock = E3G_CONTINUOUS_CLOCK;
|
||||
if (rate > 50000)
|
||||
clock |= E3G_DOUBLE_SPEED_MODE;
|
||||
break;
|
||||
}
|
||||
|
||||
control_reg |= clock;
|
||||
control_reg = set_spdif_bits(chip, control_reg, rate);
|
||||
|
||||
base_rate = rate;
|
||||
if (base_rate > 50000)
|
||||
base_rate /= 2;
|
||||
if (base_rate < 32000)
|
||||
base_rate = 32000;
|
||||
|
||||
frq_reg = E3G_MAGIC_NUMBER / base_rate - 2;
|
||||
if (frq_reg > E3G_FREQ_REG_MAX)
|
||||
frq_reg = E3G_FREQ_REG_MAX;
|
||||
|
||||
chip->comm_page->sample_rate = cpu_to_le32(rate); /* ignored by the DSP */
|
||||
chip->sample_rate = rate;
|
||||
DE_ACT(("SetSampleRate: %d clock %x\n", rate, control_reg));
|
||||
|
||||
/* Tell the DSP about it - DSP reads both control reg & freq reg */
|
||||
return write_control_reg(chip, control_reg, frq_reg, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Set the sample clock source to internal, S/PDIF, ADAT */
|
||||
static int set_input_clock(struct echoaudio *chip, u16 clock)
|
||||
{
|
||||
u32 control_reg, clocks_from_dsp;
|
||||
|
||||
DE_ACT(("set_input_clock:\n"));
|
||||
|
||||
/* Mask off the clock select bits */
|
||||
control_reg = le32_to_cpu(chip->comm_page->control_register) &
|
||||
E3G_CLOCK_CLEAR_MASK;
|
||||
clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
|
||||
|
||||
switch (clock) {
|
||||
case ECHO_CLOCK_INTERNAL:
|
||||
DE_ACT(("Set Echo3G clock to INTERNAL\n"));
|
||||
chip->input_clock = ECHO_CLOCK_INTERNAL;
|
||||
return set_sample_rate(chip, chip->sample_rate);
|
||||
case ECHO_CLOCK_SPDIF:
|
||||
if (chip->digital_mode == DIGITAL_MODE_ADAT)
|
||||
return -EAGAIN;
|
||||
DE_ACT(("Set Echo3G clock to SPDIF\n"));
|
||||
control_reg |= E3G_SPDIF_CLOCK;
|
||||
if (clocks_from_dsp & E3G_CLOCK_DETECT_BIT_SPDIF96)
|
||||
control_reg |= E3G_DOUBLE_SPEED_MODE;
|
||||
else
|
||||
control_reg &= ~E3G_DOUBLE_SPEED_MODE;
|
||||
break;
|
||||
case ECHO_CLOCK_ADAT:
|
||||
if (chip->digital_mode != DIGITAL_MODE_ADAT)
|
||||
return -EAGAIN;
|
||||
DE_ACT(("Set Echo3G clock to ADAT\n"));
|
||||
control_reg |= E3G_ADAT_CLOCK;
|
||||
control_reg &= ~E3G_DOUBLE_SPEED_MODE;
|
||||
break;
|
||||
case ECHO_CLOCK_WORD:
|
||||
DE_ACT(("Set Echo3G clock to WORD\n"));
|
||||
control_reg |= E3G_WORD_CLOCK;
|
||||
if (clocks_from_dsp & E3G_CLOCK_DETECT_BIT_WORD96)
|
||||
control_reg |= E3G_DOUBLE_SPEED_MODE;
|
||||
else
|
||||
control_reg &= ~E3G_DOUBLE_SPEED_MODE;
|
||||
break;
|
||||
default:
|
||||
DE_ACT(("Input clock 0x%x not supported for Echo3G\n", clock));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chip->input_clock = clock;
|
||||
return write_control_reg(chip, control_reg, get_frq_reg(chip), 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
|
||||
{
|
||||
u32 control_reg;
|
||||
int err, incompatible_clock;
|
||||
|
||||
/* Set clock to "internal" if it's not compatible with the new mode */
|
||||
incompatible_clock = FALSE;
|
||||
switch (mode) {
|
||||
case DIGITAL_MODE_SPDIF_OPTICAL:
|
||||
case DIGITAL_MODE_SPDIF_RCA:
|
||||
if (chip->input_clock == ECHO_CLOCK_ADAT)
|
||||
incompatible_clock = TRUE;
|
||||
break;
|
||||
case DIGITAL_MODE_ADAT:
|
||||
if (chip->input_clock == ECHO_CLOCK_SPDIF)
|
||||
incompatible_clock = TRUE;
|
||||
break;
|
||||
default:
|
||||
DE_ACT(("Digital mode not supported: %d\n", mode));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irq(&chip->lock);
|
||||
|
||||
if (incompatible_clock) {
|
||||
chip->sample_rate = 48000;
|
||||
set_input_clock(chip, ECHO_CLOCK_INTERNAL);
|
||||
}
|
||||
|
||||
/* Clear the current digital mode */
|
||||
control_reg = le32_to_cpu(chip->comm_page->control_register);
|
||||
control_reg &= E3G_DIGITAL_MODE_CLEAR_MASK;
|
||||
|
||||
/* Tweak the control reg */
|
||||
switch (mode) {
|
||||
case DIGITAL_MODE_SPDIF_OPTICAL:
|
||||
control_reg |= E3G_SPDIF_OPTICAL_MODE;
|
||||
break;
|
||||
case DIGITAL_MODE_SPDIF_RCA:
|
||||
/* E3G_SPDIF_OPTICAL_MODE bit cleared */
|
||||
break;
|
||||
case DIGITAL_MODE_ADAT:
|
||||
control_reg |= E3G_ADAT_MODE;
|
||||
control_reg &= ~E3G_DOUBLE_SPEED_MODE; /* @@ useless */
|
||||
break;
|
||||
}
|
||||
|
||||
err = write_control_reg(chip, control_reg, get_frq_reg(chip), 1);
|
||||
spin_unlock_irq(&chip->lock);
|
||||
if (err < 0)
|
||||
return err;
|
||||
chip->digital_mode = mode;
|
||||
|
||||
DE_ACT(("set_digital_mode(%d)\n", chip->digital_mode));
|
||||
return incompatible_clock;
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,694 @@
|
|||
/****************************************************************************
|
||||
|
||||
Copyright Echo Digital Audio Corporation (c) 1998 - 2004
|
||||
All rights reserved
|
||||
www.echoaudio.com
|
||||
|
||||
This file is part of Echo Digital Audio's generic driver library.
|
||||
|
||||
Echo Digital Audio's generic driver library 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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA.
|
||||
|
||||
*************************************************************************
|
||||
|
||||
Translation from C++ and adaptation for use in ALSA-Driver
|
||||
were made by Giuliano Pochini <pochini@shiny.it>
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _ECHO_DSP_
|
||||
#define _ECHO_DSP_
|
||||
|
||||
|
||||
/**** Echogals: Darla20, Gina20, Layla20, and Darla24 ****/
|
||||
#if defined(ECHOGALS_FAMILY)
|
||||
|
||||
#define NUM_ASIC_TESTS 5
|
||||
#define READ_DSP_TIMEOUT 1000000L /* one second */
|
||||
|
||||
/**** Echo24: Gina24, Layla24, Mona, Mia, Mia-midi ****/
|
||||
#elif defined(ECHO24_FAMILY)
|
||||
|
||||
#define DSP_56361 /* Some Echo24 cards use the 56361 DSP */
|
||||
#define READ_DSP_TIMEOUT 100000L /* .1 second */
|
||||
|
||||
/**** 3G: Gina3G, Layla3G ****/
|
||||
#elif defined(ECHO3G_FAMILY)
|
||||
|
||||
#define DSP_56361
|
||||
#define READ_DSP_TIMEOUT 100000L /* .1 second */
|
||||
#define MIN_MTC_1X_RATE 32000
|
||||
|
||||
/**** Indigo: Indigo, Indigo IO, Indigo DJ ****/
|
||||
#elif defined(INDIGO_FAMILY)
|
||||
|
||||
#define DSP_56361
|
||||
#define READ_DSP_TIMEOUT 100000L /* .1 second */
|
||||
|
||||
#else
|
||||
|
||||
#error No family is defined
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Max inputs and outputs
|
||||
*
|
||||
*/
|
||||
|
||||
#define DSP_MAXAUDIOINPUTS 16 /* Max audio input channels */
|
||||
#define DSP_MAXAUDIOOUTPUTS 16 /* Max audio output channels */
|
||||
#define DSP_MAXPIPES 32 /* Max total pipes (input + output) */
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* These are the offsets for the memory-mapped DSP registers; the DSP base
|
||||
* address is treated as the start of a u32 array.
|
||||
*/
|
||||
|
||||
#define CHI32_CONTROL_REG 4
|
||||
#define CHI32_STATUS_REG 5
|
||||
#define CHI32_VECTOR_REG 6
|
||||
#define CHI32_DATA_REG 7
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Interesting bits within the DSP registers
|
||||
*
|
||||
*/
|
||||
|
||||
#define CHI32_VECTOR_BUSY 0x00000001
|
||||
#define CHI32_STATUS_REG_HF3 0x00000008
|
||||
#define CHI32_STATUS_REG_HF4 0x00000010
|
||||
#define CHI32_STATUS_REG_HF5 0x00000020
|
||||
#define CHI32_STATUS_HOST_READ_FULL 0x00000004
|
||||
#define CHI32_STATUS_HOST_WRITE_EMPTY 0x00000002
|
||||
#define CHI32_STATUS_IRQ 0x00000040
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* DSP commands sent via slave mode; these are sent to the DSP by write_dsp()
|
||||
*
|
||||
*/
|
||||
|
||||
#define DSP_FNC_SET_COMMPAGE_ADDR 0x02
|
||||
#define DSP_FNC_LOAD_LAYLA_ASIC 0xa0
|
||||
#define DSP_FNC_LOAD_GINA24_ASIC 0xa0
|
||||
#define DSP_FNC_LOAD_MONA_PCI_CARD_ASIC 0xa0
|
||||
#define DSP_FNC_LOAD_LAYLA24_PCI_CARD_ASIC 0xa0
|
||||
#define DSP_FNC_LOAD_MONA_EXTERNAL_ASIC 0xa1
|
||||
#define DSP_FNC_LOAD_LAYLA24_EXTERNAL_ASIC 0xa1
|
||||
#define DSP_FNC_LOAD_3G_ASIC 0xa0
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Defines to handle the MIDI input state engine; these are used to properly
|
||||
* extract MIDI time code bytes and their timestamps from the MIDI input stream.
|
||||
*
|
||||
*/
|
||||
|
||||
#define MIDI_IN_STATE_NORMAL 0
|
||||
#define MIDI_IN_STATE_TS_HIGH 1
|
||||
#define MIDI_IN_STATE_TS_LOW 2
|
||||
#define MIDI_IN_STATE_F1_DATA 3
|
||||
#define MIDI_IN_SKIP_DATA (-1)
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
|
||||
Setting the sample rates on Layla24 is somewhat schizophrenic.
|
||||
|
||||
For standard rates, it works exactly like Mona and Gina24. That is, for
|
||||
8, 11.025, 16, 22.05, 32, 44.1, 48, 88.2, and 96 kHz, you just set the
|
||||
appropriate bits in the control register and write the control register.
|
||||
|
||||
In order to support MIDI time code sync (and possibly SMPTE LTC sync in
|
||||
the future), Layla24 also has "continuous sample rate mode". In this mode,
|
||||
Layla24 can generate any sample rate between 25 and 50 kHz inclusive, or
|
||||
50 to 100 kHz inclusive for double speed mode.
|
||||
|
||||
To use continuous mode:
|
||||
|
||||
-Set the clock select bits in the control register to 0xe (see the #define
|
||||
below)
|
||||
|
||||
-Set double-speed mode if you want to use sample rates above 50 kHz
|
||||
|
||||
-Write the control register as you would normally
|
||||
|
||||
-Now, you need to set the frequency register. First, you need to determine the
|
||||
value for the frequency register. This is given by the following formula:
|
||||
|
||||
frequency_reg = (LAYLA24_MAGIC_NUMBER / sample_rate) - 2
|
||||
|
||||
Note the #define below for the magic number
|
||||
|
||||
-Wait for the DSP handshake
|
||||
-Write the frequency_reg value to the .SampleRate field of the comm page
|
||||
-Send the vector command SET_LAYLA24_FREQUENCY_REG (see vmonkey.h)
|
||||
|
||||
Once you have set the control register up for continuous mode, you can just
|
||||
write the frequency register to change the sample rate. This could be
|
||||
used for MIDI time code sync. For MTC sync, the control register is set for
|
||||
continuous mode. The driver then just keeps writing the
|
||||
SET_LAYLA24_FREQUENCY_REG command.
|
||||
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
#define LAYLA24_MAGIC_NUMBER 677376000
|
||||
#define LAYLA24_CONTINUOUS_CLOCK 0x000e
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* DSP vector commands
|
||||
*
|
||||
*/
|
||||
|
||||
#define DSP_VC_RESET 0x80ff
|
||||
|
||||
#ifndef DSP_56361
|
||||
|
||||
#define DSP_VC_ACK_INT 0x8073
|
||||
#define DSP_VC_SET_VMIXER_GAIN 0x0000 /* Not used, only for compile */
|
||||
#define DSP_VC_START_TRANSFER 0x0075 /* Handshke rqd. */
|
||||
#define DSP_VC_METERS_ON 0x0079
|
||||
#define DSP_VC_METERS_OFF 0x007b
|
||||
#define DSP_VC_UPDATE_OUTVOL 0x007d /* Handshke rqd. */
|
||||
#define DSP_VC_UPDATE_INGAIN 0x007f /* Handshke rqd. */
|
||||
#define DSP_VC_ADD_AUDIO_BUFFER 0x0081 /* Handshke rqd. */
|
||||
#define DSP_VC_TEST_ASIC 0x00eb
|
||||
#define DSP_VC_UPDATE_CLOCKS 0x00ef /* Handshke rqd. */
|
||||
#define DSP_VC_SET_LAYLA_SAMPLE_RATE 0x00f1 /* Handshke rqd. */
|
||||
#define DSP_VC_SET_GD_AUDIO_STATE 0x00f1 /* Handshke rqd. */
|
||||
#define DSP_VC_WRITE_CONTROL_REG 0x00f1 /* Handshke rqd. */
|
||||
#define DSP_VC_MIDI_WRITE 0x00f5 /* Handshke rqd. */
|
||||
#define DSP_VC_STOP_TRANSFER 0x00f7 /* Handshke rqd. */
|
||||
#define DSP_VC_UPDATE_FLAGS 0x00fd /* Handshke rqd. */
|
||||
#define DSP_VC_GO_COMATOSE 0x00f9
|
||||
|
||||
#else /* !DSP_56361 */
|
||||
|
||||
/* Vector commands for families that use either the 56301 or 56361 */
|
||||
#define DSP_VC_ACK_INT 0x80F5
|
||||
#define DSP_VC_SET_VMIXER_GAIN 0x00DB /* Handshke rqd. */
|
||||
#define DSP_VC_START_TRANSFER 0x00DD /* Handshke rqd. */
|
||||
#define DSP_VC_METERS_ON 0x00EF
|
||||
#define DSP_VC_METERS_OFF 0x00F1
|
||||
#define DSP_VC_UPDATE_OUTVOL 0x00E3 /* Handshke rqd. */
|
||||
#define DSP_VC_UPDATE_INGAIN 0x00E5 /* Handshke rqd. */
|
||||
#define DSP_VC_ADD_AUDIO_BUFFER 0x00E1 /* Handshke rqd. */
|
||||
#define DSP_VC_TEST_ASIC 0x00ED
|
||||
#define DSP_VC_UPDATE_CLOCKS 0x00E9 /* Handshke rqd. */
|
||||
#define DSP_VC_SET_LAYLA24_FREQUENCY_REG 0x00E9 /* Handshke rqd. */
|
||||
#define DSP_VC_SET_LAYLA_SAMPLE_RATE 0x00EB /* Handshke rqd. */
|
||||
#define DSP_VC_SET_GD_AUDIO_STATE 0x00EB /* Handshke rqd. */
|
||||
#define DSP_VC_WRITE_CONTROL_REG 0x00EB /* Handshke rqd. */
|
||||
#define DSP_VC_MIDI_WRITE 0x00E7 /* Handshke rqd. */
|
||||
#define DSP_VC_STOP_TRANSFER 0x00DF /* Handshke rqd. */
|
||||
#define DSP_VC_UPDATE_FLAGS 0x00FB /* Handshke rqd. */
|
||||
#define DSP_VC_GO_COMATOSE 0x00d9
|
||||
|
||||
#endif /* !DSP_56361 */
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Timeouts
|
||||
*
|
||||
*/
|
||||
|
||||
#define HANDSHAKE_TIMEOUT 20000 /* send_vector command timeout (20ms) */
|
||||
#define VECTOR_BUSY_TIMEOUT 100000 /* 100ms */
|
||||
#define MIDI_OUT_DELAY_USEC 2000 /* How long to wait after MIDI fills up */
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Flags for .Flags field in the comm page
|
||||
*
|
||||
*/
|
||||
|
||||
#define DSP_FLAG_MIDI_INPUT 0x0001 /* Enable MIDI input */
|
||||
#define DSP_FLAG_SPDIF_NONAUDIO 0x0002 /* Sets the "non-audio" bit
|
||||
* in the S/PDIF out status
|
||||
* bits. Clear this flag for
|
||||
* audio data;
|
||||
* set it for AC3 or WMA or
|
||||
* some such */
|
||||
#define DSP_FLAG_PROFESSIONAL_SPDIF 0x0008 /* 1 Professional, 0 Consumer */
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Clock detect bits reported by the DSP for Gina20, Layla20, Darla24, and Mia
|
||||
*
|
||||
*/
|
||||
|
||||
#define GLDM_CLOCK_DETECT_BIT_WORD 0x0002
|
||||
#define GLDM_CLOCK_DETECT_BIT_SUPER 0x0004
|
||||
#define GLDM_CLOCK_DETECT_BIT_SPDIF 0x0008
|
||||
#define GLDM_CLOCK_DETECT_BIT_ESYNC 0x0010
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Clock detect bits reported by the DSP for Gina24, Mona, and Layla24
|
||||
*
|
||||
*/
|
||||
|
||||
#define GML_CLOCK_DETECT_BIT_WORD96 0x0002
|
||||
#define GML_CLOCK_DETECT_BIT_WORD48 0x0004
|
||||
#define GML_CLOCK_DETECT_BIT_SPDIF48 0x0008
|
||||
#define GML_CLOCK_DETECT_BIT_SPDIF96 0x0010
|
||||
#define GML_CLOCK_DETECT_BIT_WORD (GML_CLOCK_DETECT_BIT_WORD96 | GML_CLOCK_DETECT_BIT_WORD48)
|
||||
#define GML_CLOCK_DETECT_BIT_SPDIF (GML_CLOCK_DETECT_BIT_SPDIF48 | GML_CLOCK_DETECT_BIT_SPDIF96)
|
||||
#define GML_CLOCK_DETECT_BIT_ESYNC 0x0020
|
||||
#define GML_CLOCK_DETECT_BIT_ADAT 0x0040
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Layla clock numbers to send to DSP
|
||||
*
|
||||
*/
|
||||
|
||||
#define LAYLA20_CLOCK_INTERNAL 0
|
||||
#define LAYLA20_CLOCK_SPDIF 1
|
||||
#define LAYLA20_CLOCK_WORD 2
|
||||
#define LAYLA20_CLOCK_SUPER 3
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Gina/Darla clock states
|
||||
*
|
||||
*/
|
||||
|
||||
#define GD_CLOCK_NOCHANGE 0
|
||||
#define GD_CLOCK_44 1
|
||||
#define GD_CLOCK_48 2
|
||||
#define GD_CLOCK_SPDIFIN 3
|
||||
#define GD_CLOCK_UNDEF 0xff
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Gina/Darla S/PDIF status bits
|
||||
*
|
||||
*/
|
||||
|
||||
#define GD_SPDIF_STATUS_NOCHANGE 0
|
||||
#define GD_SPDIF_STATUS_44 1
|
||||
#define GD_SPDIF_STATUS_48 2
|
||||
#define GD_SPDIF_STATUS_UNDEF 0xff
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Layla20 output clocks
|
||||
*
|
||||
*/
|
||||
|
||||
#define LAYLA20_OUTPUT_CLOCK_SUPER 0
|
||||
#define LAYLA20_OUTPUT_CLOCK_WORD 1
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
|
||||
Magic constants for the Darla24 hardware
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
#define GD24_96000 0x0
|
||||
#define GD24_48000 0x1
|
||||
#define GD24_44100 0x2
|
||||
#define GD24_32000 0x3
|
||||
#define GD24_22050 0x4
|
||||
#define GD24_16000 0x5
|
||||
#define GD24_11025 0x6
|
||||
#define GD24_8000 0x7
|
||||
#define GD24_88200 0x8
|
||||
#define GD24_EXT_SYNC 0x9
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Return values from the DSP when ASIC is loaded
|
||||
*
|
||||
*/
|
||||
|
||||
#define ASIC_ALREADY_LOADED 0x1
|
||||
#define ASIC_NOT_LOADED 0x0
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* DSP Audio formats
|
||||
*
|
||||
* These are the audio formats that the DSP can transfer
|
||||
* via input and output pipes. LE means little-endian,
|
||||
* BE means big-endian.
|
||||
*
|
||||
* DSP_AUDIOFORM_MS_8
|
||||
*
|
||||
* 8-bit mono unsigned samples. For playback,
|
||||
* mono data is duplicated out the left and right channels
|
||||
* of the output bus. The "MS" part of the name
|
||||
* means mono->stereo.
|
||||
*
|
||||
* DSP_AUDIOFORM_MS_16LE
|
||||
*
|
||||
* 16-bit signed little-endian mono samples. Playback works
|
||||
* like the previous code.
|
||||
*
|
||||
* DSP_AUDIOFORM_MS_24LE
|
||||
*
|
||||
* 24-bit signed little-endian mono samples. Data is packed
|
||||
* three bytes per sample; if you had two samples 0x112233 and 0x445566
|
||||
* they would be stored in memory like this: 33 22 11 66 55 44.
|
||||
*
|
||||
* DSP_AUDIOFORM_MS_32LE
|
||||
*
|
||||
* 24-bit signed little-endian mono samples in a 32-bit
|
||||
* container. In other words, each sample is a 32-bit signed
|
||||
* integer, where the actual audio data is left-justified
|
||||
* in the 32 bits and only the 24 most significant bits are valid.
|
||||
*
|
||||
* DSP_AUDIOFORM_SS_8
|
||||
* DSP_AUDIOFORM_SS_16LE
|
||||
* DSP_AUDIOFORM_SS_24LE
|
||||
* DSP_AUDIOFORM_SS_32LE
|
||||
*
|
||||
* Like the previous ones, except now with stereo interleaved
|
||||
* data. "SS" means stereo->stereo.
|
||||
*
|
||||
* DSP_AUDIOFORM_MM_32LE
|
||||
*
|
||||
* Similar to DSP_AUDIOFORM_MS_32LE, except that the mono
|
||||
* data is not duplicated out both the left and right outputs.
|
||||
* This mode is used by the ASIO driver. Here, "MM" means
|
||||
* mono->mono.
|
||||
*
|
||||
* DSP_AUDIOFORM_MM_32BE
|
||||
*
|
||||
* Just like DSP_AUDIOFORM_MM_32LE, but now the data is
|
||||
* in big-endian format.
|
||||
*
|
||||
*/
|
||||
|
||||
#define DSP_AUDIOFORM_MS_8 0 /* 8 bit mono */
|
||||
#define DSP_AUDIOFORM_MS_16LE 1 /* 16 bit mono */
|
||||
#define DSP_AUDIOFORM_MS_24LE 2 /* 24 bit mono */
|
||||
#define DSP_AUDIOFORM_MS_32LE 3 /* 32 bit mono */
|
||||
#define DSP_AUDIOFORM_SS_8 4 /* 8 bit stereo */
|
||||
#define DSP_AUDIOFORM_SS_16LE 5 /* 16 bit stereo */
|
||||
#define DSP_AUDIOFORM_SS_24LE 6 /* 24 bit stereo */
|
||||
#define DSP_AUDIOFORM_SS_32LE 7 /* 32 bit stereo */
|
||||
#define DSP_AUDIOFORM_MM_32LE 8 /* 32 bit mono->mono little-endian */
|
||||
#define DSP_AUDIOFORM_MM_32BE 9 /* 32 bit mono->mono big-endian */
|
||||
#define DSP_AUDIOFORM_SS_32BE 10 /* 32 bit stereo big endian */
|
||||
#define DSP_AUDIOFORM_INVALID 0xFF /* Invalid audio format */
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Super-interleave is defined as interleaving by 4 or more. Darla20 and Gina20
|
||||
* do not support super interleave.
|
||||
*
|
||||
* 16 bit, 24 bit, and 32 bit little endian samples are supported for super
|
||||
* interleave. The interleave factor must be even. 16 - way interleave is the
|
||||
* current maximum, so you can interleave by 4, 6, 8, 10, 12, 14, and 16.
|
||||
*
|
||||
* The actual format code is derived by taking the define below and or-ing with
|
||||
* the interleave factor. So, 32 bit interleave by 6 is 0x86 and
|
||||
* 16 bit interleave by 16 is (0x40 | 0x10) = 0x50.
|
||||
*
|
||||
*/
|
||||
|
||||
#define DSP_AUDIOFORM_SUPER_INTERLEAVE_16LE 0x40
|
||||
#define DSP_AUDIOFORM_SUPER_INTERLEAVE_24LE 0xc0
|
||||
#define DSP_AUDIOFORM_SUPER_INTERLEAVE_32LE 0x80
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Gina24, Mona, and Layla24 control register defines
|
||||
*
|
||||
*/
|
||||
|
||||
#define GML_CONVERTER_ENABLE 0x0010
|
||||
#define GML_SPDIF_PRO_MODE 0x0020 /* Professional S/PDIF == 1,
|
||||
consumer == 0 */
|
||||
#define GML_SPDIF_SAMPLE_RATE0 0x0040
|
||||
#define GML_SPDIF_SAMPLE_RATE1 0x0080
|
||||
#define GML_SPDIF_TWO_CHANNEL 0x0100 /* 1 == two channels,
|
||||
0 == one channel */
|
||||
#define GML_SPDIF_NOT_AUDIO 0x0200
|
||||
#define GML_SPDIF_COPY_PERMIT 0x0400
|
||||
#define GML_SPDIF_24_BIT 0x0800 /* 1 == 24 bit, 0 == 20 bit */
|
||||
#define GML_ADAT_MODE 0x1000 /* 1 == ADAT mode, 0 == S/PDIF mode */
|
||||
#define GML_SPDIF_OPTICAL_MODE 0x2000 /* 1 == optical mode, 0 == RCA mode */
|
||||
#define GML_SPDIF_CDROM_MODE 0x3000 /* 1 == CDROM mode,
|
||||
* 0 == RCA or optical mode */
|
||||
#define GML_DOUBLE_SPEED_MODE 0x4000 /* 1 == double speed,
|
||||
0 == single speed */
|
||||
|
||||
#define GML_DIGITAL_IN_AUTO_MUTE 0x800000
|
||||
|
||||
#define GML_96KHZ (0x0 | GML_DOUBLE_SPEED_MODE)
|
||||
#define GML_88KHZ (0x1 | GML_DOUBLE_SPEED_MODE)
|
||||
#define GML_48KHZ 0x2
|
||||
#define GML_44KHZ 0x3
|
||||
#define GML_32KHZ 0x4
|
||||
#define GML_22KHZ 0x5
|
||||
#define GML_16KHZ 0x6
|
||||
#define GML_11KHZ 0x7
|
||||
#define GML_8KHZ 0x8
|
||||
#define GML_SPDIF_CLOCK 0x9
|
||||
#define GML_ADAT_CLOCK 0xA
|
||||
#define GML_WORD_CLOCK 0xB
|
||||
#define GML_ESYNC_CLOCK 0xC
|
||||
#define GML_ESYNCx2_CLOCK 0xD
|
||||
|
||||
#define GML_CLOCK_CLEAR_MASK 0xffffbff0
|
||||
#define GML_SPDIF_RATE_CLEAR_MASK (~(GML_SPDIF_SAMPLE_RATE0|GML_SPDIF_SAMPLE_RATE1))
|
||||
#define GML_DIGITAL_MODE_CLEAR_MASK 0xffffcfff
|
||||
#define GML_SPDIF_FORMAT_CLEAR_MASK 0xfffff01f
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Mia sample rate and clock setting constants
|
||||
*
|
||||
*/
|
||||
|
||||
#define MIA_32000 0x0040
|
||||
#define MIA_44100 0x0042
|
||||
#define MIA_48000 0x0041
|
||||
#define MIA_88200 0x0142
|
||||
#define MIA_96000 0x0141
|
||||
|
||||
#define MIA_SPDIF 0x00000044
|
||||
#define MIA_SPDIF96 0x00000144
|
||||
|
||||
#define MIA_MIDI_REV 1 /* Must be Mia rev 1 for MIDI support */
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* 3G register bits
|
||||
*
|
||||
*/
|
||||
|
||||
#define E3G_CONVERTER_ENABLE 0x0010
|
||||
#define E3G_SPDIF_PRO_MODE 0x0020 /* Professional S/PDIF == 1,
|
||||
consumer == 0 */
|
||||
#define E3G_SPDIF_SAMPLE_RATE0 0x0040
|
||||
#define E3G_SPDIF_SAMPLE_RATE1 0x0080
|
||||
#define E3G_SPDIF_TWO_CHANNEL 0x0100 /* 1 == two channels,
|
||||
0 == one channel */
|
||||
#define E3G_SPDIF_NOT_AUDIO 0x0200
|
||||
#define E3G_SPDIF_COPY_PERMIT 0x0400
|
||||
#define E3G_SPDIF_24_BIT 0x0800 /* 1 == 24 bit, 0 == 20 bit */
|
||||
#define E3G_DOUBLE_SPEED_MODE 0x4000 /* 1 == double speed,
|
||||
0 == single speed */
|
||||
#define E3G_PHANTOM_POWER 0x8000 /* 1 == phantom power on,
|
||||
0 == phantom power off */
|
||||
|
||||
#define E3G_96KHZ (0x0 | E3G_DOUBLE_SPEED_MODE)
|
||||
#define E3G_88KHZ (0x1 | E3G_DOUBLE_SPEED_MODE)
|
||||
#define E3G_48KHZ 0x2
|
||||
#define E3G_44KHZ 0x3
|
||||
#define E3G_32KHZ 0x4
|
||||
#define E3G_22KHZ 0x5
|
||||
#define E3G_16KHZ 0x6
|
||||
#define E3G_11KHZ 0x7
|
||||
#define E3G_8KHZ 0x8
|
||||
#define E3G_SPDIF_CLOCK 0x9
|
||||
#define E3G_ADAT_CLOCK 0xA
|
||||
#define E3G_WORD_CLOCK 0xB
|
||||
#define E3G_CONTINUOUS_CLOCK 0xE
|
||||
|
||||
#define E3G_ADAT_MODE 0x1000
|
||||
#define E3G_SPDIF_OPTICAL_MODE 0x2000
|
||||
|
||||
#define E3G_CLOCK_CLEAR_MASK 0xbfffbff0
|
||||
#define E3G_DIGITAL_MODE_CLEAR_MASK 0xffffcfff
|
||||
#define E3G_SPDIF_FORMAT_CLEAR_MASK 0xfffff01f
|
||||
|
||||
/* Clock detect bits reported by the DSP */
|
||||
#define E3G_CLOCK_DETECT_BIT_WORD96 0x0001
|
||||
#define E3G_CLOCK_DETECT_BIT_WORD48 0x0002
|
||||
#define E3G_CLOCK_DETECT_BIT_SPDIF48 0x0004
|
||||
#define E3G_CLOCK_DETECT_BIT_ADAT 0x0004
|
||||
#define E3G_CLOCK_DETECT_BIT_SPDIF96 0x0008
|
||||
#define E3G_CLOCK_DETECT_BIT_WORD (E3G_CLOCK_DETECT_BIT_WORD96|E3G_CLOCK_DETECT_BIT_WORD48)
|
||||
#define E3G_CLOCK_DETECT_BIT_SPDIF (E3G_CLOCK_DETECT_BIT_SPDIF48|E3G_CLOCK_DETECT_BIT_SPDIF96)
|
||||
|
||||
/* Frequency control register */
|
||||
#define E3G_MAGIC_NUMBER 677376000
|
||||
#define E3G_FREQ_REG_DEFAULT (E3G_MAGIC_NUMBER / 48000 - 2)
|
||||
#define E3G_FREQ_REG_MAX 0xffff
|
||||
|
||||
/* 3G external box types */
|
||||
#define E3G_GINA3G_BOX_TYPE 0x00
|
||||
#define E3G_LAYLA3G_BOX_TYPE 0x10
|
||||
#define E3G_ASIC_NOT_LOADED 0xffff
|
||||
#define E3G_BOX_TYPE_MASK 0xf0
|
||||
|
||||
#define EXT_3GBOX_NC 0x01
|
||||
#define EXT_3GBOX_NOT_SET 0x02
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Gina20 & Layla20 have input gain controls for the analog inputs;
|
||||
* this is the magic number for the hardware that gives you 0 dB at -10.
|
||||
*
|
||||
*/
|
||||
|
||||
#define GL20_INPUT_GAIN_MAGIC_NUMBER 0xC8
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Defines how much time must pass between DSP load attempts
|
||||
*
|
||||
*/
|
||||
|
||||
#define DSP_LOAD_ATTEMPT_PERIOD 1000000L /* One second */
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Size of arrays for the comm page. MAX_PLAY_TAPS and MAX_REC_TAPS are
|
||||
* no longer used, but the sizes must still be right for the DSP to see
|
||||
* the comm page correctly.
|
||||
*
|
||||
*/
|
||||
|
||||
#define MONITOR_ARRAY_SIZE 0x180
|
||||
#define VMIXER_ARRAY_SIZE 0x40
|
||||
#define MIDI_OUT_BUFFER_SIZE 32
|
||||
#define MIDI_IN_BUFFER_SIZE 256
|
||||
#define MAX_PLAY_TAPS 168
|
||||
#define MAX_REC_TAPS 192
|
||||
#define DSP_MIDI_OUT_FIFO_SIZE 64
|
||||
|
||||
|
||||
/* sg_entry is a single entry for the scatter-gather list. The array of struct
|
||||
sg_entry struct is read by the DSP, so all values must be little-endian. */
|
||||
|
||||
#define MAX_SGLIST_ENTRIES 512
|
||||
|
||||
struct sg_entry {
|
||||
u32 addr;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
|
||||
The comm page. This structure is read and written by the DSP; the
|
||||
DSP code is a firm believer in the byte offsets written in the comments
|
||||
at the end of each line. This structure should not be changed.
|
||||
|
||||
Any reads from or writes to this structure should be in little-endian format.
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
struct comm_page { /* Base Length*/
|
||||
u32 comm_size; /* size of this object 0x000 4 */
|
||||
u32 flags; /* See Appendix A below 0x004 4 */
|
||||
u32 unused; /* Unused entry 0x008 4 */
|
||||
u32 sample_rate; /* Card sample rate in Hz 0x00c 4 */
|
||||
volatile u32 handshake; /* DSP command handshake 0x010 4 */
|
||||
u32 cmd_start; /* Chs. to start mask 0x014 4 */
|
||||
u32 cmd_stop; /* Chs. to stop mask 0x018 4 */
|
||||
u32 cmd_reset; /* Chs. to reset mask 0x01c 4 */
|
||||
u16 audio_format[DSP_MAXPIPES]; /* Chs. audio format 0x020 32*2 */
|
||||
struct sg_entry sglist_addr[DSP_MAXPIPES];
|
||||
/* Chs. Physical sglist addrs 0x060 32*8 */
|
||||
volatile u32 position[DSP_MAXPIPES];
|
||||
/* Positions for ea. ch. 0x160 32*4 */
|
||||
volatile s8 vu_meter[DSP_MAXPIPES];
|
||||
/* VU meters 0x1e0 32*1 */
|
||||
volatile s8 peak_meter[DSP_MAXPIPES];
|
||||
/* Peak meters 0x200 32*1 */
|
||||
s8 line_out_level[DSP_MAXAUDIOOUTPUTS];
|
||||
/* Output gain 0x220 16*1 */
|
||||
s8 line_in_level[DSP_MAXAUDIOINPUTS];
|
||||
/* Input gain 0x230 16*1 */
|
||||
s8 monitors[MONITOR_ARRAY_SIZE];
|
||||
/* Monitor map 0x240 0x180 */
|
||||
u32 play_coeff[MAX_PLAY_TAPS];
|
||||
/* Gina/Darla play filters - obsolete 0x3c0 168*4 */
|
||||
u32 rec_coeff[MAX_REC_TAPS];
|
||||
/* Gina/Darla record filters - obsolete 0x660 192*4 */
|
||||
volatile u16 midi_input[MIDI_IN_BUFFER_SIZE];
|
||||
/* MIDI input data transfer buffer 0x960 256*2 */
|
||||
u8 gd_clock_state; /* Chg Gina/Darla clock state 0xb60 1 */
|
||||
u8 gd_spdif_status; /* Chg. Gina/Darla S/PDIF state 0xb61 1 */
|
||||
u8 gd_resampler_state; /* Should always be 3 0xb62 1 */
|
||||
u8 filler2; /* 0xb63 1 */
|
||||
u32 nominal_level_mask; /* -10 level enable mask 0xb64 4 */
|
||||
u16 input_clock; /* Chg. Input clock state 0xb68 2 */
|
||||
u16 output_clock; /* Chg. Output clock state 0xb6a 2 */
|
||||
volatile u32 status_clocks;
|
||||
/* Current Input clock state 0xb6c 4 */
|
||||
u32 ext_box_status; /* External box status 0xb70 4 */
|
||||
u32 cmd_add_buffer; /* Pipes to add (obsolete) 0xb74 4 */
|
||||
volatile u32 midi_out_free_count;
|
||||
/* # of bytes free in MIDI output FIFO 0xb78 4 */
|
||||
u32 unused2; /* Cyclic pipes 0xb7c 4 */
|
||||
u32 control_register;
|
||||
/* Mona, Gina24, Layla24, 3G ctrl reg 0xb80 4 */
|
||||
u32 e3g_frq_register; /* 3G frequency register 0xb84 4 */
|
||||
u8 filler[24]; /* filler 0xb88 24*1 */
|
||||
s8 vmixer[VMIXER_ARRAY_SIZE];
|
||||
/* Vmixer levels 0xba0 64*1 */
|
||||
u8 midi_output[MIDI_OUT_BUFFER_SIZE];
|
||||
/* MIDI output data 0xbe0 32*1 */
|
||||
};
|
||||
|
||||
#endif /* _ECHO_DSP_ */
|
|
@ -0,0 +1,198 @@
|
|||
/****************************************************************************
|
||||
|
||||
Copyright Echo Digital Audio Corporation (c) 1998 - 2004
|
||||
All rights reserved
|
||||
www.echoaudio.com
|
||||
|
||||
This file is part of Echo Digital Audio's generic driver library.
|
||||
|
||||
Echo Digital Audio's generic driver library 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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA.
|
||||
|
||||
*************************************************************************
|
||||
|
||||
Translation from C++ and adaptation for use in ALSA-Driver
|
||||
were made by Giuliano Pochini <pochini@shiny.it>
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
/* These functions are common for Gina24, Layla24 and Mona cards */
|
||||
|
||||
|
||||
/* ASIC status check - some cards have one or two ASICs that need to be
|
||||
loaded. Once that load is complete, this function is called to see if
|
||||
the load was successful.
|
||||
If this load fails, it does not necessarily mean that the hardware is
|
||||
defective - the external box may be disconnected or turned off. */
|
||||
static int check_asic_status(struct echoaudio *chip)
|
||||
{
|
||||
u32 asic_status;
|
||||
|
||||
send_vector(chip, DSP_VC_TEST_ASIC);
|
||||
|
||||
/* The DSP will return a value to indicate whether or not the
|
||||
ASIC is currently loaded */
|
||||
if (read_dsp(chip, &asic_status) < 0) {
|
||||
DE_INIT(("check_asic_status: failed on read_dsp\n"));
|
||||
chip->asic_loaded = FALSE;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
chip->asic_loaded = (asic_status == ASIC_ALREADY_LOADED);
|
||||
return chip->asic_loaded ? 0 : -EIO;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Most configuration of Gina24, Layla24, or Mona is accomplished by writing
|
||||
the control register. write_control_reg sends the new control register
|
||||
value to the DSP. */
|
||||
static int write_control_reg(struct echoaudio *chip, u32 value, char force)
|
||||
{
|
||||
/* Handle the digital input auto-mute */
|
||||
if (chip->digital_in_automute)
|
||||
value |= GML_DIGITAL_IN_AUTO_MUTE;
|
||||
else
|
||||
value &= ~GML_DIGITAL_IN_AUTO_MUTE;
|
||||
|
||||
DE_ACT(("write_control_reg: 0x%x\n", value));
|
||||
|
||||
/* Write the control register */
|
||||
value = cpu_to_le32(value);
|
||||
if (value != chip->comm_page->control_register || force) {
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
chip->comm_page->control_register = value;
|
||||
clear_handshake(chip);
|
||||
return send_vector(chip, DSP_VC_WRITE_CONTROL_REG);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Gina24, Layla24, and Mona support digital input auto-mute. If the digital
|
||||
input auto-mute is enabled, the DSP will only enable the digital inputs if
|
||||
the card is syncing to a valid clock on the ADAT or S/PDIF inputs.
|
||||
If the auto-mute is disabled, the digital inputs are enabled regardless of
|
||||
what the input clock is set or what is connected. */
|
||||
static int set_input_auto_mute(struct echoaudio *chip, int automute)
|
||||
{
|
||||
DE_ACT(("set_input_auto_mute %d\n", automute));
|
||||
|
||||
chip->digital_in_automute = automute;
|
||||
|
||||
/* Re-set the input clock to the current value - indirectly causes
|
||||
the auto-mute flag to be sent to the DSP */
|
||||
return set_input_clock(chip, chip->input_clock);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* S/PDIF coax / S/PDIF optical / ADAT - switch */
|
||||
static int set_digital_mode(struct echoaudio *chip, u8 mode)
|
||||
{
|
||||
u8 previous_mode;
|
||||
int err, i, o;
|
||||
|
||||
if (chip->bad_board)
|
||||
return -EIO;
|
||||
|
||||
/* All audio channels must be closed before changing the digital mode */
|
||||
snd_assert(!chip->pipe_alloc_mask, return -EAGAIN);
|
||||
|
||||
snd_assert(chip->digital_modes & (1 << mode), return -EINVAL);
|
||||
|
||||
previous_mode = chip->digital_mode;
|
||||
err = dsp_set_digital_mode(chip, mode);
|
||||
|
||||
/* If we successfully changed the digital mode from or to ADAT,
|
||||
then make sure all output, input and monitor levels are
|
||||
updated by the DSP comm object. */
|
||||
if (err >= 0 && previous_mode != mode &&
|
||||
(previous_mode == DIGITAL_MODE_ADAT || mode == DIGITAL_MODE_ADAT)) {
|
||||
spin_lock_irq(&chip->lock);
|
||||
for (o = 0; o < num_busses_out(chip); o++)
|
||||
for (i = 0; i < num_busses_in(chip); i++)
|
||||
set_monitor_gain(chip, o, i,
|
||||
chip->monitor_gain[o][i]);
|
||||
|
||||
#ifdef ECHOCARD_HAS_INPUT_GAIN
|
||||
for (i = 0; i < num_busses_in(chip); i++)
|
||||
set_input_gain(chip, i, chip->input_gain[i]);
|
||||
update_input_line_level(chip);
|
||||
#endif
|
||||
|
||||
for (o = 0; o < num_busses_out(chip); o++)
|
||||
set_output_gain(chip, o, chip->output_gain[o]);
|
||||
update_output_line_level(chip);
|
||||
spin_unlock_irq(&chip->lock);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Set the S/PDIF output format */
|
||||
static int set_professional_spdif(struct echoaudio *chip, char prof)
|
||||
{
|
||||
u32 control_reg;
|
||||
int err;
|
||||
|
||||
/* Clear the current S/PDIF flags */
|
||||
control_reg = le32_to_cpu(chip->comm_page->control_register);
|
||||
control_reg &= GML_SPDIF_FORMAT_CLEAR_MASK;
|
||||
|
||||
/* Set the new S/PDIF flags depending on the mode */
|
||||
control_reg |= GML_SPDIF_TWO_CHANNEL | GML_SPDIF_24_BIT |
|
||||
GML_SPDIF_COPY_PERMIT;
|
||||
if (prof) {
|
||||
/* Professional mode */
|
||||
control_reg |= GML_SPDIF_PRO_MODE;
|
||||
|
||||
switch (chip->sample_rate) {
|
||||
case 32000:
|
||||
control_reg |= GML_SPDIF_SAMPLE_RATE0 |
|
||||
GML_SPDIF_SAMPLE_RATE1;
|
||||
break;
|
||||
case 44100:
|
||||
control_reg |= GML_SPDIF_SAMPLE_RATE0;
|
||||
break;
|
||||
case 48000:
|
||||
control_reg |= GML_SPDIF_SAMPLE_RATE1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Consumer mode */
|
||||
switch (chip->sample_rate) {
|
||||
case 32000:
|
||||
control_reg |= GML_SPDIF_SAMPLE_RATE0 |
|
||||
GML_SPDIF_SAMPLE_RATE1;
|
||||
break;
|
||||
case 48000:
|
||||
control_reg |= GML_SPDIF_SAMPLE_RATE1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((err = write_control_reg(chip, control_reg, FALSE)))
|
||||
return err;
|
||||
chip->professional_spdif = prof;
|
||||
DE_ACT(("set_professional_spdif to %s\n",
|
||||
prof ? "Professional" : "Consumer"));
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* ALSA driver for Echoaudio soundcards.
|
||||
* Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.it>
|
||||
*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#define ECHOGALS_FAMILY
|
||||
#define ECHOCARD_GINA20
|
||||
#define ECHOCARD_NAME "Gina20"
|
||||
#define ECHOCARD_HAS_MONITOR
|
||||
#define ECHOCARD_HAS_INPUT_GAIN
|
||||
#define ECHOCARD_HAS_DIGITAL_IO
|
||||
#define ECHOCARD_HAS_EXTERNAL_CLOCK
|
||||
#define ECHOCARD_HAS_ADAT FALSE
|
||||
|
||||
/* Pipe indexes */
|
||||
#define PX_ANALOG_OUT 0 /* 8 */
|
||||
#define PX_DIGITAL_OUT 8 /* 2 */
|
||||
#define PX_ANALOG_IN 10 /* 2 */
|
||||
#define PX_DIGITAL_IN 12 /* 2 */
|
||||
#define PX_NUM 14
|
||||
|
||||
/* Bus indexes */
|
||||
#define BX_ANALOG_OUT 0 /* 8 */
|
||||
#define BX_DIGITAL_OUT 8 /* 2 */
|
||||
#define BX_ANALOG_IN 10 /* 2 */
|
||||
#define BX_DIGITAL_IN 12 /* 2 */
|
||||
#define BX_NUM 14
|
||||
|
||||
|
||||
#include <sound/driver.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/info.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/initval.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/atomic.h>
|
||||
#include "echoaudio.h"
|
||||
|
||||
#define FW_GINA20_DSP 0
|
||||
|
||||
static const struct firmware card_fw[] = {
|
||||
{0, "gina20_dsp.fw"}
|
||||
};
|
||||
|
||||
static struct pci_device_id snd_echo_ids[] = {
|
||||
{0x1057, 0x1801, 0xECC0, 0x0020, 0, 0, 0}, /* DSP 56301 Gina20 rev.0 */
|
||||
{0,}
|
||||
};
|
||||
|
||||
static struct snd_pcm_hardware pcm_hardware_skel = {
|
||||
.info = SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_SYNC_START,
|
||||
.formats = SNDRV_PCM_FMTBIT_U8 |
|
||||
SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_3LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_BE,
|
||||
.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
|
||||
.rate_min = 44100,
|
||||
.rate_max = 48000,
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.buffer_bytes_max = 262144,
|
||||
.period_bytes_min = 32,
|
||||
.period_bytes_max = 131072,
|
||||
.periods_min = 2,
|
||||
.periods_max = 220,
|
||||
/* One page (4k) contains 512 instructions. I don't know if the hw
|
||||
supports lists longer than this. In this case periods_max=220 is a
|
||||
safe limit to make sure the list never exceeds 512 instructions. */
|
||||
};
|
||||
|
||||
|
||||
#include "gina20_dsp.c"
|
||||
#include "echoaudio_dsp.c"
|
||||
#include "echoaudio.c"
|
|
@ -0,0 +1,215 @@
|
|||
/****************************************************************************
|
||||
|
||||
Copyright Echo Digital Audio Corporation (c) 1998 - 2004
|
||||
All rights reserved
|
||||
www.echoaudio.com
|
||||
|
||||
This file is part of Echo Digital Audio's generic driver library.
|
||||
|
||||
Echo Digital Audio's generic driver library 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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA.
|
||||
|
||||
*************************************************************************
|
||||
|
||||
Translation from C++ and adaptation for use in ALSA-Driver
|
||||
were made by Giuliano Pochini <pochini@shiny.it>
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
static int set_professional_spdif(struct echoaudio *chip, char prof);
|
||||
static int update_flags(struct echoaudio *chip);
|
||||
|
||||
|
||||
static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
|
||||
{
|
||||
int err;
|
||||
|
||||
DE_INIT(("init_hw() - Gina20\n"));
|
||||
snd_assert((subdevice_id & 0xfff0) == GINA20, return -ENODEV);
|
||||
|
||||
if ((err = init_dsp_comm_page(chip))) {
|
||||
DE_INIT(("init_hw - could not initialize DSP comm page\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
chip->device_id = device_id;
|
||||
chip->subdevice_id = subdevice_id;
|
||||
chip->bad_board = TRUE;
|
||||
chip->dsp_code_to_load = &card_fw[FW_GINA20_DSP];
|
||||
chip->spdif_status = GD_SPDIF_STATUS_UNDEF;
|
||||
chip->clock_state = GD_CLOCK_UNDEF;
|
||||
/* Since this card has no ASIC, mark it as loaded so everything
|
||||
works OK */
|
||||
chip->asic_loaded = TRUE;
|
||||
chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL |
|
||||
ECHO_CLOCK_BIT_SPDIF;
|
||||
|
||||
if ((err = load_firmware(chip)) < 0)
|
||||
return err;
|
||||
chip->bad_board = FALSE;
|
||||
|
||||
if ((err = init_line_levels(chip)) < 0)
|
||||
return err;
|
||||
|
||||
err = set_professional_spdif(chip, TRUE);
|
||||
|
||||
DE_INIT(("init_hw done\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static u32 detect_input_clocks(const struct echoaudio *chip)
|
||||
{
|
||||
u32 clocks_from_dsp, clock_bits;
|
||||
|
||||
/* Map the DSP clock detect bits to the generic driver clock
|
||||
detect bits */
|
||||
clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
|
||||
|
||||
clock_bits = ECHO_CLOCK_BIT_INTERNAL;
|
||||
|
||||
if (clocks_from_dsp & GLDM_CLOCK_DETECT_BIT_SPDIF)
|
||||
clock_bits |= ECHO_CLOCK_BIT_SPDIF;
|
||||
|
||||
return clock_bits;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* The Gina20 has no ASIC. Just do nothing */
|
||||
static int load_asic(struct echoaudio *chip)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int set_sample_rate(struct echoaudio *chip, u32 rate)
|
||||
{
|
||||
u8 clock_state, spdif_status;
|
||||
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
|
||||
switch (rate) {
|
||||
case 44100:
|
||||
clock_state = GD_CLOCK_44;
|
||||
spdif_status = GD_SPDIF_STATUS_44;
|
||||
break;
|
||||
case 48000:
|
||||
clock_state = GD_CLOCK_48;
|
||||
spdif_status = GD_SPDIF_STATUS_48;
|
||||
break;
|
||||
default:
|
||||
clock_state = GD_CLOCK_NOCHANGE;
|
||||
spdif_status = GD_SPDIF_STATUS_NOCHANGE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (chip->clock_state == clock_state)
|
||||
clock_state = GD_CLOCK_NOCHANGE;
|
||||
if (spdif_status == chip->spdif_status)
|
||||
spdif_status = GD_SPDIF_STATUS_NOCHANGE;
|
||||
|
||||
chip->comm_page->sample_rate = cpu_to_le32(rate);
|
||||
chip->comm_page->gd_clock_state = clock_state;
|
||||
chip->comm_page->gd_spdif_status = spdif_status;
|
||||
chip->comm_page->gd_resampler_state = 3; /* magic number - should always be 3 */
|
||||
|
||||
/* Save the new audio state if it changed */
|
||||
if (clock_state != GD_CLOCK_NOCHANGE)
|
||||
chip->clock_state = clock_state;
|
||||
if (spdif_status != GD_SPDIF_STATUS_NOCHANGE)
|
||||
chip->spdif_status = spdif_status;
|
||||
chip->sample_rate = rate;
|
||||
|
||||
clear_handshake(chip);
|
||||
return send_vector(chip, DSP_VC_SET_GD_AUDIO_STATE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int set_input_clock(struct echoaudio *chip, u16 clock)
|
||||
{
|
||||
DE_ACT(("set_input_clock:\n"));
|
||||
|
||||
switch (clock) {
|
||||
case ECHO_CLOCK_INTERNAL:
|
||||
/* Reset the audio state to unknown (just in case) */
|
||||
chip->clock_state = GD_CLOCK_UNDEF;
|
||||
chip->spdif_status = GD_SPDIF_STATUS_UNDEF;
|
||||
set_sample_rate(chip, chip->sample_rate);
|
||||
chip->input_clock = clock;
|
||||
DE_ACT(("Set Gina clock to INTERNAL\n"));
|
||||
break;
|
||||
case ECHO_CLOCK_SPDIF:
|
||||
chip->comm_page->gd_clock_state = GD_CLOCK_SPDIFIN;
|
||||
chip->comm_page->gd_spdif_status = GD_SPDIF_STATUS_NOCHANGE;
|
||||
clear_handshake(chip);
|
||||
send_vector(chip, DSP_VC_SET_GD_AUDIO_STATE);
|
||||
chip->clock_state = GD_CLOCK_SPDIFIN;
|
||||
DE_ACT(("Set Gina20 clock to SPDIF\n"));
|
||||
chip->input_clock = clock;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Set input bus gain (one unit is 0.5dB !) */
|
||||
static int set_input_gain(struct echoaudio *chip, u16 input, int gain)
|
||||
{
|
||||
snd_assert(input < num_busses_in(chip), return -EINVAL);
|
||||
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
|
||||
chip->input_gain[input] = gain;
|
||||
gain += GL20_INPUT_GAIN_MAGIC_NUMBER;
|
||||
chip->comm_page->line_in_level[input] = gain;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Tell the DSP to reread the flags from the comm page */
|
||||
static int update_flags(struct echoaudio *chip)
|
||||
{
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
clear_handshake(chip);
|
||||
return send_vector(chip, DSP_VC_UPDATE_FLAGS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int set_professional_spdif(struct echoaudio *chip, char prof)
|
||||
{
|
||||
DE_ACT(("set_professional_spdif %d\n", prof));
|
||||
if (prof)
|
||||
chip->comm_page->flags |=
|
||||
__constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
|
||||
else
|
||||
chip->comm_page->flags &=
|
||||
~__constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
|
||||
chip->professional_spdif = prof;
|
||||
return update_flags(chip);
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* ALSA driver for Echoaudio soundcards.
|
||||
* Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.it>
|
||||
*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#define ECHO24_FAMILY
|
||||
#define ECHOCARD_GINA24
|
||||
#define ECHOCARD_NAME "Gina24"
|
||||
#define ECHOCARD_HAS_MONITOR
|
||||
#define ECHOCARD_HAS_ASIC
|
||||
#define ECHOCARD_HAS_INPUT_NOMINAL_LEVEL
|
||||
#define ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL
|
||||
#define ECHOCARD_HAS_SUPER_INTERLEAVE
|
||||
#define ECHOCARD_HAS_DIGITAL_IO
|
||||
#define ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE
|
||||
#define ECHOCARD_HAS_DIGITAL_MODE_SWITCH
|
||||
#define ECHOCARD_HAS_EXTERNAL_CLOCK
|
||||
#define ECHOCARD_HAS_ADAT 6
|
||||
#define ECHOCARD_HAS_STEREO_BIG_ENDIAN32
|
||||
|
||||
/* Pipe indexes */
|
||||
#define PX_ANALOG_OUT 0 /* 8 */
|
||||
#define PX_DIGITAL_OUT 8 /* 8 */
|
||||
#define PX_ANALOG_IN 16 /* 2 */
|
||||
#define PX_DIGITAL_IN 18 /* 8 */
|
||||
#define PX_NUM 26
|
||||
|
||||
/* Bus indexes */
|
||||
#define BX_ANALOG_OUT 0 /* 8 */
|
||||
#define BX_DIGITAL_OUT 8 /* 8 */
|
||||
#define BX_ANALOG_IN 16 /* 2 */
|
||||
#define BX_DIGITAL_IN 18 /* 8 */
|
||||
#define BX_NUM 26
|
||||
|
||||
|
||||
#include <sound/driver.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/info.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/initval.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/atomic.h>
|
||||
#include "echoaudio.h"
|
||||
|
||||
#define FW_361_LOADER 0
|
||||
#define FW_GINA24_301_DSP 1
|
||||
#define FW_GINA24_361_DSP 2
|
||||
#define FW_GINA24_301_ASIC 3
|
||||
#define FW_GINA24_361_ASIC 4
|
||||
|
||||
static const struct firmware card_fw[] = {
|
||||
{0, "loader_dsp.fw"},
|
||||
{0, "gina24_301_dsp.fw"},
|
||||
{0, "gina24_361_dsp.fw"},
|
||||
{0, "gina24_301_asic.fw"},
|
||||
{0, "gina24_361_asic.fw"}
|
||||
};
|
||||
|
||||
static struct pci_device_id snd_echo_ids[] = {
|
||||
{0x1057, 0x1801, 0xECC0, 0x0050, 0, 0, 0}, /* DSP 56301 Gina24 rev.0 */
|
||||
{0x1057, 0x1801, 0xECC0, 0x0051, 0, 0, 0}, /* DSP 56301 Gina24 rev.1 */
|
||||
{0x1057, 0x3410, 0xECC0, 0x0050, 0, 0, 0}, /* DSP 56361 Gina24 rev.0 */
|
||||
{0x1057, 0x3410, 0xECC0, 0x0051, 0, 0, 0}, /* DSP 56361 Gina24 rev.1 */
|
||||
{0,}
|
||||
};
|
||||
|
||||
static struct snd_pcm_hardware pcm_hardware_skel = {
|
||||
.info = SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_SYNC_START,
|
||||
.formats = SNDRV_PCM_FMTBIT_U8 |
|
||||
SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_3LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_BE,
|
||||
.rates = SNDRV_PCM_RATE_8000_48000 |
|
||||
SNDRV_PCM_RATE_88200 |
|
||||
SNDRV_PCM_RATE_96000,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 96000,
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.buffer_bytes_max = 262144,
|
||||
.period_bytes_min = 32,
|
||||
.period_bytes_max = 131072,
|
||||
.periods_min = 2,
|
||||
.periods_max = 220,
|
||||
/* One page (4k) contains 512 instructions. I don't know if the hw
|
||||
supports lists longer than this. In this case periods_max=220 is a
|
||||
safe limit to make sure the list never exceeds 512 instructions.
|
||||
220 ~= (512 - 1 - (BUFFER_BYTES_MAX / PAGE_SIZE)) / 2 */
|
||||
};
|
||||
|
||||
#include "gina24_dsp.c"
|
||||
#include "echoaudio_dsp.c"
|
||||
#include "echoaudio_gml.c"
|
||||
#include "echoaudio.c"
|
|
@ -0,0 +1,346 @@
|
|||
/****************************************************************************
|
||||
|
||||
Copyright Echo Digital Audio Corporation (c) 1998 - 2004
|
||||
All rights reserved
|
||||
www.echoaudio.com
|
||||
|
||||
This file is part of Echo Digital Audio's generic driver library.
|
||||
|
||||
Echo Digital Audio's generic driver library 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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA.
|
||||
|
||||
*************************************************************************
|
||||
|
||||
Translation from C++ and adaptation for use in ALSA-Driver
|
||||
were made by Giuliano Pochini <pochini@shiny.it>
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
static int write_control_reg(struct echoaudio *chip, u32 value, char force);
|
||||
static int set_input_clock(struct echoaudio *chip, u16 clock);
|
||||
static int set_professional_spdif(struct echoaudio *chip, char prof);
|
||||
static int set_digital_mode(struct echoaudio *chip, u8 mode);
|
||||
static int load_asic_generic(struct echoaudio *chip, u32 cmd,
|
||||
const struct firmware *asic);
|
||||
static int check_asic_status(struct echoaudio *chip);
|
||||
|
||||
|
||||
static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
|
||||
{
|
||||
int err;
|
||||
|
||||
DE_INIT(("init_hw() - Gina24\n"));
|
||||
snd_assert((subdevice_id & 0xfff0) == GINA24, return -ENODEV);
|
||||
|
||||
if ((err = init_dsp_comm_page(chip))) {
|
||||
DE_INIT(("init_hw - could not initialize DSP comm page\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
chip->device_id = device_id;
|
||||
chip->subdevice_id = subdevice_id;
|
||||
chip->bad_board = TRUE;
|
||||
chip->input_clock_types =
|
||||
ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF |
|
||||
ECHO_CLOCK_BIT_ESYNC | ECHO_CLOCK_BIT_ESYNC96 |
|
||||
ECHO_CLOCK_BIT_ADAT;
|
||||
chip->professional_spdif = FALSE;
|
||||
chip->digital_in_automute = TRUE;
|
||||
chip->digital_mode = DIGITAL_MODE_SPDIF_RCA;
|
||||
|
||||
/* Gina24 comes in both '301 and '361 flavors */
|
||||
if (chip->device_id == DEVICE_ID_56361) {
|
||||
chip->dsp_code_to_load = &card_fw[FW_GINA24_361_DSP];
|
||||
chip->digital_modes =
|
||||
ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA |
|
||||
ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL |
|
||||
ECHOCAPS_HAS_DIGITAL_MODE_ADAT;
|
||||
} else {
|
||||
chip->dsp_code_to_load = &card_fw[FW_GINA24_301_DSP];
|
||||
chip->digital_modes =
|
||||
ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA |
|
||||
ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL |
|
||||
ECHOCAPS_HAS_DIGITAL_MODE_ADAT |
|
||||
ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_CDROM;
|
||||
}
|
||||
|
||||
if ((err = load_firmware(chip)) < 0)
|
||||
return err;
|
||||
chip->bad_board = FALSE;
|
||||
|
||||
if ((err = init_line_levels(chip)) < 0)
|
||||
return err;
|
||||
err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA);
|
||||
snd_assert(err >= 0, return err);
|
||||
err = set_professional_spdif(chip, TRUE);
|
||||
|
||||
DE_INIT(("init_hw done\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static u32 detect_input_clocks(const struct echoaudio *chip)
|
||||
{
|
||||
u32 clocks_from_dsp, clock_bits;
|
||||
|
||||
/* Map the DSP clock detect bits to the generic driver clock
|
||||
detect bits */
|
||||
clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
|
||||
|
||||
clock_bits = ECHO_CLOCK_BIT_INTERNAL;
|
||||
|
||||
if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_SPDIF)
|
||||
clock_bits |= ECHO_CLOCK_BIT_SPDIF;
|
||||
|
||||
if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_ADAT)
|
||||
clock_bits |= ECHO_CLOCK_BIT_ADAT;
|
||||
|
||||
if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_ESYNC)
|
||||
clock_bits |= ECHO_CLOCK_BIT_ESYNC | ECHO_CLOCK_BIT_ESYNC96;
|
||||
|
||||
return clock_bits;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Gina24 has an ASIC on the PCI card which must be loaded for anything
|
||||
interesting to happen. */
|
||||
static int load_asic(struct echoaudio *chip)
|
||||
{
|
||||
u32 control_reg;
|
||||
int err;
|
||||
const struct firmware *fw;
|
||||
|
||||
if (chip->asic_loaded)
|
||||
return 1;
|
||||
|
||||
/* Give the DSP a few milliseconds to settle down */
|
||||
mdelay(10);
|
||||
|
||||
/* Pick the correct ASIC for '301 or '361 Gina24 */
|
||||
if (chip->device_id == DEVICE_ID_56361)
|
||||
fw = &card_fw[FW_GINA24_361_ASIC];
|
||||
else
|
||||
fw = &card_fw[FW_GINA24_301_ASIC];
|
||||
|
||||
if ((err = load_asic_generic(chip, DSP_FNC_LOAD_GINA24_ASIC, fw)) < 0)
|
||||
return err;
|
||||
|
||||
chip->asic_code = fw;
|
||||
|
||||
/* Now give the new ASIC a little time to set up */
|
||||
mdelay(10);
|
||||
/* See if it worked */
|
||||
err = check_asic_status(chip);
|
||||
|
||||
/* Set up the control register if the load succeeded -
|
||||
48 kHz, internal clock, S/PDIF RCA mode */
|
||||
if (!err) {
|
||||
control_reg = GML_CONVERTER_ENABLE | GML_48KHZ;
|
||||
err = write_control_reg(chip, control_reg, TRUE);
|
||||
}
|
||||
DE_INIT(("load_asic() done\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int set_sample_rate(struct echoaudio *chip, u32 rate)
|
||||
{
|
||||
u32 control_reg, clock;
|
||||
|
||||
snd_assert(rate < 50000 || chip->digital_mode != DIGITAL_MODE_ADAT,
|
||||
return -EINVAL);
|
||||
|
||||
/* Only set the clock for internal mode. */
|
||||
if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
|
||||
DE_ACT(("set_sample_rate: Cannot set sample rate - "
|
||||
"clock not set to CLK_CLOCKININTERNAL\n"));
|
||||
/* Save the rate anyhow */
|
||||
chip->comm_page->sample_rate = cpu_to_le32(rate);
|
||||
chip->sample_rate = rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
clock = 0;
|
||||
|
||||
control_reg = le32_to_cpu(chip->comm_page->control_register);
|
||||
control_reg &= GML_CLOCK_CLEAR_MASK & GML_SPDIF_RATE_CLEAR_MASK;
|
||||
|
||||
switch (rate) {
|
||||
case 96000:
|
||||
clock = GML_96KHZ;
|
||||
break;
|
||||
case 88200:
|
||||
clock = GML_88KHZ;
|
||||
break;
|
||||
case 48000:
|
||||
clock = GML_48KHZ | GML_SPDIF_SAMPLE_RATE1;
|
||||
break;
|
||||
case 44100:
|
||||
clock = GML_44KHZ;
|
||||
/* Professional mode ? */
|
||||
if (control_reg & GML_SPDIF_PRO_MODE)
|
||||
clock |= GML_SPDIF_SAMPLE_RATE0;
|
||||
break;
|
||||
case 32000:
|
||||
clock = GML_32KHZ | GML_SPDIF_SAMPLE_RATE0 |
|
||||
GML_SPDIF_SAMPLE_RATE1;
|
||||
break;
|
||||
case 22050:
|
||||
clock = GML_22KHZ;
|
||||
break;
|
||||
case 16000:
|
||||
clock = GML_16KHZ;
|
||||
break;
|
||||
case 11025:
|
||||
clock = GML_11KHZ;
|
||||
break;
|
||||
case 8000:
|
||||
clock = GML_8KHZ;
|
||||
break;
|
||||
default:
|
||||
DE_ACT(("set_sample_rate: %d invalid!\n", rate));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
control_reg |= clock;
|
||||
|
||||
chip->comm_page->sample_rate = cpu_to_le32(rate); /* ignored by the DSP */
|
||||
chip->sample_rate = rate;
|
||||
DE_ACT(("set_sample_rate: %d clock %d\n", rate, clock));
|
||||
|
||||
return write_control_reg(chip, control_reg, FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int set_input_clock(struct echoaudio *chip, u16 clock)
|
||||
{
|
||||
u32 control_reg, clocks_from_dsp;
|
||||
|
||||
DE_ACT(("set_input_clock:\n"));
|
||||
|
||||
/* Mask off the clock select bits */
|
||||
control_reg = le32_to_cpu(chip->comm_page->control_register) &
|
||||
GML_CLOCK_CLEAR_MASK;
|
||||
clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
|
||||
|
||||
switch (clock) {
|
||||
case ECHO_CLOCK_INTERNAL:
|
||||
DE_ACT(("Set Gina24 clock to INTERNAL\n"));
|
||||
chip->input_clock = ECHO_CLOCK_INTERNAL;
|
||||
return set_sample_rate(chip, chip->sample_rate);
|
||||
case ECHO_CLOCK_SPDIF:
|
||||
if (chip->digital_mode == DIGITAL_MODE_ADAT)
|
||||
return -EAGAIN;
|
||||
DE_ACT(("Set Gina24 clock to SPDIF\n"));
|
||||
control_reg |= GML_SPDIF_CLOCK;
|
||||
if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_SPDIF96)
|
||||
control_reg |= GML_DOUBLE_SPEED_MODE;
|
||||
else
|
||||
control_reg &= ~GML_DOUBLE_SPEED_MODE;
|
||||
break;
|
||||
case ECHO_CLOCK_ADAT:
|
||||
if (chip->digital_mode != DIGITAL_MODE_ADAT)
|
||||
return -EAGAIN;
|
||||
DE_ACT(("Set Gina24 clock to ADAT\n"));
|
||||
control_reg |= GML_ADAT_CLOCK;
|
||||
control_reg &= ~GML_DOUBLE_SPEED_MODE;
|
||||
break;
|
||||
case ECHO_CLOCK_ESYNC:
|
||||
DE_ACT(("Set Gina24 clock to ESYNC\n"));
|
||||
control_reg |= GML_ESYNC_CLOCK;
|
||||
control_reg &= ~GML_DOUBLE_SPEED_MODE;
|
||||
break;
|
||||
case ECHO_CLOCK_ESYNC96:
|
||||
DE_ACT(("Set Gina24 clock to ESYNC96\n"));
|
||||
control_reg |= GML_ESYNC_CLOCK | GML_DOUBLE_SPEED_MODE;
|
||||
break;
|
||||
default:
|
||||
DE_ACT(("Input clock 0x%x not supported for Gina24\n", clock));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chip->input_clock = clock;
|
||||
return write_control_reg(chip, control_reg, TRUE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
|
||||
{
|
||||
u32 control_reg;
|
||||
int err, incompatible_clock;
|
||||
|
||||
/* Set clock to "internal" if it's not compatible with the new mode */
|
||||
incompatible_clock = FALSE;
|
||||
switch (mode) {
|
||||
case DIGITAL_MODE_SPDIF_OPTICAL:
|
||||
case DIGITAL_MODE_SPDIF_CDROM:
|
||||
case DIGITAL_MODE_SPDIF_RCA:
|
||||
if (chip->input_clock == ECHO_CLOCK_ADAT)
|
||||
incompatible_clock = TRUE;
|
||||
break;
|
||||
case DIGITAL_MODE_ADAT:
|
||||
if (chip->input_clock == ECHO_CLOCK_SPDIF)
|
||||
incompatible_clock = TRUE;
|
||||
break;
|
||||
default:
|
||||
DE_ACT(("Digital mode not supported: %d\n", mode));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irq(&chip->lock);
|
||||
|
||||
if (incompatible_clock) { /* Switch to 48KHz, internal */
|
||||
chip->sample_rate = 48000;
|
||||
set_input_clock(chip, ECHO_CLOCK_INTERNAL);
|
||||
}
|
||||
|
||||
/* Clear the current digital mode */
|
||||
control_reg = le32_to_cpu(chip->comm_page->control_register);
|
||||
control_reg &= GML_DIGITAL_MODE_CLEAR_MASK;
|
||||
|
||||
/* Tweak the control reg */
|
||||
switch (mode) {
|
||||
case DIGITAL_MODE_SPDIF_OPTICAL:
|
||||
control_reg |= GML_SPDIF_OPTICAL_MODE;
|
||||
break;
|
||||
case DIGITAL_MODE_SPDIF_CDROM:
|
||||
/* '361 Gina24 cards do not have the S/PDIF CD-ROM mode */
|
||||
if (chip->device_id == DEVICE_ID_56301)
|
||||
control_reg |= GML_SPDIF_CDROM_MODE;
|
||||
break;
|
||||
case DIGITAL_MODE_SPDIF_RCA:
|
||||
/* GML_SPDIF_OPTICAL_MODE bit cleared */
|
||||
break;
|
||||
case DIGITAL_MODE_ADAT:
|
||||
control_reg |= GML_ADAT_MODE;
|
||||
control_reg &= ~GML_DOUBLE_SPEED_MODE;
|
||||
break;
|
||||
}
|
||||
|
||||
err = write_control_reg(chip, control_reg, TRUE);
|
||||
spin_unlock_irq(&chip->lock);
|
||||
if (err < 0)
|
||||
return err;
|
||||
chip->digital_mode = mode;
|
||||
|
||||
DE_ACT(("set_digital_mode to %d\n", chip->digital_mode));
|
||||
return incompatible_clock;
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* ALSA driver for Echoaudio soundcards.
|
||||
* Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.it>
|
||||
*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#define INDIGO_FAMILY
|
||||
#define ECHOCARD_INDIGO
|
||||
#define ECHOCARD_NAME "Indigo"
|
||||
#define ECHOCARD_HAS_SUPER_INTERLEAVE
|
||||
#define ECHOCARD_HAS_VMIXER
|
||||
#define ECHOCARD_HAS_STEREO_BIG_ENDIAN32
|
||||
|
||||
/* Pipe indexes */
|
||||
#define PX_ANALOG_OUT 0 /* 8 */
|
||||
#define PX_DIGITAL_OUT 8 /* 0 */
|
||||
#define PX_ANALOG_IN 8 /* 0 */
|
||||
#define PX_DIGITAL_IN 8 /* 0 */
|
||||
#define PX_NUM 8
|
||||
|
||||
/* Bus indexes */
|
||||
#define BX_ANALOG_OUT 0 /* 2 */
|
||||
#define BX_DIGITAL_OUT 2 /* 0 */
|
||||
#define BX_ANALOG_IN 2 /* 0 */
|
||||
#define BX_DIGITAL_IN 2 /* 0 */
|
||||
#define BX_NUM 2
|
||||
|
||||
|
||||
#include <sound/driver.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/info.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/initval.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/atomic.h>
|
||||
#include "echoaudio.h"
|
||||
|
||||
#define FW_361_LOADER 0
|
||||
#define FW_INDIGO_DSP 1
|
||||
|
||||
static const struct firmware card_fw[] = {
|
||||
{0, "loader_dsp.fw"},
|
||||
{0, "indigo_dsp.fw"}
|
||||
};
|
||||
|
||||
static struct pci_device_id snd_echo_ids[] = {
|
||||
{0x1057, 0x3410, 0xECC0, 0x0090, 0, 0, 0}, /* Indigo */
|
||||
{0,}
|
||||
};
|
||||
|
||||
static struct snd_pcm_hardware pcm_hardware_skel = {
|
||||
.info = SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_SYNC_START,
|
||||
.formats = SNDRV_PCM_FMTBIT_U8 |
|
||||
SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_3LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_BE,
|
||||
.rates = SNDRV_PCM_RATE_32000 |
|
||||
SNDRV_PCM_RATE_44100 |
|
||||
SNDRV_PCM_RATE_48000 |
|
||||
SNDRV_PCM_RATE_88200 |
|
||||
SNDRV_PCM_RATE_96000,
|
||||
.rate_min = 32000,
|
||||
.rate_max = 96000,
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.buffer_bytes_max = 262144,
|
||||
.period_bytes_min = 32,
|
||||
.period_bytes_max = 131072,
|
||||
.periods_min = 2,
|
||||
.periods_max = 220,
|
||||
};
|
||||
|
||||
#include "indigo_dsp.c"
|
||||
#include "echoaudio_dsp.c"
|
||||
#include "echoaudio.c"
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
/****************************************************************************
|
||||
|
||||
Copyright Echo Digital Audio Corporation (c) 1998 - 2004
|
||||
All rights reserved
|
||||
www.echoaudio.com
|
||||
|
||||
This file is part of Echo Digital Audio's generic driver library.
|
||||
|
||||
Echo Digital Audio's generic driver library 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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA.
|
||||
|
||||
*************************************************************************
|
||||
|
||||
Translation from C++ and adaptation for use in ALSA-Driver
|
||||
were made by Giuliano Pochini <pochini@shiny.it>
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
|
||||
int gain);
|
||||
static int update_vmixer_level(struct echoaudio *chip);
|
||||
|
||||
|
||||
static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
|
||||
{
|
||||
int err;
|
||||
|
||||
DE_INIT(("init_hw() - Indigo\n"));
|
||||
snd_assert((subdevice_id & 0xfff0) == INDIGO, return -ENODEV);
|
||||
|
||||
if ((err = init_dsp_comm_page(chip))) {
|
||||
DE_INIT(("init_hw - could not initialize DSP comm page\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
chip->device_id = device_id;
|
||||
chip->subdevice_id = subdevice_id;
|
||||
chip->bad_board = TRUE;
|
||||
chip->dsp_code_to_load = &card_fw[FW_INDIGO_DSP];
|
||||
/* Since this card has no ASIC, mark it as loaded so everything
|
||||
works OK */
|
||||
chip->asic_loaded = TRUE;
|
||||
chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL;
|
||||
|
||||
if ((err = load_firmware(chip)) < 0)
|
||||
return err;
|
||||
chip->bad_board = FALSE;
|
||||
|
||||
if ((err = init_line_levels(chip)) < 0)
|
||||
return err;
|
||||
|
||||
/* Default routing of the virtual channels: all vchannels are routed
|
||||
to the stereo output */
|
||||
set_vmixer_gain(chip, 0, 0, 0);
|
||||
set_vmixer_gain(chip, 1, 1, 0);
|
||||
set_vmixer_gain(chip, 0, 2, 0);
|
||||
set_vmixer_gain(chip, 1, 3, 0);
|
||||
set_vmixer_gain(chip, 0, 4, 0);
|
||||
set_vmixer_gain(chip, 1, 5, 0);
|
||||
set_vmixer_gain(chip, 0, 6, 0);
|
||||
set_vmixer_gain(chip, 1, 7, 0);
|
||||
err = update_vmixer_level(chip);
|
||||
|
||||
DE_INIT(("init_hw done\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static u32 detect_input_clocks(const struct echoaudio *chip)
|
||||
{
|
||||
return ECHO_CLOCK_BIT_INTERNAL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* The Indigo has no ASIC. Just do nothing */
|
||||
static int load_asic(struct echoaudio *chip)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int set_sample_rate(struct echoaudio *chip, u32 rate)
|
||||
{
|
||||
u32 control_reg;
|
||||
|
||||
switch (rate) {
|
||||
case 96000:
|
||||
control_reg = MIA_96000;
|
||||
break;
|
||||
case 88200:
|
||||
control_reg = MIA_88200;
|
||||
break;
|
||||
case 48000:
|
||||
control_reg = MIA_48000;
|
||||
break;
|
||||
case 44100:
|
||||
control_reg = MIA_44100;
|
||||
break;
|
||||
case 32000:
|
||||
control_reg = MIA_32000;
|
||||
break;
|
||||
default:
|
||||
DE_ACT(("set_sample_rate: %d invalid!\n", rate));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Set the control register if it has changed */
|
||||
if (control_reg != le32_to_cpu(chip->comm_page->control_register)) {
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
|
||||
chip->comm_page->sample_rate = cpu_to_le32(rate); /* ignored by the DSP */
|
||||
chip->comm_page->control_register = cpu_to_le32(control_reg);
|
||||
chip->sample_rate = rate;
|
||||
|
||||
clear_handshake(chip);
|
||||
return send_vector(chip, DSP_VC_UPDATE_CLOCKS);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* This function routes the sound from a virtual channel to a real output */
|
||||
static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
|
||||
int gain)
|
||||
{
|
||||
int index;
|
||||
|
||||
snd_assert(pipe < num_pipes_out(chip) &&
|
||||
output < num_busses_out(chip), return -EINVAL);
|
||||
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
|
||||
chip->vmixer_gain[output][pipe] = gain;
|
||||
index = output * num_pipes_out(chip) + pipe;
|
||||
chip->comm_page->vmixer[index] = gain;
|
||||
|
||||
DE_ACT(("set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Tell the DSP to read and update virtual mixer levels in comm page. */
|
||||
static int update_vmixer_level(struct echoaudio *chip)
|
||||
{
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
clear_handshake(chip);
|
||||
return send_vector(chip, DSP_VC_SET_VMIXER_GAIN);
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* ALSA driver for Echoaudio soundcards.
|
||||
* Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.it>
|
||||
*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#define INDIGO_FAMILY
|
||||
#define ECHOCARD_INDIGO_DJ
|
||||
#define ECHOCARD_NAME "Indigo DJ"
|
||||
#define ECHOCARD_HAS_SUPER_INTERLEAVE
|
||||
#define ECHOCARD_HAS_VMIXER
|
||||
#define ECHOCARD_HAS_STEREO_BIG_ENDIAN32
|
||||
|
||||
/* Pipe indexes */
|
||||
#define PX_ANALOG_OUT 0 /* 8 */
|
||||
#define PX_DIGITAL_OUT 8 /* 0 */
|
||||
#define PX_ANALOG_IN 8 /* 0 */
|
||||
#define PX_DIGITAL_IN 8 /* 0 */
|
||||
#define PX_NUM 8
|
||||
|
||||
/* Bus indexes */
|
||||
#define BX_ANALOG_OUT 0 /* 4 */
|
||||
#define BX_DIGITAL_OUT 4 /* 0 */
|
||||
#define BX_ANALOG_IN 4 /* 0 */
|
||||
#define BX_DIGITAL_IN 4 /* 0 */
|
||||
#define BX_NUM 4
|
||||
|
||||
|
||||
#include <sound/driver.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/info.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/initval.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/atomic.h>
|
||||
#include "echoaudio.h"
|
||||
|
||||
#define FW_361_LOADER 0
|
||||
#define FW_INDIGO_DJ_DSP 1
|
||||
|
||||
static const struct firmware card_fw[] = {
|
||||
{0, "loader_dsp.fw"},
|
||||
{0, "indigo_dj_dsp.fw"}
|
||||
};
|
||||
|
||||
static struct pci_device_id snd_echo_ids[] = {
|
||||
{0x1057, 0x3410, 0xECC0, 0x00B0, 0, 0, 0}, /* Indigo DJ*/
|
||||
{0,}
|
||||
};
|
||||
|
||||
static struct snd_pcm_hardware pcm_hardware_skel = {
|
||||
.info = SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_SYNC_START,
|
||||
.formats = SNDRV_PCM_FMTBIT_U8 |
|
||||
SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_3LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_BE,
|
||||
.rates = SNDRV_PCM_RATE_32000 |
|
||||
SNDRV_PCM_RATE_44100 |
|
||||
SNDRV_PCM_RATE_48000 |
|
||||
SNDRV_PCM_RATE_88200 |
|
||||
SNDRV_PCM_RATE_96000,
|
||||
.rate_min = 32000,
|
||||
.rate_max = 96000,
|
||||
.channels_min = 1,
|
||||
.channels_max = 4,
|
||||
.buffer_bytes_max = 262144,
|
||||
.period_bytes_min = 32,
|
||||
.period_bytes_max = 131072,
|
||||
.periods_min = 2,
|
||||
.periods_max = 220,
|
||||
};
|
||||
|
||||
#include "indigodj_dsp.c"
|
||||
#include "echoaudio_dsp.c"
|
||||
#include "echoaudio.c"
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
/****************************************************************************
|
||||
|
||||
Copyright Echo Digital Audio Corporation (c) 1998 - 2004
|
||||
All rights reserved
|
||||
www.echoaudio.com
|
||||
|
||||
This file is part of Echo Digital Audio's generic driver library.
|
||||
|
||||
Echo Digital Audio's generic driver library 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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA.
|
||||
|
||||
*************************************************************************
|
||||
|
||||
Translation from C++ and adaptation for use in ALSA-Driver
|
||||
were made by Giuliano Pochini <pochini@shiny.it>
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
|
||||
int gain);
|
||||
static int update_vmixer_level(struct echoaudio *chip);
|
||||
|
||||
|
||||
static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
|
||||
{
|
||||
int err;
|
||||
|
||||
DE_INIT(("init_hw() - Indigo DJ\n"));
|
||||
snd_assert((subdevice_id & 0xfff0) == INDIGO_DJ, return -ENODEV);
|
||||
|
||||
if ((err = init_dsp_comm_page(chip))) {
|
||||
DE_INIT(("init_hw - could not initialize DSP comm page\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
chip->device_id = device_id;
|
||||
chip->subdevice_id = subdevice_id;
|
||||
chip->bad_board = TRUE;
|
||||
chip->dsp_code_to_load = &card_fw[FW_INDIGO_DJ_DSP];
|
||||
/* Since this card has no ASIC, mark it as loaded so everything
|
||||
works OK */
|
||||
chip->asic_loaded = TRUE;
|
||||
chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL;
|
||||
|
||||
if ((err = load_firmware(chip)) < 0)
|
||||
return err;
|
||||
chip->bad_board = FALSE;
|
||||
|
||||
if ((err = init_line_levels(chip)) < 0)
|
||||
return err;
|
||||
|
||||
/* Default routing of the virtual channels: vchannels 0-3 and
|
||||
vchannels 4-7 are routed to real channels 0-4 */
|
||||
set_vmixer_gain(chip, 0, 0, 0);
|
||||
set_vmixer_gain(chip, 1, 1, 0);
|
||||
set_vmixer_gain(chip, 2, 2, 0);
|
||||
set_vmixer_gain(chip, 3, 3, 0);
|
||||
set_vmixer_gain(chip, 0, 4, 0);
|
||||
set_vmixer_gain(chip, 1, 5, 0);
|
||||
set_vmixer_gain(chip, 2, 6, 0);
|
||||
set_vmixer_gain(chip, 3, 7, 0);
|
||||
err = update_vmixer_level(chip);
|
||||
|
||||
DE_INIT(("init_hw done\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static u32 detect_input_clocks(const struct echoaudio *chip)
|
||||
{
|
||||
return ECHO_CLOCK_BIT_INTERNAL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* The IndigoDJ has no ASIC. Just do nothing */
|
||||
static int load_asic(struct echoaudio *chip)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int set_sample_rate(struct echoaudio *chip, u32 rate)
|
||||
{
|
||||
u32 control_reg;
|
||||
|
||||
switch (rate) {
|
||||
case 96000:
|
||||
control_reg = MIA_96000;
|
||||
break;
|
||||
case 88200:
|
||||
control_reg = MIA_88200;
|
||||
break;
|
||||
case 48000:
|
||||
control_reg = MIA_48000;
|
||||
break;
|
||||
case 44100:
|
||||
control_reg = MIA_44100;
|
||||
break;
|
||||
case 32000:
|
||||
control_reg = MIA_32000;
|
||||
break;
|
||||
default:
|
||||
DE_ACT(("set_sample_rate: %d invalid!\n", rate));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Set the control register if it has changed */
|
||||
if (control_reg != le32_to_cpu(chip->comm_page->control_register)) {
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
|
||||
chip->comm_page->sample_rate = cpu_to_le32(rate); /* ignored by the DSP */
|
||||
chip->comm_page->control_register = cpu_to_le32(control_reg);
|
||||
chip->sample_rate = rate;
|
||||
|
||||
clear_handshake(chip);
|
||||
return send_vector(chip, DSP_VC_UPDATE_CLOCKS);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* This function routes the sound from a virtual channel to a real output */
|
||||
static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
|
||||
int gain)
|
||||
{
|
||||
int index;
|
||||
|
||||
snd_assert(pipe < num_pipes_out(chip) &&
|
||||
output < num_busses_out(chip), return -EINVAL);
|
||||
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
|
||||
chip->vmixer_gain[output][pipe] = gain;
|
||||
index = output * num_pipes_out(chip) + pipe;
|
||||
chip->comm_page->vmixer[index] = gain;
|
||||
|
||||
DE_ACT(("set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Tell the DSP to read and update virtual mixer levels in comm page. */
|
||||
static int update_vmixer_level(struct echoaudio *chip)
|
||||
{
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
clear_handshake(chip);
|
||||
return send_vector(chip, DSP_VC_SET_VMIXER_GAIN);
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* ALSA driver for Echoaudio soundcards.
|
||||
* Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.it>
|
||||
*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#define INDIGO_FAMILY
|
||||
#define ECHOCARD_INDIGO_IO
|
||||
#define ECHOCARD_NAME "Indigo IO"
|
||||
#define ECHOCARD_HAS_MONITOR
|
||||
#define ECHOCARD_HAS_SUPER_INTERLEAVE
|
||||
#define ECHOCARD_HAS_VMIXER
|
||||
#define ECHOCARD_HAS_STEREO_BIG_ENDIAN32
|
||||
|
||||
/* Pipe indexes */
|
||||
#define PX_ANALOG_OUT 0 /* 8 */
|
||||
#define PX_DIGITAL_OUT 8 /* 0 */
|
||||
#define PX_ANALOG_IN 8 /* 2 */
|
||||
#define PX_DIGITAL_IN 10 /* 0 */
|
||||
#define PX_NUM 10
|
||||
|
||||
/* Bus indexes */
|
||||
#define BX_ANALOG_OUT 0 /* 2 */
|
||||
#define BX_DIGITAL_OUT 2 /* 0 */
|
||||
#define BX_ANALOG_IN 2 /* 2 */
|
||||
#define BX_DIGITAL_IN 4 /* 0 */
|
||||
#define BX_NUM 4
|
||||
|
||||
|
||||
#include <sound/driver.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/info.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/initval.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/atomic.h>
|
||||
#include "echoaudio.h"
|
||||
|
||||
#define FW_361_LOADER 0
|
||||
#define FW_INDIGO_IO_DSP 1
|
||||
|
||||
static const struct firmware card_fw[] = {
|
||||
{0, "loader_dsp.fw"},
|
||||
{0, "indigo_io_dsp.fw"}
|
||||
};
|
||||
|
||||
static struct pci_device_id snd_echo_ids[] = {
|
||||
{0x1057, 0x3410, 0xECC0, 0x00A0, 0, 0, 0}, /* Indigo IO*/
|
||||
{0,}
|
||||
};
|
||||
|
||||
static struct snd_pcm_hardware pcm_hardware_skel = {
|
||||
.info = SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_SYNC_START,
|
||||
.formats = SNDRV_PCM_FMTBIT_U8 |
|
||||
SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_3LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_BE,
|
||||
.rates = SNDRV_PCM_RATE_32000 |
|
||||
SNDRV_PCM_RATE_44100 |
|
||||
SNDRV_PCM_RATE_48000 |
|
||||
SNDRV_PCM_RATE_88200 |
|
||||
SNDRV_PCM_RATE_96000,
|
||||
.rate_min = 32000,
|
||||
.rate_max = 96000,
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.buffer_bytes_max = 262144,
|
||||
.period_bytes_min = 32,
|
||||
.period_bytes_max = 131072,
|
||||
.periods_min = 2,
|
||||
.periods_max = 220,
|
||||
};
|
||||
|
||||
#include "indigoio_dsp.c"
|
||||
#include "echoaudio_dsp.c"
|
||||
#include "echoaudio.c"
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
/****************************************************************************
|
||||
|
||||
Copyright Echo Digital Audio Corporation (c) 1998 - 2004
|
||||
All rights reserved
|
||||
www.echoaudio.com
|
||||
|
||||
This file is part of Echo Digital Audio's generic driver library.
|
||||
|
||||
Echo Digital Audio's generic driver library 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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA.
|
||||
|
||||
*************************************************************************
|
||||
|
||||
Translation from C++ and adaptation for use in ALSA-Driver
|
||||
were made by Giuliano Pochini <pochini@shiny.it>
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
|
||||
int gain);
|
||||
static int update_vmixer_level(struct echoaudio *chip);
|
||||
|
||||
|
||||
static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
|
||||
{
|
||||
int err;
|
||||
|
||||
DE_INIT(("init_hw() - Indigo IO\n"));
|
||||
snd_assert((subdevice_id & 0xfff0) == INDIGO_IO, return -ENODEV);
|
||||
|
||||
if ((err = init_dsp_comm_page(chip))) {
|
||||
DE_INIT(("init_hw - could not initialize DSP comm page\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
chip->device_id = device_id;
|
||||
chip->subdevice_id = subdevice_id;
|
||||
chip->bad_board = TRUE;
|
||||
chip->dsp_code_to_load = &card_fw[FW_INDIGO_IO_DSP];
|
||||
/* Since this card has no ASIC, mark it as loaded so everything
|
||||
works OK */
|
||||
chip->asic_loaded = TRUE;
|
||||
chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL;
|
||||
|
||||
if ((err = load_firmware(chip)) < 0)
|
||||
return err;
|
||||
chip->bad_board = FALSE;
|
||||
|
||||
if ((err = init_line_levels(chip)) < 0)
|
||||
return err;
|
||||
|
||||
/* Default routing of the virtual channels: all vchannels are routed
|
||||
to the stereo output */
|
||||
set_vmixer_gain(chip, 0, 0, 0);
|
||||
set_vmixer_gain(chip, 1, 1, 0);
|
||||
set_vmixer_gain(chip, 0, 2, 0);
|
||||
set_vmixer_gain(chip, 1, 3, 0);
|
||||
set_vmixer_gain(chip, 0, 4, 0);
|
||||
set_vmixer_gain(chip, 1, 5, 0);
|
||||
set_vmixer_gain(chip, 0, 6, 0);
|
||||
set_vmixer_gain(chip, 1, 7, 0);
|
||||
err = update_vmixer_level(chip);
|
||||
|
||||
DE_INIT(("init_hw done\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static u32 detect_input_clocks(const struct echoaudio *chip)
|
||||
{
|
||||
return ECHO_CLOCK_BIT_INTERNAL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* The IndigoIO has no ASIC. Just do nothing */
|
||||
static int load_asic(struct echoaudio *chip)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int set_sample_rate(struct echoaudio *chip, u32 rate)
|
||||
{
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
|
||||
chip->sample_rate = rate;
|
||||
chip->comm_page->sample_rate = cpu_to_le32(rate);
|
||||
clear_handshake(chip);
|
||||
return send_vector(chip, DSP_VC_UPDATE_CLOCKS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* This function routes the sound from a virtual channel to a real output */
|
||||
static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
|
||||
int gain)
|
||||
{
|
||||
int index;
|
||||
|
||||
snd_assert(pipe < num_pipes_out(chip) &&
|
||||
output < num_busses_out(chip), return -EINVAL);
|
||||
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
|
||||
chip->vmixer_gain[output][pipe] = gain;
|
||||
index = output * num_pipes_out(chip) + pipe;
|
||||
chip->comm_page->vmixer[index] = gain;
|
||||
|
||||
DE_ACT(("set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Tell the DSP to read and update virtual mixer levels in comm page. */
|
||||
static int update_vmixer_level(struct echoaudio *chip)
|
||||
{
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
clear_handshake(chip);
|
||||
return send_vector(chip, DSP_VC_SET_VMIXER_GAIN);
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* ALSA driver for Echoaudio soundcards.
|
||||
* Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.it>
|
||||
*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#define ECHOGALS_FAMILY
|
||||
#define ECHOCARD_LAYLA20
|
||||
#define ECHOCARD_NAME "Layla20"
|
||||
#define ECHOCARD_HAS_MONITOR
|
||||
#define ECHOCARD_HAS_ASIC
|
||||
#define ECHOCARD_HAS_INPUT_GAIN
|
||||
#define ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL
|
||||
#define ECHOCARD_HAS_SUPER_INTERLEAVE
|
||||
#define ECHOCARD_HAS_DIGITAL_IO
|
||||
#define ECHOCARD_HAS_EXTERNAL_CLOCK
|
||||
#define ECHOCARD_HAS_ADAT FALSE
|
||||
#define ECHOCARD_HAS_OUTPUT_CLOCK_SWITCH
|
||||
#define ECHOCARD_HAS_MIDI
|
||||
|
||||
/* Pipe indexes */
|
||||
#define PX_ANALOG_OUT 0 /* 10 */
|
||||
#define PX_DIGITAL_OUT 10 /* 2 */
|
||||
#define PX_ANALOG_IN 12 /* 8 */
|
||||
#define PX_DIGITAL_IN 20 /* 2 */
|
||||
#define PX_NUM 22
|
||||
|
||||
/* Bus indexes */
|
||||
#define BX_ANALOG_OUT 0 /* 10 */
|
||||
#define BX_DIGITAL_OUT 10 /* 2 */
|
||||
#define BX_ANALOG_IN 12 /* 8 */
|
||||
#define BX_DIGITAL_IN 20 /* 2 */
|
||||
#define BX_NUM 22
|
||||
|
||||
|
||||
#include <sound/driver.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/info.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/rawmidi.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/atomic.h>
|
||||
#include "echoaudio.h"
|
||||
|
||||
#define FW_LAYLA20_DSP 0
|
||||
#define FW_LAYLA20_ASIC 1
|
||||
|
||||
static const struct firmware card_fw[] = {
|
||||
{0, "layla20_dsp.fw"},
|
||||
{0, "layla20_asic.fw"}
|
||||
};
|
||||
|
||||
static struct pci_device_id snd_echo_ids[] = {
|
||||
{0x1057, 0x1801, 0xECC0, 0x0030, 0, 0, 0}, /* DSP 56301 Layla20 rev.0 */
|
||||
{0x1057, 0x1801, 0xECC0, 0x0031, 0, 0, 0}, /* DSP 56301 Layla20 rev.1 */
|
||||
{0,}
|
||||
};
|
||||
|
||||
static struct snd_pcm_hardware pcm_hardware_skel = {
|
||||
.info = SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_SYNC_START,
|
||||
.formats = SNDRV_PCM_FMTBIT_U8 |
|
||||
SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_3LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_BE,
|
||||
.rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_CONTINUOUS,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 50000,
|
||||
.channels_min = 1,
|
||||
.channels_max = 10,
|
||||
.buffer_bytes_max = 262144,
|
||||
.period_bytes_min = 32,
|
||||
.period_bytes_max = 131072,
|
||||
.periods_min = 2,
|
||||
.periods_max = 220,
|
||||
/* One page (4k) contains 512 instructions. I don't know if the hw
|
||||
supports lists longer than this. In this case periods_max=220 is a
|
||||
safe limit to make sure the list never exceeds 512 instructions. */
|
||||
};
|
||||
|
||||
#include "layla20_dsp.c"
|
||||
#include "echoaudio_dsp.c"
|
||||
#include "echoaudio.c"
|
||||
#include "midi.c"
|
|
@ -0,0 +1,290 @@
|
|||
/****************************************************************************
|
||||
|
||||
Copyright Echo Digital Audio Corporation (c) 1998 - 2004
|
||||
All rights reserved
|
||||
www.echoaudio.com
|
||||
|
||||
This file is part of Echo Digital Audio's generic driver library.
|
||||
|
||||
Echo Digital Audio's generic driver library 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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA.
|
||||
|
||||
*************************************************************************
|
||||
|
||||
Translation from C++ and adaptation for use in ALSA-Driver
|
||||
were made by Giuliano Pochini <pochini@shiny.it>
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
static int read_dsp(struct echoaudio *chip, u32 *data);
|
||||
static int set_professional_spdif(struct echoaudio *chip, char prof);
|
||||
static int load_asic_generic(struct echoaudio *chip, u32 cmd,
|
||||
const struct firmware *asic);
|
||||
static int check_asic_status(struct echoaudio *chip);
|
||||
static int update_flags(struct echoaudio *chip);
|
||||
|
||||
|
||||
static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
|
||||
{
|
||||
int err;
|
||||
|
||||
DE_INIT(("init_hw() - Layla20\n"));
|
||||
snd_assert((subdevice_id & 0xfff0) == LAYLA20, return -ENODEV);
|
||||
|
||||
if ((err = init_dsp_comm_page(chip))) {
|
||||
DE_INIT(("init_hw - could not initialize DSP comm page\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
chip->device_id = device_id;
|
||||
chip->subdevice_id = subdevice_id;
|
||||
chip->bad_board = TRUE;
|
||||
chip->has_midi = TRUE;
|
||||
chip->dsp_code_to_load = &card_fw[FW_LAYLA20_DSP];
|
||||
chip->input_clock_types =
|
||||
ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF |
|
||||
ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_SUPER;
|
||||
chip->output_clock_types =
|
||||
ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_SUPER;
|
||||
|
||||
if ((err = load_firmware(chip)) < 0)
|
||||
return err;
|
||||
chip->bad_board = FALSE;
|
||||
|
||||
if ((err = init_line_levels(chip)) < 0)
|
||||
return err;
|
||||
|
||||
err = set_professional_spdif(chip, TRUE);
|
||||
|
||||
DE_INIT(("init_hw done\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static u32 detect_input_clocks(const struct echoaudio *chip)
|
||||
{
|
||||
u32 clocks_from_dsp, clock_bits;
|
||||
|
||||
/* Map the DSP clock detect bits to the generic driver clock detect bits */
|
||||
clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
|
||||
|
||||
clock_bits = ECHO_CLOCK_BIT_INTERNAL;
|
||||
|
||||
if (clocks_from_dsp & GLDM_CLOCK_DETECT_BIT_SPDIF)
|
||||
clock_bits |= ECHO_CLOCK_BIT_SPDIF;
|
||||
|
||||
if (clocks_from_dsp & GLDM_CLOCK_DETECT_BIT_WORD) {
|
||||
if (clocks_from_dsp & GLDM_CLOCK_DETECT_BIT_SUPER)
|
||||
clock_bits |= ECHO_CLOCK_BIT_SUPER;
|
||||
else
|
||||
clock_bits |= ECHO_CLOCK_BIT_WORD;
|
||||
}
|
||||
|
||||
return clock_bits;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ASIC status check - some cards have one or two ASICs that need to be
|
||||
loaded. Once that load is complete, this function is called to see if
|
||||
the load was successful.
|
||||
If this load fails, it does not necessarily mean that the hardware is
|
||||
defective - the external box may be disconnected or turned off.
|
||||
This routine sometimes fails for Layla20; for Layla20, the loop runs
|
||||
5 times and succeeds if it wins on three of the loops. */
|
||||
static int check_asic_status(struct echoaudio *chip)
|
||||
{
|
||||
u32 asic_status;
|
||||
int goodcnt, i;
|
||||
|
||||
chip->asic_loaded = FALSE;
|
||||
for (i = goodcnt = 0; i < 5; i++) {
|
||||
send_vector(chip, DSP_VC_TEST_ASIC);
|
||||
|
||||
/* The DSP will return a value to indicate whether or not
|
||||
the ASIC is currently loaded */
|
||||
if (read_dsp(chip, &asic_status) < 0) {
|
||||
DE_ACT(("check_asic_status: failed on read_dsp\n"));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (asic_status == ASIC_ALREADY_LOADED) {
|
||||
if (++goodcnt == 3) {
|
||||
chip->asic_loaded = TRUE;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Layla20 has an ASIC in the external box */
|
||||
static int load_asic(struct echoaudio *chip)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (chip->asic_loaded)
|
||||
return 0;
|
||||
|
||||
err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA_ASIC,
|
||||
&card_fw[FW_LAYLA20_ASIC]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Check if ASIC is alive and well. */
|
||||
return check_asic_status(chip);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int set_sample_rate(struct echoaudio *chip, u32 rate)
|
||||
{
|
||||
snd_assert(rate >= 8000 && rate <= 50000, return -EINVAL);
|
||||
|
||||
/* Only set the clock for internal mode. Do not return failure,
|
||||
simply treat it as a non-event. */
|
||||
if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
|
||||
DE_ACT(("set_sample_rate: Cannot set sample rate - "
|
||||
"clock not set to CLK_CLOCKININTERNAL\n"));
|
||||
chip->comm_page->sample_rate = cpu_to_le32(rate);
|
||||
chip->sample_rate = rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
|
||||
DE_ACT(("set_sample_rate(%d)\n", rate));
|
||||
chip->sample_rate = rate;
|
||||
chip->comm_page->sample_rate = cpu_to_le32(rate);
|
||||
clear_handshake(chip);
|
||||
return send_vector(chip, DSP_VC_SET_LAYLA_SAMPLE_RATE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int set_input_clock(struct echoaudio *chip, u16 clock_source)
|
||||
{
|
||||
u16 clock;
|
||||
u32 rate;
|
||||
|
||||
DE_ACT(("set_input_clock:\n"));
|
||||
rate = 0;
|
||||
switch (clock_source) {
|
||||
case ECHO_CLOCK_INTERNAL:
|
||||
DE_ACT(("Set Layla20 clock to INTERNAL\n"));
|
||||
rate = chip->sample_rate;
|
||||
clock = LAYLA20_CLOCK_INTERNAL;
|
||||
break;
|
||||
case ECHO_CLOCK_SPDIF:
|
||||
DE_ACT(("Set Layla20 clock to SPDIF\n"));
|
||||
clock = LAYLA20_CLOCK_SPDIF;
|
||||
break;
|
||||
case ECHO_CLOCK_WORD:
|
||||
DE_ACT(("Set Layla20 clock to WORD\n"));
|
||||
clock = LAYLA20_CLOCK_WORD;
|
||||
break;
|
||||
case ECHO_CLOCK_SUPER:
|
||||
DE_ACT(("Set Layla20 clock to SUPER\n"));
|
||||
clock = LAYLA20_CLOCK_SUPER;
|
||||
break;
|
||||
default:
|
||||
DE_ACT(("Input clock 0x%x not supported for Layla24\n",
|
||||
clock_source));
|
||||
return -EINVAL;
|
||||
}
|
||||
chip->input_clock = clock_source;
|
||||
|
||||
chip->comm_page->input_clock = cpu_to_le16(clock);
|
||||
clear_handshake(chip);
|
||||
send_vector(chip, DSP_VC_UPDATE_CLOCKS);
|
||||
|
||||
if (rate)
|
||||
set_sample_rate(chip, rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int set_output_clock(struct echoaudio *chip, u16 clock)
|
||||
{
|
||||
DE_ACT(("set_output_clock: %d\n", clock));
|
||||
switch (clock) {
|
||||
case ECHO_CLOCK_SUPER:
|
||||
clock = LAYLA20_OUTPUT_CLOCK_SUPER;
|
||||
break;
|
||||
case ECHO_CLOCK_WORD:
|
||||
clock = LAYLA20_OUTPUT_CLOCK_WORD;
|
||||
break;
|
||||
default:
|
||||
DE_ACT(("set_output_clock wrong clock\n"));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
|
||||
chip->comm_page->output_clock = cpu_to_le16(clock);
|
||||
chip->output_clock = clock;
|
||||
clear_handshake(chip);
|
||||
return send_vector(chip, DSP_VC_UPDATE_CLOCKS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Set input bus gain (one unit is 0.5dB !) */
|
||||
static int set_input_gain(struct echoaudio *chip, u16 input, int gain)
|
||||
{
|
||||
snd_assert(input < num_busses_in(chip), return -EINVAL);
|
||||
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
|
||||
chip->input_gain[input] = gain;
|
||||
gain += GL20_INPUT_GAIN_MAGIC_NUMBER;
|
||||
chip->comm_page->line_in_level[input] = gain;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Tell the DSP to reread the flags from the comm page */
|
||||
static int update_flags(struct echoaudio *chip)
|
||||
{
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
clear_handshake(chip);
|
||||
return send_vector(chip, DSP_VC_UPDATE_FLAGS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int set_professional_spdif(struct echoaudio *chip, char prof)
|
||||
{
|
||||
DE_ACT(("set_professional_spdif %d\n", prof));
|
||||
if (prof)
|
||||
chip->comm_page->flags |=
|
||||
__constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
|
||||
else
|
||||
chip->comm_page->flags &=
|
||||
~__constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
|
||||
chip->professional_spdif = prof;
|
||||
return update_flags(chip);
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* ALSA driver for Echoaudio soundcards.
|
||||
* Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.it>
|
||||
*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#define ECHO24_FAMILY
|
||||
#define ECHOCARD_LAYLA24
|
||||
#define ECHOCARD_NAME "Layla24"
|
||||
#define ECHOCARD_HAS_MONITOR
|
||||
#define ECHOCARD_HAS_ASIC
|
||||
#define ECHOCARD_HAS_INPUT_NOMINAL_LEVEL
|
||||
#define ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL
|
||||
#define ECHOCARD_HAS_SUPER_INTERLEAVE
|
||||
#define ECHOCARD_HAS_DIGITAL_IO
|
||||
#define ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE
|
||||
#define ECHOCARD_HAS_DIGITAL_MODE_SWITCH
|
||||
#define ECHOCARD_HAS_EXTERNAL_CLOCK
|
||||
#define ECHOCARD_HAS_ADAT 6
|
||||
#define ECHOCARD_HAS_STEREO_BIG_ENDIAN32
|
||||
#define ECHOCARD_HAS_MIDI
|
||||
|
||||
/* Pipe indexes */
|
||||
#define PX_ANALOG_OUT 0 /* 8 */
|
||||
#define PX_DIGITAL_OUT 8 /* 8 */
|
||||
#define PX_ANALOG_IN 16 /* 8 */
|
||||
#define PX_DIGITAL_IN 24 /* 8 */
|
||||
#define PX_NUM 32
|
||||
|
||||
/* Bus indexes */
|
||||
#define BX_ANALOG_OUT 0 /* 8 */
|
||||
#define BX_DIGITAL_OUT 8 /* 8 */
|
||||
#define BX_ANALOG_IN 16 /* 8 */
|
||||
#define BX_DIGITAL_IN 24 /* 8 */
|
||||
#define BX_NUM 32
|
||||
|
||||
|
||||
#include <sound/driver.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/info.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/rawmidi.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/atomic.h>
|
||||
#include "echoaudio.h"
|
||||
|
||||
#define FW_361_LOADER 0
|
||||
#define FW_LAYLA24_DSP 1
|
||||
#define FW_LAYLA24_1_ASIC 2
|
||||
#define FW_LAYLA24_2A_ASIC 3
|
||||
#define FW_LAYLA24_2S_ASIC 4
|
||||
|
||||
static const struct firmware card_fw[] = {
|
||||
{0, "loader_dsp.fw"},
|
||||
{0, "layla24_dsp.fw"},
|
||||
{0, "layla24_1_asic.fw"},
|
||||
{0, "layla24_2A_asic.fw"},
|
||||
{0, "layla24_2S_asic.fw"}
|
||||
};
|
||||
|
||||
static struct pci_device_id snd_echo_ids[] = {
|
||||
{0x1057, 0x3410, 0xECC0, 0x0060, 0, 0, 0}, /* DSP 56361 Layla24 rev.0 */
|
||||
{0,}
|
||||
};
|
||||
|
||||
static struct snd_pcm_hardware pcm_hardware_skel = {
|
||||
.info = SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_SYNC_START,
|
||||
.formats = SNDRV_PCM_FMTBIT_U8 |
|
||||
SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_3LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_BE,
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 100000,
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.buffer_bytes_max = 262144,
|
||||
.period_bytes_min = 32,
|
||||
.period_bytes_max = 131072,
|
||||
.periods_min = 2,
|
||||
.periods_max = 220,
|
||||
/* One page (4k) contains 512 instructions. I don't know if the hw
|
||||
supports lists longer than this. In this case periods_max=220 is a
|
||||
safe limit to make sure the list never exceeds 512 instructions. */
|
||||
};
|
||||
|
||||
|
||||
#include "layla24_dsp.c"
|
||||
#include "echoaudio_dsp.c"
|
||||
#include "echoaudio_gml.c"
|
||||
#include "echoaudio.c"
|
||||
#include "midi.c"
|
|
@ -0,0 +1,394 @@
|
|||
/****************************************************************************
|
||||
|
||||
Copyright Echo Digital Audio Corporation (c) 1998 - 2004
|
||||
All rights reserved
|
||||
www.echoaudio.com
|
||||
|
||||
This file is part of Echo Digital Audio's generic driver library.
|
||||
|
||||
Echo Digital Audio's generic driver library 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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA.
|
||||
|
||||
*************************************************************************
|
||||
|
||||
Translation from C++ and adaptation for use in ALSA-Driver
|
||||
were made by Giuliano Pochini <pochini@shiny.it>
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
static int write_control_reg(struct echoaudio *chip, u32 value, char force);
|
||||
static int set_input_clock(struct echoaudio *chip, u16 clock);
|
||||
static int set_professional_spdif(struct echoaudio *chip, char prof);
|
||||
static int set_digital_mode(struct echoaudio *chip, u8 mode);
|
||||
static int load_asic_generic(struct echoaudio *chip, u32 cmd,
|
||||
const struct firmware *asic);
|
||||
static int check_asic_status(struct echoaudio *chip);
|
||||
|
||||
|
||||
static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
|
||||
{
|
||||
int err;
|
||||
|
||||
DE_INIT(("init_hw() - Layla24\n"));
|
||||
snd_assert((subdevice_id & 0xfff0) == LAYLA24, return -ENODEV);
|
||||
|
||||
if ((err = init_dsp_comm_page(chip))) {
|
||||
DE_INIT(("init_hw - could not initialize DSP comm page\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
chip->device_id = device_id;
|
||||
chip->subdevice_id = subdevice_id;
|
||||
chip->bad_board = TRUE;
|
||||
chip->has_midi = TRUE;
|
||||
chip->dsp_code_to_load = &card_fw[FW_LAYLA24_DSP];
|
||||
chip->input_clock_types =
|
||||
ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF |
|
||||
ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_ADAT;
|
||||
chip->digital_modes =
|
||||
ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA |
|
||||
ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL |
|
||||
ECHOCAPS_HAS_DIGITAL_MODE_ADAT;
|
||||
chip->digital_mode = DIGITAL_MODE_SPDIF_RCA;
|
||||
chip->professional_spdif = FALSE;
|
||||
chip->digital_in_automute = TRUE;
|
||||
|
||||
if ((err = load_firmware(chip)) < 0)
|
||||
return err;
|
||||
chip->bad_board = FALSE;
|
||||
|
||||
if ((err = init_line_levels(chip)) < 0)
|
||||
return err;
|
||||
|
||||
err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA);
|
||||
snd_assert(err >= 0, return err);
|
||||
err = set_professional_spdif(chip, TRUE);
|
||||
|
||||
DE_INIT(("init_hw done\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static u32 detect_input_clocks(const struct echoaudio *chip)
|
||||
{
|
||||
u32 clocks_from_dsp, clock_bits;
|
||||
|
||||
/* Map the DSP clock detect bits to the generic driver clock detect bits */
|
||||
clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
|
||||
|
||||
clock_bits = ECHO_CLOCK_BIT_INTERNAL;
|
||||
|
||||
if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_SPDIF)
|
||||
clock_bits |= ECHO_CLOCK_BIT_SPDIF;
|
||||
|
||||
if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_ADAT)
|
||||
clock_bits |= ECHO_CLOCK_BIT_ADAT;
|
||||
|
||||
if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_WORD)
|
||||
clock_bits |= ECHO_CLOCK_BIT_WORD;
|
||||
|
||||
return clock_bits;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Layla24 has an ASIC on the PCI card and another ASIC in the external box;
|
||||
both need to be loaded. */
|
||||
static int load_asic(struct echoaudio *chip)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (chip->asic_loaded)
|
||||
return 1;
|
||||
|
||||
DE_INIT(("load_asic\n"));
|
||||
|
||||
/* Give the DSP a few milliseconds to settle down */
|
||||
mdelay(10);
|
||||
|
||||
/* Load the ASIC for the PCI card */
|
||||
err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA24_PCI_CARD_ASIC,
|
||||
&card_fw[FW_LAYLA24_1_ASIC]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
chip->asic_code = &card_fw[FW_LAYLA24_2S_ASIC];
|
||||
|
||||
/* Now give the new ASIC a little time to set up */
|
||||
mdelay(10);
|
||||
|
||||
/* Do the external one */
|
||||
err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA24_EXTERNAL_ASIC,
|
||||
&card_fw[FW_LAYLA24_2S_ASIC]);
|
||||
if (err < 0)
|
||||
return FALSE;
|
||||
|
||||
/* Now give the external ASIC a little time to set up */
|
||||
mdelay(10);
|
||||
|
||||
/* See if it worked */
|
||||
err = check_asic_status(chip);
|
||||
|
||||
/* Set up the control register if the load succeeded -
|
||||
48 kHz, internal clock, S/PDIF RCA mode */
|
||||
if (!err)
|
||||
err = write_control_reg(chip, GML_CONVERTER_ENABLE | GML_48KHZ,
|
||||
TRUE);
|
||||
|
||||
DE_INIT(("load_asic() done\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int set_sample_rate(struct echoaudio *chip, u32 rate)
|
||||
{
|
||||
u32 control_reg, clock, base_rate;
|
||||
|
||||
snd_assert(rate < 50000 || chip->digital_mode != DIGITAL_MODE_ADAT,
|
||||
return -EINVAL);
|
||||
|
||||
/* Only set the clock for internal mode. */
|
||||
if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
|
||||
DE_ACT(("set_sample_rate: Cannot set sample rate - "
|
||||
"clock not set to CLK_CLOCKININTERNAL\n"));
|
||||
/* Save the rate anyhow */
|
||||
chip->comm_page->sample_rate = cpu_to_le32(rate);
|
||||
chip->sample_rate = rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the control register & clear the appropriate bits */
|
||||
control_reg = le32_to_cpu(chip->comm_page->control_register);
|
||||
control_reg &= GML_CLOCK_CLEAR_MASK & GML_SPDIF_RATE_CLEAR_MASK;
|
||||
|
||||
clock = 0;
|
||||
|
||||
switch (rate) {
|
||||
case 96000:
|
||||
clock = GML_96KHZ;
|
||||
break;
|
||||
case 88200:
|
||||
clock = GML_88KHZ;
|
||||
break;
|
||||
case 48000:
|
||||
clock = GML_48KHZ | GML_SPDIF_SAMPLE_RATE1;
|
||||
break;
|
||||
case 44100:
|
||||
clock = GML_44KHZ;
|
||||
/* Professional mode */
|
||||
if (control_reg & GML_SPDIF_PRO_MODE)
|
||||
clock |= GML_SPDIF_SAMPLE_RATE0;
|
||||
break;
|
||||
case 32000:
|
||||
clock = GML_32KHZ | GML_SPDIF_SAMPLE_RATE0 |
|
||||
GML_SPDIF_SAMPLE_RATE1;
|
||||
break;
|
||||
case 22050:
|
||||
clock = GML_22KHZ;
|
||||
break;
|
||||
case 16000:
|
||||
clock = GML_16KHZ;
|
||||
break;
|
||||
case 11025:
|
||||
clock = GML_11KHZ;
|
||||
break;
|
||||
case 8000:
|
||||
clock = GML_8KHZ;
|
||||
break;
|
||||
default:
|
||||
/* If this is a non-standard rate, then the driver needs to
|
||||
use Layla24's special "continuous frequency" mode */
|
||||
clock = LAYLA24_CONTINUOUS_CLOCK;
|
||||
if (rate > 50000) {
|
||||
base_rate = rate >> 1;
|
||||
control_reg |= GML_DOUBLE_SPEED_MODE;
|
||||
} else {
|
||||
base_rate = rate;
|
||||
}
|
||||
|
||||
if (base_rate < 25000)
|
||||
base_rate = 25000;
|
||||
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
|
||||
chip->comm_page->sample_rate =
|
||||
cpu_to_le32(LAYLA24_MAGIC_NUMBER / base_rate - 2);
|
||||
|
||||
clear_handshake(chip);
|
||||
send_vector(chip, DSP_VC_SET_LAYLA24_FREQUENCY_REG);
|
||||
}
|
||||
|
||||
control_reg |= clock;
|
||||
|
||||
chip->comm_page->sample_rate = cpu_to_le32(rate); /* ignored by the DSP ? */
|
||||
chip->sample_rate = rate;
|
||||
DE_ACT(("set_sample_rate: %d clock %d\n", rate, control_reg));
|
||||
|
||||
return write_control_reg(chip, control_reg, FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int set_input_clock(struct echoaudio *chip, u16 clock)
|
||||
{
|
||||
u32 control_reg, clocks_from_dsp;
|
||||
|
||||
/* Mask off the clock select bits */
|
||||
control_reg = le32_to_cpu(chip->comm_page->control_register) &
|
||||
GML_CLOCK_CLEAR_MASK;
|
||||
clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
|
||||
|
||||
/* Pick the new clock */
|
||||
switch (clock) {
|
||||
case ECHO_CLOCK_INTERNAL:
|
||||
DE_ACT(("Set Layla24 clock to INTERNAL\n"));
|
||||
chip->input_clock = ECHO_CLOCK_INTERNAL;
|
||||
return set_sample_rate(chip, chip->sample_rate);
|
||||
case ECHO_CLOCK_SPDIF:
|
||||
if (chip->digital_mode == DIGITAL_MODE_ADAT)
|
||||
return -EAGAIN;
|
||||
control_reg |= GML_SPDIF_CLOCK;
|
||||
/* Layla24 doesn't support 96KHz S/PDIF */
|
||||
control_reg &= ~GML_DOUBLE_SPEED_MODE;
|
||||
DE_ACT(("Set Layla24 clock to SPDIF\n"));
|
||||
break;
|
||||
case ECHO_CLOCK_WORD:
|
||||
control_reg |= GML_WORD_CLOCK;
|
||||
if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_WORD96)
|
||||
control_reg |= GML_DOUBLE_SPEED_MODE;
|
||||
else
|
||||
control_reg &= ~GML_DOUBLE_SPEED_MODE;
|
||||
DE_ACT(("Set Layla24 clock to WORD\n"));
|
||||
break;
|
||||
case ECHO_CLOCK_ADAT:
|
||||
if (chip->digital_mode != DIGITAL_MODE_ADAT)
|
||||
return -EAGAIN;
|
||||
control_reg |= GML_ADAT_CLOCK;
|
||||
control_reg &= ~GML_DOUBLE_SPEED_MODE;
|
||||
DE_ACT(("Set Layla24 clock to ADAT\n"));
|
||||
break;
|
||||
default:
|
||||
DE_ACT(("Input clock 0x%x not supported for Layla24\n", clock));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chip->input_clock = clock;
|
||||
return write_control_reg(chip, control_reg, TRUE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Depending on what digital mode you want, Layla24 needs different ASICs
|
||||
loaded. This function checks the ASIC needed for the new mode and sees
|
||||
if it matches the one already loaded. */
|
||||
static int switch_asic(struct echoaudio *chip, const struct firmware *asic)
|
||||
{
|
||||
s8 *monitors;
|
||||
|
||||
/* Check to see if this is already loaded */
|
||||
if (asic != chip->asic_code) {
|
||||
monitors = kmalloc(MONITOR_ARRAY_SIZE, GFP_KERNEL);
|
||||
if (! monitors)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(monitors, chip->comm_page->monitors, MONITOR_ARRAY_SIZE);
|
||||
memset(chip->comm_page->monitors, ECHOGAIN_MUTED,
|
||||
MONITOR_ARRAY_SIZE);
|
||||
|
||||
/* Load the desired ASIC */
|
||||
if (load_asic_generic(chip, DSP_FNC_LOAD_LAYLA24_EXTERNAL_ASIC,
|
||||
asic) < 0) {
|
||||
memcpy(chip->comm_page->monitors, monitors,
|
||||
MONITOR_ARRAY_SIZE);
|
||||
kfree(monitors);
|
||||
return -EIO;
|
||||
}
|
||||
chip->asic_code = asic;
|
||||
memcpy(chip->comm_page->monitors, monitors, MONITOR_ARRAY_SIZE);
|
||||
kfree(monitors);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
|
||||
{
|
||||
u32 control_reg;
|
||||
int err, incompatible_clock;
|
||||
const struct firmware *asic;
|
||||
|
||||
/* Set clock to "internal" if it's not compatible with the new mode */
|
||||
incompatible_clock = FALSE;
|
||||
switch (mode) {
|
||||
case DIGITAL_MODE_SPDIF_OPTICAL:
|
||||
case DIGITAL_MODE_SPDIF_RCA:
|
||||
if (chip->input_clock == ECHO_CLOCK_ADAT)
|
||||
incompatible_clock = TRUE;
|
||||
asic = &card_fw[FW_LAYLA24_2S_ASIC];
|
||||
break;
|
||||
case DIGITAL_MODE_ADAT:
|
||||
if (chip->input_clock == ECHO_CLOCK_SPDIF)
|
||||
incompatible_clock = TRUE;
|
||||
asic = &card_fw[FW_LAYLA24_2A_ASIC];
|
||||
break;
|
||||
default:
|
||||
DE_ACT(("Digital mode not supported: %d\n", mode));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (incompatible_clock) { /* Switch to 48KHz, internal */
|
||||
chip->sample_rate = 48000;
|
||||
spin_lock_irq(&chip->lock);
|
||||
set_input_clock(chip, ECHO_CLOCK_INTERNAL);
|
||||
spin_unlock_irq(&chip->lock);
|
||||
}
|
||||
|
||||
/* switch_asic() can sleep */
|
||||
if (switch_asic(chip, asic) < 0)
|
||||
return -EIO;
|
||||
|
||||
spin_lock_irq(&chip->lock);
|
||||
|
||||
/* Tweak the control register */
|
||||
control_reg = le32_to_cpu(chip->comm_page->control_register);
|
||||
control_reg &= GML_DIGITAL_MODE_CLEAR_MASK;
|
||||
|
||||
switch (mode) {
|
||||
case DIGITAL_MODE_SPDIF_OPTICAL:
|
||||
control_reg |= GML_SPDIF_OPTICAL_MODE;
|
||||
break;
|
||||
case DIGITAL_MODE_SPDIF_RCA:
|
||||
/* GML_SPDIF_OPTICAL_MODE bit cleared */
|
||||
break;
|
||||
case DIGITAL_MODE_ADAT:
|
||||
control_reg |= GML_ADAT_MODE;
|
||||
control_reg &= ~GML_DOUBLE_SPEED_MODE;
|
||||
break;
|
||||
}
|
||||
|
||||
err = write_control_reg(chip, control_reg, TRUE);
|
||||
spin_unlock_irq(&chip->lock);
|
||||
if (err < 0)
|
||||
return err;
|
||||
chip->digital_mode = mode;
|
||||
|
||||
DE_ACT(("set_digital_mode to %d\n", mode));
|
||||
return incompatible_clock;
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* ALSA driver for Echoaudio soundcards.
|
||||
* Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.it>
|
||||
*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#define ECHO24_FAMILY
|
||||
#define ECHOCARD_MIA
|
||||
#define ECHOCARD_NAME "Mia"
|
||||
#define ECHOCARD_HAS_MONITOR
|
||||
#define ECHOCARD_HAS_INPUT_NOMINAL_LEVEL
|
||||
#define ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL
|
||||
#define ECHOCARD_HAS_SUPER_INTERLEAVE
|
||||
#define ECHOCARD_HAS_VMIXER
|
||||
#define ECHOCARD_HAS_DIGITAL_IO
|
||||
#define ECHOCARD_HAS_EXTERNAL_CLOCK
|
||||
#define ECHOCARD_HAS_ADAT FALSE
|
||||
#define ECHOCARD_HAS_STEREO_BIG_ENDIAN32
|
||||
#define ECHOCARD_HAS_MIDI
|
||||
|
||||
/* Pipe indexes */
|
||||
#define PX_ANALOG_OUT 0 /* 8 */
|
||||
#define PX_DIGITAL_OUT 8 /* 0 */
|
||||
#define PX_ANALOG_IN 8 /* 2 */
|
||||
#define PX_DIGITAL_IN 10 /* 2 */
|
||||
#define PX_NUM 12
|
||||
|
||||
/* Bus indexes */
|
||||
#define BX_ANALOG_OUT 0 /* 2 */
|
||||
#define BX_DIGITAL_OUT 2 /* 2 */
|
||||
#define BX_ANALOG_IN 4 /* 2 */
|
||||
#define BX_DIGITAL_IN 6 /* 2 */
|
||||
#define BX_NUM 8
|
||||
|
||||
|
||||
#include <sound/driver.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/info.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/rawmidi.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/atomic.h>
|
||||
#include "echoaudio.h"
|
||||
|
||||
#define FW_361_LOADER 0
|
||||
#define FW_MIA_DSP 1
|
||||
|
||||
static const struct firmware card_fw[] = {
|
||||
{0, "loader_dsp.fw"},
|
||||
{0, "mia_dsp.fw"}
|
||||
};
|
||||
|
||||
static struct pci_device_id snd_echo_ids[] = {
|
||||
{0x1057, 0x3410, 0xECC0, 0x0080, 0, 0, 0}, /* DSP 56361 Mia rev.0 */
|
||||
{0x1057, 0x3410, 0xECC0, 0x0081, 0, 0, 0}, /* DSP 56361 Mia rev.1 */
|
||||
{0,}
|
||||
};
|
||||
|
||||
static struct snd_pcm_hardware pcm_hardware_skel = {
|
||||
.info = SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_SYNC_START,
|
||||
.formats = SNDRV_PCM_FMTBIT_U8 |
|
||||
SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_3LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_BE,
|
||||
.rates = SNDRV_PCM_RATE_32000 |
|
||||
SNDRV_PCM_RATE_44100 |
|
||||
SNDRV_PCM_RATE_48000 |
|
||||
SNDRV_PCM_RATE_88200 |
|
||||
SNDRV_PCM_RATE_96000,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 96000,
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.buffer_bytes_max = 262144,
|
||||
.period_bytes_min = 32,
|
||||
.period_bytes_max = 131072,
|
||||
.periods_min = 2,
|
||||
.periods_max = 220,
|
||||
/* One page (4k) contains 512 instructions. I don't know if the hw
|
||||
supports lists longer than this. In this case periods_max=220 is a
|
||||
safe limit to make sure the list never exceeds 512 instructions. */
|
||||
};
|
||||
|
||||
|
||||
#include "mia_dsp.c"
|
||||
#include "echoaudio_dsp.c"
|
||||
#include "echoaudio.c"
|
||||
#include "midi.c"
|
|
@ -0,0 +1,229 @@
|
|||
/****************************************************************************
|
||||
|
||||
Copyright Echo Digital Audio Corporation (c) 1998 - 2004
|
||||
All rights reserved
|
||||
www.echoaudio.com
|
||||
|
||||
This file is part of Echo Digital Audio's generic driver library.
|
||||
|
||||
Echo Digital Audio's generic driver library 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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA.
|
||||
|
||||
*************************************************************************
|
||||
|
||||
Translation from C++ and adaptation for use in ALSA-Driver
|
||||
were made by Giuliano Pochini <pochini@shiny.it>
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
static int set_input_clock(struct echoaudio *chip, u16 clock);
|
||||
static int set_professional_spdif(struct echoaudio *chip, char prof);
|
||||
static int update_flags(struct echoaudio *chip);
|
||||
static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
|
||||
int gain);
|
||||
static int update_vmixer_level(struct echoaudio *chip);
|
||||
|
||||
|
||||
static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
|
||||
{
|
||||
int err;
|
||||
|
||||
DE_INIT(("init_hw() - Mia\n"));
|
||||
snd_assert((subdevice_id & 0xfff0) == MIA, return -ENODEV);
|
||||
|
||||
if ((err = init_dsp_comm_page(chip))) {
|
||||
DE_INIT(("init_hw - could not initialize DSP comm page\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
chip->device_id = device_id;
|
||||
chip->subdevice_id = subdevice_id;
|
||||
chip->bad_board = TRUE;
|
||||
chip->dsp_code_to_load = &card_fw[FW_MIA_DSP];
|
||||
/* Since this card has no ASIC, mark it as loaded so everything
|
||||
works OK */
|
||||
chip->asic_loaded = TRUE;
|
||||
if ((subdevice_id & 0x0000f) == MIA_MIDI_REV)
|
||||
chip->has_midi = TRUE;
|
||||
chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL |
|
||||
ECHO_CLOCK_BIT_SPDIF;
|
||||
|
||||
if ((err = load_firmware(chip)) < 0)
|
||||
return err;
|
||||
chip->bad_board = FALSE;
|
||||
|
||||
if ((err = init_line_levels(chip)))
|
||||
return err;
|
||||
|
||||
/* Default routing of the virtual channels: vchannels 0-3 go to analog
|
||||
outputs and vchannels 4-7 go to S/PDIF outputs */
|
||||
set_vmixer_gain(chip, 0, 0, 0);
|
||||
set_vmixer_gain(chip, 1, 1, 0);
|
||||
set_vmixer_gain(chip, 0, 2, 0);
|
||||
set_vmixer_gain(chip, 1, 3, 0);
|
||||
set_vmixer_gain(chip, 2, 4, 0);
|
||||
set_vmixer_gain(chip, 3, 5, 0);
|
||||
set_vmixer_gain(chip, 2, 6, 0);
|
||||
set_vmixer_gain(chip, 3, 7, 0);
|
||||
err = update_vmixer_level(chip);
|
||||
|
||||
DE_INIT(("init_hw done\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static u32 detect_input_clocks(const struct echoaudio *chip)
|
||||
{
|
||||
u32 clocks_from_dsp, clock_bits;
|
||||
|
||||
/* Map the DSP clock detect bits to the generic driver clock
|
||||
detect bits */
|
||||
clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
|
||||
|
||||
clock_bits = ECHO_CLOCK_BIT_INTERNAL;
|
||||
|
||||
if (clocks_from_dsp & GLDM_CLOCK_DETECT_BIT_SPDIF)
|
||||
clock_bits |= ECHO_CLOCK_BIT_SPDIF;
|
||||
|
||||
return clock_bits;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* The Mia has no ASIC. Just do nothing */
|
||||
static int load_asic(struct echoaudio *chip)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int set_sample_rate(struct echoaudio *chip, u32 rate)
|
||||
{
|
||||
u32 control_reg;
|
||||
|
||||
switch (rate) {
|
||||
case 96000:
|
||||
control_reg = MIA_96000;
|
||||
break;
|
||||
case 88200:
|
||||
control_reg = MIA_88200;
|
||||
break;
|
||||
case 48000:
|
||||
control_reg = MIA_48000;
|
||||
break;
|
||||
case 44100:
|
||||
control_reg = MIA_44100;
|
||||
break;
|
||||
case 32000:
|
||||
control_reg = MIA_32000;
|
||||
break;
|
||||
default:
|
||||
DE_ACT(("set_sample_rate: %d invalid!\n", rate));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Override the clock setting if this Mia is set to S/PDIF clock */
|
||||
if (chip->input_clock == ECHO_CLOCK_SPDIF)
|
||||
control_reg |= MIA_SPDIF;
|
||||
|
||||
/* Set the control register if it has changed */
|
||||
if (control_reg != le32_to_cpu(chip->comm_page->control_register)) {
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
|
||||
chip->comm_page->sample_rate = cpu_to_le32(rate); /* ignored by the DSP */
|
||||
chip->comm_page->control_register = cpu_to_le32(control_reg);
|
||||
chip->sample_rate = rate;
|
||||
|
||||
clear_handshake(chip);
|
||||
return send_vector(chip, DSP_VC_UPDATE_CLOCKS);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int set_input_clock(struct echoaudio *chip, u16 clock)
|
||||
{
|
||||
DE_ACT(("set_input_clock(%d)\n", clock));
|
||||
snd_assert(clock == ECHO_CLOCK_INTERNAL || clock == ECHO_CLOCK_SPDIF,
|
||||
return -EINVAL);
|
||||
|
||||
chip->input_clock = clock;
|
||||
return set_sample_rate(chip, chip->sample_rate);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* This function routes the sound from a virtual channel to a real output */
|
||||
static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
|
||||
int gain)
|
||||
{
|
||||
int index;
|
||||
|
||||
snd_assert(pipe < num_pipes_out(chip) &&
|
||||
output < num_busses_out(chip), return -EINVAL);
|
||||
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
|
||||
chip->vmixer_gain[output][pipe] = gain;
|
||||
index = output * num_pipes_out(chip) + pipe;
|
||||
chip->comm_page->vmixer[index] = gain;
|
||||
|
||||
DE_ACT(("set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Tell the DSP to read and update virtual mixer levels in comm page. */
|
||||
static int update_vmixer_level(struct echoaudio *chip)
|
||||
{
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
clear_handshake(chip);
|
||||
return send_vector(chip, DSP_VC_SET_VMIXER_GAIN);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Tell the DSP to reread the flags from the comm page */
|
||||
static int update_flags(struct echoaudio *chip)
|
||||
{
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
clear_handshake(chip);
|
||||
return send_vector(chip, DSP_VC_UPDATE_FLAGS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int set_professional_spdif(struct echoaudio *chip, char prof)
|
||||
{
|
||||
DE_ACT(("set_professional_spdif %d\n", prof));
|
||||
if (prof)
|
||||
chip->comm_page->flags |=
|
||||
__constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
|
||||
else
|
||||
chip->comm_page->flags &=
|
||||
~__constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
|
||||
chip->professional_spdif = prof;
|
||||
return update_flags(chip);
|
||||
}
|
||||
|
|
@ -0,0 +1,327 @@
|
|||
/****************************************************************************
|
||||
|
||||
Copyright Echo Digital Audio Corporation (c) 1998 - 2004
|
||||
All rights reserved
|
||||
www.echoaudio.com
|
||||
|
||||
This file is part of Echo Digital Audio's generic driver library.
|
||||
|
||||
Echo Digital Audio's generic driver library 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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA.
|
||||
|
||||
*************************************************************************
|
||||
|
||||
Translation from C++ and adaptation for use in ALSA-Driver
|
||||
were made by Giuliano Pochini <pochini@shiny.it>
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
MIDI lowlevel code
|
||||
******************************************************************************/
|
||||
|
||||
/* Start and stop Midi input */
|
||||
static int enable_midi_input(struct echoaudio *chip, char enable)
|
||||
{
|
||||
DE_MID(("enable_midi_input(%d)\n", enable));
|
||||
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
|
||||
if (enable) {
|
||||
chip->mtc_state = MIDI_IN_STATE_NORMAL;
|
||||
chip->comm_page->flags |=
|
||||
_constant_cpu_to_le32(DSP_FLAG_MIDI_INPUT);
|
||||
} else
|
||||
chip->comm_page->flags &=
|
||||
~__constant_cpu_to_le32(DSP_FLAG_MIDI_INPUT);
|
||||
|
||||
clear_handshake(chip);
|
||||
return send_vector(chip, DSP_VC_UPDATE_FLAGS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Send a buffer full of MIDI data to the DSP
|
||||
Returns how many actually written or < 0 on error */
|
||||
static int write_midi(struct echoaudio *chip, u8 *data, int bytes)
|
||||
{
|
||||
snd_assert(bytes > 0 && bytes < MIDI_OUT_BUFFER_SIZE, return -EINVAL);
|
||||
|
||||
if (wait_handshake(chip))
|
||||
return -EIO;
|
||||
|
||||
/* HF4 indicates that it is safe to write MIDI output data */
|
||||
if (! (get_dsp_register(chip, CHI32_STATUS_REG) & CHI32_STATUS_REG_HF4))
|
||||
return 0;
|
||||
|
||||
chip->comm_page->midi_output[0] = bytes;
|
||||
memcpy(&chip->comm_page->midi_output[1], data, bytes);
|
||||
chip->comm_page->midi_out_free_count = 0;
|
||||
clear_handshake(chip);
|
||||
send_vector(chip, DSP_VC_MIDI_WRITE);
|
||||
DE_MID(("write_midi: %d\n", bytes));
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Run the state machine for MIDI input data
|
||||
MIDI time code sync isn't supported by this code right now, but you still need
|
||||
this state machine to parse the incoming MIDI data stream. Every time the DSP
|
||||
sees a 0xF1 byte come in, it adds the DSP sample position to the MIDI data
|
||||
stream. The DSP sample position is represented as a 32 bit unsigned value,
|
||||
with the high 16 bits first, followed by the low 16 bits. Since these aren't
|
||||
real MIDI bytes, the following logic is needed to skip them. */
|
||||
static inline int mtc_process_data(struct echoaudio *chip, short midi_byte)
|
||||
{
|
||||
switch (chip->mtc_state) {
|
||||
case MIDI_IN_STATE_NORMAL:
|
||||
if (midi_byte == 0xF1)
|
||||
chip->mtc_state = MIDI_IN_STATE_TS_HIGH;
|
||||
break;
|
||||
case MIDI_IN_STATE_TS_HIGH:
|
||||
chip->mtc_state = MIDI_IN_STATE_TS_LOW;
|
||||
return MIDI_IN_SKIP_DATA;
|
||||
break;
|
||||
case MIDI_IN_STATE_TS_LOW:
|
||||
chip->mtc_state = MIDI_IN_STATE_F1_DATA;
|
||||
return MIDI_IN_SKIP_DATA;
|
||||
break;
|
||||
case MIDI_IN_STATE_F1_DATA:
|
||||
chip->mtc_state = MIDI_IN_STATE_NORMAL;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* This function is called from the IRQ handler and it reads the midi data
|
||||
from the DSP's buffer. It returns the number of bytes received. */
|
||||
static int midi_service_irq(struct echoaudio *chip)
|
||||
{
|
||||
short int count, midi_byte, i, received;
|
||||
|
||||
/* The count is at index 0, followed by actual data */
|
||||
count = le16_to_cpu(chip->comm_page->midi_input[0]);
|
||||
|
||||
snd_assert(count < MIDI_IN_BUFFER_SIZE, return 0);
|
||||
|
||||
/* Get the MIDI data from the comm page */
|
||||
i = 1;
|
||||
received = 0;
|
||||
for (i = 1; i <= count; i++) {
|
||||
/* Get the MIDI byte */
|
||||
midi_byte = le16_to_cpu(chip->comm_page->midi_input[i]);
|
||||
|
||||
/* Parse the incoming MIDI stream. The incoming MIDI data
|
||||
consists of MIDI bytes and timestamps for the MIDI time code
|
||||
0xF1 bytes. mtc_process_data() is a little state machine that
|
||||
parses the stream. If you get MIDI_IN_SKIP_DATA back, then
|
||||
this is a timestamp byte, not a MIDI byte, so don't store it
|
||||
in the MIDI input buffer. */
|
||||
if (mtc_process_data(chip, midi_byte) == MIDI_IN_SKIP_DATA)
|
||||
continue;
|
||||
|
||||
chip->midi_buffer[received++] = (u8)midi_byte;
|
||||
}
|
||||
|
||||
return received;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
MIDI interface
|
||||
******************************************************************************/
|
||||
|
||||
static int snd_echo_midi_input_open(struct snd_rawmidi_substream *substream)
|
||||
{
|
||||
struct echoaudio *chip = substream->rmidi->private_data;
|
||||
|
||||
chip->midi_in = substream;
|
||||
DE_MID(("rawmidi_iopen\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void snd_echo_midi_input_trigger(struct snd_rawmidi_substream *substream,
|
||||
int up)
|
||||
{
|
||||
struct echoaudio *chip = substream->rmidi->private_data;
|
||||
|
||||
if (up != chip->midi_input_enabled) {
|
||||
spin_lock_irq(&chip->lock);
|
||||
enable_midi_input(chip, up);
|
||||
spin_unlock_irq(&chip->lock);
|
||||
chip->midi_input_enabled = up;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int snd_echo_midi_input_close(struct snd_rawmidi_substream *substream)
|
||||
{
|
||||
struct echoaudio *chip = substream->rmidi->private_data;
|
||||
|
||||
chip->midi_in = NULL;
|
||||
DE_MID(("rawmidi_iclose\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int snd_echo_midi_output_open(struct snd_rawmidi_substream *substream)
|
||||
{
|
||||
struct echoaudio *chip = substream->rmidi->private_data;
|
||||
|
||||
chip->tinuse = 0;
|
||||
chip->midi_full = 0;
|
||||
chip->midi_out = substream;
|
||||
DE_MID(("rawmidi_oopen\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void snd_echo_midi_output_write(unsigned long data)
|
||||
{
|
||||
struct echoaudio *chip = (struct echoaudio *)data;
|
||||
unsigned long flags;
|
||||
int bytes, sent, time;
|
||||
unsigned char buf[MIDI_OUT_BUFFER_SIZE - 1];
|
||||
|
||||
DE_MID(("snd_echo_midi_output_write\n"));
|
||||
/* No interrupts are involved: we have to check at regular intervals
|
||||
if the card's output buffer has room for new data. */
|
||||
sent = bytes = 0;
|
||||
spin_lock_irqsave(&chip->lock, flags);
|
||||
chip->midi_full = 0;
|
||||
if (chip->midi_out && !snd_rawmidi_transmit_empty(chip->midi_out)) {
|
||||
bytes = snd_rawmidi_transmit_peek(chip->midi_out, buf,
|
||||
MIDI_OUT_BUFFER_SIZE - 1);
|
||||
DE_MID(("Try to send %d bytes...\n", bytes));
|
||||
sent = write_midi(chip, buf, bytes);
|
||||
if (sent < 0) {
|
||||
snd_printk(KERN_ERR "write_midi() error %d\n", sent);
|
||||
/* retry later */
|
||||
sent = 9000;
|
||||
chip->midi_full = 1;
|
||||
} else if (sent > 0) {
|
||||
DE_MID(("%d bytes sent\n", sent));
|
||||
snd_rawmidi_transmit_ack(chip->midi_out, sent);
|
||||
} else {
|
||||
/* Buffer is full. DSP's internal buffer is 64 (128 ?)
|
||||
bytes long. Let's wait until half of them are sent */
|
||||
DE_MID(("Full\n"));
|
||||
sent = 32;
|
||||
chip->midi_full = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* We restart the timer only if there is some data left to send */
|
||||
if (!snd_rawmidi_transmit_empty(chip->midi_out) && chip->tinuse) {
|
||||
/* The timer will expire slightly after the data has been
|
||||
sent */
|
||||
time = (sent << 3) / 25 + 1; /* 8/25=0.32ms to send a byte */
|
||||
mod_timer(&chip->timer, jiffies + (time * HZ + 999) / 1000);
|
||||
DE_MID(("Timer armed(%d)\n", ((time * HZ + 999) / 1000)));
|
||||
}
|
||||
spin_unlock_irqrestore(&chip->lock, flags);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void snd_echo_midi_output_trigger(struct snd_rawmidi_substream *substream,
|
||||
int up)
|
||||
{
|
||||
struct echoaudio *chip = substream->rmidi->private_data;
|
||||
|
||||
DE_MID(("snd_echo_midi_output_trigger(%d)\n", up));
|
||||
spin_lock_irq(&chip->lock);
|
||||
if (up) {
|
||||
if (!chip->tinuse) {
|
||||
init_timer(&chip->timer);
|
||||
chip->timer.function = snd_echo_midi_output_write;
|
||||
chip->timer.data = (unsigned long)chip;
|
||||
chip->tinuse = 1;
|
||||
}
|
||||
} else {
|
||||
if (chip->tinuse) {
|
||||
del_timer(&chip->timer);
|
||||
chip->tinuse = 0;
|
||||
DE_MID(("Timer removed\n"));
|
||||
}
|
||||
}
|
||||
spin_unlock_irq(&chip->lock);
|
||||
|
||||
if (up && !chip->midi_full)
|
||||
snd_echo_midi_output_write((unsigned long)chip);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int snd_echo_midi_output_close(struct snd_rawmidi_substream *substream)
|
||||
{
|
||||
struct echoaudio *chip = substream->rmidi->private_data;
|
||||
|
||||
chip->midi_out = NULL;
|
||||
DE_MID(("rawmidi_oclose\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct snd_rawmidi_ops snd_echo_midi_input = {
|
||||
.open = snd_echo_midi_input_open,
|
||||
.close = snd_echo_midi_input_close,
|
||||
.trigger = snd_echo_midi_input_trigger,
|
||||
};
|
||||
|
||||
static struct snd_rawmidi_ops snd_echo_midi_output = {
|
||||
.open = snd_echo_midi_output_open,
|
||||
.close = snd_echo_midi_output_close,
|
||||
.trigger = snd_echo_midi_output_trigger,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* <--snd_echo_probe() */
|
||||
static int __devinit snd_echo_midi_create(struct snd_card *card,
|
||||
struct echoaudio *chip)
|
||||
{
|
||||
int err;
|
||||
|
||||
if ((err = snd_rawmidi_new(card, card->shortname, 0, 1, 1,
|
||||
&chip->rmidi)) < 0)
|
||||
return err;
|
||||
|
||||
strcpy(chip->rmidi->name, card->shortname);
|
||||
chip->rmidi->private_data = chip;
|
||||
|
||||
snd_rawmidi_set_ops(chip->rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
|
||||
&snd_echo_midi_input);
|
||||
snd_rawmidi_set_ops(chip->rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
|
||||
&snd_echo_midi_output);
|
||||
|
||||
chip->rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
|
||||
SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
|
||||
DE_INIT(("MIDI ok\n"));
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* ALSA driver for Echoaudio soundcards.
|
||||
* Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.it>
|
||||
*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#define ECHO24_FAMILY
|
||||
#define ECHOCARD_MONA
|
||||
#define ECHOCARD_NAME "Mona"
|
||||
#define ECHOCARD_HAS_MONITOR
|
||||
#define ECHOCARD_HAS_ASIC
|
||||
#define ECHOCARD_HAS_SUPER_INTERLEAVE
|
||||
#define ECHOCARD_HAS_DIGITAL_IO
|
||||
#define ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE
|
||||
#define ECHOCARD_HAS_DIGITAL_MODE_SWITCH
|
||||
#define ECHOCARD_HAS_EXTERNAL_CLOCK
|
||||
#define ECHOCARD_HAS_ADAT 6
|
||||
#define ECHOCARD_HAS_STEREO_BIG_ENDIAN32
|
||||
|
||||
/* Pipe indexes */
|
||||
#define PX_ANALOG_OUT 0 /* 6 */
|
||||
#define PX_DIGITAL_OUT 6 /* 8 */
|
||||
#define PX_ANALOG_IN 14 /* 4 */
|
||||
#define PX_DIGITAL_IN 18 /* 8 */
|
||||
#define PX_NUM 26
|
||||
|
||||
/* Bus indexes */
|
||||
#define BX_ANALOG_OUT 0 /* 6 */
|
||||
#define BX_DIGITAL_OUT 6 /* 8 */
|
||||
#define BX_ANALOG_IN 14 /* 4 */
|
||||
#define BX_DIGITAL_IN 18 /* 8 */
|
||||
#define BX_NUM 26
|
||||
|
||||
|
||||
#include <sound/driver.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/info.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/initval.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/atomic.h>
|
||||
#include "echoaudio.h"
|
||||
|
||||
#define FW_361_LOADER 0
|
||||
#define FW_MONA_301_DSP 1
|
||||
#define FW_MONA_361_DSP 2
|
||||
#define FW_MONA_301_1_ASIC48 3
|
||||
#define FW_MONA_301_1_ASIC96 4
|
||||
#define FW_MONA_361_1_ASIC48 5
|
||||
#define FW_MONA_361_1_ASIC96 6
|
||||
#define FW_MONA_2_ASIC 7
|
||||
|
||||
static const struct firmware card_fw[] = {
|
||||
{0, "loader_dsp.fw"},
|
||||
{0, "mona_301_dsp.fw"},
|
||||
{0, "mona_361_dsp.fw"},
|
||||
{0, "mona_301_1_asic_48.fw"},
|
||||
{0, "mona_301_1_asic_96.fw"},
|
||||
{0, "mona_361_1_asic_48.fw"},
|
||||
{0, "mona_361_1_asic_96.fw"},
|
||||
{0, "mona_2_asic.fw"}
|
||||
};
|
||||
|
||||
static struct pci_device_id snd_echo_ids[] = {
|
||||
{0x1057, 0x1801, 0xECC0, 0x0070, 0, 0, 0}, /* DSP 56301 Mona rev.0 */
|
||||
{0x1057, 0x1801, 0xECC0, 0x0071, 0, 0, 0}, /* DSP 56301 Mona rev.1 */
|
||||
{0x1057, 0x1801, 0xECC0, 0x0072, 0, 0, 0}, /* DSP 56301 Mona rev.2 */
|
||||
{0x1057, 0x3410, 0xECC0, 0x0070, 0, 0, 0}, /* DSP 56361 Mona rev.0 */
|
||||
{0x1057, 0x3410, 0xECC0, 0x0071, 0, 0, 0}, /* DSP 56361 Mona rev.1 */
|
||||
{0x1057, 0x3410, 0xECC0, 0x0072, 0, 0, 0}, /* DSP 56361 Mona rev.2 */
|
||||
{0,}
|
||||
};
|
||||
|
||||
static struct snd_pcm_hardware pcm_hardware_skel = {
|
||||
.info = SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_SYNC_START,
|
||||
.formats = SNDRV_PCM_FMTBIT_U8 |
|
||||
SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_3LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_BE,
|
||||
.rates = SNDRV_PCM_RATE_8000_48000 |
|
||||
SNDRV_PCM_RATE_88200 |
|
||||
SNDRV_PCM_RATE_96000,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 96000,
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.buffer_bytes_max = 262144,
|
||||
.period_bytes_min = 32,
|
||||
.period_bytes_max = 131072,
|
||||
.periods_min = 2,
|
||||
.periods_max = 220,
|
||||
/* One page (4k) contains 512 instructions. I don't know if the hw
|
||||
supports lists longer than this. In this case periods_max=220 is a
|
||||
safe limit to make sure the list never exceeds 512 instructions. */
|
||||
};
|
||||
|
||||
|
||||
#include "mona_dsp.c"
|
||||
#include "echoaudio_dsp.c"
|
||||
#include "echoaudio_gml.c"
|
||||
#include "echoaudio.c"
|
|
@ -0,0 +1,428 @@
|
|||
/****************************************************************************
|
||||
|
||||
Copyright Echo Digital Audio Corporation (c) 1998 - 2004
|
||||
All rights reserved
|
||||
www.echoaudio.com
|
||||
|
||||
This file is part of Echo Digital Audio's generic driver library.
|
||||
|
||||
Echo Digital Audio's generic driver library 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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA.
|
||||
|
||||
*************************************************************************
|
||||
|
||||
Translation from C++ and adaptation for use in ALSA-Driver
|
||||
were made by Giuliano Pochini <pochini@shiny.it>
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
static int write_control_reg(struct echoaudio *chip, u32 value, char force);
|
||||
static int set_input_clock(struct echoaudio *chip, u16 clock);
|
||||
static int set_professional_spdif(struct echoaudio *chip, char prof);
|
||||
static int set_digital_mode(struct echoaudio *chip, u8 mode);
|
||||
static int load_asic_generic(struct echoaudio *chip, u32 cmd,
|
||||
const struct firmware *asic);
|
||||
static int check_asic_status(struct echoaudio *chip);
|
||||
|
||||
|
||||
static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
|
||||
{
|
||||
int err;
|
||||
|
||||
DE_INIT(("init_hw() - Mona\n"));
|
||||
snd_assert((subdevice_id & 0xfff0) == MONA, return -ENODEV);
|
||||
|
||||
if ((err = init_dsp_comm_page(chip))) {
|
||||
DE_INIT(("init_hw - could not initialize DSP comm page\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
chip->device_id = device_id;
|
||||
chip->subdevice_id = subdevice_id;
|
||||
chip->bad_board = TRUE;
|
||||
chip->input_clock_types =
|
||||
ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF |
|
||||
ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_ADAT;
|
||||
chip->digital_modes =
|
||||
ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA |
|
||||
ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL |
|
||||
ECHOCAPS_HAS_DIGITAL_MODE_ADAT;
|
||||
|
||||
/* Mona comes in both '301 and '361 flavors */
|
||||
if (chip->device_id == DEVICE_ID_56361)
|
||||
chip->dsp_code_to_load = &card_fw[FW_MONA_361_DSP];
|
||||
else
|
||||
chip->dsp_code_to_load = &card_fw[FW_MONA_301_DSP];
|
||||
|
||||
chip->digital_mode = DIGITAL_MODE_SPDIF_RCA;
|
||||
chip->professional_spdif = FALSE;
|
||||
chip->digital_in_automute = TRUE;
|
||||
|
||||
if ((err = load_firmware(chip)) < 0)
|
||||
return err;
|
||||
chip->bad_board = FALSE;
|
||||
|
||||
if ((err = init_line_levels(chip)) < 0)
|
||||
return err;
|
||||
|
||||
err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA);
|
||||
snd_assert(err >= 0, return err);
|
||||
err = set_professional_spdif(chip, TRUE);
|
||||
|
||||
DE_INIT(("init_hw done\n"));
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static u32 detect_input_clocks(const struct echoaudio *chip)
|
||||
{
|
||||
u32 clocks_from_dsp, clock_bits;
|
||||
|
||||
/* Map the DSP clock detect bits to the generic driver clock
|
||||
detect bits */
|
||||
clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
|
||||
|
||||
clock_bits = ECHO_CLOCK_BIT_INTERNAL;
|
||||
|
||||
if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_SPDIF)
|
||||
clock_bits |= ECHO_CLOCK_BIT_SPDIF;
|
||||
|
||||
if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_ADAT)
|
||||
clock_bits |= ECHO_CLOCK_BIT_ADAT;
|
||||
|
||||
if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_WORD)
|
||||
clock_bits |= ECHO_CLOCK_BIT_WORD;
|
||||
|
||||
return clock_bits;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Mona has an ASIC on the PCI card and another ASIC in the external box;
|
||||
both need to be loaded. */
|
||||
static int load_asic(struct echoaudio *chip)
|
||||
{
|
||||
u32 control_reg;
|
||||
int err;
|
||||
const struct firmware *asic;
|
||||
|
||||
if (chip->asic_loaded)
|
||||
return 0;
|
||||
|
||||
mdelay(10);
|
||||
|
||||
if (chip->device_id == DEVICE_ID_56361)
|
||||
asic = &card_fw[FW_MONA_361_1_ASIC48];
|
||||
else
|
||||
asic = &card_fw[FW_MONA_301_1_ASIC48];
|
||||
|
||||
err = load_asic_generic(chip, DSP_FNC_LOAD_MONA_PCI_CARD_ASIC, asic);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
chip->asic_code = asic;
|
||||
mdelay(10);
|
||||
|
||||
/* Do the external one */
|
||||
err = load_asic_generic(chip, DSP_FNC_LOAD_MONA_EXTERNAL_ASIC,
|
||||
&card_fw[FW_MONA_2_ASIC]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
mdelay(10);
|
||||
err = check_asic_status(chip);
|
||||
|
||||
/* Set up the control register if the load succeeded -
|
||||
48 kHz, internal clock, S/PDIF RCA mode */
|
||||
if (!err) {
|
||||
control_reg = GML_CONVERTER_ENABLE | GML_48KHZ;
|
||||
err = write_control_reg(chip, control_reg, TRUE);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Depending on what digital mode you want, Mona needs different ASICs
|
||||
loaded. This function checks the ASIC needed for the new mode and sees
|
||||
if it matches the one already loaded. */
|
||||
static int switch_asic(struct echoaudio *chip, char double_speed)
|
||||
{
|
||||
const struct firmware *asic;
|
||||
int err;
|
||||
|
||||
/* Check the clock detect bits to see if this is
|
||||
a single-speed clock or a double-speed clock; load
|
||||
a new ASIC if necessary. */
|
||||
if (chip->device_id == DEVICE_ID_56361) {
|
||||
if (double_speed)
|
||||
asic = &card_fw[FW_MONA_361_1_ASIC96];
|
||||
else
|
||||
asic = &card_fw[FW_MONA_361_1_ASIC48];
|
||||
} else {
|
||||
if (double_speed)
|
||||
asic = &card_fw[FW_MONA_301_1_ASIC96];
|
||||
else
|
||||
asic = &card_fw[FW_MONA_301_1_ASIC48];
|
||||
}
|
||||
|
||||
if (asic != chip->asic_code) {
|
||||
/* Load the desired ASIC */
|
||||
err = load_asic_generic(chip, DSP_FNC_LOAD_MONA_PCI_CARD_ASIC,
|
||||
asic);
|
||||
if (err < 0)
|
||||
return err;
|
||||
chip->asic_code = asic;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int set_sample_rate(struct echoaudio *chip, u32 rate)
|
||||
{
|
||||
u32 control_reg, clock;
|
||||
const struct firmware *asic;
|
||||
char force_write;
|
||||
|
||||
/* Only set the clock for internal mode. */
|
||||
if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
|
||||
DE_ACT(("set_sample_rate: Cannot set sample rate - "
|
||||
"clock not set to CLK_CLOCKININTERNAL\n"));
|
||||
/* Save the rate anyhow */
|
||||
chip->comm_page->sample_rate = cpu_to_le32(rate);
|
||||
chip->sample_rate = rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Now, check to see if the required ASIC is loaded */
|
||||
if (rate >= 88200) {
|
||||
if (chip->digital_mode == DIGITAL_MODE_ADAT)
|
||||
return -EINVAL;
|
||||
if (chip->device_id == DEVICE_ID_56361)
|
||||
asic = &card_fw[FW_MONA_361_1_ASIC96];
|
||||
else
|
||||
asic = &card_fw[FW_MONA_301_1_ASIC96];
|
||||
} else {
|
||||
if (chip->device_id == DEVICE_ID_56361)
|
||||
asic = &card_fw[FW_MONA_361_1_ASIC48];
|
||||
else
|
||||
asic = &card_fw[FW_MONA_301_1_ASIC48];
|
||||
}
|
||||
|
||||
force_write = 0;
|
||||
if (asic != chip->asic_code) {
|
||||
int err;
|
||||
/* Load the desired ASIC (load_asic_generic() can sleep) */
|
||||
spin_unlock_irq(&chip->lock);
|
||||
err = load_asic_generic(chip, DSP_FNC_LOAD_MONA_PCI_CARD_ASIC,
|
||||
asic);
|
||||
spin_lock_irq(&chip->lock);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
chip->asic_code = asic;
|
||||
force_write = 1;
|
||||
}
|
||||
|
||||
/* Compute the new control register value */
|
||||
clock = 0;
|
||||
control_reg = le32_to_cpu(chip->comm_page->control_register);
|
||||
control_reg &= GML_CLOCK_CLEAR_MASK;
|
||||
control_reg &= GML_SPDIF_RATE_CLEAR_MASK;
|
||||
|
||||
switch (rate) {
|
||||
case 96000:
|
||||
clock = GML_96KHZ;
|
||||
break;
|
||||
case 88200:
|
||||
clock = GML_88KHZ;
|
||||
break;
|
||||
case 48000:
|
||||
clock = GML_48KHZ | GML_SPDIF_SAMPLE_RATE1;
|
||||
break;
|
||||
case 44100:
|
||||
clock = GML_44KHZ;
|
||||
/* Professional mode */
|
||||
if (control_reg & GML_SPDIF_PRO_MODE)
|
||||
clock |= GML_SPDIF_SAMPLE_RATE0;
|
||||
break;
|
||||
case 32000:
|
||||
clock = GML_32KHZ | GML_SPDIF_SAMPLE_RATE0 |
|
||||
GML_SPDIF_SAMPLE_RATE1;
|
||||
break;
|
||||
case 22050:
|
||||
clock = GML_22KHZ;
|
||||
break;
|
||||
case 16000:
|
||||
clock = GML_16KHZ;
|
||||
break;
|
||||
case 11025:
|
||||
clock = GML_11KHZ;
|
||||
break;
|
||||
case 8000:
|
||||
clock = GML_8KHZ;
|
||||
break;
|
||||
default:
|
||||
DE_ACT(("set_sample_rate: %d invalid!\n", rate));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
control_reg |= clock;
|
||||
|
||||
chip->comm_page->sample_rate = cpu_to_le32(rate); /* ignored by the DSP */
|
||||
chip->sample_rate = rate;
|
||||
DE_ACT(("set_sample_rate: %d clock %d\n", rate, clock));
|
||||
|
||||
return write_control_reg(chip, control_reg, force_write);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int set_input_clock(struct echoaudio *chip, u16 clock)
|
||||
{
|
||||
u32 control_reg, clocks_from_dsp;
|
||||
int err;
|
||||
|
||||
DE_ACT(("set_input_clock:\n"));
|
||||
|
||||
/* Prevent two simultaneous calls to switch_asic() */
|
||||
if (atomic_read(&chip->opencount))
|
||||
return -EAGAIN;
|
||||
|
||||
/* Mask off the clock select bits */
|
||||
control_reg = le32_to_cpu(chip->comm_page->control_register) &
|
||||
GML_CLOCK_CLEAR_MASK;
|
||||
clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
|
||||
|
||||
switch (clock) {
|
||||
case ECHO_CLOCK_INTERNAL:
|
||||
DE_ACT(("Set Mona clock to INTERNAL\n"));
|
||||
chip->input_clock = ECHO_CLOCK_INTERNAL;
|
||||
return set_sample_rate(chip, chip->sample_rate);
|
||||
case ECHO_CLOCK_SPDIF:
|
||||
if (chip->digital_mode == DIGITAL_MODE_ADAT)
|
||||
return -EAGAIN;
|
||||
spin_unlock_irq(&chip->lock);
|
||||
err = switch_asic(chip, clocks_from_dsp &
|
||||
GML_CLOCK_DETECT_BIT_SPDIF96);
|
||||
spin_lock_irq(&chip->lock);
|
||||
if (err < 0)
|
||||
return err;
|
||||
DE_ACT(("Set Mona clock to SPDIF\n"));
|
||||
control_reg |= GML_SPDIF_CLOCK;
|
||||
if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_SPDIF96)
|
||||
control_reg |= GML_DOUBLE_SPEED_MODE;
|
||||
else
|
||||
control_reg &= ~GML_DOUBLE_SPEED_MODE;
|
||||
break;
|
||||
case ECHO_CLOCK_WORD:
|
||||
DE_ACT(("Set Mona clock to WORD\n"));
|
||||
spin_unlock_irq(&chip->lock);
|
||||
err = switch_asic(chip, clocks_from_dsp &
|
||||
GML_CLOCK_DETECT_BIT_WORD96);
|
||||
spin_lock_irq(&chip->lock);
|
||||
if (err < 0)
|
||||
return err;
|
||||
control_reg |= GML_WORD_CLOCK;
|
||||
if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_WORD96)
|
||||
control_reg |= GML_DOUBLE_SPEED_MODE;
|
||||
else
|
||||
control_reg &= ~GML_DOUBLE_SPEED_MODE;
|
||||
break;
|
||||
case ECHO_CLOCK_ADAT:
|
||||
DE_ACT(("Set Mona clock to ADAT\n"));
|
||||
if (chip->digital_mode != DIGITAL_MODE_ADAT)
|
||||
return -EAGAIN;
|
||||
control_reg |= GML_ADAT_CLOCK;
|
||||
control_reg &= ~GML_DOUBLE_SPEED_MODE;
|
||||
break;
|
||||
default:
|
||||
DE_ACT(("Input clock 0x%x not supported for Mona\n", clock));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chip->input_clock = clock;
|
||||
return write_control_reg(chip, control_reg, TRUE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
|
||||
{
|
||||
u32 control_reg;
|
||||
int err, incompatible_clock;
|
||||
|
||||
/* Set clock to "internal" if it's not compatible with the new mode */
|
||||
incompatible_clock = FALSE;
|
||||
switch (mode) {
|
||||
case DIGITAL_MODE_SPDIF_OPTICAL:
|
||||
case DIGITAL_MODE_SPDIF_RCA:
|
||||
if (chip->input_clock == ECHO_CLOCK_ADAT)
|
||||
incompatible_clock = TRUE;
|
||||
break;
|
||||
case DIGITAL_MODE_ADAT:
|
||||
if (chip->input_clock == ECHO_CLOCK_SPDIF)
|
||||
incompatible_clock = TRUE;
|
||||
break;
|
||||
default:
|
||||
DE_ACT(("Digital mode not supported: %d\n", mode));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irq(&chip->lock);
|
||||
|
||||
if (incompatible_clock) { /* Switch to 48KHz, internal */
|
||||
chip->sample_rate = 48000;
|
||||
set_input_clock(chip, ECHO_CLOCK_INTERNAL);
|
||||
}
|
||||
|
||||
/* Clear the current digital mode */
|
||||
control_reg = le32_to_cpu(chip->comm_page->control_register);
|
||||
control_reg &= GML_DIGITAL_MODE_CLEAR_MASK;
|
||||
|
||||
/* Tweak the control reg */
|
||||
switch (mode) {
|
||||
case DIGITAL_MODE_SPDIF_OPTICAL:
|
||||
control_reg |= GML_SPDIF_OPTICAL_MODE;
|
||||
break;
|
||||
case DIGITAL_MODE_SPDIF_RCA:
|
||||
/* GML_SPDIF_OPTICAL_MODE bit cleared */
|
||||
break;
|
||||
case DIGITAL_MODE_ADAT:
|
||||
/* If the current ASIC is the 96KHz ASIC, switch the ASIC
|
||||
and set to 48 KHz */
|
||||
if (chip->asic_code == &card_fw[FW_MONA_361_1_ASIC96] ||
|
||||
chip->asic_code == &card_fw[FW_MONA_301_1_ASIC96]) {
|
||||
set_sample_rate(chip, 48000);
|
||||
}
|
||||
control_reg |= GML_ADAT_MODE;
|
||||
control_reg &= ~GML_DOUBLE_SPEED_MODE;
|
||||
break;
|
||||
}
|
||||
|
||||
err = write_control_reg(chip, control_reg, FALSE);
|
||||
spin_unlock_irq(&chip->lock);
|
||||
if (err < 0)
|
||||
return err;
|
||||
chip->digital_mode = mode;
|
||||
|
||||
DE_ACT(("set_digital_mode to %d\n", mode));
|
||||
return incompatible_clock;
|
||||
}
|
Загрузка…
Ссылка в новой задаче