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 uchar reg_value; 722 char DriverVersion[] = "1.3.2 (Jul 17, 2001)"; 723 724 pcm_dev * port = (pcm_dev *)cookie; 725 status_t err = B_BAD_VALUE; 726 pcm_cfg config = port->config; 727 static float rates[7] = { 48000.0, 44100.0, 32000.0, 22050.0, 16000.0, 11025.0, 8000.0 }; 728 bool configure = false; 729 config.play_buf_size /= 2; 730 config.rec_buf_size /= 2; 731 732 ddprintf(("cmedia_pci: pcm_control()\n")); 733 734 switch (iop) { 735 case B_AUDIO_GET_AUDIO_FORMAT: 736 memcpy(data, &config, sizeof(port->config)); 737 err = B_OK; 738 break; 739 case B_AUDIO_GET_PREFERRED_SAMPLE_RATES: 740 memcpy(data, rates, sizeof(rates)); 741 err = B_OK; 742 break; 743 case B_AUDIO_SET_AUDIO_FORMAT: 744 memcpy(&config, data, sizeof(config)); 745 configure = true; 746 err = B_OK; 747 break; 748 case SV_RD_TIME_WAIT: 749 atomic_add(&port->rd_time_wait, 1); 750 err = acquire_sem(port->rd_time_sem); 751 if (err >= B_OK) { 752 cpu_status cp; 753 KTRACE(); 754 cp = disable_interrupts(); 755 acquire_spinlock(&port->rd_lock); 756 ((sv_timing *)data)->time = port->rd_time; 757 ((sv_timing *)data)->bytes = port->rd_total; 758 ((sv_timing *)data)->skipped = port->rd_skipped; 759 ((sv_timing *)data)->_reserved_[0] = 0xffffffffUL; 760 release_spinlock(&port->rd_lock); 761 restore_interrupts(cp); 762 } 763 break; 764 case SV_WR_TIME_WAIT: 765 atomic_add(&port->wr_time_wait, 1); 766 err = acquire_sem(port->wr_time_sem); 767 if (err >= B_OK) { 768 cpu_status cp; 769 KTRACE(); 770 cp = disable_interrupts(); 771 acquire_spinlock(&port->wr_lock); 772 ((sv_timing *)data)->time = port->wr_time; 773 ((sv_timing *)data)->bytes = port->wr_total; 774 ((sv_timing *)data)->skipped = port->wr_skipped; 775 ((sv_timing *)data)->_reserved_[0] = 0xffffffffUL; 776 release_spinlock(&port->wr_lock); 777 restore_interrupts(cp); 778 } 779 break; 780 case SV_SECRET_HANDSHAKE: { 781 cpu_status cp; 782 KTRACE(); 783 cp = disable_interrupts(); 784 acquire_spinlock(&port->wr_lock); 785 acquire_spinlock(&port->rd_lock); 786 ((sv_handshake *)data)->wr_time = port->wr_time; 787 ((sv_handshake *)data)->wr_skipped = port->wr_skipped; 788 ((sv_handshake *)data)->rd_time = port->rd_time; 789 ((sv_handshake *)data)->rd_skipped = port->rd_skipped; 790 ((sv_handshake *)data)->wr_total = port->wr_total; 791 ((sv_handshake *)data)->rd_total = port->rd_total; 792 ((sv_handshake *)data)->_reserved_[0] = 0xffffffffUL; 793 err = B_OK; 794 release_spinlock(&port->rd_lock); 795 release_spinlock(&port->wr_lock); 796 restore_interrupts(cp); 797 } break; 798 case SOUND_GET_PARAMS: { 799 cpu_status cp; 800 uchar u; 801 sound_setup * sound = (sound_setup *)data; 802 err = B_OK; 803 cp = disable_interrupts(); 804 acquire_spinlock(&port->card->hardware); 805 /* Here we get to hard-code the mix/mux values. */ 806 /* Huh-huh; he said "hard-code"! */ 807 sound->sample_rate = kHz_44_1; 808 if (!port->config.big_endian == !B_HOST_IS_BENDIAN) { 809 sound->playback_format = linear_16bit_big_endian_stereo; 810 sound->capture_format = linear_16bit_big_endian_stereo; 811 } 812 else { 813 sound->playback_format = linear_16bit_little_endian_stereo; 814 sound->capture_format = linear_16bit_little_endian_stereo; 815 } 816 sound->dither_enable = false; 817 sound->loop_attn = 0; 818 sound->loop_enable = 0; 819 sound->output_boost = 0; 820 sound->highpass_enable = 0; 821 /* this is a master control on C-Media... */ 822 u = get_indirect(port->card, 0x30)>>2; 823 sound->mono_gain = u&63; 824 sound->mono_mute = 0; 825 826 /* left channel */ 827 u = get_indirect(port->card, 0x3d); // Legacy SB compatible Mixer 828 switch (u) 829 { 830 case 0x10: 831 sound->left.adc_source = line; // record line left 832 break; 833 834 case 4: 835 sound->left.adc_source = aux1; // record CD left ?? 836 break; 837 838 case 1: 839 sound->left.adc_source = mic; // record mic left 840 break; 841 842 default: 843 sound->left.adc_source = loopback; 844 break; 845 } 846 u = get_indirect(port->card, 0x3f)>>4; 847 sound->left.adc_gain = u&15; 848 849 u = get_direct(port->card, 0x25)<<4; 850 sound->left.mic_gain_enable = u&16; 851 852 u = get_indirect(port->card, 0x36)>>3; 853 sound->left.aux1_mix_gain = 31-(u&31); 854 855 u = get_indirect(port->card, 0x3c)<<5; 856 sound->left.aux1_mix_mute = ~u&128; 857 858 u = get_indirect(port->card, 0x34)>>3; 859 sound->left.aux2_mix_gain = 31-(u&31); 860 861 u = get_direct(port->card, 0x24); 862 sound->left.aux2_mix_mute = u&128; 863 864 u = get_indirect(port->card, 0x38)>>3; 865 sound->left.line_mix_gain = 31-(u&31); 866 867 u = get_indirect(port->card, 0x3c)<<3; 868 sound->left.line_mix_mute = ~u&128; 869 870 u = get_indirect(port->card, 0x32)>>2; 871 sound->left.dac_attn = 63-(u&63); 872 873 u = get_direct(port->card, 0x24)<<1; 874 sound->left.dac_mute = u&128; 875 876 /* right channel */ 877 u = get_indirect(port->card, 0x3e); 878 switch (u) 879 { 880 case 8: 881 sound->right.adc_source = line; //record line right 882 break; 883 884 case 2: 885 sound->right.adc_source = aux1; // record CD right? 886 break; 887 888 case 1: 889 sound->right.adc_source = mic; // record mic right 890 break; 891 892 default: 893 sound->right.adc_source = loopback; 894 break; 895 } 896 u = get_indirect(port->card, 0x40)>>4; 897 sound->right.adc_gain = u&15; 898 sound->right.mic_gain_enable = sound->left.mic_gain_enable; 899 u = get_indirect(port->card, 0x37)>>3; 900 sound->right.aux1_mix_gain = 31-(u&31); 901 u = get_indirect(port->card, 0x3c)<<6; 902 sound->right.aux1_mix_mute = ~u&128; 903 u = get_indirect(port->card, 0x35)>>3; 904 sound->right.aux2_mix_gain = 31-(u&31); 905 u = get_direct(port->card, 0x24); 906 sound->right.aux2_mix_mute = u&128; 907 u = get_indirect(port->card, 0x39)>>3; 908 sound->right.line_mix_gain = 31-(u&31); 909 u = get_indirect(port->card, 0x3c)<<4; 910 sound->right.line_mix_mute = ~u&128; 911 u = get_indirect(port->card, 0x33)>>2; 912 sound->right.dac_attn = 63-(u&63); 913 u = get_direct(port->card, 0x24)<<1; 914 sound->right.dac_mute = u&128; 915 /* done */ 916 release_spinlock(&port->card->hardware); 917 restore_interrupts(cp); 918 } break; 919 case SOUND_SET_PARAMS: { 920 cpu_status cp; 921 uchar u; 922 sound_setup * sound = (sound_setup *)data; 923 err = B_OK; 924 cp = disable_interrupts(); 925 acquire_spinlock(&port->card->hardware); 926 /* Here we get to hard-code the mix/mux values. */ 927 /* Huh-huh; he said "hard-code"! */ 928 929 /* ignore sample rate */ 930 sound->sample_rate = kHz_44_1; 931 if (config.sample_rate < 43999 || config.sample_rate > 44201) { 932 config.sample_rate = 44100.0; 933 configure = true; 934 } 935 /* we only support 16-bit formats */ 936 if (sound->playback_format == linear_16bit_big_endian_stereo && 937 sound->capture_format == linear_16bit_big_endian_stereo) { 938 if (!config.big_endian != !B_HOST_IS_BENDIAN || config.format != 0x2) { 939 config.big_endian = B_HOST_IS_BENDIAN; 940 config.format = 0x2; 941 configure = true; 942 } 943 OLDAPI(("same_endian\n")); 944 } 945 else if (sound->playback_format == linear_16bit_little_endian_stereo && 946 sound->capture_format == linear_16bit_little_endian_stereo) { 947 if (!config.big_endian != !!B_HOST_IS_BENDIAN || config.format != 0x2) { 948 config.big_endian = !B_HOST_IS_BENDIAN; 949 config.format = 0x2; 950 configure = true; 951 } 952 OLDAPI(("other_endian\n")); 953 } 954 else { 955 config.big_endian = !!B_HOST_IS_BENDIAN; 956 configure = true; 957 OLDAPI(("other format!!!\n")); 958 } 959 /* ignore these values */ 960 sound->dither_enable = false; 961 sound->loop_attn = 0; 962 sound->loop_enable = 0; 963 sound->output_boost = 0; 964 sound->highpass_enable = 0; 965 /* this is a stereo control on C-Media... */ 966 u = (sound->mono_gain>>1)&0x1f; 967 OLDAPI(("output: %x\n", u)); 968 set_indirect(port->card, 0x30, u<<3, 0xff); 969 set_indirect(port->card, 0x31, u<<3, 0xff); 970 /* left channel */ 971 switch (sound->left.adc_source) 972 { 973 case line: 974 u = 1<<4; 975 break; 976 case aux1: 977 u = 1<<2; 978 break; 979 case mic: 980 u = 1<<0; 981 break; 982 default: 983 u = 0x15; 984 break; 985 } 986 OLDAPI(("input: %x\n", u)); 987 set_indirect(port->card, 0x3d, u, 0xff); 988 u = (sound->left.adc_gain&15); 989 set_indirect(port->card, 0x3f, u<<4, 0xff); 990 u = sound->left.mic_gain_enable ? 0 : 0x01; 991 set_direct(port->card, 0x25, u, 0x01); 992 u = 31-(sound->left.aux1_mix_gain&31); 993 OLDAPI(("cd: %x\n", u)); 994 set_indirect(port->card, 0x36, u<<3, 0xff); 995 u = sound->left.aux1_mix_mute ? 0 : 0x04; 996 set_indirect(port->card, 0x3c, u, 0x04); 997 u = 31-(sound->left.aux2_mix_gain&31); 998 OLDAPI(("aux2: %x\n", u)); 999 set_indirect(port->card, 0x34, u<<3, 0xff); 1000 u = sound->left.aux2_mix_mute ? 0x80 : 0; 1001 set_direct(port->card, 0x24, u, 0x80); 1002 u = 31-(sound->left.line_mix_gain&31); 1003 OLDAPI(("line: %x\n", u)); 1004 set_indirect(port->card, 0x38, u<<3, 0xff); 1005 u = sound->left.line_mix_mute ? 0 : 0x10; 1006 set_indirect(port->card, 0x3c, u, 0x10); 1007 u = 63-(sound->left.dac_attn & 63); 1008 OLDAPI(("PCM: %x\n", u)); 1009 set_indirect(port->card, 0x32, u<<2, 0xff); 1010 u = sound->left.dac_mute ? 0x40 : 0; 1011 set_direct(port->card, 0x24, u, 0x40); 1012 /* right channel */ 1013 switch (sound->right.adc_source) { 1014 case line: 1015 u = 1<<3; 1016 break; 1017 case aux1: 1018 u = 1<<1; 1019 break; 1020 case mic: 1021 u = 1<<0; 1022 break; 1023 default: 1024 u = 0x0a; 1025 break; 1026 } 1027 sound->right.mic_gain_enable = sound->left.mic_gain_enable; 1028 set_indirect(port->card, 0x3e, u, 0xff); 1029 u = (sound->right.adc_gain&15); 1030 set_indirect(port->card, 0x40, u<<4, 0xff); 1031 u = sound->right.mic_gain_enable ? 0 : 0x01; 1032 set_direct(port->card, 0x25, u, 0x01); 1033 u = 31-(sound->right.aux1_mix_gain&31); 1034 set_indirect(port->card, 0x37, u<<3, 0xff); 1035 u = sound->right.aux1_mix_mute ? 0 : 0x02; 1036 set_indirect(port->card, 0x3c, u, 0x02); 1037 u = 31-(sound->right.aux2_mix_gain&31); 1038 set_indirect(port->card, 0x35, u<<3, 0xff); 1039 u = sound->right.aux2_mix_mute ? 0x80 : 0; 1040 set_direct(port->card, 0x24, u, 0x80); 1041 u = 31-(sound->right.line_mix_gain&31); 1042 set_indirect(port->card, 0x39, u<<3, 0xff); 1043 u = sound->right.line_mix_mute ? 0 : 0x08; 1044 set_indirect(port->card, 0x3c, u, 0x08); 1045 u = 63-(sound->right.dac_attn & 63); 1046 set_indirect(port->card, 0x33, u<<2, 0xff); 1047 u = sound->right.dac_mute ? 0x40 : 0; 1048 set_direct(port->card, 0x24, u, 0x40); 1049 /* done */ 1050 release_spinlock(&port->card->hardware); 1051 restore_interrupts(cp); 1052 } break; 1053 case SOUND_SET_PLAYBACK_COMPLETION_SEM: 1054 port->old_play_sem = *(sem_id *)data; 1055 err = B_OK; 1056 break; 1057 case SOUND_SET_CAPTURE_COMPLETION_SEM: 1058 port->old_cap_sem = *(sem_id *)data; 1059 err = B_OK; 1060 break; 1061 // case SOUND_GET_PLAYBACK_TIMESTAMP: 1062 // break; 1063 // case SOUND_GET_CAPTURE_TIMESTAMP: 1064 // break; 1065 // case SOUND_DEBUG_ON: 1066 // break; 1067 // case SOUND_DEBUG_OFF: 1068 // break; 1069 case SOUND_UNSAFE_WRITE: { 1070 audio_buffer_header * buf = (audio_buffer_header *)data; 1071 size_t n = buf->reserved_1-sizeof(*buf); 1072 pcm_write(cookie, 0, buf+1, &n); 1073 buf->time = port->wr_time; 1074 buf->sample_clock = port->wr_total/4 * 10000 / 441; 1075 err = release_sem(port->old_play_sem); 1076 } break; 1077 case SOUND_UNSAFE_READ: { 1078 audio_buffer_header * buf = (audio_buffer_header *)data; 1079 size_t n = buf->reserved_1-sizeof(*buf); 1080 pcm_read(cookie, 0, buf+1, &n); 1081 buf->time = port->rd_time; 1082 buf->sample_clock = port->rd_total/4 * 10000 / 441; 1083 err = release_sem(port->old_cap_sem); 1084 } break; 1085 case SOUND_LOCK_FOR_DMA: 1086 err = B_OK; 1087 break; 1088 case SOUND_SET_PLAYBACK_PREFERRED_BUF_SIZE: 1089 config.play_buf_size = (intptr_t)data; 1090 configure = true; 1091 err = B_OK; 1092 break; 1093 case SOUND_SET_CAPTURE_PREFERRED_BUF_SIZE: 1094 config.rec_buf_size = (intptr_t)data; 1095 configure = true; 1096 err = B_OK; 1097 break; 1098 case SOUND_GET_PLAYBACK_PREFERRED_BUF_SIZE: 1099 *(int32*)data = config.play_buf_size; 1100 err = B_OK; 1101 break; 1102 case SOUND_GET_CAPTURE_PREFERRED_BUF_SIZE: 1103 *(int32*)data = config.rec_buf_size; 1104 err = B_OK; 1105 break; 1106 1107 1108 // control ports for SPDIF settings 1109 case SOUND_GET_SPDIF_IN_OUT_LOOPBACK: 1110 *(int8 *)data = 0; 1111 reg_value = get_direct( port->card, 0x04 ); 1112 if( reg_value && 0x80 ) *(int8 *)data = 1; 1113 err = B_OK; 1114 break; 1115 1116 case SOUND_SET_SPDIF_IN_OUT_LOOPBACK: 1117 if( *(int8 *)data == 0 ) // disable SPDIF-IN loopback to SPDIF (bypass) 1118 set_direct( port->card, 0x04, 0x00, 0x80 ); 1119 else // enable SPDIF-IN loopback to SPDIF (bypass) 1120 set_direct( port->card, 0x04, 0x80, 0x80 ); 1121 err = B_OK; 1122 break; 1123 1124 1125 1126 1127 case SOUND_GET_SPDIF_OUT: 1128 *(int8 *)data = 0; 1129 reg_value = get_direct( port->card, 0x16 ); // Adresse 0x16 1130 if( reg_value && 0x80 ) *(int8 *)data = 1; 1131 err = B_OK; 1132 break; 1133 1134 case SOUND_SET_SPDIF_OUT: 1135 if( *(int8 *)data == 0 ) // disable SPDIF-OUT 1136 set_direct( port->card, 0x16, 0x00, 0x80); 1137 else // enable SPDIF-OUT 1138 set_direct( port->card, 0x16, 0x80, 0x80 ); 1139 err = B_OK; 1140 break; 1141 1142 1143 1144 case SOUND_GET_SPDIF_MONITOR: 1145 *(int8 *)data = 0; 1146 reg_value = get_direct( port->card, 0x24 ); 1147 if( reg_value && 0x01 ) *(int8 *)data = 1; 1148 err = B_OK; 1149 break; 1150 1151 1152 case SOUND_SET_SPDIF_MONITOR: 1153 if( *(int8 *)data == 0 ) // disable SPDIF_IN PCM to DAC (CDPlay) 1154 set_direct( port->card, 0x24, 0x00, 0x01 ); 1155 else // enable SPDIF_IN PCM to DAC (CDPlay) 1156 set_direct( port->card, 0x24, 0x01, 0x01 ); 1157 err = B_OK; 1158 break; 1159 1160 case SOUND_GET_SPDIF_OUT_LEVEL: 1161 *(int8 *)data = 0; 1162 reg_value = get_direct( port->card, 0x1b ); 1163 if( reg_value && 0x02 ) *(int8 *)data = 1; 1164 err = B_OK; 1165 break; 1166 1167 case SOUND_SET_SPDIF_OUT_LEVEL: 1168 if( *(int8 *)data == 0 ) // enable SPDIF-OUT optical 1169 set_direct( port->card, 0x1b, 0x00, 0x02 ); 1170 else // enable SPDIF-OUT coaxial 1171 set_direct( port->card, 0x1b, 0x02, 0x02 ); 1172 break; 1173 1174 case SOUND_GET_SPDIF_IN_FORMAT: 1175 *(int8 *)data = 0; 1176 reg_value = get_direct( port->card, 0x08 ); // Adresse 0x08 1177 if( reg_value && 0x80 ) *(int8 *)data = 1; 1178 err = B_OK; 1179 break; 1180 1181 1182 case SOUND_SET_SPDIF_IN_FORMAT: 1183 if( *(int8 *)data == 0 ) // disable SPDIF inverse (SPDIF normal) 1184 set_direct( port->card, 0x08, 0x00, 0x80 ); 1185 else // enable SPDIF inverse 1186 set_direct( port->card, 0x08, 0x80, 0x80 ); // Adresse 0x08, Daten 0x80 1187 err = B_OK; 1188 break; 1189 1190 1191 case SOUND_GET_SPDIF_IN_OUT_COPYRIGHT: 1192 *(int8 *)data = 0; 1193 reg_value = get_direct( port->card, 0x16 ); 1194 if( reg_value && 0x40 ) *(int8 *)data = 1; 1195 err = B_OK; 1196 break; 1197 1198 case SOUND_SET_SPDIF_IN_OUT_COPYRIGHT: 1199 if( *(int8 *)data == 0 ) // disable SPDIF-IN/OUT copyright protection 1200 set_direct( port->card, 0x16, 0x00, 0x40 ); 1201 else // enable SPDIF-IN/OUT copyright protection 1202 set_direct( port->card, 0x16, 0x40, 0x40 ); 1203 err = B_OK; 1204 break; 1205 1206 case SOUND_GET_SPDIF_IN_VALIDITY: 1207 *(int8 *)data = 0; 1208 reg_value = get_direct( port->card, 0x27 ); 1209 if( reg_value && 0x02 ) *(int8 *)data = 1; 1210 err = B_OK; 1211 break; 1212 1213 case SOUND_SET_SPDIF_IN_VALIDITY: 1214 if( *(int8 *)data == 0 ) // disable SPDIF-IN validity detection 1215 set_direct( port->card, 0x27, 0x00, 0x02 ); 1216 else // enable SPDIF-IN validity detection 1217 set_direct( port->card, 0x27, 0x02, 0x02 ); 1218 err = B_OK; 1219 break; 1220 // control ports for analog settings 1221 1222 case SOUND_GET_4_CHANNEL_DUPLICATE: 1223 *(int8 *)data = 0; 1224 reg_value = get_direct( port->card, 0x1b ); 1225 if( reg_value && 0x04 ) *(int8 *)data = 1; 1226 1227 // 0x1b, 0x04, 0x04, /* dual channel mode enable */ 1228 // 0x1a, 0x00, 0x80, /* Double DAC structure disable */ 1229 1230 err = B_OK; 1231 break; 1232 1233 case SOUND_SET_4_CHANNEL_DUPLICATE: 1234 if( *(int8 *)data == 0 ) // disable 4 channel analog duplicate mode 1235 set_direct( port->card, 0x1b, 0x00, 0x04 ); 1236 else // enable 4 channel analog duplicate mode 1237 set_direct( port->card, 0x1b, 0x04, 0x04 ); 1238 err = B_OK; 1239 break; 1240 // control ports for additional info 1241 1242 case SOUND_GET_DEVICE_ID: 1243 // *(int32*)data.vendor_id = cards[0].info.vendor_id; 1244 // *(int32*)data.device_id = cards[0].info.device_id; 1245 1246 // static int32 chipinfo[] = { 0,0 }; 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 size_t 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 ((uint32)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 < (int32)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