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