495be27e3ba23a178d60e6e26025d99f063ee8ed
[muen/linux.git] / sound / pci / pcxhr / pcxhr_core.c
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  */
113 static 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
166 static 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
226 void 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
233 static 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
244 void 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
259 void 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  */
268 int 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  */
320 static 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  */
371 int 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  */
403 int 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  */
432 int 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
453 struct 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 */
460 enum {
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  */
469 static 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
500 static char* 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
532 static 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
595 static 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  */
717 void 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
729 void 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  */
755 int 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
765 static 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
781 static 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
821 static 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
853 static 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
893 int 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
959 int 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
999 enum pcxhr_async_err_src {
1000         PCXHR_ERR_PIPE,
1001         PCXHR_ERR_STREAM,
1002         PCXHR_ERR_AUDIO
1003 };
1004
1005 static 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 char* 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
1034 static 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
1115 static 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
1147 static 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
1217 irqreturn_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
1266 irqreturn_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 }