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