1 /* 2 Copyright 1999, Be Incorporated. All Rights Reserved. 3 This file may be used under the terms of the Be Sample Code License. 4 */ 5 #include <string.h> 6 7 #include <ByteOrder.h> 8 #include <MediaDefs.h> 9 10 #include "cm_private.h" 11 #include "sound.h" 12 13 #include <KernelExport.h> 14 15 extern int sprintf(char *, const char *, ...); 16 17 18 extern void dump_card(cmedia_pci_dev * card); 19 20 // Buffer header for audio server from BeOS R3 MediaDefs.h 21 22 typedef struct audio_buffer_header { 23 int32 buffer_number; 24 int32 subscriber_count; 25 bigtime_t time; 26 int32 reserved_1; 27 int32 reserved_2; 28 bigtime_t sample_clock; 29 } audio_buffer_header; 30 31 #if !defined(OLDAPI) 32 #if DEBUG 33 #define OLDAPI(x) dprintf x 34 #else 35 #define OLDAPI(x) 36 #endif 37 #endif 38 39 #if DEBUG 40 int32 int_cnt; 41 int32 put_cnt; 42 bigtime_t the_time; 43 #endif 44 45 #if 0 46 /* early Intel kernels forgot to export these functions */ 47 #undef B_HOST_TO_LENDIAN_FLOAT 48 #undef B_HOST_TO_BENDIAN_FLOAT 49 #undef B_LENDIAN_TO_HOST_FLOAT 50 #undef B_BENDIAN_TO_HOST_FLOAT 51 52 static float 53 _swap_float_(float x) 54 { 55 uint32 temp1 = *(uint32*)&x; 56 uint32 temp2 = ((temp1>>24)|((temp1>>8)&0xff00)|((temp1<<8)&0xff0000)| 57 (temp1<<24)); 58 return *(float *)&temp2; 59 } 60 61 #if B_HOST_IS_BENDIAN 62 #define B_HOST_TO_LENDIAN_FLOAT(x) _swap_float_(x) 63 #define B_HOST_TO_BENDIAN_FLOAT(x) ((float)(x)) 64 #define B_LENDIAN_TO_HOST_FLOAT(x) _swap_float_(x) 65 #define B_BENDIAN_TO_HOST_FLOAT(x) ((float)(x)) 66 #else 67 #define B_HOST_TO_LENDIAN_FLOAT(x) ((float)(x)) 68 #define B_HOST_TO_BENDIAN_FLOAT(x) _swap_float_(x) 69 #define B_LENDIAN_TO_HOST_FLOAT(x) ((float)(x)) 70 #define B_BENDIAN_TO_HOST_FLOAT(x) _swap_float_(x) 71 #endif 72 73 #endif 74 75 76 static status_t pcm_open(const char *name, uint32 flags, void **cookie); 77 static status_t pcm_close(void *cookie); 78 static status_t pcm_free(void *cookie); 79 static status_t pcm_control(void *cookie, uint32 op, void *data, size_t len); 80 static status_t pcm_read(void *cookie, off_t pos, void *data, size_t *len); 81 static status_t pcm_write(void *cookie, off_t pos, const void *data, size_t *len); 82 //static status_t pcm_writev(void *cookie, off_t pos, const iovec *vec, size_t count, size_t *len); /* */ 83 84 device_hooks pcm_hooks = { 85 &pcm_open, 86 &pcm_close, 87 &pcm_free, 88 &pcm_control, 89 &pcm_read, 90 &pcm_write, 91 NULL, /* select */ 92 NULL, /* deselect */ 93 NULL, /* readv */ 94 NULL // &pcm_writev /* writev */ 95 }; 96 97 static pcm_cfg default_pcm = { 98 44100.0, /* sample rate */ 99 2, /* channels */ 100 0x2, /* format */ 101 #if B_HOST_IS_BENDIAN 102 1, /* endian (big) */ 103 #else 104 0, /* endian (little) */ 105 #endif 106 0, /* header size */ 107 PLAYBACK_BUF_SIZE, /* these are currently hard-coded */ 108 RECORD_BUF_SIZE /* and cannot be changed without re-compile */ 109 }; 110 111 112 #if 0 113 114 typedef struct { 115 uint8 control; 116 uint8 imask; 117 uint8 regs[0x2e]; 118 } chip_state; 119 120 static void 121 save_state( 122 pcm_dev * port, 123 chip_state * state) 124 { 125 int ix; 126 state->control = get_direct(port->card, 0); 127 state->imask = get_direct(port->card, 1); 128 for (ix=0; ix<0x0e; ix++) { 129 if (ix != 0x28 && ix != 0x29 && ix != 0x1a && ix != 0x1b) { 130 state->regs[ix] = get_indirect(port->card, ix+0x30); 131 } 132 } 133 } 134 135 136 static void 137 restore_state( 138 pcm_dev * port, 139 const chip_state * state) 140 { 141 int ix; 142 set_direct(port->card, 0, state->control, 0xff); 143 for (ix=0; ix<0x0e; ix++) { 144 if (ix != 0x28 && ix != 0x29 && ix != 0x1a && ix != 0x1b) { 145 set_indirect(port->card, ix, state->regs[ix]+0x30, 0xff); 146 } 147 } 148 set_direct(port->card, 1, state->imask, 0xff); 149 } 150 151 152 static void 153 reset_chip( 154 pcm_dev * port) 155 { 156 set_direct(port->card, 0x1b, 0x40, 0x40); 157 snooze(2); 158 set_direct(port->card, 0x1b, 0x00, 0x40); 159 } 160 161 #endif 162 163 164 static void 165 stop_dma( 166 pcm_dev * port) 167 { 168 set_direct(port->card, 0x24, 0x40, 0x40); // mute wave stream 169 set_direct(port->card, 0x02, 0, 0x03); // stop both ch0 and ch1 170 171 set_direct(port->card, 0x02, 0x0c, 0x0c); // reset both ch0 and ch1 172 set_direct(port->card, 0x02, 0, 0x0c); 173 ddprintf(("cmedia_pci: DMA stopped\n")); 174 } 175 176 177 static void 178 start_dma( 179 pcm_dev * port) 180 { 181 int sample_size = 1; 182 183 /* start out with a clean slate */ 184 185 KTRACE(); 186 ddprintf(("cmedia_pci: start_dma()\n")); 187 if (port->config.format == 0x11) { 188 memset((void*)port->card->low_mem, 0x80, port->config.play_buf_size + 189 port->config.rec_buf_size); 190 } 191 else { 192 memset((void *)port->card->low_mem, 0, port->config.play_buf_size + 193 port->config.rec_buf_size); 194 } 195 196 port->wr_cur = port->wr_2; 197 port->wr_silence = port->config.play_buf_size; 198 port->was_written = 0; 199 port->rd_cur = port->rd_2; 200 port->was_read = port->config.rec_buf_size/2; /* how much has been read */ 201 port->wr_total = 0; 202 port->rd_total = 0; 203 204 /* we split the available low memory buffer in a small chunk */ 205 /* for playback, and a large chunk for recording. Then we split */ 206 /* each of those in half for double-buffering. While the DMA */ 207 /* just runs the entire range of the buffer, wrapping around when */ 208 /* done, the count register is set up to generate interrupt after */ 209 /* each half of the buffer. Because of latency requirements, we */ 210 /* will get 187 interrupts a second from playback, and 94 interrupts */ 211 /* a second from recording, at 48 kHz sampling rate, when buffers */ 212 /* are 2048 for playback and 4096 for record. */ 213 214 ddprintf(("play_buf_size %lx rec_buf_size %lx\n", 215 port->config.play_buf_size/2, port->config.rec_buf_size/2)); 216 217 PCI_IO_WR(port->dma_c, ((uint32)port->card->low_phys+ 218 port->config.play_buf_size)&0xff); 219 PCI_IO_WR(port->dma_c+1, (((uint32)port->card->low_phys+ 220 port->config.play_buf_size)>>8)&0xff); 221 PCI_IO_WR(port->dma_c+2, (((uint32)port->card->low_phys+ 222 port->config.play_buf_size)>>16)&0xff); 223 PCI_IO_WR(port->dma_c+3, 0); 224 /* if this is a 16 bit channel, divide transfer count in 2 */ 225 if (port->config.format != 0x11) 226 sample_size *= 2; 227 /* if this is a stereo channel, divide transfer count in 2 */ 228 if (port->config.channels == 2) 229 sample_size *= 2; 230 PCI_IO_WR(port->dma_c+4, (port->config.rec_buf_size/sample_size-1)&0xff); 231 PCI_IO_WR(port->dma_c+5, ((port->config.rec_buf_size/sample_size-1)>>8)&0xff); 232 PCI_IO_WR(port->dma_c+6, (port->rd_size/sample_size-1)&0xff); 233 PCI_IO_WR(port->dma_c+7, ((port->rd_size/sample_size-1)>>8)&0xff); 234 235 PCI_IO_WR(port->dma_a, ((uint32)port->card->low_phys)&0xff); 236 PCI_IO_WR(port->dma_a+1, ((uint32)port->card->low_phys>>8)&0xff); 237 PCI_IO_WR(port->dma_a+2, ((uint32)port->card->low_phys>>16)&0xff); 238 PCI_IO_WR(port->dma_a+3, 0); 239 PCI_IO_WR(port->dma_a+4, (port->config.play_buf_size/sample_size-1)&0xff); 240 PCI_IO_WR(port->dma_a+5, ((port->config.play_buf_size/sample_size-1)>>8)&0xff); 241 PCI_IO_WR(port->dma_a+6, (port->wr_size/sample_size-1)&0xff); 242 PCI_IO_WR(port->dma_a+7, ((port->wr_size/sample_size-1)>>8)&0xff); 243 244 /* here, we should mute the PCM output to avoid clicking */ 245 246 ddprintf(("cmedia_pci: DMA starts as %lx/%lx\n", port->config.format, port->open_mode)); 247 set_direct(port->card, 0x24, 0x00, 0x40); 248 249 /* enable ch0 as play, and ch1 as record */ 250 set_direct(port->card, 0, 0x02, 0x03); 251 set_direct(port->card, 0x02, 0x03, 0x03); 252 253 /* here, we should snooze for 16 samples' time, then un-mute the PCM output */ 254 KTRACE(); 255 } 256 257 258 static status_t 259 configure_pcm( 260 pcm_dev * port, 261 pcm_cfg * config, 262 bool force) 263 { 264 status_t err = B_OK; 265 int m = 0, n = 0, r = 0; /* parameters for the PLL sample rate synthesizer */ 266 int asr = -1; /* alternate sample rate divisor */ 267 uint32 s; /* size of buffer */ 268 269 ddprintf(("cmedia_pci: configure_pcm()\n")); 270 271 /* check args */ 272 if (config->sample_rate < 4000.0) { 273 config->sample_rate = default_pcm.sample_rate; 274 } 275 if (config->sample_rate > 48000.0) { 276 config->sample_rate = 48000.0; 277 } 278 if (config->channels < 1) { 279 config->channels = default_pcm.channels; 280 } 281 if (config->channels > 2) { 282 config->channels = default_pcm.channels; 283 } 284 /* secret format of format: upper nybble = signed, unsigned, float */ 285 /* lower nybble = bytes per sample */ 286 if ((config->format != 0x11) && (config->format != 0x2) && 287 (config->format != 0x24) && (config->format != 0x4)) { 288 config->format = default_pcm.format; 289 } 290 if (config->buf_header < 0) { 291 config->buf_header = 0; 292 } 293 294 /* figure out buffer size that's a power of two and within size limits */ 295 if (!config->play_buf_size) { 296 /* default is 256 samples for a comfy 6 ms latency */ 297 s = 256*config->channels*(config->format&0xf); 298 } /* minimum is 32 samples for a more extreme 0.75ms latency */ 299 else for (s = 32*config->channels*(config->format&0xf); s < MIN_MEMORY_SIZE/2; s = (s<<1)) { 300 if (s >= config->play_buf_size) { 301 break; 302 } 303 } 304 config->play_buf_size = s; 305 if (!config->rec_buf_size) { 306 s = 256*config->channels*(config->format&0xf); 307 } 308 else for (s = 32*config->channels*(config->format&0xf); s < MIN_MEMORY_SIZE/2; s = (s<<1)) { 309 if (s >= config->rec_buf_size) { 310 break; 311 } 312 } 313 config->rec_buf_size = s; 314 315 /* calculate m, n and r (and asr) */ 316 317 if (!force && abs(config->sample_rate - port->config.sample_rate) < config->sample_rate/250) { 318 n = -1; 319 } 320 else if (config->sample_rate == 48000.0) { 321 asr = 7; 322 } 323 else if (config->sample_rate == 32000.0) { 324 asr = 6; 325 } 326 else if (config->sample_rate == 16000.0) { 327 asr = 5; 328 } 329 else if (config->sample_rate == 8000.0) { 330 asr = 4; 331 } 332 else if (config->sample_rate == 44100.0) { 333 asr = 3; 334 } 335 else if (config->sample_rate == 22050.0) { 336 asr = 2; 337 } 338 else if (config->sample_rate == 11025.0) { 339 asr = 1; 340 } 341 else { 342 float freq; 343 float delta = 1000000.0; 344 int sr = -1; 345 int sn = -1; 346 int sm = -1; 347 float diff; 348 349 for (r=0; r<8; r++) { 350 if ((1<<r)*config->sample_rate*512 < MIN_FREQ) { 351 continue; 352 } 353 break; 354 } 355 if (r == 8) { 356 OLDAPI(("cmedia_pci: r value is 8!\n")); 357 r = 7; 358 } 359 n = 0; 360 do { 361 n++; 362 m = config->sample_rate*512/1000*(n+2)*(1<<r)/(F_REF/1000)-2; 363 if (m < 1) { 364 continue; 365 } 366 if (m > 255) { 367 ddprintf(("cmedia_pci: m > 255; outahere\n")); 368 break; 369 } 370 freq = (m+2)*(F_REF/1000)/(512*(n+2)*(1<<r)/1000); 371 diff = freq-config->sample_rate; 372 if (diff < 0) { 373 diff = -diff; 374 } 375 if (diff < delta) { 376 sr = r; 377 sn = n; 378 sm = m; 379 } 380 } while (n < 31); 381 r = sr; 382 n = sn; 383 m = sm; 384 ddprintf(("cmedia_pci: m = %d r = %d n = %d\n", m, r, n)); 385 } 386 387 /* configure device */ 388 389 if (!force) { 390 stop_dma(port); 391 /* should mute PCM out, too */ 392 } 393 if (asr > -1 || n > -1) { /* new sampling rate */ 394 if (asr > -1) { 395 port->config.sample_rate = config->sample_rate; 396 set_direct(port->card, 0x05, (asr<<5)|(asr<<2), 0xfc); 397 } 398 else { 399 port->config.sample_rate = ((float)m+2.0)*(F_REF/1000.0)/ 400 (0.512*(n+2.0)*(1<<r)); 401 config->sample_rate = port->config.sample_rate; 402 #if 1 403 /* not exact the frequency supported */ 404 #else 405 set_indirect(port->card, 0x24, m, 0xff); 406 set_indirect(port->card, 0x25, (r<<5)|n, 0xff); 407 set_indirect(port->card, 0x22, 0x00, 0xff); 408 #endif 409 } 410 } 411 if (force || config->channels != port->config.channels || 412 config->format != port->config.format) { 413 uchar val = 0; 414 if (config->channels == 2) { 415 val |= 0x01; /* stereo */ 416 } 417 if (config->format != 0x11) { 418 val |= 0x02; /* 16 bits */ 419 } 420 set_direct(port->card, 0x08, (val<<2)|val, 0x0f); /* MCE -- may take time to take effect */ 421 port->config.channels = config->channels; 422 port->config.format = config->format; 423 } 424 if (force || config->big_endian != port->config.big_endian) { 425 port->config.big_endian = config->big_endian; 426 } 427 if (force || config->buf_header != port->config.buf_header) { 428 port->config.buf_header = config->buf_header; 429 } 430 if (force || config->play_buf_size != port->config.play_buf_size*2) { 431 port->config.play_buf_size = config->play_buf_size*2; /* because we break it in two */ 432 } 433 if (force || config->rec_buf_size != port->config.rec_buf_size*2) { 434 port->config.rec_buf_size = config->rec_buf_size*2; /* because we break it in two */ 435 } 436 437 /* here is where we should care about record and playback buffer sizes */ 438 439 ddprintf(("cmedia_pci: play %04lx rec %04lx\n", port->config.play_buf_size/2, 440 port->config.rec_buf_size/2)); 441 442 port->wr_1 = port->card->low_mem; 443 port->wr_2 = port->wr_1+port->config.play_buf_size/2; 444 port->wr_size = port->config.play_buf_size/2; 445 446 port->rd_1 = port->card->low_mem+port->config.play_buf_size; 447 port->rd_2 = port->rd_1+port->config.rec_buf_size/2; 448 port->rd_size = port->config.rec_buf_size/2; 449 450 if (!force) { 451 /* should un-mute PCM out, if we muted it */ 452 start_dma(port); 453 } 454 return err; 455 } 456 457 458 static status_t 459 pcm_open( 460 const char * name, 461 uint32 flags, 462 void ** cookie) 463 { 464 int ix; 465 pcm_dev * port = NULL; 466 char name_buf[256]; 467 int32 prev_mode; 468 469 ddprintf(("cmedia_pci: pcm_open()\n")); 470 471 *cookie = NULL; 472 for (ix=0; ix<num_cards; ix++) { 473 if (!strcmp(name, cards[ix].pcm.name)) { 474 goto gotit; 475 } 476 } 477 for (ix=0; ix<num_cards; ix++) { 478 if (!strcmp(name, cards[ix].pcm.oldname)) { 479 goto gotit; 480 } 481 } 482 ddprintf(("cmedia_pci: %s not found\n", name)); 483 return ENODEV; 484 485 gotit: 486 *cookie = port = &cards[ix].pcm; 487 488 acquire_sem(port->init_sem); 489 490 prev_mode = port->open_mode; 491 if ((flags & 3) == O_RDONLY) { 492 atomic_or(&port->open_mode, kRecord); 493 } 494 else if ((flags & 3) == O_WRONLY) { 495 atomic_or(&port->open_mode, kPlayback); 496 } 497 else { 498 atomic_or(&port->open_mode, kPlayback|kRecord); 499 } 500 501 if (atomic_add(&port->open_count, 1) == 0) { 502 503 /* initialize device first time */ 504 505 port->card = &cards[ix]; 506 port->config = default_pcm; 507 port->config.play_buf_size *= 2; 508 port->config.rec_buf_size *= 2; 509 510 /* playback */ 511 B_INITIALIZE_SPINLOCK(&port->wr_lock); 512 port->dma_a = cards[ix].dma_base; 513 port->wr_1 = cards[ix].low_mem; 514 port->wr_2 = cards[ix].low_mem+port->config.play_buf_size/2; 515 port->wr_size = port->config.play_buf_size/2; 516 port->write_waiting = 0; 517 sprintf(name_buf, "WS:%s", port->name); 518 name_buf[B_OS_NAME_LENGTH-1] = 0; 519 port->write_sem = create_sem(0, name_buf); 520 if (port->write_sem < B_OK) { 521 port->open_count = 0; 522 return port->write_sem; 523 } 524 set_sem_owner(port->write_sem, B_SYSTEM_TEAM); 525 name_buf[0] = 'W'; name_buf[1] = 'E'; 526 port->wr_entry = create_sem(1, name_buf); 527 if (port->wr_entry < B_OK) { 528 delete_sem(port->write_sem); 529 port->open_count = 0; 530 return port->wr_entry; 531 } 532 set_sem_owner(port->wr_entry, B_SYSTEM_TEAM); 533 name_buf[1] = 'T'; 534 port->wr_time_wait = 0; 535 port->wr_time_sem = create_sem(0, name_buf); 536 if (port->wr_time_sem < B_OK) { 537 delete_sem(port->write_sem); 538 delete_sem(port->wr_entry); 539 port->open_count = 0; 540 return port->wr_time_sem; 541 } 542 set_sem_owner(port->wr_time_sem, B_SYSTEM_TEAM); 543 544 /* recording */ 545 546 B_INITIALIZE_SPINLOCK(&port->rd_lock); 547 port->dma_c = cards[ix].dma_base+0x08; 548 port->rd_1 = cards[ix].low_mem+port->config.play_buf_size; 549 port->rd_2 = cards[ix].low_mem+port->config.play_buf_size+port->config.rec_buf_size/2; 550 port->rd_size = port->config.rec_buf_size/2; 551 port->read_waiting = 0; 552 name_buf[0] = 'R'; name_buf[1] = 'S'; 553 port->read_sem = create_sem(0, name_buf); 554 if (port->read_sem < B_OK) { 555 delete_sem(port->write_sem); 556 delete_sem(port->wr_entry); 557 delete_sem(port->wr_time_sem); 558 port->open_count = 0; 559 return port->read_sem; 560 } 561 set_sem_owner(port->read_sem, B_SYSTEM_TEAM); 562 name_buf[0] = 'R'; name_buf[1] = 'E'; 563 port->rd_entry = create_sem(1, name_buf); 564 if (port->rd_entry < B_OK) { 565 delete_sem(port->write_sem); 566 delete_sem(port->wr_entry); 567 delete_sem(port->read_sem); 568 delete_sem(port->wr_time_sem); 569 port->open_count = 0; 570 return port->rd_entry; 571 } 572 set_sem_owner(port->rd_entry, B_SYSTEM_TEAM); 573 name_buf[1] = 'T'; 574 port->rd_time_wait = 0; 575 port->rd_time_sem = create_sem(0, name_buf); 576 if (port->rd_time_sem < B_OK) { 577 delete_sem(port->write_sem); 578 delete_sem(port->wr_entry); 579 delete_sem(port->read_sem); 580 delete_sem(port->wr_time_sem); 581 delete_sem(port->rd_entry); 582 port->open_count = 0; 583 return port->rd_time_sem; 584 } 585 set_sem_owner(port->rd_time_sem, B_SYSTEM_TEAM); 586 587 port->rd_time = 0; 588 port->next_rd_time = 0; 589 port->wr_time = 0; 590 591 /* old API */ 592 593 port->old_cap_sem = -1; 594 port->old_play_sem = -1; 595 596 /* configuration */ 597 598 configure_pcm(port, &default_pcm, true); 599 600 /* interrupts */ 601 KTRACE(); 602 increment_interrupt_handler(port->card); 603 604 set_direct(port->card, 0x0e, 0x03, 0x03); /* */ 605 start_dma(port); 606 607 /* initialization is done, let other clients of the driver go */ 608 } else { 609 if (prev_mode != port->open_mode) { 610 pcm_cfg temp = port->config; 611 temp.play_buf_size /= 2; 612 temp.rec_buf_size /= 2; 613 configure_pcm(port, &temp, false); /* change rec/play if needed */ 614 } 615 } 616 release_sem(port->init_sem); 617 618 #if DEBUG 619 dump_card(&cards[ix]); 620 #endif 621 622 return B_OK; 623 } 624 625 626 static status_t 627 pcm_close( 628 void * cookie) 629 { 630 pcm_dev * port = (pcm_dev *)cookie; 631 cpu_status cp; 632 int spin = 0; 633 634 ddprintf(("cmedia_pci: pcm_close()\n")); 635 636 acquire_sem(port->init_sem); 637 638 if (atomic_add(&port->open_count, -1) == 1) { 639 640 KTRACE(); 641 cp = disable_interrupts(); 642 acquire_spinlock(&port->card->hardware); 643 644 /* turn off interrupts */ 645 stop_dma(port); 646 set_direct(port->card, 0x0e, 0x00, 0x03); /* */ 647 648 if (port->config.format == 0x11) { 649 memset((void *)port->wr_1, 0x80, port->config.play_buf_size); /* play silence */ 650 } 651 else { 652 memset((void *)port->wr_1, 0, port->config.play_buf_size); /* play silence */ 653 } 654 spin = 1; 655 656 release_spinlock(&port->card->hardware); 657 restore_interrupts(cp); 658 659 delete_sem(port->write_sem); 660 delete_sem(port->read_sem); 661 delete_sem(port->wr_entry); 662 delete_sem(port->rd_entry); 663 delete_sem(port->rd_time_sem); 664 delete_sem(port->wr_time_sem); 665 port->write_sem = -1; 666 port->read_sem = -1; 667 port->wr_entry = -1; 668 port->rd_entry = -1; 669 port->rd_time_sem = -1; 670 port->wr_time_sem = -1; 671 } 672 release_sem(port->init_sem); 673 674 if (spin) { 675 /* wait so we know FIFO gets filled with silence */ 676 snooze(port->config.play_buf_size*1000/(port->config.sample_rate* 677 (port->config.format&0xf)*port->config.channels/1000)); 678 } 679 return B_OK; 680 } 681 682 683 static status_t 684 pcm_free( 685 void * cookie) 686 { 687 cpu_status cp; 688 pcm_dev * port = (pcm_dev *)cookie; 689 690 ddprintf(("cmedia_pci: pcm_free()\n")); 691 692 acquire_sem(port->init_sem); 693 694 if (((pcm_dev *)cookie)->open_count == 0) { 695 696 /* the last free will actually stop everything */ 697 698 KTRACE(); 699 cp = disable_interrupts(); 700 acquire_spinlock(&port->card->hardware); 701 702 decrement_interrupt_handler(port->card); 703 704 release_spinlock(&port->card->hardware); 705 restore_interrupts(cp); 706 } 707 release_sem(port->init_sem); 708 709 return B_OK; 710 } 711 712 713 static status_t 714 pcm_control( 715 void * cookie, 716 uint32 iop, 717 void * data, 718 size_t len) 719 { 720 // declarations for SPDIF settings I/O 721 static int32 chipinfo[] = { 0,0 }; 722 uchar reg_value; 723 char DriverVersion[] = "1.3.2 (Jul 17, 2001)"; 724 725 pcm_dev * port = (pcm_dev *)cookie; 726 status_t err = B_BAD_VALUE; 727 pcm_cfg config = port->config; 728 static float rates[7] = { 48000.0, 44100.0, 32000.0, 22050.0, 16000.0, 11025.0, 8000.0 }; 729 bool configure = false; 730 config.play_buf_size /= 2; 731 config.rec_buf_size /= 2; 732 733 ddprintf(("cmedia_pci: pcm_control()\n")); 734 735 switch (iop) { 736 case B_AUDIO_GET_AUDIO_FORMAT: 737 memcpy(data, &config, sizeof(port->config)); 738 err = B_OK; 739 break; 740 case B_AUDIO_GET_PREFERRED_SAMPLE_RATES: 741 memcpy(data, rates, sizeof(rates)); 742 err = B_OK; 743 break; 744 case B_AUDIO_SET_AUDIO_FORMAT: 745 memcpy(&config, data, sizeof(config)); 746 configure = true; 747 err = B_OK; 748 break; 749 case SV_RD_TIME_WAIT: 750 atomic_add(&port->rd_time_wait, 1); 751 err = acquire_sem(port->rd_time_sem); 752 if (err >= B_OK) { 753 cpu_status cp; 754 KTRACE(); 755 cp = disable_interrupts(); 756 acquire_spinlock(&port->rd_lock); 757 ((sv_timing *)data)->time = port->rd_time; 758 ((sv_timing *)data)->bytes = port->rd_total; 759 ((sv_timing *)data)->skipped = port->rd_skipped; 760 ((sv_timing *)data)->_reserved_[0] = 0xffffffffUL; 761 release_spinlock(&port->rd_lock); 762 restore_interrupts(cp); 763 } 764 break; 765 case SV_WR_TIME_WAIT: 766 atomic_add(&port->wr_time_wait, 1); 767 err = acquire_sem(port->wr_time_sem); 768 if (err >= B_OK) { 769 cpu_status cp; 770 KTRACE(); 771 cp = disable_interrupts(); 772 acquire_spinlock(&port->wr_lock); 773 ((sv_timing *)data)->time = port->wr_time; 774 ((sv_timing *)data)->bytes = port->wr_total; 775 ((sv_timing *)data)->skipped = port->wr_skipped; 776 ((sv_timing *)data)->_reserved_[0] = 0xffffffffUL; 777 release_spinlock(&port->wr_lock); 778 restore_interrupts(cp); 779 } 780 break; 781 case SV_SECRET_HANDSHAKE: { 782 cpu_status cp; 783 KTRACE(); 784 cp = disable_interrupts(); 785 acquire_spinlock(&port->wr_lock); 786 acquire_spinlock(&port->rd_lock); 787 ((sv_handshake *)data)->wr_time = port->wr_time; 788 ((sv_handshake *)data)->wr_skipped = port->wr_skipped; 789 ((sv_handshake *)data)->rd_time = port->rd_time; 790 ((sv_handshake *)data)->rd_skipped = port->rd_skipped; 791 ((sv_handshake *)data)->wr_total = port->wr_total; 792 ((sv_handshake *)data)->rd_total = port->rd_total; 793 ((sv_handshake *)data)->_reserved_[0] = 0xffffffffUL; 794 err = B_OK; 795 release_spinlock(&port->rd_lock); 796 release_spinlock(&port->wr_lock); 797 restore_interrupts(cp); 798 } break; 799 case SOUND_GET_PARAMS: { 800 cpu_status cp; 801 uchar u; 802 sound_setup * sound = (sound_setup *)data; 803 err = B_OK; 804 cp = disable_interrupts(); 805 acquire_spinlock(&port->card->hardware); 806 /* Here we get to hard-code the mix/mux values. */ 807 /* Huh-huh; he said "hard-code"! */ 808 sound->sample_rate = kHz_44_1; 809 if (!port->config.big_endian == !B_HOST_IS_BENDIAN) { 810 sound->playback_format = linear_16bit_big_endian_stereo; 811 sound->capture_format = linear_16bit_big_endian_stereo; 812 } 813 else { 814 sound->playback_format = linear_16bit_little_endian_stereo; 815 sound->capture_format = linear_16bit_little_endian_stereo; 816 } 817 sound->dither_enable = false; 818 sound->loop_attn = 0; 819 sound->loop_enable = 0; 820 sound->output_boost = 0; 821 sound->highpass_enable = 0; 822 /* this is a master control on C-Media... */ 823 u = get_indirect(port->card, 0x30)>>2; 824 sound->mono_gain = u&63; 825 sound->mono_mute = 0; 826 827 /* left channel */ 828 u = get_indirect(port->card, 0x3d); // Legacy SB compatible Mixer 829 switch (u) 830 { 831 case 0x10: 832 sound->left.adc_source = line; // record line left 833 break; 834 835 case 4: 836 sound->left.adc_source = aux1; // record CD left ?? 837 break; 838 839 case 1: 840 sound->left.adc_source = mic; // record mic left 841 break; 842 843 default: 844 sound->left.adc_source = loopback; 845 break; 846 } 847 u = get_indirect(port->card, 0x3f)>>4; 848 sound->left.adc_gain = u&15; 849 850 u = get_direct(port->card, 0x25)<<4; 851 sound->left.mic_gain_enable = u&16; 852 853 u = get_indirect(port->card, 0x36)>>3; 854 sound->left.aux1_mix_gain = 31-(u&31); 855 856 u = get_indirect(port->card, 0x3c)<<5; 857 sound->left.aux1_mix_mute = ~u&128; 858 859 u = get_indirect(port->card, 0x34)>>3; 860 sound->left.aux2_mix_gain = 31-(u&31); 861 862 u = get_direct(port->card, 0x24); 863 sound->left.aux2_mix_mute = u&128; 864 865 u = get_indirect(port->card, 0x38)>>3; 866 sound->left.line_mix_gain = 31-(u&31); 867 868 u = get_indirect(port->card, 0x3c)<<3; 869 sound->left.line_mix_mute = ~u&128; 870 871 u = get_indirect(port->card, 0x32)>>2; 872 sound->left.dac_attn = 63-(u&63); 873 874 u = get_direct(port->card, 0x24)<<1; 875 sound->left.dac_mute = u&128; 876 877 /* right channel */ 878 u = get_indirect(port->card, 0x3e); 879 switch (u) 880 { 881 case 8: 882 sound->right.adc_source = line; //record line right 883 break; 884 885 case 2: 886 sound->right.adc_source = aux1; // record CD right? 887 break; 888 889 case 1: 890 sound->right.adc_source = mic; // record mic right 891 break; 892 893 default: 894 sound->right.adc_source = loopback; 895 break; 896 } 897 u = get_indirect(port->card, 0x40)>>4; 898 sound->right.adc_gain = u&15; 899 sound->right.mic_gain_enable = sound->left.mic_gain_enable; 900 u = get_indirect(port->card, 0x37)>>3; 901 sound->right.aux1_mix_gain = 31-(u&31); 902 u = get_indirect(port->card, 0x3c)<<6; 903 sound->right.aux1_mix_mute = ~u&128; 904 u = get_indirect(port->card, 0x35)>>3; 905 sound->right.aux2_mix_gain = 31-(u&31); 906 u = get_direct(port->card, 0x24); 907 sound->right.aux2_mix_mute = u&128; 908 u = get_indirect(port->card, 0x39)>>3; 909 sound->right.line_mix_gain = 31-(u&31); 910 u = get_indirect(port->card, 0x3c)<<4; 911 sound->right.line_mix_mute = ~u&128; 912 u = get_indirect(port->card, 0x33)>>2; 913 sound->right.dac_attn = 63-(u&63); 914 u = get_direct(port->card, 0x24)<<1; 915 sound->right.dac_mute = u&128; 916 /* done */ 917 release_spinlock(&port->card->hardware); 918 restore_interrupts(cp); 919 } break; 920 case SOUND_SET_PARAMS: { 921 cpu_status cp; 922 uchar u; 923 sound_setup * sound = (sound_setup *)data; 924 err = B_OK; 925 cp = disable_interrupts(); 926 acquire_spinlock(&port->card->hardware); 927 /* Here we get to hard-code the mix/mux values. */ 928 /* Huh-huh; he said "hard-code"! */ 929 930 /* ignore sample rate */ 931 sound->sample_rate = kHz_44_1; 932 if (config.sample_rate < 43999 || config.sample_rate > 44201) { 933 config.sample_rate = 44100.0; 934 configure = true; 935 } 936 /* we only support 16-bit formats */ 937 if (sound->playback_format == linear_16bit_big_endian_stereo && 938 sound->capture_format == linear_16bit_big_endian_stereo) { 939 if (!config.big_endian != !B_HOST_IS_BENDIAN || config.format != 0x2) { 940 config.big_endian = B_HOST_IS_BENDIAN; 941 config.format = 0x2; 942 configure = true; 943 } 944 OLDAPI(("same_endian\n")); 945 } 946 else if (sound->playback_format == linear_16bit_little_endian_stereo && 947 sound->capture_format == linear_16bit_little_endian_stereo) { 948 if (!config.big_endian != !!B_HOST_IS_BENDIAN || config.format != 0x2) { 949 config.big_endian = !B_HOST_IS_BENDIAN; 950 config.format = 0x2; 951 configure = true; 952 } 953 OLDAPI(("other_endian\n")); 954 } 955 else { 956 config.big_endian = !!B_HOST_IS_BENDIAN; 957 configure = true; 958 OLDAPI(("other format!!!\n")); 959 } 960 /* ignore these values */ 961 sound->dither_enable = false; 962 sound->loop_attn = 0; 963 sound->loop_enable = 0; 964 sound->output_boost = 0; 965 sound->highpass_enable = 0; 966 /* this is a stereo control on C-Media... */ 967 u = (sound->mono_gain>>1)&0x1f; 968 OLDAPI(("output: %x\n", u)); 969 set_indirect(port->card, 0x30, u<<3, 0xff); 970 set_indirect(port->card, 0x31, u<<3, 0xff); 971 /* left channel */ 972 switch (sound->left.adc_source) 973 { 974 case line: 975 u = 1<<4; 976 break; 977 case aux1: 978 u = 1<<2; 979 break; 980 case mic: 981 u = 1<<0; 982 break; 983 default: 984 u = 0x15; 985 break; 986 } 987 OLDAPI(("input: %x\n", u)); 988 set_indirect(port->card, 0x3d, u, 0xff); 989 u = (sound->left.adc_gain&15); 990 set_indirect(port->card, 0x3f, u<<4, 0xff); 991 u = sound->left.mic_gain_enable ? 0 : 0x01; 992 set_direct(port->card, 0x25, u, 0x01); 993 u = 31-(sound->left.aux1_mix_gain&31); 994 OLDAPI(("cd: %x\n", u)); 995 set_indirect(port->card, 0x36, u<<3, 0xff); 996 u = sound->left.aux1_mix_mute ? 0 : 0x04; 997 set_indirect(port->card, 0x3c, u, 0x04); 998 u = 31-(sound->left.aux2_mix_gain&31); 999 OLDAPI(("aux2: %x\n", u)); 1000 set_indirect(port->card, 0x34, u<<3, 0xff); 1001 u = sound->left.aux2_mix_mute ? 0x80 : 0; 1002 set_direct(port->card, 0x24, u, 0x80); 1003 u = 31-(sound->left.line_mix_gain&31); 1004 OLDAPI(("line: %x\n", u)); 1005 set_indirect(port->card, 0x38, u<<3, 0xff); 1006 u = sound->left.line_mix_mute ? 0 : 0x10; 1007 set_indirect(port->card, 0x3c, u, 0x10); 1008 u = 63-(sound->left.dac_attn & 63); 1009 OLDAPI(("PCM: %x\n", u)); 1010 set_indirect(port->card, 0x32, u<<2, 0xff); 1011 u = sound->left.dac_mute ? 0x40 : 0; 1012 set_direct(port->card, 0x24, u, 0x40); 1013 /* right channel */ 1014 switch (sound->right.adc_source) { 1015 case line: 1016 u = 1<<3; 1017 break; 1018 case aux1: 1019 u = 1<<1; 1020 break; 1021 case mic: 1022 u = 1<<0; 1023 break; 1024 default: 1025 u = 0x0a; 1026 break; 1027 } 1028 sound->right.mic_gain_enable = sound->left.mic_gain_enable; 1029 set_indirect(port->card, 0x3e, u, 0xff); 1030 u = (sound->right.adc_gain&15); 1031 set_indirect(port->card, 0x40, u<<4, 0xff); 1032 u = sound->right.mic_gain_enable ? 0 : 0x01; 1033 set_direct(port->card, 0x25, u, 0x01); 1034 u = 31-(sound->right.aux1_mix_gain&31); 1035 set_indirect(port->card, 0x37, u<<3, 0xff); 1036 u = sound->right.aux1_mix_mute ? 0 : 0x02; 1037 set_indirect(port->card, 0x3c, u, 0x02); 1038 u = 31-(sound->right.aux2_mix_gain&31); 1039 set_indirect(port->card, 0x35, u<<3, 0xff); 1040 u = sound->right.aux2_mix_mute ? 0x80 : 0; 1041 set_direct(port->card, 0x24, u, 0x80); 1042 u = 31-(sound->right.line_mix_gain&31); 1043 set_indirect(port->card, 0x39, u<<3, 0xff); 1044 u = sound->right.line_mix_mute ? 0 : 0x08; 1045 set_indirect(port->card, 0x3c, u, 0x08); 1046 u = 63-(sound->right.dac_attn & 63); 1047 set_indirect(port->card, 0x33, u<<2, 0xff); 1048 u = sound->right.dac_mute ? 0x40 : 0; 1049 set_direct(port->card, 0x24, u, 0x40); 1050 /* done */ 1051 release_spinlock(&port->card->hardware); 1052 restore_interrupts(cp); 1053 } break; 1054 case SOUND_SET_PLAYBACK_COMPLETION_SEM: 1055 port->old_play_sem = *(sem_id *)data; 1056 err = B_OK; 1057 break; 1058 case SOUND_SET_CAPTURE_COMPLETION_SEM: 1059 port->old_cap_sem = *(sem_id *)data; 1060 err = B_OK; 1061 break; 1062 // case SOUND_GET_PLAYBACK_TIMESTAMP: 1063 // break; 1064 // case SOUND_GET_CAPTURE_TIMESTAMP: 1065 // break; 1066 // case SOUND_DEBUG_ON: 1067 // break; 1068 // case SOUND_DEBUG_OFF: 1069 // break; 1070 case SOUND_UNSAFE_WRITE: { 1071 audio_buffer_header * buf = (audio_buffer_header *)data; 1072 size_t n = buf->reserved_1-sizeof(*buf); 1073 pcm_write(cookie, 0, buf+1, &n); 1074 buf->time = port->wr_time; 1075 buf->sample_clock = port->wr_total/4 * 10000 / 441; 1076 err = release_sem(port->old_play_sem); 1077 } break; 1078 case SOUND_UNSAFE_READ: { 1079 audio_buffer_header * buf = (audio_buffer_header *)data; 1080 size_t n = buf->reserved_1-sizeof(*buf); 1081 pcm_read(cookie, 0, buf+1, &n); 1082 buf->time = port->rd_time; 1083 buf->sample_clock = port->rd_total/4 * 10000 / 441; 1084 err = release_sem(port->old_cap_sem); 1085 } break; 1086 case SOUND_LOCK_FOR_DMA: 1087 err = B_OK; 1088 break; 1089 case SOUND_SET_PLAYBACK_PREFERRED_BUF_SIZE: 1090 config.play_buf_size = (int32)data; 1091 configure = true; 1092 err = B_OK; 1093 break; 1094 case SOUND_SET_CAPTURE_PREFERRED_BUF_SIZE: 1095 config.rec_buf_size = (int32)data; 1096 configure = true; 1097 err = B_OK; 1098 break; 1099 case SOUND_GET_PLAYBACK_PREFERRED_BUF_SIZE: 1100 *(int32*)data = config.play_buf_size; 1101 err = B_OK; 1102 break; 1103 case SOUND_GET_CAPTURE_PREFERRED_BUF_SIZE: 1104 *(int32*)data = config.rec_buf_size; 1105 err = B_OK; 1106 break; 1107 1108 1109 // control ports for SPDIF settings 1110 case SOUND_GET_SPDIF_IN_OUT_LOOPBACK: 1111 *(int8 *)data = 0; 1112 reg_value = get_direct( port->card, 0x04 ); 1113 if( reg_value && 0x80 ) *(int8 *)data = 1; 1114 err = B_OK; 1115 break; 1116 1117 case SOUND_SET_SPDIF_IN_OUT_LOOPBACK: 1118 if( *(int8 *)data == 0 ) // disable SPDIF-IN loopback to SPDIF (bypass) 1119 set_direct( port->card, 0x04, 0x00, 0x80 ); 1120 else // enable SPDIF-IN loopback to SPDIF (bypass) 1121 set_direct( port->card, 0x04, 0x80, 0x80 ); 1122 err = B_OK; 1123 break; 1124 1125 1126 1127 1128 case SOUND_GET_SPDIF_OUT: 1129 *(int8 *)data = 0; 1130 reg_value = get_direct( port->card, 0x16 ); // Adresse 0x16 1131 if( reg_value && 0x80 ) *(int8 *)data = 1; 1132 err = B_OK; 1133 break; 1134 1135 case SOUND_SET_SPDIF_OUT: 1136 if( *(int8 *)data == 0 ) // disable SPDIF-OUT 1137 set_direct( port->card, 0x16, 0x00, 0x80); 1138 else // enable SPDIF-OUT 1139 set_direct( port->card, 0x16, 0x80, 0x80 ); 1140 err = B_OK; 1141 break; 1142 1143 1144 1145 case SOUND_GET_SPDIF_MONITOR: 1146 *(int8 *)data = 0; 1147 reg_value = get_direct( port->card, 0x24 ); 1148 if( reg_value && 0x01 ) *(int8 *)data = 1; 1149 err = B_OK; 1150 break; 1151 1152 1153 case SOUND_SET_SPDIF_MONITOR: 1154 if( *(int8 *)data == 0 ) // disable SPDIF_IN PCM to DAC (CDPlay) 1155 set_direct( port->card, 0x24, 0x00, 0x01 ); 1156 else // enable SPDIF_IN PCM to DAC (CDPlay) 1157 set_direct( port->card, 0x24, 0x01, 0x01 ); 1158 err = B_OK; 1159 break; 1160 1161 case SOUND_GET_SPDIF_OUT_LEVEL: 1162 *(int8 *)data = 0; 1163 reg_value = get_direct( port->card, 0x1b ); 1164 if( reg_value && 0x02 ) *(int8 *)data = 1; 1165 err = B_OK; 1166 break; 1167 1168 case SOUND_SET_SPDIF_OUT_LEVEL: 1169 if( *(int8 *)data == 0 ) // enable SPDIF-OUT optical 1170 set_direct( port->card, 0x1b, 0x00, 0x02 ); 1171 else // enable SPDIF-OUT coaxial 1172 set_direct( port->card, 0x1b, 0x02, 0x02 ); 1173 break; 1174 1175 case SOUND_GET_SPDIF_IN_FORMAT: 1176 *(int8 *)data = 0; 1177 reg_value = get_direct( port->card, 0x08 ); // Adresse 0x08 1178 if( reg_value && 0x80 ) *(int8 *)data = 1; 1179 err = B_OK; 1180 break; 1181 1182 1183 case SOUND_SET_SPDIF_IN_FORMAT: 1184 if( *(int8 *)data == 0 ) // disable SPDIF inverse (SPDIF normal) 1185 set_direct( port->card, 0x08, 0x00, 0x80 ); 1186 else // enable SPDIF inverse 1187 set_direct( port->card, 0x08, 0x80, 0x80 ); // Adresse 0x08, Daten 0x80 1188 err = B_OK; 1189 break; 1190 1191 1192 case SOUND_GET_SPDIF_IN_OUT_COPYRIGHT: 1193 *(int8 *)data = 0; 1194 reg_value = get_direct( port->card, 0x16 ); 1195 if( reg_value && 0x40 ) *(int8 *)data = 1; 1196 err = B_OK; 1197 break; 1198 1199 case SOUND_SET_SPDIF_IN_OUT_COPYRIGHT: 1200 if( *(int8 *)data == 0 ) // disable SPDIF-IN/OUT copyright protection 1201 set_direct( port->card, 0x16, 0x00, 0x40 ); 1202 else // enable SPDIF-IN/OUT copyright protection 1203 set_direct( port->card, 0x16, 0x40, 0x40 ); 1204 err = B_OK; 1205 break; 1206 1207 case SOUND_GET_SPDIF_IN_VALIDITY: 1208 *(int8 *)data = 0; 1209 reg_value = get_direct( port->card, 0x27 ); 1210 if( reg_value && 0x02 ) *(int8 *)data = 1; 1211 err = B_OK; 1212 break; 1213 1214 case SOUND_SET_SPDIF_IN_VALIDITY: 1215 if( *(int8 *)data == 0 ) // disable SPDIF-IN validity detection 1216 set_direct( port->card, 0x27, 0x00, 0x02 ); 1217 else // enable SPDIF-IN validity detection 1218 set_direct( port->card, 0x27, 0x02, 0x02 ); 1219 err = B_OK; 1220 break; 1221 // control ports for analog settings 1222 1223 case SOUND_GET_4_CHANNEL_DUPLICATE: 1224 *(int8 *)data = 0; 1225 reg_value = get_direct( port->card, 0x1b ); 1226 if( reg_value && 0x04 ) *(int8 *)data = 1; 1227 1228 // 0x1b, 0x04, 0x04, /* dual channel mode enable */ 1229 // 0x1a, 0x00, 0x80, /* Double DAC structure disable */ 1230 1231 err = B_OK; 1232 break; 1233 1234 case SOUND_SET_4_CHANNEL_DUPLICATE: 1235 if( *(int8 *)data == 0 ) // disable 4 channel analog duplicate mode 1236 set_direct( port->card, 0x1b, 0x00, 0x04 ); 1237 else // enable 4 channel analog duplicate mode 1238 set_direct( port->card, 0x1b, 0x04, 0x04 ); 1239 err = B_OK; 1240 break; 1241 // control ports for additional info 1242 1243 case SOUND_GET_DEVICE_ID: 1244 // *(int32*)data.vendor_id = cards[0].info.vendor_id; 1245 // *(int32*)data.device_id = cards[0].info.device_id; 1246 1247 // chipinfo[0] = cards[0].info.vendor_id; 1248 *(int32 *)data = cards[0].info.device_id; 1249 1250 // memcpy(data, &chipinfo, sizeof(chipinfo)); 1251 err = B_OK; 1252 break; 1253 1254 case SOUND_GET_INTERNAL_CHIP_ID: 1255 // XXX 1256 break; 1257 1258 case SOUND_GET_DRIVER_VERSION: 1259 memcpy(data, &DriverVersion, sizeof(DriverVersion)); 1260 break; 1261 1262 default: 1263 OLDAPI(("cmedia_pci: unknown code %ld\n", iop)); 1264 err = B_BAD_VALUE; 1265 break; 1266 } 1267 if ((err == B_OK) && configure) { 1268 cpu_status cp; 1269 KTRACE(); 1270 cp = disable_interrupts(); 1271 acquire_spinlock(&port->card->hardware); 1272 err = configure_pcm(port, &config, false); 1273 release_spinlock(&port->card->hardware); 1274 restore_interrupts(cp); 1275 } 1276 return err; 1277 } 1278 1279 1280 static void 1281 copy_short_to_float( 1282 float * f, 1283 const short * s, 1284 int c, 1285 int endian) /* endian means float data in big-endian */ 1286 { 1287 if (endian) { 1288 while (c > 1) { 1289 short sh = B_LENDIAN_TO_HOST_FLOAT(*s); 1290 *(f++) = B_HOST_TO_BENDIAN_FLOAT((float)B_LENDIAN_TO_HOST_INT16(sh)); 1291 s++; 1292 c -= 2; 1293 } 1294 } 1295 else { 1296 while (c > 1) { 1297 short sh = B_LENDIAN_TO_HOST_FLOAT(*s); 1298 *(f++) = B_HOST_TO_LENDIAN_FLOAT((float)B_LENDIAN_TO_HOST_INT16(sh)); 1299 s++; 1300 c -= 2; 1301 } 1302 } 1303 } 1304 1305 1306 static void 1307 copy_float_to_short( 1308 short * s, 1309 const float * f, 1310 int c, 1311 int endian) /* endian means float data in big-endian */ 1312 { 1313 if (endian) { 1314 while (c > 1) { 1315 float fl = *(f++); 1316 *(s++) = B_HOST_TO_LENDIAN_INT16((float)B_BENDIAN_TO_HOST_FLOAT(fl)); 1317 c -= 2; 1318 } 1319 } 1320 else { 1321 while (c > 1) { 1322 float fl = *(f++); 1323 *(s++) = B_HOST_TO_LENDIAN_INT16((float)B_LENDIAN_TO_HOST_FLOAT(fl)); 1324 c -= 2; 1325 } 1326 } 1327 } 1328 1329 1330 static void 1331 swap_copy( 1332 short * dest, 1333 const short * src, 1334 int c) 1335 { 1336 while (c > 1) { 1337 unsigned short sh = *(src++); 1338 *(dest++) = ((sh << 8) | (sh >> 8)); 1339 c -= 2; 1340 } 1341 } 1342 1343 1344 static status_t 1345 pcm_read( 1346 void * cookie, 1347 off_t pos, 1348 void * data, 1349 size_t * nread) 1350 { 1351 pcm_dev * port = (pcm_dev *)cookie; 1352 size_t to_read = *nread; 1353 status_t err; 1354 int block; 1355 cpu_status cp; 1356 int bytes_xferred; 1357 void * hdrptr = data; 1358 int hdrsize = port->config.buf_header; 1359 cmedia_pci_audio_buf_header hdr; 1360 1361 // ddprintf(("cmedia_pci: pcm_read()\n")); /* we're here */ 1362 1363 *nread = 0; 1364 data = ((char *)data)+hdrsize; 1365 to_read -= hdrsize; 1366 1367 err = acquire_sem_etc(port->rd_entry, 1, B_CAN_INTERRUPT, 0); 1368 if (err < B_OK) { 1369 return err; 1370 } 1371 1372 hdr.capture_time = port->rd_time; 1373 1374 goto first_time; 1375 1376 while (to_read > 0) { 1377 /* wait for more data */ 1378 atomic_add(&port->read_waiting, 1); 1379 err = acquire_sem_etc(port->read_sem, 1, B_CAN_INTERRUPT, 0); 1380 if (err < B_OK) { 1381 release_sem(port->rd_entry); 1382 return err; 1383 } 1384 1385 first_time: /* we need to check whether anything's available first */ 1386 KTRACE(); 1387 cp = disable_interrupts(); 1388 acquire_spinlock(&port->rd_lock); 1389 1390 block = port->rd_size-port->was_read; 1391 1392 if (port->config.format == 0x24) { 1393 if (block > (to_read>>1)) { /* floats expand by factor 2 */ 1394 block = to_read>>1; 1395 } 1396 } 1397 else if (block > to_read) { 1398 block = to_read; 1399 } 1400 switch (port->config.format) { 1401 case 0x24: /* floats */ 1402 copy_short_to_float((float *)data, (const short *)(port->rd_cur+port->was_read), 1403 block, !B_HOST_IS_LENDIAN == !port->config.big_endian); 1404 bytes_xferred = block * 2; 1405 break; 1406 case 0x02: /* shorts */ 1407 if (!B_HOST_IS_LENDIAN == !port->config.big_endian) { 1408 /* we need to swap */ 1409 swap_copy((short *)data, (const short *)(port->rd_cur+port->was_read), block); 1410 bytes_xferred = block; 1411 break; 1412 } 1413 /* else fall through to default case */ 1414 case 0x11: /* bytes */ 1415 default: 1416 memcpy(data, (void *)(port->rd_cur+port->was_read), block); 1417 bytes_xferred = block; 1418 break; 1419 } 1420 port->was_read += block; 1421 1422 release_spinlock(&port->rd_lock); 1423 restore_interrupts(cp); 1424 1425 to_read -= bytes_xferred; 1426 data = ((char *)data)+bytes_xferred; 1427 *nread += bytes_xferred; 1428 } 1429 1430 /* provide header if requested */ 1431 if (hdrsize > 0) { 1432 ddprintf(("header %d\n", hdrsize)); 1433 *nread += hdrsize; 1434 hdr.capture_size = *nread; 1435 hdr.sample_rate = port->config.sample_rate; 1436 if (hdrsize > sizeof(hdr)) { 1437 hdrsize = sizeof(hdr); 1438 } 1439 memcpy(hdrptr, &hdr, hdrsize); 1440 } 1441 1442 release_sem(port->rd_entry); 1443 1444 return B_OK; 1445 } 1446 1447 1448 static status_t 1449 pcm_write( 1450 void * cookie, 1451 off_t pos, 1452 const void * data, 1453 size_t * nwritten) 1454 { 1455 pcm_dev * port = (pcm_dev *)cookie; 1456 status_t err; 1457 cpu_status cp; 1458 int written = 0; 1459 int to_write = *nwritten; /* in play bytes, not input bytes! */ 1460 int block; 1461 int bytes_xferred; 1462 1463 // ddprintf(("cmedia_pci: pcm_write()\n")); /* we're here */ 1464 1465 *nwritten = 0; 1466 1467 err = acquire_sem_etc(port->wr_entry, 1, B_CAN_INTERRUPT, 0); 1468 if (err < B_OK) { 1469 return err; 1470 } 1471 1472 atomic_add(&port->write_waiting, 1); 1473 if (port->config.format == 0x24) { 1474 to_write >>= 1; /* floats collapse by 2 */ 1475 } 1476 while (to_write > 0) { 1477 1478 /* wait to write */ 1479 1480 err = acquire_sem_etc(port->write_sem, 1, B_CAN_INTERRUPT, 0); 1481 if (err < B_OK) { 1482 release_sem(port->wr_entry); 1483 return err; 1484 } 1485 1486 #if DEBUG 1487 put_cnt++; 1488 { 1489 bigtime_t delta = system_time() - the_time; 1490 if (delta < 1) { 1491 ddprintf(("cmedia_pci: delta %lld (low!) #%ld\n", delta, put_cnt)); 1492 } 1493 else if (delta > 2000) { 1494 ddprintf(("cmedia_pci: delta %lld (high!) #%ld\n", delta, put_cnt)); 1495 } 1496 } 1497 if (put_cnt != int_cnt) { 1498 static int last; 1499 if (last != int_cnt-put_cnt) 1500 OLDAPI(("cmedia_pci: %ld mismatch\n", int_cnt-put_cnt)); 1501 last = int_cnt-put_cnt; 1502 } 1503 #endif /* DEBUG */ 1504 1505 KTRACE(); 1506 cp = disable_interrupts(); 1507 acquire_spinlock(&port->wr_lock); 1508 1509 block = port->wr_size-port->was_written; 1510 if (block > to_write) { 1511 /* must let next guy in */ 1512 if (atomic_add(&port->write_waiting, -1) > 0) { 1513 release_sem_etc(port->write_sem, 1, B_DO_NOT_RESCHEDULE); 1514 } 1515 else { 1516 atomic_add(&port->write_waiting, 1); /* undo damage */ 1517 } 1518 block = to_write; 1519 } 1520 else if (block < to_write) { 1521 atomic_add(&port->write_waiting, 1); /* we will loop back */ 1522 } 1523 switch (port->config.format) { 1524 case 0x24: /* floats */ 1525 copy_float_to_short((short *)(port->wr_cur+port->was_written), (const float *)data, 1526 block, !B_HOST_IS_LENDIAN == !port->config.big_endian); 1527 bytes_xferred = block * 2; 1528 break; 1529 case 0x02: /* shorts */ 1530 if (!B_HOST_IS_LENDIAN == !port->config.big_endian) { 1531 /* we need to swap */ 1532 swap_copy((short *)(port->wr_cur+port->was_written), (const short *)data, block); 1533 bytes_xferred = block; 1534 break; 1535 } 1536 /* else fall through to default case */ 1537 case 0x11: /* bytes */ 1538 default: 1539 memcpy((void *)(port->wr_cur+port->was_written), data, block); 1540 bytes_xferred = block; 1541 break; 1542 } 1543 port->was_written += block; 1544 port->wr_silence = 0; 1545 1546 release_spinlock(&port->wr_lock); 1547 restore_interrupts(cp); 1548 1549 data = ((char *)data)+bytes_xferred; 1550 written += bytes_xferred; 1551 to_write -= block; 1552 } 1553 1554 *nwritten = written; 1555 release_sem(port->wr_entry); 1556 1557 return B_OK; 1558 } 1559 1560 1561 bool 1562 dma_a_interrupt( 1563 cmedia_pci_dev * dev) 1564 { 1565 bool ret = false; 1566 pcm_dev * port = &dev->pcm; 1567 volatile uchar * ptr; 1568 uint32 addr; 1569 uint32 offs; 1570 bigtime_t st = system_time(); 1571 int32 ww; 1572 1573 #if 0 1574 ddprintf(("cmedia_pci: dma_a 0x%x+0x%x\n", PCI_IO_RD_32((int)port->dma_a), PCI_IO_RD_32((int)port->dma_a+4))); 1575 #endif 1576 // KTRACE(); /* */ 1577 acquire_spinlock(&port->wr_lock); 1578 1579 if (port->write_sem < 0) { 1580 kprintf("cmedia_pci: spurious DMA A interrupt!\n"); 1581 release_spinlock(&port->wr_lock); 1582 return false; 1583 } 1584 /* copy possible silence into playback buffer */ 1585 1586 if (port->was_written > 0 && port->was_written < port->wr_size) { 1587 if (port->config.format == 0x11) { 1588 memset((void *)(port->wr_cur+port->was_written), 0x80, port->wr_size-port->was_written); 1589 } 1590 else { 1591 memset((void *)(port->wr_cur+port->was_written), 0, port->wr_size-port->was_written); 1592 } 1593 } 1594 1595 /* because the system may be lacking and not hand us the */ 1596 /* interrupt in time, we check which half is currently being */ 1597 /* played, and set the pointer to the other half */ 1598 1599 addr = PCI_IO_RD_32((uint32)port->dma_a); 1600 if ((offs = addr-(uint32)port->card->low_phys) < port->wr_size) { 1601 ptr = port->wr_2; 1602 } 1603 else { 1604 ptr = port->wr_1; 1605 } 1606 port->wr_total += port->config.play_buf_size/2; 1607 /* compensate for interrupt latency */ 1608 /* assuming 4 byte frames */ 1609 port->wr_time = st-(offs&(port->config.play_buf_size/2-1))*250000LL/(int64)port->config.sample_rate; 1610 if ((ww = atomic_add(&port->wr_time_wait, -1)) > 0) { 1611 release_sem_etc(port->wr_time_sem, 1, B_DO_NOT_RESCHEDULE); 1612 ret = true; 1613 } 1614 else { 1615 atomic_add(&port->wr_time_wait, 1); /* re-set to 0 */ 1616 } 1617 1618 if (port->wr_cur == ptr) { 1619 port->wr_skipped++; 1620 OLDAPI(("cmedia_pci: write skipped %ld\n", port->wr_skipped)); 1621 } 1622 port->wr_cur = ptr; 1623 port->was_written = 0; 1624 1625 /* check for client there to write into buffer */ 1626 1627 if (atomic_add(&port->write_waiting, -1) > 0) { 1628 #if DEBUG 1629 int_cnt++; 1630 the_time = st; 1631 #endif 1632 release_sem_etc(port->write_sem, 1, B_DO_NOT_RESCHEDULE); 1633 ret = true; 1634 } 1635 else { 1636 atomic_add(&port->write_waiting, 1); 1637 /* if none there, fill with silence */ 1638 if (port->wr_silence < port->config.play_buf_size*2) { 1639 if (port->config.format == 0x11) { 1640 memset((void *)ptr, 0x80, port->wr_size); 1641 } 1642 else { 1643 memset((void *)ptr, 0, port->wr_size); 1644 } 1645 port->wr_silence += port->wr_size; 1646 } 1647 } 1648 /* copying will be done in user thread */ 1649 1650 release_spinlock(&port->wr_lock); 1651 return ret; 1652 } 1653 1654 1655 bool 1656 dma_c_interrupt( 1657 cmedia_pci_dev * dev) 1658 { 1659 bool ret = false; 1660 pcm_dev * port = &dev->pcm; 1661 volatile uchar * ptr; 1662 uint32 addr; 1663 uint32 offs; 1664 int32 rr; 1665 bigtime_t st = system_time(); 1666 1667 /* mark data as readable in record buffer */ 1668 #if 0 1669 ddprintf(("cmedia_pci: dma_c 0x%x+0x%x\n", PCI_IO_RD_32((int)port->dma_c), PCI_IO_RD_32((int)port->dma_c+4))); 1670 #endif 1671 // KTRACE(); /* */ 1672 acquire_spinlock(&port->rd_lock); 1673 1674 if (port->read_sem < 0) { 1675 kprintf("cmedia_pci: spurious DMA C interrupt!\n"); 1676 release_spinlock(&port->rd_lock); 1677 return false; 1678 } 1679 /* if we lose an interrupt, we automatically avoid constant glitching by setting */ 1680 /* the write pointer based on where the DMA counter is everytime */ 1681 addr = PCI_IO_RD_32((uint32)port->dma_c); 1682 if ((offs = addr-port->config.play_buf_size-(uint32)port->card->low_phys) < port->rd_size) { 1683 ptr = port->rd_2; 1684 } 1685 else { 1686 ptr = port->rd_1; 1687 } 1688 if (port->rd_cur == ptr) { 1689 port->rd_skipped++; 1690 OLDAPI(("cmedia_pci: read skipped %ld\n", port->rd_skipped)); 1691 } 1692 port->rd_total += port->rd_size; 1693 1694 port->rd_cur = ptr; 1695 port->was_read = 0; 1696 port->rd_time = port->next_rd_time; 1697 /* time stamp when this buffer became available -- compensate for interrupt latency */ 1698 port->next_rd_time = st-(offs&(port->config.rec_buf_size/2-1))*1000000LL/(int64)port->config.sample_rate; 1699 if ((rr = atomic_add(&port->rd_time_wait, -1)) > 0) { 1700 release_sem_etc(port->rd_time_sem, 1, B_DO_NOT_RESCHEDULE); 1701 ret = true; 1702 } 1703 else { 1704 atomic_add(&port->rd_time_wait, 1); /* re-set to 0 */ 1705 } 1706 1707 if (atomic_add(&port->read_waiting, -1) > 0) { 1708 release_sem_etc(port->read_sem, 1, B_DO_NOT_RESCHEDULE); 1709 ret = true; 1710 } 1711 else { 1712 atomic_add(&port->read_waiting, 1); 1713 } 1714 /* copying will be done in the user thread */ 1715 release_spinlock(&port->rd_lock); 1716 return ret; 1717 } 1718 1719