ALSA: pcxhr - add support for pcxhr stereo sound cards
- Add support for pcxhr stereo cards - do some clean up Signed-off-by: Markus Bollinger <bollinger@digigram.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
13d428afc0
commit
93bf5d8753
2 changed files with 190 additions and 106 deletions
|
@ -132,13 +132,15 @@ static int pcxhr_check_reg_bit(struct pcxhr_mgr *mgr, unsigned int reg,
|
|||
*read = PCXHR_INPB(mgr, reg);
|
||||
if ((*read & mask) == bit) {
|
||||
if (i > 100)
|
||||
snd_printdd("ATTENTION! check_reg(%x) loopcount=%d\n",
|
||||
snd_printdd("ATTENTION! check_reg(%x) "
|
||||
"loopcount=%d\n",
|
||||
reg, i);
|
||||
return 0;
|
||||
}
|
||||
i++;
|
||||
} while (time_after_eq(end_time, jiffies));
|
||||
snd_printk(KERN_ERR "pcxhr_check_reg_bit: timeout, reg=%x, mask=0x%x, val=0x%x\n",
|
||||
snd_printk(KERN_ERR
|
||||
"pcxhr_check_reg_bit: timeout, reg=%x, mask=0x%x, val=%x\n",
|
||||
reg, mask, *read);
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -159,18 +161,22 @@ static int pcxhr_check_reg_bit(struct pcxhr_mgr *mgr, unsigned int reg,
|
|||
#define PCXHR_IT_TEST_XILINX (0x0000003C | PCXHR_MASK_IT_HF1 | \
|
||||
PCXHR_MASK_IT_MANAGE_HF5)
|
||||
#define PCXHR_IT_DOWNLOAD_BOOT (0x0000000C | PCXHR_MASK_IT_HF1 | \
|
||||
PCXHR_MASK_IT_MANAGE_HF5 | PCXHR_MASK_IT_WAIT)
|
||||
PCXHR_MASK_IT_MANAGE_HF5 | \
|
||||
PCXHR_MASK_IT_WAIT)
|
||||
#define PCXHR_IT_RESET_BOARD_FUNC (0x0000000C | PCXHR_MASK_IT_HF0 | \
|
||||
PCXHR_MASK_IT_MANAGE_HF5 | PCXHR_MASK_IT_WAIT_EXTRA)
|
||||
PCXHR_MASK_IT_MANAGE_HF5 | \
|
||||
PCXHR_MASK_IT_WAIT_EXTRA)
|
||||
#define PCXHR_IT_DOWNLOAD_DSP (0x0000000C | \
|
||||
PCXHR_MASK_IT_MANAGE_HF5 | PCXHR_MASK_IT_WAIT)
|
||||
PCXHR_MASK_IT_MANAGE_HF5 | \
|
||||
PCXHR_MASK_IT_WAIT)
|
||||
#define PCXHR_IT_DEBUG (0x0000005A | PCXHR_MASK_IT_NO_HF0_HF1)
|
||||
#define PCXHR_IT_RESET_SEMAPHORE (0x0000005C | PCXHR_MASK_IT_NO_HF0_HF1)
|
||||
#define PCXHR_IT_MESSAGE (0x00000074 | PCXHR_MASK_IT_NO_HF0_HF1)
|
||||
#define PCXHR_IT_RESET_CHK (0x00000076 | PCXHR_MASK_IT_NO_HF0_HF1)
|
||||
#define PCXHR_IT_UPDATE_RBUFFER (0x00000078 | PCXHR_MASK_IT_NO_HF0_HF1)
|
||||
|
||||
static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr, unsigned int itdsp, int atomic)
|
||||
static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr,
|
||||
unsigned int itdsp, int atomic)
|
||||
{
|
||||
int err;
|
||||
unsigned char reg;
|
||||
|
@ -178,17 +184,21 @@ static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr, unsigned int itdsp, int atom
|
|||
if (itdsp & PCXHR_MASK_IT_MANAGE_HF5) {
|
||||
/* clear hf5 bit */
|
||||
PCXHR_OUTPL(mgr, PCXHR_PLX_MBOX0,
|
||||
PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) & ~PCXHR_MBOX0_HF5);
|
||||
PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) &
|
||||
~PCXHR_MBOX0_HF5);
|
||||
}
|
||||
if ((itdsp & PCXHR_MASK_IT_NO_HF0_HF1) == 0) {
|
||||
reg = PCXHR_ICR_HI08_RREQ | PCXHR_ICR_HI08_TREQ | PCXHR_ICR_HI08_HDRQ;
|
||||
reg = (PCXHR_ICR_HI08_RREQ |
|
||||
PCXHR_ICR_HI08_TREQ |
|
||||
PCXHR_ICR_HI08_HDRQ);
|
||||
if (itdsp & PCXHR_MASK_IT_HF0)
|
||||
reg |= PCXHR_ICR_HI08_HF0;
|
||||
if (itdsp & PCXHR_MASK_IT_HF1)
|
||||
reg |= PCXHR_ICR_HI08_HF1;
|
||||
PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg);
|
||||
}
|
||||
reg = (unsigned char)(((itdsp & PCXHR_MASK_EXTRA_INFO) >> 1) | PCXHR_CVR_HI08_HC);
|
||||
reg = (unsigned char)(((itdsp & PCXHR_MASK_EXTRA_INFO) >> 1) |
|
||||
PCXHR_CVR_HI08_HC);
|
||||
PCXHR_OUTPB(mgr, PCXHR_DSP_CVR, reg);
|
||||
if (itdsp & PCXHR_MASK_IT_WAIT) {
|
||||
if (atomic)
|
||||
|
@ -211,10 +221,14 @@ static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr, unsigned int itdsp, int atom
|
|||
}
|
||||
if (itdsp & PCXHR_MASK_IT_MANAGE_HF5) {
|
||||
/* wait for hf5 bit */
|
||||
err = pcxhr_check_reg_bit(mgr, PCXHR_PLX_MBOX0, PCXHR_MBOX0_HF5,
|
||||
PCXHR_MBOX0_HF5, PCXHR_TIMEOUT_DSP, ®);
|
||||
err = pcxhr_check_reg_bit(mgr, PCXHR_PLX_MBOX0,
|
||||
PCXHR_MBOX0_HF5,
|
||||
PCXHR_MBOX0_HF5,
|
||||
PCXHR_TIMEOUT_DSP,
|
||||
®);
|
||||
if (err) {
|
||||
snd_printk(KERN_ERR "pcxhr_send_it_dsp : TIMEOUT HF5\n");
|
||||
snd_printk(KERN_ERR
|
||||
"pcxhr_send_it_dsp : TIMEOUT HF5\n");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
@ -263,7 +277,8 @@ void pcxhr_enable_dsp(struct pcxhr_mgr *mgr)
|
|||
/*
|
||||
* load the xilinx image
|
||||
*/
|
||||
int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr, const struct firmware *xilinx, int second)
|
||||
int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr,
|
||||
const struct firmware *xilinx, int second)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int chipsc;
|
||||
|
@ -274,7 +289,9 @@ int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr, const struct firmware *xilin
|
|||
/* test first xilinx */
|
||||
chipsc = PCXHR_INPL(mgr, PCXHR_PLX_CHIPSC);
|
||||
/* REV01 cards do not support the PCXHR_CHIPSC_GPI_USERI bit anymore */
|
||||
/* this bit will always be 1; no possibility to test presence of first xilinx */
|
||||
/* this bit will always be 1;
|
||||
* no possibility to test presence of first xilinx
|
||||
*/
|
||||
if(second) {
|
||||
if ((chipsc & PCXHR_CHIPSC_GPI_USERI) == 0) {
|
||||
snd_printk(KERN_ERR "error loading first xilinx\n");
|
||||
|
@ -290,7 +307,8 @@ int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr, const struct firmware *xilin
|
|||
data = *image;
|
||||
mask = 0x80;
|
||||
while (mask) {
|
||||
chipsc &= ~(PCXHR_CHIPSC_DATA_CLK | PCXHR_CHIPSC_DATA_IN);
|
||||
chipsc &= ~(PCXHR_CHIPSC_DATA_CLK |
|
||||
PCXHR_CHIPSC_DATA_IN);
|
||||
if (data & mask)
|
||||
chipsc |= PCXHR_CHIPSC_DATA_IN;
|
||||
PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC, chipsc);
|
||||
|
@ -330,15 +348,20 @@ static int pcxhr_download_dsp(struct pcxhr_mgr *mgr, const struct firmware *dsp)
|
|||
data = dsp->data + i;
|
||||
if (i == 0) {
|
||||
/* test data header consistency */
|
||||
len = (unsigned int)((data[0]<<16) + (data[1]<<8) + data[2]);
|
||||
if (len && dsp->size != (len + 2) * 3)
|
||||
len = (unsigned int)((data[0]<<16) +
|
||||
(data[1]<<8) +
|
||||
data[2]);
|
||||
if (len && (dsp->size != (len + 2) * 3))
|
||||
return -EINVAL;
|
||||
}
|
||||
/* wait DSP ready for new transfer */
|
||||
err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY,
|
||||
PCXHR_ISR_HI08_TRDY, PCXHR_TIMEOUT_DSP, &dummy);
|
||||
err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
|
||||
PCXHR_ISR_HI08_TRDY,
|
||||
PCXHR_ISR_HI08_TRDY,
|
||||
PCXHR_TIMEOUT_DSP, &dummy);
|
||||
if (err) {
|
||||
snd_printk(KERN_ERR "dsp loading error at position %d\n", i);
|
||||
snd_printk(KERN_ERR
|
||||
"dsp loading error at position %d\n", i);
|
||||
return err;
|
||||
}
|
||||
/* send host data */
|
||||
|
@ -357,7 +380,8 @@ static int pcxhr_download_dsp(struct pcxhr_mgr *mgr, const struct firmware *dsp)
|
|||
/*
|
||||
* load the eeprom image
|
||||
*/
|
||||
int pcxhr_load_eeprom_binary(struct pcxhr_mgr *mgr, const struct firmware *eeprom)
|
||||
int pcxhr_load_eeprom_binary(struct pcxhr_mgr *mgr,
|
||||
const struct firmware *eeprom)
|
||||
{
|
||||
int err;
|
||||
unsigned char reg;
|
||||
|
@ -365,7 +389,9 @@ int pcxhr_load_eeprom_binary(struct pcxhr_mgr *mgr, const struct firmware *eepro
|
|||
/* init value of the ICR register */
|
||||
reg = PCXHR_ICR_HI08_RREQ | PCXHR_ICR_HI08_TREQ | PCXHR_ICR_HI08_HDRQ;
|
||||
if (PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) & PCXHR_MBOX0_BOOT_HERE) {
|
||||
/* no need to load the eeprom binary, but init the HI08 interface */
|
||||
/* no need to load the eeprom binary,
|
||||
* but init the HI08 interface
|
||||
*/
|
||||
PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg | PCXHR_ICR_HI08_INIT);
|
||||
msleep(PCXHR_WAIT_DEFAULT);
|
||||
PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg);
|
||||
|
@ -429,8 +455,10 @@ int pcxhr_load_dsp_binary(struct pcxhr_mgr *mgr, const struct firmware *dsp)
|
|||
if (err)
|
||||
return err;
|
||||
/* wait for chk bit */
|
||||
return pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK,
|
||||
PCXHR_ISR_HI08_CHK, PCXHR_TIMEOUT_DSP, &dummy);
|
||||
return pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
|
||||
PCXHR_ISR_HI08_CHK,
|
||||
PCXHR_ISR_HI08_CHK,
|
||||
PCXHR_TIMEOUT_DSP, &dummy);
|
||||
}
|
||||
|
||||
|
||||
|
@ -443,8 +471,8 @@ struct pcxhr_cmd_info {
|
|||
/* RMH status type */
|
||||
enum {
|
||||
RMH_SSIZE_FIXED = 0, /* status size fix (st_length = 0..x) */
|
||||
RMH_SSIZE_ARG = 1, /* status size given in the LSB byte (used with st_length = 1) */
|
||||
RMH_SSIZE_MASK = 2, /* status size given in bitmask (used with st_length = 1) */
|
||||
RMH_SSIZE_ARG = 1, /* status size given in the LSB byte */
|
||||
RMH_SSIZE_MASK = 2, /* status size given in bitmask */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -474,7 +502,7 @@ static struct pcxhr_cmd_info pcxhr_dsp_cmds[] = {
|
|||
[CMD_UPDATE_R_BUFFERS] = { 0x840000, 0, RMH_SSIZE_FIXED },
|
||||
[CMD_FORMAT_STREAM_OUT] = { 0x860000, 0, RMH_SSIZE_FIXED },
|
||||
[CMD_FORMAT_STREAM_IN] = { 0x870000, 0, RMH_SSIZE_FIXED },
|
||||
[CMD_STREAM_SAMPLE_COUNT] = { 0x902000, 2, RMH_SSIZE_FIXED }, /* stat_len = nb_streams * 2 */
|
||||
[CMD_STREAM_SAMPLE_COUNT] = { 0x902000, 2, RMH_SSIZE_FIXED },
|
||||
[CMD_AUDIO_LEVEL_ADJUST] = { 0xc22000, 0, RMH_SSIZE_FIXED },
|
||||
};
|
||||
|
||||
|
@ -524,10 +552,13 @@ static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
|
|||
|
||||
for (i = 0; i < rmh->stat_len; i++) {
|
||||
/* wait for receiver full */
|
||||
err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_RXDF,
|
||||
PCXHR_ISR_HI08_RXDF, PCXHR_TIMEOUT_DSP, ®);
|
||||
err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
|
||||
PCXHR_ISR_HI08_RXDF,
|
||||
PCXHR_ISR_HI08_RXDF,
|
||||
PCXHR_TIMEOUT_DSP, ®);
|
||||
if (err) {
|
||||
snd_printk(KERN_ERR "ERROR RMH stat: ISR:RXDF=1 (ISR = %x; i=%d )\n",
|
||||
snd_printk(KERN_ERR "ERROR RMH stat: "
|
||||
"ISR:RXDF=1 (ISR = %x; i=%d )\n",
|
||||
reg, i);
|
||||
return err;
|
||||
}
|
||||
|
@ -537,10 +568,10 @@ static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
|
|||
data |= PCXHR_INPB(mgr, PCXHR_DSP_TXL);
|
||||
|
||||
/* need to update rmh->stat_len on the fly ?? */
|
||||
if (i==0) {
|
||||
if (!i) {
|
||||
if (rmh->dsp_stat != RMH_SSIZE_FIXED) {
|
||||
if (rmh->dsp_stat == RMH_SSIZE_ARG) {
|
||||
rmh->stat_len = (u16)(data & 0x0000ff) + 1;
|
||||
rmh->stat_len = (data & 0x0000ff) + 1;
|
||||
data &= 0xffff00;
|
||||
} else {
|
||||
/* rmh->dsp_stat == RMH_SSIZE_MASK */
|
||||
|
@ -562,7 +593,8 @@ static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
|
|||
rmh->stat[i] = data;
|
||||
}
|
||||
if (rmh->stat_len > max_stat_len) {
|
||||
snd_printdd("PCXHR : rmh->stat_len=%x too big\n", rmh->stat_len);
|
||||
snd_printdd("PCXHR : rmh->stat_len=%x too big\n",
|
||||
rmh->stat_len);
|
||||
rmh->stat_len = max_stat_len;
|
||||
}
|
||||
return 0;
|
||||
|
@ -605,7 +637,8 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
|
|||
data &= 0xff7fff; /* MASK_1_WORD_COMMAND */
|
||||
#ifdef CONFIG_SND_DEBUG_VERBOSE
|
||||
if (rmh->cmd_idx < CMD_LAST_INDEX)
|
||||
snd_printdd("MSG cmd[0]=%x (%s)\n", data, cmd_names[rmh->cmd_idx]);
|
||||
snd_printdd("MSG cmd[0]=%x (%s)\n",
|
||||
data, cmd_names[rmh->cmd_idx]);
|
||||
#endif
|
||||
|
||||
err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY,
|
||||
|
@ -619,8 +652,10 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
|
|||
if (rmh->cmd_len > 1) {
|
||||
/* send length */
|
||||
data = rmh->cmd_len - 1;
|
||||
err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY,
|
||||
PCXHR_ISR_HI08_TRDY, PCXHR_TIMEOUT_DSP, ®);
|
||||
err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
|
||||
PCXHR_ISR_HI08_TRDY,
|
||||
PCXHR_ISR_HI08_TRDY,
|
||||
PCXHR_TIMEOUT_DSP, ®);
|
||||
if (err)
|
||||
return err;
|
||||
PCXHR_OUTPB(mgr, PCXHR_DSP_TXH, (data>>16)&0xFF);
|
||||
|
@ -653,8 +688,10 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
|
|||
/* test status ISR */
|
||||
if (reg & PCXHR_ISR_HI08_ERR) {
|
||||
/* ERROR, wait for receiver full */
|
||||
err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_RXDF,
|
||||
PCXHR_ISR_HI08_RXDF, PCXHR_TIMEOUT_DSP, ®);
|
||||
err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
|
||||
PCXHR_ISR_HI08_RXDF,
|
||||
PCXHR_ISR_HI08_RXDF,
|
||||
PCXHR_TIMEOUT_DSP, ®);
|
||||
if (err) {
|
||||
snd_printk(KERN_ERR "ERROR RMH: ISR:RXDF=1 (ISR = %x)\n", reg);
|
||||
return err;
|
||||
|
@ -663,7 +700,8 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
|
|||
data = PCXHR_INPB(mgr, PCXHR_DSP_TXH) << 16;
|
||||
data |= PCXHR_INPB(mgr, PCXHR_DSP_TXM) << 8;
|
||||
data |= PCXHR_INPB(mgr, PCXHR_DSP_TXL);
|
||||
snd_printk(KERN_ERR "ERROR RMH(%d): 0x%x\n", rmh->cmd_idx, data);
|
||||
snd_printk(KERN_ERR "ERROR RMH(%d): 0x%x\n",
|
||||
rmh->cmd_idx, data);
|
||||
err = -EINVAL;
|
||||
} else {
|
||||
/* read the response data */
|
||||
|
@ -732,8 +770,9 @@ int pcxhr_send_msg(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
|
|||
static inline int pcxhr_pipes_running(struct pcxhr_mgr *mgr)
|
||||
{
|
||||
int start_mask = PCXHR_INPL(mgr, PCXHR_PLX_MBOX2);
|
||||
/* least segnificant 12 bits are the pipe states for the playback audios */
|
||||
/* next 12 bits are the pipe states for the capture audios
|
||||
/* least segnificant 12 bits are the pipe states
|
||||
* for the playback audios
|
||||
* next 12 bits are the pipe states for the capture audios
|
||||
* (PCXHR_PIPE_STATE_CAPTURE_OFFSET)
|
||||
*/
|
||||
start_mask &= 0xffffff;
|
||||
|
@ -744,7 +783,8 @@ static inline int pcxhr_pipes_running(struct pcxhr_mgr *mgr)
|
|||
#define PCXHR_PIPE_STATE_CAPTURE_OFFSET 12
|
||||
#define MAX_WAIT_FOR_DSP 20
|
||||
|
||||
static int pcxhr_prepair_pipe_start(struct pcxhr_mgr *mgr, int audio_mask, int *retry)
|
||||
static int pcxhr_prepair_pipe_start(struct pcxhr_mgr *mgr,
|
||||
int audio_mask, int *retry)
|
||||
{
|
||||
struct pcxhr_rmh rmh;
|
||||
int err;
|
||||
|
@ -766,11 +806,14 @@ static int pcxhr_prepair_pipe_start(struct pcxhr_mgr *mgr, int audio_mask, int *
|
|||
err = pcxhr_send_msg(mgr, &rmh);
|
||||
if (err) {
|
||||
snd_printk(KERN_ERR
|
||||
"error pipe start (CMD_CAN_START_PIPE) err=%x!\n",
|
||||
"error pipe start "
|
||||
"(CMD_CAN_START_PIPE) err=%x!\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
/* if the pipe couldn't be prepaired for start, retry it later */
|
||||
/* if the pipe couldn't be prepaired for start,
|
||||
* retry it later
|
||||
*/
|
||||
if (rmh.stat[0] == 0)
|
||||
*retry |= (1<<audio);
|
||||
}
|
||||
|
@ -801,8 +844,8 @@ static int pcxhr_stop_pipes(struct pcxhr_mgr *mgr, int audio_mask)
|
|||
err = pcxhr_send_msg(mgr, &rmh);
|
||||
if (err) {
|
||||
snd_printk(KERN_ERR
|
||||
"error pipe stop (CMD_STOP_PIPE) err=%x!\n",
|
||||
err);
|
||||
"error pipe stop "
|
||||
"(CMD_STOP_PIPE) err=%x!\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
@ -822,15 +865,16 @@ static int pcxhr_toggle_pipes(struct pcxhr_mgr *mgr, int audio_mask)
|
|||
if (audio_mask & 1) {
|
||||
pcxhr_init_rmh(&rmh, CMD_CONF_PIPE);
|
||||
if (audio < PCXHR_PIPE_STATE_CAPTURE_OFFSET)
|
||||
pcxhr_set_pipe_cmd_params(&rmh, 0, 0, 0, 1 << audio);
|
||||
pcxhr_set_pipe_cmd_params(&rmh, 0, 0, 0,
|
||||
1 << audio);
|
||||
else
|
||||
pcxhr_set_pipe_cmd_params(&rmh, 1, 0, 0,
|
||||
1 << (audio - PCXHR_PIPE_STATE_CAPTURE_OFFSET));
|
||||
err = pcxhr_send_msg(mgr, &rmh);
|
||||
if (err) {
|
||||
snd_printk(KERN_ERR
|
||||
"error pipe start (CMD_CONF_PIPE) err=%x!\n",
|
||||
err);
|
||||
"error pipe start "
|
||||
"(CMD_CONF_PIPE) err=%x!\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
@ -841,7 +885,9 @@ static int pcxhr_toggle_pipes(struct pcxhr_mgr *mgr, int audio_mask)
|
|||
pcxhr_init_rmh(&rmh, CMD_SEND_IRQA);
|
||||
err = pcxhr_send_msg(mgr, &rmh);
|
||||
if (err) {
|
||||
snd_printk(KERN_ERR "error pipe start (CMD_SEND_IRQA) err=%x!\n", err );
|
||||
snd_printk(KERN_ERR
|
||||
"error pipe start (CMD_SEND_IRQA) err=%x!\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
|
@ -849,7 +895,8 @@ static int pcxhr_toggle_pipes(struct pcxhr_mgr *mgr, int audio_mask)
|
|||
|
||||
|
||||
|
||||
int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask, int capture_mask, int start)
|
||||
int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask,
|
||||
int capture_mask, int start)
|
||||
{
|
||||
int state, i, err;
|
||||
int audio_mask;
|
||||
|
@ -858,21 +905,23 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask, int capture_m
|
|||
struct timeval my_tv1, my_tv2;
|
||||
do_gettimeofday(&my_tv1);
|
||||
#endif
|
||||
audio_mask = (playback_mask | (capture_mask << PCXHR_PIPE_STATE_CAPTURE_OFFSET));
|
||||
audio_mask = (playback_mask |
|
||||
(capture_mask << PCXHR_PIPE_STATE_CAPTURE_OFFSET));
|
||||
/* current pipe state (playback + record) */
|
||||
state = pcxhr_pipes_running(mgr);
|
||||
snd_printdd("pcxhr_set_pipe_state %s (mask %x current %x)\n",
|
||||
start ? "START" : "STOP", audio_mask, state);
|
||||
if (start) {
|
||||
audio_mask &= ~state; /* start only pipes that are not yet started */
|
||||
/* start only pipes that are not yet started */
|
||||
audio_mask &= ~state;
|
||||
state = audio_mask;
|
||||
for (i = 0; i < MAX_WAIT_FOR_DSP; i++) {
|
||||
err = pcxhr_prepair_pipe_start(mgr, state, &state);
|
||||
if (err)
|
||||
return err;
|
||||
if (state == 0)
|
||||
break; /* success, all pipes prepaired for start */
|
||||
mdelay(1); /* otherwise wait 1 millisecond and retry */
|
||||
break; /* success, all pipes prepaired */
|
||||
mdelay(1); /* wait 1 millisecond and retry */
|
||||
}
|
||||
} else {
|
||||
audio_mask &= state; /* stop only pipes that are started */
|
||||
|
@ -891,7 +940,7 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask, int capture_m
|
|||
if ((state & audio_mask) == (start ? audio_mask : 0))
|
||||
break;
|
||||
if (++i >= MAX_WAIT_FOR_DSP * 100) {
|
||||
snd_printk(KERN_ERR "error pipe start/stop (ED_NO_RESPONSE_AT_IRQA)\n");
|
||||
snd_printk(KERN_ERR "error pipe start/stop\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
udelay(10); /* wait 10 microseconds */
|
||||
|
@ -918,7 +967,8 @@ int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask,
|
|||
|
||||
spin_lock_irqsave(&mgr->msg_lock, flags);
|
||||
if ((mgr->io_num_reg_cont & mask) == value) {
|
||||
snd_printdd("IO_NUM_REG_CONT mask %x already is set to %x\n", mask, value);
|
||||
snd_printdd("IO_NUM_REG_CONT mask %x already is set to %x\n",
|
||||
mask, value);
|
||||
if (changed)
|
||||
*changed = 0;
|
||||
spin_unlock_irqrestore(&mgr->msg_lock, flags);
|
||||
|
@ -971,7 +1021,8 @@ static int pcxhr_handle_async_err(struct pcxhr_mgr *mgr, u32 err,
|
|||
err = ((err >> 12) & 0xfff);
|
||||
if (!err)
|
||||
return 0;
|
||||
snd_printdd("CMD_ASYNC : Error %s %s Pipe %d err=%x\n", err_src_name[err_src],
|
||||
snd_printdd("CMD_ASYNC : Error %s %s Pipe %d err=%x\n",
|
||||
err_src_name[err_src],
|
||||
is_capture ? "Record" : "Play", pipe, err);
|
||||
if (err == 0xe01)
|
||||
mgr->async_err_stream_xrun++;
|
||||
|
@ -996,6 +1047,13 @@ void pcxhr_msg_tasklet(unsigned long arg)
|
|||
snd_printdd("TASKLET : PCXHR_IRQ_TIME_CODE event occured\n");
|
||||
if (mgr->src_it_dsp & PCXHR_IRQ_NOTIFY)
|
||||
snd_printdd("TASKLET : PCXHR_IRQ_NOTIFY event occured\n");
|
||||
if (mgr->src_it_dsp & (PCXHR_IRQ_FREQ_CHANGE | PCXHR_IRQ_TIME_CODE)) {
|
||||
/* clear events FREQ_CHANGE and TIME_CODE */
|
||||
pcxhr_init_rmh(prmh, CMD_TEST_IT);
|
||||
err = pcxhr_send_msg(mgr, prmh);
|
||||
snd_printdd("CMD_TEST_IT : err=%x, stat=%x\n",
|
||||
err, prmh->stat[0]);
|
||||
}
|
||||
if (mgr->src_it_dsp & PCXHR_IRQ_ASYNC) {
|
||||
snd_printdd("TASKLET : PCXHR_IRQ_ASYNC event occured\n");
|
||||
|
||||
|
@ -1005,18 +1063,22 @@ void pcxhr_msg_tasklet(unsigned long arg)
|
|||
prmh->stat_len = PCXHR_SIZE_MAX_LONG_STATUS;
|
||||
err = pcxhr_send_msg(mgr, prmh);
|
||||
if (err)
|
||||
snd_printk(KERN_ERR "ERROR pcxhr_msg_tasklet=%x;\n", err);
|
||||
snd_printk(KERN_ERR "ERROR pcxhr_msg_tasklet=%x;\n",
|
||||
err);
|
||||
i = 1;
|
||||
while (i < prmh->stat_len) {
|
||||
int nb_audio = (prmh->stat[i] >> FIELD_SIZE) & MASK_FIRST_FIELD;
|
||||
int nb_stream = (prmh->stat[i] >> (2*FIELD_SIZE)) & MASK_FIRST_FIELD;
|
||||
int nb_audio = ((prmh->stat[i] >> FIELD_SIZE) &
|
||||
MASK_FIRST_FIELD);
|
||||
int nb_stream = ((prmh->stat[i] >> (2*FIELD_SIZE)) &
|
||||
MASK_FIRST_FIELD);
|
||||
int pipe = prmh->stat[i] & MASK_FIRST_FIELD;
|
||||
int is_capture = prmh->stat[i] & 0x400000;
|
||||
u32 err2;
|
||||
|
||||
if (prmh->stat[i] & 0x800000) { /* if BIT_END */
|
||||
snd_printdd("TASKLET : End%sPipe %d\n",
|
||||
is_capture ? "Record" : "Play", pipe);
|
||||
is_capture ? "Record" : "Play",
|
||||
pipe);
|
||||
}
|
||||
i++;
|
||||
err2 = prmh->stat[i] ? prmh->stat[i] : prmh->stat[i+1];
|
||||
|
@ -1072,18 +1134,21 @@ static u_int64_t pcxhr_stream_read_position(struct pcxhr_mgr *mgr,
|
|||
hw_sample_count += (u_int64_t)rmh.stat[1];
|
||||
|
||||
snd_printdd("stream %c%d : abs samples real(%ld) timer(%ld)\n",
|
||||
stream->pipe->is_capture ? 'C':'P', stream->substream->number,
|
||||
stream->pipe->is_capture ? 'C' : 'P',
|
||||
stream->substream->number,
|
||||
(long unsigned int)hw_sample_count,
|
||||
(long unsigned int)(stream->timer_abs_periods +
|
||||
stream->timer_period_frag + PCXHR_GRANULARITY));
|
||||
|
||||
stream->timer_period_frag +
|
||||
mgr->granularity));
|
||||
return hw_sample_count;
|
||||
}
|
||||
|
||||
static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr,
|
||||
struct pcxhr_stream *stream, int samples_to_add)
|
||||
struct pcxhr_stream *stream,
|
||||
int samples_to_add)
|
||||
{
|
||||
if (stream->substream && (stream->status == PCXHR_STREAM_STATUS_RUNNING)) {
|
||||
if (stream->substream &&
|
||||
(stream->status == PCXHR_STREAM_STATUS_RUNNING)) {
|
||||
u_int64_t new_sample_count;
|
||||
int elapsed = 0;
|
||||
int hardware_read = 0;
|
||||
|
@ -1092,20 +1157,22 @@ static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr,
|
|||
if (samples_to_add < 0) {
|
||||
stream->timer_is_synced = 0;
|
||||
/* add default if no hardware_read possible */
|
||||
samples_to_add = PCXHR_GRANULARITY;
|
||||
samples_to_add = mgr->granularity;
|
||||
}
|
||||
|
||||
if (!stream->timer_is_synced) {
|
||||
if (stream->timer_abs_periods != 0 ||
|
||||
stream->timer_period_frag + PCXHR_GRANULARITY >=
|
||||
runtime->period_size) {
|
||||
new_sample_count = pcxhr_stream_read_position(mgr, stream);
|
||||
if ((stream->timer_abs_periods != 0) ||
|
||||
((stream->timer_period_frag + samples_to_add) >=
|
||||
runtime->period_size)) {
|
||||
new_sample_count =
|
||||
pcxhr_stream_read_position(mgr, stream);
|
||||
hardware_read = 1;
|
||||
if (new_sample_count >= PCXHR_GRANULARITY_MIN) {
|
||||
/* sub security offset because of jitter and
|
||||
* finer granularity of dsp time (MBOX4)
|
||||
if (new_sample_count >= mgr->granularity) {
|
||||
/* sub security offset because of
|
||||
* jitter and finer granularity of
|
||||
* dsp time (MBOX4)
|
||||
*/
|
||||
new_sample_count -= PCXHR_GRANULARITY_MIN;
|
||||
new_sample_count -= mgr->granularity;
|
||||
stream->timer_is_synced = 1;
|
||||
}
|
||||
}
|
||||
|
@ -1128,12 +1195,15 @@ static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr,
|
|||
stream->timer_buf_periods = 0;
|
||||
stream->timer_abs_periods = new_elapse_pos;
|
||||
}
|
||||
if (new_sample_count >= stream->timer_abs_periods)
|
||||
stream->timer_period_frag = (u_int32_t)(new_sample_count -
|
||||
if (new_sample_count >= stream->timer_abs_periods) {
|
||||
stream->timer_period_frag =
|
||||
(u_int32_t)(new_sample_count -
|
||||
stream->timer_abs_periods);
|
||||
else
|
||||
snd_printk(KERN_ERR "ERROR new_sample_count too small ??? %lx\n",
|
||||
} else {
|
||||
snd_printk(KERN_ERR
|
||||
"ERROR new_sample_count too small ??? %ld\n",
|
||||
(long unsigned int)new_sample_count);
|
||||
}
|
||||
|
||||
if (elapsed) {
|
||||
spin_unlock(&mgr->lock);
|
||||
|
@ -1143,7 +1213,6 @@ static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct pcxhr_mgr *mgr = dev_id;
|
||||
|
@ -1156,7 +1225,8 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
|
|||
reg = PCXHR_INPL(mgr, PCXHR_PLX_IRQCS);
|
||||
if (! (reg & PCXHR_IRQCS_ACTIVE_PCIDB)) {
|
||||
spin_unlock(&mgr->lock);
|
||||
return IRQ_NONE; /* this device did not cause the interrupt */
|
||||
/* this device did not cause the interrupt */
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/* clear interrupt */
|
||||
|
@ -1167,10 +1237,12 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
|
|||
if (reg & PCXHR_IRQ_TIMER) {
|
||||
int timer_toggle = reg & PCXHR_IRQ_TIMER;
|
||||
/* is a 24 bit counter */
|
||||
int dsp_time_new = PCXHR_INPL(mgr, PCXHR_PLX_MBOX4) & PCXHR_DSP_TIME_MASK;
|
||||
int dsp_time_new =
|
||||
PCXHR_INPL(mgr, PCXHR_PLX_MBOX4) & PCXHR_DSP_TIME_MASK;
|
||||
int dsp_time_diff = dsp_time_new - mgr->dsp_time_last;
|
||||
|
||||
if (dsp_time_diff < 0 && mgr->dsp_time_last != PCXHR_DSP_TIME_INVALID) {
|
||||
if ((dsp_time_diff < 0) &&
|
||||
(mgr->dsp_time_last != PCXHR_DSP_TIME_INVALID)) {
|
||||
snd_printdd("ERROR DSP TIME old(%d) new(%d) -> "
|
||||
"resynchronize all streams\n",
|
||||
mgr->dsp_time_last, dsp_time_new);
|
||||
|
@ -1178,40 +1250,49 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
|
|||
}
|
||||
#ifdef CONFIG_SND_DEBUG_VERBOSE
|
||||
if (dsp_time_diff == 0)
|
||||
snd_printdd("ERROR DSP TIME NO DIFF time(%d)\n", dsp_time_new);
|
||||
else if (dsp_time_diff >= (2*PCXHR_GRANULARITY))
|
||||
snd_printdd("ERROR DSP TIME NO DIFF time(%d)\n",
|
||||
dsp_time_new);
|
||||
else if (dsp_time_diff >= (2*mgr->granularity))
|
||||
snd_printdd("ERROR DSP TIME TOO BIG old(%d) add(%d)\n",
|
||||
mgr->dsp_time_last, dsp_time_new - mgr->dsp_time_last);
|
||||
mgr->dsp_time_last,
|
||||
dsp_time_new - mgr->dsp_time_last);
|
||||
else if (dsp_time_diff % mgr->granularity)
|
||||
snd_printdd("ERROR DSP TIME increased by %d\n",
|
||||
dsp_time_diff);
|
||||
#endif
|
||||
mgr->dsp_time_last = dsp_time_new;
|
||||
|
||||
if (timer_toggle == mgr->timer_toggle)
|
||||
if (timer_toggle == mgr->timer_toggle) {
|
||||
snd_printdd("ERROR TIMER TOGGLE\n");
|
||||
mgr->dsp_time_err++;
|
||||
}
|
||||
mgr->timer_toggle = timer_toggle;
|
||||
|
||||
reg &= ~PCXHR_IRQ_TIMER;
|
||||
for (i = 0; i < mgr->num_cards; i++) {
|
||||
chip = mgr->chip[i];
|
||||
for (j = 0; j < chip->nb_streams_capt; j++)
|
||||
pcxhr_update_timer_pos(mgr, &chip->capture_stream[j],
|
||||
pcxhr_update_timer_pos(mgr,
|
||||
&chip->capture_stream[j],
|
||||
dsp_time_diff);
|
||||
}
|
||||
for (i = 0; i < mgr->num_cards; i++) {
|
||||
chip = mgr->chip[i];
|
||||
for (j = 0; j < chip->nb_streams_play; j++)
|
||||
pcxhr_update_timer_pos(mgr, &chip->playback_stream[j],
|
||||
pcxhr_update_timer_pos(mgr,
|
||||
&chip->playback_stream[j],
|
||||
dsp_time_diff);
|
||||
}
|
||||
}
|
||||
/* other irq's handled in the tasklet */
|
||||
if (reg & PCXHR_IRQ_MASK) {
|
||||
|
||||
/* as we didn't request any notifications, some kind of xrun error
|
||||
* will probably occured
|
||||
if (reg & PCXHR_IRQ_ASYNC) {
|
||||
/* as we didn't request any async notifications,
|
||||
* some kind of xrun error will probably occured
|
||||
*/
|
||||
/* better resynchronize all streams next interrupt : */
|
||||
mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID;
|
||||
|
||||
}
|
||||
mgr->src_it_dsp = reg;
|
||||
tasklet_hi_schedule(&mgr->msg_taskq);
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ enum {
|
|||
CMD_RESYNC_AUDIO_INPUTS, /* cmd_len = 1 stat_len = 0 */
|
||||
CMD_GET_DSP_RESOURCES, /* cmd_len = 1 stat_len = 4 */
|
||||
CMD_SET_TIMER_INTERRUPT, /* cmd_len = 1 stat_len = 0 */
|
||||
CMD_RES_PIPE, /* cmd_len = 2 stat_len = 0 */
|
||||
CMD_RES_PIPE, /* cmd_len >=2 stat_len = 0 */
|
||||
CMD_FREE_PIPE, /* cmd_len = 1 stat_len = 0 */
|
||||
CMD_CONF_PIPE, /* cmd_len = 2 stat_len = 0 */
|
||||
CMD_STOP_PIPE, /* cmd_len = 1 stat_len = 0 */
|
||||
|
@ -96,6 +96,8 @@ void pcxhr_init_rmh(struct pcxhr_rmh *rmh, int cmd);
|
|||
void pcxhr_set_pipe_cmd_params(struct pcxhr_rmh* rmh, int capture, unsigned int param1,
|
||||
unsigned int param2, unsigned int param3);
|
||||
|
||||
#define DSP_EXT_CMD_SET(x) (x->dsp_version > 0x012800)
|
||||
|
||||
/*
|
||||
send the rmh
|
||||
*/
|
||||
|
@ -110,6 +112,7 @@ int pcxhr_send_msg(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh);
|
|||
#define IO_NUM_REG_STATUS 5
|
||||
#define IO_NUM_REG_CUER 10
|
||||
#define IO_NUM_UER_CHIP_REG 11
|
||||
#define IO_NUM_REG_CONFIG_SRC 12
|
||||
#define IO_NUM_REG_OUT_ANA_LEVEL 20
|
||||
#define IO_NUM_REG_IN_ANA_LEVEL 21
|
||||
|
||||
|
|
Loading…
Reference in a new issue