Commit 93bf5d87 authored by Markus Bollinger's avatar Markus Bollinger Committed by Takashi Iwai

ALSA: pcxhr - add support for pcxhr stereo sound cards

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