/*
* 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.
*/
MODULE_AUTHOR("Giuliano Pochini <pochini@shiny.it>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Echoaudio " ECHOCARD_NAME " soundcards driver");
MODULE_SUPPORTED_DEVICE("{{Echoaudio," ECHOCARD_NAME "}}");
MODULE_DEVICE_TABLE(pci, snd_echo_ids);
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for " ECHOCARD_NAME " soundcard.");
module_param_array(id, charp, NULL, 0444);
MODULE_PARM_DESC(id, "ID string for " ECHOCARD_NAME " soundcard.");
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable " ECHOCARD_NAME " soundcard.");
static unsigned int channels_list[10] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 999999};
static const DECLARE_TLV_DB_SCALE(db_scale_output_gain, -12800, 100, 1);
static int get_firmware(const struct firmware **fw_entry,
struct echoaudio *chip, const short fw_index)
{
int err;
char name[30];
#ifdef CONFIG_PM
if (chip->fw_cache[fw_index]) {
DE_ACT(("firmware requested: %s is cached\n", card_fw[fw_index].data));
*fw_entry = chip->fw_cache[fw_index];
return 0;
}
#endif
DE_ACT(("firmware requested: %s\n", card_fw[fw_index].data));
snprintf(name, sizeof(name), "ea/%s", card_fw[fw_index].data);
err = request_firmware(fw_entry, name, pci_device(chip));
if (err < 0)
snd_printk(KERN_ERR "get_firmware(): Firmware not available (%d)\n", err);
#ifdef CONFIG_PM
else
chip->fw_cache[fw_index] = *fw_entry;
#endif
return err;
}
static void free_firmware(const struct firmware *fw_entry)
{
#ifdef CONFIG_PM
DE_ACT(("firmware not released (kept in cache)\n"));
#else
release_firmware(fw_entry);
DE_ACT(("firmware released\n"));
#endif
}
static void free_firmware_cache(struct echoaudio *chip)
{
#ifdef CONFIG_PM
int i;
for (i = 0; i < 8 ; i++)
if (chip->fw_cache[i]) {
release_firmware(chip->fw_cache[i]);
DE_ACT(("release_firmware(%d)\n", i));
}
DE_ACT(("firmware_cache released\n"));
#endif
}
/******************************************************************************
PCM interface
******************************************************************************/
static void audiopipe_free(struct snd_pcm_runtime *runtime)
{
struct audiopipe *pipe = runtime->private_data;
if (pipe->sgpage.area)
snd_dma_free_pages(&pipe->sgpage);
kfree(pipe);
}
static int hw_rule_capture_format_by_channels(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
struct snd_interval *c = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
struct snd_mask fmt;
snd_mask_any(&fmt);
#ifndef ECHOCARD_HAS_STEREO_BIG_ENDIAN32
/* >=2 channels cannot be S32_BE */
if (c->min == 2) {
fmt.bits[0] &= ~SNDRV_PCM_FMTBIT_S32_BE;
return snd_mask_refine(f, &fmt);
}
#endif
/* > 2 channels cannot be U8 and S32_BE */
if (c->min > 2) {
fmt.bits[0] &= ~(SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_BE);
return snd_mask_refine(f, &fmt);
}
/* Mono is ok with any format */
return 0;
}
static int hw_rule_capture_channels_by_format(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
struct snd_interval *c = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
struct snd_interval ch;
snd_interval_any(&ch);
/* S32_BE is mono (and stereo) only */
if (f->bits[0] == SNDRV_PCM_FMTBIT_S32_BE) {
ch.min = 1;
#ifdef ECHOCARD_HAS_STEREO_BIG_ENDIAN32
ch.max = 2;
#else
ch.max = 1;
#endif
ch.integer = 1;
return snd_interval_refine(c, &ch);
}
/* U8 can be only mono or stereo */
if (f->bits[0] == SNDRV_PCM_FMTBIT_U8) {
ch.min = 1;
ch.max = 2;
ch.integer = 1;
return snd_interval_refine(c, &ch);
}
/* S16_LE, S24_3LE and S32_LE support any number of channels. */
return 0;
}
static int hw_rule_playback_format_by_channels(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
struct snd_interval *c = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
struct snd_mask fmt;
u64 fmask;
snd_mask_any(&fmt);
fmask = fmt.bits[0] + ((u64)fmt.bits[1] << 32);
/* >2 channels must be S16_LE, S24_3LE or S32_LE */
if (c->min > 2) {
fmask &= SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_3LE |
SNDRV_PCM_FMTBIT_S32_LE;
/* 1 channel must be S32_BE or S32_LE */
} else if (c->max == 1)
fmask &= SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE;
#ifndef ECHOCARD_HAS_STEREO_BIG_ENDIAN32
/* 2 channels cannot be S32_BE */
else if (c->min == 2 && c->max == 2)
fmask &= ~SNDRV_PCM_FMTBIT_S32_BE;
#endif
else
return 0;
fmt.bits[0] &= (u32)fmask;
fmt.bits[1] &= (u32)(fmask >> 32);
return snd_mask_refine(f, &fmt);
}
static int hw_rule_playback_channels_by_format(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
struct snd_interval *c = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
struct snd_interval ch;
u64 fmask;
snd_interval_any(&ch);
ch.integer = 1;
fmask = f->bits[0] + ((u64)f->bits[1] << 32);
/* S32_BE is mono (and stereo) only */
if (fmask == SNDRV_PCM_FMTBIT_S32_BE) {
ch.min = 1;
#ifdef ECHOCARD_HAS_STEREO_BIG_ENDIAN32
ch.max = 2;
#else
ch.max = 1;
#endif
/* U8 is stereo only */
} else if (fmask == SNDRV_PCM_FMTBIT_U8)
ch.min = ch.max = 2;
/* S16_LE and S24_3LE must be at least stereo */
else if (!(fmask & ~(SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_3LE)))
ch.min = 2;
else
return 0;
return snd_interval_refine(c, &ch);
}
/* Since the sample rate is a global setting, do allow the user to change the
sample rate only if there is only one pcm device open. */
static int hw_rule_sample_rate(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
struct snd_interval *rate = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_RATE);
struct echoaudio *chip = rule->private;
struct snd_interval fixed;
if (!chip->can_set_rate) {
snd_interval_any(&fixed);
fixed.min = fixed.max = chip->sample_rate;
return snd_interval_refine(rate, &fixed);
}
return 0;
}
static int pcm_open(struct snd_pcm_substream *substream,
signed char max_channels)
{
struct echoaudio *chip;
struct snd_pcm_runtime *runtime;
struct audiopipe *pipe;
int err, i;
if (max_channels <= 0)
return -EAGAIN;
|