Commit b793b71f authored by Jaroslav Kysela's avatar Jaroslav Kysela

Merge suse.cz:/home/perex/bk/linux-sound/linux-2.5

into suse.cz:/home/perex/bk/linux-sound/linux-sound
parents 6e9aed30 700cb4e5
......@@ -692,6 +692,15 @@ Module parameters
The power-management is supported.
Module snd-mixart
-----------------
Module for Digigram miXart8 soundcards.
Module supports multiple cards.
Note: One miXart8 board will be represented as 4 alsa cards.
See MIXART.txt for details.
Module snd-mpu401
-----------------
......
Alsa driver for Digigram miXart8 and miXart8AES/EBU soundcards
Digigram <alsa@digigram.com>
GENERAL
=======
The miXart8 is a multichannel audio processing and mixing soundcard
that has 4 stereo audio inputs and 4 stereo audio outputs.
The miXart8AES/EBU is the same with a add-on card that offers further
4 digital stereo audio inputs and outputs.
Furthermore the add-on card offers external clock synchronisation
(AES/EBU, Word Clock, Time Code and Video Synchro)
The mainboard has a PowerPC that offers onboard mpeg encoding and
decoding, samplerate conversions and various effects.
The driver don't work properly at all until the certain firmwares
are loaded, i.e. no PCM nor mixer devices will appear.
Use the mixartloader that can be found in the alsa-tools package.
VERSION 0.1.0
=============
One miXart8 board will be represented as 4 alsa cards, each with 1
stereo analog capture 'pcm0c' and 1 stereo analog playback 'pcm0p' device.
With a miXart8AES/EBU there is in addition 1 stereo digital input
'pcm1c' and 1 stereo digital output 'pcm1p' per card.
Formats
-------
U8, S16_LE, S16_BE, S24_3LE, S24_3BE, FLOAT_LE, FLOAT_BE
Sample rates : 8000 - 48000 Hz continously
Playback
--------
For instance the playback devices are configured to have max. 4
substreams performing hardware mixing. This could be changed to a
maximum of 24 substreams if wished.
Mono files will be played on the left and right channel. Each channel
can be muted for each stream to use 8 analog/digital outputs seperately.
Capture
-------
There is one substream per capture device. For instance only stereo
formats are supported.
Mixer
-----
<Master> and <Master Capture> : analog volume control of playback and capture PCM.
<PCM 0-3> and <PCM Capture> : digital volume control of each analog substream.
<AES 0-3> and <AES Capture> : digital volume control of each AES/EBU substream.
<Monitoring> : Loopback from 'pcm0c' to 'pcm0p' with digital volume
and mute control.
Rem : for best audio quality try to keep a 0 attenuation on the PCM
and AES volume controls which is set by 219 in the range from 0 to 255
(about 86% with alsamixer)
NOT YET IMPLEMENTED
===================
- external clock support (AES/EBU, Word Clock, Time Code, Video Sync)
- MPEG audio formats
- mono record
- on-board effects and samplerate conversions
- linked streams
FIRMWARE
========
For loading the firmware automatically after the module is loaded, use
the post-install command. For example, add the following entry to
/etc/modprobe.conf for miXart driver:
install snd-mixart /sbin/modprobe --first-time -i snd-mixart && \
/usr/bin/mixartloader
(for 2.2/2.4 kernels, add "post-install snd-mixart /usr/bin/vxloader" to
/etc/modules.conf, instead.)
The firmware binaries are installed on /usr/share/alsa/firmware
(or /usr/local/share/alsa/firmware, depending to the prefix option of
configure). There will be a miXart.conf file, which define the dsp image
files.
The firmware files are copyright by Digigram SA
COPYRIGHT
=========
Copyright (c) 2003 Digigram SA <alsa@digigram.com>
Distributalbe under GPL.
......@@ -50,6 +50,7 @@ typedef struct _snd_pcm_oss_runtime {
unsigned int maxfrags;
unsigned int subdivision; /* requested subdivision */
size_t period_bytes; /* requested period size */
size_t period_frames; /* period frames for poll */
size_t period_ptr; /* actual write pointer to period */
unsigned int periods;
size_t buffer_bytes; /* requested buffer size */
......
......@@ -107,5 +107,6 @@ obj-$(CONFIG_SND_VXPOCKET) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-h
obj-$(CONFIG_SND_VXP440) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-hwdep.o
obj-$(CONFIG_SND_VX222) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-hwdep.o
obj-$(CONFIG_SND_BT87X) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
obj-$(CONFIG_SND_MIXART) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-hwdep.o
obj-m := $(sort $(obj-m))
......@@ -133,6 +133,15 @@ static long snd_pcm_oss_bytes(snd_pcm_substream_t *substream, long frames)
return (runtime->oss.buffer_bytes * frames) / buffer_size;
}
static long snd_pcm_alsa_frames(snd_pcm_substream_t *substream, long bytes)
{
snd_pcm_runtime_t *runtime = substream->runtime;
snd_pcm_uframes_t buffer_size = snd_pcm_lib_buffer_bytes(substream);
if (buffer_size == runtime->oss.buffer_bytes)
return bytes_to_frames(runtime, bytes);
return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes);
}
static int snd_pcm_oss_format_from(int format)
{
switch (format) {
......@@ -254,6 +263,7 @@ static int snd_pcm_oss_period_size(snd_pcm_substream_t *substream,
snd_assert(oss_period_size >= 16, return -EINVAL);
runtime->oss.period_bytes = oss_period_size;
runtime->oss.period_frames = 1;
runtime->oss.periods = oss_periods;
return 0;
}
......@@ -511,6 +521,8 @@ static int snd_pcm_oss_change_params(snd_pcm_substream_t *substream)
if (runtime->dma_area)
snd_pcm_format_set_silence(runtime->format, runtime->dma_area, bytes_to_samples(runtime, runtime->dma_bytes));
runtime->oss.period_frames = snd_pcm_alsa_frames(substream, oss_period_size);
err = 0;
failure:
if (sw_params)
......@@ -2098,7 +2110,7 @@ static int snd_pcm_oss_playback_ready(snd_pcm_substream_t *substream)
if (atomic_read(&runtime->mmap_count))
return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
else
return snd_pcm_playback_ready(substream);
return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames;
}
static int snd_pcm_oss_capture_ready(snd_pcm_substream_t *substream)
......@@ -2107,7 +2119,7 @@ static int snd_pcm_oss_capture_ready(snd_pcm_substream_t *substream)
if (atomic_read(&runtime->mmap_count))
return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
else
return snd_pcm_capture_ready(substream);
return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames;
}
static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait)
......
......@@ -329,6 +329,7 @@ static void snd_pcm_substream_proc_hw_params_read(snd_info_entry_t *entry, snd_i
snd_iprintf(buffer, "OSS rate: %u\n", runtime->oss.rate);
snd_iprintf(buffer, "OSS period bytes: %lu\n", (unsigned long)runtime->oss.period_bytes);
snd_iprintf(buffer, "OSS periods: %u\n", runtime->oss.periods);
snd_iprintf(buffer, "OSS period frames: %lu\n", (unsigned long)runtime->oss.period_frames);
}
#endif
snd_pcm_stream_unlock_irq(substream);
......
......@@ -491,7 +491,7 @@ snd_seq_oss_midi_reset(seq_oss_devinfo_t *dp, int dev)
}
}
}
snd_seq_oss_midi_close(dp, dev);
// snd_seq_oss_midi_close(dp, dev);
snd_use_lock_free(&mdev->use_lock);
}
......
......@@ -410,6 +410,8 @@ snd_seq_oss_synth_reset(seq_oss_devinfo_t *dp, int dev)
if (midi_synth_dev.opened <= 0)
return;
snd_seq_oss_midi_reset(dp, info->midi_mapped);
/* reopen the device */
snd_seq_oss_midi_close(dp, dev);
if (snd_seq_oss_midi_open(dp, info->midi_mapped,
dp->file_mode) < 0) {
midi_synth_dev.opened--;
......
......@@ -171,10 +171,12 @@ int snd_seq_fifo_cell_out(fifo_t *f, snd_seq_event_cell_t **cellp, int nonblock)
{
snd_seq_event_cell_t *cell;
unsigned long flags;
wait_queue_t wait;
snd_assert(f != NULL, return -EINVAL);
*cellp = NULL;
init_waitqueue_entry(&wait, current);
spin_lock_irqsave(&f->lock, flags);
while ((cell = fifo_cell_out(f)) == NULL) {
if (nonblock) {
......@@ -182,17 +184,19 @@ int snd_seq_fifo_cell_out(fifo_t *f, snd_seq_event_cell_t **cellp, int nonblock)
spin_unlock_irqrestore(&f->lock, flags);
return -EAGAIN;
}
spin_unlock(&f->lock);
interruptible_sleep_on(&f->input_sleep);
spin_lock(&f->lock);
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&f->input_sleep, &wait);
spin_unlock_irq(&f->lock);
schedule();
spin_lock_irq(&f->lock);
remove_wait_queue(&f->input_sleep, &wait);
if (signal_pending(current)) {
spin_unlock_irqrestore(&f->lock, flags);
return -ERESTARTSYS;
}
}
*cellp = cell;
spin_unlock_irqrestore(&f->lock, flags);
*cellp = cell;
return 0;
}
......
......@@ -220,12 +220,14 @@ int snd_seq_cell_alloc(pool_t *pool, snd_seq_event_cell_t **cellp, int nonblock,
snd_seq_event_cell_t *cell;
unsigned long flags;
int err = -EAGAIN;
wait_queue_t wait;
if (pool == NULL)
return -EINVAL;
*cellp = NULL;
init_waitqueue_entry(&wait, current);
spin_lock_irqsave(&pool->lock, flags);
if (pool->ptr == NULL) { /* not initialized */
snd_printd("seq: pool is not initialized\n");
......@@ -234,9 +236,12 @@ int snd_seq_cell_alloc(pool_t *pool, snd_seq_event_cell_t **cellp, int nonblock,
}
while (pool->free == NULL && ! nonblock && ! pool->closing) {
spin_unlock(&pool->lock);
interruptible_sleep_on(&pool->output_sleep);
spin_lock(&pool->lock);
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&pool->output_sleep, &wait);
spin_unlock_irq(&pool->lock);
schedule();
spin_lock_irq(&pool->lock);
remove_wait_queue(&pool->output_sleep, &wait);
/* interrupted? */
if (signal_pending(current)) {
err = -ERESTARTSYS;
......
......@@ -355,11 +355,12 @@ int vx_send_msg_nolock(vx_core_t *chip, struct vx_rmh *rmh)
*/
int vx_send_msg(vx_core_t *chip, struct vx_rmh *rmh)
{
unsigned long flags;
int err;
spin_lock_bh(&chip->lock);
spin_lock_irqsave(&chip->lock, flags);
err = vx_send_msg_nolock(chip, rmh);
spin_unlock_bh(&chip->lock);
spin_unlock_irqrestore(&chip->lock, flags);
return err;
}
......@@ -414,11 +415,12 @@ int vx_send_rih_nolock(vx_core_t *chip, int cmd)
*/
int vx_send_rih(vx_core_t *chip, int cmd)
{
unsigned long flags;
int err;
spin_lock_bh(&chip->lock);
spin_lock_irqsave(&chip->lock, flags);
err = vx_send_rih_nolock(chip, cmd);
spin_unlock_bh(&chip->lock);
spin_unlock_irqrestore(&chip->lock, flags);
return err;
}
......
......@@ -919,7 +919,7 @@ int snd_vx_mixer_new(vx_core_t *chip)
if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_iec958, chip))) < 0)
return err;
/* VU, peak, saturation meters */
for (c = 0; c < 1; c++) {
for (c = 0; c < 2; c++) {
static char *dir[2] = { "Output", "Input" };
for (i = 0; i < chip->hw->num_ins; i++) {
int val = (i * 2) | (c << 8);
......
......@@ -561,7 +561,7 @@ static snd_pcm_hardware_t vx_pcm_playback_hw = {
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
.rate_min = 5000,
.rate_max = 48000,
.channels_min = 2,
.channels_min = 1,
.channels_max = 2,
.buffer_bytes_max = (128*1024),
.period_bytes_min = 126,
......@@ -958,7 +958,7 @@ static snd_pcm_hardware_t vx_pcm_capture_hw = {
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
.rate_min = 5000,
.rate_max = 48000,
.channels_min = 2,
.channels_min = 1,
.channels_max = 2,
.buffer_bytes_max = (128*1024),
.period_bytes_min = 126,
......
......@@ -55,6 +55,12 @@ config SND_KORG1212
help
Say 'Y' or 'M' to include support for Korg 1212IO.
config SND_MIXART
tristate "Digigram miXart"
depends on SND
help
Say 'Y' or 'M' to include support for Digigram miXart soundcard.
config SND_NM256
tristate "NeoMagic NM256AV/ZX"
depends on SND
......
......@@ -38,4 +38,16 @@ obj-$(CONFIG_SND_RME96) += snd-rme96.o
obj-$(CONFIG_SND_SONICVIBES) += snd-sonicvibes.o
obj-$(CONFIG_SND_VIA82XX) += snd-via82xx.o
obj-$(CONFIG_SND) += ac97/ ali5451/ cs46xx/ emu10k1/ korg1212/ nm256/ rme9652/ trident/ ymfpci/ ice1712/ vx222/
obj-$(CONFIG_SND) += \
ac97/ \
ali5451/ \
cs46xx/ \
emu10k1/ \
ice1712/ \
korg1212/ \
mixart/ \
nm256/ \
rme9652/ \
trident/ \
ymfpci/ \
vx222/
......@@ -100,6 +100,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x41445361, 0xffffffff, "AD1886", patch_ad1886, NULL },
{ 0x41445362, 0xffffffff, "AD1887", patch_ad1881, NULL },
{ 0x41445363, 0xffffffff, "AD1886A", patch_ad1881, NULL },
{ 0x41445368, 0xffffffff, "AD1888", patch_ad1888, NULL },
{ 0x41445370, 0xffffffff, "AD1980", patch_ad1980, NULL },
{ 0x41445372, 0xffffffff, "AD1981A", patch_ad1981a, NULL },
{ 0x41445374, 0xffffffff, "AD1981B", patch_ad1981b, NULL },
......@@ -1526,38 +1527,40 @@ static int snd_ac97_modem_build(snd_card_t * card, ac97_t * ac97)
return 0;
}
static int snd_ac97_test_rate(ac97_t *ac97, int reg, int rate)
static int snd_ac97_test_rate(ac97_t *ac97, int reg, int shadow_reg, int rate)
{
unsigned short val;
unsigned int tmp;
tmp = ((unsigned int)rate * ac97->bus->clock) / 48000;
snd_ac97_write_cache(ac97, reg, tmp & 0xffff);
if (shadow_reg)
snd_ac97_write_cache(ac97, shadow_reg, tmp & 0xffff);
val = snd_ac97_read(ac97, reg);
return val == (tmp & 0xffff);
}
static void snd_ac97_determine_rates(ac97_t *ac97, int reg, unsigned int *r_result)
static void snd_ac97_determine_rates(ac97_t *ac97, int reg, int shadow_reg, unsigned int *r_result)
{
unsigned int result = 0;
/* test a non-standard rate */
if (snd_ac97_test_rate(ac97, reg, 11000))
if (snd_ac97_test_rate(ac97, reg, shadow_reg, 11000))
result |= SNDRV_PCM_RATE_CONTINUOUS;
/* let's try to obtain standard rates */
if (snd_ac97_test_rate(ac97, reg, 8000))
if (snd_ac97_test_rate(ac97, reg, shadow_reg, 8000))
result |= SNDRV_PCM_RATE_8000;
if (snd_ac97_test_rate(ac97, reg, 11025))
if (snd_ac97_test_rate(ac97, reg, shadow_reg, 11025))
result |= SNDRV_PCM_RATE_11025;
if (snd_ac97_test_rate(ac97, reg, 16000))
if (snd_ac97_test_rate(ac97, reg, shadow_reg, 16000))
result |= SNDRV_PCM_RATE_16000;
if (snd_ac97_test_rate(ac97, reg, 22050))
if (snd_ac97_test_rate(ac97, reg, shadow_reg, 22050))
result |= SNDRV_PCM_RATE_22050;
if (snd_ac97_test_rate(ac97, reg, 32000))
if (snd_ac97_test_rate(ac97, reg, shadow_reg, 32000))
result |= SNDRV_PCM_RATE_32000;
if (snd_ac97_test_rate(ac97, reg, 44100))
if (snd_ac97_test_rate(ac97, reg, shadow_reg, 44100))
result |= SNDRV_PCM_RATE_44100;
if (snd_ac97_test_rate(ac97, reg, 48000))
if (snd_ac97_test_rate(ac97, reg, shadow_reg, 48000))
result |= SNDRV_PCM_RATE_48000;
*r_result = result;
}
......@@ -1866,8 +1869,8 @@ int snd_ac97_mixer(ac97_bus_t * bus, ac97_t * _ac97, ac97_t ** rac97)
if (ac97->ext_id & 0x0189) /* L/R, MIC, SDAC, LDAC VRA support */
snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, ac97->ext_id & 0x0189);
if (ac97->ext_id & AC97_EI_VRA) { /* VRA support */
snd_ac97_determine_rates(ac97, AC97_PCM_FRONT_DAC_RATE, &ac97->rates[AC97_RATES_FRONT_DAC]);
snd_ac97_determine_rates(ac97, AC97_PCM_LR_ADC_RATE, &ac97->rates[AC97_RATES_ADC]);
snd_ac97_determine_rates(ac97, AC97_PCM_FRONT_DAC_RATE, 0, &ac97->rates[AC97_RATES_FRONT_DAC]);
snd_ac97_determine_rates(ac97, AC97_PCM_LR_ADC_RATE, 0, &ac97->rates[AC97_RATES_ADC]);
} else {
ac97->rates[AC97_RATES_FRONT_DAC] = SNDRV_PCM_RATE_48000;
ac97->rates[AC97_RATES_ADC] = SNDRV_PCM_RATE_48000;
......@@ -1884,16 +1887,16 @@ int snd_ac97_mixer(ac97_bus_t * bus, ac97_t * _ac97, ac97_t ** rac97)
SNDRV_PCM_RATE_32000;
}
if (ac97->ext_id & AC97_EI_VRM) { /* MIC VRA support */
snd_ac97_determine_rates(ac97, AC97_PCM_MIC_ADC_RATE, &ac97->rates[AC97_RATES_MIC_ADC]);
snd_ac97_determine_rates(ac97, AC97_PCM_MIC_ADC_RATE, 0, &ac97->rates[AC97_RATES_MIC_ADC]);
} else {
ac97->rates[AC97_RATES_MIC_ADC] = SNDRV_PCM_RATE_48000;
}
if (ac97->ext_id & AC97_EI_SDAC) { /* SDAC support */
snd_ac97_determine_rates(ac97, AC97_PCM_SURR_DAC_RATE, &ac97->rates[AC97_RATES_SURR_DAC]);
snd_ac97_determine_rates(ac97, AC97_PCM_SURR_DAC_RATE, AC97_PCM_FRONT_DAC_RATE, &ac97->rates[AC97_RATES_SURR_DAC]);
ac97->scaps |= AC97_SCAP_SURROUND_DAC;
}
if (ac97->ext_id & AC97_EI_LDAC) { /* LDAC support */
snd_ac97_determine_rates(ac97, AC97_PCM_LFE_DAC_RATE, &ac97->rates[AC97_RATES_LFE_DAC]);
snd_ac97_determine_rates(ac97, AC97_PCM_LFE_DAC_RATE, AC97_PCM_FRONT_DAC_RATE, &ac97->rates[AC97_RATES_LFE_DAC]);
ac97->scaps |= AC97_SCAP_CENTER_LFE_DAC;
}
/* additional initializations */
......@@ -2112,6 +2115,8 @@ static int swap_headphone(ac97_t *ac97, int remove_master)
{
/* FIXME: error checks.. */
if (remove_master) {
if (ctl_find(ac97, "Headphone Playback Switch") == NULL)
return 0;
snd_ac97_remove_ctl(ac97, "Master Playback Switch");
snd_ac97_remove_ctl(ac97, "Master Playback Volume");
} else {
......
......@@ -652,7 +652,7 @@ int patch_ad1881(ac97_t * ac97)
static const snd_kcontrol_new_t snd_ac97_controls_ad1885[] = {
AC97_SINGLE("Digital Mono Direct", AC97_AD_MISC, 11, 1, 0),
AC97_SINGLE("Digital Audio Mode", AC97_AD_MISC, 12, 1, 0),
/* AC97_SINGLE("Digital Audio Mode", AC97_AD_MISC, 12, 1, 0), */ /* seems problematic */
AC97_SINGLE("Low Power Mixer", AC97_AD_MISC, 14, 1, 0),
AC97_SINGLE("Zero Fill DAC", AC97_AD_MISC, 15, 1, 0),
};
......@@ -682,6 +682,9 @@ int patch_ad1885(ac97_t * ac97)
jack = snd_ac97_read(ac97, AC97_AD_JACK_SPDIF);
snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, jack | 0x0300);
/* set default */
snd_ac97_write_cache(ac97, AC97_AD_MISC, 0x0404);
ac97->build_ops = &patch_ad1885_build_ops;
return 0;
}
......@@ -799,7 +802,7 @@ int patch_ad1981b(ac97_t *ac97)
return 0;
}
static int snd_ac97_ad1980_lohpsel_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
static int snd_ac97_ad1888_lohpsel_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->count = 1;
......@@ -808,7 +811,7 @@ static int snd_ac97_ad1980_lohpsel_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_i
return 0;
}
static int snd_ac97_ad1980_lohpsel_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t* ucontrol)
static int snd_ac97_ad1888_lohpsel_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t* ucontrol)
{
ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
unsigned short val;
......@@ -818,7 +821,7 @@ static int snd_ac97_ad1980_lohpsel_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_va
return 0;
}
static int snd_ac97_ad1980_lohpsel_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
static int snd_ac97_ad1888_lohpsel_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
unsigned short val;
......@@ -829,7 +832,7 @@ static int snd_ac97_ad1980_lohpsel_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_va
AC97_AD198X_LOSEL | AC97_AD198X_HPSEL, val);
}
static int snd_ac97_ad1980_downmix_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
static int snd_ac97_ad1888_downmix_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
{
static char *texts[3] = {"Off", "6 -> 4", "6 -> 2"};
......@@ -842,7 +845,7 @@ static int snd_ac97_ad1980_downmix_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_i
return 0;
}
static int snd_ac97_ad1980_downmix_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t* ucontrol)
static int snd_ac97_ad1888_downmix_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t* ucontrol)
{
ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
unsigned short val;
......@@ -855,7 +858,7 @@ static int snd_ac97_ad1980_downmix_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_va
return 0;
}
static int snd_ac97_ad1980_downmix_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
static int snd_ac97_ad1888_downmix_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
unsigned short val;
......@@ -871,51 +874,47 @@ static int snd_ac97_ad1980_downmix_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_va
AC97_AD198X_DMIX0 | AC97_AD198X_DMIX1, val);
}
static const snd_kcontrol_new_t snd_ac97_ad1980_controls[] = {
static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Exchange Front/Surround",
.info = snd_ac97_ad1980_lohpsel_info,
.get = snd_ac97_ad1980_lohpsel_get,
.put = snd_ac97_ad1980_lohpsel_put
.info = snd_ac97_ad1888_lohpsel_info,
.get = snd_ac97_ad1888_lohpsel_get,
.put = snd_ac97_ad1888_lohpsel_put
},
AC97_SINGLE("Spread Front to Surround and Center/LFE", AC97_AD_MISC, 7, 1, 0),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Downmix",
.info = snd_ac97_ad1980_downmix_info,
.get = snd_ac97_ad1980_downmix_get,
.put = snd_ac97_ad1980_downmix_put
.info = snd_ac97_ad1888_downmix_info,
.get = snd_ac97_ad1888_downmix_get,
.put = snd_ac97_ad1888_downmix_put
},
AC97_SINGLE("Surround Jack as Input", AC97_AD_MISC, 12, 1, 0),
AC97_SINGLE("Center/LFE Jack as Input", AC97_AD_MISC, 11, 1, 0),
};
static int patch_ad1980_specific(ac97_t *ac97)
static int patch_ad1888_specific(ac97_t *ac97)
{
int err;
/* rename 0x04 as "Master" and 0x02 as "Master Surround" */
snd_ac97_rename_ctl(ac97, "Master Playback Switch", "Master Surround Playback Switch");
snd_ac97_rename_ctl(ac97, "Master Playback Volume", "Master Surround Playback Volume");
snd_ac97_rename_ctl(ac97, "Headphone Playback Switch", "Master Playback Switch");
snd_ac97_rename_ctl(ac97, "Headphone Playback Volume", "Master Playback Volume");
if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0)
return err;
return patch_build_controls(ac97, snd_ac97_ad1980_controls, ARRAY_SIZE(snd_ac97_ad1980_controls));
return patch_build_controls(ac97, snd_ac97_ad1888_controls, ARRAY_SIZE(snd_ac97_ad1888_controls));
}
static struct snd_ac97_build_ops patch_ad1980_build_ops = {
static struct snd_ac97_build_ops patch_ad1888_build_ops = {
.build_post_spdif = patch_ad198x_post_spdif,
.build_specific = patch_ad1980_specific
.build_specific = patch_ad1888_specific
};
int patch_ad1980(ac97_t * ac97)
int patch_ad1888(ac97_t * ac97)
{
unsigned short misc;
patch_ad1881(ac97);
ac97->build_ops = &patch_ad1980_build_ops;
ac97->build_ops = &patch_ad1888_build_ops;
/* Switch FRONT/SURROUND LINE-OUT/HP-OUT default connection */
/* it seems that most vendors connect line-out connector to headphone out of AC'97 */
/* AD-compatible mode */
......@@ -930,6 +929,27 @@ int patch_ad1980(ac97_t * ac97)
return 0;
}
static int patch_ad1980_specific(ac97_t *ac97)
{
int err;
if ((err = patch_ad1888_specific(ac97)) < 0)
return err;
return patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1);
}
static struct snd_ac97_build_ops patch_ad1980_build_ops = {
.build_post_spdif = patch_ad198x_post_spdif,
.build_specific = patch_ad1980_specific
};
int patch_ad1980(ac97_t * ac97)
{
patch_ad1888(ac97);
ac97->build_ops = &patch_ad1980_build_ops;
return 0;
}
static const snd_kcontrol_new_t snd_ac97_ad1985_controls[] = {
AC97_SINGLE("Center/LFE Jack as Mic", AC97_AD_SERIAL_CFG, 9, 1, 0),
AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0)
......@@ -1014,8 +1034,7 @@ static int snd_ac97_alc650_mic_gpio_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_v
ucontrol->value.integer.value[0] ? (1 << 10) : 0);
if (change) {
/* GPIO0 write for mic */
snd_ac97_update_bits(ac97, 0x76, 0x01,
ucontrol->value.integer.value[0] ? 0 : 0x01);
snd_ac97_update_bits(ac97, 0x76, 0x01, 0x01);
/* GPIO0 high for mic */
snd_ac97_update_bits(ac97, 0x78, 0x100,
ucontrol->value.integer.value[0] ? 0 : 0x100);
......@@ -1092,9 +1111,6 @@ int patch_alc650(ac97_t * ac97)
mic_off = snd_ac97_read(ac97, AC97_ALC650_MULTICH) & (1 << 10);
/* GPIO0 direction */
val = snd_ac97_read(ac97, AC97_ALC650_GPIO_SETUP);
if (mic_off)
val &= ~0x01;
else
val |= 0x01;
snd_ac97_write_cache(ac97, AC97_ALC650_GPIO_SETUP, val);
val = snd_ac97_read(ac97, AC97_ALC650_GPIO_STATUS);
......@@ -1111,10 +1127,36 @@ int patch_alc650(ac97_t * ac97)
return 0;
}
static int snd_ac97_alc655_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
{
ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1;
return 0;
}
static int snd_ac97_alc655_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
{
ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
int change;
snd_ac97_update_bits(ac97, 0x7a, 1 << 12, /* misc control; vrefout disable */
ucontrol->value.integer.value[0] ? (1 << 12) : 0);
change = snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10,
ucontrol->value.integer.value[0] ? (1 << 10) : 0);
return change;
}
static const snd_kcontrol_new_t snd_ac97_controls_alc655[] = {
AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0),
AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0),
AC97_SINGLE("Mic As Center/LFE", AC97_ALC650_MULTICH, 10, 1, 0),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Mic As Center/LFE",
.info = snd_ac97_info_single,
.get = snd_ac97_alc655_mic_get,
.put = snd_ac97_alc655_mic_put,
},
};
static int alc655_iec958_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
......@@ -1187,15 +1229,21 @@ static struct snd_ac97_build_ops patch_alc655_ops = {
int patch_alc655(ac97_t * ac97)
{
unsigned int val;
ac97->spec.dev_flags = (ac97->id == 0x414c4780); /* ALC658 */
ac97->build_ops = &patch_alc655_ops;
/* enable spdif in */
snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK,
snd_ac97_read(ac97, AC97_ALC650_MULTICH) | 0x8000);
snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK,
snd_ac97_read(ac97, AC97_ALC650_CLOCK) | 0x02);
/* adjust default values */
val = snd_ac97_read(ac97, 0x7a); /* misc control */
val |= (1 << 1); /* spdif input pin */
val &= ~(1 << 12); /* vref enable */
snd_ac97_write_cache(ac97, 0x7a, val);
val = snd_ac97_read(ac97, AC97_ALC650_MULTICH);
val |= (1 << 15); /* enable spdif in */
val &= ~(1 << 10); /* disable center on mic */
snd_ac97_write_cache(ac97, AC97_ALC650_MULTICH, val);
/* full DAC volume */
snd_ac97_write_cache(ac97, AC97_ALC650_SURR_DAC_VOL, 0x0808);
......
......@@ -41,6 +41,7 @@ int patch_ad1819(ac97_t * ac97);
int patch_ad1881(ac97_t * ac97);
int patch_ad1885(ac97_t * ac97);
int patch_ad1886(ac97_t * ac97);
int patch_ad1888(ac97_t * ac97);
int patch_ad1980(ac97_t * ac97);
int patch_ad1981a(ac97_t * ac97);
int patch_ad1981b(ac97_t * ac97);
......
......@@ -2375,6 +2375,7 @@ static int __devinit snd_ice1712_create(snd_card_t * card,
ice->omni = omni ? 1 : 0;
spin_lock_init(&ice->reg_lock);
init_MUTEX(&ice->gpio_mutex);
init_MUTEX(&ice->open_mutex);
ice->gpio.set_mask = snd_ice1712_set_gpio_mask;
ice->gpio.set_dir = snd_ice1712_set_gpio_dir;
ice->gpio.set_data = snd_ice1712_set_gpio_data;
......
......@@ -335,6 +335,9 @@ struct _snd_ice1712 {
unsigned short hoontech_boxconfig[4];
unsigned int cur_rate; /* current rate */
struct semaphore open_mutex;
snd_pcm_substream_t *pcm_reserved[4];
unsigned int akm_codecs;
akm4xxx_t *akm;
struct snd_ice1712_spdif spdif;
......
This diff is collapsed.
......@@ -143,6 +143,9 @@ MODULE_PARM_SYNTAX(mpu_port, SNDRV_ENABLED ",allows:{{0},{0x330},{0x300}},dialog
#ifndef PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO
#define PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO 0x00da
#endif
#ifndef PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO
#define PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO 0x00ea
#endif
enum { DEVICE_INTEL, DEVICE_INTEL_ICH4, DEVICE_SIS, DEVICE_ALI, DEVICE_NFORCE };
......@@ -443,6 +446,7 @@ static struct pci_device_id snd_intel8x0_ids[] = {
{ 0x10de, 0x01b1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE */
{ 0x10de, 0x006a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE2 */
{ 0x10de, 0x00da, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE3 */
{ 0x10de, 0x00ea, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* CK8S */
{ 0x1022, 0x746d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD8111 */
{ 0x1022, 0x7445, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD768 */
{ 0x10b9, 0x5455, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALI }, /* Ali5455 */
......@@ -804,10 +808,19 @@ static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id, struct pt_regs
spin_lock(&chip->reg_lock);
status = igetdword(chip, chip->int_sta_reg);
if ((status & chip->int_sta_mask) == 0) {
if (status)
static int err_count = 10;
if (status) {
/* ack */
iputdword(chip, chip->int_sta_reg, status);
status ^= igetdword(chip, chip->int_sta_reg);
}
spin_unlock(&chip->reg_lock);
return IRQ_NONE;
if (status && err_count) {
err_count--;
snd_printd("intel8x0: unknown IRQ bits 0x%x (sta_mask=0x%x)\n",
status, chip->int_sta_mask);
}
return IRQ_RETVAL(status);
}
for (i = 0; i < chip->bdbars_count; i++) {
......@@ -1017,6 +1030,7 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(snd_pcm_substream_t * substrea
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
ichdev_t *ichdev = get_ichdev(substream);
unsigned long flags;
size_t ptr1, ptr;
ptr1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << chip->pcm_pos_shift;
......@@ -1024,7 +1038,9 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(snd_pcm_substream_t * substrea
ptr = ichdev->fragsize1 - ptr1;
else
ptr = 0;
spin_lock_irqsave(&chip->reg_lock, flags);
ptr += ichdev->position;
spin_unlock_irqrestore(&chip->reg_lock, flags);
if (ptr >= ichdev->size)
return 0;
return bytes_to_frames(substream->runtime, ptr);
......@@ -1739,6 +1755,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
.name = "Intel ICH5/AD1985",
.type = AC97_TUNE_AD_SHARING
},
{
.vendor = 0x8086,
.device = 0x4856,
.name = "Intel D845WN (82801BA)",
.type = AC97_TUNE_SWAP_HP
},
{
.vendor = 0x8086,
.device = 0x4d44,
......@@ -2567,6 +2589,7 @@ static struct shortname_table {
{ PCI_DEVICE_ID_NVIDIA_MCP_AUDIO, "NVidia nForce" },
{ PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO, "NVidia nForce2" },
{ PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO, "NVidia nForce3" },
{ PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO, "NVidia CK8S" },
{ 0x746d, "AMD AMD8111" },
{ 0x7445, "AMD AMD768" },
{ 0x5455, "ALi M5455" },
......
#
# Makefile for ALSA
# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
#
snd-mixart-objs := mixart.o mixart_core.o mixart_hwdep.o mixart_mixer.o
obj-$(CONFIG_SND_MIXART) += snd-mixart.o
This diff is collapsed.
/*
* Driver for Digigram miXart soundcards
*
* main header file
*
* Copyright (c) 2003 by Digigram <alsa@digigram.com>
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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
*/
#ifndef __SOUND_MIXART_H
#define __SOUND_MIXART_H
#include <sound/pcm.h>
#define MIXART_DRIVER_VERSION 0x000100 /* 0.1.0 */
/*
*/
#define mixart_t_magic 0xa17a3e01
#define mixart_mgr_t_magic 0xa17a3e02
typedef struct snd_mixart mixart_t;
typedef struct snd_mixart_mgr mixart_mgr_t;
typedef struct snd_mixart_stream mixart_stream_t;
typedef struct snd_mixart_pipe mixart_pipe_t;
typedef struct mixart_bufferinfo mixart_bufferinfo_t;
typedef struct mixart_flowinfo mixart_flowinfo_t;
typedef struct mixart_uid mixart_uid_t;
struct mixart_uid
{
u32 object_id;
u32 desc;
};
struct mem_area {
unsigned long phys;
unsigned long virt;
struct resource *res;
};
typedef struct mixart_route mixart_route_t;
struct mixart_route {
unsigned char connected;
unsigned char phase_inv;
int volume;
};
/* firmware status codes */
#define MIXART_MOTHERBOARD_XLX_INDEX 0
#define MIXART_MOTHERBOARD_ELF_INDEX 1
#define MIXART_AESEBUBOARD_XLX_INDEX 2
#define MIXART_HARDW_FILES_MAX_INDEX 3 /* xilinx, elf, AESEBU xilinx */
#define MIXART_MAX_CARDS 4
#define MSG_FIFO_SIZE 16
#define MIXART_MAX_PHYS_CONNECTORS (MIXART_MAX_CARDS * 2 * 2) /* 4 * stereo * (analog+digital) */
struct snd_mixart_mgr {
unsigned int num_cards;
mixart_t *chip[MIXART_MAX_CARDS];
struct pci_dev *pci;
int irq;
/* memory-maps */
struct mem_area mem[2];
/* share the name */
char shortname[32]; /* short name of this soundcard */
char longname[80]; /* name of this soundcard */
/* message tasklet */
struct tasklet_struct msg_taskq;
/* one and only blocking message or notification may be pending */
u32 pending_event;
wait_queue_head_t msg_sleep;
/* messages stored for tasklet */
u32 msg_fifo[MSG_FIFO_SIZE];
int msg_fifo_readptr;
int msg_fifo_writeptr;
spinlock_t lock; /* interrupt spinlock */
spinlock_t msg_lock; /* mailbox spinlock */
struct semaphore msg_mutex; /* mutex for blocking_requests */
struct semaphore setup_mutex; /* mutex used in hw_params, open and close */
/* hardware interface */
snd_hwdep_t *hwdep;
unsigned int board_type; /* read from embedded once elf file is loaded, 250 = miXart8, 251 = with AES, 252 = with Cobranet */
mixart_flowinfo_t* flowinfo_array;
dma_addr_t flowinfo_physaddr;
mixart_bufferinfo_t* bufferinfo_array;
dma_addr_t bufferinfo_physaddr;
mixart_uid_t uid_console_manager;
int sample_rate;
int ref_count_rate;
struct semaphore mixer_mutex; /* mutex for mixer */
};
#define MIXART_STREAM_STATUS_FREE 0
#define MIXART_STREAM_STATUS_OPEN 1
#define MIXART_STREAM_STATUS_RUNNING 2
#define MIXART_STREAM_STATUS_DRAINING 3
#define MIXART_STREAM_STATUS_PAUSE 4
#define MIXART_PLAYBACK_STREAMS 4
#define MIXART_CAPTURE_STREAMS 1
#define MIXART_PCM_ANALOG 0
#define MIXART_PCM_DIGITAL 1
#define MIXART_PCM_TOTAL 2
#define MIXART_MAX_STREAM_PER_CARD (MIXART_PCM_TOTAL * (MIXART_PLAYBACK_STREAMS + MIXART_CAPTURE_STREAMS) )
#define MIXART_NOTIFY_CARD_MASK 0xF000
#define MIXART_NOTIFY_CARD_OFFSET 12
#define MIXART_NOTIFY_PCM_MASK 0x0F00
#define MIXART_NOTIFY_PCM_OFFSET 8
#define MIXART_NOTIFY_CAPT_MASK 0x0080
#define MIXART_NOTIFY_SUBS_MASK 0x007F
struct snd_mixart_stream {
snd_pcm_substream_t *substream;
mixart_pipe_t *pipe;
int pcm_number;
int status; /* nothing, running, draining */
u64 abs_period_elapsed; /* last absolute stream position where period_elapsed was called (multiple of runtime->period_size) */
u32 buf_periods; /* periods counter in the buffer (< runtime->periods) */
u32 buf_period_frag; /* defines with buf_period_pos the exact position in the buffer (< runtime->period_size) */
int channels;
};
enum mixart_pipe_status {
PIPE_UNDEFINED,
PIPE_STOPPED,
PIPE_RUNNING,
PIPE_CLOCK_SET
};
struct snd_mixart_pipe {
mixart_uid_t group_uid; /* id of the pipe, as returned by embedded */
int stream_count;
mixart_uid_t uid_left_connector; /* UID's for the audio connectors */
mixart_uid_t uid_right_connector;
enum mixart_pipe_status status;
int references; /* number of subs openned */
int monitoring; /* pipe used for monitoring issue */
};
struct snd_mixart {
snd_card_t *card;
mixart_mgr_t *mgr;
int chip_idx; /* zero based */
snd_hwdep_t *hwdep; /* DSP loader, only for the first card */
snd_pcm_t *pcm; /* PCM analog i/o */
snd_pcm_t *pcm_dig; /* PCM digital i/o */
/* allocate stereo pipe for instance */
mixart_pipe_t pipe_in_ana;
mixart_pipe_t pipe_out_ana;
/* if AES/EBU daughter board is available, additional pipes possible on pcm_dig */
mixart_pipe_t pipe_in_dig;
mixart_pipe_t pipe_out_dig;
mixart_stream_t playback_stream[MIXART_PCM_TOTAL][MIXART_PLAYBACK_STREAMS]; /* 0 = pcm, 1 = pcm_dig */
mixart_stream_t capture_stream[MIXART_PCM_TOTAL]; /* 0 = pcm, 1 = pcm_dig */
/* UID's for the physical io's */
mixart_uid_t uid_out_analog_physio;
mixart_uid_t uid_in_analog_physio;
int analog_playback_active[2]; /* Mixer : Master Playback active (!mute) */
int analog_playback_volume[2]; /* Mixer : Master Playback Volume */
int analog_capture_volume[2]; /* Mixer : Master Capture Volume */
int digital_playback_active[2*MIXART_PLAYBACK_STREAMS][2]; /* Mixer : Digital Playback Active [(analog+AES output)*streams][stereo]*/
int digital_playback_volume[2*MIXART_PLAYBACK_STREAMS][2]; /* Mixer : Digital Playback Volume [(analog+AES output)*streams][stereo]*/
int digital_capture_volume[2][2]; /* Mixer : Digital Capture Volume [analog+AES output][stereo] */
int monitoring_active[2]; /* Mixer : Monitoring Active */
int monitoring_volume[2]; /* Mixer : Monitoring Volume */
};
struct mixart_bufferinfo
{
u32 buffer_address;
u32 reserved[5];
u32 available_length;
u32 buffer_id;
};
struct mixart_flowinfo
{
u32 bufferinfo_array_phy_address;
u32 reserved[11];
u32 bufferinfo_count;
u32 capture;
};
/* exported */
int snd_mixart_create_pcm(mixart_t* chip);
mixart_pipe_t* snd_mixart_add_ref_pipe( mixart_t *chip, int pcm_number, int capture, int monitoring);
int snd_mixart_kill_ref_pipe( mixart_mgr_t *mgr, mixart_pipe_t *pipe, int monitoring);
#endif /* __SOUND_MIXART_H */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* Driver for Digigram miXart soundcards
*
* definitions and makros for basic card access
*
* Copyright (c) 2003 by Digigram <alsa@digigram.com>
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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
*/
#ifndef __SOUND_MIXART_HWDEP_H
#define __SOUND_MIXART_HWDEP_H
#include <sound/hwdep.h>
#define readl_be(x) be32_to_cpu(__raw_readl(x))
#define writel_be(data,addr) __raw_writel(cpu_to_be32(data),addr)
#define readl_le(x) le32_to_cpu(__raw_readl(x))
#define writel_le(data,addr) __raw_writel(cpu_to_le32(data),addr)
#define MIXART_MEM(mgr,x) ((mgr)->mem[0].virt + (x))
#define MIXART_REG(mgr,x) ((mgr)->mem[1].virt + (x))
/* Daughter board Type */
#define DAUGHTER_TYPE_MASK 0x0F
#define DAUGHTER_VER_MASK 0xF0
#define DAUGHTER_TYPEVER_MASK (DAUGHTER_TYPE_MASK|DAUGHTER_VER_MASK)
#define MIXART_DAUGHTER_TYPE_NONE 0x00
#define MIXART_DAUGHTER_TYPE_COBRANET 0x08
#define MIXART_DAUGHTER_TYPE_AES 0x0E
#define MIXART_BA0_SIZE (16 * 1024 * 1024) /* 16M */
#define MIXART_BA1_SIZE (4 * 1024) /* 4k */
/*
* -----------BAR 0 --------------------------------------------------------------------------------------------------------
*/
#define MIXART_PSEUDOREG 0x2000 /* base address for pseudoregister */
#define MIXART_PSEUDOREG_BOARDNUMBER MIXART_PSEUDOREG+0 /* board number */
/* perfmeter (available when elf loaded)*/
#define MIXART_PSEUDOREG_PERF_STREAM_LOAD_OFFSET MIXART_PSEUDOREG+0x70 /* streaming load */
#define MIXART_PSEUDOREG_PERF_SYSTEM_LOAD_OFFSET MIXART_PSEUDOREG+0x78 /* system load (reference)*/
#define MIXART_PSEUDOREG_PERF_MAILBX_LOAD_OFFSET MIXART_PSEUDOREG+0x7C /* mailbox load */
#define MIXART_PSEUDOREG_PERF_INTERR_LOAD_OFFSET MIXART_PSEUDOREG+0x74 /* interrupt handling load */
/* motherboard xilinx loader info */
#define MIXART_PSEUDOREG_MXLX_BASE_ADDR_OFFSET MIXART_PSEUDOREG+0x9C /* 0x00600000 */
#define MIXART_PSEUDOREG_MXLX_SIZE_OFFSET MIXART_PSEUDOREG+0xA0 /* xilinx size in bytes */
#define MIXART_PSEUDOREG_MXLX_STATUS_OFFSET MIXART_PSEUDOREG+0xA4 /* status = EMBEBBED_STAT_XXX */
/* elf loader info */
#define MIXART_PSEUDOREG_ELF_STATUS_OFFSET MIXART_PSEUDOREG+0xB0 /* status = EMBEBBED_STAT_XXX */
/*
* after the elf code is loaded, and the flowtable info was passed to it,
* the driver polls on this address, until it shows 1 (presence) or 2 (absence)
* once it is non-zero, the daughter board type may be read
*/
#define MIXART_PSEUDOREG_DBRD_PRESENCE_OFFSET MIXART_PSEUDOREG+0x990
/* Global info structure */
#define MIXART_PSEUDOREG_DBRD_TYPE_OFFSET MIXART_PSEUDOREG+0x994 /* Type and version of daughterboard */
/* daughterboard xilinx loader info */
#define MIXART_PSEUDOREG_DXLX_BASE_ADDR_OFFSET MIXART_PSEUDOREG+0x998 /* get the address here where to write the file */
#define MIXART_PSEUDOREG_DXLX_SIZE_OFFSET MIXART_PSEUDOREG+0x99C /* xilinx size in bytes */
#define MIXART_PSEUDOREG_DXLX_STATUS_OFFSET MIXART_PSEUDOREG+0x9A0 /* status = EMBEBBED_STAT_XXX */
/* */
#define MIXART_FLOWTABLE_PTR 0x3000 /* pointer to flow table */
/* mailbox addresses */
/* message DRV -> EMB */
#define MSG_INBOUND_POST_HEAD 0x010008 /* DRV posts MF + increment4 */
#define MSG_INBOUND_POST_TAIL 0x01000C /* EMB gets MF + increment4 */
/* message EMB -> DRV */
#define MSG_OUTBOUND_POST_TAIL 0x01001C /* DRV gets MF + increment4 */
#define MSG_OUTBOUND_POST_HEAD 0x010018 /* EMB posts MF + increment4 */
/* Get Free Frames */
#define MSG_INBOUND_FREE_TAIL 0x010004 /* DRV gets MFA + increment4 */
#define MSG_OUTBOUND_FREE_TAIL 0x010014 /* EMB gets MFA + increment4 */
/* Put Free Frames */
#define MSG_OUTBOUND_FREE_HEAD 0x010010 /* DRV puts MFA + increment4 */
#define MSG_INBOUND_FREE_HEAD 0x010000 /* EMB puts MFA + increment4 */
/* firmware addresses of the message fifos */
#define MSG_BOUND_STACK_SIZE 0x004000 /* size of each following stack */
/* posted messages */
#define MSG_OUTBOUND_POST_STACK 0x108000 /* stack of messages to the DRV */
#define MSG_INBOUND_POST_STACK 0x104000 /* stack of messages to the EMB */
/* available empty messages */
#define MSG_OUTBOUND_FREE_STACK 0x10C000 /* stack of free enveloped for EMB */
#define MSG_INBOUND_FREE_STACK 0x100000 /* stack of free enveloped for DRV */
/* defines for mailbox message frames */
#define MSG_FRAME_OFFSET 0x64
#define MSG_FRAME_SIZE 0x6400
#define MSG_FRAME_NUMBER 32
#define MSG_FROM_AGENT_ITMF_OFFSET (MSG_FRAME_OFFSET + (MSG_FRAME_SIZE * MSG_FRAME_NUMBER))
#define MSG_TO_AGENT_ITMF_OFFSET (MSG_FROM_AGENT_ITMF_OFFSET + MSG_FRAME_SIZE)
#define MSG_HOST_RSC_PROTECTION (MSG_TO_AGENT_ITMF_OFFSET + MSG_FRAME_SIZE)
#define MSG_AGENT_RSC_PROTECTION (MSG_HOST_RSC_PROTECTION + 4)
/*
* -----------BAR 1 --------------------------------------------------------------------------------------------------------
*/
/* interrupt addresses and constants */
#define MIXART_PCI_OMIMR_OFFSET 0x34 /* outbound message interrupt mask register */
#define MIXART_PCI_OMISR_OFFSET 0x30 /* outbound message interrupt status register */
#define MIXART_PCI_ODBR_OFFSET 0x60 /* outbound doorbell register */
#define MIXART_BA1_BRUTAL_RESET_OFFSET 0x68 /* write 1 in LSBit to reset board */
#define MIXART_HOST_ALL_INTERRUPT_MASKED 0x02B /* 0000 0010 1011 */
#define MIXART_ALLOW_OUTBOUND_DOORBELL 0x023 /* 0000 0010 0011 */
#define MIXART_OIDI 0x008 /* 0000 0000 1000 */
/* exported */
int snd_mixart_hwdep_new(mixart_mgr_t *mgr);
#endif /* __SOUND_MIXART_HWDEP_H */
This diff is collapsed.
/*
* Driver for Digigram miXart soundcards
*
* include file for mixer
*
* Copyright (c) 2003 by Digigram <alsa@digigram.com>
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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
*/
#ifndef __SOUND_MIXART_MIXER_H
#define __SOUND_MIXART_MIXER_H
/* exported */
int mixart_update_playback_stream_level(mixart_t* chip, int is_aes, int idx);
int mixart_update_capture_stream_level(mixart_t* chip, int is_aes);
int snd_mixart_create_mixer(mixart_mgr_t* mgr);
#endif /* __SOUND_MIXART_MIXER_H */
......@@ -922,12 +922,10 @@ static int snd_via8233_playback_prepare(snd_pcm_substream_t *substream)
chip->no_vra ? 48000 : runtime->rate);
snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate);
}
#if 0
if (chip->revision == VIA_REV_8233A)
rbits = 0;
if (runtime->rate == 48000)
rbits = 0xfffff;
else
#endif
rbits = (0xfffff / 48000) * runtime->rate + ((0xfffff % 48000) * runtime->rate) / 48000;
rbits = (0x100000 / 48000) * runtime->rate + ((0x100000 % 48000) * runtime->rate) / 48000;
snd_assert((rbits & ~0xfffff) == 0, return -EINVAL);
snd_via82xx_channel_reset(chip, viadev);
snd_via82xx_set_table_ptr(chip, viadev);
......@@ -1989,11 +1987,12 @@ static int __devinit check_dxs_list(struct pci_dev *pci)
{ .vendor = 0x1106, .device = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */
{ .vendor = 0x1297, .device = 0xa232, .action = VIA_DXS_ENABLE }, /* Shuttle ?? */
{ .vendor = 0x1297, .device = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */
{ .vendor = 0x1458, .device = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */
{ .vendor = 0x1458, .device = 0xa002, .action = VIA_DXS_NO_VRA }, /* Gigabyte GA-7VAXP (FIXME: or DXS_ENABLE?) */
{ .vendor = 0x147b, .device = 0x1401, .action = VIA_DXS_ENABLE }, /* ABIT KD7(-RAID) */
{ .vendor = 0x14ff, .device = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */
{ .vendor = 0x1462, .device = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */
{ .vendor = 0x1462, .device = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */
{ .vendor = 0x1462, .device = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */
{ .vendor = 0x1631, .device = 0xe004, .action = VIA_DXS_ENABLE }, /* Easy Note 3174, Packard Bell */
{ .vendor = 0x1695, .device = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */
{ .vendor = 0x1849, .device = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */
......
......@@ -117,7 +117,7 @@ struct audioformat {
struct list_head list;
snd_pcm_format_t format; /* format type */
unsigned int channels; /* # channels */
unsigned int nonaudio: 1; /* non-audio (type II) */
unsigned int fmt_type; /* USB audio format type (1-3) */
unsigned int frame_size; /* samples per frame for non-audio */
int iface; /* interface number */
unsigned char altsetting; /* corresponding alternate setting */
......@@ -171,7 +171,7 @@ struct snd_usb_substream {
unsigned int curpacksize; /* current packet size in bytes (for capture) */
unsigned int curframesize; /* current packet size in frames (for capture) */
unsigned int fill_max: 1; /* fill max packet size always */
unsigned int nonaudio: 1; /* Type II format (MPEG, AC3) */
unsigned int fmt_type; /* USB audio format type (1-3) */
unsigned int running: 1; /* running status */
......@@ -201,6 +201,7 @@ struct snd_usb_stream {
snd_usb_audio_t *chip;
snd_pcm_t *pcm;
int pcm_index;
unsigned int fmt_type; /* USB audio format type (1-3) */
snd_usb_substream_t substream[2];
struct list_head list;
};
......@@ -477,7 +478,7 @@ static int prepare_playback_urb(snd_usb_substream_t *subs,
subs->transfer_sched += counts;
if (subs->transfer_sched >= runtime->period_size) {
subs->transfer_sched -= runtime->period_size;
if (subs->nonaudio) {
if (subs->fmt_type == USB_FORMAT_TYPE_II) {
if (subs->transfer_sched > 0) {
/* FIXME: fill-max mode is not supported yet */
offs -= subs->transfer_sched;
......@@ -894,7 +895,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
u->subs = subs;
u->transfer = 0;
u->packets = npacks[i];
if (subs->nonaudio)
if (subs->fmt_type == USB_FORMAT_TYPE_II)
u->packets++; /* for transfer delimiter */
if (! is_playback) {
/* allocate a capture buffer per urb */
......@@ -1588,7 +1589,7 @@ static int setup_hw_info(snd_pcm_runtime_t *runtime, snd_usb_substream_t *subs)
runtime->hw.channels_min = fp->channels;
if (runtime->hw.channels_max < fp->channels)
runtime->hw.channels_max = fp->channels;
if (fp->nonaudio && fp->frame_size > 0) {
if (fp->fmt_type == USB_FORMAT_TYPE_II && fp->frame_size > 0) {
/* FIXME: there might be more than one audio formats... */
runtime->hw.period_bytes_min = runtime->hw.period_bytes_max =
fp->frame_size;
......@@ -1895,7 +1896,7 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat
subs->formats |= 1ULL << fp->format;
subs->endpoint = fp->endpoint;
subs->num_formats++;
subs->nonaudio = fp->nonaudio;
subs->fmt_type = fp->fmt_type;
}
......@@ -1954,17 +1955,12 @@ static int add_audio_endpoint(snd_usb_audio_t *chip, int stream, struct audiofor
list_for_each(p, &chip->pcm_list) {
as = list_entry(p, snd_usb_stream_t, list);
if (as->fmt_type != fp->fmt_type)
continue;
subs = &as->substream[stream];
if (! subs->endpoint)
break;
if (subs->endpoint == fp->endpoint) {
if (fp->nonaudio) {
if (!subs->nonaudio || subs->formats != (1ULL << fp->format))
continue; /* non-linear formats are handled exclusively */
} else {
if (subs->nonaudio)
continue;
}
if (subs->endpoint == fp->endpoint) {
list_add_tail(&fp->list, &subs->fmt_list);
subs->num_formats++;
subs->formats |= 1ULL << fp->format;
......@@ -1974,6 +1970,8 @@ static int add_audio_endpoint(snd_usb_audio_t *chip, int stream, struct audiofor
/* look for an empty stream */
list_for_each(p, &chip->pcm_list) {
as = list_entry(p, snd_usb_stream_t, list);
if (as->fmt_type != fp->fmt_type)
continue;
subs = &as->substream[stream];
if (subs->endpoint)
continue;
......@@ -1991,6 +1989,7 @@ static int add_audio_endpoint(snd_usb_audio_t *chip, int stream, struct audiofor
memset(as, 0, sizeof(*as));
as->pcm_index = chip->pcm_devs;
as->chip = chip;
as->fmt_type = fp->fmt_type;
err = snd_pcm_new(chip->card, "USB Audio", chip->pcm_devs,
stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0,
stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1,
......@@ -2216,7 +2215,6 @@ static int parse_audio_format_ii(struct usb_device *dev, struct audioformat *fp,
break;
}
fp->channels = 1;
fp->nonaudio = 1;
brate = combine_word(&fmt[4]); /* fmt[4,5] : wMaxBitRate (in kbps) */
framesize = combine_word(&fmt[6]); /* fmt[6,7]: wSamplesPerFrame */
snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize);
......@@ -2242,6 +2240,7 @@ static int parse_audio_format(struct usb_device *dev, struct audioformat *fp,
dev->devnum, fp->iface, fp->altsetting, fmt[3]);
return -1;
}
fp->fmt_type = fmt[3];
if (err < 0)
return err;
#if 1
......
......@@ -501,6 +501,32 @@ YAMAHA_DEVICE(0x5008, "01V96"),
}
}
},
{
/*
* This quirk is for the "Advanced Driver" mode. If off, the UA-3FX
* is standard compliant, but has only 16-bit PCM.
*/
USB_DEVICE(0x0582, 0x0050),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "EDIROL",
.product_name = "UA-3FX",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_COMPOSITE,
.data = & (const snd_usb_audio_quirk_t[]) {
{
.ifnum = 1,
.type = QUIRK_AUDIO_STANDARD_INTERFACE
},
{
.ifnum = 2,
.type = QUIRK_AUDIO_STANDARD_INTERFACE
},
{
.ifnum = -1
}
}
}
},
{
USB_DEVICE(0x0582, 0x0052),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
......@@ -688,4 +714,14 @@ YAMAHA_DEVICE(0x5008, "01V96"),
},
{
USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0013),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Terratec",
.product_name = "PHASE 26",
.ifnum = 3,
.type = QUIRK_MIDI_STANDARD_INTERFACE
}
},
#undef USB_DEVICE_VENDOR_SPEC
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment