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