Merge master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa
* master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa: [ALSA] echoaudio - Remove kfree_nocheck() [ALSA] echoaudio - Fix Makefile [ALSA] Add Intel D965 board support [ALSA] Fix/add support of Realtek ALC883 / ALC888 and ALC861 codecs [ALSA] Fix a typo in echoaudio/midi.c [ALSA] snd-aoa: enable dual-edge in GPIOs [ALSA] snd-aoa: support iMac G5 iSight [ALSA] snd-aoa: not experimental [ALSA] Add echoaudio sound drivers [ALSA] ak4xxx-adda - Code clean-up [ALSA] Remove CONFIG_EXPERIMENTAL from intel8x0m driver [ALSA] Stereo controls for M-Audio Revolution cards [ALSA] Fix misuse of __list_add() in seq_ports.c [ALSA] hda-codec - Add model entry for Samsung X60 Chane [ALSA] make CONFIG_SND_DYNAMIC_MINORS non-experimental [ALSA] Fix wrong dependencies of snd-aoa driver [ALSA] fix build failure due to snd-aoa [ALSA] AD1888 mixer controls for DC mode [ALSA] Suppress irq handler mismatch messages in ALSA ISA drivers [ALSA] usb-audio support for Turtle Beach Roadie
This commit is contained in:
commit
0950c358ee
53 changed files with 11393 additions and 210 deletions
|
@ -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
|
||||
---------------------
|
||||
|
||||
|
@ -760,12 +800,18 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
|||
basic fixed pin assignment w/o SPDIF
|
||||
auto auto-config reading BIOS (default)
|
||||
|
||||
ALC882/883/885
|
||||
ALC882/885
|
||||
3stack-dig 3-jack with SPDIF I/O
|
||||
6stck-dig 6-jack digital with SPDIF I/O
|
||||
auto auto-config reading BIOS (default)
|
||||
|
||||
ALC861
|
||||
ALC883/888
|
||||
3stack-dig 3-jack with SPDIF I/O
|
||||
6stack-dig 6-jack digital with SPDIF I/O
|
||||
6stack-dig-demo 6-stack digital for Intel demo board
|
||||
auto auto-config reading BIOS (default)
|
||||
|
||||
ALC861/660
|
||||
3stack 3-jack
|
||||
3stack-dig 3-jack with SPDIF I/O
|
||||
6stack-dig 6-jack with SPDIF I/O
|
||||
|
@ -937,6 +983,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 +1106,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 +1142,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 +1182,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
|
||||
-----------------
|
||||
|
||||
|
|
|
@ -265,6 +265,7 @@
|
|||
|
||||
/* specific - Analog Devices */
|
||||
#define AC97_AD_TEST 0x5a /* test register */
|
||||
#define AC97_AD_TEST2 0x5c /* undocumented test register 2 */
|
||||
#define AC97_AD_CODEC_CFG 0x70 /* codec configuration */
|
||||
#define AC97_AD_JACK_SPDIF 0x72 /* Jack Sense & S/PDIF */
|
||||
#define AC97_AD_SERIAL_CFG 0x74 /* Serial Configuration */
|
||||
|
|
|
@ -32,8 +32,8 @@ struct snd_akm4xxx;
|
|||
struct snd_ak4xxx_ops {
|
||||
void (*lock)(struct snd_akm4xxx *ak, int chip);
|
||||
void (*unlock)(struct snd_akm4xxx *ak, int chip);
|
||||
void (*write)(struct snd_akm4xxx *ak, int chip, unsigned char reg, unsigned char val);
|
||||
// unsigned char (*read)(struct snd_akm4xxx *ak, int chip, unsigned char reg);
|
||||
void (*write)(struct snd_akm4xxx *ak, int chip, unsigned char reg,
|
||||
unsigned char val);
|
||||
void (*set_rate_val)(struct snd_akm4xxx *ak, unsigned int rate);
|
||||
};
|
||||
|
||||
|
@ -41,29 +41,40 @@ struct snd_ak4xxx_ops {
|
|||
|
||||
struct snd_akm4xxx {
|
||||
struct snd_card *card;
|
||||
unsigned int num_adcs; /* AK4524 or AK4528 ADCs */
|
||||
unsigned int num_dacs; /* AK4524 or AK4528 DACs */
|
||||
unsigned char images[AK4XXX_IMAGE_SIZE]; /* saved register image */
|
||||
unsigned char ipga_gain[AK4XXX_MAX_CHIPS][2]; /* saved register image for IPGA (AK4528) */
|
||||
unsigned int num_adcs; /* AK4524 or AK4528 ADCs */
|
||||
unsigned int num_dacs; /* AK4524 or AK4528 DACs */
|
||||
unsigned char images[AK4XXX_IMAGE_SIZE]; /* saved register image */
|
||||
unsigned char ipga_gain[AK4XXX_MAX_CHIPS][2]; /* saved register image
|
||||
* for IPGA (AK4528)
|
||||
*/
|
||||
unsigned long private_value[AK4XXX_MAX_CHIPS]; /* helper for driver */
|
||||
void *private_data[AK4XXX_MAX_CHIPS]; /* helper for driver */
|
||||
/* template should fill the following fields */
|
||||
unsigned int idx_offset; /* control index offset */
|
||||
unsigned int idx_offset; /* control index offset */
|
||||
enum {
|
||||
SND_AK4524, SND_AK4528, SND_AK4529,
|
||||
SND_AK4355, SND_AK4358, SND_AK4381
|
||||
} type;
|
||||
unsigned int *num_stereo; /* array of combined counts
|
||||
* for the mixer
|
||||
*/
|
||||
char **channel_names; /* array of mixer channel names */
|
||||
struct snd_ak4xxx_ops ops;
|
||||
};
|
||||
|
||||
void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg, unsigned char val);
|
||||
void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg,
|
||||
unsigned char val);
|
||||
void snd_akm4xxx_reset(struct snd_akm4xxx *ak, int state);
|
||||
void snd_akm4xxx_init(struct snd_akm4xxx *ak);
|
||||
int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak);
|
||||
|
||||
#define snd_akm4xxx_get(ak,chip,reg) (ak)->images[(chip) * 16 + (reg)]
|
||||
#define snd_akm4xxx_set(ak,chip,reg,val) ((ak)->images[(chip) * 16 + (reg)] = (val))
|
||||
#define snd_akm4xxx_get_ipga(ak,chip,reg) (ak)->ipga_gain[chip][(reg)-4]
|
||||
#define snd_akm4xxx_set_ipga(ak,chip,reg,val) ((ak)->ipga_gain[chip][(reg)-4] = (val))
|
||||
#define snd_akm4xxx_get(ak,chip,reg) \
|
||||
(ak)->images[(chip) * 16 + (reg)]
|
||||
#define snd_akm4xxx_set(ak,chip,reg,val) \
|
||||
((ak)->images[(chip) * 16 + (reg)] = (val))
|
||||
#define snd_akm4xxx_get_ipga(ak,chip,reg) \
|
||||
(ak)->ipga_gain[chip][(reg)-4]
|
||||
#define snd_akm4xxx_set_ipga(ak,chip,reg,val) \
|
||||
((ak)->ipga_gain[chip][(reg)-4] = (val))
|
||||
|
||||
#endif /* __SOUND_AK4XXX_ADDA_H */
|
||||
|
|
|
@ -62,7 +62,8 @@ static int snd_legacy_find_free_irq(int *irq_table)
|
|||
{
|
||||
while (*irq_table != -1) {
|
||||
if (!request_irq(*irq_table, snd_legacy_empty_irq_handler,
|
||||
SA_INTERRUPT, "ALSA Test IRQ", (void *) irq_table)) {
|
||||
SA_INTERRUPT | SA_PROBEIRQ, "ALSA Test IRQ",
|
||||
(void *) irq_table)) {
|
||||
free_irq(*irq_table, (void *) irq_table);
|
||||
return *irq_table;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
obj-$(CONFIG_SOUND) += soundcore.o
|
||||
obj-$(CONFIG_SOUND_PRIME) += oss/
|
||||
obj-$(CONFIG_DMASOUND) += oss/
|
||||
obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ aoa/
|
||||
obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/
|
||||
obj-$(CONFIG_SND_AOA) += aoa/
|
||||
|
||||
ifeq ($(CONFIG_SND),y)
|
||||
obj-y += last.o
|
||||
|
|
|
@ -3,7 +3,8 @@ menu "Apple Onboard Audio driver"
|
|||
|
||||
config SND_AOA
|
||||
tristate "Apple Onboard Audio driver"
|
||||
depends on SOUND && SND_PCM
|
||||
depends on SND
|
||||
select SND_PCM
|
||||
---help---
|
||||
This option enables the new driver for the various
|
||||
Apple Onboard Audio components.
|
||||
|
|
|
@ -207,6 +207,17 @@ static void ftr_handle_notify(void *data)
|
|||
mutex_unlock(¬if->mutex);
|
||||
}
|
||||
|
||||
static void gpio_enable_dual_edge(int gpio)
|
||||
{
|
||||
int v;
|
||||
|
||||
if (gpio == -1)
|
||||
return;
|
||||
v = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio, 0);
|
||||
v |= 0x80; /* enable dual edge */
|
||||
pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, gpio, v);
|
||||
}
|
||||
|
||||
static void ftr_gpio_init(struct gpio_runtime *rt)
|
||||
{
|
||||
get_gpio("headphone-mute", NULL,
|
||||
|
@ -234,6 +245,10 @@ static void ftr_gpio_init(struct gpio_runtime *rt)
|
|||
&linein_detect_gpio,
|
||||
&linein_detect_gpio_activestate);
|
||||
|
||||
gpio_enable_dual_edge(headphone_detect_gpio);
|
||||
gpio_enable_dual_edge(lineout_detect_gpio);
|
||||
gpio_enable_dual_edge(linein_detect_gpio);
|
||||
|
||||
get_irq(headphone_detect_node, &headphone_detect_irq);
|
||||
get_irq(lineout_detect_node, &lineout_detect_irq);
|
||||
get_irq(linein_detect_node, &linein_detect_irq);
|
||||
|
|
|
@ -94,6 +94,7 @@ MODULE_ALIAS("sound-layout-82");
|
|||
MODULE_ALIAS("sound-layout-84");
|
||||
MODULE_ALIAS("sound-layout-86");
|
||||
MODULE_ALIAS("sound-layout-92");
|
||||
MODULE_ALIAS("sound-layout-96");
|
||||
|
||||
/* onyx with all but microphone connected */
|
||||
static struct codec_connection onyx_connections_nomic[] = {
|
||||
|
@ -381,6 +382,13 @@ static struct layout layouts[] = {
|
|||
.connections = toonie_connections,
|
||||
},
|
||||
},
|
||||
{
|
||||
.layout_id = 96,
|
||||
.codecs[0] = {
|
||||
.name = "onyx",
|
||||
.connections = onyx_connections_noheadphones,
|
||||
},
|
||||
},
|
||||
/* unknown, untested, but this comes from Apple */
|
||||
{ .layout_id = 41,
|
||||
.codecs[0] = {
|
||||
|
@ -479,12 +487,6 @@ static struct layout layouts[] = {
|
|||
.connections = onyx_connections_noheadphones,
|
||||
},
|
||||
},
|
||||
{ .layout_id = 96,
|
||||
.codecs[0] = {
|
||||
.name = "onyx",
|
||||
.connections = onyx_connections_noheadphones,
|
||||
},
|
||||
},
|
||||
{ .layout_id = 98,
|
||||
.codecs[0] = {
|
||||
.name = "toonie",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
config SND_AOA_SOUNDBUS
|
||||
tristate "Apple Soundbus support"
|
||||
depends on SOUND && SND_PCM && EXPERIMENTAL
|
||||
depends on SOUND
|
||||
select SND_PCM
|
||||
---help---
|
||||
This option enables the generic driver for the soundbus
|
||||
support on Apple machines.
|
||||
|
|
|
@ -122,8 +122,8 @@ config SND_SEQ_RTCTIMER_DEFAULT
|
|||
If in doubt, say Y.
|
||||
|
||||
config SND_DYNAMIC_MINORS
|
||||
bool "Dynamic device file minor numbers (EXPERIMENTAL)"
|
||||
depends on SND && EXPERIMENTAL
|
||||
bool "Dynamic device file minor numbers"
|
||||
depends on SND
|
||||
help
|
||||
If you say Y here, the minor numbers of ALSA device files in
|
||||
/dev/snd/ are allocated dynamically. This allows you to have
|
||||
|
|
|
@ -322,10 +322,8 @@ int snd_seq_delete_all_ports(struct snd_seq_client *client)
|
|||
mutex_lock(&client->ports_mutex);
|
||||
write_lock_irqsave(&client->ports_lock, flags);
|
||||
if (! list_empty(&client->ports_list_head)) {
|
||||
__list_add(&deleted_list,
|
||||
client->ports_list_head.prev,
|
||||
client->ports_list_head.next);
|
||||
INIT_LIST_HEAD(&client->ports_list_head);
|
||||
list_add(&deleted_list, &client->ports_list_head);
|
||||
list_del_init(&client->ports_list_head);
|
||||
} else {
|
||||
INIT_LIST_HEAD(&deleted_list);
|
||||
}
|
||||
|
|
|
@ -34,7 +34,8 @@ MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Takashi Iwai <tiwai@suse.de>");
|
|||
MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx AD/DA converters");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg, unsigned char val)
|
||||
void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg,
|
||||
unsigned char val)
|
||||
{
|
||||
ak->ops.lock(ak, chip);
|
||||
ak->ops.write(ak, chip, reg, val);
|
||||
|
@ -52,6 +53,67 @@ void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg, unsi
|
|||
ak->ops.unlock(ak, chip);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_akm4xxx_write);
|
||||
|
||||
/* reset procedure for AK4524 and AK4528 */
|
||||
static void ak4524_reset(struct snd_akm4xxx *ak, int state)
|
||||
{
|
||||
unsigned int chip;
|
||||
unsigned char reg, maxreg;
|
||||
|
||||
if (ak->type == SND_AK4528)
|
||||
maxreg = 0x06;
|
||||
else
|
||||
maxreg = 0x08;
|
||||
for (chip = 0; chip < ak->num_dacs/2; chip++) {
|
||||
snd_akm4xxx_write(ak, chip, 0x01, state ? 0x00 : 0x03);
|
||||
if (state)
|
||||
continue;
|
||||
/* DAC volumes */
|
||||
for (reg = 0x04; reg < maxreg; reg++)
|
||||
snd_akm4xxx_write(ak, chip, reg,
|
||||
snd_akm4xxx_get(ak, chip, reg));
|
||||
if (ak->type == SND_AK4528)
|
||||
continue;
|
||||
/* IPGA */
|
||||
for (reg = 0x04; reg < 0x06; reg++)
|
||||
snd_akm4xxx_write(ak, chip, reg,
|
||||
snd_akm4xxx_get_ipga(ak, chip, reg));
|
||||
}
|
||||
}
|
||||
|
||||
/* reset procedure for AK4355 and AK4358 */
|
||||
static void ak4355_reset(struct snd_akm4xxx *ak, int state)
|
||||
{
|
||||
unsigned char reg;
|
||||
|
||||
if (state) {
|
||||
snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */
|
||||
return;
|
||||
}
|
||||
for (reg = 0x00; reg < 0x0b; reg++)
|
||||
if (reg != 0x01)
|
||||
snd_akm4xxx_write(ak, 0, reg,
|
||||
snd_akm4xxx_get(ak, 0, reg));
|
||||
snd_akm4xxx_write(ak, 0, 0x01, 0x01); /* un-reset, unmute */
|
||||
}
|
||||
|
||||
/* reset procedure for AK4381 */
|
||||
static void ak4381_reset(struct snd_akm4xxx *ak, int state)
|
||||
{
|
||||
unsigned int chip;
|
||||
unsigned char reg;
|
||||
|
||||
for (chip = 0; chip < ak->num_dacs/2; chip++) {
|
||||
snd_akm4xxx_write(ak, chip, 0x00, state ? 0x0c : 0x0f);
|
||||
if (state)
|
||||
continue;
|
||||
for (reg = 0x01; reg < 0x05; reg++)
|
||||
snd_akm4xxx_write(ak, chip, reg,
|
||||
snd_akm4xxx_get(ak, chip, reg));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* reset the AKM codecs
|
||||
* @state: 1 = reset codec, 0 = restore the registers
|
||||
|
@ -60,52 +122,26 @@ void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg, unsi
|
|||
*/
|
||||
void snd_akm4xxx_reset(struct snd_akm4xxx *ak, int state)
|
||||
{
|
||||
unsigned int chip;
|
||||
unsigned char reg;
|
||||
|
||||
switch (ak->type) {
|
||||
case SND_AK4524:
|
||||
case SND_AK4528:
|
||||
for (chip = 0; chip < ak->num_dacs/2; chip++) {
|
||||
snd_akm4xxx_write(ak, chip, 0x01, state ? 0x00 : 0x03);
|
||||
if (state)
|
||||
continue;
|
||||
/* DAC volumes */
|
||||
for (reg = 0x04; reg < (ak->type == SND_AK4528 ? 0x06 : 0x08); reg++)
|
||||
snd_akm4xxx_write(ak, chip, reg, snd_akm4xxx_get(ak, chip, reg));
|
||||
if (ak->type == SND_AK4528)
|
||||
continue;
|
||||
/* IPGA */
|
||||
for (reg = 0x04; reg < 0x06; reg++)
|
||||
snd_akm4xxx_write(ak, chip, reg, snd_akm4xxx_get_ipga(ak, chip, reg));
|
||||
}
|
||||
ak4524_reset(ak, state);
|
||||
break;
|
||||
case SND_AK4529:
|
||||
/* FIXME: needed for ak4529? */
|
||||
break;
|
||||
case SND_AK4355:
|
||||
case SND_AK4358:
|
||||
if (state) {
|
||||
snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */
|
||||
return;
|
||||
}
|
||||
for (reg = 0x00; reg < 0x0b; reg++)
|
||||
if (reg != 0x01)
|
||||
snd_akm4xxx_write(ak, 0, reg, snd_akm4xxx_get(ak, 0, reg));
|
||||
snd_akm4xxx_write(ak, 0, 0x01, 0x01); /* un-reset, unmute */
|
||||
ak4355_reset(ak, state);
|
||||
break;
|
||||
case SND_AK4381:
|
||||
for (chip = 0; chip < ak->num_dacs/2; chip++) {
|
||||
snd_akm4xxx_write(ak, chip, 0x00, state ? 0x0c : 0x0f);
|
||||
if (state)
|
||||
continue;
|
||||
for (reg = 0x01; reg < 0x05; reg++)
|
||||
snd_akm4xxx_write(ak, chip, reg, snd_akm4xxx_get(ak, chip, reg));
|
||||
}
|
||||
ak4381_reset(ak, state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_akm4xxx_reset);
|
||||
|
||||
/*
|
||||
* initialize all the ak4xxx chips
|
||||
*/
|
||||
|
@ -153,7 +189,8 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
|
|||
};
|
||||
static unsigned char inits_ak4355[] = {
|
||||
0x01, 0x02, /* 1: reset and soft-mute */
|
||||
0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, disable DZF, sharp roll-off, RSTN#=0 */
|
||||
0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
|
||||
* disable DZF, sharp roll-off, RSTN#=0 */
|
||||
0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */
|
||||
// 0x02, 0x2e, /* quad speed */
|
||||
0x03, 0x01, /* 3: de-emphasis off */
|
||||
|
@ -169,7 +206,8 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
|
|||
};
|
||||
static unsigned char inits_ak4358[] = {
|
||||
0x01, 0x02, /* 1: reset and soft-mute */
|
||||
0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, disable DZF, sharp roll-off, RSTN#=0 */
|
||||
0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
|
||||
* disable DZF, sharp roll-off, RSTN#=0 */
|
||||
0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */
|
||||
// 0x02, 0x2e, /* quad speed */
|
||||
0x03, 0x01, /* 3: de-emphasis off */
|
||||
|
@ -187,7 +225,8 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
|
|||
};
|
||||
static unsigned char inits_ak4381[] = {
|
||||
0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */
|
||||
0x01, 0x02, /* 1: de-emphasis off, normal speed, sharp roll-off, DZF off */
|
||||
0x01, 0x02, /* 1: de-emphasis off, normal speed,
|
||||
* sharp roll-off, DZF off */
|
||||
// 0x01, 0x12, /* quad speed */
|
||||
0x02, 0x00, /* 2: DZF disabled */
|
||||
0x03, 0x00, /* 3: LATT 0 */
|
||||
|
@ -239,12 +278,15 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
|
|||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_akm4xxx_init);
|
||||
|
||||
#define AK_GET_CHIP(val) (((val) >> 8) & 0xff)
|
||||
#define AK_GET_ADDR(val) ((val) & 0xff)
|
||||
#define AK_GET_SHIFT(val) (((val) >> 16) & 0x7f)
|
||||
#define AK_GET_INVERT(val) (((val) >> 23) & 1)
|
||||
#define AK_GET_MASK(val) (((val) >> 24) & 0xff)
|
||||
#define AK_COMPOSE(chip,addr,shift,mask) (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24))
|
||||
#define AK_COMPOSE(chip,addr,shift,mask) \
|
||||
(((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24))
|
||||
#define AK_INVERT (1<<23)
|
||||
|
||||
static int snd_akm4xxx_volume_info(struct snd_kcontrol *kcontrol,
|
||||
|
@ -292,6 +334,64 @@ static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol,
|
|||
return change;
|
||||
}
|
||||
|
||||
static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
unsigned int mask = AK_GET_MASK(kcontrol->private_value);
|
||||
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->count = 2;
|
||||
uinfo->value.integer.min = 0;
|
||||
uinfo->value.integer.max = mask;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_akm4xxx_stereo_volume_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
|
||||
int chip = AK_GET_CHIP(kcontrol->private_value);
|
||||
int addr = AK_GET_ADDR(kcontrol->private_value);
|
||||
int invert = AK_GET_INVERT(kcontrol->private_value);
|
||||
unsigned int mask = AK_GET_MASK(kcontrol->private_value);
|
||||
unsigned char val = snd_akm4xxx_get(ak, chip, addr);
|
||||
|
||||
ucontrol->value.integer.value[0] = invert ? mask - val : val;
|
||||
|
||||
val = snd_akm4xxx_get(ak, chip, addr+1);
|
||||
ucontrol->value.integer.value[1] = invert ? mask - val : val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
|
||||
int chip = AK_GET_CHIP(kcontrol->private_value);
|
||||
int addr = AK_GET_ADDR(kcontrol->private_value);
|
||||
int invert = AK_GET_INVERT(kcontrol->private_value);
|
||||
unsigned int mask = AK_GET_MASK(kcontrol->private_value);
|
||||
unsigned char nval = ucontrol->value.integer.value[0] % (mask+1);
|
||||
int change0, change1;
|
||||
|
||||
if (invert)
|
||||
nval = mask - nval;
|
||||
change0 = snd_akm4xxx_get(ak, chip, addr) != nval;
|
||||
if (change0)
|
||||
snd_akm4xxx_write(ak, chip, addr, nval);
|
||||
|
||||
nval = ucontrol->value.integer.value[1] % (mask+1);
|
||||
if (invert)
|
||||
nval = mask - nval;
|
||||
change1 = snd_akm4xxx_get(ak, chip, addr+1) != nval;
|
||||
if (change1)
|
||||
snd_akm4xxx_write(ak, chip, addr+1, nval);
|
||||
|
||||
|
||||
return change0 || change1;
|
||||
}
|
||||
|
||||
static int snd_akm4xxx_ipga_gain_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
|
@ -308,7 +408,8 @@ static int snd_akm4xxx_ipga_gain_get(struct snd_kcontrol *kcontrol,
|
|||
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
|
||||
int chip = AK_GET_CHIP(kcontrol->private_value);
|
||||
int addr = AK_GET_ADDR(kcontrol->private_value);
|
||||
ucontrol->value.integer.value[0] = snd_akm4xxx_get_ipga(ak, chip, addr) & 0x7f;
|
||||
ucontrol->value.integer.value[0] =
|
||||
snd_akm4xxx_get_ipga(ak, chip, addr) & 0x7f;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -336,7 +437,8 @@ static int snd_akm4xxx_deemphasis_info(struct snd_kcontrol *kcontrol,
|
|||
uinfo->value.enumerated.items = 4;
|
||||
if (uinfo->value.enumerated.item >= 4)
|
||||
uinfo->value.enumerated.item = 3;
|
||||
strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
|
||||
strcpy(uinfo->value.enumerated.name,
|
||||
texts[uinfo->value.enumerated.item]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -347,7 +449,8 @@ static int snd_akm4xxx_deemphasis_get(struct snd_kcontrol *kcontrol,
|
|||
int chip = AK_GET_CHIP(kcontrol->private_value);
|
||||
int addr = AK_GET_ADDR(kcontrol->private_value);
|
||||
int shift = AK_GET_SHIFT(kcontrol->private_value);
|
||||
ucontrol->value.enumerated.item[0] = (snd_akm4xxx_get(ak, chip, addr) >> shift) & 3;
|
||||
ucontrol->value.enumerated.item[0] =
|
||||
(snd_akm4xxx_get(ak, chip, addr) >> shift) & 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -361,7 +464,8 @@ static int snd_akm4xxx_deemphasis_put(struct snd_kcontrol *kcontrol,
|
|||
unsigned char nval = ucontrol->value.enumerated.item[0] & 3;
|
||||
int change;
|
||||
|
||||
nval = (nval << shift) | (snd_akm4xxx_get(ak, chip, addr) & ~(3 << shift));
|
||||
nval = (nval << shift) |
|
||||
(snd_akm4xxx_get(ak, chip, addr) & ~(3 << shift));
|
||||
change = snd_akm4xxx_get(ak, chip, addr) != nval;
|
||||
if (change)
|
||||
snd_akm4xxx_write(ak, chip, addr, nval);
|
||||
|
@ -377,51 +481,86 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
|
|||
unsigned int idx, num_emphs;
|
||||
struct snd_kcontrol *ctl;
|
||||
int err;
|
||||
int mixer_ch = 0;
|
||||
int num_stereo;
|
||||
|
||||
ctl = kmalloc(sizeof(*ctl), GFP_KERNEL);
|
||||
if (! ctl)
|
||||
return -ENOMEM;
|
||||
|
||||
for (idx = 0; idx < ak->num_dacs; ++idx) {
|
||||
for (idx = 0; idx < ak->num_dacs; ) {
|
||||
memset(ctl, 0, sizeof(*ctl));
|
||||
strcpy(ctl->id.name, "DAC Volume");
|
||||
ctl->id.index = idx + ak->idx_offset * 2;
|
||||
if (ak->channel_names == NULL) {
|
||||
strcpy(ctl->id.name, "DAC Volume");
|
||||
num_stereo = 1;
|
||||
ctl->id.index = mixer_ch + ak->idx_offset * 2;
|
||||
} else {
|
||||
strcpy(ctl->id.name, ak->channel_names[mixer_ch]);
|
||||
num_stereo = ak->num_stereo[mixer_ch];
|
||||
ctl->id.index = 0;
|
||||
}
|
||||
ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
||||
ctl->count = 1;
|
||||
ctl->info = snd_akm4xxx_volume_info;
|
||||
ctl->get = snd_akm4xxx_volume_get;
|
||||
ctl->put = snd_akm4xxx_volume_put;
|
||||
if (num_stereo == 2) {
|
||||
ctl->info = snd_akm4xxx_stereo_volume_info;
|
||||
ctl->get = snd_akm4xxx_stereo_volume_get;
|
||||
ctl->put = snd_akm4xxx_stereo_volume_put;
|
||||
} else {
|
||||
ctl->info = snd_akm4xxx_volume_info;
|
||||
ctl->get = snd_akm4xxx_volume_get;
|
||||
ctl->put = snd_akm4xxx_volume_put;
|
||||
}
|
||||
switch (ak->type) {
|
||||
case SND_AK4524:
|
||||
ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127); /* register 6 & 7 */
|
||||
/* register 6 & 7 */
|
||||
ctl->private_value =
|
||||
AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127);
|
||||
break;
|
||||
case SND_AK4528:
|
||||
ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); /* register 4 & 5 */
|
||||
/* register 4 & 5 */
|
||||
ctl->private_value =
|
||||
AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127);
|
||||
break;
|
||||
case SND_AK4529: {
|
||||
int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb; /* registers 2-7 and b,c */
|
||||
ctl->private_value = AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
|
||||
/* registers 2-7 and b,c */
|
||||
int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb;
|
||||
ctl->private_value =
|
||||
AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
|
||||
break;
|
||||
}
|
||||
case SND_AK4355:
|
||||
ctl->private_value = AK_COMPOSE(0, idx + 4, 0, 255); /* register 4-9, chip #0 only */
|
||||
/* register 4-9, chip #0 only */
|
||||
ctl->private_value = AK_COMPOSE(0, idx + 4, 0, 255);
|
||||
break;
|
||||
case SND_AK4358:
|
||||
if (idx >= 6)
|
||||
ctl->private_value = AK_COMPOSE(0, idx + 5, 0, 255); /* register 4-9, chip #0 only */
|
||||
/* register 4-9, chip #0 only */
|
||||
ctl->private_value =
|
||||
AK_COMPOSE(0, idx + 5, 0, 255);
|
||||
else
|
||||
ctl->private_value = AK_COMPOSE(0, idx + 4, 0, 255); /* register 4-9, chip #0 only */
|
||||
/* register 4-9, chip #0 only */
|
||||
ctl->private_value =
|
||||
AK_COMPOSE(0, idx + 4, 0, 255);
|
||||
break;
|
||||
case SND_AK4381:
|
||||
ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255); /* register 3 & 4 */
|
||||
/* register 3 & 4 */
|
||||
ctl->private_value =
|
||||
AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255);
|
||||
break;
|
||||
default:
|
||||
err = -EINVAL;
|
||||
goto __error;
|
||||
}
|
||||
|
||||
ctl->private_data = ak;
|
||||
if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0)
|
||||
err = snd_ctl_add(ak->card,
|
||||
snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|
|
||||
SNDRV_CTL_ELEM_ACCESS_WRITE));
|
||||
if (err < 0)
|
||||
goto __error;
|
||||
|
||||
idx += num_stereo;
|
||||
mixer_ch++;
|
||||
}
|
||||
for (idx = 0; idx < ak->num_adcs && ak->type == SND_AK4524; ++idx) {
|
||||
memset(ctl, 0, sizeof(*ctl));
|
||||
|
@ -432,9 +571,14 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
|
|||
ctl->info = snd_akm4xxx_volume_info;
|
||||
ctl->get = snd_akm4xxx_volume_get;
|
||||
ctl->put = snd_akm4xxx_volume_put;
|
||||
ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); /* register 4 & 5 */
|
||||
/* register 4 & 5 */
|
||||
ctl->private_value =
|
||||
AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127);
|
||||
ctl->private_data = ak;
|
||||
if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0)
|
||||
err = snd_ctl_add(ak->card,
|
||||
snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|
|
||||
SNDRV_CTL_ELEM_ACCESS_WRITE));
|
||||
if (err < 0)
|
||||
goto __error;
|
||||
|
||||
memset(ctl, 0, sizeof(*ctl));
|
||||
|
@ -445,9 +589,13 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
|
|||
ctl->info = snd_akm4xxx_ipga_gain_info;
|
||||
ctl->get = snd_akm4xxx_ipga_gain_get;
|
||||
ctl->put = snd_akm4xxx_ipga_gain_put;
|
||||
ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 0); /* register 4 & 5 */
|
||||
/* register 4 & 5 */
|
||||
ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 0);
|
||||
ctl->private_data = ak;
|
||||
if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0)
|
||||
err = snd_ctl_add(ak->card,
|
||||
snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|
|
||||
SNDRV_CTL_ELEM_ACCESS_WRITE));
|
||||
if (err < 0)
|
||||
goto __error;
|
||||
}
|
||||
if (ak->type == SND_AK4355 || ak->type == SND_AK4358)
|
||||
|
@ -466,11 +614,13 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
|
|||
switch (ak->type) {
|
||||
case SND_AK4524:
|
||||
case SND_AK4528:
|
||||
ctl->private_value = AK_COMPOSE(idx, 3, 0, 0); /* register 3 */
|
||||
/* register 3 */
|
||||
ctl->private_value = AK_COMPOSE(idx, 3, 0, 0);
|
||||
break;
|
||||
case SND_AK4529: {
|
||||
int shift = idx == 3 ? 6 : (2 - idx) * 2;
|
||||
ctl->private_value = AK_COMPOSE(0, 8, shift, 0); /* register 8 with shift */
|
||||
/* register 8 with shift */
|
||||
ctl->private_value = AK_COMPOSE(0, 8, shift, 0);
|
||||
break;
|
||||
}
|
||||
case SND_AK4355:
|
||||
|
@ -482,7 +632,10 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
|
|||
break;
|
||||
}
|
||||
ctl->private_data = ak;
|
||||
if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0)
|
||||
err = snd_ctl_add(ak->card,
|
||||
snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|
|
||||
SNDRV_CTL_ELEM_ACCESS_WRITE));
|
||||
if (err < 0)
|
||||
goto __error;
|
||||
}
|
||||
err = 0;
|
||||
|
@ -492,6 +645,8 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
|
|||
return err;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_akm4xxx_build_controls);
|
||||
|
||||
static int __init alsa_akm4xxx_module_init(void)
|
||||
{
|
||||
return 0;
|
||||
|
@ -503,8 +658,3 @@ static void __exit alsa_akm4xxx_module_exit(void)
|
|||
|
||||
module_init(alsa_akm4xxx_module_init)
|
||||
module_exit(alsa_akm4xxx_module_exit)
|
||||
|
||||
EXPORT_SYMBOL(snd_akm4xxx_write);
|
||||
EXPORT_SYMBOL(snd_akm4xxx_reset);
|
||||
EXPORT_SYMBOL(snd_akm4xxx_init);
|
||||
EXPORT_SYMBOL(snd_akm4xxx_build_controls);
|
||||
|
|
|
@ -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
|
||||
|
@ -420,8 +557,8 @@ config SND_INTEL8X0
|
|||
will be called snd-intel8x0.
|
||||
|
||||
config SND_INTEL8X0M
|
||||
tristate "Intel/SiS/nVidia/AMD MC97 Modem (EXPERIMENTAL)"
|
||||
depends on SND && EXPERIMENTAL
|
||||
tristate "Intel/SiS/nVidia/AMD MC97 Modem"
|
||||
depends on SND
|
||||
select SND_AC97_CODEC
|
||||
help
|
||||
Say Y here to include support for the integrated MC97 modem on
|
||||
|
|
|
@ -57,6 +57,7 @@ obj-$(CONFIG_SND) += \
|
|||
ca0106/ \
|
||||
cs46xx/ \
|
||||
cs5535audio/ \
|
||||
echoaudio/ \
|
||||
emu10k1/ \
|
||||
hda/ \
|
||||
ice1712/ \
|
||||
|
|
|
@ -1824,6 +1824,8 @@ static const struct snd_kcontrol_new snd_ac97_ad1888_controls[] = {
|
|||
.get = snd_ac97_ad1888_lohpsel_get,
|
||||
.put = snd_ac97_ad1888_lohpsel_put
|
||||
},
|
||||
AC97_SINGLE("V_REFOUT Enable", AC97_AD_MISC, 2, 1, 1),
|
||||
AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2, 12, 1, 1),
|
||||
AC97_SINGLE("Spread Front to Surround and Center/LFE", AC97_AD_MISC, 7, 1, 0),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
|
|
30
sound/pci/echoaudio/Makefile
Normal file
30
sound/pci/echoaudio/Makefile
Normal file
|
@ -0,0 +1,30 @@
|
|||
#
|
||||
# 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
|
||||
|
||||
obj-$(CONFIG_SND_DARLA20) += snd-darla20.o
|
||||
obj-$(CONFIG_SND_GINA20) += snd-gina20.o
|
||||
obj-$(CONFIG_SND_LAYLA20) += snd-layla20.o
|
||||
obj-$(CONFIG_SND_DARLA24) += snd-darla24.o
|
||||
obj-$(CONFIG_SND_GINA24) += snd-gina24.o
|
||||
obj-$(CONFIG_SND_LAYLA24) += snd-layla24.o
|
||||
obj-$(CONFIG_SND_MONA) += snd-mona.o
|
||||
obj-$(CONFIG_SND_MIA) += snd-mia.o
|
||||
obj-$(CONFIG_SND_ECHO3G) += snd-echo3g.o
|
||||
obj-$(CONFIG_SND_INDIGO) += snd-indigo.o
|
||||
obj-$(CONFIG_SND_INDIGOIO) += snd-indigoio.o
|
||||
obj-$(CONFIG_SND_INDIGODJ) += snd-indigodj.o
|
99
sound/pci/echoaudio/darla20.c
Normal file
99
sound/pci/echoaudio/darla20.c
Normal file
|
@ -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"
|
125
sound/pci/echoaudio/darla20_dsp.c
Normal file
125
sound/pci/echoaudio/darla20_dsp.c
Normal file
|
@ -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);
|
||||
}
|
106
sound/pci/echoaudio/darla24.c
Normal file
106
sound/pci/echoaudio/darla24.c
Normal file
|
@ -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"
|
156
sound/pci/echoaudio/darla24_dsp.c
Normal file
156
sound/pci/echoaudio/darla24_dsp.c
Normal file
|
@ -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);
|
||||
}
|
||||
|
118
sound/pci/echoaudio/echo3g.c
Normal file
118
sound/pci/echoaudio/echo3g.c
Normal file
|
@ -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"
|
131
sound/pci/echoaudio/echo3g_dsp.c
Normal file
131
sound/pci/echoaudio/echo3g_dsp.c
Normal file
|
@ -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);
|
||||
}
|
2196
sound/pci/echoaudio/echoaudio.c
Normal file
2196
sound/pci/echoaudio/echoaudio.c
Normal file
File diff suppressed because it is too large
Load diff
590
sound/pci/echoaudio/echoaudio.h
Normal file
590
sound/pci/echoaudio/echoaudio.h
Normal file
|
@ -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_ */
|
431
sound/pci/echoaudio/echoaudio_3g.c
Normal file
431
sound/pci/echoaudio/echoaudio_3g.c
Normal file
|
@ -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;
|
||||
}
|
1125
sound/pci/echoaudio/echoaudio_dsp.c
Normal file
1125
sound/pci/echoaudio/echoaudio_dsp.c
Normal file
File diff suppressed because it is too large
Load diff
694
sound/pci/echoaudio/echoaudio_dsp.h
Normal file
694
sound/pci/echoaudio/echoaudio_dsp.h
Normal file
|
@ -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_ */
|
198
sound/pci/echoaudio/echoaudio_gml.c
Normal file
198
sound/pci/echoaudio/echoaudio_gml.c
Normal file
|
@ -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;
|
||||
}
|
103
sound/pci/echoaudio/gina20.c
Normal file
103
sound/pci/echoaudio/gina20.c
Normal file
|
@ -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"
|
215
sound/pci/echoaudio/gina20_dsp.c
Normal file
215
sound/pci/echoaudio/gina20_dsp.c
Normal file
|
@ -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);
|
||||
}
|
123
sound/pci/echoaudio/gina24.c
Normal file
123
sound/pci/echoaudio/gina24.c
Normal file
|
@ -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"
|
346
sound/pci/echoaudio/gina24_dsp.c
Normal file
346
sound/pci/echoaudio/gina24_dsp.c
Normal file
|
@ -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;
|
||||
}
|
104
sound/pci/echoaudio/indigo.c
Normal file
104
sound/pci/echoaudio/indigo.c
Normal file
|
@ -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"
|
||||
|
170
sound/pci/echoaudio/indigo_dsp.c
Normal file
170
sound/pci/echoaudio/indigo_dsp.c
Normal file
|
@ -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);
|
||||
}
|
||||
|
104
sound/pci/echoaudio/indigodj.c
Normal file
104
sound/pci/echoaudio/indigodj.c
Normal file
|
@ -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"
|
||||
|
170
sound/pci/echoaudio/indigodj_dsp.c
Normal file
170
sound/pci/echoaudio/indigodj_dsp.c
Normal file
|
@ -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);
|
||||
}
|
||||
|
105
sound/pci/echoaudio/indigoio.c
Normal file
105
sound/pci/echoaudio/indigoio.c
Normal file
|
@ -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"
|
||||
|
141
sound/pci/echoaudio/indigoio_dsp.c
Normal file
141
sound/pci/echoaudio/indigoio_dsp.c
Normal file
|
@ -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);
|
||||
}
|
||||
|
112
sound/pci/echoaudio/layla20.c
Normal file
112
sound/pci/echoaudio/layla20.c
Normal file
|
@ -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"
|
290
sound/pci/echoaudio/layla20_dsp.c
Normal file
290
sound/pci/echoaudio/layla20_dsp.c
Normal file
|
@ -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);
|
||||
}
|
121
sound/pci/echoaudio/layla24.c
Normal file
121
sound/pci/echoaudio/layla24.c
Normal file
|
@ -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"
|
394
sound/pci/echoaudio/layla24_dsp.c
Normal file
394
sound/pci/echoaudio/layla24_dsp.c
Normal file
|
@ -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;
|
||||
}
|
117
sound/pci/echoaudio/mia.c
Normal file
117
sound/pci/echoaudio/mia.c
Normal file
|
@ -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"
|
229
sound/pci/echoaudio/mia_dsp.c
Normal file
229
sound/pci/echoaudio/mia_dsp.c
Normal file
|
@ -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);
|
||||
}
|
||||
|
327
sound/pci/echoaudio/midi.c
Normal file
327
sound/pci/echoaudio/midi.c
Normal file
|
@ -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;
|
||||
}
|
129
sound/pci/echoaudio/mona.c
Normal file
129
sound/pci/echoaudio/mona.c
Normal file
|
@ -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"
|
428
sound/pci/echoaudio/mona_dsp.c
Normal file
428
sound/pci/echoaudio/mona_dsp.c
Normal file
|
@ -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;
|
||||
}
|
|
@ -408,7 +408,9 @@ static const struct hda_codec_preset *find_codec_preset(struct hda_codec *codec)
|
|||
u32 mask = preset->mask;
|
||||
if (! mask)
|
||||
mask = ~0;
|
||||
if (preset->id == (codec->vendor_id & mask))
|
||||
if (preset->id == (codec->vendor_id & mask) &&
|
||||
(! preset->rev ||
|
||||
preset->rev == codec->revision_id))
|
||||
return preset;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -799,6 +799,8 @@ static struct hda_board_config ad1986a_cfg_tbl[] = {
|
|||
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x818f,
|
||||
.config = AD1986A_LAPTOP }, /* ASUS P5GV-MX */
|
||||
{ .modelname = "laptop-eapd", .config = AD1986A_LAPTOP_EAPD },
|
||||
{ .pci_subvendor = 0x144d, .pci_subdevice = 0xc023,
|
||||
.config = AD1986A_LAPTOP_EAPD }, /* Samsung X60 Chane */
|
||||
{ .pci_subvendor = 0x144d, .pci_subdevice = 0xc024,
|
||||
.config = AD1986A_LAPTOP_EAPD }, /* Samsung R65-T2300 Charis */
|
||||
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1153,
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -42,6 +42,9 @@
|
|||
#define STAC_D945GTP3 1
|
||||
#define STAC_D945GTP5 2
|
||||
#define STAC_MACMINI 3
|
||||
#define STAC_D965_2112 4
|
||||
#define STAC_D965_284B 5
|
||||
#define STAC_922X_MODELS 6 /* number of 922x models */
|
||||
|
||||
struct sigmatel_spec {
|
||||
struct snd_kcontrol_new *mixers[4];
|
||||
|
@ -107,10 +110,24 @@ static hda_nid_t stac922x_adc_nids[2] = {
|
|||
0x06, 0x07,
|
||||
};
|
||||
|
||||
static hda_nid_t stac9227_adc_nids[2] = {
|
||||
0x07, 0x08,
|
||||
};
|
||||
|
||||
#if 0
|
||||
static hda_nid_t d965_2112_dac_nids[3] = {
|
||||
0x02, 0x03, 0x05,
|
||||
};
|
||||
#endif
|
||||
|
||||
static hda_nid_t stac922x_mux_nids[2] = {
|
||||
0x12, 0x13,
|
||||
};
|
||||
|
||||
static hda_nid_t stac9227_mux_nids[2] = {
|
||||
0x15, 0x16,
|
||||
};
|
||||
|
||||
static hda_nid_t stac927x_adc_nids[3] = {
|
||||
0x07, 0x08, 0x09
|
||||
};
|
||||
|
@ -173,6 +190,24 @@ static struct hda_verb stac922x_core_init[] = {
|
|||
{}
|
||||
};
|
||||
|
||||
static struct hda_verb stac9227_core_init[] = {
|
||||
/* set master volume and direct control */
|
||||
{ 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
|
||||
/* unmute node 0x1b */
|
||||
{ 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct hda_verb d965_2112_core_init[] = {
|
||||
/* set master volume and direct control */
|
||||
{ 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
|
||||
/* unmute node 0x1b */
|
||||
{ 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
|
||||
/* select node 0x03 as DAC */
|
||||
{ 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct hda_verb stac927x_core_init[] = {
|
||||
/* set master volume and direct control */
|
||||
{ 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
|
||||
|
@ -212,6 +247,21 @@ static struct snd_kcontrol_new stac922x_mixer[] = {
|
|||
{ } /* end */
|
||||
};
|
||||
|
||||
/* This needs to be generated dynamically based on sequence */
|
||||
static struct snd_kcontrol_new stac9227_mixer[] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Input Source",
|
||||
.count = 1,
|
||||
.info = stac92xx_mux_enum_info,
|
||||
.get = stac92xx_mux_enum_get,
|
||||
.put = stac92xx_mux_enum_put,
|
||||
},
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x1b, 0x0, HDA_OUTPUT),
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static snd_kcontrol_new_t stac927x_mixer[] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
|
@ -291,11 +341,17 @@ static unsigned int d945gtp5_pin_configs[10] = {
|
|||
0x02a19320, 0x40000100,
|
||||
};
|
||||
|
||||
static unsigned int *stac922x_brd_tbl[] = {
|
||||
ref922x_pin_configs,
|
||||
d945gtp3_pin_configs,
|
||||
d945gtp5_pin_configs,
|
||||
NULL, /* STAC_MACMINI */
|
||||
static unsigned int d965_2112_pin_configs[10] = {
|
||||
0x0221401f, 0x40000100, 0x40000100, 0x01014011,
|
||||
0x01a19021, 0x01813024, 0x01452130, 0x40000100,
|
||||
0x02a19320, 0x40000100,
|
||||
};
|
||||
|
||||
static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
|
||||
[STAC_REF] = ref922x_pin_configs,
|
||||
[STAC_D945GTP3] = d945gtp3_pin_configs,
|
||||
[STAC_D945GTP5] = d945gtp5_pin_configs,
|
||||
[STAC_D965_2112] = d965_2112_pin_configs,
|
||||
};
|
||||
|
||||
static struct hda_board_config stac922x_cfg_tbl[] = {
|
||||
|
@ -330,6 +386,12 @@ static struct hda_board_config stac922x_cfg_tbl[] = {
|
|||
{ .pci_subvendor = 0x8384,
|
||||
.pci_subdevice = 0x7680,
|
||||
.config = STAC_MACMINI }, /* Apple Mac Mini (early 2006) */
|
||||
{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
|
||||
.pci_subdevice = 0x2112,
|
||||
.config = STAC_D965_2112 },
|
||||
{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
|
||||
.pci_subdevice = 0x284b,
|
||||
.config = STAC_D965_284B },
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
|
@ -713,7 +775,8 @@ static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cf
|
|||
* A and B is not supported.
|
||||
*/
|
||||
/* fill in the dac_nids table from the parsed pin configuration */
|
||||
static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
|
||||
static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
|
||||
const struct auto_pin_cfg *cfg)
|
||||
{
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
hda_nid_t nid;
|
||||
|
@ -732,10 +795,13 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, const struct aut
|
|||
}
|
||||
|
||||
/* add playback controls from the parsed DAC table */
|
||||
static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, const struct auto_pin_cfg *cfg)
|
||||
static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec,
|
||||
const struct auto_pin_cfg *cfg)
|
||||
{
|
||||
char name[32];
|
||||
static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" };
|
||||
static const char *chname[4] = {
|
||||
"Front", "Surround", NULL /*CLFE*/, "Side"
|
||||
};
|
||||
hda_nid_t nid;
|
||||
int i, err;
|
||||
|
||||
|
@ -893,10 +959,12 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
|
|||
return err;
|
||||
if (! spec->autocfg.line_outs)
|
||||
return 0; /* can't find valid pin config */
|
||||
|
||||
if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
|
||||
return err;
|
||||
if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
|
||||
return err;
|
||||
if (spec->multiout.num_dacs == 0)
|
||||
if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
|
||||
return err;
|
||||
|
||||
if ((err = stac92xx_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
|
||||
(err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg)) < 0 ||
|
||||
|
@ -1194,7 +1262,8 @@ static int patch_stac922x(struct hda_codec *codec)
|
|||
codec->spec = spec;
|
||||
spec->board_config = snd_hda_check_board_config(codec, stac922x_cfg_tbl);
|
||||
if (spec->board_config < 0)
|
||||
snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, using BIOS defaults\n");
|
||||
snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
|
||||
"using BIOS defaults\n");
|
||||
else if (stac922x_brd_tbl[spec->board_config] != NULL) {
|
||||
spec->num_pins = 10;
|
||||
spec->pin_nids = stac922x_pin_nids;
|
||||
|
@ -1210,6 +1279,25 @@ static int patch_stac922x(struct hda_codec *codec)
|
|||
spec->mixer = stac922x_mixer;
|
||||
|
||||
spec->multiout.dac_nids = spec->dac_nids;
|
||||
|
||||
switch (spec->board_config) {
|
||||
case STAC_D965_2112:
|
||||
spec->adc_nids = stac9227_adc_nids;
|
||||
spec->mux_nids = stac9227_mux_nids;
|
||||
#if 0
|
||||
spec->multiout.dac_nids = d965_2112_dac_nids;
|
||||
spec->multiout.num_dacs = ARRAY_SIZE(d965_2112_dac_nids);
|
||||
#endif
|
||||
spec->init = d965_2112_core_init;
|
||||
spec->mixer = stac9227_mixer;
|
||||
break;
|
||||
case STAC_D965_284B:
|
||||
spec->adc_nids = stac9227_adc_nids;
|
||||
spec->mux_nids = stac9227_mux_nids;
|
||||
spec->init = stac9227_core_init;
|
||||
spec->mixer = stac9227_mixer;
|
||||
break;
|
||||
}
|
||||
|
||||
err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
|
||||
if (err < 0) {
|
||||
|
|
|
@ -87,12 +87,25 @@ static void revo_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
|
|||
* initialize the chips on M-Audio Revolution cards
|
||||
*/
|
||||
|
||||
static unsigned int revo71_num_stereo_front[] = {2};
|
||||
static char *revo71_channel_names_front[] = {"PCM Playback Volume"};
|
||||
|
||||
static unsigned int revo71_num_stereo_surround[] = {1, 1, 2, 2};
|
||||
static char *revo71_channel_names_surround[] = {"PCM Center Playback Volume", "PCM LFE Playback Volume",
|
||||
"PCM Side Playback Volume", "PCM Rear Playback Volume"};
|
||||
|
||||
static unsigned int revo51_num_stereo[] = {2, 1, 1, 2};
|
||||
static char *revo51_channel_names[] = {"PCM Playback Volume", "PCM Center Playback Volume",
|
||||
"PCM LFE Playback Volume", "PCM Rear Playback Volume"};
|
||||
|
||||
static struct snd_akm4xxx akm_revo_front __devinitdata = {
|
||||
.type = SND_AK4381,
|
||||
.num_dacs = 2,
|
||||
.ops = {
|
||||
.set_rate_val = revo_set_rate_val
|
||||
}
|
||||
},
|
||||
.num_stereo = revo71_num_stereo_front,
|
||||
.channel_names = revo71_channel_names_front
|
||||
};
|
||||
|
||||
static struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = {
|
||||
|
@ -113,7 +126,9 @@ static struct snd_akm4xxx akm_revo_surround __devinitdata = {
|
|||
.num_dacs = 6,
|
||||
.ops = {
|
||||
.set_rate_val = revo_set_rate_val
|
||||
}
|
||||
},
|
||||
.num_stereo = revo71_num_stereo_surround,
|
||||
.channel_names = revo71_channel_names_surround
|
||||
};
|
||||
|
||||
static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = {
|
||||
|
@ -133,7 +148,9 @@ static struct snd_akm4xxx akm_revo51 __devinitdata = {
|
|||
.num_dacs = 6,
|
||||
.ops = {
|
||||
.set_rate_val = revo_set_rate_val
|
||||
}
|
||||
},
|
||||
.num_stereo = revo51_num_stereo,
|
||||
.channel_names = revo51_channel_names
|
||||
};
|
||||
|
||||
static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = {
|
||||
|
|
|
@ -3095,6 +3095,32 @@ static int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* C-Media CM106/CM106+ have four 16-bit internal registers that are nicely
|
||||
* documented in the device's data sheet.
|
||||
*/
|
||||
static int snd_usb_cm106_write_int_reg(struct usb_device *dev, int reg, u16 value)
|
||||
{
|
||||
u8 buf[4];
|
||||
buf[0] = 0x20;
|
||||
buf[1] = value & 0xff;
|
||||
buf[2] = (value >> 8) & 0xff;
|
||||
buf[3] = reg;
|
||||
return snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_CONFIGURATION,
|
||||
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
|
||||
0, 0, &buf, 4, 1000);
|
||||
}
|
||||
|
||||
static int snd_usb_cm106_boot_quirk(struct usb_device *dev)
|
||||
{
|
||||
/*
|
||||
* Enable line-out driver mode, set headphone source to front
|
||||
* channels, enable stereo mic.
|
||||
*/
|
||||
return snd_usb_cm106_write_int_reg(dev, 2, 0x8004);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Setup quirks
|
||||
*/
|
||||
|
@ -3365,6 +3391,12 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
|
|||
goto __err_val;
|
||||
}
|
||||
|
||||
/* C-Media CM106 / Turtle Beach Audio Advantage Roadie */
|
||||
if (id == USB_ID(0x10f5, 0x0200)) {
|
||||
if (snd_usb_cm106_boot_quirk(dev) < 0)
|
||||
goto __err_val;
|
||||
}
|
||||
|
||||
/*
|
||||
* found a config. now register to ALSA
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue