Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Driver for Digigram pcxhr compatible soundcards
0004  *
0005  * low level interface with interrupt and message handling implementation
0006  *
0007  * Copyright (c) 2004 by Digigram <alsa@digigram.com>
0008  */
0009 
0010 #include <linux/delay.h>
0011 #include <linux/firmware.h>
0012 #include <linux/interrupt.h>
0013 #include <linux/pci.h>
0014 #include <linux/io.h>
0015 #include <sound/core.h>
0016 #include "pcxhr.h"
0017 #include "pcxhr_mixer.h"
0018 #include "pcxhr_hwdep.h"
0019 #include "pcxhr_core.h"
0020 
0021 
0022 /* registers used on the PLX (port 1) */
0023 #define PCXHR_PLX_OFFSET_MIN    0x40
0024 #define PCXHR_PLX_MBOX0     0x40
0025 #define PCXHR_PLX_MBOX1     0x44
0026 #define PCXHR_PLX_MBOX2     0x48
0027 #define PCXHR_PLX_MBOX3     0x4C
0028 #define PCXHR_PLX_MBOX4     0x50
0029 #define PCXHR_PLX_MBOX5     0x54
0030 #define PCXHR_PLX_MBOX6     0x58
0031 #define PCXHR_PLX_MBOX7     0x5C
0032 #define PCXHR_PLX_L2PCIDB   0x64
0033 #define PCXHR_PLX_IRQCS     0x68
0034 #define PCXHR_PLX_CHIPSC    0x6C
0035 
0036 /* registers used on the DSP (port 2) */
0037 #define PCXHR_DSP_ICR       0x00
0038 #define PCXHR_DSP_CVR       0x04
0039 #define PCXHR_DSP_ISR       0x08
0040 #define PCXHR_DSP_IVR       0x0C
0041 #define PCXHR_DSP_RXH       0x14
0042 #define PCXHR_DSP_TXH       0x14
0043 #define PCXHR_DSP_RXM       0x18
0044 #define PCXHR_DSP_TXM       0x18
0045 #define PCXHR_DSP_RXL       0x1C
0046 #define PCXHR_DSP_TXL       0x1C
0047 #define PCXHR_DSP_RESET     0x20
0048 #define PCXHR_DSP_OFFSET_MAX    0x20
0049 
0050 /* access to the card */
0051 #define PCXHR_PLX 1
0052 #define PCXHR_DSP 2
0053 
0054 #if (PCXHR_DSP_OFFSET_MAX > PCXHR_PLX_OFFSET_MIN)
0055 #error  PCXHR_REG_TO_PORT(x)
0056 #else
0057 #define PCXHR_REG_TO_PORT(x)    ((x)>PCXHR_DSP_OFFSET_MAX ? PCXHR_PLX : PCXHR_DSP)
0058 #endif
0059 #define PCXHR_INPB(mgr,x)   inb((mgr)->port[PCXHR_REG_TO_PORT(x)] + (x))
0060 #define PCXHR_INPL(mgr,x)   inl((mgr)->port[PCXHR_REG_TO_PORT(x)] + (x))
0061 #define PCXHR_OUTPB(mgr,x,data) outb((data), (mgr)->port[PCXHR_REG_TO_PORT(x)] + (x))
0062 #define PCXHR_OUTPL(mgr,x,data) outl((data), (mgr)->port[PCXHR_REG_TO_PORT(x)] + (x))
0063 /* attention : access the PCXHR_DSP_* registers with inb and outb only ! */
0064 
0065 /* params used with PCXHR_PLX_MBOX0 */
0066 #define PCXHR_MBOX0_HF5         (1 << 0)
0067 #define PCXHR_MBOX0_HF4         (1 << 1)
0068 #define PCXHR_MBOX0_BOOT_HERE       (1 << 23)
0069 /* params used with PCXHR_PLX_IRQCS */
0070 #define PCXHR_IRQCS_ENABLE_PCIIRQ   (1 << 8)
0071 #define PCXHR_IRQCS_ENABLE_PCIDB    (1 << 9)
0072 #define PCXHR_IRQCS_ACTIVE_PCIDB    (1 << 13)
0073 /* params used with PCXHR_PLX_CHIPSC */
0074 #define PCXHR_CHIPSC_INIT_VALUE     0x100D767E
0075 #define PCXHR_CHIPSC_RESET_XILINX   (1 << 16)
0076 #define PCXHR_CHIPSC_GPI_USERI      (1 << 17)
0077 #define PCXHR_CHIPSC_DATA_CLK       (1 << 24)
0078 #define PCXHR_CHIPSC_DATA_IN        (1 << 26)
0079 
0080 /* params used with PCXHR_DSP_ICR */
0081 #define PCXHR_ICR_HI08_RREQ     0x01
0082 #define PCXHR_ICR_HI08_TREQ     0x02
0083 #define PCXHR_ICR_HI08_HDRQ     0x04
0084 #define PCXHR_ICR_HI08_HF0      0x08
0085 #define PCXHR_ICR_HI08_HF1      0x10
0086 #define PCXHR_ICR_HI08_HLEND        0x20
0087 #define PCXHR_ICR_HI08_INIT     0x80
0088 /* params used with PCXHR_DSP_CVR */
0089 #define PCXHR_CVR_HI08_HC       0x80
0090 /* params used with PCXHR_DSP_ISR */
0091 #define PCXHR_ISR_HI08_RXDF     0x01
0092 #define PCXHR_ISR_HI08_TXDE     0x02
0093 #define PCXHR_ISR_HI08_TRDY     0x04
0094 #define PCXHR_ISR_HI08_ERR      0x08
0095 #define PCXHR_ISR_HI08_CHK      0x10
0096 #define PCXHR_ISR_HI08_HREQ     0x80
0097 
0098 
0099 /* constants used for delay in msec */
0100 #define PCXHR_WAIT_DEFAULT      2
0101 #define PCXHR_WAIT_IT           25
0102 #define PCXHR_WAIT_IT_EXTRA     65
0103 
0104 /*
0105  * pcxhr_check_reg_bit - wait for the specified bit is set/reset on a register
0106  * @reg: register to check
0107  * @mask: bit mask
0108  * @bit: resultant bit to be checked
0109  * @time: time-out of loop in msec
0110  *
0111  * returns zero if a bit matches, or a negative error code.
0112  */
0113 static int pcxhr_check_reg_bit(struct pcxhr_mgr *mgr, unsigned int reg,
0114                    unsigned char mask, unsigned char bit, int time,
0115                    unsigned char* read)
0116 {
0117     int i = 0;
0118     unsigned long end_time = jiffies + (time * HZ + 999) / 1000;
0119     do {
0120         *read = PCXHR_INPB(mgr, reg);
0121         if ((*read & mask) == bit) {
0122             if (i > 100)
0123                 dev_dbg(&mgr->pci->dev,
0124                     "ATTENTION! check_reg(%x) loopcount=%d\n",
0125                         reg, i);
0126             return 0;
0127         }
0128         i++;
0129     } while (time_after_eq(end_time, jiffies));
0130     dev_err(&mgr->pci->dev,
0131            "pcxhr_check_reg_bit: timeout, reg=%x, mask=0x%x, val=%x\n",
0132            reg, mask, *read);
0133     return -EIO;
0134 }
0135 
0136 /* constants used with pcxhr_check_reg_bit() */
0137 #define PCXHR_TIMEOUT_DSP       200
0138 
0139 
0140 #define PCXHR_MASK_EXTRA_INFO       0x0000FE
0141 #define PCXHR_MASK_IT_HF0       0x000100
0142 #define PCXHR_MASK_IT_HF1       0x000200
0143 #define PCXHR_MASK_IT_NO_HF0_HF1    0x000400
0144 #define PCXHR_MASK_IT_MANAGE_HF5    0x000800
0145 #define PCXHR_MASK_IT_WAIT      0x010000
0146 #define PCXHR_MASK_IT_WAIT_EXTRA    0x020000
0147 
0148 #define PCXHR_IT_SEND_BYTE_XILINX   (0x0000003C | PCXHR_MASK_IT_HF0)
0149 #define PCXHR_IT_TEST_XILINX        (0x0000003C | PCXHR_MASK_IT_HF1 | \
0150                      PCXHR_MASK_IT_MANAGE_HF5)
0151 #define PCXHR_IT_DOWNLOAD_BOOT      (0x0000000C | PCXHR_MASK_IT_HF1 | \
0152                      PCXHR_MASK_IT_MANAGE_HF5 | \
0153                      PCXHR_MASK_IT_WAIT)
0154 #define PCXHR_IT_RESET_BOARD_FUNC   (0x0000000C | PCXHR_MASK_IT_HF0 | \
0155                      PCXHR_MASK_IT_MANAGE_HF5 | \
0156                      PCXHR_MASK_IT_WAIT_EXTRA)
0157 #define PCXHR_IT_DOWNLOAD_DSP       (0x0000000C | \
0158                      PCXHR_MASK_IT_MANAGE_HF5 | \
0159                      PCXHR_MASK_IT_WAIT)
0160 #define PCXHR_IT_DEBUG          (0x0000005A | PCXHR_MASK_IT_NO_HF0_HF1)
0161 #define PCXHR_IT_RESET_SEMAPHORE    (0x0000005C | PCXHR_MASK_IT_NO_HF0_HF1)
0162 #define PCXHR_IT_MESSAGE        (0x00000074 | PCXHR_MASK_IT_NO_HF0_HF1)
0163 #define PCXHR_IT_RESET_CHK      (0x00000076 | PCXHR_MASK_IT_NO_HF0_HF1)
0164 #define PCXHR_IT_UPDATE_RBUFFER     (0x00000078 | PCXHR_MASK_IT_NO_HF0_HF1)
0165 
0166 static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr,
0167                  unsigned int itdsp, int atomic)
0168 {
0169     int err;
0170     unsigned char reg;
0171 
0172     if (itdsp & PCXHR_MASK_IT_MANAGE_HF5) {
0173         /* clear hf5 bit */
0174         PCXHR_OUTPL(mgr, PCXHR_PLX_MBOX0,
0175                 PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) &
0176                 ~PCXHR_MBOX0_HF5);
0177     }
0178     if ((itdsp & PCXHR_MASK_IT_NO_HF0_HF1) == 0) {
0179         reg = (PCXHR_ICR_HI08_RREQ |
0180                PCXHR_ICR_HI08_TREQ |
0181                PCXHR_ICR_HI08_HDRQ);
0182         if (itdsp & PCXHR_MASK_IT_HF0)
0183             reg |= PCXHR_ICR_HI08_HF0;
0184         if (itdsp & PCXHR_MASK_IT_HF1)
0185             reg |= PCXHR_ICR_HI08_HF1;
0186         PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg);
0187     }
0188     reg = (unsigned char)(((itdsp & PCXHR_MASK_EXTRA_INFO) >> 1) |
0189                   PCXHR_CVR_HI08_HC);
0190     PCXHR_OUTPB(mgr, PCXHR_DSP_CVR, reg);
0191     if (itdsp & PCXHR_MASK_IT_WAIT) {
0192         if (atomic)
0193             mdelay(PCXHR_WAIT_IT);
0194         else
0195             msleep(PCXHR_WAIT_IT);
0196     }
0197     if (itdsp & PCXHR_MASK_IT_WAIT_EXTRA) {
0198         if (atomic)
0199             mdelay(PCXHR_WAIT_IT_EXTRA);
0200         else
0201             msleep(PCXHR_WAIT_IT);
0202     }
0203     /* wait for CVR_HI08_HC == 0 */
0204     err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_CVR,  PCXHR_CVR_HI08_HC, 0,
0205                   PCXHR_TIMEOUT_DSP, &reg);
0206     if (err) {
0207         dev_err(&mgr->pci->dev, "pcxhr_send_it_dsp : TIMEOUT CVR\n");
0208         return err;
0209     }
0210     if (itdsp & PCXHR_MASK_IT_MANAGE_HF5) {
0211         /* wait for hf5 bit */
0212         err = pcxhr_check_reg_bit(mgr, PCXHR_PLX_MBOX0,
0213                       PCXHR_MBOX0_HF5,
0214                       PCXHR_MBOX0_HF5,
0215                       PCXHR_TIMEOUT_DSP,
0216                       &reg);
0217         if (err) {
0218             dev_err(&mgr->pci->dev,
0219                    "pcxhr_send_it_dsp : TIMEOUT HF5\n");
0220             return err;
0221         }
0222     }
0223     return 0; /* retry not handled here */
0224 }
0225 
0226 void pcxhr_reset_xilinx_com(struct pcxhr_mgr *mgr)
0227 {
0228     /* reset second xilinx */
0229     PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC,
0230             PCXHR_CHIPSC_INIT_VALUE & ~PCXHR_CHIPSC_RESET_XILINX);
0231 }
0232 
0233 static void pcxhr_enable_irq(struct pcxhr_mgr *mgr, int enable)
0234 {
0235     unsigned int reg = PCXHR_INPL(mgr, PCXHR_PLX_IRQCS);
0236     /* enable/disable interrupts */
0237     if (enable)
0238         reg |=  (PCXHR_IRQCS_ENABLE_PCIIRQ | PCXHR_IRQCS_ENABLE_PCIDB);
0239     else
0240         reg &= ~(PCXHR_IRQCS_ENABLE_PCIIRQ | PCXHR_IRQCS_ENABLE_PCIDB);
0241     PCXHR_OUTPL(mgr, PCXHR_PLX_IRQCS, reg);
0242 }
0243 
0244 void pcxhr_reset_dsp(struct pcxhr_mgr *mgr)
0245 {
0246     /* disable interrupts */
0247     pcxhr_enable_irq(mgr, 0);
0248 
0249     /* let's reset the DSP */
0250     PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, 0);
0251     msleep( PCXHR_WAIT_DEFAULT ); /* wait 2 msec */
0252     PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, 3);
0253     msleep( PCXHR_WAIT_DEFAULT ); /* wait 2 msec */
0254 
0255     /* reset mailbox */
0256     PCXHR_OUTPL(mgr, PCXHR_PLX_MBOX0, 0);
0257 }
0258 
0259 void pcxhr_enable_dsp(struct pcxhr_mgr *mgr)
0260 {
0261     /* enable interrupts */
0262     pcxhr_enable_irq(mgr, 1);
0263 }
0264 
0265 /*
0266  * load the xilinx image
0267  */
0268 int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr,
0269                  const struct firmware *xilinx, int second)
0270 {
0271     unsigned int i;
0272     unsigned int chipsc;
0273     unsigned char data;
0274     unsigned char mask;
0275     const unsigned char *image;
0276 
0277     /* test first xilinx */
0278     chipsc = PCXHR_INPL(mgr, PCXHR_PLX_CHIPSC);
0279     /* REV01 cards do not support the PCXHR_CHIPSC_GPI_USERI bit anymore */
0280     /* this bit will always be 1;
0281      * no possibility to test presence of first xilinx
0282      */
0283     if(second) {
0284         if ((chipsc & PCXHR_CHIPSC_GPI_USERI) == 0) {
0285             dev_err(&mgr->pci->dev, "error loading first xilinx\n");
0286             return -EINVAL;
0287         }
0288         /* activate second xilinx */
0289         chipsc |= PCXHR_CHIPSC_RESET_XILINX;
0290         PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC, chipsc);
0291         msleep( PCXHR_WAIT_DEFAULT ); /* wait 2 msec */
0292     }
0293     image = xilinx->data;
0294     for (i = 0; i < xilinx->size; i++, image++) {
0295         data = *image;
0296         mask = 0x80;
0297         while (mask) {
0298             chipsc &= ~(PCXHR_CHIPSC_DATA_CLK |
0299                     PCXHR_CHIPSC_DATA_IN);
0300             if (data & mask)
0301                 chipsc |= PCXHR_CHIPSC_DATA_IN;
0302             PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC, chipsc);
0303             chipsc |= PCXHR_CHIPSC_DATA_CLK;
0304             PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC, chipsc);
0305             mask >>= 1;
0306         }
0307         /* don't take too much time in this loop... */
0308         cond_resched();
0309     }
0310     chipsc &= ~(PCXHR_CHIPSC_DATA_CLK | PCXHR_CHIPSC_DATA_IN);
0311     PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC, chipsc);
0312     /* wait 2 msec (time to boot the xilinx before any access) */
0313     msleep( PCXHR_WAIT_DEFAULT );
0314     return 0;
0315 }
0316 
0317 /*
0318  * send an executable file to the DSP
0319  */
0320 static int pcxhr_download_dsp(struct pcxhr_mgr *mgr, const struct firmware *dsp)
0321 {
0322     int err;
0323     unsigned int i;
0324     unsigned int len;
0325     const unsigned char *data;
0326     unsigned char dummy;
0327     /* check the length of boot image */
0328     if (dsp->size <= 0)
0329         return -EINVAL;
0330     if (dsp->size % 3)
0331         return -EINVAL;
0332     if (snd_BUG_ON(!dsp->data))
0333         return -EINVAL;
0334     /* transfert data buffer from PC to DSP */
0335     for (i = 0; i < dsp->size; i += 3) {
0336         data = dsp->data + i;
0337         if (i == 0) {
0338             /* test data header consistency */
0339             len = (unsigned int)((data[0]<<16) +
0340                          (data[1]<<8) +
0341                          data[2]);
0342             if (len && (dsp->size != (len + 2) * 3))
0343                 return -EINVAL;
0344         }
0345         /* wait DSP ready for new transfer */
0346         err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
0347                       PCXHR_ISR_HI08_TRDY,
0348                       PCXHR_ISR_HI08_TRDY,
0349                       PCXHR_TIMEOUT_DSP, &dummy);
0350         if (err) {
0351             dev_err(&mgr->pci->dev,
0352                    "dsp loading error at position %d\n", i);
0353             return err;
0354         }
0355         /* send host data */
0356         PCXHR_OUTPB(mgr, PCXHR_DSP_TXH, data[0]);
0357         PCXHR_OUTPB(mgr, PCXHR_DSP_TXM, data[1]);
0358         PCXHR_OUTPB(mgr, PCXHR_DSP_TXL, data[2]);
0359 
0360         /* don't take too much time in this loop... */
0361         cond_resched();
0362     }
0363     /* give some time to boot the DSP */
0364     msleep(PCXHR_WAIT_DEFAULT);
0365     return 0;
0366 }
0367 
0368 /*
0369  * load the eeprom image
0370  */
0371 int pcxhr_load_eeprom_binary(struct pcxhr_mgr *mgr,
0372                  const struct firmware *eeprom)
0373 {
0374     int err;
0375     unsigned char reg;
0376 
0377     /* init value of the ICR register */
0378     reg = PCXHR_ICR_HI08_RREQ | PCXHR_ICR_HI08_TREQ | PCXHR_ICR_HI08_HDRQ;
0379     if (PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) & PCXHR_MBOX0_BOOT_HERE) {
0380         /* no need to load the eeprom binary,
0381          * but init the HI08 interface
0382          */
0383         PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg | PCXHR_ICR_HI08_INIT);
0384         msleep(PCXHR_WAIT_DEFAULT);
0385         PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg);
0386         msleep(PCXHR_WAIT_DEFAULT);
0387         dev_dbg(&mgr->pci->dev, "no need to load eeprom boot\n");
0388         return 0;
0389     }
0390     PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg);
0391 
0392     err = pcxhr_download_dsp(mgr, eeprom);
0393     if (err)
0394         return err;
0395     /* wait for chk bit */
0396     return pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK,
0397                    PCXHR_ISR_HI08_CHK, PCXHR_TIMEOUT_DSP, &reg);
0398 }
0399 
0400 /*
0401  * load the boot image
0402  */
0403 int pcxhr_load_boot_binary(struct pcxhr_mgr *mgr, const struct firmware *boot)
0404 {
0405     int err;
0406     unsigned int physaddr = mgr->hostport.addr;
0407     unsigned char dummy;
0408 
0409     /* send the hostport address to the DSP (only the upper 24 bit !) */
0410     if (snd_BUG_ON(physaddr & 0xff))
0411         return -EINVAL;
0412     PCXHR_OUTPL(mgr, PCXHR_PLX_MBOX1, (physaddr >> 8));
0413 
0414     err = pcxhr_send_it_dsp(mgr, PCXHR_IT_DOWNLOAD_BOOT, 0);
0415     if (err)
0416         return err;
0417     /* clear hf5 bit */
0418     PCXHR_OUTPL(mgr, PCXHR_PLX_MBOX0,
0419             PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) & ~PCXHR_MBOX0_HF5);
0420 
0421     err = pcxhr_download_dsp(mgr, boot);
0422     if (err)
0423         return err;
0424     /* wait for hf5 bit */
0425     return pcxhr_check_reg_bit(mgr, PCXHR_PLX_MBOX0, PCXHR_MBOX0_HF5,
0426                    PCXHR_MBOX0_HF5, PCXHR_TIMEOUT_DSP, &dummy);
0427 }
0428 
0429 /*
0430  * load the final dsp image
0431  */
0432 int pcxhr_load_dsp_binary(struct pcxhr_mgr *mgr, const struct firmware *dsp)
0433 {
0434     int err;
0435     unsigned char dummy;
0436     err = pcxhr_send_it_dsp(mgr, PCXHR_IT_RESET_BOARD_FUNC, 0);
0437     if (err)
0438         return err;
0439     err = pcxhr_send_it_dsp(mgr, PCXHR_IT_DOWNLOAD_DSP, 0);
0440     if (err)
0441         return err;
0442     err = pcxhr_download_dsp(mgr, dsp);
0443     if (err)
0444         return err;
0445     /* wait for chk bit */
0446     return pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
0447                    PCXHR_ISR_HI08_CHK,
0448                    PCXHR_ISR_HI08_CHK,
0449                    PCXHR_TIMEOUT_DSP, &dummy);
0450 }
0451 
0452 
0453 struct pcxhr_cmd_info {
0454     u32 opcode;     /* command word */
0455     u16 st_length;      /* status length */
0456     u16 st_type;        /* status type (RMH_SSIZE_XXX) */
0457 };
0458 
0459 /* RMH status type */
0460 enum {
0461     RMH_SSIZE_FIXED = 0,    /* status size fix (st_length = 0..x) */
0462     RMH_SSIZE_ARG = 1,  /* status size given in the LSB byte */
0463     RMH_SSIZE_MASK = 2, /* status size given in bitmask */
0464 };
0465 
0466 /*
0467  * Array of DSP commands
0468  */
0469 static const struct pcxhr_cmd_info pcxhr_dsp_cmds[] = {
0470 [CMD_VERSION] =             { 0x010000, 1, RMH_SSIZE_FIXED },
0471 [CMD_SUPPORTED] =           { 0x020000, 4, RMH_SSIZE_FIXED },
0472 [CMD_TEST_IT] =             { 0x040000, 1, RMH_SSIZE_FIXED },
0473 [CMD_SEND_IRQA] =           { 0x070001, 0, RMH_SSIZE_FIXED },
0474 [CMD_ACCESS_IO_WRITE] =         { 0x090000, 1, RMH_SSIZE_ARG },
0475 [CMD_ACCESS_IO_READ] =          { 0x094000, 1, RMH_SSIZE_ARG },
0476 [CMD_ASYNC] =               { 0x0a0000, 1, RMH_SSIZE_ARG },
0477 [CMD_MODIFY_CLOCK] =            { 0x0d0000, 0, RMH_SSIZE_FIXED },
0478 [CMD_RESYNC_AUDIO_INPUTS] =     { 0x0e0000, 0, RMH_SSIZE_FIXED },
0479 [CMD_GET_DSP_RESOURCES] =       { 0x100000, 4, RMH_SSIZE_FIXED },
0480 [CMD_SET_TIMER_INTERRUPT] =     { 0x110000, 0, RMH_SSIZE_FIXED },
0481 [CMD_RES_PIPE] =            { 0x400000, 0, RMH_SSIZE_FIXED },
0482 [CMD_FREE_PIPE] =           { 0x410000, 0, RMH_SSIZE_FIXED },
0483 [CMD_CONF_PIPE] =           { 0x422101, 0, RMH_SSIZE_FIXED },
0484 [CMD_STOP_PIPE] =           { 0x470004, 0, RMH_SSIZE_FIXED },
0485 [CMD_PIPE_SAMPLE_COUNT] =       { 0x49a000, 2, RMH_SSIZE_FIXED },
0486 [CMD_CAN_START_PIPE] =          { 0x4b0000, 1, RMH_SSIZE_FIXED },
0487 [CMD_START_STREAM] =            { 0x802000, 0, RMH_SSIZE_FIXED },
0488 [CMD_STREAM_OUT_LEVEL_ADJUST] =     { 0x822000, 0, RMH_SSIZE_FIXED },
0489 [CMD_STOP_STREAM] =         { 0x832000, 0, RMH_SSIZE_FIXED },
0490 [CMD_UPDATE_R_BUFFERS] =        { 0x840000, 0, RMH_SSIZE_FIXED },
0491 [CMD_FORMAT_STREAM_OUT] =       { 0x860000, 0, RMH_SSIZE_FIXED },
0492 [CMD_FORMAT_STREAM_IN] =        { 0x870000, 0, RMH_SSIZE_FIXED },
0493 [CMD_STREAM_SAMPLE_COUNT] =     { 0x902000, 2, RMH_SSIZE_FIXED },
0494 [CMD_AUDIO_LEVEL_ADJUST] =      { 0xc22000, 0, RMH_SSIZE_FIXED },
0495 [CMD_GET_TIME_CODE] =           { 0x060000, 5, RMH_SSIZE_FIXED },
0496 [CMD_MANAGE_SIGNAL] =           { 0x0f0000, 0, RMH_SSIZE_FIXED },
0497 };
0498 
0499 #ifdef CONFIG_SND_DEBUG_VERBOSE
0500 static const char * const cmd_names[] = {
0501 [CMD_VERSION] =             "CMD_VERSION",
0502 [CMD_SUPPORTED] =           "CMD_SUPPORTED",
0503 [CMD_TEST_IT] =             "CMD_TEST_IT",
0504 [CMD_SEND_IRQA] =           "CMD_SEND_IRQA",
0505 [CMD_ACCESS_IO_WRITE] =         "CMD_ACCESS_IO_WRITE",
0506 [CMD_ACCESS_IO_READ] =          "CMD_ACCESS_IO_READ",
0507 [CMD_ASYNC] =               "CMD_ASYNC",
0508 [CMD_MODIFY_CLOCK] =            "CMD_MODIFY_CLOCK",
0509 [CMD_RESYNC_AUDIO_INPUTS] =     "CMD_RESYNC_AUDIO_INPUTS",
0510 [CMD_GET_DSP_RESOURCES] =       "CMD_GET_DSP_RESOURCES",
0511 [CMD_SET_TIMER_INTERRUPT] =     "CMD_SET_TIMER_INTERRUPT",
0512 [CMD_RES_PIPE] =            "CMD_RES_PIPE",
0513 [CMD_FREE_PIPE] =           "CMD_FREE_PIPE",
0514 [CMD_CONF_PIPE] =           "CMD_CONF_PIPE",
0515 [CMD_STOP_PIPE] =           "CMD_STOP_PIPE",
0516 [CMD_PIPE_SAMPLE_COUNT] =       "CMD_PIPE_SAMPLE_COUNT",
0517 [CMD_CAN_START_PIPE] =          "CMD_CAN_START_PIPE",
0518 [CMD_START_STREAM] =            "CMD_START_STREAM",
0519 [CMD_STREAM_OUT_LEVEL_ADJUST] =     "CMD_STREAM_OUT_LEVEL_ADJUST",
0520 [CMD_STOP_STREAM] =         "CMD_STOP_STREAM",
0521 [CMD_UPDATE_R_BUFFERS] =        "CMD_UPDATE_R_BUFFERS",
0522 [CMD_FORMAT_STREAM_OUT] =       "CMD_FORMAT_STREAM_OUT",
0523 [CMD_FORMAT_STREAM_IN] =        "CMD_FORMAT_STREAM_IN",
0524 [CMD_STREAM_SAMPLE_COUNT] =     "CMD_STREAM_SAMPLE_COUNT",
0525 [CMD_AUDIO_LEVEL_ADJUST] =      "CMD_AUDIO_LEVEL_ADJUST",
0526 [CMD_GET_TIME_CODE] =           "CMD_GET_TIME_CODE",
0527 [CMD_MANAGE_SIGNAL] =           "CMD_MANAGE_SIGNAL",
0528 };
0529 #endif
0530 
0531 
0532 static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
0533 {
0534     int err;
0535     int i;
0536     u32 data;
0537     u32 size_mask;
0538     unsigned char reg;
0539     int max_stat_len;
0540 
0541     if (rmh->stat_len < PCXHR_SIZE_MAX_STATUS)
0542         max_stat_len = PCXHR_SIZE_MAX_STATUS;
0543     else    max_stat_len = rmh->stat_len;
0544 
0545     for (i = 0; i < rmh->stat_len; i++) {
0546         /* wait for receiver full */
0547         err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
0548                       PCXHR_ISR_HI08_RXDF,
0549                       PCXHR_ISR_HI08_RXDF,
0550                       PCXHR_TIMEOUT_DSP, &reg);
0551         if (err) {
0552             dev_err(&mgr->pci->dev,
0553                 "ERROR RMH stat: ISR:RXDF=1 (ISR = %x; i=%d )\n",
0554                 reg, i);
0555             return err;
0556         }
0557         /* read data */
0558         data  = PCXHR_INPB(mgr, PCXHR_DSP_TXH) << 16;
0559         data |= PCXHR_INPB(mgr, PCXHR_DSP_TXM) << 8;
0560         data |= PCXHR_INPB(mgr, PCXHR_DSP_TXL);
0561 
0562         /* need to update rmh->stat_len on the fly ?? */
0563         if (!i) {
0564             if (rmh->dsp_stat != RMH_SSIZE_FIXED) {
0565                 if (rmh->dsp_stat == RMH_SSIZE_ARG) {
0566                     rmh->stat_len = (data & 0x0000ff) + 1;
0567                     data &= 0xffff00;
0568                 } else {
0569                     /* rmh->dsp_stat == RMH_SSIZE_MASK */
0570                     rmh->stat_len = 1;
0571                     size_mask = data;
0572                     while (size_mask) {
0573                         if (size_mask & 1)
0574                             rmh->stat_len++;
0575                         size_mask >>= 1;
0576                     }
0577                 }
0578             }
0579         }
0580 #ifdef CONFIG_SND_DEBUG_VERBOSE
0581         if (rmh->cmd_idx < CMD_LAST_INDEX)
0582             dev_dbg(&mgr->pci->dev, "    stat[%d]=%x\n", i, data);
0583 #endif
0584         if (i < max_stat_len)
0585             rmh->stat[i] = data;
0586     }
0587     if (rmh->stat_len > max_stat_len) {
0588         dev_dbg(&mgr->pci->dev, "PCXHR : rmh->stat_len=%x too big\n",
0589                 rmh->stat_len);
0590         rmh->stat_len = max_stat_len;
0591     }
0592     return 0;
0593 }
0594 
0595 static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
0596 {
0597     int err;
0598     int i;
0599     u32 data;
0600     unsigned char reg;
0601 
0602     if (snd_BUG_ON(rmh->cmd_len >= PCXHR_SIZE_MAX_CMD))
0603         return -EINVAL;
0604     err = pcxhr_send_it_dsp(mgr, PCXHR_IT_MESSAGE, 1);
0605     if (err) {
0606         dev_err(&mgr->pci->dev,
0607             "pcxhr_send_message : ED_DSP_CRASHED\n");
0608         return err;
0609     }
0610     /* wait for chk bit */
0611     err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK,
0612                   PCXHR_ISR_HI08_CHK, PCXHR_TIMEOUT_DSP, &reg);
0613     if (err)
0614         return err;
0615     /* reset irq chk */
0616     err = pcxhr_send_it_dsp(mgr, PCXHR_IT_RESET_CHK, 1);
0617     if (err)
0618         return err;
0619     /* wait for chk bit == 0*/
0620     err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK, 0,
0621                   PCXHR_TIMEOUT_DSP, &reg);
0622     if (err)
0623         return err;
0624 
0625     data = rmh->cmd[0];
0626 
0627     if (rmh->cmd_len > 1)
0628         data |= 0x008000;   /* MASK_MORE_THAN_1_WORD_COMMAND */
0629     else
0630         data &= 0xff7fff;   /* MASK_1_WORD_COMMAND */
0631 #ifdef CONFIG_SND_DEBUG_VERBOSE
0632     if (rmh->cmd_idx < CMD_LAST_INDEX)
0633         dev_dbg(&mgr->pci->dev, "MSG cmd[0]=%x (%s)\n",
0634                 data, cmd_names[rmh->cmd_idx]);
0635 #endif
0636 
0637     err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY,
0638                   PCXHR_ISR_HI08_TRDY, PCXHR_TIMEOUT_DSP, &reg);
0639     if (err)
0640         return err;
0641     PCXHR_OUTPB(mgr, PCXHR_DSP_TXH, (data>>16)&0xFF);
0642     PCXHR_OUTPB(mgr, PCXHR_DSP_TXM, (data>>8)&0xFF);
0643     PCXHR_OUTPB(mgr, PCXHR_DSP_TXL, (data&0xFF));
0644 
0645     if (rmh->cmd_len > 1) {
0646         /* send length */
0647         data = rmh->cmd_len - 1;
0648         err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
0649                       PCXHR_ISR_HI08_TRDY,
0650                       PCXHR_ISR_HI08_TRDY,
0651                       PCXHR_TIMEOUT_DSP, &reg);
0652         if (err)
0653             return err;
0654         PCXHR_OUTPB(mgr, PCXHR_DSP_TXH, (data>>16)&0xFF);
0655         PCXHR_OUTPB(mgr, PCXHR_DSP_TXM, (data>>8)&0xFF);
0656         PCXHR_OUTPB(mgr, PCXHR_DSP_TXL, (data&0xFF));
0657 
0658         for (i=1; i < rmh->cmd_len; i++) {
0659             /* send other words */
0660             data = rmh->cmd[i];
0661 #ifdef CONFIG_SND_DEBUG_VERBOSE
0662             if (rmh->cmd_idx < CMD_LAST_INDEX)
0663                 dev_dbg(&mgr->pci->dev,
0664                     "    cmd[%d]=%x\n", i, data);
0665 #endif
0666             err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
0667                           PCXHR_ISR_HI08_TRDY,
0668                           PCXHR_ISR_HI08_TRDY,
0669                           PCXHR_TIMEOUT_DSP, &reg);
0670             if (err)
0671                 return err;
0672             PCXHR_OUTPB(mgr, PCXHR_DSP_TXH, (data>>16)&0xFF);
0673             PCXHR_OUTPB(mgr, PCXHR_DSP_TXM, (data>>8)&0xFF);
0674             PCXHR_OUTPB(mgr, PCXHR_DSP_TXL, (data&0xFF));
0675         }
0676     }
0677     /* wait for chk bit */
0678     err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK,
0679                   PCXHR_ISR_HI08_CHK, PCXHR_TIMEOUT_DSP, &reg);
0680     if (err)
0681         return err;
0682     /* test status ISR */
0683     if (reg & PCXHR_ISR_HI08_ERR) {
0684         /* ERROR, wait for receiver full */
0685         err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
0686                       PCXHR_ISR_HI08_RXDF,
0687                       PCXHR_ISR_HI08_RXDF,
0688                       PCXHR_TIMEOUT_DSP, &reg);
0689         if (err) {
0690             dev_err(&mgr->pci->dev,
0691                 "ERROR RMH: ISR:RXDF=1 (ISR = %x)\n", reg);
0692             return err;
0693         }
0694         /* read error code */
0695         data  = PCXHR_INPB(mgr, PCXHR_DSP_TXH) << 16;
0696         data |= PCXHR_INPB(mgr, PCXHR_DSP_TXM) << 8;
0697         data |= PCXHR_INPB(mgr, PCXHR_DSP_TXL);
0698         dev_err(&mgr->pci->dev, "ERROR RMH(%d): 0x%x\n",
0699                rmh->cmd_idx, data);
0700         err = -EINVAL;
0701     } else {
0702         /* read the response data */
0703         err = pcxhr_read_rmh_status(mgr, rmh);
0704     }
0705     /* reset semaphore */
0706     if (pcxhr_send_it_dsp(mgr, PCXHR_IT_RESET_SEMAPHORE, 1) < 0)
0707         return -EIO;
0708     return err;
0709 }
0710 
0711 
0712 /**
0713  * pcxhr_init_rmh - initialize the RMH instance
0714  * @rmh: the rmh pointer to be initialized
0715  * @cmd: the rmh command to be set
0716  */
0717 void pcxhr_init_rmh(struct pcxhr_rmh *rmh, int cmd)
0718 {
0719     if (snd_BUG_ON(cmd >= CMD_LAST_INDEX))
0720         return;
0721     rmh->cmd[0] = pcxhr_dsp_cmds[cmd].opcode;
0722     rmh->cmd_len = 1;
0723     rmh->stat_len = pcxhr_dsp_cmds[cmd].st_length;
0724     rmh->dsp_stat = pcxhr_dsp_cmds[cmd].st_type;
0725     rmh->cmd_idx = cmd;
0726 }
0727 
0728 
0729 void pcxhr_set_pipe_cmd_params(struct pcxhr_rmh *rmh, int capture,
0730                    unsigned int param1, unsigned int param2,
0731                    unsigned int param3)
0732 {
0733     snd_BUG_ON(param1 > MASK_FIRST_FIELD);
0734     if (capture)
0735         rmh->cmd[0] |= 0x800;       /* COMMAND_RECORD_MASK */
0736     if (param1)
0737         rmh->cmd[0] |= (param1 << FIELD_SIZE);
0738     if (param2) {
0739         snd_BUG_ON(param2 > MASK_FIRST_FIELD);
0740         rmh->cmd[0] |= param2;
0741     }
0742     if(param3) {
0743         snd_BUG_ON(param3 > MASK_DSP_WORD);
0744         rmh->cmd[1] = param3;
0745         rmh->cmd_len = 2;
0746     }
0747 }
0748 
0749 /*
0750  * pcxhr_send_msg - send a DSP message with spinlock
0751  * @rmh: the rmh record to send and receive
0752  *
0753  * returns 0 if successful, or a negative error code.
0754  */
0755 int pcxhr_send_msg(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
0756 {
0757     int err;
0758 
0759     mutex_lock(&mgr->msg_lock);
0760     err = pcxhr_send_msg_nolock(mgr, rmh);
0761     mutex_unlock(&mgr->msg_lock);
0762     return err;
0763 }
0764 
0765 static inline int pcxhr_pipes_running(struct pcxhr_mgr *mgr)
0766 {
0767     int start_mask = PCXHR_INPL(mgr, PCXHR_PLX_MBOX2);
0768     /* least segnificant 12 bits are the pipe states
0769      * for the playback audios
0770      * next 12 bits are the pipe states for the capture audios
0771      * (PCXHR_PIPE_STATE_CAPTURE_OFFSET)
0772      */
0773     start_mask &= 0xffffff;
0774     dev_dbg(&mgr->pci->dev, "CMD_PIPE_STATE MBOX2=0x%06x\n", start_mask);
0775     return start_mask;
0776 }
0777 
0778 #define PCXHR_PIPE_STATE_CAPTURE_OFFSET     12
0779 #define MAX_WAIT_FOR_DSP            20
0780 
0781 static int pcxhr_prepair_pipe_start(struct pcxhr_mgr *mgr,
0782                     int audio_mask, int *retry)
0783 {
0784     struct pcxhr_rmh rmh;
0785     int err;
0786     int audio = 0;
0787 
0788     *retry = 0;
0789     while (audio_mask) {
0790         if (audio_mask & 1) {
0791             pcxhr_init_rmh(&rmh, CMD_CAN_START_PIPE);
0792             if (audio < PCXHR_PIPE_STATE_CAPTURE_OFFSET) {
0793                 /* can start playback pipe */
0794                 pcxhr_set_pipe_cmd_params(&rmh, 0, audio, 0, 0);
0795             } else {
0796                 /* can start capture pipe */
0797                 pcxhr_set_pipe_cmd_params(&rmh, 1, audio -
0798                         PCXHR_PIPE_STATE_CAPTURE_OFFSET,
0799                         0, 0);
0800             }
0801             err = pcxhr_send_msg(mgr, &rmh);
0802             if (err) {
0803                 dev_err(&mgr->pci->dev,
0804                        "error pipe start "
0805                        "(CMD_CAN_START_PIPE) err=%x!\n",
0806                        err);
0807                 return err;
0808             }
0809             /* if the pipe couldn't be prepaired for start,
0810              * retry it later
0811              */
0812             if (rmh.stat[0] == 0)
0813                 *retry |= (1<<audio);
0814         }
0815         audio_mask>>=1;
0816         audio++;
0817     }
0818     return 0;
0819 }
0820 
0821 static int pcxhr_stop_pipes(struct pcxhr_mgr *mgr, int audio_mask)
0822 {
0823     struct pcxhr_rmh rmh;
0824     int err;
0825     int audio = 0;
0826 
0827     while (audio_mask) {
0828         if (audio_mask & 1) {
0829             pcxhr_init_rmh(&rmh, CMD_STOP_PIPE);
0830             if (audio < PCXHR_PIPE_STATE_CAPTURE_OFFSET) {
0831                 /* stop playback pipe */
0832                 pcxhr_set_pipe_cmd_params(&rmh, 0, audio, 0, 0);
0833             } else {
0834                 /* stop capture pipe */
0835                 pcxhr_set_pipe_cmd_params(&rmh, 1, audio -
0836                         PCXHR_PIPE_STATE_CAPTURE_OFFSET,
0837                         0, 0);
0838             }
0839             err = pcxhr_send_msg(mgr, &rmh);
0840             if (err) {
0841                 dev_err(&mgr->pci->dev,
0842                        "error pipe stop "
0843                        "(CMD_STOP_PIPE) err=%x!\n", err);
0844                 return err;
0845             }
0846         }
0847         audio_mask>>=1;
0848         audio++;
0849     }
0850     return 0;
0851 }
0852 
0853 static int pcxhr_toggle_pipes(struct pcxhr_mgr *mgr, int audio_mask)
0854 {
0855     struct pcxhr_rmh rmh;
0856     int err;
0857     int audio = 0;
0858 
0859     while (audio_mask) {
0860         if (audio_mask & 1) {
0861             pcxhr_init_rmh(&rmh, CMD_CONF_PIPE);
0862             if (audio < PCXHR_PIPE_STATE_CAPTURE_OFFSET)
0863                 pcxhr_set_pipe_cmd_params(&rmh, 0, 0, 0,
0864                               1 << audio);
0865             else
0866                 pcxhr_set_pipe_cmd_params(&rmh, 1, 0, 0,
0867                               1 << (audio - PCXHR_PIPE_STATE_CAPTURE_OFFSET));
0868             err = pcxhr_send_msg(mgr, &rmh);
0869             if (err) {
0870                 dev_err(&mgr->pci->dev,
0871                        "error pipe start "
0872                        "(CMD_CONF_PIPE) err=%x!\n", err);
0873                 return err;
0874             }
0875         }
0876         audio_mask>>=1;
0877         audio++;
0878     }
0879     /* now fire the interrupt on the card */
0880     pcxhr_init_rmh(&rmh, CMD_SEND_IRQA);
0881     err = pcxhr_send_msg(mgr, &rmh);
0882     if (err) {
0883         dev_err(&mgr->pci->dev,
0884                "error pipe start (CMD_SEND_IRQA) err=%x!\n",
0885                err);
0886         return err;
0887     }
0888     return 0;
0889 }
0890 
0891 
0892 
0893 int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask,
0894              int capture_mask, int start)
0895 {
0896     int state, i, err;
0897     int audio_mask;
0898 
0899 #ifdef CONFIG_SND_DEBUG_VERBOSE
0900     ktime_t start_time, stop_time, diff_time;
0901 
0902     start_time = ktime_get();
0903 #endif
0904     audio_mask = (playback_mask |
0905               (capture_mask << PCXHR_PIPE_STATE_CAPTURE_OFFSET));
0906     /* current pipe state (playback + record) */
0907     state = pcxhr_pipes_running(mgr);
0908     dev_dbg(&mgr->pci->dev,
0909         "pcxhr_set_pipe_state %s (mask %x current %x)\n",
0910             start ? "START" : "STOP", audio_mask, state);
0911     if (start) {
0912         /* start only pipes that are not yet started */
0913         audio_mask &= ~state;
0914         state = audio_mask;
0915         for (i = 0; i < MAX_WAIT_FOR_DSP; i++) {
0916             err = pcxhr_prepair_pipe_start(mgr, state, &state);
0917             if (err)
0918                 return err;
0919             if (state == 0)
0920                 break;  /* success, all pipes prepaired */
0921             mdelay(1);  /* wait 1 millisecond and retry */
0922         }
0923     } else {
0924         audio_mask &= state;    /* stop only pipes that are started */
0925     }
0926     if (audio_mask == 0)
0927         return 0;
0928 
0929     err = pcxhr_toggle_pipes(mgr, audio_mask);
0930     if (err)
0931         return err;
0932 
0933     i = 0;
0934     while (1) {
0935         state = pcxhr_pipes_running(mgr);
0936         /* have all pipes the new state ? */
0937         if ((state & audio_mask) == (start ? audio_mask : 0))
0938             break;
0939         if (++i >= MAX_WAIT_FOR_DSP * 100) {
0940             dev_err(&mgr->pci->dev, "error pipe start/stop\n");
0941             return -EBUSY;
0942         }
0943         udelay(10);         /* wait 10 microseconds */
0944     }
0945     if (!start) {
0946         err = pcxhr_stop_pipes(mgr, audio_mask);
0947         if (err)
0948             return err;
0949     }
0950 #ifdef CONFIG_SND_DEBUG_VERBOSE
0951     stop_time = ktime_get();
0952     diff_time = ktime_sub(stop_time, start_time);
0953     dev_dbg(&mgr->pci->dev, "***SET PIPE STATE*** TIME = %ld (err = %x)\n",
0954             (long)(ktime_to_ns(diff_time)), err);
0955 #endif
0956     return 0;
0957 }
0958 
0959 int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask,
0960                 unsigned int value, int *changed)
0961 {
0962     struct pcxhr_rmh rmh;
0963     int err;
0964 
0965     mutex_lock(&mgr->msg_lock);
0966     if ((mgr->io_num_reg_cont & mask) == value) {
0967         dev_dbg(&mgr->pci->dev,
0968             "IO_NUM_REG_CONT mask %x already is set to %x\n",
0969                 mask, value);
0970         if (changed)
0971             *changed = 0;
0972         mutex_unlock(&mgr->msg_lock);
0973         return 0;   /* already programmed */
0974     }
0975     pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);
0976     rmh.cmd[0] |= IO_NUM_REG_CONT;
0977     rmh.cmd[1]  = mask;
0978     rmh.cmd[2]  = value;
0979     rmh.cmd_len = 3;
0980     err = pcxhr_send_msg_nolock(mgr, &rmh);
0981     if (err == 0) {
0982         mgr->io_num_reg_cont &= ~mask;
0983         mgr->io_num_reg_cont |= value;
0984         if (changed)
0985             *changed = 1;
0986     }
0987     mutex_unlock(&mgr->msg_lock);
0988     return err;
0989 }
0990 
0991 #define PCXHR_IRQ_TIMER     0x000300
0992 #define PCXHR_IRQ_FREQ_CHANGE   0x000800
0993 #define PCXHR_IRQ_TIME_CODE 0x001000
0994 #define PCXHR_IRQ_NOTIFY    0x002000
0995 #define PCXHR_IRQ_ASYNC     0x008000
0996 #define PCXHR_IRQ_MASK      0x00bb00
0997 #define PCXHR_FATAL_DSP_ERR 0xff0000
0998 
0999 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 const char * const err_src_name[] = {
1010         [PCXHR_ERR_PIPE]    = "Pipe",
1011         [PCXHR_ERR_STREAM]  = "Stream",
1012         [PCXHR_ERR_AUDIO]   = "Audio"
1013     };
1014 
1015     if (err & 0xfff)
1016         err &= 0xfff;
1017     else
1018         err = ((err >> 12) & 0xfff);
1019     if (!err)
1020         return 0;
1021     dev_dbg(&mgr->pci->dev, "CMD_ASYNC : Error %s %s Pipe %d err=%x\n",
1022             err_src_name[err_src],
1023             is_capture ? "Record" : "Play", pipe, err);
1024     if (err == 0xe01)
1025         mgr->async_err_stream_xrun++;
1026     else if (err == 0xe10)
1027         mgr->async_err_pipe_xrun++;
1028     else
1029         mgr->async_err_other_last = (int)err;
1030     return 1;
1031 }
1032 
1033 
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 }