summary refs log tree commit diff
path: root/sound/pci/pcxhr
diff options
context:
space:
mode:
authorMarkus Bollinger <bollinger@digigram.com>2008-11-25 12:21:05 +0100
committerTakashi Iwai <tiwai@suse.de>2008-11-25 12:26:46 +0100
commit93bf5d8753b2e3cc9e8982d551d119a54a31a7ec (patch)
tree1f93f7d3737d7bd81dadeebf7be5ec6641d9b2cb /sound/pci/pcxhr
parent13d428afc007fcfcd6deeb215618f54cf9c0cae6 (diff)
downloadlinux-93bf5d8753b2e3cc9e8982d551d119a54a31a7ec.tar.gz
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>
Diffstat (limited to 'sound/pci/pcxhr')
-rw-r--r--sound/pci/pcxhr/pcxhr_core.c291
-rw-r--r--sound/pci/pcxhr/pcxhr_core.h5
2 files changed, 190 insertions, 106 deletions
diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c
index 7143259cfe34..d5f18226261d 100644
--- a/sound/pci/pcxhr/pcxhr_core.c
+++ b/sound/pci/pcxhr/pcxhr_core.c
@@ -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, &reg);
+		err = pcxhr_check_reg_bit(mgr, PCXHR_PLX_MBOX0,
+					  PCXHR_MBOX0_HF5,
+					  PCXHR_MBOX0_HF5,
+					  PCXHR_TIMEOUT_DSP,
+					  &reg);
 		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, &reg);
+		err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
+					  PCXHR_ISR_HI08_RXDF,
+					  PCXHR_ISR_HI08_RXDF,
+					  PCXHR_TIMEOUT_DSP, &reg);
 		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, &reg);
+		err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
+					  PCXHR_ISR_HI08_TRDY,
+					  PCXHR_ISR_HI08_TRDY,
+					  PCXHR_TIMEOUT_DSP, &reg);
 		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, &reg);
+		err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
+					  PCXHR_ISR_HI08_RXDF,
+					  PCXHR_ISR_HI08_RXDF,
+					  PCXHR_TIMEOUT_DSP, &reg);
 		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;
@@ -760,17 +800,20 @@ static int pcxhr_prepair_pipe_start(struct pcxhr_mgr *mgr, int audio_mask, int *
 			} else {
 				/* can start capture pipe */
 				pcxhr_set_pipe_cmd_params(&rmh, 1, audio -
-							  PCXHR_PIPE_STATE_CAPTURE_OFFSET,
-							  0, 0);
+						PCXHR_PIPE_STATE_CAPTURE_OFFSET,
+						0, 0);
 			}
 			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);
 		}
@@ -795,14 +838,14 @@ static int pcxhr_stop_pipes(struct pcxhr_mgr *mgr, int audio_mask)
 			} else {
 				/* stop capture pipe */
 				pcxhr_set_pipe_cmd_params(&rmh, 1, audio -
-							  PCXHR_PIPE_STATE_CAPTURE_OFFSET,
-							  0, 0);
+						PCXHR_PIPE_STATE_CAPTURE_OFFSET,
+						0, 0);
 			}
 			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];
@@ -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_set_pipe_cmd_params(&rmh, stream->pipe->is_capture,
 				  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);
 	if (err)
@@ -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 -
-								stream->timer_abs_periods);
-		else
-			snd_printk(KERN_ERR "ERROR new_sample_count too small ??? %lx\n",
+		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 ??? %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],
-						       dsp_time_diff);
+				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],
-						       dsp_time_diff);
+				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
-		 */
-		/* better resynchronize all streams next interrupt : */
-		mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID;
-		
+		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);
 	}
diff --git a/sound/pci/pcxhr/pcxhr_core.h b/sound/pci/pcxhr/pcxhr_core.h
index d9a4ab609875..bbbd66d13a64 100644
--- a/sound/pci/pcxhr/pcxhr_core.h
+++ b/sound/pci/pcxhr/pcxhr_core.h
@@ -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