Linux Audio

Check our new training course

Loading...
v5.9
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Driver for Digigram pcxhr compatible soundcards
   4 *
   5 * low level interface with interrupt and message handling implementation
   6 *
   7 * Copyright (c) 2004 by Digigram <alsa@digigram.com>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
   8 */
   9
  10#include <linux/delay.h>
  11#include <linux/firmware.h>
  12#include <linux/interrupt.h>
  13#include <linux/pci.h>
  14#include <linux/io.h>
  15#include <sound/core.h>
  16#include "pcxhr.h"
  17#include "pcxhr_mixer.h"
  18#include "pcxhr_hwdep.h"
  19#include "pcxhr_core.h"
  20
  21
  22/* registers used on the PLX (port 1) */
  23#define PCXHR_PLX_OFFSET_MIN	0x40
  24#define PCXHR_PLX_MBOX0		0x40
  25#define PCXHR_PLX_MBOX1		0x44
  26#define PCXHR_PLX_MBOX2		0x48
  27#define PCXHR_PLX_MBOX3		0x4C
  28#define PCXHR_PLX_MBOX4		0x50
  29#define PCXHR_PLX_MBOX5		0x54
  30#define PCXHR_PLX_MBOX6		0x58
  31#define PCXHR_PLX_MBOX7		0x5C
  32#define PCXHR_PLX_L2PCIDB	0x64
  33#define PCXHR_PLX_IRQCS		0x68
  34#define PCXHR_PLX_CHIPSC	0x6C
  35
  36/* registers used on the DSP (port 2) */
  37#define PCXHR_DSP_ICR		0x00
  38#define PCXHR_DSP_CVR		0x04
  39#define PCXHR_DSP_ISR		0x08
  40#define PCXHR_DSP_IVR		0x0C
  41#define PCXHR_DSP_RXH		0x14
  42#define PCXHR_DSP_TXH		0x14
  43#define PCXHR_DSP_RXM		0x18
  44#define PCXHR_DSP_TXM		0x18
  45#define PCXHR_DSP_RXL		0x1C
  46#define PCXHR_DSP_TXL		0x1C
  47#define PCXHR_DSP_RESET		0x20
  48#define PCXHR_DSP_OFFSET_MAX	0x20
  49
  50/* access to the card */
  51#define PCXHR_PLX 1
  52#define PCXHR_DSP 2
  53
  54#if (PCXHR_DSP_OFFSET_MAX > PCXHR_PLX_OFFSET_MIN)
  55#undef  PCXHR_REG_TO_PORT(x)
  56#else
  57#define PCXHR_REG_TO_PORT(x)	((x)>PCXHR_DSP_OFFSET_MAX ? PCXHR_PLX : PCXHR_DSP)
  58#endif
  59#define PCXHR_INPB(mgr,x)	inb((mgr)->port[PCXHR_REG_TO_PORT(x)] + (x))
  60#define PCXHR_INPL(mgr,x)	inl((mgr)->port[PCXHR_REG_TO_PORT(x)] + (x))
  61#define PCXHR_OUTPB(mgr,x,data)	outb((data), (mgr)->port[PCXHR_REG_TO_PORT(x)] + (x))
  62#define PCXHR_OUTPL(mgr,x,data)	outl((data), (mgr)->port[PCXHR_REG_TO_PORT(x)] + (x))
  63/* attention : access the PCXHR_DSP_* registers with inb and outb only ! */
  64
  65/* params used with PCXHR_PLX_MBOX0 */
  66#define PCXHR_MBOX0_HF5			(1 << 0)
  67#define PCXHR_MBOX0_HF4			(1 << 1)
  68#define PCXHR_MBOX0_BOOT_HERE		(1 << 23)
  69/* params used with PCXHR_PLX_IRQCS */
  70#define PCXHR_IRQCS_ENABLE_PCIIRQ	(1 << 8)
  71#define PCXHR_IRQCS_ENABLE_PCIDB	(1 << 9)
  72#define PCXHR_IRQCS_ACTIVE_PCIDB	(1 << 13)
  73/* params used with PCXHR_PLX_CHIPSC */
  74#define PCXHR_CHIPSC_INIT_VALUE		0x100D767E
  75#define PCXHR_CHIPSC_RESET_XILINX	(1 << 16)
  76#define PCXHR_CHIPSC_GPI_USERI		(1 << 17)
  77#define PCXHR_CHIPSC_DATA_CLK		(1 << 24)
  78#define PCXHR_CHIPSC_DATA_IN		(1 << 26)
  79
  80/* params used with PCXHR_DSP_ICR */
  81#define PCXHR_ICR_HI08_RREQ		0x01
  82#define PCXHR_ICR_HI08_TREQ		0x02
  83#define PCXHR_ICR_HI08_HDRQ		0x04
  84#define PCXHR_ICR_HI08_HF0		0x08
  85#define PCXHR_ICR_HI08_HF1		0x10
  86#define PCXHR_ICR_HI08_HLEND		0x20
  87#define PCXHR_ICR_HI08_INIT		0x80
  88/* params used with PCXHR_DSP_CVR */
  89#define PCXHR_CVR_HI08_HC		0x80
  90/* params used with PCXHR_DSP_ISR */
  91#define PCXHR_ISR_HI08_RXDF		0x01
  92#define PCXHR_ISR_HI08_TXDE		0x02
  93#define PCXHR_ISR_HI08_TRDY		0x04
  94#define PCXHR_ISR_HI08_ERR		0x08
  95#define PCXHR_ISR_HI08_CHK		0x10
  96#define PCXHR_ISR_HI08_HREQ		0x80
  97
  98
  99/* constants used for delay in msec */
 100#define PCXHR_WAIT_DEFAULT		2
 101#define PCXHR_WAIT_IT			25
 102#define PCXHR_WAIT_IT_EXTRA		65
 103
 104/*
 105 * pcxhr_check_reg_bit - wait for the specified bit is set/reset on a register
 106 * @reg: register to check
 107 * @mask: bit mask
 108 * @bit: resultant bit to be checked
 109 * @time: time-out of loop in msec
 110 *
 111 * returns zero if a bit matches, or a negative error code.
 112 */
 113static int pcxhr_check_reg_bit(struct pcxhr_mgr *mgr, unsigned int reg,
 114			       unsigned char mask, unsigned char bit, int time,
 115			       unsigned char* read)
 116{
 117	int i = 0;
 118	unsigned long end_time = jiffies + (time * HZ + 999) / 1000;
 119	do {
 120		*read = PCXHR_INPB(mgr, reg);
 121		if ((*read & mask) == bit) {
 122			if (i > 100)
 123				dev_dbg(&mgr->pci->dev,
 124					"ATTENTION! check_reg(%x) loopcount=%d\n",
 125					    reg, i);
 126			return 0;
 127		}
 128		i++;
 129	} while (time_after_eq(end_time, jiffies));
 130	dev_err(&mgr->pci->dev,
 131		   "pcxhr_check_reg_bit: timeout, reg=%x, mask=0x%x, val=%x\n",
 132		   reg, mask, *read);
 133	return -EIO;
 134}
 135
 136/* constants used with pcxhr_check_reg_bit() */
 137#define PCXHR_TIMEOUT_DSP		200
 138
 139
 140#define PCXHR_MASK_EXTRA_INFO		0x0000FE
 141#define PCXHR_MASK_IT_HF0		0x000100
 142#define PCXHR_MASK_IT_HF1		0x000200
 143#define PCXHR_MASK_IT_NO_HF0_HF1	0x000400
 144#define PCXHR_MASK_IT_MANAGE_HF5	0x000800
 145#define PCXHR_MASK_IT_WAIT		0x010000
 146#define PCXHR_MASK_IT_WAIT_EXTRA	0x020000
 147
 148#define PCXHR_IT_SEND_BYTE_XILINX	(0x0000003C | PCXHR_MASK_IT_HF0)
 149#define PCXHR_IT_TEST_XILINX		(0x0000003C | PCXHR_MASK_IT_HF1 | \
 150					 PCXHR_MASK_IT_MANAGE_HF5)
 151#define PCXHR_IT_DOWNLOAD_BOOT		(0x0000000C | PCXHR_MASK_IT_HF1 | \
 152					 PCXHR_MASK_IT_MANAGE_HF5 | \
 153					 PCXHR_MASK_IT_WAIT)
 154#define PCXHR_IT_RESET_BOARD_FUNC	(0x0000000C | PCXHR_MASK_IT_HF0 | \
 155					 PCXHR_MASK_IT_MANAGE_HF5 | \
 156					 PCXHR_MASK_IT_WAIT_EXTRA)
 157#define PCXHR_IT_DOWNLOAD_DSP		(0x0000000C | \
 158					 PCXHR_MASK_IT_MANAGE_HF5 | \
 159					 PCXHR_MASK_IT_WAIT)
 160#define PCXHR_IT_DEBUG			(0x0000005A | PCXHR_MASK_IT_NO_HF0_HF1)
 161#define PCXHR_IT_RESET_SEMAPHORE	(0x0000005C | PCXHR_MASK_IT_NO_HF0_HF1)
 162#define PCXHR_IT_MESSAGE		(0x00000074 | PCXHR_MASK_IT_NO_HF0_HF1)
 163#define PCXHR_IT_RESET_CHK		(0x00000076 | PCXHR_MASK_IT_NO_HF0_HF1)
 164#define PCXHR_IT_UPDATE_RBUFFER		(0x00000078 | PCXHR_MASK_IT_NO_HF0_HF1)
 165
 166static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr,
 167			     unsigned int itdsp, int atomic)
 168{
 169	int err;
 170	unsigned char reg;
 171
 172	if (itdsp & PCXHR_MASK_IT_MANAGE_HF5) {
 173		/* clear hf5 bit */
 174		PCXHR_OUTPL(mgr, PCXHR_PLX_MBOX0,
 175			    PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) &
 176			    ~PCXHR_MBOX0_HF5);
 177	}
 178	if ((itdsp & PCXHR_MASK_IT_NO_HF0_HF1) == 0) {
 179		reg = (PCXHR_ICR_HI08_RREQ |
 180		       PCXHR_ICR_HI08_TREQ |
 181		       PCXHR_ICR_HI08_HDRQ);
 182		if (itdsp & PCXHR_MASK_IT_HF0)
 183			reg |= PCXHR_ICR_HI08_HF0;
 184		if (itdsp & PCXHR_MASK_IT_HF1)
 185			reg |= PCXHR_ICR_HI08_HF1;
 186		PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg);
 187	}
 188	reg = (unsigned char)(((itdsp & PCXHR_MASK_EXTRA_INFO) >> 1) |
 189			      PCXHR_CVR_HI08_HC);
 190	PCXHR_OUTPB(mgr, PCXHR_DSP_CVR, reg);
 191	if (itdsp & PCXHR_MASK_IT_WAIT) {
 192		if (atomic)
 193			mdelay(PCXHR_WAIT_IT);
 194		else
 195			msleep(PCXHR_WAIT_IT);
 196	}
 197	if (itdsp & PCXHR_MASK_IT_WAIT_EXTRA) {
 198		if (atomic)
 199			mdelay(PCXHR_WAIT_IT_EXTRA);
 200		else
 201			msleep(PCXHR_WAIT_IT);
 202	}
 203	/* wait for CVR_HI08_HC == 0 */
 204	err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_CVR,  PCXHR_CVR_HI08_HC, 0,
 205				  PCXHR_TIMEOUT_DSP, &reg);
 206	if (err) {
 207		dev_err(&mgr->pci->dev, "pcxhr_send_it_dsp : TIMEOUT CVR\n");
 208		return err;
 209	}
 210	if (itdsp & PCXHR_MASK_IT_MANAGE_HF5) {
 211		/* wait for hf5 bit */
 212		err = pcxhr_check_reg_bit(mgr, PCXHR_PLX_MBOX0,
 213					  PCXHR_MBOX0_HF5,
 214					  PCXHR_MBOX0_HF5,
 215					  PCXHR_TIMEOUT_DSP,
 216					  &reg);
 217		if (err) {
 218			dev_err(&mgr->pci->dev,
 219				   "pcxhr_send_it_dsp : TIMEOUT HF5\n");
 220			return err;
 221		}
 222	}
 223	return 0; /* retry not handled here */
 224}
 225
 226void pcxhr_reset_xilinx_com(struct pcxhr_mgr *mgr)
 227{
 228	/* reset second xilinx */
 229	PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC,
 230		    PCXHR_CHIPSC_INIT_VALUE & ~PCXHR_CHIPSC_RESET_XILINX);
 231}
 232
 233static void pcxhr_enable_irq(struct pcxhr_mgr *mgr, int enable)
 234{
 235	unsigned int reg = PCXHR_INPL(mgr, PCXHR_PLX_IRQCS);
 236	/* enable/disable interrupts */
 237	if (enable)
 238		reg |=  (PCXHR_IRQCS_ENABLE_PCIIRQ | PCXHR_IRQCS_ENABLE_PCIDB);
 239	else
 240		reg &= ~(PCXHR_IRQCS_ENABLE_PCIIRQ | PCXHR_IRQCS_ENABLE_PCIDB);
 241	PCXHR_OUTPL(mgr, PCXHR_PLX_IRQCS, reg);
 242}
 243
 244void pcxhr_reset_dsp(struct pcxhr_mgr *mgr)
 245{
 246	/* disable interrupts */
 247	pcxhr_enable_irq(mgr, 0);
 248
 249	/* let's reset the DSP */
 250	PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, 0);
 251	msleep( PCXHR_WAIT_DEFAULT ); /* wait 2 msec */
 252	PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, 3);
 253	msleep( PCXHR_WAIT_DEFAULT ); /* wait 2 msec */
 254
 255	/* reset mailbox */
 256	PCXHR_OUTPL(mgr, PCXHR_PLX_MBOX0, 0);
 257}
 258
 259void pcxhr_enable_dsp(struct pcxhr_mgr *mgr)
 260{
 261	/* enable interrupts */
 262	pcxhr_enable_irq(mgr, 1);
 263}
 264
 265/*
 266 * load the xilinx image
 267 */
 268int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr,
 269			     const struct firmware *xilinx, int second)
 270{
 271	unsigned int i;
 272	unsigned int chipsc;
 273	unsigned char data;
 274	unsigned char mask;
 275	const unsigned char *image;
 276
 277	/* test first xilinx */
 278	chipsc = PCXHR_INPL(mgr, PCXHR_PLX_CHIPSC);
 279	/* REV01 cards do not support the PCXHR_CHIPSC_GPI_USERI bit anymore */
 280	/* this bit will always be 1;
 281	 * no possibility to test presence of first xilinx
 282	 */
 283	if(second) {
 284		if ((chipsc & PCXHR_CHIPSC_GPI_USERI) == 0) {
 285			dev_err(&mgr->pci->dev, "error loading first xilinx\n");
 286			return -EINVAL;
 287		}
 288		/* activate second xilinx */
 289		chipsc |= PCXHR_CHIPSC_RESET_XILINX;
 290		PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC, chipsc);
 291		msleep( PCXHR_WAIT_DEFAULT ); /* wait 2 msec */
 292	}
 293	image = xilinx->data;
 294	for (i = 0; i < xilinx->size; i++, image++) {
 295		data = *image;
 296		mask = 0x80;
 297		while (mask) {
 298			chipsc &= ~(PCXHR_CHIPSC_DATA_CLK |
 299				    PCXHR_CHIPSC_DATA_IN);
 300			if (data & mask)
 301				chipsc |= PCXHR_CHIPSC_DATA_IN;
 302			PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC, chipsc);
 303			chipsc |= PCXHR_CHIPSC_DATA_CLK;
 304			PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC, chipsc);
 305			mask >>= 1;
 306		}
 307		/* don't take too much time in this loop... */
 308		cond_resched();
 309	}
 310	chipsc &= ~(PCXHR_CHIPSC_DATA_CLK | PCXHR_CHIPSC_DATA_IN);
 311	PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC, chipsc);
 312	/* wait 2 msec (time to boot the xilinx before any access) */
 313	msleep( PCXHR_WAIT_DEFAULT );
 314	return 0;
 315}
 316
 317/*
 318 * send an executable file to the DSP
 319 */
 320static int pcxhr_download_dsp(struct pcxhr_mgr *mgr, const struct firmware *dsp)
 321{
 322	int err;
 323	unsigned int i;
 324	unsigned int len;
 325	const unsigned char *data;
 326	unsigned char dummy;
 327	/* check the length of boot image */
 328	if (dsp->size <= 0)
 329		return -EINVAL;
 330	if (dsp->size % 3)
 331		return -EINVAL;
 332	if (snd_BUG_ON(!dsp->data))
 333		return -EINVAL;
 334	/* transfert data buffer from PC to DSP */
 335	for (i = 0; i < dsp->size; i += 3) {
 336		data = dsp->data + i;
 337		if (i == 0) {
 338			/* test data header consistency */
 339			len = (unsigned int)((data[0]<<16) +
 340					     (data[1]<<8) +
 341					     data[2]);
 342			if (len && (dsp->size != (len + 2) * 3))
 343				return -EINVAL;
 344		}
 345		/* wait DSP ready for new transfer */
 346		err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
 347					  PCXHR_ISR_HI08_TRDY,
 348					  PCXHR_ISR_HI08_TRDY,
 349					  PCXHR_TIMEOUT_DSP, &dummy);
 350		if (err) {
 351			dev_err(&mgr->pci->dev,
 352				   "dsp loading error at position %d\n", i);
 353			return err;
 354		}
 355		/* send host data */
 356		PCXHR_OUTPB(mgr, PCXHR_DSP_TXH, data[0]);
 357		PCXHR_OUTPB(mgr, PCXHR_DSP_TXM, data[1]);
 358		PCXHR_OUTPB(mgr, PCXHR_DSP_TXL, data[2]);
 359
 360		/* don't take too much time in this loop... */
 361		cond_resched();
 362	}
 363	/* give some time to boot the DSP */
 364	msleep(PCXHR_WAIT_DEFAULT);
 365	return 0;
 366}
 367
 368/*
 369 * load the eeprom image
 370 */
 371int pcxhr_load_eeprom_binary(struct pcxhr_mgr *mgr,
 372			     const struct firmware *eeprom)
 373{
 374	int err;
 375	unsigned char reg;
 376
 377	/* init value of the ICR register */
 378	reg = PCXHR_ICR_HI08_RREQ | PCXHR_ICR_HI08_TREQ | PCXHR_ICR_HI08_HDRQ;
 379	if (PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) & PCXHR_MBOX0_BOOT_HERE) {
 380		/* no need to load the eeprom binary,
 381		 * but init the HI08 interface
 382		 */
 383		PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg | PCXHR_ICR_HI08_INIT);
 384		msleep(PCXHR_WAIT_DEFAULT);
 385		PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg);
 386		msleep(PCXHR_WAIT_DEFAULT);
 387		dev_dbg(&mgr->pci->dev, "no need to load eeprom boot\n");
 388		return 0;
 389	}
 390	PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg);
 391
 392	err = pcxhr_download_dsp(mgr, eeprom);
 393	if (err)
 394		return err;
 395	/* wait for chk bit */
 396	return pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK,
 397				   PCXHR_ISR_HI08_CHK, PCXHR_TIMEOUT_DSP, &reg);
 398}
 399
 400/*
 401 * load the boot image
 402 */
 403int pcxhr_load_boot_binary(struct pcxhr_mgr *mgr, const struct firmware *boot)
 404{
 405	int err;
 406	unsigned int physaddr = mgr->hostport.addr;
 407	unsigned char dummy;
 408
 409	/* send the hostport address to the DSP (only the upper 24 bit !) */
 410	if (snd_BUG_ON(physaddr & 0xff))
 411		return -EINVAL;
 412	PCXHR_OUTPL(mgr, PCXHR_PLX_MBOX1, (physaddr >> 8));
 413
 414	err = pcxhr_send_it_dsp(mgr, PCXHR_IT_DOWNLOAD_BOOT, 0);
 415	if (err)
 416		return err;
 417	/* clear hf5 bit */
 418	PCXHR_OUTPL(mgr, PCXHR_PLX_MBOX0,
 419		    PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) & ~PCXHR_MBOX0_HF5);
 420
 421	err = pcxhr_download_dsp(mgr, boot);
 422	if (err)
 423		return err;
 424	/* wait for hf5 bit */
 425	return pcxhr_check_reg_bit(mgr, PCXHR_PLX_MBOX0, PCXHR_MBOX0_HF5,
 426				   PCXHR_MBOX0_HF5, PCXHR_TIMEOUT_DSP, &dummy);
 427}
 428
 429/*
 430 * load the final dsp image
 431 */
 432int pcxhr_load_dsp_binary(struct pcxhr_mgr *mgr, const struct firmware *dsp)
 433{
 434	int err;
 435	unsigned char dummy;
 436	err = pcxhr_send_it_dsp(mgr, PCXHR_IT_RESET_BOARD_FUNC, 0);
 437	if (err)
 438		return err;
 439	err = pcxhr_send_it_dsp(mgr, PCXHR_IT_DOWNLOAD_DSP, 0);
 440	if (err)
 441		return err;
 442	err = pcxhr_download_dsp(mgr, dsp);
 443	if (err)
 444		return err;
 445	/* wait for chk bit */
 446	return pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
 447				   PCXHR_ISR_HI08_CHK,
 448				   PCXHR_ISR_HI08_CHK,
 449				   PCXHR_TIMEOUT_DSP, &dummy);
 450}
 451
 452
 453struct pcxhr_cmd_info {
 454	u32 opcode;		/* command word */
 455	u16 st_length;		/* status length */
 456	u16 st_type;		/* status type (RMH_SSIZE_XXX) */
 457};
 458
 459/* RMH status type */
 460enum {
 461	RMH_SSIZE_FIXED = 0,	/* status size fix (st_length = 0..x) */
 462	RMH_SSIZE_ARG = 1,	/* status size given in the LSB byte */
 463	RMH_SSIZE_MASK = 2,	/* status size given in bitmask */
 464};
 465
 466/*
 467 * Array of DSP commands
 468 */
 469static const struct pcxhr_cmd_info pcxhr_dsp_cmds[] = {
 470[CMD_VERSION] =				{ 0x010000, 1, RMH_SSIZE_FIXED },
 471[CMD_SUPPORTED] =			{ 0x020000, 4, RMH_SSIZE_FIXED },
 472[CMD_TEST_IT] =				{ 0x040000, 1, RMH_SSIZE_FIXED },
 473[CMD_SEND_IRQA] =			{ 0x070001, 0, RMH_SSIZE_FIXED },
 474[CMD_ACCESS_IO_WRITE] =			{ 0x090000, 1, RMH_SSIZE_ARG },
 475[CMD_ACCESS_IO_READ] =			{ 0x094000, 1, RMH_SSIZE_ARG },
 476[CMD_ASYNC] =				{ 0x0a0000, 1, RMH_SSIZE_ARG },
 477[CMD_MODIFY_CLOCK] =			{ 0x0d0000, 0, RMH_SSIZE_FIXED },
 478[CMD_RESYNC_AUDIO_INPUTS] =		{ 0x0e0000, 0, RMH_SSIZE_FIXED },
 479[CMD_GET_DSP_RESOURCES] =		{ 0x100000, 4, RMH_SSIZE_FIXED },
 480[CMD_SET_TIMER_INTERRUPT] =		{ 0x110000, 0, RMH_SSIZE_FIXED },
 481[CMD_RES_PIPE] =			{ 0x400000, 0, RMH_SSIZE_FIXED },
 482[CMD_FREE_PIPE] =			{ 0x410000, 0, RMH_SSIZE_FIXED },
 483[CMD_CONF_PIPE] =			{ 0x422101, 0, RMH_SSIZE_FIXED },
 484[CMD_STOP_PIPE] =			{ 0x470004, 0, RMH_SSIZE_FIXED },
 485[CMD_PIPE_SAMPLE_COUNT] =		{ 0x49a000, 2, RMH_SSIZE_FIXED },
 486[CMD_CAN_START_PIPE] =			{ 0x4b0000, 1, RMH_SSIZE_FIXED },
 487[CMD_START_STREAM] =			{ 0x802000, 0, RMH_SSIZE_FIXED },
 488[CMD_STREAM_OUT_LEVEL_ADJUST] =		{ 0x822000, 0, RMH_SSIZE_FIXED },
 489[CMD_STOP_STREAM] =			{ 0x832000, 0, RMH_SSIZE_FIXED },
 490[CMD_UPDATE_R_BUFFERS] =		{ 0x840000, 0, RMH_SSIZE_FIXED },
 491[CMD_FORMAT_STREAM_OUT] =		{ 0x860000, 0, RMH_SSIZE_FIXED },
 492[CMD_FORMAT_STREAM_IN] =		{ 0x870000, 0, RMH_SSIZE_FIXED },
 493[CMD_STREAM_SAMPLE_COUNT] =		{ 0x902000, 2, RMH_SSIZE_FIXED },
 494[CMD_AUDIO_LEVEL_ADJUST] =		{ 0xc22000, 0, RMH_SSIZE_FIXED },
 495[CMD_GET_TIME_CODE] =			{ 0x060000, 5, RMH_SSIZE_FIXED },
 496[CMD_MANAGE_SIGNAL] =			{ 0x0f0000, 0, RMH_SSIZE_FIXED },
 497};
 498
 499#ifdef CONFIG_SND_DEBUG_VERBOSE
 500static const char * const cmd_names[] = {
 501[CMD_VERSION] =				"CMD_VERSION",
 502[CMD_SUPPORTED] =			"CMD_SUPPORTED",
 503[CMD_TEST_IT] =				"CMD_TEST_IT",
 504[CMD_SEND_IRQA] =			"CMD_SEND_IRQA",
 505[CMD_ACCESS_IO_WRITE] =			"CMD_ACCESS_IO_WRITE",
 506[CMD_ACCESS_IO_READ] =			"CMD_ACCESS_IO_READ",
 507[CMD_ASYNC] =				"CMD_ASYNC",
 508[CMD_MODIFY_CLOCK] =			"CMD_MODIFY_CLOCK",
 509[CMD_RESYNC_AUDIO_INPUTS] =		"CMD_RESYNC_AUDIO_INPUTS",
 510[CMD_GET_DSP_RESOURCES] =		"CMD_GET_DSP_RESOURCES",
 511[CMD_SET_TIMER_INTERRUPT] =		"CMD_SET_TIMER_INTERRUPT",
 512[CMD_RES_PIPE] =			"CMD_RES_PIPE",
 513[CMD_FREE_PIPE] =			"CMD_FREE_PIPE",
 514[CMD_CONF_PIPE] =			"CMD_CONF_PIPE",
 515[CMD_STOP_PIPE] =			"CMD_STOP_PIPE",
 516[CMD_PIPE_SAMPLE_COUNT] =		"CMD_PIPE_SAMPLE_COUNT",
 517[CMD_CAN_START_PIPE] =			"CMD_CAN_START_PIPE",
 518[CMD_START_STREAM] =			"CMD_START_STREAM",
 519[CMD_STREAM_OUT_LEVEL_ADJUST] =		"CMD_STREAM_OUT_LEVEL_ADJUST",
 520[CMD_STOP_STREAM] =			"CMD_STOP_STREAM",
 521[CMD_UPDATE_R_BUFFERS] =		"CMD_UPDATE_R_BUFFERS",
 522[CMD_FORMAT_STREAM_OUT] =		"CMD_FORMAT_STREAM_OUT",
 523[CMD_FORMAT_STREAM_IN] =		"CMD_FORMAT_STREAM_IN",
 524[CMD_STREAM_SAMPLE_COUNT] =		"CMD_STREAM_SAMPLE_COUNT",
 525[CMD_AUDIO_LEVEL_ADJUST] =		"CMD_AUDIO_LEVEL_ADJUST",
 526[CMD_GET_TIME_CODE] =			"CMD_GET_TIME_CODE",
 527[CMD_MANAGE_SIGNAL] =			"CMD_MANAGE_SIGNAL",
 528};
 529#endif
 530
 531
 532static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
 533{
 534	int err;
 535	int i;
 536	u32 data;
 537	u32 size_mask;
 538	unsigned char reg;
 539	int max_stat_len;
 540
 541	if (rmh->stat_len < PCXHR_SIZE_MAX_STATUS)
 542		max_stat_len = PCXHR_SIZE_MAX_STATUS;
 543	else	max_stat_len = rmh->stat_len;
 544
 545	for (i = 0; i < rmh->stat_len; i++) {
 546		/* wait for receiver full */
 547		err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
 548					  PCXHR_ISR_HI08_RXDF,
 549					  PCXHR_ISR_HI08_RXDF,
 550					  PCXHR_TIMEOUT_DSP, &reg);
 551		if (err) {
 552			dev_err(&mgr->pci->dev,
 553				"ERROR RMH stat: ISR:RXDF=1 (ISR = %x; i=%d )\n",
 554				reg, i);
 555			return err;
 556		}
 557		/* read data */
 558		data  = PCXHR_INPB(mgr, PCXHR_DSP_TXH) << 16;
 559		data |= PCXHR_INPB(mgr, PCXHR_DSP_TXM) << 8;
 560		data |= PCXHR_INPB(mgr, PCXHR_DSP_TXL);
 561
 562		/* need to update rmh->stat_len on the fly ?? */
 563		if (!i) {
 564			if (rmh->dsp_stat != RMH_SSIZE_FIXED) {
 565				if (rmh->dsp_stat == RMH_SSIZE_ARG) {
 566					rmh->stat_len = (data & 0x0000ff) + 1;
 567					data &= 0xffff00;
 568				} else {
 569					/* rmh->dsp_stat == RMH_SSIZE_MASK */
 570					rmh->stat_len = 1;
 571					size_mask = data;
 572					while (size_mask) {
 573						if (size_mask & 1)
 574							rmh->stat_len++;
 575						size_mask >>= 1;
 576					}
 577				}
 578			}
 579		}
 580#ifdef CONFIG_SND_DEBUG_VERBOSE
 581		if (rmh->cmd_idx < CMD_LAST_INDEX)
 582			dev_dbg(&mgr->pci->dev, "    stat[%d]=%x\n", i, data);
 583#endif
 584		if (i < max_stat_len)
 585			rmh->stat[i] = data;
 586	}
 587	if (rmh->stat_len > max_stat_len) {
 588		dev_dbg(&mgr->pci->dev, "PCXHR : rmh->stat_len=%x too big\n",
 589			    rmh->stat_len);
 590		rmh->stat_len = max_stat_len;
 591	}
 592	return 0;
 593}
 594
 595static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
 596{
 597	int err;
 598	int i;
 599	u32 data;
 600	unsigned char reg;
 601
 602	if (snd_BUG_ON(rmh->cmd_len >= PCXHR_SIZE_MAX_CMD))
 603		return -EINVAL;
 604	err = pcxhr_send_it_dsp(mgr, PCXHR_IT_MESSAGE, 1);
 605	if (err) {
 606		dev_err(&mgr->pci->dev,
 607			"pcxhr_send_message : ED_DSP_CRASHED\n");
 608		return err;
 609	}
 610	/* wait for chk bit */
 611	err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK,
 612				  PCXHR_ISR_HI08_CHK, PCXHR_TIMEOUT_DSP, &reg);
 613	if (err)
 614		return err;
 615	/* reset irq chk */
 616	err = pcxhr_send_it_dsp(mgr, PCXHR_IT_RESET_CHK, 1);
 617	if (err)
 618		return err;
 619	/* wait for chk bit == 0*/
 620	err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK, 0,
 621				  PCXHR_TIMEOUT_DSP, &reg);
 622	if (err)
 623		return err;
 624
 625	data = rmh->cmd[0];
 626
 627	if (rmh->cmd_len > 1)
 628		data |= 0x008000;	/* MASK_MORE_THAN_1_WORD_COMMAND */
 629	else
 630		data &= 0xff7fff;	/* MASK_1_WORD_COMMAND */
 631#ifdef CONFIG_SND_DEBUG_VERBOSE
 632	if (rmh->cmd_idx < CMD_LAST_INDEX)
 633		dev_dbg(&mgr->pci->dev, "MSG cmd[0]=%x (%s)\n",
 634			    data, cmd_names[rmh->cmd_idx]);
 635#endif
 636
 637	err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY,
 638				  PCXHR_ISR_HI08_TRDY, PCXHR_TIMEOUT_DSP, &reg);
 639	if (err)
 640		return err;
 641	PCXHR_OUTPB(mgr, PCXHR_DSP_TXH, (data>>16)&0xFF);
 642	PCXHR_OUTPB(mgr, PCXHR_DSP_TXM, (data>>8)&0xFF);
 643	PCXHR_OUTPB(mgr, PCXHR_DSP_TXL, (data&0xFF));
 644
 645	if (rmh->cmd_len > 1) {
 646		/* send length */
 647		data = rmh->cmd_len - 1;
 648		err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
 649					  PCXHR_ISR_HI08_TRDY,
 650					  PCXHR_ISR_HI08_TRDY,
 651					  PCXHR_TIMEOUT_DSP, &reg);
 652		if (err)
 653			return err;
 654		PCXHR_OUTPB(mgr, PCXHR_DSP_TXH, (data>>16)&0xFF);
 655		PCXHR_OUTPB(mgr, PCXHR_DSP_TXM, (data>>8)&0xFF);
 656		PCXHR_OUTPB(mgr, PCXHR_DSP_TXL, (data&0xFF));
 657
 658		for (i=1; i < rmh->cmd_len; i++) {
 659			/* send other words */
 660			data = rmh->cmd[i];
 661#ifdef CONFIG_SND_DEBUG_VERBOSE
 662			if (rmh->cmd_idx < CMD_LAST_INDEX)
 663				dev_dbg(&mgr->pci->dev,
 664					"    cmd[%d]=%x\n", i, data);
 665#endif
 666			err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
 667						  PCXHR_ISR_HI08_TRDY,
 668						  PCXHR_ISR_HI08_TRDY,
 669						  PCXHR_TIMEOUT_DSP, &reg);
 670			if (err)
 671				return err;
 672			PCXHR_OUTPB(mgr, PCXHR_DSP_TXH, (data>>16)&0xFF);
 673			PCXHR_OUTPB(mgr, PCXHR_DSP_TXM, (data>>8)&0xFF);
 674			PCXHR_OUTPB(mgr, PCXHR_DSP_TXL, (data&0xFF));
 675		}
 676	}
 677	/* wait for chk bit */
 678	err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK,
 679				  PCXHR_ISR_HI08_CHK, PCXHR_TIMEOUT_DSP, &reg);
 680	if (err)
 681		return err;
 682	/* test status ISR */
 683	if (reg & PCXHR_ISR_HI08_ERR) {
 684		/* ERROR, wait for receiver full */
 685		err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
 686					  PCXHR_ISR_HI08_RXDF,
 687					  PCXHR_ISR_HI08_RXDF,
 688					  PCXHR_TIMEOUT_DSP, &reg);
 689		if (err) {
 690			dev_err(&mgr->pci->dev,
 691				"ERROR RMH: ISR:RXDF=1 (ISR = %x)\n", reg);
 692			return err;
 693		}
 694		/* read error code */
 695		data  = PCXHR_INPB(mgr, PCXHR_DSP_TXH) << 16;
 696		data |= PCXHR_INPB(mgr, PCXHR_DSP_TXM) << 8;
 697		data |= PCXHR_INPB(mgr, PCXHR_DSP_TXL);
 698		dev_err(&mgr->pci->dev, "ERROR RMH(%d): 0x%x\n",
 699			   rmh->cmd_idx, data);
 700		err = -EINVAL;
 701	} else {
 702		/* read the response data */
 703		err = pcxhr_read_rmh_status(mgr, rmh);
 704	}
 705	/* reset semaphore */
 706	if (pcxhr_send_it_dsp(mgr, PCXHR_IT_RESET_SEMAPHORE, 1) < 0)
 707		return -EIO;
 708	return err;
 709}
 710
 711
 712/**
 713 * pcxhr_init_rmh - initialize the RMH instance
 714 * @rmh: the rmh pointer to be initialized
 715 * @cmd: the rmh command to be set
 716 */
 717void pcxhr_init_rmh(struct pcxhr_rmh *rmh, int cmd)
 718{
 719	if (snd_BUG_ON(cmd >= CMD_LAST_INDEX))
 720		return;
 721	rmh->cmd[0] = pcxhr_dsp_cmds[cmd].opcode;
 722	rmh->cmd_len = 1;
 723	rmh->stat_len = pcxhr_dsp_cmds[cmd].st_length;
 724	rmh->dsp_stat = pcxhr_dsp_cmds[cmd].st_type;
 725	rmh->cmd_idx = cmd;
 726}
 727
 728
 729void pcxhr_set_pipe_cmd_params(struct pcxhr_rmh *rmh, int capture,
 730			       unsigned int param1, unsigned int param2,
 731			       unsigned int param3)
 732{
 733	snd_BUG_ON(param1 > MASK_FIRST_FIELD);
 734	if (capture)
 735		rmh->cmd[0] |= 0x800;		/* COMMAND_RECORD_MASK */
 736	if (param1)
 737		rmh->cmd[0] |= (param1 << FIELD_SIZE);
 738	if (param2) {
 739		snd_BUG_ON(param2 > MASK_FIRST_FIELD);
 740		rmh->cmd[0] |= param2;
 741	}
 742	if(param3) {
 743		snd_BUG_ON(param3 > MASK_DSP_WORD);
 744		rmh->cmd[1] = param3;
 745		rmh->cmd_len = 2;
 746	}
 747}
 748
 749/*
 750 * pcxhr_send_msg - send a DSP message with spinlock
 751 * @rmh: the rmh record to send and receive
 752 *
 753 * returns 0 if successful, or a negative error code.
 754 */
 755int pcxhr_send_msg(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
 756{
 
 757	int err;
 758
 759	mutex_lock(&mgr->msg_lock);
 760	err = pcxhr_send_msg_nolock(mgr, rmh);
 761	mutex_unlock(&mgr->msg_lock);
 762	return err;
 763}
 764
 765static inline int pcxhr_pipes_running(struct pcxhr_mgr *mgr)
 766{
 767	int start_mask = PCXHR_INPL(mgr, PCXHR_PLX_MBOX2);
 768	/* least segnificant 12 bits are the pipe states
 769	 * for the playback audios
 770	 * next 12 bits are the pipe states for the capture audios
 771	 * (PCXHR_PIPE_STATE_CAPTURE_OFFSET)
 772	 */
 773	start_mask &= 0xffffff;
 774	dev_dbg(&mgr->pci->dev, "CMD_PIPE_STATE MBOX2=0x%06x\n", start_mask);
 775	return start_mask;
 776}
 777
 778#define PCXHR_PIPE_STATE_CAPTURE_OFFSET		12
 779#define MAX_WAIT_FOR_DSP			20
 780
 781static int pcxhr_prepair_pipe_start(struct pcxhr_mgr *mgr,
 782				    int audio_mask, int *retry)
 783{
 784	struct pcxhr_rmh rmh;
 785	int err;
 786	int audio = 0;
 787
 788	*retry = 0;
 789	while (audio_mask) {
 790		if (audio_mask & 1) {
 791			pcxhr_init_rmh(&rmh, CMD_CAN_START_PIPE);
 792			if (audio < PCXHR_PIPE_STATE_CAPTURE_OFFSET) {
 793				/* can start playback pipe */
 794				pcxhr_set_pipe_cmd_params(&rmh, 0, audio, 0, 0);
 795			} else {
 796				/* can start capture pipe */
 797				pcxhr_set_pipe_cmd_params(&rmh, 1, audio -
 798						PCXHR_PIPE_STATE_CAPTURE_OFFSET,
 799						0, 0);
 800			}
 801			err = pcxhr_send_msg(mgr, &rmh);
 802			if (err) {
 803				dev_err(&mgr->pci->dev,
 804					   "error pipe start "
 805					   "(CMD_CAN_START_PIPE) err=%x!\n",
 806					   err);
 807				return err;
 808			}
 809			/* if the pipe couldn't be prepaired for start,
 810			 * retry it later
 811			 */
 812			if (rmh.stat[0] == 0)
 813				*retry |= (1<<audio);
 814		}
 815		audio_mask>>=1;
 816		audio++;
 817	}
 818	return 0;
 819}
 820
 821static int pcxhr_stop_pipes(struct pcxhr_mgr *mgr, int audio_mask)
 822{
 823	struct pcxhr_rmh rmh;
 824	int err;
 825	int audio = 0;
 826
 827	while (audio_mask) {
 828		if (audio_mask & 1) {
 829			pcxhr_init_rmh(&rmh, CMD_STOP_PIPE);
 830			if (audio < PCXHR_PIPE_STATE_CAPTURE_OFFSET) {
 831				/* stop playback pipe */
 832				pcxhr_set_pipe_cmd_params(&rmh, 0, audio, 0, 0);
 833			} else {
 834				/* stop capture pipe */
 835				pcxhr_set_pipe_cmd_params(&rmh, 1, audio -
 836						PCXHR_PIPE_STATE_CAPTURE_OFFSET,
 837						0, 0);
 838			}
 839			err = pcxhr_send_msg(mgr, &rmh);
 840			if (err) {
 841				dev_err(&mgr->pci->dev,
 842					   "error pipe stop "
 843					   "(CMD_STOP_PIPE) err=%x!\n", err);
 844				return err;
 845			}
 846		}
 847		audio_mask>>=1;
 848		audio++;
 849	}
 850	return 0;
 851}
 852
 853static int pcxhr_toggle_pipes(struct pcxhr_mgr *mgr, int audio_mask)
 854{
 855	struct pcxhr_rmh rmh;
 856	int err;
 857	int audio = 0;
 858
 859	while (audio_mask) {
 860		if (audio_mask & 1) {
 861			pcxhr_init_rmh(&rmh, CMD_CONF_PIPE);
 862			if (audio < PCXHR_PIPE_STATE_CAPTURE_OFFSET)
 863				pcxhr_set_pipe_cmd_params(&rmh, 0, 0, 0,
 864							  1 << audio);
 865			else
 866				pcxhr_set_pipe_cmd_params(&rmh, 1, 0, 0,
 867							  1 << (audio - PCXHR_PIPE_STATE_CAPTURE_OFFSET));
 868			err = pcxhr_send_msg(mgr, &rmh);
 869			if (err) {
 870				dev_err(&mgr->pci->dev,
 871					   "error pipe start "
 872					   "(CMD_CONF_PIPE) err=%x!\n", err);
 873				return err;
 874			}
 875		}
 876		audio_mask>>=1;
 877		audio++;
 878	}
 879	/* now fire the interrupt on the card */
 880	pcxhr_init_rmh(&rmh, CMD_SEND_IRQA);
 881	err = pcxhr_send_msg(mgr, &rmh);
 882	if (err) {
 883		dev_err(&mgr->pci->dev,
 884			   "error pipe start (CMD_SEND_IRQA) err=%x!\n",
 885			   err);
 886		return err;
 887	}
 888	return 0;
 889}
 890
 891
 892
 893int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask,
 894			 int capture_mask, int start)
 895{
 896	int state, i, err;
 897	int audio_mask;
 898
 899#ifdef CONFIG_SND_DEBUG_VERBOSE
 900	ktime_t start_time, stop_time, diff_time;
 901
 902	start_time = ktime_get();
 903#endif
 904	audio_mask = (playback_mask |
 905		      (capture_mask << PCXHR_PIPE_STATE_CAPTURE_OFFSET));
 906	/* current pipe state (playback + record) */
 907	state = pcxhr_pipes_running(mgr);
 908	dev_dbg(&mgr->pci->dev,
 909		"pcxhr_set_pipe_state %s (mask %x current %x)\n",
 910		    start ? "START" : "STOP", audio_mask, state);
 911	if (start) {
 912		/* start only pipes that are not yet started */
 913		audio_mask &= ~state;
 914		state = audio_mask;
 915		for (i = 0; i < MAX_WAIT_FOR_DSP; i++) {
 916			err = pcxhr_prepair_pipe_start(mgr, state, &state);
 917			if (err)
 918				return err;
 919			if (state == 0)
 920				break;	/* success, all pipes prepaired */
 921			mdelay(1);	/* wait 1 millisecond and retry */
 922		}
 923	} else {
 924		audio_mask &= state;	/* stop only pipes that are started */
 925	}
 926	if (audio_mask == 0)
 927		return 0;
 928
 929	err = pcxhr_toggle_pipes(mgr, audio_mask);
 930	if (err)
 931		return err;
 932
 933	i = 0;
 934	while (1) {
 935		state = pcxhr_pipes_running(mgr);
 936		/* have all pipes the new state ? */
 937		if ((state & audio_mask) == (start ? audio_mask : 0))
 938			break;
 939		if (++i >= MAX_WAIT_FOR_DSP * 100) {
 940			dev_err(&mgr->pci->dev, "error pipe start/stop\n");
 941			return -EBUSY;
 942		}
 943		udelay(10);			/* wait 10 microseconds */
 944	}
 945	if (!start) {
 946		err = pcxhr_stop_pipes(mgr, audio_mask);
 947		if (err)
 948			return err;
 949	}
 950#ifdef CONFIG_SND_DEBUG_VERBOSE
 951	stop_time = ktime_get();
 952	diff_time = ktime_sub(stop_time, start_time);
 953	dev_dbg(&mgr->pci->dev, "***SET PIPE STATE*** TIME = %ld (err = %x)\n",
 954			(long)(ktime_to_ns(diff_time)), err);
 955#endif
 956	return 0;
 957}
 958
 959int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask,
 960				unsigned int value, int *changed)
 961{
 962	struct pcxhr_rmh rmh;
 
 963	int err;
 964
 965	mutex_lock(&mgr->msg_lock);
 966	if ((mgr->io_num_reg_cont & mask) == value) {
 967		dev_dbg(&mgr->pci->dev,
 968			"IO_NUM_REG_CONT mask %x already is set to %x\n",
 969			    mask, value);
 970		if (changed)
 971			*changed = 0;
 972		mutex_unlock(&mgr->msg_lock);
 973		return 0;	/* already programmed */
 974	}
 975	pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);
 976	rmh.cmd[0] |= IO_NUM_REG_CONT;
 977	rmh.cmd[1]  = mask;
 978	rmh.cmd[2]  = value;
 979	rmh.cmd_len = 3;
 980	err = pcxhr_send_msg_nolock(mgr, &rmh);
 981	if (err == 0) {
 982		mgr->io_num_reg_cont &= ~mask;
 983		mgr->io_num_reg_cont |= value;
 984		if (changed)
 985			*changed = 1;
 986	}
 987	mutex_unlock(&mgr->msg_lock);
 988	return err;
 989}
 990
 991#define PCXHR_IRQ_TIMER		0x000300
 992#define PCXHR_IRQ_FREQ_CHANGE	0x000800
 993#define PCXHR_IRQ_TIME_CODE	0x001000
 994#define PCXHR_IRQ_NOTIFY	0x002000
 995#define PCXHR_IRQ_ASYNC		0x008000
 996#define PCXHR_IRQ_MASK		0x00bb00
 997#define PCXHR_FATAL_DSP_ERR	0xff0000
 998
 999enum pcxhr_async_err_src {
1000	PCXHR_ERR_PIPE,
1001	PCXHR_ERR_STREAM,
1002	PCXHR_ERR_AUDIO
1003};
1004
1005static int pcxhr_handle_async_err(struct pcxhr_mgr *mgr, u32 err,
1006				  enum pcxhr_async_err_src err_src, int pipe,
1007				  int is_capture)
1008{
1009	static const char * const err_src_name[] = {
 
1010		[PCXHR_ERR_PIPE]	= "Pipe",
1011		[PCXHR_ERR_STREAM]	= "Stream",
1012		[PCXHR_ERR_AUDIO]	= "Audio"
1013	};
1014
1015	if (err & 0xfff)
1016		err &= 0xfff;
1017	else
1018		err = ((err >> 12) & 0xfff);
1019	if (!err)
1020		return 0;
1021	dev_dbg(&mgr->pci->dev, "CMD_ASYNC : Error %s %s Pipe %d err=%x\n",
1022		    err_src_name[err_src],
1023		    is_capture ? "Record" : "Play", pipe, err);
1024	if (err == 0xe01)
1025		mgr->async_err_stream_xrun++;
1026	else if (err == 0xe10)
1027		mgr->async_err_pipe_xrun++;
1028	else
1029		mgr->async_err_other_last = (int)err;
1030	return 1;
1031}
1032
1033
1034static void pcxhr_msg_thread(struct pcxhr_mgr *mgr)
1035{
 
1036	struct pcxhr_rmh *prmh = mgr->prmh;
1037	int err;
1038	int i, j;
1039
1040	if (mgr->src_it_dsp & PCXHR_IRQ_FREQ_CHANGE)
1041		dev_dbg(&mgr->pci->dev,
1042			"PCXHR_IRQ_FREQ_CHANGE event occurred\n");
1043	if (mgr->src_it_dsp & PCXHR_IRQ_TIME_CODE)
1044		dev_dbg(&mgr->pci->dev,
1045			"PCXHR_IRQ_TIME_CODE event occurred\n");
1046	if (mgr->src_it_dsp & PCXHR_IRQ_NOTIFY)
1047		dev_dbg(&mgr->pci->dev,
1048			"PCXHR_IRQ_NOTIFY event occurred\n");
1049	if (mgr->src_it_dsp & (PCXHR_IRQ_FREQ_CHANGE | PCXHR_IRQ_TIME_CODE)) {
1050		/* clear events FREQ_CHANGE and TIME_CODE */
1051		pcxhr_init_rmh(prmh, CMD_TEST_IT);
1052		err = pcxhr_send_msg(mgr, prmh);
1053		dev_dbg(&mgr->pci->dev, "CMD_TEST_IT : err=%x, stat=%x\n",
1054			    err, prmh->stat[0]);
1055	}
1056	if (mgr->src_it_dsp & PCXHR_IRQ_ASYNC) {
1057		dev_dbg(&mgr->pci->dev,
1058			"PCXHR_IRQ_ASYNC event occurred\n");
1059
1060		pcxhr_init_rmh(prmh, CMD_ASYNC);
1061		prmh->cmd[0] |= 1;	/* add SEL_ASYNC_EVENTS */
1062		/* this is the only one extra long response command */
1063		prmh->stat_len = PCXHR_SIZE_MAX_LONG_STATUS;
1064		err = pcxhr_send_msg(mgr, prmh);
1065		if (err)
1066			dev_err(&mgr->pci->dev, "ERROR pcxhr_msg_thread=%x;\n",
1067				   err);
1068		i = 1;
1069		while (i < prmh->stat_len) {
1070			int nb_audio = ((prmh->stat[i] >> FIELD_SIZE) &
1071					MASK_FIRST_FIELD);
1072			int nb_stream = ((prmh->stat[i] >> (2*FIELD_SIZE)) &
1073					 MASK_FIRST_FIELD);
1074			int pipe = prmh->stat[i] & MASK_FIRST_FIELD;
1075			int is_capture = prmh->stat[i] & 0x400000;
1076			u32 err2;
1077
1078			if (prmh->stat[i] & 0x800000) {	/* if BIT_END */
1079				dev_dbg(&mgr->pci->dev,
1080					"TASKLET : End%sPipe %d\n",
1081					    is_capture ? "Record" : "Play",
1082					    pipe);
1083			}
1084			i++;
1085			err2 = prmh->stat[i] ? prmh->stat[i] : prmh->stat[i+1];
1086			if (err2)
1087				pcxhr_handle_async_err(mgr, err2,
1088						       PCXHR_ERR_PIPE,
1089						       pipe, is_capture);
1090			i += 2;
1091			for (j = 0; j < nb_stream; j++) {
1092				err2 = prmh->stat[i] ?
1093					prmh->stat[i] : prmh->stat[i+1];
1094				if (err2)
1095					pcxhr_handle_async_err(mgr, err2,
1096							       PCXHR_ERR_STREAM,
1097							       pipe,
1098							       is_capture);
1099				i += 2;
1100			}
1101			for (j = 0; j < nb_audio; j++) {
1102				err2 = prmh->stat[i] ?
1103					prmh->stat[i] : prmh->stat[i+1];
1104				if (err2)
1105					pcxhr_handle_async_err(mgr, err2,
1106							       PCXHR_ERR_AUDIO,
1107							       pipe,
1108							       is_capture);
1109				i += 2;
1110			}
1111		}
1112	}
1113}
1114
1115static u_int64_t pcxhr_stream_read_position(struct pcxhr_mgr *mgr,
1116					    struct pcxhr_stream *stream)
1117{
1118	u_int64_t hw_sample_count;
1119	struct pcxhr_rmh rmh;
1120	int err, stream_mask;
1121
1122	stream_mask = stream->pipe->is_capture ? 1 : 1<<stream->substream->number;
1123
1124	/* get sample count for one stream */
1125	pcxhr_init_rmh(&rmh, CMD_STREAM_SAMPLE_COUNT);
1126	pcxhr_set_pipe_cmd_params(&rmh, stream->pipe->is_capture,
1127				  stream->pipe->first_audio, 0, stream_mask);
1128	/* rmh.stat_len = 2; */	/* 2 resp data for each stream of the pipe */
1129
1130	err = pcxhr_send_msg(mgr, &rmh);
1131	if (err)
1132		return 0;
1133
1134	hw_sample_count = ((u_int64_t)rmh.stat[0]) << 24;
1135	hw_sample_count += (u_int64_t)rmh.stat[1];
1136
1137	dev_dbg(&mgr->pci->dev,
1138		"stream %c%d : abs samples real(%llu) timer(%llu)\n",
1139		    stream->pipe->is_capture ? 'C' : 'P',
1140		    stream->substream->number,
1141		    hw_sample_count,
1142		    stream->timer_abs_periods + stream->timer_period_frag +
1143						mgr->granularity);
 
1144	return hw_sample_count;
1145}
1146
1147static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr,
1148				   struct pcxhr_stream *stream,
1149				   int samples_to_add)
1150{
1151	if (stream->substream &&
1152	    (stream->status == PCXHR_STREAM_STATUS_RUNNING)) {
1153		u_int64_t new_sample_count;
1154		int elapsed = 0;
1155		int hardware_read = 0;
1156		struct snd_pcm_runtime *runtime = stream->substream->runtime;
1157
1158		if (samples_to_add < 0) {
1159			stream->timer_is_synced = 0;
1160			/* add default if no hardware_read possible */
1161			samples_to_add = mgr->granularity;
1162		}
1163
1164		if (!stream->timer_is_synced) {
1165			if ((stream->timer_abs_periods != 0) ||
1166			    ((stream->timer_period_frag + samples_to_add) >=
1167			    runtime->period_size)) {
1168				new_sample_count =
1169				  pcxhr_stream_read_position(mgr, stream);
1170				hardware_read = 1;
1171				if (new_sample_count >= mgr->granularity) {
1172					/* sub security offset because of
1173					 * jitter and finer granularity of
1174					 * dsp time (MBOX4)
1175					 */
1176					new_sample_count -= mgr->granularity;
1177					stream->timer_is_synced = 1;
1178				}
1179			}
1180		}
1181		if (!hardware_read) {
1182			/* if we didn't try to sync the position, increment it
1183			 * by PCXHR_GRANULARITY every timer interrupt
1184			 */
1185			new_sample_count = stream->timer_abs_periods +
1186				stream->timer_period_frag + samples_to_add;
1187		}
1188		while (1) {
1189			u_int64_t new_elapse_pos = stream->timer_abs_periods +
1190				runtime->period_size;
1191			if (new_elapse_pos > new_sample_count)
1192				break;
1193			elapsed = 1;
1194			stream->timer_buf_periods++;
1195			if (stream->timer_buf_periods >= runtime->periods)
1196				stream->timer_buf_periods = 0;
1197			stream->timer_abs_periods = new_elapse_pos;
1198		}
1199		if (new_sample_count >= stream->timer_abs_periods) {
1200			stream->timer_period_frag =
1201				(u_int32_t)(new_sample_count -
1202					    stream->timer_abs_periods);
1203		} else {
1204			dev_err(&mgr->pci->dev,
1205				   "ERROR new_sample_count too small ??? %ld\n",
1206				   (long unsigned int)new_sample_count);
1207		}
1208
1209		if (elapsed) {
1210			mutex_unlock(&mgr->lock);
1211			snd_pcm_period_elapsed(stream->substream);
1212			mutex_lock(&mgr->lock);
1213		}
1214	}
1215}
1216
1217irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
1218{
1219	struct pcxhr_mgr *mgr = dev_id;
1220	unsigned int reg;
1221	bool wake_thread = false;
 
 
 
1222
1223	reg = PCXHR_INPL(mgr, PCXHR_PLX_IRQCS);
1224	if (! (reg & PCXHR_IRQCS_ACTIVE_PCIDB)) {
 
1225		/* this device did not cause the interrupt */
1226		return IRQ_NONE;
1227	}
1228
1229	/* clear interrupt */
1230	reg = PCXHR_INPL(mgr, PCXHR_PLX_L2PCIDB);
1231	PCXHR_OUTPL(mgr, PCXHR_PLX_L2PCIDB, reg);
1232
1233	/* timer irq occurred */
1234	if (reg & PCXHR_IRQ_TIMER) {
1235		int timer_toggle = reg & PCXHR_IRQ_TIMER;
1236		if (timer_toggle == mgr->timer_toggle) {
1237			dev_dbg(&mgr->pci->dev, "ERROR TIMER TOGGLE\n");
1238			mgr->dsp_time_err++;
1239		}
1240
1241		mgr->timer_toggle = timer_toggle;
1242		mgr->src_it_dsp = reg;
1243		wake_thread = true;
1244	}
1245
1246	/* other irq's handled in the thread */
1247	if (reg & PCXHR_IRQ_MASK) {
1248		if (reg & PCXHR_IRQ_ASYNC) {
1249			/* as we didn't request any async notifications,
1250			 * some kind of xrun error will probably occurred
1251			 */
1252			/* better resynchronize all streams next interrupt : */
1253			mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID;
1254		}
1255		mgr->src_it_dsp = reg;
1256		wake_thread = true;
1257	}
1258#ifdef CONFIG_SND_DEBUG_VERBOSE
1259	if (reg & PCXHR_FATAL_DSP_ERR)
1260		dev_dbg(&mgr->pci->dev, "FATAL DSP ERROR : %x\n", reg);
1261#endif
1262
1263	return wake_thread ? IRQ_WAKE_THREAD : IRQ_HANDLED;
1264}
1265
1266irqreturn_t pcxhr_threaded_irq(int irq, void *dev_id)
1267{
1268	struct pcxhr_mgr *mgr = dev_id;
1269	int i, j;
1270	struct snd_pcxhr *chip;
1271
1272	mutex_lock(&mgr->lock);
1273	if (mgr->src_it_dsp & PCXHR_IRQ_TIMER) {
1274		/* is a 24 bit counter */
1275		int dsp_time_new =
1276			PCXHR_INPL(mgr, PCXHR_PLX_MBOX4) & PCXHR_DSP_TIME_MASK;
1277		int dsp_time_diff = dsp_time_new - mgr->dsp_time_last;
1278
1279		if ((dsp_time_diff < 0) &&
1280		    (mgr->dsp_time_last != PCXHR_DSP_TIME_INVALID)) {
1281			/* handle dsp counter wraparound without resync */
1282			int tmp_diff = dsp_time_diff + PCXHR_DSP_TIME_MASK + 1;
1283			dev_dbg(&mgr->pci->dev,
1284				"WARNING DSP timestamp old(%d) new(%d)",
1285				    mgr->dsp_time_last, dsp_time_new);
1286			if (tmp_diff > 0 && tmp_diff <= (2*mgr->granularity)) {
1287				dev_dbg(&mgr->pci->dev,
1288					"-> timestamp wraparound OK: "
1289					    "diff=%d\n", tmp_diff);
1290				dsp_time_diff = tmp_diff;
1291			} else {
1292				dev_dbg(&mgr->pci->dev,
1293					"-> resynchronize all streams\n");
1294				mgr->dsp_time_err++;
1295			}
1296		}
1297#ifdef CONFIG_SND_DEBUG_VERBOSE
1298		if (dsp_time_diff == 0)
1299			dev_dbg(&mgr->pci->dev,
1300				"ERROR DSP TIME NO DIFF time(%d)\n",
1301				    dsp_time_new);
1302		else if (dsp_time_diff >= (2*mgr->granularity))
1303			dev_dbg(&mgr->pci->dev,
1304				"ERROR DSP TIME TOO BIG old(%d) add(%d)\n",
1305				    mgr->dsp_time_last,
1306				    dsp_time_new - mgr->dsp_time_last);
1307		else if (dsp_time_diff % mgr->granularity)
1308			dev_dbg(&mgr->pci->dev,
1309				"ERROR DSP TIME increased by %d\n",
1310				    dsp_time_diff);
1311#endif
1312		mgr->dsp_time_last = dsp_time_new;
1313
 
 
 
 
 
 
 
1314		for (i = 0; i < mgr->num_cards; i++) {
1315			chip = mgr->chip[i];
1316			for (j = 0; j < chip->nb_streams_capt; j++)
1317				pcxhr_update_timer_pos(mgr,
1318						&chip->capture_stream[j],
1319						dsp_time_diff);
1320		}
1321		for (i = 0; i < mgr->num_cards; i++) {
1322			chip = mgr->chip[i];
1323			for (j = 0; j < chip->nb_streams_play; j++)
1324				pcxhr_update_timer_pos(mgr,
1325						&chip->playback_stream[j],
1326						dsp_time_diff);
1327		}
1328	}
1329
1330	pcxhr_msg_thread(mgr);
1331	mutex_unlock(&mgr->lock);
1332	return IRQ_HANDLED;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1333}
v3.5.6
 
   1/*
   2 * Driver for Digigram pcxhr compatible soundcards
   3 *
   4 * low level interface with interrupt and message handling implementation
   5 *
   6 * Copyright (c) 2004 by Digigram <alsa@digigram.com>
   7 *
   8 *   This program is free software; you can redistribute it and/or modify
   9 *   it under the terms of the GNU General Public License as published by
  10 *   the Free Software Foundation; either version 2 of the License, or
  11 *   (at your option) any later version.
  12 *
  13 *   This program is distributed in the hope that it will be useful,
  14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 *   GNU General Public License for more details.
  17 *
  18 *   You should have received a copy of the GNU General Public License
  19 *   along with this program; if not, write to the Free Software
  20 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  21 */
  22
  23#include <linux/delay.h>
  24#include <linux/firmware.h>
  25#include <linux/interrupt.h>
  26#include <asm/io.h>
 
  27#include <sound/core.h>
  28#include "pcxhr.h"
  29#include "pcxhr_mixer.h"
  30#include "pcxhr_hwdep.h"
  31#include "pcxhr_core.h"
  32
  33
  34/* registers used on the PLX (port 1) */
  35#define PCXHR_PLX_OFFSET_MIN	0x40
  36#define PCXHR_PLX_MBOX0		0x40
  37#define PCXHR_PLX_MBOX1		0x44
  38#define PCXHR_PLX_MBOX2		0x48
  39#define PCXHR_PLX_MBOX3		0x4C
  40#define PCXHR_PLX_MBOX4		0x50
  41#define PCXHR_PLX_MBOX5		0x54
  42#define PCXHR_PLX_MBOX6		0x58
  43#define PCXHR_PLX_MBOX7		0x5C
  44#define PCXHR_PLX_L2PCIDB	0x64
  45#define PCXHR_PLX_IRQCS		0x68
  46#define PCXHR_PLX_CHIPSC	0x6C
  47
  48/* registers used on the DSP (port 2) */
  49#define PCXHR_DSP_ICR		0x00
  50#define PCXHR_DSP_CVR		0x04
  51#define PCXHR_DSP_ISR		0x08
  52#define PCXHR_DSP_IVR		0x0C
  53#define PCXHR_DSP_RXH		0x14
  54#define PCXHR_DSP_TXH		0x14
  55#define PCXHR_DSP_RXM		0x18
  56#define PCXHR_DSP_TXM		0x18
  57#define PCXHR_DSP_RXL		0x1C
  58#define PCXHR_DSP_TXL		0x1C
  59#define PCXHR_DSP_RESET		0x20
  60#define PCXHR_DSP_OFFSET_MAX	0x20
  61
  62/* access to the card */
  63#define PCXHR_PLX 1
  64#define PCXHR_DSP 2
  65
  66#if (PCXHR_DSP_OFFSET_MAX > PCXHR_PLX_OFFSET_MIN)
  67#undef  PCXHR_REG_TO_PORT(x)
  68#else
  69#define PCXHR_REG_TO_PORT(x)	((x)>PCXHR_DSP_OFFSET_MAX ? PCXHR_PLX : PCXHR_DSP)
  70#endif
  71#define PCXHR_INPB(mgr,x)	inb((mgr)->port[PCXHR_REG_TO_PORT(x)] + (x))
  72#define PCXHR_INPL(mgr,x)	inl((mgr)->port[PCXHR_REG_TO_PORT(x)] + (x))
  73#define PCXHR_OUTPB(mgr,x,data)	outb((data), (mgr)->port[PCXHR_REG_TO_PORT(x)] + (x))
  74#define PCXHR_OUTPL(mgr,x,data)	outl((data), (mgr)->port[PCXHR_REG_TO_PORT(x)] + (x))
  75/* attention : access the PCXHR_DSP_* registers with inb and outb only ! */
  76
  77/* params used with PCXHR_PLX_MBOX0 */
  78#define PCXHR_MBOX0_HF5			(1 << 0)
  79#define PCXHR_MBOX0_HF4			(1 << 1)
  80#define PCXHR_MBOX0_BOOT_HERE		(1 << 23)
  81/* params used with PCXHR_PLX_IRQCS */
  82#define PCXHR_IRQCS_ENABLE_PCIIRQ	(1 << 8)
  83#define PCXHR_IRQCS_ENABLE_PCIDB	(1 << 9)
  84#define PCXHR_IRQCS_ACTIVE_PCIDB	(1 << 13)
  85/* params used with PCXHR_PLX_CHIPSC */
  86#define PCXHR_CHIPSC_INIT_VALUE		0x100D767E
  87#define PCXHR_CHIPSC_RESET_XILINX	(1 << 16)
  88#define PCXHR_CHIPSC_GPI_USERI		(1 << 17)
  89#define PCXHR_CHIPSC_DATA_CLK		(1 << 24)
  90#define PCXHR_CHIPSC_DATA_IN		(1 << 26)
  91
  92/* params used with PCXHR_DSP_ICR */
  93#define PCXHR_ICR_HI08_RREQ		0x01
  94#define PCXHR_ICR_HI08_TREQ		0x02
  95#define PCXHR_ICR_HI08_HDRQ		0x04
  96#define PCXHR_ICR_HI08_HF0		0x08
  97#define PCXHR_ICR_HI08_HF1		0x10
  98#define PCXHR_ICR_HI08_HLEND		0x20
  99#define PCXHR_ICR_HI08_INIT		0x80
 100/* params used with PCXHR_DSP_CVR */
 101#define PCXHR_CVR_HI08_HC		0x80
 102/* params used with PCXHR_DSP_ISR */
 103#define PCXHR_ISR_HI08_RXDF		0x01
 104#define PCXHR_ISR_HI08_TXDE		0x02
 105#define PCXHR_ISR_HI08_TRDY		0x04
 106#define PCXHR_ISR_HI08_ERR		0x08
 107#define PCXHR_ISR_HI08_CHK		0x10
 108#define PCXHR_ISR_HI08_HREQ		0x80
 109
 110
 111/* constants used for delay in msec */
 112#define PCXHR_WAIT_DEFAULT		2
 113#define PCXHR_WAIT_IT			25
 114#define PCXHR_WAIT_IT_EXTRA		65
 115
 116/*
 117 * pcxhr_check_reg_bit - wait for the specified bit is set/reset on a register
 118 * @reg: register to check
 119 * @mask: bit mask
 120 * @bit: resultant bit to be checked
 121 * @time: time-out of loop in msec
 122 *
 123 * returns zero if a bit matches, or a negative error code.
 124 */
 125static int pcxhr_check_reg_bit(struct pcxhr_mgr *mgr, unsigned int reg,
 126			       unsigned char mask, unsigned char bit, int time,
 127			       unsigned char* read)
 128{
 129	int i = 0;
 130	unsigned long end_time = jiffies + (time * HZ + 999) / 1000;
 131	do {
 132		*read = PCXHR_INPB(mgr, reg);
 133		if ((*read & mask) == bit) {
 134			if (i > 100)
 135				snd_printdd("ATTENTION! check_reg(%x) "
 136					    "loopcount=%d\n",
 137					    reg, i);
 138			return 0;
 139		}
 140		i++;
 141	} while (time_after_eq(end_time, jiffies));
 142	snd_printk(KERN_ERR
 143		   "pcxhr_check_reg_bit: timeout, reg=%x, mask=0x%x, val=%x\n",
 144		   reg, mask, *read);
 145	return -EIO;
 146}
 147
 148/* constants used with pcxhr_check_reg_bit() */
 149#define PCXHR_TIMEOUT_DSP		200
 150
 151
 152#define PCXHR_MASK_EXTRA_INFO		0x0000FE
 153#define PCXHR_MASK_IT_HF0		0x000100
 154#define PCXHR_MASK_IT_HF1		0x000200
 155#define PCXHR_MASK_IT_NO_HF0_HF1	0x000400
 156#define PCXHR_MASK_IT_MANAGE_HF5	0x000800
 157#define PCXHR_MASK_IT_WAIT		0x010000
 158#define PCXHR_MASK_IT_WAIT_EXTRA	0x020000
 159
 160#define PCXHR_IT_SEND_BYTE_XILINX	(0x0000003C | PCXHR_MASK_IT_HF0)
 161#define PCXHR_IT_TEST_XILINX		(0x0000003C | PCXHR_MASK_IT_HF1 | \
 162					 PCXHR_MASK_IT_MANAGE_HF5)
 163#define PCXHR_IT_DOWNLOAD_BOOT		(0x0000000C | PCXHR_MASK_IT_HF1 | \
 164					 PCXHR_MASK_IT_MANAGE_HF5 | \
 165					 PCXHR_MASK_IT_WAIT)
 166#define PCXHR_IT_RESET_BOARD_FUNC	(0x0000000C | PCXHR_MASK_IT_HF0 | \
 167					 PCXHR_MASK_IT_MANAGE_HF5 | \
 168					 PCXHR_MASK_IT_WAIT_EXTRA)
 169#define PCXHR_IT_DOWNLOAD_DSP		(0x0000000C | \
 170					 PCXHR_MASK_IT_MANAGE_HF5 | \
 171					 PCXHR_MASK_IT_WAIT)
 172#define PCXHR_IT_DEBUG			(0x0000005A | PCXHR_MASK_IT_NO_HF0_HF1)
 173#define PCXHR_IT_RESET_SEMAPHORE	(0x0000005C | PCXHR_MASK_IT_NO_HF0_HF1)
 174#define PCXHR_IT_MESSAGE		(0x00000074 | PCXHR_MASK_IT_NO_HF0_HF1)
 175#define PCXHR_IT_RESET_CHK		(0x00000076 | PCXHR_MASK_IT_NO_HF0_HF1)
 176#define PCXHR_IT_UPDATE_RBUFFER		(0x00000078 | PCXHR_MASK_IT_NO_HF0_HF1)
 177
 178static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr,
 179			     unsigned int itdsp, int atomic)
 180{
 181	int err;
 182	unsigned char reg;
 183
 184	if (itdsp & PCXHR_MASK_IT_MANAGE_HF5) {
 185		/* clear hf5 bit */
 186		PCXHR_OUTPL(mgr, PCXHR_PLX_MBOX0,
 187			    PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) &
 188			    ~PCXHR_MBOX0_HF5);
 189	}
 190	if ((itdsp & PCXHR_MASK_IT_NO_HF0_HF1) == 0) {
 191		reg = (PCXHR_ICR_HI08_RREQ |
 192		       PCXHR_ICR_HI08_TREQ |
 193		       PCXHR_ICR_HI08_HDRQ);
 194		if (itdsp & PCXHR_MASK_IT_HF0)
 195			reg |= PCXHR_ICR_HI08_HF0;
 196		if (itdsp & PCXHR_MASK_IT_HF1)
 197			reg |= PCXHR_ICR_HI08_HF1;
 198		PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg);
 199	}
 200	reg = (unsigned char)(((itdsp & PCXHR_MASK_EXTRA_INFO) >> 1) |
 201			      PCXHR_CVR_HI08_HC);
 202	PCXHR_OUTPB(mgr, PCXHR_DSP_CVR, reg);
 203	if (itdsp & PCXHR_MASK_IT_WAIT) {
 204		if (atomic)
 205			mdelay(PCXHR_WAIT_IT);
 206		else
 207			msleep(PCXHR_WAIT_IT);
 208	}
 209	if (itdsp & PCXHR_MASK_IT_WAIT_EXTRA) {
 210		if (atomic)
 211			mdelay(PCXHR_WAIT_IT_EXTRA);
 212		else
 213			msleep(PCXHR_WAIT_IT);
 214	}
 215	/* wait for CVR_HI08_HC == 0 */
 216	err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_CVR,  PCXHR_CVR_HI08_HC, 0,
 217				  PCXHR_TIMEOUT_DSP, &reg);
 218	if (err) {
 219		snd_printk(KERN_ERR "pcxhr_send_it_dsp : TIMEOUT CVR\n");
 220		return err;
 221	}
 222	if (itdsp & PCXHR_MASK_IT_MANAGE_HF5) {
 223		/* wait for hf5 bit */
 224		err = pcxhr_check_reg_bit(mgr, PCXHR_PLX_MBOX0,
 225					  PCXHR_MBOX0_HF5,
 226					  PCXHR_MBOX0_HF5,
 227					  PCXHR_TIMEOUT_DSP,
 228					  &reg);
 229		if (err) {
 230			snd_printk(KERN_ERR
 231				   "pcxhr_send_it_dsp : TIMEOUT HF5\n");
 232			return err;
 233		}
 234	}
 235	return 0; /* retry not handled here */
 236}
 237
 238void pcxhr_reset_xilinx_com(struct pcxhr_mgr *mgr)
 239{
 240	/* reset second xilinx */
 241	PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC,
 242		    PCXHR_CHIPSC_INIT_VALUE & ~PCXHR_CHIPSC_RESET_XILINX);
 243}
 244
 245static void pcxhr_enable_irq(struct pcxhr_mgr *mgr, int enable)
 246{
 247	unsigned int reg = PCXHR_INPL(mgr, PCXHR_PLX_IRQCS);
 248	/* enable/disable interrupts */
 249	if (enable)
 250		reg |=  (PCXHR_IRQCS_ENABLE_PCIIRQ | PCXHR_IRQCS_ENABLE_PCIDB);
 251	else
 252		reg &= ~(PCXHR_IRQCS_ENABLE_PCIIRQ | PCXHR_IRQCS_ENABLE_PCIDB);
 253	PCXHR_OUTPL(mgr, PCXHR_PLX_IRQCS, reg);
 254}
 255
 256void pcxhr_reset_dsp(struct pcxhr_mgr *mgr)
 257{
 258	/* disable interrupts */
 259	pcxhr_enable_irq(mgr, 0);
 260
 261	/* let's reset the DSP */
 262	PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, 0);
 263	msleep( PCXHR_WAIT_DEFAULT ); /* wait 2 msec */
 264	PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, 3);
 265	msleep( PCXHR_WAIT_DEFAULT ); /* wait 2 msec */
 266
 267	/* reset mailbox */
 268	PCXHR_OUTPL(mgr, PCXHR_PLX_MBOX0, 0);
 269}
 270
 271void pcxhr_enable_dsp(struct pcxhr_mgr *mgr)
 272{
 273	/* enable interrupts */
 274	pcxhr_enable_irq(mgr, 1);
 275}
 276
 277/*
 278 * load the xilinx image
 279 */
 280int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr,
 281			     const struct firmware *xilinx, int second)
 282{
 283	unsigned int i;
 284	unsigned int chipsc;
 285	unsigned char data;
 286	unsigned char mask;
 287	const unsigned char *image;
 288
 289	/* test first xilinx */
 290	chipsc = PCXHR_INPL(mgr, PCXHR_PLX_CHIPSC);
 291	/* REV01 cards do not support the PCXHR_CHIPSC_GPI_USERI bit anymore */
 292	/* this bit will always be 1;
 293	 * no possibility to test presence of first xilinx
 294	 */
 295	if(second) {
 296		if ((chipsc & PCXHR_CHIPSC_GPI_USERI) == 0) {
 297			snd_printk(KERN_ERR "error loading first xilinx\n");
 298			return -EINVAL;
 299		}
 300		/* activate second xilinx */
 301		chipsc |= PCXHR_CHIPSC_RESET_XILINX;
 302		PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC, chipsc);
 303		msleep( PCXHR_WAIT_DEFAULT ); /* wait 2 msec */
 304	}
 305	image = xilinx->data;
 306	for (i = 0; i < xilinx->size; i++, image++) {
 307		data = *image;
 308		mask = 0x80;
 309		while (mask) {
 310			chipsc &= ~(PCXHR_CHIPSC_DATA_CLK |
 311				    PCXHR_CHIPSC_DATA_IN);
 312			if (data & mask)
 313				chipsc |= PCXHR_CHIPSC_DATA_IN;
 314			PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC, chipsc);
 315			chipsc |= PCXHR_CHIPSC_DATA_CLK;
 316			PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC, chipsc);
 317			mask >>= 1;
 318		}
 319		/* don't take too much time in this loop... */
 320		cond_resched();
 321	}
 322	chipsc &= ~(PCXHR_CHIPSC_DATA_CLK | PCXHR_CHIPSC_DATA_IN);
 323	PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC, chipsc);
 324	/* wait 2 msec (time to boot the xilinx before any access) */
 325	msleep( PCXHR_WAIT_DEFAULT );
 326	return 0;
 327}
 328
 329/*
 330 * send an executable file to the DSP
 331 */
 332static int pcxhr_download_dsp(struct pcxhr_mgr *mgr, const struct firmware *dsp)
 333{
 334	int err;
 335	unsigned int i;
 336	unsigned int len;
 337	const unsigned char *data;
 338	unsigned char dummy;
 339	/* check the length of boot image */
 340	if (dsp->size <= 0)
 341		return -EINVAL;
 342	if (dsp->size % 3)
 343		return -EINVAL;
 344	if (snd_BUG_ON(!dsp->data))
 345		return -EINVAL;
 346	/* transfert data buffer from PC to DSP */
 347	for (i = 0; i < dsp->size; i += 3) {
 348		data = dsp->data + i;
 349		if (i == 0) {
 350			/* test data header consistency */
 351			len = (unsigned int)((data[0]<<16) +
 352					     (data[1]<<8) +
 353					     data[2]);
 354			if (len && (dsp->size != (len + 2) * 3))
 355				return -EINVAL;
 356		}
 357		/* wait DSP ready for new transfer */
 358		err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
 359					  PCXHR_ISR_HI08_TRDY,
 360					  PCXHR_ISR_HI08_TRDY,
 361					  PCXHR_TIMEOUT_DSP, &dummy);
 362		if (err) {
 363			snd_printk(KERN_ERR
 364				   "dsp loading error at position %d\n", i);
 365			return err;
 366		}
 367		/* send host data */
 368		PCXHR_OUTPB(mgr, PCXHR_DSP_TXH, data[0]);
 369		PCXHR_OUTPB(mgr, PCXHR_DSP_TXM, data[1]);
 370		PCXHR_OUTPB(mgr, PCXHR_DSP_TXL, data[2]);
 371
 372		/* don't take too much time in this loop... */
 373		cond_resched();
 374	}
 375	/* give some time to boot the DSP */
 376	msleep(PCXHR_WAIT_DEFAULT);
 377	return 0;
 378}
 379
 380/*
 381 * load the eeprom image
 382 */
 383int pcxhr_load_eeprom_binary(struct pcxhr_mgr *mgr,
 384			     const struct firmware *eeprom)
 385{
 386	int err;
 387	unsigned char reg;
 388
 389	/* init value of the ICR register */
 390	reg = PCXHR_ICR_HI08_RREQ | PCXHR_ICR_HI08_TREQ | PCXHR_ICR_HI08_HDRQ;
 391	if (PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) & PCXHR_MBOX0_BOOT_HERE) {
 392		/* no need to load the eeprom binary,
 393		 * but init the HI08 interface
 394		 */
 395		PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg | PCXHR_ICR_HI08_INIT);
 396		msleep(PCXHR_WAIT_DEFAULT);
 397		PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg);
 398		msleep(PCXHR_WAIT_DEFAULT);
 399		snd_printdd("no need to load eeprom boot\n");
 400		return 0;
 401	}
 402	PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg);
 403
 404	err = pcxhr_download_dsp(mgr, eeprom);
 405	if (err)
 406		return err;
 407	/* wait for chk bit */
 408	return pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK,
 409				   PCXHR_ISR_HI08_CHK, PCXHR_TIMEOUT_DSP, &reg);
 410}
 411
 412/*
 413 * load the boot image
 414 */
 415int pcxhr_load_boot_binary(struct pcxhr_mgr *mgr, const struct firmware *boot)
 416{
 417	int err;
 418	unsigned int physaddr = mgr->hostport.addr;
 419	unsigned char dummy;
 420
 421	/* send the hostport address to the DSP (only the upper 24 bit !) */
 422	if (snd_BUG_ON(physaddr & 0xff))
 423		return -EINVAL;
 424	PCXHR_OUTPL(mgr, PCXHR_PLX_MBOX1, (physaddr >> 8));
 425
 426	err = pcxhr_send_it_dsp(mgr, PCXHR_IT_DOWNLOAD_BOOT, 0);
 427	if (err)
 428		return err;
 429	/* clear hf5 bit */
 430	PCXHR_OUTPL(mgr, PCXHR_PLX_MBOX0,
 431		    PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) & ~PCXHR_MBOX0_HF5);
 432
 433	err = pcxhr_download_dsp(mgr, boot);
 434	if (err)
 435		return err;
 436	/* wait for hf5 bit */
 437	return pcxhr_check_reg_bit(mgr, PCXHR_PLX_MBOX0, PCXHR_MBOX0_HF5,
 438				   PCXHR_MBOX0_HF5, PCXHR_TIMEOUT_DSP, &dummy);
 439}
 440
 441/*
 442 * load the final dsp image
 443 */
 444int pcxhr_load_dsp_binary(struct pcxhr_mgr *mgr, const struct firmware *dsp)
 445{
 446	int err;
 447	unsigned char dummy;
 448	err = pcxhr_send_it_dsp(mgr, PCXHR_IT_RESET_BOARD_FUNC, 0);
 449	if (err)
 450		return err;
 451	err = pcxhr_send_it_dsp(mgr, PCXHR_IT_DOWNLOAD_DSP, 0);
 452	if (err)
 453		return err;
 454	err = pcxhr_download_dsp(mgr, dsp);
 455	if (err)
 456		return err;
 457	/* wait for chk bit */
 458	return pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
 459				   PCXHR_ISR_HI08_CHK,
 460				   PCXHR_ISR_HI08_CHK,
 461				   PCXHR_TIMEOUT_DSP, &dummy);
 462}
 463
 464
 465struct pcxhr_cmd_info {
 466	u32 opcode;		/* command word */
 467	u16 st_length;		/* status length */
 468	u16 st_type;		/* status type (RMH_SSIZE_XXX) */
 469};
 470
 471/* RMH status type */
 472enum {
 473	RMH_SSIZE_FIXED = 0,	/* status size fix (st_length = 0..x) */
 474	RMH_SSIZE_ARG = 1,	/* status size given in the LSB byte */
 475	RMH_SSIZE_MASK = 2,	/* status size given in bitmask */
 476};
 477
 478/*
 479 * Array of DSP commands
 480 */
 481static struct pcxhr_cmd_info pcxhr_dsp_cmds[] = {
 482[CMD_VERSION] =				{ 0x010000, 1, RMH_SSIZE_FIXED },
 483[CMD_SUPPORTED] =			{ 0x020000, 4, RMH_SSIZE_FIXED },
 484[CMD_TEST_IT] =				{ 0x040000, 1, RMH_SSIZE_FIXED },
 485[CMD_SEND_IRQA] =			{ 0x070001, 0, RMH_SSIZE_FIXED },
 486[CMD_ACCESS_IO_WRITE] =			{ 0x090000, 1, RMH_SSIZE_ARG },
 487[CMD_ACCESS_IO_READ] =			{ 0x094000, 1, RMH_SSIZE_ARG },
 488[CMD_ASYNC] =				{ 0x0a0000, 1, RMH_SSIZE_ARG },
 489[CMD_MODIFY_CLOCK] =			{ 0x0d0000, 0, RMH_SSIZE_FIXED },
 490[CMD_RESYNC_AUDIO_INPUTS] =		{ 0x0e0000, 0, RMH_SSIZE_FIXED },
 491[CMD_GET_DSP_RESOURCES] =		{ 0x100000, 4, RMH_SSIZE_FIXED },
 492[CMD_SET_TIMER_INTERRUPT] =		{ 0x110000, 0, RMH_SSIZE_FIXED },
 493[CMD_RES_PIPE] =			{ 0x400000, 0, RMH_SSIZE_FIXED },
 494[CMD_FREE_PIPE] =			{ 0x410000, 0, RMH_SSIZE_FIXED },
 495[CMD_CONF_PIPE] =			{ 0x422101, 0, RMH_SSIZE_FIXED },
 496[CMD_STOP_PIPE] =			{ 0x470004, 0, RMH_SSIZE_FIXED },
 497[CMD_PIPE_SAMPLE_COUNT] =		{ 0x49a000, 2, RMH_SSIZE_FIXED },
 498[CMD_CAN_START_PIPE] =			{ 0x4b0000, 1, RMH_SSIZE_FIXED },
 499[CMD_START_STREAM] =			{ 0x802000, 0, RMH_SSIZE_FIXED },
 500[CMD_STREAM_OUT_LEVEL_ADJUST] =		{ 0x822000, 0, RMH_SSIZE_FIXED },
 501[CMD_STOP_STREAM] =			{ 0x832000, 0, RMH_SSIZE_FIXED },
 502[CMD_UPDATE_R_BUFFERS] =		{ 0x840000, 0, RMH_SSIZE_FIXED },
 503[CMD_FORMAT_STREAM_OUT] =		{ 0x860000, 0, RMH_SSIZE_FIXED },
 504[CMD_FORMAT_STREAM_IN] =		{ 0x870000, 0, RMH_SSIZE_FIXED },
 505[CMD_STREAM_SAMPLE_COUNT] =		{ 0x902000, 2, RMH_SSIZE_FIXED },
 506[CMD_AUDIO_LEVEL_ADJUST] =		{ 0xc22000, 0, RMH_SSIZE_FIXED },
 
 
 507};
 508
 509#ifdef CONFIG_SND_DEBUG_VERBOSE
 510static char* cmd_names[] = {
 511[CMD_VERSION] =				"CMD_VERSION",
 512[CMD_SUPPORTED] =			"CMD_SUPPORTED",
 513[CMD_TEST_IT] =				"CMD_TEST_IT",
 514[CMD_SEND_IRQA] =			"CMD_SEND_IRQA",
 515[CMD_ACCESS_IO_WRITE] =			"CMD_ACCESS_IO_WRITE",
 516[CMD_ACCESS_IO_READ] =			"CMD_ACCESS_IO_READ",
 517[CMD_ASYNC] =				"CMD_ASYNC",
 518[CMD_MODIFY_CLOCK] =			"CMD_MODIFY_CLOCK",
 519[CMD_RESYNC_AUDIO_INPUTS] =		"CMD_RESYNC_AUDIO_INPUTS",
 520[CMD_GET_DSP_RESOURCES] =		"CMD_GET_DSP_RESOURCES",
 521[CMD_SET_TIMER_INTERRUPT] =		"CMD_SET_TIMER_INTERRUPT",
 522[CMD_RES_PIPE] =			"CMD_RES_PIPE",
 523[CMD_FREE_PIPE] =			"CMD_FREE_PIPE",
 524[CMD_CONF_PIPE] =			"CMD_CONF_PIPE",
 525[CMD_STOP_PIPE] =			"CMD_STOP_PIPE",
 526[CMD_PIPE_SAMPLE_COUNT] =		"CMD_PIPE_SAMPLE_COUNT",
 527[CMD_CAN_START_PIPE] =			"CMD_CAN_START_PIPE",
 528[CMD_START_STREAM] =			"CMD_START_STREAM",
 529[CMD_STREAM_OUT_LEVEL_ADJUST] =		"CMD_STREAM_OUT_LEVEL_ADJUST",
 530[CMD_STOP_STREAM] =			"CMD_STOP_STREAM",
 531[CMD_UPDATE_R_BUFFERS] =		"CMD_UPDATE_R_BUFFERS",
 532[CMD_FORMAT_STREAM_OUT] =		"CMD_FORMAT_STREAM_OUT",
 533[CMD_FORMAT_STREAM_IN] =		"CMD_FORMAT_STREAM_IN",
 534[CMD_STREAM_SAMPLE_COUNT] =		"CMD_STREAM_SAMPLE_COUNT",
 535[CMD_AUDIO_LEVEL_ADJUST] =		"CMD_AUDIO_LEVEL_ADJUST",
 
 
 536};
 537#endif
 538
 539
 540static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
 541{
 542	int err;
 543	int i;
 544	u32 data;
 545	u32 size_mask;
 546	unsigned char reg;
 547	int max_stat_len;
 548
 549	if (rmh->stat_len < PCXHR_SIZE_MAX_STATUS)
 550		max_stat_len = PCXHR_SIZE_MAX_STATUS;
 551	else	max_stat_len = rmh->stat_len;
 552
 553	for (i = 0; i < rmh->stat_len; i++) {
 554		/* wait for receiver full */
 555		err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
 556					  PCXHR_ISR_HI08_RXDF,
 557					  PCXHR_ISR_HI08_RXDF,
 558					  PCXHR_TIMEOUT_DSP, &reg);
 559		if (err) {
 560			snd_printk(KERN_ERR "ERROR RMH stat: "
 561				   "ISR:RXDF=1 (ISR = %x; i=%d )\n",
 562				   reg, i);
 563			return err;
 564		}
 565		/* read data */
 566		data  = PCXHR_INPB(mgr, PCXHR_DSP_TXH) << 16;
 567		data |= PCXHR_INPB(mgr, PCXHR_DSP_TXM) << 8;
 568		data |= PCXHR_INPB(mgr, PCXHR_DSP_TXL);
 569
 570		/* need to update rmh->stat_len on the fly ?? */
 571		if (!i) {
 572			if (rmh->dsp_stat != RMH_SSIZE_FIXED) {
 573				if (rmh->dsp_stat == RMH_SSIZE_ARG) {
 574					rmh->stat_len = (data & 0x0000ff) + 1;
 575					data &= 0xffff00;
 576				} else {
 577					/* rmh->dsp_stat == RMH_SSIZE_MASK */
 578					rmh->stat_len = 1;
 579					size_mask = data;
 580					while (size_mask) {
 581						if (size_mask & 1)
 582							rmh->stat_len++;
 583						size_mask >>= 1;
 584					}
 585				}
 586			}
 587		}
 588#ifdef CONFIG_SND_DEBUG_VERBOSE
 589		if (rmh->cmd_idx < CMD_LAST_INDEX)
 590			snd_printdd("    stat[%d]=%x\n", i, data);
 591#endif
 592		if (i < max_stat_len)
 593			rmh->stat[i] = data;
 594	}
 595	if (rmh->stat_len > max_stat_len) {
 596		snd_printdd("PCXHR : rmh->stat_len=%x too big\n",
 597			    rmh->stat_len);
 598		rmh->stat_len = max_stat_len;
 599	}
 600	return 0;
 601}
 602
 603static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
 604{
 605	int err;
 606	int i;
 607	u32 data;
 608	unsigned char reg;
 609
 610	if (snd_BUG_ON(rmh->cmd_len >= PCXHR_SIZE_MAX_CMD))
 611		return -EINVAL;
 612	err = pcxhr_send_it_dsp(mgr, PCXHR_IT_MESSAGE, 1);
 613	if (err) {
 614		snd_printk(KERN_ERR "pcxhr_send_message : ED_DSP_CRASHED\n");
 
 615		return err;
 616	}
 617	/* wait for chk bit */
 618	err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK,
 619				  PCXHR_ISR_HI08_CHK, PCXHR_TIMEOUT_DSP, &reg);
 620	if (err)
 621		return err;
 622	/* reset irq chk */
 623	err = pcxhr_send_it_dsp(mgr, PCXHR_IT_RESET_CHK, 1);
 624	if (err)
 625		return err;
 626	/* wait for chk bit == 0*/
 627	err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK, 0,
 628				  PCXHR_TIMEOUT_DSP, &reg);
 629	if (err)
 630		return err;
 631
 632	data = rmh->cmd[0];
 633
 634	if (rmh->cmd_len > 1)
 635		data |= 0x008000;	/* MASK_MORE_THAN_1_WORD_COMMAND */
 636	else
 637		data &= 0xff7fff;	/* MASK_1_WORD_COMMAND */
 638#ifdef CONFIG_SND_DEBUG_VERBOSE
 639	if (rmh->cmd_idx < CMD_LAST_INDEX)
 640		snd_printdd("MSG cmd[0]=%x (%s)\n",
 641			    data, cmd_names[rmh->cmd_idx]);
 642#endif
 643
 644	err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY,
 645				  PCXHR_ISR_HI08_TRDY, PCXHR_TIMEOUT_DSP, &reg);
 646	if (err)
 647		return err;
 648	PCXHR_OUTPB(mgr, PCXHR_DSP_TXH, (data>>16)&0xFF);
 649	PCXHR_OUTPB(mgr, PCXHR_DSP_TXM, (data>>8)&0xFF);
 650	PCXHR_OUTPB(mgr, PCXHR_DSP_TXL, (data&0xFF));
 651
 652	if (rmh->cmd_len > 1) {
 653		/* send length */
 654		data = rmh->cmd_len - 1;
 655		err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
 656					  PCXHR_ISR_HI08_TRDY,
 657					  PCXHR_ISR_HI08_TRDY,
 658					  PCXHR_TIMEOUT_DSP, &reg);
 659		if (err)
 660			return err;
 661		PCXHR_OUTPB(mgr, PCXHR_DSP_TXH, (data>>16)&0xFF);
 662		PCXHR_OUTPB(mgr, PCXHR_DSP_TXM, (data>>8)&0xFF);
 663		PCXHR_OUTPB(mgr, PCXHR_DSP_TXL, (data&0xFF));
 664
 665		for (i=1; i < rmh->cmd_len; i++) {
 666			/* send other words */
 667			data = rmh->cmd[i];
 668#ifdef CONFIG_SND_DEBUG_VERBOSE
 669			if (rmh->cmd_idx < CMD_LAST_INDEX)
 670				snd_printdd("    cmd[%d]=%x\n", i, data);
 
 671#endif
 672			err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
 673						  PCXHR_ISR_HI08_TRDY,
 674						  PCXHR_ISR_HI08_TRDY,
 675						  PCXHR_TIMEOUT_DSP, &reg);
 676			if (err)
 677				return err;
 678			PCXHR_OUTPB(mgr, PCXHR_DSP_TXH, (data>>16)&0xFF);
 679			PCXHR_OUTPB(mgr, PCXHR_DSP_TXM, (data>>8)&0xFF);
 680			PCXHR_OUTPB(mgr, PCXHR_DSP_TXL, (data&0xFF));
 681		}
 682	}
 683	/* wait for chk bit */
 684	err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK,
 685				  PCXHR_ISR_HI08_CHK, PCXHR_TIMEOUT_DSP, &reg);
 686	if (err)
 687		return err;
 688	/* test status ISR */
 689	if (reg & PCXHR_ISR_HI08_ERR) {
 690		/* ERROR, wait for receiver full */
 691		err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
 692					  PCXHR_ISR_HI08_RXDF,
 693					  PCXHR_ISR_HI08_RXDF,
 694					  PCXHR_TIMEOUT_DSP, &reg);
 695		if (err) {
 696			snd_printk(KERN_ERR "ERROR RMH: ISR:RXDF=1 (ISR = %x)\n", reg);
 
 697			return err;
 698		}
 699		/* read error code */
 700		data  = PCXHR_INPB(mgr, PCXHR_DSP_TXH) << 16;
 701		data |= PCXHR_INPB(mgr, PCXHR_DSP_TXM) << 8;
 702		data |= PCXHR_INPB(mgr, PCXHR_DSP_TXL);
 703		snd_printk(KERN_ERR "ERROR RMH(%d): 0x%x\n",
 704			   rmh->cmd_idx, data);
 705		err = -EINVAL;
 706	} else {
 707		/* read the response data */
 708		err = pcxhr_read_rmh_status(mgr, rmh);
 709	}
 710	/* reset semaphore */
 711	if (pcxhr_send_it_dsp(mgr, PCXHR_IT_RESET_SEMAPHORE, 1) < 0)
 712		return -EIO;
 713	return err;
 714}
 715
 716
 717/**
 718 * pcxhr_init_rmh - initialize the RMH instance
 719 * @rmh: the rmh pointer to be initialized
 720 * @cmd: the rmh command to be set
 721 */
 722void pcxhr_init_rmh(struct pcxhr_rmh *rmh, int cmd)
 723{
 724	if (snd_BUG_ON(cmd >= CMD_LAST_INDEX))
 725		return;
 726	rmh->cmd[0] = pcxhr_dsp_cmds[cmd].opcode;
 727	rmh->cmd_len = 1;
 728	rmh->stat_len = pcxhr_dsp_cmds[cmd].st_length;
 729	rmh->dsp_stat = pcxhr_dsp_cmds[cmd].st_type;
 730	rmh->cmd_idx = cmd;
 731}
 732
 733
 734void pcxhr_set_pipe_cmd_params(struct pcxhr_rmh *rmh, int capture,
 735			       unsigned int param1, unsigned int param2,
 736			       unsigned int param3)
 737{
 738	snd_BUG_ON(param1 > MASK_FIRST_FIELD);
 739	if (capture)
 740		rmh->cmd[0] |= 0x800;		/* COMMAND_RECORD_MASK */
 741	if (param1)
 742		rmh->cmd[0] |= (param1 << FIELD_SIZE);
 743	if (param2) {
 744		snd_BUG_ON(param2 > MASK_FIRST_FIELD);
 745		rmh->cmd[0] |= param2;
 746	}
 747	if(param3) {
 748		snd_BUG_ON(param3 > MASK_DSP_WORD);
 749		rmh->cmd[1] = param3;
 750		rmh->cmd_len = 2;
 751	}
 752}
 753
 754/*
 755 * pcxhr_send_msg - send a DSP message with spinlock
 756 * @rmh: the rmh record to send and receive
 757 *
 758 * returns 0 if successful, or a negative error code.
 759 */
 760int pcxhr_send_msg(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
 761{
 762	unsigned long flags;
 763	int err;
 764	spin_lock_irqsave(&mgr->msg_lock, flags);
 
 765	err = pcxhr_send_msg_nolock(mgr, rmh);
 766	spin_unlock_irqrestore(&mgr->msg_lock, flags);
 767	return err;
 768}
 769
 770static inline int pcxhr_pipes_running(struct pcxhr_mgr *mgr)
 771{
 772	int start_mask = PCXHR_INPL(mgr, PCXHR_PLX_MBOX2);
 773	/* least segnificant 12 bits are the pipe states
 774	 * for the playback audios
 775	 * next 12 bits are the pipe states for the capture audios
 776	 * (PCXHR_PIPE_STATE_CAPTURE_OFFSET)
 777	 */
 778	start_mask &= 0xffffff;
 779	snd_printdd("CMD_PIPE_STATE MBOX2=0x%06x\n", start_mask);
 780	return start_mask;
 781}
 782
 783#define PCXHR_PIPE_STATE_CAPTURE_OFFSET		12
 784#define MAX_WAIT_FOR_DSP			20
 785
 786static int pcxhr_prepair_pipe_start(struct pcxhr_mgr *mgr,
 787				    int audio_mask, int *retry)
 788{
 789	struct pcxhr_rmh rmh;
 790	int err;
 791	int audio = 0;
 792
 793	*retry = 0;
 794	while (audio_mask) {
 795		if (audio_mask & 1) {
 796			pcxhr_init_rmh(&rmh, CMD_CAN_START_PIPE);
 797			if (audio < PCXHR_PIPE_STATE_CAPTURE_OFFSET) {
 798				/* can start playback pipe */
 799				pcxhr_set_pipe_cmd_params(&rmh, 0, audio, 0, 0);
 800			} else {
 801				/* can start capture pipe */
 802				pcxhr_set_pipe_cmd_params(&rmh, 1, audio -
 803						PCXHR_PIPE_STATE_CAPTURE_OFFSET,
 804						0, 0);
 805			}
 806			err = pcxhr_send_msg(mgr, &rmh);
 807			if (err) {
 808				snd_printk(KERN_ERR
 809					   "error pipe start "
 810					   "(CMD_CAN_START_PIPE) err=%x!\n",
 811					   err);
 812				return err;
 813			}
 814			/* if the pipe couldn't be prepaired for start,
 815			 * retry it later
 816			 */
 817			if (rmh.stat[0] == 0)
 818				*retry |= (1<<audio);
 819		}
 820		audio_mask>>=1;
 821		audio++;
 822	}
 823	return 0;
 824}
 825
 826static int pcxhr_stop_pipes(struct pcxhr_mgr *mgr, int audio_mask)
 827{
 828	struct pcxhr_rmh rmh;
 829	int err;
 830	int audio = 0;
 831
 832	while (audio_mask) {
 833		if (audio_mask & 1) {
 834			pcxhr_init_rmh(&rmh, CMD_STOP_PIPE);
 835			if (audio < PCXHR_PIPE_STATE_CAPTURE_OFFSET) {
 836				/* stop playback pipe */
 837				pcxhr_set_pipe_cmd_params(&rmh, 0, audio, 0, 0);
 838			} else {
 839				/* stop capture pipe */
 840				pcxhr_set_pipe_cmd_params(&rmh, 1, audio -
 841						PCXHR_PIPE_STATE_CAPTURE_OFFSET,
 842						0, 0);
 843			}
 844			err = pcxhr_send_msg(mgr, &rmh);
 845			if (err) {
 846				snd_printk(KERN_ERR
 847					   "error pipe stop "
 848					   "(CMD_STOP_PIPE) err=%x!\n", err);
 849				return err;
 850			}
 851		}
 852		audio_mask>>=1;
 853		audio++;
 854	}
 855	return 0;
 856}
 857
 858static int pcxhr_toggle_pipes(struct pcxhr_mgr *mgr, int audio_mask)
 859{
 860	struct pcxhr_rmh rmh;
 861	int err;
 862	int audio = 0;
 863
 864	while (audio_mask) {
 865		if (audio_mask & 1) {
 866			pcxhr_init_rmh(&rmh, CMD_CONF_PIPE);
 867			if (audio < PCXHR_PIPE_STATE_CAPTURE_OFFSET)
 868				pcxhr_set_pipe_cmd_params(&rmh, 0, 0, 0,
 869							  1 << audio);
 870			else
 871				pcxhr_set_pipe_cmd_params(&rmh, 1, 0, 0,
 872							  1 << (audio - PCXHR_PIPE_STATE_CAPTURE_OFFSET));
 873			err = pcxhr_send_msg(mgr, &rmh);
 874			if (err) {
 875				snd_printk(KERN_ERR
 876					   "error pipe start "
 877					   "(CMD_CONF_PIPE) err=%x!\n", err);
 878				return err;
 879			}
 880		}
 881		audio_mask>>=1;
 882		audio++;
 883	}
 884	/* now fire the interrupt on the card */
 885	pcxhr_init_rmh(&rmh, CMD_SEND_IRQA);
 886	err = pcxhr_send_msg(mgr, &rmh);
 887	if (err) {
 888		snd_printk(KERN_ERR
 889			   "error pipe start (CMD_SEND_IRQA) err=%x!\n",
 890			   err);
 891		return err;
 892	}
 893	return 0;
 894}
 895
 896
 897
 898int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask,
 899			 int capture_mask, int start)
 900{
 901	int state, i, err;
 902	int audio_mask;
 903
 904#ifdef CONFIG_SND_DEBUG_VERBOSE
 905	struct timeval my_tv1, my_tv2;
 906	do_gettimeofday(&my_tv1);
 
 907#endif
 908	audio_mask = (playback_mask |
 909		      (capture_mask << PCXHR_PIPE_STATE_CAPTURE_OFFSET));
 910	/* current pipe state (playback + record) */
 911	state = pcxhr_pipes_running(mgr);
 912	snd_printdd("pcxhr_set_pipe_state %s (mask %x current %x)\n",
 
 913		    start ? "START" : "STOP", audio_mask, state);
 914	if (start) {
 915		/* start only pipes that are not yet started */
 916		audio_mask &= ~state;
 917		state = audio_mask;
 918		for (i = 0; i < MAX_WAIT_FOR_DSP; i++) {
 919			err = pcxhr_prepair_pipe_start(mgr, state, &state);
 920			if (err)
 921				return err;
 922			if (state == 0)
 923				break;	/* success, all pipes prepaired */
 924			mdelay(1);	/* wait 1 millisecond and retry */
 925		}
 926	} else {
 927		audio_mask &= state;	/* stop only pipes that are started */
 928	}
 929	if (audio_mask == 0)
 930		return 0;
 931
 932	err = pcxhr_toggle_pipes(mgr, audio_mask);
 933	if (err)
 934		return err;
 935
 936	i = 0;
 937	while (1) {
 938		state = pcxhr_pipes_running(mgr);
 939		/* have all pipes the new state ? */
 940		if ((state & audio_mask) == (start ? audio_mask : 0))
 941			break;
 942		if (++i >= MAX_WAIT_FOR_DSP * 100) {
 943			snd_printk(KERN_ERR "error pipe start/stop\n");
 944			return -EBUSY;
 945		}
 946		udelay(10);			/* wait 10 microseconds */
 947	}
 948	if (!start) {
 949		err = pcxhr_stop_pipes(mgr, audio_mask);
 950		if (err)
 951			return err;
 952	}
 953#ifdef CONFIG_SND_DEBUG_VERBOSE
 954	do_gettimeofday(&my_tv2);
 955	snd_printdd("***SET PIPE STATE*** TIME = %ld (err = %x)\n",
 956		    (long)(my_tv2.tv_usec - my_tv1.tv_usec), err);
 
 957#endif
 958	return 0;
 959}
 960
 961int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask,
 962				unsigned int value, int *changed)
 963{
 964	struct pcxhr_rmh rmh;
 965	unsigned long flags;
 966	int err;
 967
 968	spin_lock_irqsave(&mgr->msg_lock, flags);
 969	if ((mgr->io_num_reg_cont & mask) == value) {
 970		snd_printdd("IO_NUM_REG_CONT mask %x already is set to %x\n",
 
 971			    mask, value);
 972		if (changed)
 973			*changed = 0;
 974		spin_unlock_irqrestore(&mgr->msg_lock, flags);
 975		return 0;	/* already programmed */
 976	}
 977	pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);
 978	rmh.cmd[0] |= IO_NUM_REG_CONT;
 979	rmh.cmd[1]  = mask;
 980	rmh.cmd[2]  = value;
 981	rmh.cmd_len = 3;
 982	err = pcxhr_send_msg_nolock(mgr, &rmh);
 983	if (err == 0) {
 984		mgr->io_num_reg_cont &= ~mask;
 985		mgr->io_num_reg_cont |= value;
 986		if (changed)
 987			*changed = 1;
 988	}
 989	spin_unlock_irqrestore(&mgr->msg_lock, flags);
 990	return err;
 991}
 992
 993#define PCXHR_IRQ_TIMER		0x000300
 994#define PCXHR_IRQ_FREQ_CHANGE	0x000800
 995#define PCXHR_IRQ_TIME_CODE	0x001000
 996#define PCXHR_IRQ_NOTIFY	0x002000
 997#define PCXHR_IRQ_ASYNC		0x008000
 998#define PCXHR_IRQ_MASK		0x00bb00
 999#define PCXHR_FATAL_DSP_ERR	0xff0000
