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