Commit 2f2fc324 authored by Jaroslav Kysela's avatar Jaroslav Kysela

Merge http://linux.bkbits.net/linux-2.5

into suse.cz:/home/perex/bk/linux-sound/linux-sound
parents 7f9f9f51 bf734625
...@@ -63,7 +63,6 @@ ...@@ -63,7 +63,6 @@
#define DSP_SPDIF_STATUS_OUTPUT_ENABLED 1 #define DSP_SPDIF_STATUS_OUTPUT_ENABLED 1
#define DSP_SPDIF_STATUS_PLAYBACK_OPEN 2 #define DSP_SPDIF_STATUS_PLAYBACK_OPEN 2
#define DSP_SPDIF_STATUS_HW_ENABLED 4 #define DSP_SPDIF_STATUS_HW_ENABLED 4
#define DSP_SPDIF_STATUS_AC3_MODE 8
struct _dsp_module_desc_t; struct _dsp_module_desc_t;
...@@ -196,6 +195,10 @@ typedef struct _dsp_spos_instance_t { ...@@ -196,6 +195,10 @@ typedef struct _dsp_spos_instance_t {
int spdif_status_in; int spdif_status_in;
u16 spdif_input_volume_right; u16 spdif_input_volume_right;
u16 spdif_input_volume_left; u16 spdif_input_volume_left;
/* spdif channel status,
left right and user validity bits */
int spdif_csuv_default;
int spdif_csuv_stream;
/* SPDIF input sample rate converter */ /* SPDIF input sample rate converter */
dsp_scb_descriptor_t * spdif_in_src; dsp_scb_descriptor_t * spdif_in_src;
......
...@@ -101,10 +101,18 @@ ...@@ -101,10 +101,18 @@
/* Global registers */ /* Global registers */
enum global_control_bits { enum global_control_bits {
CHANNEL_IDX = 0x0000003f, OVERRUN_IE = 0x00000400, CHANNEL_IDX = 0x0000003f,
UNDERRUN_IE = 0x00000800, ENDLP_IE = 0x00001000, OVERRUN_IE = 0x00000400, /* interrupt enable: capture overrun */
MIDLP_IE = 0x00002000, ETOG_IE = 0x00004000, UNDERRUN_IE = 0x00000800, /* interrupt enable: playback underrun */
EDROP_IE = 0x00008000, BANK_B_EN = 0x00010000 ENDLP_IE = 0x00001000, /* interrupt enable: end of buffer */
MIDLP_IE = 0x00002000, /* interrupt enable: middle buffer */
ETOG_IE = 0x00004000, /* interrupt enable: envelope toggling */
EDROP_IE = 0x00008000, /* interrupt enable: envelope drop */
BANK_B_EN = 0x00010000, /* SiS: enable bank B (64 channels) */
PCMIN_B_MIX = 0x00020000, /* SiS: PCM IN B mixing enable */
I2S_OUT_ASSIGN = 0x00040000, /* SiS: I2S Out contains surround PCM */
SPDIF_OUT_ASSIGN= 0x00080000, /* SiS: 0=S/PDIF L/R | 1=PCM Out FIFO */
MAIN_OUT_ASSIGN = 0x00100000, /* SiS: 0=PCM Out FIFO | 1=MMC Out buffer */
}; };
enum miscint_bits { enum miscint_bits {
...@@ -423,6 +431,8 @@ struct _snd_trident { ...@@ -423,6 +431,8 @@ struct _snd_trident {
int ChanPCM; /* max number of PCM channels */ int ChanPCM; /* max number of PCM channels */
int ChanPCMcnt; /* actual number of PCM channels */ int ChanPCMcnt; /* actual number of PCM channels */
int ac97_detect; /* 1 = AC97 in detection phase */
struct _snd_4dwave synth; /* synth specific variables */ struct _snd_4dwave synth; /* synth specific variables */
spinlock_t event_lock; spinlock_t event_lock;
......
/* include/version.h. Generated automatically by configure. */ /* include/version.h. Generated automatically by configure. */
#define CONFIG_SND_VERSION "0.9.0rc5" #define CONFIG_SND_VERSION "0.9.0rc5"
#define CONFIG_SND_DATE " (Sun Nov 10 19:48:18 2002 UTC)" #define CONFIG_SND_DATE " (Sat Nov 23 10:12:47 2002 UTC)"
...@@ -266,7 +266,6 @@ static int snd_opl3_seq_new_device(snd_seq_device_t *dev) ...@@ -266,7 +266,6 @@ static int snd_opl3_seq_new_device(snd_seq_device_t *dev)
snd_seq_fm_init(&opl3->fm_ops, NULL); snd_seq_fm_init(&opl3->fm_ops, NULL);
/* setup system timer */ /* setup system timer */
memset(&opl3->tlist, 0, sizeof(opl3->tlist));
init_timer(&opl3->tlist); init_timer(&opl3->tlist);
opl3->tlist.function = snd_opl3_timer_func; opl3->tlist.function = snd_opl3_timer_func;
opl3->tlist.data = (unsigned long) opl3; opl3->tlist.data = (unsigned long) opl3;
......
...@@ -51,6 +51,9 @@ ...@@ -51,6 +51,9 @@
#define SNDRV_GET_ID #define SNDRV_GET_ID
#include <sound/initval.h> #include <sound/initval.h>
/* hack: OSS defines midi_devs, so undefine it (versioned symbols) */
#undef midi_devs
MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
MODULE_DESCRIPTION("Dummy soundcard for virtual rawmidi devices"); MODULE_DESCRIPTION("Dummy soundcard for virtual rawmidi devices");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
......
...@@ -10,6 +10,12 @@ ...@@ -10,6 +10,12 @@
* Note: 16-bit wide is assigned to first direction which made request. * Note: 16-bit wide is assigned to first direction which made request.
* With full duplex - playback is preferred with abstract layer. * With full duplex - playback is preferred with abstract layer.
* *
* Note: Some chip revisions have hardware bug. Changing capture
* channel from full-duplex 8bit DMA to 16bit DMA will block
* 16bit DMA transfers from DSP chip (capture) until 8bit transfer
* to DSP chip (playback) starts. This bug can be avoided with
* "16bit DMA Allocation" setting set to Playback or Capture.
*
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
......
...@@ -950,15 +950,15 @@ static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream, ...@@ -950,15 +950,15 @@ static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream,
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
#ifdef CONFIG_SND_CS46XX_NEW_DSP #ifdef CONFIG_SND_CS46XX_NEW_DSP
/* magic value to unmute PCM stream playback volume */
snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address +
SCBVolumeCtrl) << 2, 0x80007fff);
if (cpcm->pcm_channel->unlinked) if (cpcm->pcm_channel->unlinked)
cs46xx_dsp_pcm_link(chip,cpcm->pcm_channel); cs46xx_dsp_pcm_link(chip,cpcm->pcm_channel);
if (substream->runtime->periods != CS46XX_FRAGS) if (substream->runtime->periods != CS46XX_FRAGS)
snd_cs46xx_playback_transfer(substream, 0); snd_cs46xx_playback_transfer(substream, 0);
/* raise playback volume */
cs46xx_dsp_scb_set_volume (chip,cpcm->pcm_channel->pcm_reader_scb,
chip->dsp_spos_instance->dac_volume_right,
chip->dsp_spos_instance->dac_volume_left);
#else #else
if (substream->runtime->periods != CS46XX_FRAGS) if (substream->runtime->periods != CS46XX_FRAGS)
snd_cs46xx_playback_transfer(substream, 0); snd_cs46xx_playback_transfer(substream, 0);
...@@ -972,8 +972,9 @@ static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream, ...@@ -972,8 +972,9 @@ static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream,
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_SUSPEND:
#ifdef CONFIG_SND_CS46XX_NEW_DSP #ifdef CONFIG_SND_CS46XX_NEW_DSP
/* mute channel */ /* magic mute channel */
cs46xx_dsp_scb_set_volume (chip,cpcm->pcm_channel->pcm_reader_scb,0,0); snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address +
SCBVolumeCtrl) << 2, 0xffffffff);
if (!cpcm->pcm_channel->unlinked) if (!cpcm->pcm_channel->unlinked)
cs46xx_dsp_pcm_unlink(chip,cpcm->pcm_channel); cs46xx_dsp_pcm_unlink(chip,cpcm->pcm_channel);
...@@ -1067,6 +1068,7 @@ static int _cs46xx_adjust_sample_rate (cs46xx_t *chip, cs46xx_pcm_t *cpcm, ...@@ -1067,6 +1068,7 @@ static int _cs46xx_adjust_sample_rate (cs46xx_t *chip, cs46xx_pcm_t *cpcm,
} }
#endif #endif
static int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream, static int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream,
snd_pcm_hw_params_t * hw_params) snd_pcm_hw_params_t * hw_params)
{ {
...@@ -1083,15 +1085,10 @@ static int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream, ...@@ -1083,15 +1085,10 @@ static int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream,
down (&chip->spos_mutex); down (&chip->spos_mutex);
snd_assert (cpcm->pcm_channel != NULL); snd_assert (cpcm->pcm_channel != NULL);
/* if IEC958 is opened in AC3 mode dont adjust SRCTask is not if (_cs46xx_adjust_sample_rate (chip,cpcm,sample_rate)) {
used so dont adjust sample rate */ up (&chip->spos_mutex);
if (cpcm->pcm_channel->pcm_channel_id != DSP_IEC958_CHANNEL || return -ENXIO;
!(chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE)) {
if (_cs46xx_adjust_sample_rate (chip,cpcm,sample_rate)) {
up (&chip->spos_mutex);
return -ENXIO;
}
} }
if (cs46xx_dsp_pcm_channel_set_period (chip,cpcm->pcm_channel,period_size * 4)) { if (cs46xx_dsp_pcm_channel_set_period (chip,cpcm->pcm_channel,period_size * 4)) {
...@@ -2042,34 +2039,6 @@ static int snd_cs46xx_pcm_capture_get(snd_kcontrol_t *kcontrol, ...@@ -2042,34 +2039,6 @@ static int snd_cs46xx_pcm_capture_get(snd_kcontrol_t *kcontrol,
return 0; return 0;
} }
static int snd_cs46xx_iec958_ac3_mode_get(snd_kcontrol_t *kcontrol,
snd_ctl_elem_value_t *ucontrol)
{
cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
dsp_spos_instance_t * ins = chip->dsp_spos_instance;
if (!ins->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE)
ucontrol->value.integer.value[0] = 1;
else
ucontrol->value.integer.value[0] = 0;
return 0;
}
static int snd_cs46xx_iec958_ac3_mode_put(snd_kcontrol_t *kcontrol,
snd_ctl_elem_value_t *ucontrol)
{
cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
dsp_spos_instance_t * ins = chip->dsp_spos_instance;
int old = ins->spdif_status_out;
if (ucontrol->value.integer.value[0])
ins->spdif_status_out |= DSP_SPDIF_STATUS_AC3_MODE;
else
ins->spdif_status_out &= ~DSP_SPDIF_STATUS_AC3_MODE;
return (old != ins->spdif_status_out);
}
static int snd_cs46xx_pcm_capture_put(snd_kcontrol_t *kcontrol, static int snd_cs46xx_pcm_capture_put(snd_kcontrol_t *kcontrol,
snd_ctl_elem_value_t *ucontrol) snd_ctl_elem_value_t *ucontrol)
...@@ -2131,6 +2100,110 @@ static int snd_herc_spdif_select_put(snd_kcontrol_t *kcontrol, ...@@ -2131,6 +2100,110 @@ static int snd_herc_spdif_select_put(snd_kcontrol_t *kcontrol,
return (val1 != snd_cs46xx_peekBA0(chip, BA0_EGPIODR)); return (val1 != snd_cs46xx_peekBA0(chip, BA0_EGPIODR));
} }
static int snd_cs46xx_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
uinfo->count = 1;
return 0;
}
static int snd_cs46xx_spdif_default_get(snd_kcontrol_t * kcontrol,
snd_ctl_elem_value_t * ucontrol)
{
cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
dsp_spos_instance_t * ins = chip->dsp_spos_instance;
down (&chip->spos_mutex);
ucontrol->value.iec958.status[0] = _wrap_all_bits((ins->spdif_csuv_default >> 24) & 0xff);
ucontrol->value.iec958.status[1] = _wrap_all_bits((ins->spdif_csuv_default >> 16) & 0xff);
ucontrol->value.iec958.status[2] = 0;
ucontrol->value.iec958.status[3] = _wrap_all_bits((ins->spdif_csuv_default) & 0xff);
up (&chip->spos_mutex);
return 0;
}
static int snd_cs46xx_spdif_default_put(snd_kcontrol_t * kcontrol,
snd_ctl_elem_value_t * ucontrol)
{
cs46xx_t * chip = snd_kcontrol_chip(kcontrol);
dsp_spos_instance_t * ins = chip->dsp_spos_instance;
unsigned int val;
int change;
down (&chip->spos_mutex);
val = _wrap_all_bits(((u32)ucontrol->value.iec958.status[0] << 24)) |
_wrap_all_bits(((u32)ucontrol->value.iec958.status[2] << 16)) |
_wrap_all_bits( (u32)ucontrol->value.iec958.status[3]) |
/* left and right validity bit */
(1 << 13) | (1 << 12);
change = ins->spdif_csuv_default != val;
ins->spdif_csuv_default = val;
if ( !(ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) )
cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV,val);
up (&chip->spos_mutex);
return change;
}
static int snd_cs46xx_spdif_mask_get(snd_kcontrol_t * kcontrol,
snd_ctl_elem_value_t * ucontrol)
{
ucontrol->value.iec958.status[0] = 0xff;
ucontrol->value.iec958.status[1] = 0xff;
ucontrol->value.iec958.status[2] = 0x00;
ucontrol->value.iec958.status[3] = 0xff;
return 0;
}
static int snd_cs46xx_spdif_stream_get(snd_kcontrol_t * kcontrol,
snd_ctl_elem_value_t * ucontrol)
{
cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
dsp_spos_instance_t * ins = chip->dsp_spos_instance;
down (&chip->spos_mutex);
ucontrol->value.iec958.status[0] = _wrap_all_bits((ins->spdif_csuv_stream >> 24) & 0xff);
ucontrol->value.iec958.status[1] = _wrap_all_bits((ins->spdif_csuv_stream >> 16) & 0xff);
ucontrol->value.iec958.status[2] = 0;
ucontrol->value.iec958.status[3] = _wrap_all_bits((ins->spdif_csuv_stream) & 0xff);
up (&chip->spos_mutex);
return 0;
}
static int snd_cs46xx_spdif_stream_put(snd_kcontrol_t * kcontrol,
snd_ctl_elem_value_t * ucontrol)
{
cs46xx_t * chip = snd_kcontrol_chip(kcontrol);
dsp_spos_instance_t * ins = chip->dsp_spos_instance;
unsigned int val;
int change;
down (&chip->spos_mutex);
val = _wrap_all_bits(((u32)ucontrol->value.iec958.status[0] << 24)) |
_wrap_all_bits(((u32)ucontrol->value.iec958.status[1] << 16)) |
_wrap_all_bits( (u32)ucontrol->value.iec958.status[3]) |
/* left and right validity bit */
(1 << 13) | (1 << 12);
change = ins->spdif_csuv_stream != val;
ins->spdif_csuv_stream = val;
if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN )
cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV,val);
up (&chip->spos_mutex);
return change;
}
#endif /* CONFIG_SND_CS46XX_NEW_DSP */ #endif /* CONFIG_SND_CS46XX_NEW_DSP */
#ifdef CONFIG_SND_CS46XX_DEBUG_GPIO #ifdef CONFIG_SND_CS46XX_DEBUG_GPIO
...@@ -2242,7 +2315,7 @@ static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = { ...@@ -2242,7 +2315,7 @@ static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = {
}, },
{ {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC 958 Output Switch", .name = "IEC958 Output Switch",
.info = snd_mixer_boolean_info, .info = snd_mixer_boolean_info,
.get = snd_cs46xx_iec958_get, .get = snd_cs46xx_iec958_get,
.put = snd_cs46xx_iec958_put, .put = snd_cs46xx_iec958_put,
...@@ -2250,14 +2323,7 @@ static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = { ...@@ -2250,14 +2323,7 @@ static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = {
}, },
{ {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC 958 AC3 Mode Switch", .name = "IEC958 Input Switch",
.info = snd_mixer_boolean_info,
.get = snd_cs46xx_iec958_ac3_mode_get,
.put = snd_cs46xx_iec958_ac3_mode_put,
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC 958 Input Switch",
.info = snd_mixer_boolean_info, .info = snd_mixer_boolean_info,
.get = snd_cs46xx_iec958_get, .get = snd_cs46xx_iec958_get,
.put = snd_cs46xx_iec958_put, .put = snd_cs46xx_iec958_put,
...@@ -2265,12 +2331,34 @@ static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = { ...@@ -2265,12 +2331,34 @@ static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = {
}, },
{ {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC 958 Input Volume", .name = "IEC958 Input Volume",
.info = snd_cs46xx_vol_info, .info = snd_cs46xx_vol_info,
.get = snd_cs46xx_vol_iec958_get, .get = snd_cs46xx_vol_iec958_get,
.put = snd_cs46xx_vol_iec958_put, .put = snd_cs46xx_vol_iec958_put,
.private_value = (ASYNCRX_SCB_ADDR + 0xE) << 2, .private_value = (ASYNCRX_SCB_ADDR + 0xE) << 2,
}, },
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
.info = snd_cs46xx_spdif_info,
.get = snd_cs46xx_spdif_default_get,
.put = snd_cs46xx_spdif_default_put,
},
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
.info = snd_cs46xx_spdif_info,
.get = snd_cs46xx_spdif_mask_get,
.access = SNDRV_CTL_ELEM_ACCESS_READ
},
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),
.info = snd_cs46xx_spdif_info,
.get = snd_cs46xx_spdif_stream_get,
.put = snd_cs46xx_spdif_stream_put
},
#endif #endif
#ifdef CONFIG_SND_CS46XX_DEBUG_GPIO #ifdef CONFIG_SND_CS46XX_DEBUG_GPIO
{ {
......
...@@ -217,6 +217,6 @@ int cs46xx_dsp_pcm_channel_set_period (cs46xx_t * chip, ...@@ -217,6 +217,6 @@ int cs46xx_dsp_pcm_channel_set_period (cs46xx_t * chip,
int period_size); int period_size);
int cs46xx_dsp_pcm_ostream_set_period (cs46xx_t * chip, int cs46xx_dsp_pcm_ostream_set_period (cs46xx_t * chip,
int period_size); int period_size);
int cs46xx_dsp_set_dac_volume (cs46xx_t * chip,u16 right,u16 left); int cs46xx_dsp_set_dac_volume (cs46xx_t * chip,u16 left,u16 right);
int cs46xx_dsp_set_iec958_volume (cs46xx_t * chip,u16 right,u16 left); int cs46xx_dsp_set_iec958_volume (cs46xx_t * chip,u16 left,u16 right);
#endif /* __CS46XX_LIB_H__ */ #endif /* __CS46XX_LIB_H__ */
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <sound/core.h> #include <sound/core.h>
#include <sound/control.h> #include <sound/control.h>
#include <sound/info.h> #include <sound/info.h>
#include <sound/asoundef.h>
#include <sound/cs46xx.h> #include <sound/cs46xx.h>
#include "cs46xx_lib.h" #include "cs46xx_lib.h"
...@@ -262,6 +263,15 @@ dsp_spos_instance_t * cs46xx_dsp_spos_create (cs46xx_t * chip) ...@@ -262,6 +263,15 @@ dsp_spos_instance_t * cs46xx_dsp_spos_create (cs46xx_t * chip)
ins->spdif_input_volume_right = 0x8000; ins->spdif_input_volume_right = 0x8000;
ins->spdif_input_volume_left = 0x8000; ins->spdif_input_volume_left = 0x8000;
/* set left and right validity bits and
default channel status */
ins->spdif_csuv_default =
ins->spdif_csuv_stream =
/* byte 0 */ (_wrap_all_bits( (SNDRV_PCM_DEFAULT_CON_SPDIF & 0xff)) << 24) |
/* byte 1 */ (_wrap_all_bits( ((SNDRV_PCM_DEFAULT_CON_SPDIF >> 16) & 0xff)) << 16) |
/* byte 3 */ _wrap_all_bits( (SNDRV_PCM_DEFAULT_CON_SPDIF >> 24) & 0xff) |
/* left and right validity bits */ (1 << 13) | (1 << 12);
return ins; return ins;
} }
...@@ -1549,7 +1559,7 @@ int cs46xx_dsp_enable_spdif_hw (cs46xx_t *chip) ...@@ -1549,7 +1559,7 @@ int cs46xx_dsp_enable_spdif_hw (cs46xx_t *chip)
cs46xx_poke_via_dsp (chip,SP_SPDOUT_CONTROL, 0x80000000); cs46xx_poke_via_dsp (chip,SP_SPDOUT_CONTROL, 0x80000000);
/* right and left validate bit */ /* right and left validate bit */
cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, 0x00000000 | (1 << 13) | (1 << 12)); cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);
/* monitor state */ /* monitor state */
ins->spdif_status_out |= DSP_SPDIF_STATUS_HW_ENABLED; ins->spdif_status_out |= DSP_SPDIF_STATUS_HW_ENABLED;
...@@ -1587,11 +1597,6 @@ int cs46xx_dsp_enable_spdif_in (cs46xx_t *chip) ...@@ -1587,11 +1597,6 @@ int cs46xx_dsp_enable_spdif_in (cs46xx_t *chip)
cs46xx_poke_via_dsp (chip,SP_SPDIN_FIFOPTR, 0x0); cs46xx_poke_via_dsp (chip,SP_SPDIN_FIFOPTR, 0x0);
cs46xx_src_link(chip,ins->spdif_in_src); cs46xx_src_link(chip,ins->spdif_in_src);
/* restore SPDIF input volume */
cs46xx_dsp_scb_set_volume (chip,ins->spdif_in_src,
ins->spdif_input_volume_right,
ins->spdif_input_volume_left);
spin_unlock_irq(&chip->reg_lock); spin_unlock_irq(&chip->reg_lock);
/* set SPDIF input sample rate and unmute /* set SPDIF input sample rate and unmute
...@@ -1725,39 +1730,47 @@ int cs46xx_poke_via_dsp (cs46xx_t *chip,u32 address,u32 data) ...@@ -1725,39 +1730,47 @@ int cs46xx_poke_via_dsp (cs46xx_t *chip,u32 address,u32 data)
return 0; return 0;
} }
int cs46xx_dsp_set_dac_volume (cs46xx_t * chip,u16 right,u16 left) int cs46xx_dsp_set_dac_volume (cs46xx_t * chip,u16 left,u16 right)
{ {
int i;
dsp_spos_instance_t * ins = chip->dsp_spos_instance; dsp_spos_instance_t * ins = chip->dsp_spos_instance;
dsp_scb_descriptor_t * scb;
down(&chip->spos_mutex); down(&chip->spos_mutex);
/* main output */
scb = ins->master_mix_scb->sub_list_ptr;
while (scb != ins->the_null_scb) {
cs46xx_dsp_scb_set_volume (chip,scb,left,right);
scb = scb->next_scb_ptr;
}
ins->dac_volume_right = right; /* rear output */
ins->dac_volume_left = left; scb = ins->rear_mix_scb->sub_list_ptr;
while (scb != ins->the_null_scb) {
for (i = 0; i < DSP_MAX_PCM_CHANNELS; ++i) { cs46xx_dsp_scb_set_volume (chip,scb,left,right);
if (ins->pcm_channels[i].active && scb = scb->next_scb_ptr;
!ins->pcm_channels[i].unlinked) {
cs46xx_dsp_scb_set_volume (chip,ins->pcm_channels[i].pcm_reader_scb,
right,left);
}
} }
ins->dac_volume_left = left;
ins->dac_volume_right = right;
up(&chip->spos_mutex); up(&chip->spos_mutex);
return 0; return 0;
} }
int cs46xx_dsp_set_iec958_volume (cs46xx_t * chip,u16 right,u16 left) { int cs46xx_dsp_set_iec958_volume (cs46xx_t * chip,u16 left,u16 right) {
dsp_spos_instance_t * ins = chip->dsp_spos_instance; dsp_spos_instance_t * ins = chip->dsp_spos_instance;
down(&chip->spos_mutex); down(&chip->spos_mutex);
cs46xx_dsp_scb_set_volume (chip,ins->spdif_in_src,
right,left);
ins->spdif_input_volume_right = right; if (ins->asynch_rx_scb != NULL)
cs46xx_dsp_scb_set_volume (chip,ins->asynch_rx_scb,
left,right);
ins->spdif_input_volume_left = left; ins->spdif_input_volume_left = left;
ins->spdif_input_volume_right = right;
up(&chip->spos_mutex); up(&chip->spos_mutex);
return 0; return 0;
......
...@@ -185,6 +185,25 @@ typedef enum { ...@@ -185,6 +185,25 @@ typedef enum {
#define SP_SPDOUT_CONTROL 0x804D #define SP_SPDOUT_CONTROL 0x804D
#define SP_SPDOUT_CSUV 0x808E #define SP_SPDOUT_CSUV 0x808E
static inline u8 _wrap_all_bits (u8 val) {
u8 wrapped;
/* wrap all 8 bits */
wrapped =
((val & 0x1 ) << 7) |
((val & 0x2 ) << 5) |
((val & 0x4 ) << 3) |
((val & 0x8 ) << 1) |
((val & 0x10) >> 1) |
((val & 0x20) >> 3) |
((val & 0x40) >> 5) |
((val & 0x80) >> 6);
return wrapped;
}
static inline void cs46xx_dsp_spos_update_scb (cs46xx_t * chip,dsp_scb_descriptor_t * scb) static inline void cs46xx_dsp_spos_update_scb (cs46xx_t * chip,dsp_scb_descriptor_t * scb)
{ {
/* update nextSCB and subListPtr in SCB */ /* update nextSCB and subListPtr in SCB */
...@@ -195,12 +214,11 @@ static inline void cs46xx_dsp_spos_update_scb (cs46xx_t * chip,dsp_scb_descripto ...@@ -195,12 +214,11 @@ static inline void cs46xx_dsp_spos_update_scb (cs46xx_t * chip,dsp_scb_descripto
} }
static inline void cs46xx_dsp_scb_set_volume (cs46xx_t * chip,dsp_scb_descriptor_t * scb, static inline void cs46xx_dsp_scb_set_volume (cs46xx_t * chip,dsp_scb_descriptor_t * scb,
u16 right,u16 left) { u16 left,u16 right) {
unsigned int val = ((0xffff - right) << 16 | (0xffff - left)); unsigned int val = ((0xffff - left) << 16 | (0xffff - right));
snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl) << 2, val); snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl) << 2, val);
snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl + 1) << 2, val); snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl + 1) << 2, val);
} }
#endif /* __DSP_SPOS_H__ */ #endif /* __DSP_SPOS_H__ */
#endif /* CONFIG_SND_CS46XX_NEW_DSP */ #endif /* CONFIG_SND_CS46XX_NEW_DSP */
...@@ -603,8 +603,8 @@ cs46xx_dsp_create_src_task_scb(cs46xx_t * chip,char * scb_name, ...@@ -603,8 +603,8 @@ cs46xx_dsp_create_src_task_scb(cs46xx_t * chip,char * scb_name,
src_buffer_addr << 0x10, src_buffer_addr << 0x10,
0x04000000, 0x04000000,
{ {
0x8000,0x8000, 0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left,
0xffff,0xffff 0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left
} }
}; };
...@@ -658,7 +658,7 @@ cs46xx_dsp_create_mix_only_scb(cs46xx_t * chip,char * scb_name, ...@@ -658,7 +658,7 @@ cs46xx_dsp_create_mix_only_scb(cs46xx_t * chip,char * scb_name,
/* D */ 0, /* D */ 0,
{ {
/* E */ 0x8000,0x8000, /* E */ 0x8000,0x8000,
/* F */ 0xffff,0xffff /* F */ 0x8000,0x8000
} }
}; };
...@@ -830,7 +830,7 @@ cs46xx_dsp_create_asynch_fg_tx_scb(cs46xx_t * chip,char * scb_name,u32 dest, ...@@ -830,7 +830,7 @@ cs46xx_dsp_create_asynch_fg_tx_scb(cs46xx_t * chip,char * scb_name,u32 dest,
0,0x2aab, /* Const 1/3 */ 0,0x2aab, /* Const 1/3 */
{ {
0, /* Define the unused elements */ 0, /* Define the unused elements */
0, 0,
0 0
}, },
...@@ -846,7 +846,7 @@ cs46xx_dsp_create_asynch_fg_tx_scb(cs46xx_t * chip,char * scb_name,u32 dest, ...@@ -846,7 +846,7 @@ cs46xx_dsp_create_asynch_fg_tx_scb(cs46xx_t * chip,char * scb_name,u32 dest,
rate etc */ rate etc */
0x18000000, /* Phi increment for approx 32k operation */ 0x18000000, /* Phi increment for approx 32k operation */
0x8000,0x8000, /* Volume controls are unused at this time */ 0x8000,0x8000, /* Volume controls are unused at this time */
0xffff,0xffff 0x8000,0x8000
}; };
scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_tx_scb, scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_tx_scb,
...@@ -864,7 +864,7 @@ cs46xx_dsp_create_asynch_fg_rx_scb(cs46xx_t * chip,char * scb_name,u32 dest, ...@@ -864,7 +864,7 @@ cs46xx_dsp_create_asynch_fg_rx_scb(cs46xx_t * chip,char * scb_name,u32 dest,
dsp_scb_descriptor_t * parent_scb, dsp_scb_descriptor_t * parent_scb,
int scb_child_type) int scb_child_type)
{ {
dsp_spos_instance_t * ins = chip->dsp_spos_instance;
dsp_scb_descriptor_t * scb; dsp_scb_descriptor_t * scb;
asynch_fg_rx_scb_t asynch_fg_rx_scb = { asynch_fg_rx_scb_t asynch_fg_rx_scb = {
...@@ -893,9 +893,9 @@ cs46xx_dsp_create_asynch_fg_rx_scb(cs46xx_t * chip,char * scb_name,u32 dest, ...@@ -893,9 +893,9 @@ cs46xx_dsp_create_asynch_fg_rx_scb(cs46xx_t * chip,char * scb_name,u32 dest,
rate etc */ rate etc */
0x18000000, 0x18000000,
/* Mute stream */ /* Set IEC958 input volume */
0x8000,0x8000, 0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
0xffff,0xffff 0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
}; };
scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_rx_scb, scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_rx_scb,
...@@ -1116,11 +1116,13 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip, ...@@ -1116,11 +1116,13 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,
case DSP_IEC958_CHANNEL: case DSP_IEC958_CHANNEL:
snd_assert (ins->asynch_tx_scb != NULL, return NULL); snd_assert (ins->asynch_tx_scb != NULL, return NULL);
mixer_scb = ins->asynch_tx_scb; mixer_scb = ins->asynch_tx_scb;
#if 0
if (ins->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE) { if (ins->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE) {
snd_printdd ("IEC958 opened in AC3 mode\n"); snd_printdd ("IEC958 opened in AC3 mode\n");
/*src_scb = ins->asynch_tx_scb; /*src_scb = ins->asynch_tx_scb;
ins->asynch_tx_scb->ref_count ++;*/ ins->asynch_tx_scb->ref_count ++;*/
} }
#endif
break; break;
default: default:
snd_assert (0); snd_assert (0);
...@@ -1198,9 +1200,7 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip, ...@@ -1198,9 +1200,7 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,
return NULL; return NULL;
} }
if (pcm_channel_id != DSP_IEC958_CHANNEL || cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate);
!(ins->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE))
cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate);
ins->nsrc_scb ++; ins->nsrc_scb ++;
} }
...@@ -1461,17 +1461,11 @@ void cs46xx_dsp_set_src_sample_rate(cs46xx_t *chip,dsp_scb_descriptor_t * src, u ...@@ -1461,17 +1461,11 @@ void cs46xx_dsp_set_src_sample_rate(cs46xx_t *chip,dsp_scb_descriptor_t * src, u
*/ */
spin_lock_irqsave(&chip->reg_lock, flags); spin_lock_irqsave(&chip->reg_lock, flags);
/* mute SCB */
/* cs46xx_dsp_scb_set_volume (chip,src,0,0); */
snd_cs46xx_poke(chip, (src->address + SRCCorPerGof) << 2, snd_cs46xx_poke(chip, (src->address + SRCCorPerGof) << 2,
((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF)); ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF));
snd_cs46xx_poke(chip, (src->address + SRCPhiIncr6Int26Frac) << 2, phiIncr); snd_cs46xx_poke(chip, (src->address + SRCPhiIncr6Int26Frac) << 2, phiIncr);
/* raise volume */
/* cs46xx_dsp_scb_set_volume (chip,src,0x7fff,0x7fff); */
spin_unlock_irqrestore(&chip->reg_lock, flags); spin_unlock_irqrestore(&chip->reg_lock, flags);
} }
...@@ -1641,9 +1635,8 @@ int cs46xx_iec958_pre_open (cs46xx_t *chip) ...@@ -1641,9 +1635,8 @@ int cs46xx_iec958_pre_open (cs46xx_t *chip)
SCB_ON_PARENT_NEXT_SCB); SCB_ON_PARENT_NEXT_SCB);
if (ins->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE) /* set spdif channel status value for streaming */
/* set left (13), right validity bit (12) , and non-audio(1) and profsional bit (0) */ cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_stream);
cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, 0x00000000 | (1 << 13) | (1 << 12) | (1 << 1) | 1);
ins->spdif_status_out |= DSP_SPDIF_STATUS_PLAYBACK_OPEN; ins->spdif_status_out |= DSP_SPDIF_STATUS_PLAYBACK_OPEN;
...@@ -1659,7 +1652,7 @@ int cs46xx_iec958_post_close (cs46xx_t *chip) ...@@ -1659,7 +1652,7 @@ int cs46xx_iec958_post_close (cs46xx_t *chip)
ins->spdif_status_out &= ~DSP_SPDIF_STATUS_PLAYBACK_OPEN; ins->spdif_status_out &= ~DSP_SPDIF_STATUS_PLAYBACK_OPEN;
/* restore settings */ /* restore settings */
cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, 0x00000000 | (1 << 13) | (1 << 12)); cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);
/* deallocate stuff */ /* deallocate stuff */
cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb); cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
......
...@@ -1355,6 +1355,7 @@ static snd_kcontrol_new_t snd_ens1373_spdif_default __devinitdata = ...@@ -1355,6 +1355,7 @@ static snd_kcontrol_new_t snd_ens1373_spdif_default __devinitdata =
static snd_kcontrol_new_t snd_ens1373_spdif_mask __devinitdata = static snd_kcontrol_new_t snd_ens1373_spdif_mask __devinitdata =
{ {
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM, .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
.info = snd_ens1373_spdif_info, .info = snd_ens1373_spdif_info,
...@@ -2181,10 +2182,10 @@ static int __devinit snd_audiopci_probe(struct pci_dev *pci, ...@@ -2181,10 +2182,10 @@ static int __devinit snd_audiopci_probe(struct pci_dev *pci,
return err; return err;
} }
#ifdef CHIP1370 #ifdef CHIP1370
strcpy(card->driver, "ES1370"); strcpy(card->driver, "ENS1370");
#endif #endif
#ifdef CHIP1371 #ifdef CHIP1371
strcpy(card->driver, "ES1371"); strcpy(card->driver, "ENS1371");
#endif #endif
strcpy(card->shortname, "Ensoniq AudioPCI"); strcpy(card->shortname, "Ensoniq AudioPCI");
sprintf(card->longname, "%s %s at 0x%lx, irq %i", sprintf(card->longname, "%s %s at 0x%lx, irq %i",
......
...@@ -257,17 +257,20 @@ static int delta1010lt_ak4524_start(ice1712_t *ice, unsigned char *saved, int ch ...@@ -257,17 +257,20 @@ static int delta1010lt_ak4524_start(ice1712_t *ice, unsigned char *saved, int ch
/* /*
* change the rate of AK4524 on Delta 44/66, AP, 1010LT * change the rate of AK4524 on Delta 44/66, AP, 1010LT
*/ */
static void delta_ak4524_set_rate_val(ice1712_t *ice, unsigned char val) static void delta_ak4524_set_rate_val(ice1712_t *ice, unsigned int rate)
{ {
unsigned char tmp, tmp2; unsigned char tmp, tmp2;
if (rate == 0) /* no hint - S/PDIF input is master, simply return */
return;
/* check before reset ak4524 to avoid unnecessary clicks */ /* check before reset ak4524 to avoid unnecessary clicks */
down(&ice->gpio_mutex); down(&ice->gpio_mutex);
tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA); tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
up(&ice->gpio_mutex); up(&ice->gpio_mutex);
tmp2 = tmp; tmp2 = tmp;
tmp2 &= ~ICE1712_DELTA_DFS; tmp2 &= ~ICE1712_DELTA_DFS;
if (val == 15 || val == 11 || val == 7) if (rate > 48000)
tmp2 |= ICE1712_DELTA_DFS; tmp2 |= ICE1712_DELTA_DFS;
if (tmp == tmp2) if (tmp == tmp2)
return; return;
...@@ -275,12 +278,9 @@ static void delta_ak4524_set_rate_val(ice1712_t *ice, unsigned char val) ...@@ -275,12 +278,9 @@ static void delta_ak4524_set_rate_val(ice1712_t *ice, unsigned char val)
/* do it again */ /* do it again */
snd_ice1712_ak4524_reset(ice, 1); snd_ice1712_ak4524_reset(ice, 1);
down(&ice->gpio_mutex); down(&ice->gpio_mutex);
tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA); tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & ~ICE1712_DELTA_DFS;
if (val == 15 || val == 11 || val == 7) { if (rate > 48000)
tmp |= ICE1712_DELTA_DFS; tmp |= ICE1712_DELTA_DFS;
} else {
tmp &= ~ICE1712_DELTA_DFS;
}
snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp); snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
up(&ice->gpio_mutex); up(&ice->gpio_mutex);
snd_ice1712_ak4524_reset(ice, 0); snd_ice1712_ak4524_reset(ice, 0);
......
...@@ -104,10 +104,24 @@ MODULE_DEVICE_TABLE(pci, snd_ice1712_ids); ...@@ -104,10 +104,24 @@ MODULE_DEVICE_TABLE(pci, snd_ice1712_ids);
static int snd_ice1712_build_pro_mixer(ice1712_t *ice); static int snd_ice1712_build_pro_mixer(ice1712_t *ice);
static int snd_ice1712_build_controls(ice1712_t *ice); static int snd_ice1712_build_controls(ice1712_t *ice);
static int PRO_RATE_LOCKED = 0;
static int PRO_RATE_RESET = 1;
static unsigned int PRO_RATE_DEFAULT = 44100;
/* /*
* Basic I/O * Basic I/O
*/ */
static inline int is_spdif_master(ice1712_t *ice)
{
return (inb(ICEMT(ice, RATE)) & ICE1712_SPDIF_MASTER) ? 1 : 0;
}
static inline int is_pro_rate_locked(ice1712_t *ice)
{
return is_spdif_master(ice) || PRO_RATE_LOCKED;
}
static inline void snd_ice1712_ds_write(ice1712_t * ice, u8 channel, u8 addr, u32 data) static inline void snd_ice1712_ds_write(ice1712_t * ice, u8 channel, u8 addr, u32 data)
{ {
outb((channel << 4) | addr, ICEDS(ice, INDEX)); outb((channel << 4) | addr, ICEDS(ice, INDEX));
...@@ -980,21 +994,25 @@ static int snd_ice1712_pro_trigger(snd_pcm_substream_t *substream, ...@@ -980,21 +994,25 @@ static int snd_ice1712_pro_trigger(snd_pcm_substream_t *substream,
/* /*
*/ */
static void snd_ice1712_set_pro_rate(ice1712_t *ice, snd_pcm_substream_t *substream) static void snd_ice1712_set_pro_rate(ice1712_t *ice, unsigned int rate, int do_not_lock)
{ {
unsigned long flags; unsigned long flags;
unsigned int rate;
unsigned char val; unsigned char val;
int old_lock_value;
spin_lock_irqsave(&ice->reg_lock, flags); spin_lock_irqsave(&ice->reg_lock, flags);
if ((inb(ICEMT(ice, PLAYBACK_CONTROL)) & (ICE1712_CAPTURE_START_SHADOW| old_lock_value = PRO_RATE_LOCKED;
ICE1712_PLAYBACK_PAUSE| if (do_not_lock)
ICE1712_PLAYBACK_START)) || PRO_RATE_LOCKED = 0;
(inb(ICEMT(ice, RATE)) & ICE1712_SPDIF_MASTER)) { if (inb(ICEMT(ice, PLAYBACK_CONTROL)) & (ICE1712_CAPTURE_START_SHADOW|
ICE1712_PLAYBACK_PAUSE|
ICE1712_PLAYBACK_START)) {
spin_unlock_irqrestore(&ice->reg_lock, flags); spin_unlock_irqrestore(&ice->reg_lock, flags);
return; return;
} }
rate = substream->runtime->rate; if (!is_pro_rate_locked(ice))
goto __unlock;
switch (rate) { switch (rate) {
case 8000: val = 6; break; case 8000: val = 6; break;
case 9600: val = 3; break; case 9600: val = 3; break;
...@@ -1015,10 +1033,13 @@ static void snd_ice1712_set_pro_rate(ice1712_t *ice, snd_pcm_substream_t *substr ...@@ -1015,10 +1033,13 @@ static void snd_ice1712_set_pro_rate(ice1712_t *ice, snd_pcm_substream_t *substr
break; break;
} }
outb(val, ICEMT(ice, RATE)); outb(val, ICEMT(ice, RATE));
PRO_RATE_LOCKED = old_lock_value;
__unlock:
spin_unlock_irqrestore(&ice->reg_lock, flags); spin_unlock_irqrestore(&ice->reg_lock, flags);
if (ice->ak4524.ops.set_rate_val) if (ice->ak4524.ops.set_rate_val)
ice->ak4524.ops.set_rate_val(ice, val); ice->ak4524.ops.set_rate_val(ice, rate);
} }
static int snd_ice1712_playback_pro_prepare(snd_pcm_substream_t * substream) static int snd_ice1712_playback_pro_prepare(snd_pcm_substream_t * substream)
...@@ -1027,7 +1048,7 @@ static int snd_ice1712_playback_pro_prepare(snd_pcm_substream_t * substream) ...@@ -1027,7 +1048,7 @@ static int snd_ice1712_playback_pro_prepare(snd_pcm_substream_t * substream)
ice1712_t *ice = snd_pcm_substream_chip(substream); ice1712_t *ice = snd_pcm_substream_chip(substream);
ice->playback_pro_size = snd_pcm_lib_buffer_bytes(substream); ice->playback_pro_size = snd_pcm_lib_buffer_bytes(substream);
snd_ice1712_set_pro_rate(ice, substream); snd_ice1712_set_pro_rate(ice, substream->runtime->rate, 0);
spin_lock_irqsave(&ice->reg_lock, flags); spin_lock_irqsave(&ice->reg_lock, flags);
outl(substream->runtime->dma_addr, ICEMT(ice, PLAYBACK_ADDR)); outl(substream->runtime->dma_addr, ICEMT(ice, PLAYBACK_ADDR));
outw((ice->playback_pro_size >> 2) - 1, ICEMT(ice, PLAYBACK_SIZE)); outw((ice->playback_pro_size >> 2) - 1, ICEMT(ice, PLAYBACK_SIZE));
...@@ -1046,7 +1067,7 @@ static int snd_ice1712_capture_pro_prepare(snd_pcm_substream_t * substream) ...@@ -1046,7 +1067,7 @@ static int snd_ice1712_capture_pro_prepare(snd_pcm_substream_t * substream)
ice1712_t *ice = snd_pcm_substream_chip(substream); ice1712_t *ice = snd_pcm_substream_chip(substream);
ice->capture_pro_size = snd_pcm_lib_buffer_bytes(substream); ice->capture_pro_size = snd_pcm_lib_buffer_bytes(substream);
snd_ice1712_set_pro_rate(ice, substream); snd_ice1712_set_pro_rate(ice, substream->runtime->rate, 0);
spin_lock_irqsave(&ice->reg_lock, flags); spin_lock_irqsave(&ice->reg_lock, flags);
outl(substream->runtime->dma_addr, ICEMT(ice, CAPTURE_ADDR)); outl(substream->runtime->dma_addr, ICEMT(ice, CAPTURE_ADDR));
outw((ice->capture_pro_size >> 2) - 1, ICEMT(ice, CAPTURE_SIZE)); outw((ice->capture_pro_size >> 2) - 1, ICEMT(ice, CAPTURE_SIZE));
...@@ -1151,6 +1172,8 @@ static int snd_ice1712_playback_pro_close(snd_pcm_substream_t * substream) ...@@ -1151,6 +1172,8 @@ static int snd_ice1712_playback_pro_close(snd_pcm_substream_t * substream)
{ {
ice1712_t *ice = snd_pcm_substream_chip(substream); ice1712_t *ice = snd_pcm_substream_chip(substream);
if (PRO_RATE_RESET)
snd_ice1712_set_pro_rate(ice, PRO_RATE_DEFAULT, 0);
ice->playback_pro_substream = NULL; ice->playback_pro_substream = NULL;
if (ice->spdif.ops.close) if (ice->spdif.ops.close)
ice->spdif.ops.close(ice, substream); ice->spdif.ops.close(ice, substream);
...@@ -1162,6 +1185,8 @@ static int snd_ice1712_capture_pro_close(snd_pcm_substream_t * substream) ...@@ -1162,6 +1185,8 @@ static int snd_ice1712_capture_pro_close(snd_pcm_substream_t * substream)
{ {
ice1712_t *ice = snd_pcm_substream_chip(substream); ice1712_t *ice = snd_pcm_substream_chip(substream);
if (PRO_RATE_RESET)
snd_ice1712_set_pro_rate(ice, PRO_RATE_DEFAULT, 0);
ice->capture_pro_substream = NULL; ice->capture_pro_substream = NULL;
return 0; return 0;
} }
...@@ -1695,53 +1720,165 @@ int snd_ice1712_gpio_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucont ...@@ -1695,53 +1720,165 @@ int snd_ice1712_gpio_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucont
return val != nval; return val != nval;
} }
static int snd_ice1712_pro_spdif_master_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) /*
* rate
*/
static int snd_ice1712_pro_internal_clock_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
{ {
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; static char *texts[] = {
"8000", /* 0: 6 */
"9600", /* 1: 3 */
"11025", /* 2: 10 */
"12000", /* 3: 2 */
"16000", /* 4: 5 */
"22050", /* 5: 9 */
"24000", /* 6: 1 */
"32000", /* 7: 4 */
"44100", /* 8: 8 */
"48000", /* 9: 0 */
"64000", /* 10: 15 */
"88200", /* 11: 11 */
"96000", /* 12: 7 */
"IEC958 Input", /* 13: -- */
};
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1; uinfo->count = 1;
uinfo->value.integer.min = 0; uinfo->value.enumerated.items = 14;
uinfo->value.integer.max = 1; if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
return 0; return 0;
} }
static int snd_ice1712_pro_spdif_master_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) static int snd_ice1712_pro_internal_clock_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{ {
ice1712_t *ice = snd_kcontrol_chip(kcontrol); ice1712_t *ice = snd_kcontrol_chip(kcontrol);
unsigned long flags; static unsigned char xlate[16] = {
9, 6, 3, 1, 7, 4, 0, 12, 8, 5, 2, 11, 255, 255, 255, 10
};
unsigned char val;
spin_lock_irqsave(&ice->reg_lock, flags); spin_lock_irq(&ice->reg_lock);
ucontrol->value.integer.value[0] = inb(ICEMT(ice, RATE)) & ICE1712_SPDIF_MASTER ? 1 : 0; if (is_spdif_master(ice)) {
spin_unlock_irqrestore(&ice->reg_lock, flags); ucontrol->value.enumerated.item[0] = 13;
} else {
val = xlate[inb(ICEMT(ice, RATE)) & 15];
if (val == 255) {
snd_BUG();
val = 0;
}
ucontrol->value.enumerated.item[0] = val;
}
spin_unlock_irq(&ice->reg_lock);
return 0; return 0;
} }
static int snd_ice1712_pro_spdif_master_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) static int snd_ice1712_pro_internal_clock_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{ {
unsigned long flags;
ice1712_t *ice = snd_kcontrol_chip(kcontrol); ice1712_t *ice = snd_kcontrol_chip(kcontrol);
int nval, change; static unsigned int xrate[13] = {
8000, 9600, 11025, 12000, 1600, 22050, 24000,
32000, 44100, 48000, 64000, 88200, 96000
};
unsigned char oval;
int change = 0;
nval = ucontrol->value.integer.value[0] ? ICE1712_SPDIF_MASTER : 0; spin_lock_irq(&ice->reg_lock);
spin_lock_irqsave(&ice->reg_lock, flags); oval = inb(ICEMT(ice, RATE));
nval |= inb(ICEMT(ice, RATE)) & ~ICE1712_SPDIF_MASTER; if (ucontrol->value.enumerated.item[0] == 13) {
change = inb(ICEMT(ice, RATE)) != nval; outb(oval | ICE1712_SPDIF_MASTER, ICEMT(ice, RATE));
outb(nval, ICEMT(ice, RATE)); } else {
spin_unlock_irqrestore(&ice->reg_lock, flags); PRO_RATE_DEFAULT = xrate[ucontrol->value.integer.value[0] % 13];
spin_unlock_irq(&ice->reg_lock);
snd_ice1712_set_pro_rate(ice, PRO_RATE_DEFAULT, 1);
spin_lock_irq(&ice->reg_lock);
}
change = inb(ICEMT(ice, RATE)) != oval;
spin_unlock_irq(&ice->reg_lock);
if (ice->cs8427) { if ((oval & ICE1712_SPDIF_MASTER) != (inb(ICEMT(ice, RATE)) & ICE1712_SPDIF_MASTER)) {
/* change CS8427 clock source too */ /* change CS8427 clock source too */
snd_ice1712_cs8427_set_input_clock(ice, ucontrol->value.integer.value[0]); if (ice->cs8427) {
snd_ice1712_cs8427_set_input_clock(ice, is_spdif_master(ice));
}
/* notify ak4524 chip as well */
if (is_spdif_master(ice) && ice->ak4524.ops.set_rate_val)
ice->ak4524.ops.set_rate_val(ice, 0);
} }
return change; return change;
} }
static snd_kcontrol_new_t snd_ice1712_pro_spdif_master __devinitdata = { static snd_kcontrol_new_t snd_ice1712_pro_internal_clock = __devinitdata {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Internal Clock",
.info = snd_ice1712_pro_internal_clock_info,
.get = snd_ice1712_pro_internal_clock_get,
.put = snd_ice1712_pro_internal_clock_put
};
static int snd_ice1712_pro_rate_locking_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 1;
return 0;
}
static int snd_ice1712_pro_rate_locking_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
ucontrol->value.integer.value[0] = PRO_RATE_LOCKED ? 1 : 0;
return 0;
}
static int snd_ice1712_pro_rate_locking_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
int change = 0;
change = PRO_RATE_LOCKED ? 1 : 0 != ucontrol->value.integer.value[0] ? 1 : 0;
PRO_RATE_LOCKED = ucontrol->value.integer.value[0] ? 1 : 0;
return change;
}
static snd_kcontrol_new_t snd_ice1712_pro_rate_locking __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Rate Locking",
.info = snd_ice1712_pro_rate_locking_info,
.get = snd_ice1712_pro_rate_locking_get,
.put = snd_ice1712_pro_rate_locking_put
};
static int snd_ice1712_pro_rate_reset_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 1;
return 0;
}
static int snd_ice1712_pro_rate_reset_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
ucontrol->value.integer.value[0] = PRO_RATE_RESET ? 1 : 0;
return 0;
}
static int snd_ice1712_pro_rate_reset_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
int change = 0;
change = PRO_RATE_LOCKED ? 1 : 0 != ucontrol->value.integer.value[0] ? 1 : 0;
PRO_RATE_RESET = ucontrol->value.integer.value[0] ? 1 : 0;
return change;
}
static snd_kcontrol_new_t snd_ice1712_pro_rate_reset __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track IEC958 Master", .name = "Multi Track Rate Reset",
.info = snd_ice1712_pro_spdif_master_info, .info = snd_ice1712_pro_rate_reset_info,
.get = snd_ice1712_pro_spdif_master_get, .get = snd_ice1712_pro_rate_reset_get,
.put = snd_ice1712_pro_spdif_master_put .put = snd_ice1712_pro_rate_reset_put
}; };
/* /*
...@@ -2113,7 +2250,13 @@ static int __devinit snd_ice1712_build_controls(ice1712_t *ice) ...@@ -2113,7 +2250,13 @@ static int __devinit snd_ice1712_build_controls(ice1712_t *ice)
err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_eeprom, ice)); err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_eeprom, ice));
if (err < 0) if (err < 0)
return err; return err;
err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_pro_spdif_master, ice)); err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_pro_internal_clock, ice));
if (err < 0)
return err;
err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_pro_rate_locking, ice));
if (err < 0)
return err;
err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_pro_rate_reset, ice));
if (err < 0) if (err < 0)
return err; return err;
for (idx = 0; idx < ice->num_total_dacs; idx++) { for (idx = 0; idx < ice->num_total_dacs; idx++) {
...@@ -2283,7 +2426,7 @@ static int __devinit snd_ice1712_create(snd_card_t * card, ...@@ -2283,7 +2426,7 @@ static int __devinit snd_ice1712_create(snd_card_t * card,
/* /*
* *
* Registraton * Registration
* *
*/ */
......
...@@ -256,7 +256,7 @@ struct snd_ak4524 { ...@@ -256,7 +256,7 @@ struct snd_ak4524 {
struct snd_ak4524_ops { struct snd_ak4524_ops {
int (*start)(ice1712_t *, unsigned char *, int); int (*start)(ice1712_t *, unsigned char *, int);
void (*stop)(ice1712_t *, unsigned char *); void (*stop)(ice1712_t *, unsigned char *);
void (*set_rate_val)(ice1712_t *, unsigned char); void (*set_rate_val)(ice1712_t *, unsigned int);
} ops; } ops;
}; };
......
...@@ -178,7 +178,7 @@ void snd_hammerfall_free_buffer (struct pci_dev *pcidev, void *addr) ...@@ -178,7 +178,7 @@ void snd_hammerfall_free_buffer (struct pci_dev *pcidev, void *addr)
printk ("Hammerfall memory allocator: unknown buffer address or PCI device ID"); printk ("Hammerfall memory allocator: unknown buffer address or PCI device ID");
} }
static void hammerfall_free_buffers (void) static void __exit hammerfall_free_buffers (void)
{ {
int i; int i;
......
...@@ -85,7 +85,7 @@ static int __devinit snd_trident_probe(struct pci_dev *pci, ...@@ -85,7 +85,7 @@ static int __devinit snd_trident_probe(struct pci_dev *pci,
snd_card_t *card; snd_card_t *card;
trident_t *trident; trident_t *trident;
const char *str; const char *str;
int err; int err, pcm_dev = 0;
if (dev >= SNDRV_CARDS) if (dev >= SNDRV_CARDS)
return -ENODEV; return -ENODEV;
...@@ -106,21 +106,21 @@ static int __devinit snd_trident_probe(struct pci_dev *pci, ...@@ -106,21 +106,21 @@ static int __devinit snd_trident_probe(struct pci_dev *pci,
snd_card_free(card); snd_card_free(card);
return err; return err;
} }
if ((err = snd_trident_pcm(trident, 0, NULL)) < 0) { if ((err = snd_trident_pcm(trident, pcm_dev++, NULL)) < 0) {
snd_card_free(card); snd_card_free(card);
return err; return err;
} }
switch (trident->device) { switch (trident->device) {
case TRIDENT_DEVICE_ID_DX: case TRIDENT_DEVICE_ID_DX:
case TRIDENT_DEVICE_ID_NX: case TRIDENT_DEVICE_ID_NX:
if ((err = snd_trident_foldback_pcm(trident, 1, NULL)) < 0) { if ((err = snd_trident_foldback_pcm(trident, pcm_dev++, NULL)) < 0) {
snd_card_free(card); snd_card_free(card);
return err; return err;
} }
break; break;
} }
if (trident->device == TRIDENT_DEVICE_ID_NX) { if (trident->device == TRIDENT_DEVICE_ID_NX || trident->device == TRIDENT_DEVICE_ID_SI7018) {
if ((err = snd_trident_spdif_pcm(trident, 2, NULL)) < 0) { if ((err = snd_trident_spdif_pcm(trident, pcm_dev++, NULL)) < 0) {
snd_card_free(card); snd_card_free(card);
return err; return err;
} }
......
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
*
* SiS7018 S/PDIF support by Thomas Winischhofer <thomas@winischhofer.net>
*/ */
#include <sound/driver.h> #include <sound/driver.h>
...@@ -52,6 +54,7 @@ static void snd_trident_interrupt(int irq, void *dev_id, struct pt_regs *regs); ...@@ -52,6 +54,7 @@ static void snd_trident_interrupt(int irq, void *dev_id, struct pt_regs *regs);
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int snd_trident_set_power_state(snd_card_t *card, unsigned int power_state); static int snd_trident_set_power_state(snd_card_t *card, unsigned int power_state);
#endif #endif
static int snd_trident_sis_reset(trident_t *trident);
/* /*
* common I/O routines * common I/O routines
...@@ -149,7 +152,7 @@ static unsigned short snd_trident_codec_read(ac97_t *ac97, unsigned short reg) ...@@ -149,7 +152,7 @@ static unsigned short snd_trident_codec_read(ac97_t *ac97, unsigned short reg)
} while (--count); } while (--count);
} }
if (count == 0) { if (count == 0 && !trident->ac97_detect) {
snd_printk("ac97 codec read TIMEOUT [0x%x/0x%x]!!!\n", reg, data); snd_printk("ac97 codec read TIMEOUT [0x%x/0x%x]!!!\n", reg, data);
data = 0; data = 0;
} }
...@@ -477,6 +480,15 @@ void snd_trident_write_voice_regs(trident_t * trident, ...@@ -477,6 +480,15 @@ void snd_trident_write_voice_regs(trident_t * trident,
outl(regs[2], TRID_REG(trident, CH_START + 8)); outl(regs[2], TRID_REG(trident, CH_START + 8));
outl(regs[3], TRID_REG(trident, CH_START + 12)); outl(regs[3], TRID_REG(trident, CH_START + 12));
outl(regs[4], TRID_REG(trident, CH_START + 16)); outl(regs[4], TRID_REG(trident, CH_START + 16));
#if 0
printk("written %i channel:\n", voice->number);
printk(" regs[0] = 0x%x/0x%x\n", regs[0], inl(TRID_REG(trident, CH_START + 0)));
printk(" regs[1] = 0x%x/0x%x\n", regs[1], inl(TRID_REG(trident, CH_START + 4)));
printk(" regs[2] = 0x%x/0x%x\n", regs[2], inl(TRID_REG(trident, CH_START + 8)));
printk(" regs[3] = 0x%x/0x%x\n", regs[3], inl(TRID_REG(trident, CH_START + 12)));
printk(" regs[4] = 0x%x/0x%x\n", regs[4], inl(TRID_REG(trident, CH_START + 16)));
#endif
} }
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------
...@@ -727,9 +739,9 @@ static int snd_trident_ioctl(snd_pcm_substream_t * substream, ...@@ -727,9 +739,9 @@ static int snd_trident_ioctl(snd_pcm_substream_t * substream,
} }
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------
snd_trident_playback_hw_params snd_trident_allocate_pcm_mem
Description: Set the hardware parameters for the playback device. Description: Allocate PCM ring buffer for given substream
Parameters: substream - PCM substream class Parameters: substream - PCM substream class
hw_params - hardware parameters hw_params - hardware parameters
...@@ -738,14 +750,12 @@ static int snd_trident_ioctl(snd_pcm_substream_t * substream, ...@@ -738,14 +750,12 @@ static int snd_trident_ioctl(snd_pcm_substream_t * substream,
---------------------------------------------------------------------------*/ ---------------------------------------------------------------------------*/
static int snd_trident_playback_hw_params(snd_pcm_substream_t * substream, int snd_trident_allocate_pcm_mem(snd_pcm_substream_t * substream,
snd_pcm_hw_params_t * hw_params) snd_pcm_hw_params_t * hw_params)
{ {
trident_t *trident = snd_pcm_substream_chip(substream); trident_t *trident = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_runtime_t *runtime = substream->runtime;
snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data; snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data;
snd_trident_voice_t *evoice = voice->extra;
unsigned long flags;
int err; int err;
if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
...@@ -753,16 +763,38 @@ static int snd_trident_playback_hw_params(snd_pcm_substream_t * substream, ...@@ -753,16 +763,38 @@ static int snd_trident_playback_hw_params(snd_pcm_substream_t * substream,
if (err > 0 && trident->tlb.entries) { if (err > 0 && trident->tlb.entries) {
if (voice->memblk) if (voice->memblk)
snd_trident_free_pages(trident, voice->memblk); snd_trident_free_pages(trident, voice->memblk);
spin_lock_irqsave(&trident->reg_lock, flags); spin_lock_irq(&trident->reg_lock);
voice->memblk = snd_trident_alloc_pages(trident, runtime->dma_area, runtime->dma_addr, runtime->dma_bytes); voice->memblk = snd_trident_alloc_pages(trident, runtime->dma_area, runtime->dma_addr, runtime->dma_bytes);
spin_unlock_irqrestore(&trident->reg_lock, flags); spin_unlock_irq(&trident->reg_lock);
if (voice->memblk == NULL) if (voice->memblk == NULL)
return -ENOMEM; return -ENOMEM;
} }
return 0;
}
/*---------------------------------------------------------------------------
snd_trident_allocate_evoice
Description: Allocate extra voice as interrupt generator
Parameters: substream - PCM substream class
hw_params - hardware parameters
Returns: Error status
---------------------------------------------------------------------------*/
int snd_trident_allocate_evoice(snd_pcm_substream_t * substream,
snd_pcm_hw_params_t * hw_params)
{
trident_t *trident = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data;
snd_trident_voice_t *evoice = voice->extra;
/* voice management */ /* voice management */
if (params_buffer_size(hw_params) / 2 != params_period_size(hw_params)) { if (params_buffer_size(hw_params) / 2 != params_buffer_size(hw_params)) {
if (evoice == NULL) { if (evoice == NULL) {
evoice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_PCM, 0, 0); evoice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_PCM, 0, 0);
if (evoice == NULL) if (evoice == NULL)
...@@ -780,6 +812,29 @@ static int snd_trident_playback_hw_params(snd_pcm_substream_t * substream, ...@@ -780,6 +812,29 @@ static int snd_trident_playback_hw_params(snd_pcm_substream_t * substream,
return 0; return 0;
} }
/*---------------------------------------------------------------------------
snd_trident_hw_params
Description: Set the hardware parameters for the playback device.
Parameters: substream - PCM substream class
hw_params - hardware parameters
Returns: Error status
---------------------------------------------------------------------------*/
static int snd_trident_hw_params(snd_pcm_substream_t * substream,
snd_pcm_hw_params_t * hw_params)
{
int err;
err = snd_trident_allocate_pcm_mem(substream, hw_params);
if (err >= 0)
err = snd_trident_allocate_evoice(substream, hw_params);
return err;
}
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------
snd_trident_playback_hw_free snd_trident_playback_hw_free
...@@ -791,7 +846,7 @@ static int snd_trident_playback_hw_params(snd_pcm_substream_t * substream, ...@@ -791,7 +846,7 @@ static int snd_trident_playback_hw_params(snd_pcm_substream_t * substream,
---------------------------------------------------------------------------*/ ---------------------------------------------------------------------------*/
static int snd_trident_playback_hw_free(snd_pcm_substream_t * substream) static int snd_trident_hw_free(snd_pcm_substream_t * substream)
{ {
trident_t *trident = snd_pcm_substream_chip(substream); trident_t *trident = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_runtime_t *runtime = substream->runtime;
...@@ -828,9 +883,8 @@ static int snd_trident_playback_prepare(snd_pcm_substream_t * substream) ...@@ -828,9 +883,8 @@ static int snd_trident_playback_prepare(snd_pcm_substream_t * substream)
snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data; snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data;
snd_trident_voice_t *evoice = voice->extra; snd_trident_voice_t *evoice = voice->extra;
snd_trident_pcm_mixer_t *mix = &trident->pcm_mixer[substream->number]; snd_trident_pcm_mixer_t *mix = &trident->pcm_mixer[substream->number];
unsigned long flags;
spin_lock_irqsave(&trident->reg_lock, flags); spin_lock(&trident->reg_lock);
/* set delta (rate) value */ /* set delta (rate) value */
voice->Delta = snd_trident_convert_rate(runtime->rate); voice->Delta = snd_trident_convert_rate(runtime->rate);
...@@ -855,6 +909,12 @@ static int snd_trident_playback_prepare(snd_pcm_substream_t * substream) ...@@ -855,6 +909,12 @@ static int snd_trident_playback_prepare(snd_pcm_substream_t * substream)
voice->CVol = mix->cvol; voice->CVol = mix->cvol;
voice->Pan = mix->pan; voice->Pan = mix->pan;
voice->Attribute = 0; voice->Attribute = 0;
#if 0
voice->Attribute = (1<<(30-16))|(2<<(26-16))|
(0<<(24-16))|(0x1f<<(19-16));
#else
voice->Attribute = 0;
#endif
snd_trident_write_voice_regs(trident, voice); snd_trident_write_voice_regs(trident, voice);
...@@ -875,14 +935,14 @@ static int snd_trident_playback_prepare(snd_pcm_substream_t * substream) ...@@ -875,14 +935,14 @@ static int snd_trident_playback_prepare(snd_pcm_substream_t * substream)
evoice->Pan = 0x7f; /* mute */ evoice->Pan = 0x7f; /* mute */
#if 0 #if 0
evoice->Attribute = (1<<(30-16))|(2<<(26-16))| evoice->Attribute = (1<<(30-16))|(2<<(26-16))|
(1<<(24-16))|(0x1f<<(19-16)); (0<<(24-16))|(0x1f<<(19-16));
#else #else
evoice->Attribute = 0; evoice->Attribute = 0;
#endif #endif
snd_trident_write_voice_regs(trident, evoice); snd_trident_write_voice_regs(trident, evoice);
} }
spin_unlock_irqrestore(&trident->reg_lock, flags); spin_unlock(&trident->reg_lock);
return 0; return 0;
} }
...@@ -902,49 +962,7 @@ static int snd_trident_playback_prepare(snd_pcm_substream_t * substream) ...@@ -902,49 +962,7 @@ static int snd_trident_playback_prepare(snd_pcm_substream_t * substream)
static int snd_trident_capture_hw_params(snd_pcm_substream_t * substream, static int snd_trident_capture_hw_params(snd_pcm_substream_t * substream,
snd_pcm_hw_params_t * hw_params) snd_pcm_hw_params_t * hw_params)
{ {
trident_t *trident = snd_pcm_substream_chip(substream); return snd_trident_allocate_pcm_mem(substream, hw_params);
snd_pcm_runtime_t *runtime = substream->runtime;
snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data;
unsigned long flags;
int err;
if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
return err;
if (err > 0 && trident->tlb.entries) {
if (voice->memblk)
snd_trident_free_pages(trident, voice->memblk);
spin_lock_irqsave(&trident->reg_lock, flags);
voice->memblk = snd_trident_alloc_pages(trident, runtime->dma_area, runtime->dma_addr, runtime->dma_bytes);
spin_unlock_irqrestore(&trident->reg_lock, flags);
if (voice->memblk == NULL)
return -ENOMEM;
}
return 0;
}
/*---------------------------------------------------------------------------
snd_trident_capture_hw_free
Description: Release the hardware resources for the capture device.
Parameters: substream - PCM substream class
Returns: Error status
---------------------------------------------------------------------------*/
static int snd_trident_capture_hw_free(snd_pcm_substream_t * substream)
{
trident_t *trident = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data;
if (trident->tlb.entries && voice && voice->memblk) {
snd_trident_free_pages(trident, voice->memblk);
voice->memblk = NULL;
}
snd_pcm_lib_free_pages(substream);
return 0;
} }
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------
...@@ -964,9 +982,8 @@ static int snd_trident_capture_prepare(snd_pcm_substream_t * substream) ...@@ -964,9 +982,8 @@ static int snd_trident_capture_prepare(snd_pcm_substream_t * substream)
snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_runtime_t *runtime = substream->runtime;
snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data; snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data;
unsigned int val, ESO_bytes; unsigned int val, ESO_bytes;
unsigned long flags;
spin_lock_irqsave(&trident->reg_lock, flags); spin_lock(&trident->reg_lock);
// Initilize the channel and set channel Mode // Initilize the channel and set channel Mode
outb(0, TRID_REG(trident, LEGACY_DMAR15)); outb(0, TRID_REG(trident, LEGACY_DMAR15));
...@@ -1037,7 +1054,7 @@ static int snd_trident_capture_prepare(snd_pcm_substream_t * substream) ...@@ -1037,7 +1054,7 @@ static int snd_trident_capture_prepare(snd_pcm_substream_t * substream)
snd_trident_write_voice_regs(trident, voice); snd_trident_write_voice_regs(trident, voice);
spin_unlock_irqrestore(&trident->reg_lock, flags); spin_unlock(&trident->reg_lock);
return 0; return 0;
} }
...@@ -1056,33 +1073,12 @@ static int snd_trident_capture_prepare(snd_pcm_substream_t * substream) ...@@ -1056,33 +1073,12 @@ static int snd_trident_capture_prepare(snd_pcm_substream_t * substream)
static int snd_trident_si7018_capture_hw_params(snd_pcm_substream_t * substream, static int snd_trident_si7018_capture_hw_params(snd_pcm_substream_t * substream,
snd_pcm_hw_params_t * hw_params) snd_pcm_hw_params_t * hw_params)
{ {
trident_t *trident = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data;
snd_trident_voice_t *evoice = voice->extra;
int err; int err;
if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
return err; return err;
/* voice management */ return snd_trident_allocate_evoice(substream, hw_params);
if (params_buffer_size(hw_params) / 2 != params_period_size(hw_params)) {
if (evoice == NULL) {
evoice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_PCM, 0, 0);
if (evoice == NULL)
return -ENOMEM;
voice->extra = evoice;
evoice->substream = substream;
}
} else {
if (evoice != NULL) {
snd_trident_free_voice(trident, evoice);
voice->extra = evoice = NULL;
}
}
return 0;
} }
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------
...@@ -1128,9 +1124,8 @@ static int snd_trident_si7018_capture_prepare(snd_pcm_substream_t * substream) ...@@ -1128,9 +1124,8 @@ static int snd_trident_si7018_capture_prepare(snd_pcm_substream_t * substream)
snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_runtime_t *runtime = substream->runtime;
snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data; snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data;
snd_trident_voice_t *evoice = voice->extra; snd_trident_voice_t *evoice = voice->extra;
unsigned long flags;
spin_lock_irqsave(&trident->reg_lock, flags); spin_lock(&trident->reg_lock);
voice->LBA = runtime->dma_addr; voice->LBA = runtime->dma_addr;
voice->Delta = snd_trident_convert_adc_rate(runtime->rate); voice->Delta = snd_trident_convert_adc_rate(runtime->rate);
...@@ -1176,91 +1171,7 @@ static int snd_trident_si7018_capture_prepare(snd_pcm_substream_t * substream) ...@@ -1176,91 +1171,7 @@ static int snd_trident_si7018_capture_prepare(snd_pcm_substream_t * substream)
snd_trident_write_voice_regs(trident, evoice); snd_trident_write_voice_regs(trident, evoice);
} }
spin_unlock_irqrestore(&trident->reg_lock, flags); spin_unlock(&trident->reg_lock);
return 0;
}
/*---------------------------------------------------------------------------
snd_trident_foldback_hw_params
Description: Set the hardware parameters for the foldback device.
Parameters: substream - PCM substream class
hw_params - hardware parameters
Returns: Error status
---------------------------------------------------------------------------*/
static int snd_trident_foldback_hw_params(snd_pcm_substream_t * substream,
snd_pcm_hw_params_t * hw_params)
{
trident_t *trident = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data;
snd_trident_voice_t *evoice = voice->extra;
unsigned long flags;
int err;
if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
return err;
if (err > 0 && trident->tlb.entries) {
if (voice->memblk)
snd_trident_free_pages(trident, voice->memblk);
spin_lock_irqsave(&trident->reg_lock, flags);
voice->memblk = snd_trident_alloc_pages(trident, runtime->dma_area, runtime->dma_addr, runtime->dma_bytes);
spin_unlock_irqrestore(&trident->reg_lock, flags);
if (voice->memblk == NULL)
return -ENOMEM;
}
/* voice management */
if (params_buffer_size(hw_params) / 2 != params_buffer_size(hw_params)) {
if (evoice == NULL) {
evoice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_PCM, 0, 0);
if (evoice == NULL)
return -ENOMEM;
voice->extra = evoice;
evoice->substream = substream;
}
} else {
if (evoice != NULL) {
snd_trident_free_voice(trident, evoice);
voice->extra = evoice = NULL;
}
}
return 0;
}
/*---------------------------------------------------------------------------
snd_trident_foldback_hw_free
Description: Release the hardware resources for the foldback device.
Parameters: substream - PCM substream class
Returns: Error status
---------------------------------------------------------------------------*/
static int snd_trident_foldback_hw_free(snd_pcm_substream_t * substream)
{
trident_t *trident = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data;
snd_trident_voice_t *evoice = voice ? voice->extra : NULL;
if (trident->tlb.entries && voice && voice->memblk) {
snd_trident_free_pages(trident, voice->memblk);
voice->memblk = NULL;
}
snd_pcm_lib_free_pages(substream);
if (evoice != NULL) {
snd_trident_free_voice(trident, evoice);
voice->extra = NULL;
}
return 0; return 0;
} }
...@@ -1281,9 +1192,8 @@ static int snd_trident_foldback_prepare(snd_pcm_substream_t * substream) ...@@ -1281,9 +1192,8 @@ static int snd_trident_foldback_prepare(snd_pcm_substream_t * substream)
snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_runtime_t *runtime = substream->runtime;
snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data; snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data;
snd_trident_voice_t *evoice = voice->extra; snd_trident_voice_t *evoice = voice->extra;
unsigned long flags;
spin_lock_irqsave(&trident->reg_lock, flags); spin_lock(&trident->reg_lock);
/* Set channel buffer Address */ /* Set channel buffer Address */
if (voice->memblk) if (voice->memblk)
...@@ -1335,7 +1245,7 @@ static int snd_trident_foldback_prepare(snd_pcm_substream_t * substream) ...@@ -1335,7 +1245,7 @@ static int snd_trident_foldback_prepare(snd_pcm_substream_t * substream)
snd_trident_write_voice_regs(trident, evoice); snd_trident_write_voice_regs(trident, evoice);
} }
spin_unlock_irqrestore(&trident->reg_lock, flags); spin_unlock(&trident->reg_lock);
return 0; return 0;
} }
...@@ -1355,26 +1265,21 @@ static int snd_trident_spdif_hw_params(snd_pcm_substream_t * substream, ...@@ -1355,26 +1265,21 @@ static int snd_trident_spdif_hw_params(snd_pcm_substream_t * substream,
snd_pcm_hw_params_t * hw_params) snd_pcm_hw_params_t * hw_params)
{ {
trident_t *trident = snd_pcm_substream_chip(substream); trident_t *trident = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data;
unsigned long flags;
unsigned int old_bits = 0, change = 0; unsigned int old_bits = 0, change = 0;
int err; int err;
if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) err = snd_trident_allocate_pcm_mem(substream, hw_params);
if (err < 0)
return err; return err;
if (err > 0 && trident->tlb.entries) {
if (voice->memblk) if (trident->device == TRIDENT_DEVICE_ID_SI7018) {
snd_trident_free_pages(trident, voice->memblk); err = snd_trident_allocate_evoice(substream, hw_params);
spin_lock_irqsave(&trident->reg_lock, flags); if (err < 0)
voice->memblk = snd_trident_alloc_pages(trident, runtime->dma_area, runtime->dma_addr, runtime->dma_bytes); return err;
spin_unlock_irqrestore(&trident->reg_lock, flags);
if (voice->memblk == NULL)
return -ENOMEM;
} }
/* prepare SPDIF channel */ /* prepare SPDIF channel */
spin_lock_irqsave(&trident->reg_lock, flags); spin_lock_irq(&trident->reg_lock);
old_bits = trident->spdif_pcm_bits; old_bits = trident->spdif_pcm_bits;
if (old_bits & IEC958_AES0_PROFESSIONAL) if (old_bits & IEC958_AES0_PROFESSIONAL)
trident->spdif_pcm_bits &= ~IEC958_AES0_PRO_FS; trident->spdif_pcm_bits &= ~IEC958_AES0_PRO_FS;
...@@ -1402,7 +1307,7 @@ static int snd_trident_spdif_hw_params(snd_pcm_substream_t * substream, ...@@ -1402,7 +1307,7 @@ static int snd_trident_spdif_hw_params(snd_pcm_substream_t * substream,
(IEC958_AES3_CON_FS_32000 << 24); (IEC958_AES3_CON_FS_32000 << 24);
} }
change = old_bits != trident->spdif_pcm_bits; change = old_bits != trident->spdif_pcm_bits;
spin_unlock_irqrestore(&trident->reg_lock, flags); spin_unlock_irq(&trident->reg_lock);
if (change) if (change)
snd_ctl_notify(trident->card, SNDRV_CTL_EVENT_MASK_VALUE, &trident->spdif_pcm_ctl->id); snd_ctl_notify(trident->card, SNDRV_CTL_EVENT_MASK_VALUE, &trident->spdif_pcm_ctl->id);
...@@ -1410,31 +1315,6 @@ static int snd_trident_spdif_hw_params(snd_pcm_substream_t * substream, ...@@ -1410,31 +1315,6 @@ static int snd_trident_spdif_hw_params(snd_pcm_substream_t * substream,
return 0; return 0;
} }
/*---------------------------------------------------------------------------
snd_trident_spdif_hw_free
Description: Release the hardware resources for the spdif device.
Parameters: substream - PCM substream class
Returns: Error status
---------------------------------------------------------------------------*/
static int snd_trident_spdif_hw_free(snd_pcm_substream_t * substream)
{
trident_t *trident = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data;
if (trident->tlb.entries && voice && voice->memblk) {
snd_trident_free_pages(trident, voice->memblk);
voice->memblk = NULL;
}
snd_pcm_lib_free_pages(substream);
return 0;
}
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------
snd_trident_spdif_prepare snd_trident_spdif_prepare
...@@ -1451,55 +1331,116 @@ static int snd_trident_spdif_prepare(snd_pcm_substream_t * substream) ...@@ -1451,55 +1331,116 @@ static int snd_trident_spdif_prepare(snd_pcm_substream_t * substream)
trident_t *trident = snd_pcm_substream_chip(substream); trident_t *trident = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_runtime_t *runtime = substream->runtime;
snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data; snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data;
snd_trident_voice_t *evoice = voice->extra;
snd_trident_pcm_mixer_t *mix = &trident->pcm_mixer[substream->number];
unsigned int RESO, LBAO; unsigned int RESO, LBAO;
unsigned long flags; unsigned int temp;
spin_lock_irqsave(&trident->reg_lock, flags);
/* set delta (rate) value */ spin_lock(&trident->reg_lock);
voice->Delta = snd_trident_convert_rate(runtime->rate);
voice->spurious_threshold = snd_trident_spurious_threshold(runtime->rate, runtime->period_size);
/* set Loop Back Address */ if (trident->device != TRIDENT_DEVICE_ID_SI7018) {
LBAO = runtime->dma_addr;
if (voice->memblk)
voice->LBA = voice->memblk->offset;
else
voice->LBA = LBAO;
/* set target ESO for channel */ /* set delta (rate) value */
RESO = runtime->buffer_size - 1; voice->Delta = snd_trident_convert_rate(runtime->rate);
voice->ESO = (runtime->period_size * 2) - 1; voice->spurious_threshold = snd_trident_spurious_threshold(runtime->rate, runtime->period_size);
/* set ctrl mode */ /* set Loop Back Address */
voice->CTRL = snd_trident_control_mode(substream); LBAO = runtime->dma_addr;
if (voice->memblk)
voice->LBA = voice->memblk->offset;
else
voice->LBA = LBAO;
/* set target ESO for channel */
RESO = runtime->buffer_size - 1;
voice->ESO = (runtime->period_size * 2) - 1;
/* set ctrl mode */
voice->CTRL = snd_trident_control_mode(substream);
voice->FMC = 3;
voice->RVol = 0x7f;
voice->CVol = 0x7f;
voice->GVSel = 1;
voice->Pan = 0x7f;
voice->Vol = 0x3ff;
voice->EC = 0;
voice->CSO = 0;
voice->Alpha = 0;
voice->FMS = 0;
voice->Attribute = 0;
/* prepare surrogate IRQ channel */
snd_trident_write_voice_regs(trident, voice);
outw((RESO & 0xffff), TRID_REG(trident, NX_SPESO));
outb((RESO >> 16), TRID_REG(trident, NX_SPESO + 2));
outl((LBAO & 0xfffffffc), TRID_REG(trident, NX_SPLBA));
outw((voice->CSO & 0xffff), TRID_REG(trident, NX_SPCTRL_SPCSO));
outb((voice->CSO >> 16), TRID_REG(trident, NX_SPCTRL_SPCSO + 2));
/* set SPDIF setting */
outb(trident->spdif_pcm_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3));
outl(trident->spdif_pcm_bits, TRID_REG(trident, NX_SPCSTATUS));
voice->FMC = 3; } else { /* SiS */
voice->RVol = 0x7f;
voice->CVol = 0x7f; /* set delta (rate) value */
voice->GVSel = 1; voice->Delta = 0x800;
voice->Pan = 0x7f; voice->spurious_threshold = snd_trident_spurious_threshold(48000, runtime->period_size);
voice->Vol = 0x3ff;
voice->EC = 0;
voice->CSO = 0;
voice->Alpha = 0;
voice->FMS = 0;
voice->Attribute = 0;
/* prepare surrogate IRQ channel */ /* set Loop Begin Address */
snd_trident_write_voice_regs(trident, voice); if (voice->memblk)
voice->LBA = voice->memblk->offset;
else
voice->LBA = runtime->dma_addr;
voice->CSO = 0;
voice->ESO = runtime->buffer_size - 1; /* in samples */
voice->CTRL = snd_trident_control_mode(substream);
voice->FMC = 3;
voice->GVSel = 1;
voice->EC = 0;
voice->Alpha = 0;
voice->FMS = 0;
voice->Vol = mix->vol;
voice->RVol = mix->rvol;
voice->CVol = mix->cvol;
voice->Pan = mix->pan;
voice->Attribute = (1<<(30-16))|(7<<(26-16))|
(0<<(24-16))|(0<<(19-16));
snd_trident_write_voice_regs(trident, voice);
outw((RESO & 0xffff), TRID_REG(trident, NX_SPESO)); if (evoice != NULL) {
outb((RESO >> 16), TRID_REG(trident, NX_SPESO + 2)); evoice->Delta = voice->Delta;
outl((LBAO & 0xfffffffc), TRID_REG(trident, NX_SPLBA)); evoice->spurious_threshold = voice->spurious_threshold;
outw((voice->CSO & 0xffff), TRID_REG(trident, NX_SPCTRL_SPCSO)); evoice->LBA = voice->LBA;
outb((voice->CSO >> 16), TRID_REG(trident, NX_SPCTRL_SPCSO + 2)); evoice->CSO = 0;
evoice->ESO = (runtime->period_size * 2) - 1; /* in samples */
evoice->CTRL = voice->CTRL;
evoice->FMC = 3;
evoice->GVSel = trident->device == TRIDENT_DEVICE_ID_SI7018 ? 0 : 1;
evoice->EC = 0;
evoice->Alpha = 0;
evoice->FMS = 0;
evoice->Vol = 0x3ff; /* mute */
evoice->RVol = evoice->CVol = 0x7f; /* mute */
evoice->Pan = 0x7f; /* mute */
evoice->Attribute = 0;
snd_trident_write_voice_regs(trident, evoice);
}
/* set SPDIF setting */ outl(trident->spdif_pcm_bits, TRID_REG(trident, SI_SPDIF_CS));
outb(trident->spdif_pcm_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3)); temp = inl(TRID_REG(trident, T4D_LFO_GC_CIR));
outl(trident->spdif_pcm_bits, TRID_REG(trident, NX_SPCSTATUS)); temp &= ~(1<<19);
outl(temp, TRID_REG(trident, T4D_LFO_GC_CIR));
temp = inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL));
temp |= SPDIF_EN;
outl(temp, TRID_REG(trident, SI_SERIAL_INTF_CTRL));
}
spin_unlock_irqrestore(&trident->reg_lock, flags); spin_unlock(&trident->reg_lock);
return 0; return 0;
} }
...@@ -1570,8 +1511,14 @@ static int snd_trident_trigger(snd_pcm_substream_t *substream, ...@@ -1570,8 +1511,14 @@ static int snd_trident_trigger(snd_pcm_substream_t *substream,
s = s->link_next; s = s->link_next;
} while (s != substream); } while (s != substream);
if (spdif_flag) { if (spdif_flag) {
outl(trident->spdif_pcm_bits, TRID_REG(trident, NX_SPCSTATUS)); if (trident->device != TRIDENT_DEVICE_ID_SI7018) {
outb(trident->spdif_pcm_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3)); outl(trident->spdif_pcm_bits, TRID_REG(trident, NX_SPCSTATUS));
outb(trident->spdif_pcm_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3));
} else {
outl(trident->spdif_pcm_bits, TRID_REG(trident, SI_SPDIF_CS));
val = inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)) | SPDIF_EN;
outl(val, TRID_REG(trident, SI_SERIAL_INTF_CTRL));
}
} }
if (!go) if (!go)
outl(what, TRID_REG(trident, T4D_STOP_B)); outl(what, TRID_REG(trident, T4D_STOP_B));
...@@ -1584,7 +1531,7 @@ static int snd_trident_trigger(snd_pcm_substream_t *substream, ...@@ -1584,7 +1531,7 @@ static int snd_trident_trigger(snd_pcm_substream_t *substream,
outl(val, TRID_REG(trident, T4D_AINTEN_B)); outl(val, TRID_REG(trident, T4D_AINTEN_B));
if (go) { if (go) {
outl(what, TRID_REG(trident, T4D_START_B)); outl(what, TRID_REG(trident, T4D_START_B));
if (capture_flag && trident->device != TRIDENT_DEVICE_ID_SI7018) if (capture_flag && trident->device != TRIDENT_DEVICE_ID_SI7018)
outb(trident->bDMAStart, TRID_REG(trident, T4D_SBCTRL_SBE2R_SBDD)); outb(trident->bDMAStart, TRID_REG(trident, T4D_SBCTRL_SBE2R_SBDD));
} else { } else {
...@@ -1790,6 +1737,26 @@ static snd_pcm_hardware_t snd_trident_spdif = ...@@ -1790,6 +1737,26 @@ static snd_pcm_hardware_t snd_trident_spdif =
.fifo_size = 0, .fifo_size = 0,
}; };
static snd_pcm_hardware_t snd_trident_spdif_7018 =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_48000,
.rate_min = 48000,
.rate_max = 48000,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = (128*1024),
.period_bytes_min = 64,
.period_bytes_max = (128*1024),
.periods_min = 1,
.periods_max = 1024,
.fifo_size = 0,
};
static void snd_trident_pcm_free_substream(snd_pcm_runtime_t *runtime) static void snd_trident_pcm_free_substream(snd_pcm_runtime_t *runtime)
{ {
unsigned long flags; unsigned long flags;
...@@ -1876,7 +1843,11 @@ static int snd_trident_spdif_open(snd_pcm_substream_t * substream) ...@@ -1876,7 +1843,11 @@ static int snd_trident_spdif_open(snd_pcm_substream_t * substream)
runtime->private_data = voice; runtime->private_data = voice;
runtime->private_free = snd_trident_pcm_free_substream; runtime->private_free = snd_trident_pcm_free_substream;
runtime->hw = snd_trident_spdif; if (trident->device == TRIDENT_DEVICE_ID_SI7018) {
runtime->hw = snd_trident_spdif;
} else {
runtime->hw = snd_trident_spdif_7018;
}
trident->spdif_pcm_ctl->access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; trident->spdif_pcm_ctl->access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
snd_ctl_notify(trident->card, SNDRV_CTL_EVENT_MASK_VALUE | snd_ctl_notify(trident->card, SNDRV_CTL_EVENT_MASK_VALUE |
...@@ -1899,11 +1870,23 @@ static int snd_trident_spdif_open(snd_pcm_substream_t * substream) ...@@ -1899,11 +1870,23 @@ static int snd_trident_spdif_open(snd_pcm_substream_t * substream)
static int snd_trident_spdif_close(snd_pcm_substream_t * substream) static int snd_trident_spdif_close(snd_pcm_substream_t * substream)
{ {
trident_t *trident = snd_pcm_substream_chip(substream); trident_t *trident = snd_pcm_substream_chip(substream);
unsigned int temp;
spin_lock_irq(&trident->reg_lock); spin_lock_irq(&trident->reg_lock);
// restore default SPDIF setting // restore default SPDIF setting
outb(trident->spdif_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3)); if (trident->device != TRIDENT_DEVICE_ID_SI7018) {
outl(trident->spdif_bits, TRID_REG(trident, NX_SPCSTATUS)); outb(trident->spdif_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3));
outl(trident->spdif_bits, TRID_REG(trident, NX_SPCSTATUS));
} else {
outl(trident->spdif_bits, TRID_REG(trident, SI_SPDIF_CS));
temp = inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL));
if (trident->spdif_ctrl) {
temp |= SPDIF_EN;
} else {
temp &= ~SPDIF_EN;
}
outl(temp, TRID_REG(trident, SI_SERIAL_INTF_CTRL));
}
spin_unlock_irq(&trident->reg_lock); spin_unlock_irq(&trident->reg_lock);
trident->spdif_pcm_ctl->access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; trident->spdif_pcm_ctl->access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
snd_ctl_notify(trident->card, SNDRV_CTL_EVENT_MASK_VALUE | snd_ctl_notify(trident->card, SNDRV_CTL_EVENT_MASK_VALUE |
...@@ -2031,8 +2014,8 @@ static snd_pcm_ops_t snd_trident_playback_ops = { ...@@ -2031,8 +2014,8 @@ static snd_pcm_ops_t snd_trident_playback_ops = {
.open = snd_trident_playback_open, .open = snd_trident_playback_open,
.close = snd_trident_playback_close, .close = snd_trident_playback_close,
.ioctl = snd_trident_ioctl, .ioctl = snd_trident_ioctl,
.hw_params = snd_trident_playback_hw_params, .hw_params = snd_trident_hw_params,
.hw_free = snd_trident_playback_hw_free, .hw_free = snd_trident_hw_free,
.prepare = snd_trident_playback_prepare, .prepare = snd_trident_playback_prepare,
.trigger = snd_trident_trigger, .trigger = snd_trident_trigger,
.pointer = snd_trident_playback_pointer, .pointer = snd_trident_playback_pointer,
...@@ -2043,7 +2026,7 @@ static snd_pcm_ops_t snd_trident_capture_ops = { ...@@ -2043,7 +2026,7 @@ static snd_pcm_ops_t snd_trident_capture_ops = {
.close = snd_trident_capture_close, .close = snd_trident_capture_close,
.ioctl = snd_trident_ioctl, .ioctl = snd_trident_ioctl,
.hw_params = snd_trident_capture_hw_params, .hw_params = snd_trident_capture_hw_params,
.hw_free = snd_trident_capture_hw_free, .hw_free = snd_trident_hw_free,
.prepare = snd_trident_capture_prepare, .prepare = snd_trident_capture_prepare,
.trigger = snd_trident_trigger, .trigger = snd_trident_trigger,
.pointer = snd_trident_capture_pointer, .pointer = snd_trident_capture_pointer,
...@@ -2064,8 +2047,8 @@ static snd_pcm_ops_t snd_trident_foldback_ops = { ...@@ -2064,8 +2047,8 @@ static snd_pcm_ops_t snd_trident_foldback_ops = {
.open = snd_trident_foldback_open, .open = snd_trident_foldback_open,
.close = snd_trident_foldback_close, .close = snd_trident_foldback_close,
.ioctl = snd_trident_ioctl, .ioctl = snd_trident_ioctl,
.hw_params = snd_trident_foldback_hw_params, .hw_params = snd_trident_hw_params,
.hw_free = snd_trident_foldback_hw_free, .hw_free = snd_trident_hw_free,
.prepare = snd_trident_foldback_prepare, .prepare = snd_trident_foldback_prepare,
.trigger = snd_trident_trigger, .trigger = snd_trident_trigger,
.pointer = snd_trident_playback_pointer, .pointer = snd_trident_playback_pointer,
...@@ -2076,12 +2059,23 @@ static snd_pcm_ops_t snd_trident_spdif_ops = { ...@@ -2076,12 +2059,23 @@ static snd_pcm_ops_t snd_trident_spdif_ops = {
.close = snd_trident_spdif_close, .close = snd_trident_spdif_close,
.ioctl = snd_trident_ioctl, .ioctl = snd_trident_ioctl,
.hw_params = snd_trident_spdif_hw_params, .hw_params = snd_trident_spdif_hw_params,
.hw_free = snd_trident_spdif_hw_free, .hw_free = snd_trident_hw_free,
.prepare = snd_trident_spdif_prepare, .prepare = snd_trident_spdif_prepare,
.trigger = snd_trident_trigger, .trigger = snd_trident_trigger,
.pointer = snd_trident_spdif_pointer, .pointer = snd_trident_spdif_pointer,
}; };
static snd_pcm_ops_t snd_trident_spdif_7018_ops = {
.open = snd_trident_spdif_open,
.close = snd_trident_spdif_close,
.ioctl = snd_trident_ioctl,
.hw_params = snd_trident_spdif_hw_params,
.hw_free = snd_trident_hw_free,
.prepare = snd_trident_spdif_prepare,
.trigger = snd_trident_trigger,
.pointer = snd_trident_playback_pointer,
};
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------
snd_trident_pcm_free snd_trident_pcm_free
...@@ -2227,7 +2221,11 @@ int __devinit snd_trident_spdif_pcm(trident_t * trident, int device, snd_pcm_t * ...@@ -2227,7 +2221,11 @@ int __devinit snd_trident_spdif_pcm(trident_t * trident, int device, snd_pcm_t *
spdif->private_data = trident; spdif->private_data = trident;
spdif->private_free = snd_trident_spdif_pcm_free; spdif->private_free = snd_trident_spdif_pcm_free;
snd_pcm_set_ops(spdif, SNDRV_PCM_STREAM_PLAYBACK, &snd_trident_spdif_ops); if (trident->device != TRIDENT_DEVICE_ID_SI7018) {
snd_pcm_set_ops(spdif, SNDRV_PCM_STREAM_PLAYBACK, &snd_trident_spdif_ops);
} else {
snd_pcm_set_ops(spdif, SNDRV_PCM_STREAM_PLAYBACK, &snd_trident_spdif_7018_ops);
}
spdif->info_flags = 0; spdif->info_flags = 0;
strcpy(spdif->name, "Trident 4DWave IEC958"); strcpy(spdif->name, "Trident 4DWave IEC958");
trident->spdif = spdif; trident->spdif = spdif;
...@@ -2286,9 +2284,20 @@ static int snd_trident_spdif_control_put(snd_kcontrol_t * kcontrol, ...@@ -2286,9 +2284,20 @@ static int snd_trident_spdif_control_put(snd_kcontrol_t * kcontrol,
/* S/PDIF C Channel bits 0-31 : 48khz, SCMS disabled */ /* S/PDIF C Channel bits 0-31 : 48khz, SCMS disabled */
change = trident->spdif_ctrl != val; change = trident->spdif_ctrl != val;
trident->spdif_ctrl = val; trident->spdif_ctrl = val;
if ((inb(TRID_REG(trident, NX_SPCTRL_SPCSO + 3)) & 0x10) == 0) { if (trident->device != TRIDENT_DEVICE_ID_SI7018) {
outl(trident->spdif_bits, TRID_REG(trident, NX_SPCSTATUS)); if ((inb(TRID_REG(trident, NX_SPCTRL_SPCSO + 3)) & 0x10) == 0) {
outb(trident->spdif_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3)); outl(trident->spdif_bits, TRID_REG(trident, NX_SPCSTATUS));
outb(trident->spdif_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3));
}
} else {
if (trident->spdif == NULL) {
unsigned int temp;
outl(trident->spdif_bits, TRID_REG(trident, SI_SPDIF_CS));
temp = inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)) & ~SPDIF_EN;
if (val)
temp |= SPDIF_EN;
outl(temp, TRID_REG(trident, SI_SERIAL_INTF_CTRL));
}
} }
spin_unlock_irqrestore(&trident->reg_lock, flags); spin_unlock_irqrestore(&trident->reg_lock, flags);
return change; return change;
...@@ -2347,16 +2356,21 @@ static int snd_trident_spdif_default_put(snd_kcontrol_t * kcontrol, ...@@ -2347,16 +2356,21 @@ static int snd_trident_spdif_default_put(snd_kcontrol_t * kcontrol,
spin_lock_irqsave(&trident->reg_lock, flags); spin_lock_irqsave(&trident->reg_lock, flags);
change = trident->spdif_bits != val; change = trident->spdif_bits != val;
trident->spdif_bits = val; trident->spdif_bits = val;
if ((inb(TRID_REG(trident, NX_SPCTRL_SPCSO + 3)) & 0x10) == 0) if (trident->device != TRIDENT_DEVICE_ID_SI7018) {
outl(trident->spdif_bits, TRID_REG(trident, NX_SPCSTATUS)); if ((inb(TRID_REG(trident, NX_SPCTRL_SPCSO + 3)) & 0x10) == 0)
outl(trident->spdif_bits, TRID_REG(trident, NX_SPCSTATUS));
} else {
if (trident->spdif == NULL)
outl(trident->spdif_bits, TRID_REG(trident, SI_SPDIF_CS));
}
spin_unlock_irqrestore(&trident->reg_lock, flags); spin_unlock_irqrestore(&trident->reg_lock, flags);
return change; return change;
} }
static snd_kcontrol_new_t snd_trident_spdif_default __devinitdata = static snd_kcontrol_new_t snd_trident_spdif_default __devinitdata =
{ {
.iface = SNDRV_CTL_ELEM_IFACE_PCM, .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
.info = snd_trident_spdif_default_info, .info = snd_trident_spdif_default_info,
.get = snd_trident_spdif_default_get, .get = snd_trident_spdif_default_get,
.put = snd_trident_spdif_default_put .put = snd_trident_spdif_default_put
...@@ -2437,8 +2451,13 @@ static int snd_trident_spdif_stream_put(snd_kcontrol_t * kcontrol, ...@@ -2437,8 +2451,13 @@ static int snd_trident_spdif_stream_put(snd_kcontrol_t * kcontrol,
spin_lock_irqsave(&trident->reg_lock, flags); spin_lock_irqsave(&trident->reg_lock, flags);
change = trident->spdif_pcm_bits != val; change = trident->spdif_pcm_bits != val;
trident->spdif_pcm_bits = val; trident->spdif_pcm_bits = val;
if (trident->spdif != NULL) if (trident->spdif != NULL) {
outl(trident->spdif_pcm_bits, TRID_REG(trident, NX_SPCSTATUS)); if (trident->device != TRIDENT_DEVICE_ID_SI7018) {
outl(trident->spdif_pcm_bits, TRID_REG(trident, NX_SPCSTATUS));
} else {
outl(trident->spdif_bits, TRID_REG(trident, SI_SPDIF_CS));
}
}
spin_unlock_irqrestore(&trident->reg_lock, flags); spin_unlock_irqrestore(&trident->reg_lock, flags);
return change; return change;
} }
...@@ -2873,7 +2892,7 @@ static int __devinit snd_trident_mixer(trident_t * trident, int pcm_spdif_device ...@@ -2873,7 +2892,7 @@ static int __devinit snd_trident_mixer(trident_t * trident, int pcm_spdif_device
snd_card_t * card = trident->card; snd_card_t * card = trident->card;
snd_kcontrol_t *kctl; snd_kcontrol_t *kctl;
snd_ctl_elem_value_t uctl; snd_ctl_elem_value_t uctl;
int idx, err; int idx, err, retries = 2;
memset(&uctl, 0, sizeof(uctl)); memset(&uctl, 0, sizeof(uctl));
...@@ -2881,8 +2900,19 @@ static int __devinit snd_trident_mixer(trident_t * trident, int pcm_spdif_device ...@@ -2881,8 +2900,19 @@ static int __devinit snd_trident_mixer(trident_t * trident, int pcm_spdif_device
_ac97.write = snd_trident_codec_write; _ac97.write = snd_trident_codec_write;
_ac97.read = snd_trident_codec_read; _ac97.read = snd_trident_codec_read;
_ac97.private_data = trident; _ac97.private_data = trident;
if ((err = snd_ac97_mixer(trident->card, &_ac97, &ac97)) < 0) trident->ac97_detect = 1;
__again:
if ((err = snd_ac97_mixer(trident->card, &_ac97, &ac97)) < 0) {
if (trident->device == TRIDENT_DEVICE_ID_SI7018) {
if ((err = snd_trident_sis_reset(trident)) < 0)
return err;
if (retries-- > 0)
goto __again;
return -EIO;
}
return err; return err;
}
trident->ac97_detect = 0;
if (trident->device != TRIDENT_DEVICE_ID_SI7018) { if (trident->device != TRIDENT_DEVICE_ID_SI7018) {
if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_trident_vol_wave_control, trident))) < 0) if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_trident_vol_wave_control, trident))) < 0)
...@@ -2934,6 +2964,8 @@ static int __devinit snd_trident_mixer(trident_t * trident, int pcm_spdif_device ...@@ -2934,6 +2964,8 @@ static int __devinit snd_trident_mixer(trident_t * trident, int pcm_spdif_device
if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_trident_ac97_rear_control, trident))) < 0) if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_trident_ac97_rear_control, trident))) < 0)
return err; return err;
kctl->put(kctl, &uctl); kctl->put(kctl, &uctl);
}
if (trident->device == TRIDENT_DEVICE_ID_NX || trident->device == TRIDENT_DEVICE_ID_SI7018) {
if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_trident_spdif_control, trident))) < 0) if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_trident_spdif_control, trident))) < 0)
return err; return err;
kctl->put(kctl, &uctl); kctl->put(kctl, &uctl);
...@@ -3046,6 +3078,55 @@ void __devinit snd_trident_gameport(trident_t *chip) ...@@ -3046,6 +3078,55 @@ void __devinit snd_trident_gameport(trident_t *chip)
} }
#endif #endif
/*
* SiS reset routine
*/
static int snd_trident_sis_reset(trident_t *trident)
{
signed long end_time;
unsigned int i;
int r;
r = 2; /* count of retries */
__si7018_retry:
pci_write_config_byte(trident->pci, 0x46, 0x04); /* SOFTWARE RESET */
udelay(100);
pci_write_config_byte(trident->pci, 0x46, 0x00);
udelay(100);
/* disable AC97 GPIO interrupt */
outb(0x00, TRID_REG(trident, SI_AC97_GPIO));
/* initialize serial interface, force cold reset */
i = PCMOUT|SURROUT|CENTEROUT|LFEOUT|SECONDARY_ID|COLD_RESET;
outl(i, TRID_REG(trident, SI_SERIAL_INTF_CTRL));
udelay(1000);
/* remove cold reset */
i &= ~COLD_RESET;
outl(i, TRID_REG(trident, SI_SERIAL_INTF_CTRL));
udelay(2000);
/* wait, until the codec is ready */
end_time = (jiffies + (HZ * 3) / 4) + 1;
do {
if ((inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)) & SI_AC97_PRIMARY_READY) != 0)
goto __si7018_ok;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
} while (time_after_eq(end_time, jiffies));
snd_printk("AC'97 codec ready error [0x%x]\n", inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)));
if (r-- > 0) {
end_time = jiffies + HZ;
do {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
} while (time_after_eq(end_time, jiffies));
goto __si7018_retry;
}
__si7018_ok:
/* enable 64 channel mode */
outl(BANK_B_EN, TRID_REG(trident, T4D_LFO_GC_CIR));
return 0;
}
/* /*
* /proc interface * /proc interface
*/ */
...@@ -3072,8 +3153,9 @@ static void snd_trident_proc_read(snd_info_entry_t *entry, ...@@ -3072,8 +3153,9 @@ static void snd_trident_proc_read(snd_info_entry_t *entry,
snd_iprintf(buffer, "%s\n\n", s); snd_iprintf(buffer, "%s\n\n", s);
snd_iprintf(buffer, "Spurious IRQs : %d\n", trident->spurious_irq_count); snd_iprintf(buffer, "Spurious IRQs : %d\n", trident->spurious_irq_count);
snd_iprintf(buffer, "Spurious IRQ dlta: %d\n", trident->spurious_irq_max_delta); snd_iprintf(buffer, "Spurious IRQ dlta: %d\n", trident->spurious_irq_max_delta);
if (trident->device == TRIDENT_DEVICE_ID_NX) { if (trident->device == TRIDENT_DEVICE_ID_NX || trident->device == TRIDENT_DEVICE_ID_SI7018)
snd_iprintf(buffer, "IEC958 Mixer Out : %s\n", trident->spdif_ctrl == 0x28 ? "on" : "off"); snd_iprintf(buffer, "IEC958 Mixer Out : %s\n", trident->spdif_ctrl == 0x28 ? "on" : "off");
if (trident->device == TRIDENT_DEVICE_ID_NX) {
snd_iprintf(buffer, "Rear Speakers : %s\n", trident->ac97_ctrl & 0x00000010 ? "on" : "off"); snd_iprintf(buffer, "Rear Speakers : %s\n", trident->ac97_ctrl & 0x00000010 ? "on" : "off");
if (trident->tlb.entries) { if (trident->tlb.entries) {
snd_iprintf(buffer,"\nVirtual Memory\n"); snd_iprintf(buffer,"\nVirtual Memory\n");
...@@ -3318,35 +3400,10 @@ int __devinit snd_trident_create(snd_card_t * card, ...@@ -3318,35 +3400,10 @@ int __devinit snd_trident_create(snd_card_t * card,
outl(NX_SB_IRQ_DISABLE, TRID_REG(trident, T4D_MISCINT)); outl(NX_SB_IRQ_DISABLE, TRID_REG(trident, T4D_MISCINT));
break; break;
case TRIDENT_DEVICE_ID_SI7018: case TRIDENT_DEVICE_ID_SI7018:
pci_write_config_byte(pci, 0x46, 0x04); /* SOFTWARE RESET */ if ((err = snd_trident_sis_reset(trident)) < 0) {
udelay(100); snd_trident_free(trident);
pci_write_config_byte(pci, 0x46, 0x00); return err;
udelay(100); }
/* disable AC97 GPIO interrupt */
outb(0x00, TRID_REG(trident, SI_AC97_GPIO));
/* initialize serial interface, force cold reset */
i = PCMOUT|SURROUT|CENTEROUT|LFEOUT|SECONDARY_ID|COLD_RESET;
outl(i, TRID_REG(trident, SI_SERIAL_INTF_CTRL));
udelay(1000);
/* remove cold reset */
i &= ~COLD_RESET;
outl(i, TRID_REG(trident, SI_SERIAL_INTF_CTRL));
udelay(2000);
/* wait, until the codec is ready */
end_time = (jiffies + (HZ * 3) / 4) + 1;
do {
if ((inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)) & SI_AC97_PRIMARY_READY) != 0)
goto __si7018_ok;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
} while (end_time - (signed long)jiffies >= 0);
snd_printk("AC'97 codec ready error [0x%x]\n", inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)));
snd_trident_free(trident);
return -EIO;
__si7018_ok:
/* enable 64 channel mode */
outl(BANK_B_EN, TRID_REG(trident, T4D_LFO_GC_CIR));
break;
} }
outl(0xffffffff, TRID_REG(trident, T4D_STOP_A)); outl(0xffffffff, TRID_REG(trident, T4D_STOP_A));
...@@ -3374,6 +3431,12 @@ int __devinit snd_trident_create(snd_card_t * card, ...@@ -3374,6 +3431,12 @@ int __devinit snd_trident_create(snd_card_t * card,
outb(trident->spdif_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3)); outb(trident->spdif_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3));
} }
if (trident->device == TRIDENT_DEVICE_ID_SI7018) {
/* initialize S/PDIF */
trident->spdif_bits = trident->spdif_pcm_bits = SNDRV_PCM_DEFAULT_CON_SPDIF;
outl(trident->spdif_bits, TRID_REG(trident, SI_SPDIF_CS));
}
/* initialise synth voices */ /* initialise synth voices */
for (i = 0; i < 64; i++) { for (i = 0; i < 64; i++) {
voice = &trident->synth.voices[i]; voice = &trident->synth.voices[i];
...@@ -3429,6 +3492,9 @@ int snd_trident_free(trident_t *trident) ...@@ -3429,6 +3492,9 @@ int snd_trident_free(trident_t *trident)
// Disable S/PDIF out // Disable S/PDIF out
if (trident->device == TRIDENT_DEVICE_ID_NX) if (trident->device == TRIDENT_DEVICE_ID_NX)
outb(0x00, TRID_REG(trident, NX_SPCTRL_SPCSO + 3)); outb(0x00, TRID_REG(trident, NX_SPCTRL_SPCSO + 3));
else if (trident->device == TRIDENT_DEVICE_ID_SI7018) {
outl(0, TRID_REG(trident, SI_SERIAL_INTF_CTRL));
}
snd_trident_proc_done(trident); snd_trident_proc_done(trident);
if (trident->tlb.buffer) { if (trident->tlb.buffer) {
outl(0, TRID_REG(trident, NX_TLBC)); outl(0, TRID_REG(trident, NX_TLBC));
......
...@@ -202,4 +202,8 @@ int snd_usb_create_midi_interface(snd_usb_audio_t *chip, struct usb_interface *i ...@@ -202,4 +202,8 @@ int snd_usb_create_midi_interface(snd_usb_audio_t *chip, struct usb_interface *i
#define get_cfg_desc(cfg) (&(cfg)->desc) #define get_cfg_desc(cfg) (&(cfg)->desc)
#endif #endif
#ifndef usb_pipe_needs_resubmit
#define usb_pipe_needs_resubmit(pipe) 1
#endif
#endif /* __USBAUDIO_H */ #endif /* __USBAUDIO_H */
...@@ -114,7 +114,6 @@ struct snd_usb_midi_in_endpoint { ...@@ -114,7 +114,6 @@ struct snd_usb_midi_in_endpoint {
struct urb* urb; struct urb* urb;
struct usbmidi_in_port { struct usbmidi_in_port {
snd_rawmidi_substream_t* substream; snd_rawmidi_substream_t* substream;
int active;
} ports[0x10]; } ports[0x10];
}; };
...@@ -159,7 +158,12 @@ static void snd_usbmidi_input_packet(snd_usb_midi_in_endpoint_t* ep, ...@@ -159,7 +158,12 @@ static void snd_usbmidi_input_packet(snd_usb_midi_in_endpoint_t* ep,
int cable = packet[0] >> 4; int cable = packet[0] >> 4;
usbmidi_in_port_t* port = &ep->ports[cable]; usbmidi_in_port_t* port = &ep->ports[cable];
if (!port->active) if (!port->substream) {
snd_printd("unexpected port %d!\n", cable);
return;
}
if (!port->substream->runtime ||
!port->substream->runtime->trigger)
return; return;
snd_rawmidi_receive(port->substream, &packet[1], snd_rawmidi_receive(port->substream, &packet[1],
snd_usbmidi_cin_length[packet[0] & 0x0f]); snd_usbmidi_cin_length[packet[0] & 0x0f]);
...@@ -184,8 +188,10 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb) ...@@ -184,8 +188,10 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb)
return; return;
} }
urb->dev = ep->umidi->chip->dev; if (usb_pipe_needs_resubmit(urb->pipe)) {
snd_usbmidi_submit_urb(urb, GFP_ATOMIC); urb->dev = ep->umidi->chip->dev;
snd_usbmidi_submit_urb(urb, GFP_ATOMIC);
}
} }
/* /*
...@@ -451,20 +457,6 @@ static void snd_usbmidi_output_trigger(snd_rawmidi_substream_t* substream, int u ...@@ -451,20 +457,6 @@ static void snd_usbmidi_output_trigger(snd_rawmidi_substream_t* substream, int u
static int snd_usbmidi_input_open(snd_rawmidi_substream_t* substream) static int snd_usbmidi_input_open(snd_rawmidi_substream_t* substream)
{ {
snd_usb_midi_t* umidi = snd_magic_cast(snd_usb_midi_t, substream->rmidi->private_data, return -ENXIO);
usbmidi_in_port_t* port = NULL;
int i, j;
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)
if (umidi->endpoints[i].in)
for (j = 0; j < 0x10; ++j)
if (umidi->endpoints[i].in->ports[j].substream == substream) {
port = &umidi->endpoints[i].in->ports[j];
break;
}
if (!port)
return -ENXIO;
substream->runtime->private_data = port;
return 0; return 0;
} }
...@@ -475,9 +467,6 @@ static int snd_usbmidi_input_close(snd_rawmidi_substream_t* substream) ...@@ -475,9 +467,6 @@ static int snd_usbmidi_input_close(snd_rawmidi_substream_t* substream)
static void snd_usbmidi_input_trigger(snd_rawmidi_substream_t* substream, int up) static void snd_usbmidi_input_trigger(snd_rawmidi_substream_t* substream, int up)
{ {
usbmidi_in_port_t* port = (usbmidi_in_port_t*)substream->runtime->private_data;
port->active = up;
} }
static snd_rawmidi_ops_t snd_usbmidi_output_ops = { static snd_rawmidi_ops_t snd_usbmidi_output_ops = {
......
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