0001
0002
0003
0004
0005
0006
0007
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
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
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
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
0064
0065
0066 #define PCXHR_MBOX0_HF5 (1 << 0)
0067 #define PCXHR_MBOX0_HF4 (1 << 1)
0068 #define PCXHR_MBOX0_BOOT_HERE (1 << 23)
0069
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
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
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
0089 #define PCXHR_CVR_HI08_HC 0x80
0090
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
0100 #define PCXHR_WAIT_DEFAULT 2
0101 #define PCXHR_WAIT_IT 25
0102 #define PCXHR_WAIT_IT_EXTRA 65
0103
0104
0105
0106
0107
0108
0109
0110
0111
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
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
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
0204 err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_CVR, PCXHR_CVR_HI08_HC, 0,
0205 PCXHR_TIMEOUT_DSP, ®);
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
0212 err = pcxhr_check_reg_bit(mgr, PCXHR_PLX_MBOX0,
0213 PCXHR_MBOX0_HF5,
0214 PCXHR_MBOX0_HF5,
0215 PCXHR_TIMEOUT_DSP,
0216 ®);
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;
0224 }
0225
0226 void pcxhr_reset_xilinx_com(struct pcxhr_mgr *mgr)
0227 {
0228
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
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
0247 pcxhr_enable_irq(mgr, 0);
0248
0249
0250 PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, 0);
0251 msleep( PCXHR_WAIT_DEFAULT );
0252 PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, 3);
0253 msleep( PCXHR_WAIT_DEFAULT );
0254
0255
0256 PCXHR_OUTPL(mgr, PCXHR_PLX_MBOX0, 0);
0257 }
0258
0259 void pcxhr_enable_dsp(struct pcxhr_mgr *mgr)
0260 {
0261
0262 pcxhr_enable_irq(mgr, 1);
0263 }
0264
0265
0266
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
0278 chipsc = PCXHR_INPL(mgr, PCXHR_PLX_CHIPSC);
0279
0280
0281
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
0289 chipsc |= PCXHR_CHIPSC_RESET_XILINX;
0290 PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC, chipsc);
0291 msleep( PCXHR_WAIT_DEFAULT );
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
0308 cond_resched();
0309 }
0310 chipsc &= ~(PCXHR_CHIPSC_DATA_CLK | PCXHR_CHIPSC_DATA_IN);
0311 PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC, chipsc);
0312
0313 msleep( PCXHR_WAIT_DEFAULT );
0314 return 0;
0315 }
0316
0317
0318
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
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
0335 for (i = 0; i < dsp->size; i += 3) {
0336 data = dsp->data + i;
0337 if (i == 0) {
0338
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
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
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
0361 cond_resched();
0362 }
0363
0364 msleep(PCXHR_WAIT_DEFAULT);
0365 return 0;
0366 }
0367
0368
0369
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
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
0381
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
0396 return pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK,
0397 PCXHR_ISR_HI08_CHK, PCXHR_TIMEOUT_DSP, ®);
0398 }
0399
0400
0401
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
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
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
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
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
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;
0455 u16 st_length;
0456 u16 st_type;
0457 };
0458
0459
0460 enum {
0461 RMH_SSIZE_FIXED = 0,
0462 RMH_SSIZE_ARG = 1,
0463 RMH_SSIZE_MASK = 2,
0464 };
0465
0466
0467
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
0547 err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
0548 PCXHR_ISR_HI08_RXDF,
0549 PCXHR_ISR_HI08_RXDF,
0550 PCXHR_TIMEOUT_DSP, ®);
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
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
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
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
0611 err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK,
0612 PCXHR_ISR_HI08_CHK, PCXHR_TIMEOUT_DSP, ®);
0613 if (err)
0614 return err;
0615
0616 err = pcxhr_send_it_dsp(mgr, PCXHR_IT_RESET_CHK, 1);
0617 if (err)
0618 return err;
0619
0620 err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK, 0,
0621 PCXHR_TIMEOUT_DSP, ®);
0622 if (err)
0623 return err;
0624
0625 data = rmh->cmd[0];
0626
0627 if (rmh->cmd_len > 1)
0628 data |= 0x008000;
0629 else
0630 data &= 0xff7fff;
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, ®);
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
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, ®);
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
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, ®);
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
0678 err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK,
0679 PCXHR_ISR_HI08_CHK, PCXHR_TIMEOUT_DSP, ®);
0680 if (err)
0681 return err;
0682
0683 if (reg & PCXHR_ISR_HI08_ERR) {
0684
0685 err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
0686 PCXHR_ISR_HI08_RXDF,
0687 PCXHR_ISR_HI08_RXDF,
0688 PCXHR_TIMEOUT_DSP, ®);
0689 if (err) {
0690 dev_err(&mgr->pci->dev,
0691 "ERROR RMH: ISR:RXDF=1 (ISR = %x)\n", reg);
0692 return err;
0693 }
0694
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
0703 err = pcxhr_read_rmh_status(mgr, rmh);
0704 }
0705
0706 if (pcxhr_send_it_dsp(mgr, PCXHR_IT_RESET_SEMAPHORE, 1) < 0)
0707 return -EIO;
0708 return err;
0709 }
0710
0711
0712
0713
0714
0715
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;
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
0751
0752
0753
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
0769
0770
0771
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
0794 pcxhr_set_pipe_cmd_params(&rmh, 0, audio, 0, 0);
0795 } else {
0796
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
0810
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
0832 pcxhr_set_pipe_cmd_params(&rmh, 0, audio, 0, 0);
0833 } else {
0834
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
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
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
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;
0921 mdelay(1);
0922 }
0923 } else {
0924 audio_mask &= state;
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
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);
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;
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
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;
1062
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) {
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
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
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
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
1173
1174
1175
1176 new_sample_count -= mgr->granularity;
1177 stream->timer_is_synced = 1;
1178 }
1179 }
1180 }
1181 if (!hardware_read) {
1182
1183
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
1226 return IRQ_NONE;
1227 }
1228
1229
1230 reg = PCXHR_INPL(mgr, PCXHR_PLX_L2PCIDB);
1231 PCXHR_OUTPL(mgr, PCXHR_PLX_L2PCIDB, reg);
1232
1233
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
1247 if (reg & PCXHR_IRQ_MASK) {
1248 if (reg & PCXHR_IRQ_ASYNC) {
1249
1250
1251
1252
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
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
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 }