1000
1001enum pcxhr_async_err_src {
1002	PCXHR_ERR_PIPE,
1003	PCXHR_ERR_STREAM,
1004	PCXHR_ERR_AUDIO
1005};
1006
1007static int pcxhr_handle_async_err(struct pcxhr_mgr *mgr, u32 err,
1008				  enum pcxhr_async_err_src err_src, int pipe,
1009				  int is_capture)
1010{
1011#ifdef CONFIG_SND_DEBUG_VERBOSE
1012	static char* err_src_name[] = {
1013		[PCXHR_ERR_PIPE]	= "Pipe",
1014		[PCXHR_ERR_STREAM]	= "Stream",
1015		[PCXHR_ERR_AUDIO]	= "Audio"
1016	};
1017#endif
1018	if (err & 0xfff)
1019		err &= 0xfff;
1020	else
1021		err = ((err >> 12) & 0xfff);
1022	if (!err)
1023		return 0;
1024	snd_printdd("CMD_ASYNC : Error %s %s Pipe %d err=%x\n",
1025		    err_src_name[err_src],
1026		    is_capture ? "Record" : "Play", pipe, err);
1027	if (err == 0xe01)
1028		mgr->async_err_stream_xrun++;
1029	else if (err == 0xe10)
1030		mgr->async_err_pipe_xrun++;
1031	else
1032		mgr->async_err_other_last = (int)err;
1033	return 1;
1034}
1035
1036
1037void pcxhr_msg_tasklet(unsigned long arg)
1038{
1039	struct pcxhr_mgr *mgr = (struct pcxhr_mgr *)(arg);
1040	struct pcxhr_rmh *prmh = mgr->prmh;
1041	int err;
1042	int i, j;
1043
1044	if (mgr->src_it_dsp & PCXHR_IRQ_FREQ_CHANGE)
1045		snd_printdd("TASKLET : PCXHR_IRQ_FREQ_CHANGE event occurred\n");
 
1046	if (mgr->src_it_dsp & PCXHR_IRQ_TIME_CODE)
1047		snd_printdd("TASKLET : PCXHR_IRQ_TIME_CODE event occurred\n");
 
1048	if (mgr->src_it_dsp & PCXHR_IRQ_NOTIFY)
1049		snd_printdd("TASKLET : PCXHR_IRQ_NOTIFY event occurred\n");
 
1050	if (mgr->src_it_dsp & (PCXHR_IRQ_FREQ_CHANGE | PCXHR_IRQ_TIME_CODE)) {
1051		/* clear events FREQ_CHANGE and TIME_CODE */
1052		pcxhr_init_rmh(prmh, CMD_TEST_IT);
1053		err = pcxhr_send_msg(mgr, prmh);
1054		snd_printdd("CMD_TEST_IT : err=%x, stat=%x\n",
1055			    err, prmh->stat[0]);
1056	}
1057	if (mgr->src_it_dsp & PCXHR_IRQ_ASYNC) {
1058		snd_printdd("TASKLET : PCXHR_IRQ_ASYNC event occurred\n");
 
1059
1060		pcxhr_init_rmh(prmh, CMD_ASYNC);
1061		prmh->cmd[0] |= 1;	/* add SEL_ASYNC_EVENTS */
1062		/* this is the only one extra long response command */
1063		prmh->stat_len = PCXHR_SIZE_MAX_LONG_STATUS;
1064		err = pcxhr_send_msg(mgr, prmh);
1065		if (err)
1066			snd_printk(KERN_ERR "ERROR pcxhr_msg_tasklet=%x;\n",
1067				   err);
1068		i = 1;
1069		while (i < prmh->stat_len) {
1070			int nb_audio = ((prmh->stat[i] >> FIELD_SIZE) &
1071					MASK_FIRST_FIELD);
1072			int nb_stream = ((prmh->stat[i] >> (2*FIELD_SIZE)) &
1073					 MASK_FIRST_FIELD);
1074			int pipe = prmh->stat[i] & MASK_FIRST_FIELD;
1075			int is_capture = prmh->stat[i] & 0x400000;
1076			u32 err2;
1077
1078			if (prmh->stat[i] & 0x800000) {	/* if BIT_END */
1079				snd_printdd("TASKLET : End%sPipe %d\n",
 
1080					    is_capture ? "Record" : "Play",
1081					    pipe);
1082			}
1083			i++;
1084			err2 = prmh->stat[i] ? prmh->stat[i] : prmh->stat[i+1];
1085			if (err2)
1086				pcxhr_handle_async_err(mgr, err2,
1087						       PCXHR_ERR_PIPE,
1088						       pipe, is_capture);
1089			i += 2;
1090			for (j = 0; j < nb_stream; j++) {
1091				err2 = prmh->stat[i] ?
1092					prmh->stat[i] : prmh->stat[i+1];
1093				if (err2)
1094					pcxhr_handle_async_err(mgr, err2,
1095							       PCXHR_ERR_STREAM,
1096							       pipe,
1097							       is_capture);
1098				i += 2;
1099			}
1100			for (j = 0; j < nb_audio; j++) {
1101				err2 = prmh->stat[i] ?
1102					prmh->stat[i] : prmh->stat[i+1];
1103				if (err2)
1104					pcxhr_handle_async_err(mgr, err2,
1105							       PCXHR_ERR_AUDIO,
1106							       pipe,
1107							       is_capture);
1108				i += 2;
1109			}
1110		}
1111	}
1112}
1113
1114static u_int64_t pcxhr_stream_read_position(struct pcxhr_mgr *mgr,
1115					    struct pcxhr_stream *stream)
1116{
1117	u_int64_t hw_sample_count;
1118	struct pcxhr_rmh rmh;
1119	int err, stream_mask;
1120
1121	stream_mask = stream->pipe->is_capture ? 1 : 1<<stream->substream->number;
1122
1123	/* get sample count for one stream */
1124	pcxhr_init_rmh(&rmh, CMD_STREAM_SAMPLE_COUNT);
1125	pcxhr_set_pipe_cmd_params(&rmh, stream->pipe->is_capture,
1126				  stream->pipe->first_audio, 0, stream_mask);
1127	/* rmh.stat_len = 2; */	/* 2 resp data for each stream of the pipe */
1128
1129	err = pcxhr_send_msg(mgr, &rmh);
1130	if (err)
1131		return 0;
1132
1133	hw_sample_count = ((u_int64_t)rmh.stat[0]) << 24;
1134	hw_sample_count += (u_int64_t)rmh.stat[1];
1135
1136	snd_printdd("stream %c%d : abs samples real(%ld) timer(%ld)\n",
 
1137		    stream->pipe->is_capture ? 'C' : 'P',
1138		    stream->substream->number,
1139		    (long unsigned int)hw_sample_count,
1140		    (long unsigned int)(stream->timer_abs_periods +
1141					stream->timer_period_frag +
1142					mgr->granularity));
1143	return hw_sample_count;
1144}
1145
1146static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr,
1147				   struct pcxhr_stream *stream,
1148				   int samples_to_add)
1149{
1150	if (stream->substream &&
1151	    (stream->status == PCXHR_STREAM_STATUS_RUNNING)) {
1152		u_int64_t new_sample_count;
1153		int elapsed = 0;
1154		int hardware_read = 0;
1155		struct snd_pcm_runtime *runtime = stream->substream->runtime;
1156
1157		if (samples_to_add < 0) {
1158			stream->timer_is_synced = 0;
1159			/* add default if no hardware_read possible */
1160			samples_to_add = mgr->granularity;
1161		}
1162
1163		if (!stream->timer_is_synced) {
1164			if ((stream->timer_abs_periods != 0) ||
1165			    ((stream->timer_period_frag + samples_to_add) >=
1166			    runtime->period_size)) {
1167				new_sample_count =
1168				  pcxhr_stream_read_position(mgr, stream);
1169				hardware_read = 1;
1170				if (new_sample_count >= mgr->granularity) {
1171					/* sub security offset because of
1172					 * jitter and finer granularity of
1173					 * dsp time (MBOX4)
1174					 */
1175					new_sample_count -= mgr->granularity;
1176					stream->timer_is_synced = 1;
1177				}
1178			}
1179		}
1180		if (!hardware_read) {
1181			/* if we didn't try to sync the position, increment it
1182			 * by PCXHR_GRANULARITY every timer interrupt
1183			 */
1184			new_sample_count = stream->timer_abs_periods +
1185				stream->timer_period_frag + samples_to_add;
1186		}
1187		while (1) {
1188			u_int64_t new_elapse_pos = stream->timer_abs_periods +
1189				runtime->period_size;
1190			if (new_elapse_pos > new_sample_count)
1191				break;
1192			elapsed = 1;
1193			stream->timer_buf_periods++;
1194			if (stream->timer_buf_periods >= runtime->periods)
1195				stream->timer_buf_periods = 0;
1196			stream->timer_abs_periods = new_elapse_pos;
1197		}
1198		if (new_sample_count >= stream->timer_abs_periods) {
1199			stream->timer_period_frag =
1200				(u_int32_t)(new_sample_count -
1201					    stream->timer_abs_periods);
1202		} else {
1203			snd_printk(KERN_ERR
1204				   "ERROR new_sample_count too small ??? %ld\n",
1205				   (long unsigned int)new_sample_count);
1206		}
1207
1208		if (elapsed) {
1209			spin_unlock(&mgr->lock);
1210			snd_pcm_period_elapsed(stream->substream);
1211			spin_lock(&mgr->lock);
1212		}
1213	}
1214}
1215
1216irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
1217{
1218	struct pcxhr_mgr *mgr = dev_id;
1219	unsigned int reg;
1220	int i, j;
1221	struct snd_pcxhr *chip;
1222
1223	spin_lock(&mgr->lock);
1224
1225	reg = PCXHR_INPL(mgr, PCXHR_PLX_IRQCS);
1226	if (! (reg & PCXHR_IRQCS_ACTIVE_PCIDB)) {
1227		spin_unlock(&mgr->lock);
1228		/* this device did not cause the interrupt */
1229		return IRQ_NONE;
1230	}
1231
1232	/* clear interrupt */
1233	reg = PCXHR_INPL(mgr, PCXHR_PLX_L2PCIDB);
1234	PCXHR_OUTPL(mgr, PCXHR_PLX_L2PCIDB, reg);
1235
1236	/* timer irq occurred */
1237	if (reg & PCXHR_IRQ_TIMER) {
1238		int timer_toggle = reg & PCXHR_IRQ_TIMER;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1239		/* is a 24 bit counter */
1240		int dsp_time_new =
1241			PCXHR_INPL(mgr, PCXHR_PLX_MBOX4) & PCXHR_DSP_TIME_MASK;
1242		int dsp_time_diff = dsp_time_new - mgr->dsp_time_last;
1243
1244		if ((dsp_time_diff < 0) &&
1245		    (mgr->dsp_time_last != PCXHR_DSP_TIME_INVALID)) {
1246			snd_printdd("ERROR DSP TIME old(%d) new(%d) -> "
1247				    "resynchronize all streams\n",
 
 
1248				    mgr->dsp_time_last, dsp_time_new);
1249			mgr->dsp_time_err++;
 
 
 
 
 
 
 
 
 
1250		}
1251#ifdef CONFIG_SND_DEBUG_VERBOSE
1252		if (dsp_time_diff == 0)
1253			snd_printdd("ERROR DSP TIME NO DIFF time(%d)\n",
 
1254				    dsp_time_new);
1255		else if (dsp_time_diff >= (2*mgr->granularity))
1256			snd_printdd("ERROR DSP TIME TOO BIG old(%d) add(%d)\n",
 
1257				    mgr->dsp_time_last,
1258				    dsp_time_new - mgr->dsp_time_last);
1259		else if (dsp_time_diff % mgr->granularity)
1260			snd_printdd("ERROR DSP TIME increased by %d\n",
 
1261				    dsp_time_diff);
1262#endif
1263		mgr->dsp_time_last = dsp_time_new;
1264
1265		if (timer_toggle == mgr->timer_toggle) {
1266			snd_printdd("ERROR TIMER TOGGLE\n");
1267			mgr->dsp_time_err++;
1268		}
1269		mgr->timer_toggle = timer_toggle;
1270
1271		reg &= ~PCXHR_IRQ_TIMER;
1272		for (i = 0; i < mgr->num_cards; i++) {
1273			chip = mgr->chip[i];
1274			for (j = 0; j < chip->nb_streams_capt; j++)
1275				pcxhr_update_timer_pos(mgr,
1276						&chip->capture_stream[j],
1277						dsp_time_diff);
1278		}
1279		for (i = 0; i < mgr->num_cards; i++) {
1280			chip = mgr->chip[i];
1281			for (j = 0; j < chip->nb_streams_play; j++)
1282				pcxhr_update_timer_pos(mgr,
1283						&chip->playback_stream[j],
1284						dsp_time_diff);
1285		}
1286	}
1287	/* other irq's handled in the tasklet */
1288	if (reg & PCXHR_IRQ_MASK) {
1289		if (reg & PCXHR_IRQ_ASYNC) {
1290			/* as we didn't request any async notifications,
1291			 * some kind of xrun error will probably occurred
1292			 */
1293			/* better resynchronize all streams next interrupt : */
1294			mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID;
1295		}
1296		mgr->src_it_dsp = reg;
1297		tasklet_schedule(&mgr->msg_taskq);
1298	}
1299#ifdef CONFIG_SND_DEBUG_VERBOSE
1300	if (reg & PCXHR_FATAL_DSP_ERR)
1301		snd_printdd("FATAL DSP ERROR : %x\n", reg);
1302#endif
1303	spin_unlock(&mgr->lock);
1304	return IRQ_HANDLED;	/* this device caused the interrupt */
1305}