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 @@
#define DSP_SPDIF_STATUS_OUTPUT_ENABLED 1
#define DSP_SPDIF_STATUS_PLAYBACK_OPEN 2
#define DSP_SPDIF_STATUS_HW_ENABLED 4
#define DSP_SPDIF_STATUS_AC3_MODE 8
struct _dsp_module_desc_t;
......@@ -196,6 +195,10 @@ typedef struct _dsp_spos_instance_t {
int spdif_status_in;
u16 spdif_input_volume_right;
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 */
dsp_scb_descriptor_t * spdif_in_src;
......
......@@ -101,10 +101,18 @@
/* Global registers */
enum global_control_bits {
CHANNEL_IDX = 0x0000003f, OVERRUN_IE = 0x00000400,
UNDERRUN_IE = 0x00000800, ENDLP_IE = 0x00001000,
MIDLP_IE = 0x00002000, ETOG_IE = 0x00004000,
EDROP_IE = 0x00008000, BANK_B_EN = 0x00010000
CHANNEL_IDX = 0x0000003f,
OVERRUN_IE = 0x00000400, /* interrupt enable: capture overrun */
UNDERRUN_IE = 0x00000800, /* interrupt enable: playback underrun */
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 {
......@@ -423,6 +431,8 @@ struct _snd_trident {
int ChanPCM; /* max 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 */
spinlock_t event_lock;
......
/* include/version.h. Generated automatically by configure. */
#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)
snd_seq_fm_init(&opl3->fm_ops, NULL);
/* setup system timer */
memset(&opl3->tlist, 0, sizeof(opl3->tlist));
init_timer(&opl3->tlist);
opl3->tlist.function = snd_opl3_timer_func;
opl3->tlist.data = (unsigned long) opl3;
......
......@@ -51,6 +51,9 @@
#define SNDRV_GET_ID
#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_DESCRIPTION("Dummy soundcard for virtual rawmidi devices");
MODULE_LICENSE("GPL");
......
......@@ -10,6 +10,12 @@
* Note: 16-bit wide is assigned to first direction which made request.
* 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
* 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,
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
#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)
cs46xx_dsp_pcm_link(chip,cpcm->pcm_channel);
if (substream->runtime->periods != CS46XX_FRAGS)
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
if (substream->runtime->periods != CS46XX_FRAGS)
snd_cs46xx_playback_transfer(substream, 0);
......@@ -972,8 +972,9 @@ static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream,
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
#ifdef CONFIG_SND_CS46XX_NEW_DSP
/* mute channel */
cs46xx_dsp_scb_set_volume (chip,cpcm->pcm_channel->pcm_reader_scb,0,0);
/* magic mute channel */
snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address +
SCBVolumeCtrl) << 2, 0xffffffff);
if (!cpcm->pcm_channel->unlinked)
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,
}
#endif
static int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream,
snd_pcm_hw_params_t * hw_params)
{
......@@ -1083,15 +1085,10 @@ static int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream,
down (&chip->spos_mutex);
snd_assert (cpcm->pcm_channel != NULL);
/* if IEC958 is opened in AC3 mode dont adjust SRCTask is not
used so dont adjust sample rate */
if (cpcm->pcm_channel->pcm_channel_id != DSP_IEC958_CHANNEL ||
!(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_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)) {
......@@ -2042,34 +2039,6 @@ static int snd_cs46xx_pcm_capture_get(snd_kcontrol_t *kcontrol,
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,
snd_ctl_elem_value_t *ucontrol)
......@@ -2131,6 +2100,110 @@ static int snd_herc_spdif_select_put(snd_kcontrol_t *kcontrol,
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 */
#ifdef CONFIG_SND_CS46XX_DEBUG_GPIO
......@@ -2242,7 +2315,7 @@ static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = {
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC 958 Output Switch",
.name = "IEC958 Output Switch",
.info = snd_mixer_boolean_info,
.get = snd_cs46xx_iec958_get,
.put = snd_cs46xx_iec958_put,
......@@ -2250,14 +2323,7 @@ static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = {
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC 958 AC3 Mode 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",
.name = "IEC958 Input Switch",
.info = snd_mixer_boolean_info,
.get = snd_cs46xx_iec958_get,
.put = snd_cs46xx_iec958_put,
......@@ -2265,12 +2331,34 @@ static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = {
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC 958 Input Volume",
.name = "IEC958 Input Volume",
.info = snd_cs46xx_vol_info,
.get = snd_cs46xx_vol_iec958_get,
.put = snd_cs46xx_vol_iec958_put,
.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
#ifdef CONFIG_SND_CS46XX_DEBUG_GPIO
{
......
......@@ -217,6 +217,6 @@ int cs46xx_dsp_pcm_channel_set_period (cs46xx_t * chip,
int period_size);
int cs46xx_dsp_pcm_ostream_set_period (cs46xx_t * chip,
int period_size);
int cs46xx_dsp_set_dac_volume (cs46xx_t * chip,u16 right,u16 left);
int cs46xx_dsp_set_iec958_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 left,u16 right);
#endif /* __CS46XX_LIB_H__ */
......@@ -31,6 +31,7 @@
#include <sound/core.h>
#include <sound/control.h>
#include <sound/info.h>
#include <sound/asoundef.h>
#include <sound/cs46xx.h>
#include "cs46xx_lib.h"
......@@ -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_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;
}
......@@ -1549,7 +1559,7 @@ int cs46xx_dsp_enable_spdif_hw (cs46xx_t *chip)
cs46xx_poke_via_dsp (chip,SP_SPDOUT_CONTROL, 0x80000000);
/* 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 */
ins->spdif_status_out |= DSP_SPDIF_STATUS_HW_ENABLED;
......@@ -1587,11 +1597,6 @@ int cs46xx_dsp_enable_spdif_in (cs46xx_t *chip)
cs46xx_poke_via_dsp (chip,SP_SPDIN_FIFOPTR, 0x0);
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);
/* set SPDIF input sample rate and unmute
......@@ -1725,39 +1730,47 @@ int cs46xx_poke_via_dsp (cs46xx_t *chip,u32 address,u32 data)
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_scb_descriptor_t * scb;
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;
ins->dac_volume_left = left;
for (i = 0; i < DSP_MAX_PCM_CHANNELS; ++i) {
if (ins->pcm_channels[i].active &&
!ins->pcm_channels[i].unlinked) {
cs46xx_dsp_scb_set_volume (chip,ins->pcm_channels[i].pcm_reader_scb,
right,left);
}
/* rear output */
scb = ins->rear_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_left = left;
ins->dac_volume_right = right;
up(&chip->spos_mutex);
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;
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_right = right;
up(&chip->spos_mutex);
return 0;
......
......@@ -185,6 +185,25 @@ typedef enum {
#define SP_SPDOUT_CONTROL 0x804D
#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)
{
/* update nextSCB and subListPtr in SCB */
......@@ -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,
u16 right,u16 left) {
unsigned int val = ((0xffff - right) << 16 | (0xffff - left));
u16 left,u16 right) {
unsigned int val = ((0xffff - left) << 16 | (0xffff - right));
snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl) << 2, val);
snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl + 1) << 2, val);
}
#endif /* __DSP_SPOS_H__ */
#endif /* CONFIG_SND_CS46XX_NEW_DSP */
......@@ -603,8 +603,8 @@ cs46xx_dsp_create_src_task_scb(cs46xx_t * chip,char * scb_name,
src_buffer_addr << 0x10,
0x04000000,
{
0x8000,0x8000,
0xffff,0xffff
0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left,
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,
/* D */ 0,
{
/* 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,
0,0x2aab, /* Const 1/3 */
{
0, /* Define the unused elements */
0, /* Define the unused elements */
0,
0
},
......@@ -846,7 +846,7 @@ cs46xx_dsp_create_asynch_fg_tx_scb(cs46xx_t * chip,char * scb_name,u32 dest,
rate etc */
0x18000000, /* Phi increment for approx 32k operation */
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,
......@@ -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,
int scb_child_type)
{
dsp_spos_instance_t * ins = chip->dsp_spos_instance;
dsp_scb_descriptor_t * 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,
rate etc */
0x18000000,
/* Mute stream */
0x8000,0x8000,
0xffff,0xffff
/* Set IEC958 input volume */
0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
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,
......@@ -1116,11 +1116,13 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,
case DSP_IEC958_CHANNEL:
snd_assert (ins->asynch_tx_scb != NULL, return NULL);
mixer_scb = ins->asynch_tx_scb;
#if 0
if (ins->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE) {
snd_printdd ("IEC958 opened in AC3 mode\n");
/*src_scb = ins->asynch_tx_scb;
ins->asynch_tx_scb->ref_count ++;*/
}
#endif
break;
default:
snd_assert (0);
......@@ -1198,9 +1200,7 @@ pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,
return NULL;
}
if (pcm_channel_id != DSP_IEC958_CHANNEL ||
!(ins->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE))
cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate);
cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate);
ins->nsrc_scb ++;
}
......@@ -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);
/* mute SCB */
/* cs46xx_dsp_scb_set_volume (chip,src,0,0); */
snd_cs46xx_poke(chip, (src->address + SRCCorPerGof) << 2,
((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF));
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);
}
......@@ -1641,9 +1635,8 @@ int cs46xx_iec958_pre_open (cs46xx_t *chip)
SCB_ON_PARENT_NEXT_SCB);
if (ins->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE)
/* set left (13), right validity bit (12) , and non-audio(1) and profsional bit (0) */
cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, 0x00000000 | (1 << 13) | (1 << 12) | (1 << 1) | 1);
/* set spdif channel status value for streaming */
cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_stream);
ins->spdif_status_out |= DSP_SPDIF_STATUS_PLAYBACK_OPEN;
......@@ -1659,7 +1652,7 @@ int cs46xx_iec958_post_close (cs46xx_t *chip)
ins->spdif_status_out &= ~DSP_SPDIF_STATUS_PLAYBACK_OPEN;
/* 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 */
cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
......
......@@ -1355,6 +1355,7 @@ static snd_kcontrol_new_t snd_ens1373_spdif_default __devinitdata =
static snd_kcontrol_new_t snd_ens1373_spdif_mask __devinitdata =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
.info = snd_ens1373_spdif_info,
......@@ -2181,10 +2182,10 @@ static int __devinit snd_audiopci_probe(struct pci_dev *pci,
return err;
}
#ifdef CHIP1370
strcpy(card->driver, "ES1370");
strcpy(card->driver, "ENS1370");
#endif
#ifdef CHIP1371
strcpy(card->driver, "ES1371");
strcpy(card->driver, "ENS1371");
#endif
strcpy(card->shortname, "Ensoniq AudioPCI");
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
/*
* 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;
if (rate == 0) /* no hint - S/PDIF input is master, simply return */
return;
/* check before reset ak4524 to avoid unnecessary clicks */
down(&ice->gpio_mutex);
tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
up(&ice->gpio_mutex);
tmp2 = tmp;
tmp2 &= ~ICE1712_DELTA_DFS;
if (val == 15 || val == 11 || val == 7)
if (rate > 48000)
tmp2 |= ICE1712_DELTA_DFS;
if (tmp == tmp2)
return;
......@@ -275,12 +278,9 @@ static void delta_ak4524_set_rate_val(ice1712_t *ice, unsigned char val)
/* do it again */
snd_ice1712_ak4524_reset(ice, 1);
down(&ice->gpio_mutex);
tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
if (val == 15 || val == 11 || val == 7) {
tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & ~ICE1712_DELTA_DFS;
if (rate > 48000)
tmp |= ICE1712_DELTA_DFS;
} else {
tmp &= ~ICE1712_DELTA_DFS;
}
snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
up(&ice->gpio_mutex);
snd_ice1712_ak4524_reset(ice, 0);
......
......@@ -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_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
*/
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)
{
outb((channel << 4) | addr, ICEDS(ice, INDEX));
......@@ -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 int rate;
unsigned char val;
int old_lock_value;
spin_lock_irqsave(&ice->reg_lock, flags);
if ((inb(ICEMT(ice, PLAYBACK_CONTROL)) & (ICE1712_CAPTURE_START_SHADOW|
ICE1712_PLAYBACK_PAUSE|
ICE1712_PLAYBACK_START)) ||
(inb(ICEMT(ice, RATE)) & ICE1712_SPDIF_MASTER)) {
old_lock_value = PRO_RATE_LOCKED;
if (do_not_lock)
PRO_RATE_LOCKED = 0;
if (inb(ICEMT(ice, PLAYBACK_CONTROL)) & (ICE1712_CAPTURE_START_SHADOW|
ICE1712_PLAYBACK_PAUSE|
ICE1712_PLAYBACK_START)) {
spin_unlock_irqrestore(&ice->reg_lock, flags);
return;
}
rate = substream->runtime->rate;
if (!is_pro_rate_locked(ice))
goto __unlock;
switch (rate) {
case 8000: val = 6; 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
break;
}
outb(val, ICEMT(ice, RATE));
PRO_RATE_LOCKED = old_lock_value;
__unlock:
spin_unlock_irqrestore(&ice->reg_lock, flags);
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)
......@@ -1027,7 +1048,7 @@ static int snd_ice1712_playback_pro_prepare(snd_pcm_substream_t * substream)
ice1712_t *ice = snd_pcm_substream_chip(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);
outl(substream->runtime->dma_addr, ICEMT(ice, PLAYBACK_ADDR));
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)
ice1712_t *ice = snd_pcm_substream_chip(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);
outl(substream->runtime->dma_addr, ICEMT(ice, CAPTURE_ADDR));
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)
{
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;
if (ice->spdif.ops.close)
ice->spdif.ops.close(ice, 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);
if (PRO_RATE_RESET)
snd_ice1712_set_pro_rate(ice, PRO_RATE_DEFAULT, 0);
ice->capture_pro_substream = NULL;
return 0;
}
......@@ -1695,53 +1720,165 @@ int snd_ice1712_gpio_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucont
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->value.integer.min = 0;
uinfo->value.integer.max = 1;
uinfo->value.enumerated.items = 14;
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;
}
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);
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);
ucontrol->value.integer.value[0] = inb(ICEMT(ice, RATE)) & ICE1712_SPDIF_MASTER ? 1 : 0;
spin_unlock_irqrestore(&ice->reg_lock, flags);
spin_lock_irq(&ice->reg_lock);
if (is_spdif_master(ice)) {
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;
}
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);
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_irqsave(&ice->reg_lock, flags);
nval |= inb(ICEMT(ice, RATE)) & ~ICE1712_SPDIF_MASTER;
change = inb(ICEMT(ice, RATE)) != nval;
outb(nval, ICEMT(ice, RATE));
spin_unlock_irqrestore(&ice->reg_lock, flags);
spin_lock_irq(&ice->reg_lock);
oval = inb(ICEMT(ice, RATE));
if (ucontrol->value.enumerated.item[0] == 13) {
outb(oval | ICE1712_SPDIF_MASTER, ICEMT(ice, RATE));
} else {
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 */
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;
}
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,
.name = "Multi Track IEC958 Master",
.info = snd_ice1712_pro_spdif_master_info,
.get = snd_ice1712_pro_spdif_master_get,
.put = snd_ice1712_pro_spdif_master_put
.name = "Multi Track Rate Reset",
.info = snd_ice1712_pro_rate_reset_info,
.get = snd_ice1712_pro_rate_reset_get,
.put = snd_ice1712_pro_rate_reset_put
};
/*
......@@ -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));
if (err < 0)
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)
return err;
for (idx = 0; idx < ice->num_total_dacs; idx++) {
......@@ -2283,7 +2426,7 @@ static int __devinit snd_ice1712_create(snd_card_t * card,
/*
*
* Registraton
* Registration
*
*/
......
......@@ -256,7 +256,7 @@ struct snd_ak4524 {
struct snd_ak4524_ops {
int (*start)(ice1712_t *, unsigned char *, int);
void (*stop)(ice1712_t *, unsigned char *);
void (*set_rate_val)(ice1712_t *, unsigned char);
void (*set_rate_val)(ice1712_t *, unsigned int);
} ops;
};
......
......@@ -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");
}
static void hammerfall_free_buffers (void)
static void __exit hammerfall_free_buffers (void)
{
int i;
......
......@@ -85,7 +85,7 @@ static int __devinit snd_trident_probe(struct pci_dev *pci,
snd_card_t *card;
trident_t *trident;
const char *str;
int err;
int err, pcm_dev = 0;
if (dev >= SNDRV_CARDS)
return -ENODEV;
......@@ -106,21 +106,21 @@ static int __devinit snd_trident_probe(struct pci_dev *pci,
snd_card_free(card);
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);
return err;
}
switch (trident->device) {
case TRIDENT_DEVICE_ID_DX:
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);
return err;
}
break;
}
if (trident->device == TRIDENT_DEVICE_ID_NX) {
if ((err = snd_trident_spdif_pcm(trident, 2, NULL)) < 0) {
if (trident->device == TRIDENT_DEVICE_ID_NX || trident->device == TRIDENT_DEVICE_ID_SI7018) {
if ((err = snd_trident_spdif_pcm(trident, pcm_dev++, NULL)) < 0) {
snd_card_free(card);
return err;
}
......
......@@ -23,6 +23,8 @@
* along with this program; if not, write to the Free Software
* 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>
......@@ -52,6 +54,7 @@ static void snd_trident_interrupt(int irq, void *dev_id, struct pt_regs *regs);
#ifdef CONFIG_PM
static int snd_trident_set_power_state(snd_card_t *card, unsigned int power_state);
#endif
static int snd_trident_sis_reset(trident_t *trident);
/*
* common I/O routines
......@@ -149,7 +152,7 @@ static unsigned short snd_trident_codec_read(ac97_t *ac97, unsigned short reg)
} while (--count);
}
if (count == 0) {
if (count == 0 && !trident->ac97_detect) {
snd_printk("ac97 codec read TIMEOUT [0x%x/0x%x]!!!\n", reg, data);
data = 0;
}
......@@ -477,6 +480,15 @@ void snd_trident_write_voice_regs(trident_t * trident,
outl(regs[2], TRID_REG(trident, CH_START + 8));
outl(regs[3], TRID_REG(trident, CH_START + 12));
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,
}
/*---------------------------------------------------------------------------
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
hw_params - hardware parameters
......@@ -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,
snd_pcm_hw_params_t * hw_params)
int snd_trident_allocate_pcm_mem(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)
......@@ -753,16 +763,38 @@ static int snd_trident_playback_hw_params(snd_pcm_substream_t * substream,
if (err > 0 && trident->tlb.entries) {
if (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);
spin_unlock_irqrestore(&trident->reg_lock, flags);
spin_unlock_irq(&trident->reg_lock);
if (voice->memblk == NULL)
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 */
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) {
evoice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_PCM, 0, 0);
if (evoice == NULL)
......@@ -780,6 +812,29 @@ static int snd_trident_playback_hw_params(snd_pcm_substream_t * substream,
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
......@@ -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);
snd_pcm_runtime_t *runtime = substream->runtime;
......@@ -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 *evoice = voice->extra;
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 */
voice->Delta = snd_trident_convert_rate(runtime->rate);
......@@ -855,6 +909,12 @@ static int snd_trident_playback_prepare(snd_pcm_substream_t * substream)
voice->CVol = mix->cvol;
voice->Pan = mix->pan;
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);
......@@ -875,14 +935,14 @@ static int snd_trident_playback_prepare(snd_pcm_substream_t * substream)
evoice->Pan = 0x7f; /* mute */
#if 0
evoice->Attribute = (1<<(30-16))|(2<<(26-16))|
(1<<(24-16))|(0x1f<<(19-16));
(0<<(24-16))|(0x1f<<(19-16));
#else
evoice->Attribute = 0;
#endif
snd_trident_write_voice_regs(trident, evoice);
}
spin_unlock_irqrestore(&trident->reg_lock, flags);
spin_unlock(&trident->reg_lock);
return 0;
}
......@@ -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,
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;
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;
return snd_trident_allocate_pcm_mem(substream, hw_params);
}
/*---------------------------------------------------------------------------
......@@ -964,9 +982,8 @@ static int snd_trident_capture_prepare(snd_pcm_substream_t * substream)
snd_pcm_runtime_t *runtime = substream->runtime;
snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data;
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
outb(0, TRID_REG(trident, LEGACY_DMAR15));
......@@ -1037,7 +1054,7 @@ static int snd_trident_capture_prepare(snd_pcm_substream_t * substream)
snd_trident_write_voice_regs(trident, voice);
spin_unlock_irqrestore(&trident->reg_lock, flags);
spin_unlock(&trident->reg_lock);
return 0;
}
......@@ -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,
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;
if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
return err;
/* voice management */
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;
return snd_trident_allocate_evoice(substream, hw_params);
}
/*---------------------------------------------------------------------------
......@@ -1128,9 +1124,8 @@ static int snd_trident_si7018_capture_prepare(snd_pcm_substream_t * 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;
spin_lock_irqsave(&trident->reg_lock, flags);
spin_lock(&trident->reg_lock);
voice->LBA = runtime->dma_addr;
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)
snd_trident_write_voice_regs(trident, evoice);
}
spin_unlock_irqrestore(&trident->reg_lock, flags);
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;
}
spin_unlock(&trident->reg_lock);
return 0;
}
......@@ -1281,9 +1192,8 @@ static int snd_trident_foldback_prepare(snd_pcm_substream_t * 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;
spin_lock_irqsave(&trident->reg_lock, flags);
spin_lock(&trident->reg_lock);
/* Set channel buffer Address */
if (voice->memblk)
......@@ -1335,7 +1245,7 @@ static int snd_trident_foldback_prepare(snd_pcm_substream_t * substream)
snd_trident_write_voice_regs(trident, evoice);
}
spin_unlock_irqrestore(&trident->reg_lock, flags);
spin_unlock(&trident->reg_lock);
return 0;
}
......@@ -1355,26 +1265,21 @@ static int snd_trident_spdif_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;
unsigned long flags;
unsigned int old_bits = 0, change = 0;
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;
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;
if (trident->device == TRIDENT_DEVICE_ID_SI7018) {
err = snd_trident_allocate_evoice(substream, hw_params);
if (err < 0)
return err;
}
/* prepare SPDIF channel */
spin_lock_irqsave(&trident->reg_lock, flags);
spin_lock_irq(&trident->reg_lock);
old_bits = trident->spdif_pcm_bits;
if (old_bits & IEC958_AES0_PROFESSIONAL)
trident->spdif_pcm_bits &= ~IEC958_AES0_PRO_FS;
......@@ -1402,7 +1307,7 @@ static int snd_trident_spdif_hw_params(snd_pcm_substream_t * substream,
(IEC958_AES3_CON_FS_32000 << 24);
}
change = old_bits != trident->spdif_pcm_bits;
spin_unlock_irqrestore(&trident->reg_lock, flags);
spin_unlock_irq(&trident->reg_lock);
if (change)
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,
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
......@@ -1451,55 +1331,116 @@ static int snd_trident_spdif_prepare(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->extra;
snd_trident_pcm_mixer_t *mix = &trident->pcm_mixer[substream->number];
unsigned int RESO, LBAO;
unsigned long flags;
spin_lock_irqsave(&trident->reg_lock, flags);
unsigned int temp;
/* set delta (rate) value */
voice->Delta = snd_trident_convert_rate(runtime->rate);
voice->spurious_threshold = snd_trident_spurious_threshold(runtime->rate, runtime->period_size);
spin_lock(&trident->reg_lock);
/* set Loop Back Address */
LBAO = runtime->dma_addr;
if (voice->memblk)
voice->LBA = voice->memblk->offset;
else
voice->LBA = LBAO;
if (trident->device != TRIDENT_DEVICE_ID_SI7018) {
/* set target ESO for channel */
RESO = runtime->buffer_size - 1;
voice->ESO = (runtime->period_size * 2) - 1;
/* set delta (rate) value */
voice->Delta = snd_trident_convert_rate(runtime->rate);
voice->spurious_threshold = snd_trident_spurious_threshold(runtime->rate, runtime->period_size);
/* set ctrl mode */
voice->CTRL = snd_trident_control_mode(substream);
/* set Loop Back Address */
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;
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;
} else { /* SiS */
/* set delta (rate) value */
voice->Delta = 0x800;
voice->spurious_threshold = snd_trident_spurious_threshold(48000, runtime->period_size);
/* prepare surrogate IRQ channel */
snd_trident_write_voice_regs(trident, voice);
/* set Loop Begin Address */
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));
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));
if (evoice != NULL) {
evoice->Delta = voice->Delta;
evoice->spurious_threshold = voice->spurious_threshold;
evoice->LBA = voice->LBA;
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 */
outb(trident->spdif_pcm_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3));
outl(trident->spdif_pcm_bits, TRID_REG(trident, NX_SPCSTATUS));
outl(trident->spdif_pcm_bits, TRID_REG(trident, SI_SPDIF_CS));
temp = inl(TRID_REG(trident, T4D_LFO_GC_CIR));
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;
}
......@@ -1570,8 +1511,14 @@ static int snd_trident_trigger(snd_pcm_substream_t *substream,
s = s->link_next;
} while (s != substream);
if (spdif_flag) {
outl(trident->spdif_pcm_bits, TRID_REG(trident, NX_SPCSTATUS));
outb(trident->spdif_pcm_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3));
if (trident->device != TRIDENT_DEVICE_ID_SI7018) {
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)
outl(what, TRID_REG(trident, T4D_STOP_B));
......@@ -1584,7 +1531,7 @@ static int snd_trident_trigger(snd_pcm_substream_t *substream,
outl(val, TRID_REG(trident, T4D_AINTEN_B));
if (go) {
outl(what, TRID_REG(trident, T4D_START_B));
if (capture_flag && trident->device != TRIDENT_DEVICE_ID_SI7018)
outb(trident->bDMAStart, TRID_REG(trident, T4D_SBCTRL_SBE2R_SBDD));
} else {
......@@ -1790,6 +1737,26 @@ static snd_pcm_hardware_t snd_trident_spdif =
.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)
{
unsigned long flags;
......@@ -1876,7 +1843,11 @@ static int snd_trident_spdif_open(snd_pcm_substream_t * substream)
runtime->private_data = voice;
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;
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)
static int snd_trident_spdif_close(snd_pcm_substream_t * substream)
{
trident_t *trident = snd_pcm_substream_chip(substream);
unsigned int temp;
spin_lock_irq(&trident->reg_lock);
// restore default SPDIF setting
outb(trident->spdif_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3));
outl(trident->spdif_bits, TRID_REG(trident, NX_SPCSTATUS));
if (trident->device != TRIDENT_DEVICE_ID_SI7018) {
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);
trident->spdif_pcm_ctl->access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
snd_ctl_notify(trident->card, SNDRV_CTL_EVENT_MASK_VALUE |
......@@ -2031,8 +2014,8 @@ static snd_pcm_ops_t snd_trident_playback_ops = {
.open = snd_trident_playback_open,
.close = snd_trident_playback_close,
.ioctl = snd_trident_ioctl,
.hw_params = snd_trident_playback_hw_params,
.hw_free = snd_trident_playback_hw_free,
.hw_params = snd_trident_hw_params,
.hw_free = snd_trident_hw_free,
.prepare = snd_trident_playback_prepare,
.trigger = snd_trident_trigger,
.pointer = snd_trident_playback_pointer,
......@@ -2043,7 +2026,7 @@ static snd_pcm_ops_t snd_trident_capture_ops = {
.close = snd_trident_capture_close,
.ioctl = snd_trident_ioctl,
.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,
.trigger = snd_trident_trigger,
.pointer = snd_trident_capture_pointer,
......@@ -2064,8 +2047,8 @@ static snd_pcm_ops_t snd_trident_foldback_ops = {
.open = snd_trident_foldback_open,
.close = snd_trident_foldback_close,
.ioctl = snd_trident_ioctl,
.hw_params = snd_trident_foldback_hw_params,
.hw_free = snd_trident_foldback_hw_free,
.hw_params = snd_trident_hw_params,
.hw_free = snd_trident_hw_free,
.prepare = snd_trident_foldback_prepare,
.trigger = snd_trident_trigger,
.pointer = snd_trident_playback_pointer,
......@@ -2076,12 +2059,23 @@ static snd_pcm_ops_t snd_trident_spdif_ops = {
.close = snd_trident_spdif_close,
.ioctl = snd_trident_ioctl,
.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,
.trigger = snd_trident_trigger,
.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
......@@ -2227,7 +2221,11 @@ int __devinit snd_trident_spdif_pcm(trident_t * trident, int device, snd_pcm_t *
spdif->private_data = trident;
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;
strcpy(spdif->name, "Trident 4DWave IEC958");
trident->spdif = spdif;
......@@ -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 */
change = trident->spdif_ctrl != val;
trident->spdif_ctrl = val;
if ((inb(TRID_REG(trident, NX_SPCTRL_SPCSO + 3)) & 0x10) == 0) {
outl(trident->spdif_bits, TRID_REG(trident, NX_SPCSTATUS));
outb(trident->spdif_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3));
if (trident->device != TRIDENT_DEVICE_ID_SI7018) {
if ((inb(TRID_REG(trident, NX_SPCTRL_SPCSO + 3)) & 0x10) == 0) {
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);
return change;
......@@ -2347,16 +2356,21 @@ static int snd_trident_spdif_default_put(snd_kcontrol_t * kcontrol,
spin_lock_irqsave(&trident->reg_lock, flags);
change = trident->spdif_bits != val;
trident->spdif_bits = val;
if ((inb(TRID_REG(trident, NX_SPCTRL_SPCSO + 3)) & 0x10) == 0)
outl(trident->spdif_bits, TRID_REG(trident, NX_SPCSTATUS));
if (trident->device != TRIDENT_DEVICE_ID_SI7018) {
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);
return change;
}
static snd_kcontrol_new_t snd_trident_spdif_default __devinitdata =
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
.info = snd_trident_spdif_default_info,
.get = snd_trident_spdif_default_get,
.put = snd_trident_spdif_default_put
......@@ -2437,8 +2451,13 @@ static int snd_trident_spdif_stream_put(snd_kcontrol_t * kcontrol,
spin_lock_irqsave(&trident->reg_lock, flags);
change = trident->spdif_pcm_bits != val;
trident->spdif_pcm_bits = val;
if (trident->spdif != NULL)
outl(trident->spdif_pcm_bits, TRID_REG(trident, NX_SPCSTATUS));
if (trident->spdif != NULL) {
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);
return change;
}
......@@ -2873,7 +2892,7 @@ static int __devinit snd_trident_mixer(trident_t * trident, int pcm_spdif_device
snd_card_t * card = trident->card;
snd_kcontrol_t *kctl;
snd_ctl_elem_value_t uctl;
int idx, err;
int idx, err, retries = 2;
memset(&uctl, 0, sizeof(uctl));
......@@ -2881,8 +2900,19 @@ static int __devinit snd_trident_mixer(trident_t * trident, int pcm_spdif_device
_ac97.write = snd_trident_codec_write;
_ac97.read = snd_trident_codec_read;
_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;
}
trident->ac97_detect = 0;
if (trident->device != TRIDENT_DEVICE_ID_SI7018) {
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
if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_trident_ac97_rear_control, trident))) < 0)
return err;
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)
return err;
kctl->put(kctl, &uctl);
......@@ -3046,6 +3078,55 @@ void __devinit snd_trident_gameport(trident_t *chip)
}
#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
*/
......@@ -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, "Spurious IRQs : %d\n", trident->spurious_irq_count);
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");
if (trident->device == TRIDENT_DEVICE_ID_NX) {
snd_iprintf(buffer, "Rear Speakers : %s\n", trident->ac97_ctrl & 0x00000010 ? "on" : "off");
if (trident->tlb.entries) {
snd_iprintf(buffer,"\nVirtual Memory\n");
......@@ -3318,35 +3400,10 @@ int __devinit snd_trident_create(snd_card_t * card,
outl(NX_SB_IRQ_DISABLE, TRID_REG(trident, T4D_MISCINT));
break;
case TRIDENT_DEVICE_ID_SI7018:
pci_write_config_byte(pci, 0x46, 0x04); /* SOFTWARE RESET */
udelay(100);
pci_write_config_byte(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 (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;
if ((err = snd_trident_sis_reset(trident)) < 0) {
snd_trident_free(trident);
return err;
}
}
outl(0xffffffff, TRID_REG(trident, T4D_STOP_A));
......@@ -3374,6 +3431,12 @@ int __devinit snd_trident_create(snd_card_t * card,
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 */
for (i = 0; i < 64; i++) {
voice = &trident->synth.voices[i];
......@@ -3429,6 +3492,9 @@ int snd_trident_free(trident_t *trident)
// Disable S/PDIF out
if (trident->device == TRIDENT_DEVICE_ID_NX)
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);
if (trident->tlb.buffer) {
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
#define get_cfg_desc(cfg) (&(cfg)->desc)
#endif
#ifndef usb_pipe_needs_resubmit
#define usb_pipe_needs_resubmit(pipe) 1
#endif
#endif /* __USBAUDIO_H */
......@@ -114,7 +114,6 @@ struct snd_usb_midi_in_endpoint {
struct urb* urb;
struct usbmidi_in_port {
snd_rawmidi_substream_t* substream;
int active;
} ports[0x10];
};
......@@ -159,7 +158,12 @@ static void snd_usbmidi_input_packet(snd_usb_midi_in_endpoint_t* ep,
int cable = packet[0] >> 4;
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;
snd_rawmidi_receive(port->substream, &packet[1],
snd_usbmidi_cin_length[packet[0] & 0x0f]);
......@@ -184,8 +188,10 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb)
return;
}
urb->dev = ep->umidi->chip->dev;
snd_usbmidi_submit_urb(urb, GFP_ATOMIC);
if (usb_pipe_needs_resubmit(urb->pipe)) {
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
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;
}
......@@ -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)
{
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 = {
......
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