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