Commit d75d9f6be958f0245ed7794bbd2a31eaffae40da
1 parent
769bec72
SDL Audio support and SB16 fixes (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1108 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
860 additions
and
233 deletions
Changelog
| ... | ... | @@ -26,6 +26,7 @@ version 0.6.1: |
| 26 | 26 | - BIOS floppy fix for NT4 (Mike Nordell, Derek Fawcus, Volker Ruppert) |
| 27 | 27 | - Floppy fixes for NT4 and NT5 (Mike Nordell) |
| 28 | 28 | - NT4 IDE fixes (Ben Pfaf, Mike Nordell) |
| 29 | + - SDL Audio support and SB16 fixes (malc) | |
| 29 | 30 | |
| 30 | 31 | version 0.6.0: |
| 31 | 32 | ... | ... |
hw/sb16.c
| ... | ... | @@ -26,12 +26,10 @@ |
| 26 | 26 | #define MIN(a, b) ((a)>(b)?(b):(a)) |
| 27 | 27 | #define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0]))) |
| 28 | 28 | |
| 29 | -#define log(...) do { \ | |
| 30 | - fprintf (stderr, "sb16: " __VA_ARGS__); \ | |
| 31 | - fputc ('\n', stderr); \ | |
| 32 | -} while (0) | |
| 29 | +#define dolog(...) fprintf (stderr, "sb16: " __VA_ARGS__); | |
| 33 | 30 | |
| 34 | 31 | /* #define DEBUG_SB16 */ |
| 32 | + | |
| 35 | 33 | #ifdef DEBUG_SB16 |
| 36 | 34 | #define lwarn(...) fprintf (stderr, "sb16: " __VA_ARGS__) |
| 37 | 35 | #define linfo(...) fprintf (stderr, "sb16: " __VA_ARGS__) |
| ... | ... | @@ -47,7 +45,10 @@ |
| 47 | 45 | #define IO_WRITE_PROTO(name) \ |
| 48 | 46 | void name (void *opaque, uint32_t nport, uint32_t val) |
| 49 | 47 | |
| 50 | -static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992."; | |
| 48 | +static const char e3[] = | |
| 49 | + "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992\0" | |
| 50 | + "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1994-1997"; | |
| 51 | + /* "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1994."; */ | |
| 51 | 52 | |
| 52 | 53 | static struct { |
| 53 | 54 | int ver_lo; |
| ... | ... | @@ -80,10 +81,13 @@ typedef struct SB16State { |
| 80 | 81 | |
| 81 | 82 | int v2x6; |
| 82 | 83 | |
| 83 | - uint8_t in_data[10]; | |
| 84 | - uint8_t out_data[50]; | |
| 84 | + uint8_t in2_data[10]; | |
| 85 | + uint8_t out_data[1024]; | |
| 85 | 86 | |
| 86 | 87 | int left_till_irq; |
| 88 | + uint64_t nzero; | |
| 89 | + uint8_t last_read_byte; | |
| 90 | + uint8_t test_reg; | |
| 87 | 91 | |
| 88 | 92 | /* mixer state */ |
| 89 | 93 | int mixer_nreg; |
| ... | ... | @@ -95,7 +99,7 @@ static struct SB16State dsp; |
| 95 | 99 | |
| 96 | 100 | static void log_dsp (SB16State *dsp) |
| 97 | 101 | { |
| 98 | - linfo ("%c:%c:%d:%c:dmabuf=%d:pos=%d:freq=%d:timeconst=%d:speaker=%d\n", | |
| 102 | + ldebug ("%c:%c:%d:%c:dmabuf=%d:pos=%d:freq=%d:timeconst=%d:speaker=%d\n", | |
| 99 | 103 | dsp->fmt_stereo ? 'S' : 'M', |
| 100 | 104 | dsp->fmt_signed ? 'S' : 'U', |
| 101 | 105 | dsp->fmt_bits, |
| ... | ... | @@ -191,6 +195,7 @@ static void dma_cmd (uint8_t cmd, uint8_t d0, int dma_len) |
| 191 | 195 | mix_block = ((dsp.freq * align) / 100) & ~(align - 1); |
| 192 | 196 | } |
| 193 | 197 | |
| 198 | + if (dsp.freq) | |
| 194 | 199 | AUD_reset (dsp.freq, 1 << dsp.fmt_stereo, fmt); |
| 195 | 200 | control (1); |
| 196 | 201 | dsp.speaker = 1; |
| ... | ... | @@ -202,9 +207,17 @@ static inline void dsp_out_data(SB16State *dsp, int val) |
| 202 | 207 | dsp->out_data[dsp->out_data_len++] = val; |
| 203 | 208 | } |
| 204 | 209 | |
| 210 | +static inline uint8_t dsp_get_data(SB16State *dsp) | |
| 211 | +{ | |
| 212 | + if (dsp->in_index) | |
| 213 | + return dsp->in2_data[--dsp->in_index]; | |
| 214 | + else | |
| 215 | + return 0; | |
| 216 | +} | |
| 217 | + | |
| 205 | 218 | static void command (SB16State *dsp, uint8_t cmd) |
| 206 | 219 | { |
| 207 | - linfo ("%#x\n", cmd); | |
| 220 | + linfo ("command: %#x\n", cmd); | |
| 208 | 221 | |
| 209 | 222 | if (cmd > 0xaf && cmd < 0xd0) { |
| 210 | 223 | if (cmd & 8) |
| ... | ... | @@ -215,7 +228,7 @@ static void command (SB16State *dsp, uint8_t cmd) |
| 215 | 228 | case 12: |
| 216 | 229 | break; |
| 217 | 230 | default: |
| 218 | - log("%#x wrong bits", cmd); | |
| 231 | + dolog ("command: %#x wrong bits specification\n", cmd); | |
| 219 | 232 | goto error; |
| 220 | 233 | } |
| 221 | 234 | dsp->needed_bytes = 3; |
| ... | ... | @@ -223,23 +236,25 @@ static void command (SB16State *dsp, uint8_t cmd) |
| 223 | 236 | else { |
| 224 | 237 | switch (cmd) { |
| 225 | 238 | case 0x00: |
| 226 | - case 0x03: | |
| 227 | 239 | case 0xe7: |
| 228 | 240 | /* IMS uses those when probing for sound devices */ |
| 229 | 241 | return; |
| 230 | 242 | |
| 243 | + case 0x03: | |
| 231 | 244 | case 0x04: |
| 232 | - dsp->needed_bytes = 1; | |
| 233 | - break; | |
| 245 | + dsp_out_data (dsp, 0); | |
| 246 | + return; | |
| 234 | 247 | |
| 235 | 248 | case 0x05: |
| 249 | + dsp->needed_bytes = 2; | |
| 250 | + break; | |
| 251 | + | |
| 236 | 252 | case 0x0e: |
| 237 | 253 | dsp->needed_bytes = 2; |
| 238 | 254 | break; |
| 239 | 255 | |
| 240 | 256 | case 0x0f: |
| 241 | 257 | dsp->needed_bytes = 1; |
| 242 | - dsp_out_data (dsp, 0); | |
| 243 | 258 | break; |
| 244 | 259 | |
| 245 | 260 | case 0x10: |
| ... | ... | @@ -272,6 +287,8 @@ static void command (SB16State *dsp, uint8_t cmd) |
| 272 | 287 | dsp->needed_bytes = 2; |
| 273 | 288 | break; |
| 274 | 289 | |
| 290 | + case 0x45: | |
| 291 | + dsp_out_data (dsp, 0xaa); | |
| 275 | 292 | case 0x47: /* Continue Auto-Initialize DMA 16bit */ |
| 276 | 293 | break; |
| 277 | 294 | |
| ... | ... | @@ -346,19 +363,39 @@ static void command (SB16State *dsp, uint8_t cmd) |
| 346 | 363 | case 0xe3: |
| 347 | 364 | { |
| 348 | 365 | int i; |
| 349 | - for (i = sizeof (e3) - 1; i >= 0; --i) | |
| 366 | + for (i = sizeof (e3) - 1; i >= 0; i--) | |
| 350 | 367 | dsp_out_data (dsp, e3[i]); |
| 351 | 368 | return; |
| 352 | 369 | } |
| 353 | 370 | |
| 371 | + case 0xe4: /* write test reg */ | |
| 372 | + dsp->needed_bytes = 1; | |
| 373 | + break; | |
| 374 | + | |
| 375 | + case 0xe8: /* read test reg */ | |
| 376 | + dsp_out_data (dsp, dsp->test_reg); | |
| 377 | + break; | |
| 378 | + | |
| 354 | 379 | case 0xf2: |
| 355 | - dsp_out_data(dsp, 0xaa); | |
| 380 | + dsp_out_data (dsp, 0xaa); | |
| 356 | 381 | dsp->mixer_regs[0x82] |= dsp->mixer_regs[0x80]; |
| 357 | 382 | pic_set_irq (sb.irq, 1); |
| 358 | 383 | return; |
| 359 | 384 | |
| 385 | + case 0xf9: | |
| 386 | + dsp->needed_bytes = 1; | |
| 387 | + break; | |
| 388 | + | |
| 389 | + case 0xfa: | |
| 390 | + dsp_out_data (dsp, 0); | |
| 391 | + break; | |
| 392 | + | |
| 393 | + case 0xfc: /* FIXME */ | |
| 394 | + dsp_out_data (dsp, 0); | |
| 395 | + break; | |
| 396 | + | |
| 360 | 397 | default: |
| 361 | - log("%#x is unknown", cmd); | |
| 398 | + dolog ("unrecognized command %#x\n", cmd); | |
| 362 | 399 | goto error; |
| 363 | 400 | } |
| 364 | 401 | } |
| ... | ... | @@ -371,15 +408,14 @@ static void command (SB16State *dsp, uint8_t cmd) |
| 371 | 408 | |
| 372 | 409 | static void complete (SB16State *dsp) |
| 373 | 410 | { |
| 411 | + int d0, d1, d2; | |
| 374 | 412 | linfo ("complete command %#x, in_index %d, needed_bytes %d\n", |
| 375 | 413 | dsp->cmd, dsp->in_index, dsp->needed_bytes); |
| 376 | 414 | |
| 377 | 415 | if (dsp->cmd > 0xaf && dsp->cmd < 0xd0) { |
| 378 | - int d0, d1, d2; | |
| 379 | - | |
| 380 | - d0 = dsp->in_data[0]; | |
| 381 | - d1 = dsp->in_data[1]; | |
| 382 | - d2 = dsp->in_data[2]; | |
| 416 | + d2 = dsp_get_data (dsp); | |
| 417 | + d1 = dsp_get_data (dsp); | |
| 418 | + d0 = dsp_get_data (dsp); | |
| 383 | 419 | |
| 384 | 420 | ldebug ("d0 = %d, d1 = %d, d2 = %d\n", |
| 385 | 421 | d0, d1, d2); |
| ... | ... | @@ -387,23 +423,29 @@ static void complete (SB16State *dsp) |
| 387 | 423 | } |
| 388 | 424 | else { |
| 389 | 425 | switch (dsp->cmd) { |
| 390 | - case 0x05: | |
| 391 | 426 | case 0x04: |
| 392 | - case 0x0e: | |
| 427 | + case 0x10: | |
| 428 | + dsp_get_data (dsp); | |
| 429 | + break; | |
| 430 | + | |
| 393 | 431 | case 0x0f: |
| 432 | + d0 = dsp_get_data (dsp); | |
| 433 | + dsp_out_data (dsp, 0xf8); | |
| 394 | 434 | break; |
| 395 | 435 | |
| 396 | - case 0x10: | |
| 436 | + case 0x05: | |
| 437 | + case 0x0e: | |
| 438 | + dsp_get_data (dsp); | |
| 439 | + dsp_get_data (dsp); | |
| 397 | 440 | break; |
| 398 | 441 | |
| 399 | 442 | case 0x14: |
| 400 | 443 | { |
| 401 | - int d0, d1; | |
| 402 | 444 | int save_left; |
| 403 | 445 | int save_pos; |
| 404 | 446 | |
| 405 | - d0 = dsp->in_data[0]; | |
| 406 | - d1 = dsp->in_data[1]; | |
| 447 | + d1 = dsp_get_data (dsp); | |
| 448 | + d0 = dsp_get_data (dsp); | |
| 407 | 449 | |
| 408 | 450 | save_left = dsp->left_till_irq; |
| 409 | 451 | save_pos = dsp->dma_pos; |
| ... | ... | @@ -417,35 +459,60 @@ static void complete (SB16State *dsp) |
| 417 | 459 | } |
| 418 | 460 | |
| 419 | 461 | case 0x40: |
| 420 | - dsp->time_const = dsp->in_data[0]; | |
| 462 | + dsp->time_const = dsp_get_data (dsp); | |
| 421 | 463 | linfo ("set time const %d\n", dsp->time_const); |
| 422 | 464 | break; |
| 423 | 465 | |
| 424 | 466 | case 0x41: |
| 425 | 467 | case 0x42: |
| 426 | - dsp->freq = dsp->in_data[1] + (dsp->in_data[0] << 8); | |
| 427 | - linfo ("set freq %#x, %#x = %d\n", | |
| 428 | - dsp->in_data[1], dsp->in_data[0], dsp->freq); | |
| 468 | + d1 = dsp_get_data (dsp); | |
| 469 | + d0 = dsp_get_data (dsp); | |
| 470 | + | |
| 471 | + dsp->freq = d1 + (d0 << 8); | |
| 472 | + linfo ("set freq %#x, %#x = %d\n", d1, d0, dsp->freq); | |
| 429 | 473 | break; |
| 430 | 474 | |
| 431 | 475 | case 0x48: |
| 432 | - dsp->dma_buffer_size = dsp->in_data[1] + (dsp->in_data[0] << 8); | |
| 476 | + d1 = dsp_get_data (dsp); | |
| 477 | + d0 = dsp_get_data (dsp); | |
| 478 | + dsp->dma_buffer_size = d1 + (d0 << 8); | |
| 433 | 479 | linfo ("set dma len %#x, %#x = %d\n", |
| 434 | - dsp->in_data[1], dsp->in_data[0], dsp->dma_buffer_size); | |
| 480 | + d1, d0, dsp->dma_buffer_size); | |
| 435 | 481 | break; |
| 436 | 482 | |
| 437 | 483 | case 0xe0: |
| 484 | + d0 = dsp_get_data (dsp); | |
| 438 | 485 | dsp->out_data_len = 0; |
| 439 | - linfo ("data = %#x\n", dsp->in_data[0]); | |
| 440 | - dsp_out_data(dsp, dsp->in_data[0] ^ 0xff); | |
| 486 | + linfo ("data = %#x\n", d0); | |
| 487 | + dsp_out_data (dsp, d0 ^ 0xff); | |
| 488 | + break; | |
| 489 | + | |
| 490 | + case 0xe4: | |
| 491 | + dsp->test_reg = dsp_get_data (dsp); | |
| 492 | + break; | |
| 493 | + | |
| 494 | + | |
| 495 | + case 0xf9: | |
| 496 | + d0 = dsp_get_data (dsp); | |
| 497 | + ldebug ("f9 <- %#x\n", d0); | |
| 498 | + switch (d0) { | |
| 499 | + case 0x0e: dsp_out_data (dsp, 0xff); break; | |
| 500 | + case 0x0f: dsp_out_data (dsp, 0x07); break; | |
| 501 | + case 0xf9: dsp_out_data (dsp, 0x00); break; | |
| 502 | + case 0x37: | |
| 503 | + dsp_out_data (dsp, 0x38); break; | |
| 504 | + default: | |
| 505 | + dsp_out_data (dsp, 0); | |
| 506 | + } | |
| 441 | 507 | break; |
| 442 | 508 | |
| 443 | 509 | default: |
| 444 | - log ("unrecognized command %#x", dsp->cmd); | |
| 510 | + dolog ("complete: unrecognized command %#x\n", dsp->cmd); | |
| 445 | 511 | return; |
| 446 | 512 | } |
| 447 | 513 | } |
| 448 | 514 | |
| 515 | + dsp->needed_bytes = 0; | |
| 449 | 516 | dsp->cmd = -1; |
| 450 | 517 | return; |
| 451 | 518 | } |
| ... | ... | @@ -457,7 +524,7 @@ static IO_WRITE_PROTO (dsp_write) |
| 457 | 524 | |
| 458 | 525 | iport = nport - sb.port; |
| 459 | 526 | |
| 460 | - ldebug ("write %#x %#x\n", nport, iport); | |
| 527 | + ldebug ("dsp_write %#x <- %#x\n", nport, val); | |
| 461 | 528 | switch (iport) { |
| 462 | 529 | case 0x6: |
| 463 | 530 | control (0); |
| ... | ... | @@ -465,6 +532,14 @@ static IO_WRITE_PROTO (dsp_write) |
| 465 | 532 | dsp->v2x6 = 0; |
| 466 | 533 | else if ((1 == val) && (0 == dsp->v2x6)) { |
| 467 | 534 | dsp->v2x6 = 1; |
| 535 | + dsp->dma_pos = 0; | |
| 536 | + dsp->dma_auto = 0; | |
| 537 | + dsp->in_index = 0; | |
| 538 | + dsp->out_data_len = 0; | |
| 539 | + dsp->left_till_irq = 0; | |
| 540 | + dsp->speaker = 0; | |
| 541 | + dsp->needed_bytes = 0; | |
| 542 | + pic_set_irq (sb.irq, 0); | |
| 468 | 543 | dsp_out_data(dsp, 0xaa); |
| 469 | 544 | } |
| 470 | 545 | else |
| ... | ... | @@ -479,18 +554,22 @@ static IO_WRITE_PROTO (dsp_write) |
| 479 | 554 | } |
| 480 | 555 | } |
| 481 | 556 | else { |
| 482 | - dsp->in_data[dsp->in_index++] = val; | |
| 557 | + if (dsp->in_index == sizeof (dsp->in2_data)) { | |
| 558 | + dolog ("in data overrun\n"); | |
| 559 | + } | |
| 560 | + else { | |
| 561 | + dsp->in2_data[dsp->in_index++] = val; | |
| 483 | 562 | if (dsp->in_index == dsp->needed_bytes) { |
| 484 | 563 | dsp->needed_bytes = 0; |
| 485 | - dsp->in_index = 0; | |
| 486 | 564 | complete (dsp); |
| 487 | 565 | log_dsp (dsp); |
| 488 | 566 | } |
| 489 | 567 | } |
| 568 | + } | |
| 490 | 569 | break; |
| 491 | 570 | |
| 492 | 571 | default: |
| 493 | - log ("(nport=%#x, val=%#x)", nport, val); | |
| 572 | + dolog ("dsp_write (nport=%#x, val=%#x)\n", nport, val); | |
| 494 | 573 | break; |
| 495 | 574 | } |
| 496 | 575 | } |
| ... | ... | @@ -503,31 +582,36 @@ static IO_READ_PROTO (dsp_read) |
| 503 | 582 | iport = nport - sb.port; |
| 504 | 583 | |
| 505 | 584 | switch (iport) { |
| 506 | - | |
| 507 | 585 | case 0x6: /* reset */ |
| 508 | - return 0; | |
| 586 | + control (0); | |
| 587 | + retval = 0; | |
| 588 | + dsp->speaker = 0; | |
| 589 | + break; | |
| 509 | 590 | |
| 510 | 591 | case 0xa: /* read data */ |
| 511 | 592 | if (dsp->out_data_len) { |
| 512 | 593 | retval = dsp->out_data[--dsp->out_data_len]; |
| 594 | + dsp->last_read_byte = retval; | |
| 513 | 595 | } else { |
| 514 | - log("empty output buffer"); | |
| 515 | - goto error; | |
| 596 | + retval = dsp->last_read_byte; | |
| 597 | + dolog ("empty output buffer\n"); | |
| 598 | + /* goto error; */ | |
| 516 | 599 | } |
| 517 | 600 | break; |
| 518 | 601 | |
| 519 | - case 0xc: /* 0 can write */ | |
| 602 | + case 0xc: /* 0xxxxxxx can write */ | |
| 520 | 603 | retval = 0; |
| 604 | + if (dsp->out_data_len == sizeof (dsp->out_data)) retval |= 0x80; | |
| 521 | 605 | break; |
| 522 | 606 | |
| 523 | 607 | case 0xd: /* timer interrupt clear */ |
| 524 | - log("timer interrupt clear"); | |
| 608 | + dolog ("timer interrupt clear\n"); | |
| 525 | 609 | goto error; |
| 526 | 610 | |
| 527 | 611 | case 0xe: /* data available status | irq 8 ack */ |
| 528 | 612 | /* XXX drop pic irq line here? */ |
| 529 | - ldebug ("8 ack\n"); | |
| 530 | - retval = (0 == dsp->out_data_len) ? 0 : 0x80; | |
| 613 | + /* ldebug ("8 ack\n"); */ | |
| 614 | + retval = dsp->out_data_len ? 0x80 : 0; | |
| 531 | 615 | dsp->mixer_regs[0x82] &= ~dsp->mixer_regs[0x80]; |
| 532 | 616 | pic_set_irq (sb.irq, 0); |
| 533 | 617 | break; |
| ... | ... | @@ -544,15 +628,30 @@ static IO_READ_PROTO (dsp_read) |
| 544 | 628 | goto error; |
| 545 | 629 | } |
| 546 | 630 | |
| 547 | - if ((0xc != iport) && (0xe != iport)) { | |
| 548 | - ldebug ("nport=%#x iport %#x = %#x\n", | |
| 631 | + if (0xe == iport) { | |
| 632 | + if (0 == retval) { | |
| 633 | + if (!dsp->nzero) { | |
| 634 | + ldebug ("dsp_read (nport=%#x iport %#x) = %#x, %lld\n", | |
| 635 | + nport, iport, retval, dsp->nzero); | |
| 636 | + } | |
| 637 | + dsp->nzero += 1; | |
| 638 | + } | |
| 639 | + else { | |
| 640 | + ldebug ("dsp_read (nport=%#x iport %#x) = %#x, %lld\n", | |
| 641 | + nport, iport, retval, dsp->nzero); | |
| 642 | + dsp->nzero = 0; | |
| 643 | + } | |
| 644 | + } | |
| 645 | + else { | |
| 646 | + ldebug ("dsp_read (nport=%#x iport %#x) = %#x\n", | |
| 549 | 647 | nport, iport, retval); |
| 550 | 648 | } |
| 551 | 649 | |
| 552 | 650 | return retval; |
| 553 | 651 | |
| 554 | 652 | error: |
| 555 | - return 0; | |
| 653 | + printf ("dsp_read error %#x\n", nport); | |
| 654 | + return 0xff; | |
| 556 | 655 | } |
| 557 | 656 | |
| 558 | 657 | static IO_WRITE_PROTO(mixer_write_indexb) |
| ... | ... | @@ -564,12 +663,100 @@ static IO_WRITE_PROTO(mixer_write_indexb) |
| 564 | 663 | static IO_WRITE_PROTO(mixer_write_datab) |
| 565 | 664 | { |
| 566 | 665 | SB16State *dsp = opaque; |
| 666 | + int i; | |
| 567 | 667 | |
| 568 | - if (dsp->mixer_nreg > 0x83) | |
| 668 | + linfo ("mixer [%#x] <- %#x\n", dsp->mixer_nreg, val); | |
| 669 | + switch (dsp->mixer_nreg) { | |
| 670 | + case 0x00: | |
| 671 | + /* Bochs */ | |
| 672 | + dsp->mixer_regs[0x04] = 0xcc; | |
| 673 | + dsp->mixer_regs[0x0a] = 0x00; | |
| 674 | + dsp->mixer_regs[0x22] = 0xcc; | |
| 675 | + dsp->mixer_regs[0x26] = 0xcc; | |
| 676 | + dsp->mixer_regs[0x28] = 0x00; | |
| 677 | + dsp->mixer_regs[0x2e] = 0x00; | |
| 678 | + dsp->mixer_regs[0x3c] = 0x1f; | |
| 679 | + dsp->mixer_regs[0x3d] = 0x15; | |
| 680 | + dsp->mixer_regs[0x3e] = 0x0b; | |
| 681 | + | |
| 682 | + for (i = 0x30; i <= 0x35; i++) | |
| 683 | + dsp->mixer_regs[i] = 0xc0; | |
| 684 | + | |
| 685 | + for (i = 0x36; i <= 0x3b; i++) | |
| 686 | + dsp->mixer_regs[i] = 0x00; | |
| 687 | + | |
| 688 | + for (i = 0x3f; i <= 0x43; i++) | |
| 689 | + dsp->mixer_regs[i] = 0x00; | |
| 690 | + | |
| 691 | + for (i = 0x44; i <= 0x47; i++) | |
| 692 | + dsp->mixer_regs[i] = 0x80; | |
| 693 | + | |
| 694 | + for (i = 0x30; i < 0x48; i++) { | |
| 695 | + dsp->mixer_regs[i] = 0x20; | |
| 696 | + } | |
| 697 | + break; | |
| 698 | + | |
| 699 | + case 0x04: | |
| 700 | + case 0x0a: | |
| 701 | + case 0x22: | |
| 702 | + case 0x26: | |
| 703 | + case 0x28: | |
| 704 | + case 0x2e: | |
| 705 | + case 0x30: | |
| 706 | + case 0x31: | |
| 707 | + case 0x32: | |
| 708 | + case 0x33: | |
| 709 | + case 0x34: | |
| 710 | + case 0x35: | |
| 711 | + case 0x36: | |
| 712 | + case 0x37: | |
| 713 | + case 0x38: | |
| 714 | + case 0x39: | |
| 715 | + case 0x3a: | |
| 716 | + case 0x3b: | |
| 717 | + case 0x3c: | |
| 718 | + case 0x3d: | |
| 719 | + case 0x3e: | |
| 720 | + case 0x3f: | |
| 721 | + case 0x40: | |
| 722 | + case 0x41: | |
| 723 | + case 0x42: | |
| 724 | + case 0x43: | |
| 725 | + case 0x44: | |
| 726 | + case 0x45: | |
| 727 | + case 0x46: | |
| 728 | + case 0x47: | |
| 729 | + case 0x80: | |
| 730 | + case 0x81: | |
| 731 | + break; | |
| 732 | + default: | |
| 569 | 733 | return; |
| 734 | + } | |
| 570 | 735 | dsp->mixer_regs[dsp->mixer_nreg] = val; |
| 571 | 736 | } |
| 572 | 737 | |
| 738 | +static IO_WRITE_PROTO(mpu_write) | |
| 739 | +{ | |
| 740 | + linfo ("mpu: %#x\n", val); | |
| 741 | +} | |
| 742 | + | |
| 743 | +static IO_WRITE_PROTO(adlib_write) | |
| 744 | +{ | |
| 745 | + linfo ("adlib: %#x\n", val); | |
| 746 | +} | |
| 747 | + | |
| 748 | +static IO_READ_PROTO(mpu_read) | |
| 749 | +{ | |
| 750 | + linfo ("mpu read: %#x\n", nport); | |
| 751 | + return 0x80; | |
| 752 | +} | |
| 753 | + | |
| 754 | +static IO_READ_PROTO(adlib_read) | |
| 755 | +{ | |
| 756 | + linfo ("adlib read: %#x\n", nport); | |
| 757 | + return 0; | |
| 758 | +} | |
| 759 | + | |
| 573 | 760 | static IO_WRITE_PROTO(mixer_write_indexw) |
| 574 | 761 | { |
| 575 | 762 | mixer_write_indexb (opaque, nport, val & 0xff); |
| ... | ... | @@ -579,6 +766,7 @@ static IO_WRITE_PROTO(mixer_write_indexw) |
| 579 | 766 | static IO_READ_PROTO(mixer_read) |
| 580 | 767 | { |
| 581 | 768 | SB16State *dsp = opaque; |
| 769 | + linfo ("mixer [%#x] -> %#x\n", dsp->mixer_nreg, dsp->mixer_regs[dsp->mixer_nreg]); | |
| 582 | 770 | return dsp->mixer_regs[dsp->mixer_nreg]; |
| 583 | 771 | } |
| 584 | 772 | |
| ... | ... | @@ -637,6 +825,8 @@ static int SB_read_DMA (void *opaque, target_ulong addr, int size) |
| 637 | 825 | return 0; |
| 638 | 826 | |
| 639 | 827 | if (dsp->left_till_irq < 0) { |
| 828 | + ldebug ("left_till_irq < 0, %d, pos %d \n", | |
| 829 | + dsp->left_till_irq, dsp->dma_buffer_size); | |
| 640 | 830 | dsp->left_till_irq += dsp->dma_buffer_size; |
| 641 | 831 | return dsp->dma_pos; |
| 642 | 832 | } |
| ... | ... | @@ -644,6 +834,7 @@ static int SB_read_DMA (void *opaque, target_ulong addr, int size) |
| 644 | 834 | free = AUD_get_free (); |
| 645 | 835 | |
| 646 | 836 | if ((free <= 0) || (0 == size)) { |
| 837 | + ldebug ("returning, since free = %d and size = %d\n", free, size); | |
| 647 | 838 | return dsp->dma_pos; |
| 648 | 839 | } |
| 649 | 840 | |
| ... | ... | @@ -656,8 +847,11 @@ static int SB_read_DMA (void *opaque, target_ulong addr, int size) |
| 656 | 847 | |
| 657 | 848 | till = dsp->left_till_irq; |
| 658 | 849 | |
| 850 | +#ifdef DEBUG_SB16_MOST | |
| 659 | 851 | ldebug ("addr:%#010x free:%d till:%d size:%d\n", |
| 660 | 852 | addr, free, till, size); |
| 853 | +#endif | |
| 854 | + | |
| 661 | 855 | if (till <= copy) { |
| 662 | 856 | if (0 == dsp->dma_auto) { |
| 663 | 857 | copy = till; |
| ... | ... | @@ -671,7 +865,8 @@ static int SB_read_DMA (void *opaque, target_ulong addr, int size) |
| 671 | 865 | if (dsp->left_till_irq <= 0) { |
| 672 | 866 | dsp->mixer_regs[0x82] |= dsp->mixer_regs[0x80]; |
| 673 | 867 | if (0 == noirq) { |
| 674 | - ldebug ("request irq\n"); | |
| 868 | + ldebug ("request irq pos %d, left %d\n", | |
| 869 | + dsp->dma_pos, dsp->left_till_irq); | |
| 675 | 870 | pic_set_irq(sb.irq, 1); |
| 676 | 871 | } |
| 677 | 872 | |
| ... | ... | @@ -680,9 +875,11 @@ static int SB_read_DMA (void *opaque, target_ulong addr, int size) |
| 680 | 875 | } |
| 681 | 876 | } |
| 682 | 877 | |
| 878 | +#ifdef DEBUG_SB16_MOST | |
| 683 | 879 | ldebug ("pos %5d free %5d size %5d till % 5d copy %5d dma size %5d\n", |
| 684 | 880 | dsp->dma_pos, free, size, dsp->left_till_irq, copy, |
| 685 | 881 | dsp->dma_buffer_size); |
| 882 | +#endif | |
| 686 | 883 | |
| 687 | 884 | if (dsp->left_till_irq <= 0) { |
| 688 | 885 | dsp->left_till_irq += dsp->dma_buffer_size; |
| ... | ... | @@ -703,7 +900,7 @@ static int magic_of_irq (int irq) |
| 703 | 900 | case 10: |
| 704 | 901 | return 8; |
| 705 | 902 | default: |
| 706 | - log ("bad irq %d", irq); | |
| 903 | + dolog ("bad irq %d\n", irq); | |
| 707 | 904 | return 2; |
| 708 | 905 | } |
| 709 | 906 | } |
| ... | ... | @@ -721,12 +918,42 @@ static int irq_of_magic (int magic) |
| 721 | 918 | case 8: |
| 722 | 919 | return 10; |
| 723 | 920 | default: |
| 724 | - log ("bad irq magic %d", magic); | |
| 921 | + dolog ("bad irq magic %d\n", magic); | |
| 725 | 922 | return 2; |
| 726 | 923 | } |
| 727 | 924 | } |
| 728 | 925 | #endif |
| 729 | 926 | |
| 927 | +#ifdef SB16_TRAP_ALL | |
| 928 | +static IO_READ_PROTO (trap_read) | |
| 929 | +{ | |
| 930 | + switch (nport) { | |
| 931 | + case 0x220: | |
| 932 | + return 0; | |
| 933 | + case 0x226: | |
| 934 | + case 0x22a: | |
| 935 | + case 0x22c: | |
| 936 | + case 0x22d: | |
| 937 | + case 0x22e: | |
| 938 | + case 0x22f: | |
| 939 | + return dsp_read (opaque, nport); | |
| 940 | + } | |
| 941 | + linfo ("trap_read: %#x\n", nport); | |
| 942 | + return 0xff; | |
| 943 | +} | |
| 944 | + | |
| 945 | +static IO_WRITE_PROTO (trap_write) | |
| 946 | +{ | |
| 947 | + switch (nport) { | |
| 948 | + case 0x226: | |
| 949 | + case 0x22c: | |
| 950 | + dsp_write (opaque, nport, val); | |
| 951 | + return; | |
| 952 | + } | |
| 953 | + linfo ("trap_write: %#x = %#x\n", nport, val); | |
| 954 | +} | |
| 955 | +#endif | |
| 956 | + | |
| 730 | 957 | void SB16_init (void) |
| 731 | 958 | { |
| 732 | 959 | SB16State *s = &dsp; |
| ... | ... | @@ -736,13 +963,23 @@ void SB16_init (void) |
| 736 | 963 | |
| 737 | 964 | memset(s->mixer_regs, 0xff, sizeof(s->mixer_regs)); |
| 738 | 965 | |
| 966 | + s->mixer_regs[0x00] = 0; | |
| 739 | 967 | s->mixer_regs[0x0e] = ~0; |
| 740 | 968 | s->mixer_regs[0x80] = magic_of_irq (sb.irq); |
| 741 | - s->mixer_regs[0x81] = 0x20 | (sb.dma << 1); | |
| 742 | - | |
| 743 | - for (i = 0x30; i < 0x48; i++) { | |
| 744 | - s->mixer_regs[i] = 0x20; | |
| 969 | + s->mixer_regs[0x81] = 0x80 | 0x10 | (sb.dma << 1); | |
| 970 | + s->mixer_regs[0x82] = 0; | |
| 971 | + s->mixer_regs[0xfd] = 16; /* bochs */ | |
| 972 | + s->mixer_regs[0xfe] = 6; /* bochs */ | |
| 973 | + mixer_write_indexw (s, 0x224, 0); | |
| 974 | + | |
| 975 | +#ifdef SB16_TRAP_ALL | |
| 976 | + for (i = 0; i < 0x100; i++) { | |
| 977 | + if (i != 4 && i != 5) { | |
| 978 | + register_ioport_write (sb.port + i, 1, 1, trap_write, s); | |
| 979 | + register_ioport_read (sb.port + i, 1, 1, trap_read, s); | |
| 980 | + } | |
| 745 | 981 | } |
| 982 | +#else | |
| 746 | 983 | |
| 747 | 984 | for (i = 0; i < LENOFA (dsp_write_ports); i++) { |
| 748 | 985 | register_ioport_write (sb.port + dsp_write_ports[i], 1, 1, dsp_write, s); |
| ... | ... | @@ -751,12 +988,20 @@ void SB16_init (void) |
| 751 | 988 | for (i = 0; i < LENOFA (dsp_read_ports); i++) { |
| 752 | 989 | register_ioport_read (sb.port + dsp_read_ports[i], 1, 1, dsp_read, s); |
| 753 | 990 | } |
| 991 | +#endif | |
| 754 | 992 | |
| 755 | 993 | register_ioport_write (sb.port + 0x4, 1, 1, mixer_write_indexb, s); |
| 756 | 994 | register_ioport_write (sb.port + 0x4, 1, 2, mixer_write_indexw, s); |
| 757 | 995 | register_ioport_read (sb.port + 0x5, 1, 1, mixer_read, s); |
| 758 | 996 | register_ioport_write (sb.port + 0x5, 1, 1, mixer_write_datab, s); |
| 759 | 997 | |
| 998 | + for (i = 0; 4 < 4; i++) { | |
| 999 | + register_ioport_read (0x330 + i, 1, 1, mpu_read, s); | |
| 1000 | + register_ioport_write (0x330 + i, 1, 1, mpu_write, s); | |
| 1001 | + register_ioport_read (0x388 + i, 1, 1, adlib_read, s); | |
| 1002 | + register_ioport_write (0x388 + i, 1, 1, adlib_write, s); | |
| 1003 | + } | |
| 1004 | + | |
| 760 | 1005 | DMA_register_channel (sb.hdma, SB_read_DMA, s); |
| 761 | 1006 | DMA_register_channel (sb.dma, SB_read_DMA, s); |
| 762 | 1007 | } | ... | ... |
oss.c
| ... | ... | @@ -23,22 +23,446 @@ |
| 23 | 23 | */ |
| 24 | 24 | #include "vl.h" |
| 25 | 25 | |
| 26 | -#if !defined(_WIN32) && !defined(__APPLE__) | |
| 27 | -#include <ctype.h> | |
| 26 | +#include <stdio.h> | |
| 27 | +#include <limits.h> | |
| 28 | +#include <stdlib.h> | |
| 29 | +#include <string.h> | |
| 30 | + | |
| 31 | +/* TODO: Graceful error handling */ | |
| 32 | + | |
| 33 | +#if defined(_WIN32) | |
| 34 | +#define USE_SDL_AUDIO | |
| 35 | +#endif | |
| 36 | + | |
| 37 | +#define MIN(a, b) ((a)>(b)?(b):(a)) | |
| 38 | +#define MAX(a, b) ((a)<(b)?(b):(a)) | |
| 39 | + | |
| 40 | +#define DEREF(x) (void)x | |
| 41 | +#define dolog(...) fprintf (stderr, "audio: " __VA_ARGS__) | |
| 42 | +#define ERRFail(...) do { \ | |
| 43 | + int _errno = errno; \ | |
| 44 | + fprintf (stderr, "audio: " __VA_ARGS__); \ | |
| 45 | + fprintf (stderr, "\nsystem error: %s\n", strerror (_errno)); \ | |
| 46 | + abort (); \ | |
| 47 | +} while (0) | |
| 48 | +#define Fail(...) do { \ | |
| 49 | + fprintf (stderr, "audio: " __VA_ARGS__); \ | |
| 50 | + fprintf (stderr, "\n"); \ | |
| 51 | + abort (); \ | |
| 52 | +} while (0) | |
| 53 | + | |
| 54 | +#ifdef DEBUG_AUDIO | |
| 55 | +#define lwarn(...) fprintf (stderr, "audio: " __VA_ARGS__) | |
| 56 | +#define linfo(...) fprintf (stderr, "audio: " __VA_ARGS__) | |
| 57 | +#define ldebug(...) fprintf (stderr, "audio: " __VA_ARGS__) | |
| 58 | +#else | |
| 59 | +#define lwarn(...) | |
| 60 | +#define linfo(...) | |
| 61 | +#define ldebug(...) | |
| 62 | +#endif | |
| 63 | + | |
| 64 | +static int get_conf_val (const char *key, int defval) | |
| 65 | +{ | |
| 66 | + int val = defval; | |
| 67 | + char *strval; | |
| 68 | + | |
| 69 | + strval = getenv (key); | |
| 70 | + if (strval) { | |
| 71 | + val = atoi (strval); | |
| 72 | + } | |
| 73 | + | |
| 74 | + return val; | |
| 75 | +} | |
| 76 | + | |
| 77 | +static void copy_no_conversion (void *dst, void *src, int size) | |
| 78 | +{ | |
| 79 | + memcpy (dst, src, size); | |
| 80 | +} | |
| 81 | + | |
| 82 | +static void copy_u16_to_s16 (void *dst, void *src, int size) | |
| 83 | +{ | |
| 84 | + int i; | |
| 85 | + uint16_t *out, *in; | |
| 86 | + | |
| 87 | + out = dst; | |
| 88 | + in = src; | |
| 89 | + | |
| 90 | + for (i = 0; i < size / 2; i++) { | |
| 91 | + out[i] = in[i] + 0x8000; | |
| 92 | + } | |
| 93 | +} | |
| 94 | + | |
| 95 | +#ifdef USE_SDL_AUDIO | |
| 96 | +#include <SDL/SDL.h> | |
| 97 | +#include <SDL/SDL_thread.h> | |
| 98 | + | |
| 99 | +static struct { | |
| 100 | + int samples; | |
| 101 | +} conf = { | |
| 102 | + .samples = 4096 | |
| 103 | +}; | |
| 104 | + | |
| 105 | +typedef struct AudioState { | |
| 106 | + int freq; | |
| 107 | + int bits16; | |
| 108 | + int nchannels; | |
| 109 | + int rpos; | |
| 110 | + int wpos; | |
| 111 | + volatile int live; | |
| 112 | + volatile int exit; | |
| 113 | + int bytes_per_second; | |
| 114 | + Uint8 *buf; | |
| 115 | + int bufsize; | |
| 116 | + int leftover; | |
| 117 | + uint64_t old_ticks; | |
| 118 | + SDL_AudioSpec spec; | |
| 119 | + SDL_mutex *mutex; | |
| 120 | + SDL_sem *sem; | |
| 121 | + void (*copy_fn)(void *, void *, int); | |
| 122 | +} AudioState; | |
| 123 | + | |
| 124 | +static AudioState sdl_audio; | |
| 125 | + | |
| 126 | +void AUD_run (void) | |
| 127 | +{ | |
| 128 | +} | |
| 129 | + | |
| 130 | +static void own (AudioState *s) | |
| 131 | +{ | |
| 132 | + /* SDL_LockAudio (); */ | |
| 133 | + if (SDL_mutexP (s->mutex)) | |
| 134 | + dolog ("SDL_mutexP: %s\n", SDL_GetError ()); | |
| 135 | +} | |
| 136 | + | |
| 137 | +static void disown (AudioState *s) | |
| 138 | +{ | |
| 139 | + /* SDL_UnlockAudio (); */ | |
| 140 | + if (SDL_mutexV (s->mutex)) | |
| 141 | + dolog ("SDL_mutexV: %s\n", SDL_GetError ()); | |
| 142 | +} | |
| 143 | + | |
| 144 | +static void sem_wait (AudioState *s) | |
| 145 | +{ | |
| 146 | + if (SDL_SemWait (s->sem)) | |
| 147 | + dolog ("SDL_SemWait: %s\n", SDL_GetError ()); | |
| 148 | +} | |
| 149 | + | |
| 150 | +static void sem_post (AudioState *s) | |
| 151 | +{ | |
| 152 | + if (SDL_SemPost (s->sem)) | |
| 153 | + dolog ("SDL_SemPost: %s\n", SDL_GetError ()); | |
| 154 | +} | |
| 155 | + | |
| 156 | +static void audio_callback (void *data, Uint8 *stream, int len) | |
| 157 | +{ | |
| 158 | + int to_mix; | |
| 159 | + AudioState *s = data; | |
| 160 | + | |
| 161 | + if (s->exit) return; | |
| 162 | + while (len) { | |
| 163 | + sem_wait (s); | |
| 164 | + if (s->exit) return; | |
| 165 | + own (s); | |
| 166 | + to_mix = MIN (len, s->live); | |
| 167 | + len -= to_mix; | |
| 168 | + /* printf ("to_mix=%d len=%d live=%d\n", to_mix, len, s->live); */ | |
| 169 | + while (to_mix) { | |
| 170 | + int chunk = MIN (to_mix, s->bufsize - s->rpos); | |
| 171 | + /* SDL_MixAudio (stream, buf, chunk, SDL_MIX_MAXVOLUME); */ | |
| 172 | + memcpy (stream, s->buf + s->rpos, chunk); | |
| 173 | + | |
| 174 | + s->rpos += chunk; | |
| 175 | + s->live -= chunk; | |
| 176 | + | |
| 177 | + stream += chunk; | |
| 178 | + to_mix -= chunk; | |
| 179 | + | |
| 180 | + if (s->rpos == s->bufsize) s->rpos = 0; | |
| 181 | + } | |
| 182 | + disown (s); | |
| 183 | + } | |
| 184 | +} | |
| 185 | + | |
| 186 | +static void sem_zero (AudioState *s) | |
| 187 | +{ | |
| 188 | + int res; | |
| 189 | + | |
| 190 | + do { | |
| 191 | + res = SDL_SemTryWait (s->sem); | |
| 192 | + if (res < 0) { | |
| 193 | + dolog ("SDL_SemTryWait: %s\n", SDL_GetError ()); | |
| 194 | + return; | |
| 195 | + } | |
| 196 | + } while (res != SDL_MUTEX_TIMEDOUT); | |
| 197 | +} | |
| 198 | + | |
| 199 | +static void do_open (AudioState *s) | |
| 200 | +{ | |
| 201 | + int status; | |
| 202 | + SDL_AudioSpec obtained; | |
| 203 | + | |
| 204 | + SDL_PauseAudio (1); | |
| 205 | + if (s->buf) { | |
| 206 | + s->exit = 1; | |
| 207 | + sem_post (s); | |
| 208 | + SDL_CloseAudio (); | |
| 209 | + s->exit = 0; | |
| 210 | + qemu_free (s->buf); | |
| 211 | + s->buf = NULL; | |
| 212 | + sem_zero (s); | |
| 213 | + } | |
| 214 | + | |
| 215 | + s->bytes_per_second = (s->spec.freq << (s->spec.channels >> 1)) << s->bits16; | |
| 216 | + s->spec.samples = conf.samples; | |
| 217 | + s->spec.userdata = s; | |
| 218 | + s->spec.callback = audio_callback; | |
| 219 | + | |
| 220 | + status = SDL_OpenAudio (&s->spec, &obtained); | |
| 221 | + if (status < 0) { | |
| 222 | + dolog ("SDL_OpenAudio: %s\n", SDL_GetError ()); | |
| 223 | + goto exit; | |
| 224 | + } | |
| 225 | + | |
| 226 | + if (obtained.freq != s->spec.freq || | |
| 227 | + obtained.channels != s->spec.channels || | |
| 228 | + obtained.format != s->spec.format) { | |
| 229 | + dolog ("Audio spec mismatch requested obtained\n" | |
| 230 | + "freq %5d %5d\n" | |
| 231 | + "channels %5d %5d\n" | |
| 232 | + "fmt %5d %5d\n", | |
| 233 | + s->spec.freq, obtained.freq, | |
| 234 | + s->spec.channels, obtained.channels, | |
| 235 | + s->spec.format, obtained.format | |
| 236 | + ); | |
| 237 | + } | |
| 238 | + | |
| 239 | + s->bufsize = obtained.size; | |
| 240 | + s->buf = qemu_mallocz (s->bufsize); | |
| 241 | + if (!s->buf) { | |
| 242 | + dolog ("qemu_mallocz(%d)\n", s->bufsize); | |
| 243 | + goto exit; | |
| 244 | + } | |
| 245 | + SDL_PauseAudio (0); | |
| 246 | + | |
| 247 | +exit: | |
| 248 | + s->rpos = 0; | |
| 249 | + s->wpos = 0; | |
| 250 | + s->live = 0; | |
| 251 | +} | |
| 252 | + | |
| 253 | +int AUD_write (void *in_buf, int size) | |
| 254 | +{ | |
| 255 | + AudioState *s = &sdl_audio; | |
| 256 | + int to_copy, temp; | |
| 257 | + uint8_t *in, *out; | |
| 258 | + | |
| 259 | + own (s); | |
| 260 | + to_copy = MIN (s->bufsize - s->live, size); | |
| 261 | + | |
| 262 | + temp = to_copy; | |
| 263 | + | |
| 264 | + in = in_buf; | |
| 265 | + out = s->buf; | |
| 266 | + | |
| 267 | + while (temp) { | |
| 268 | + int copy; | |
| 269 | + | |
| 270 | + copy = MIN (temp, s->bufsize - s->wpos); | |
| 271 | + s->copy_fn (out + s->wpos, in, copy); | |
| 272 | + | |
| 273 | + s->wpos += copy; | |
| 274 | + if (s->wpos == s->bufsize) { | |
| 275 | + s->wpos = 0; | |
| 276 | + } | |
| 277 | + | |
| 278 | + temp -= copy; | |
| 279 | + in += copy; | |
| 280 | + s->live += copy; | |
| 281 | + } | |
| 282 | + | |
| 283 | + disown (s); | |
| 284 | + sem_post (s); | |
| 285 | + return to_copy; | |
| 286 | +} | |
| 287 | + | |
| 288 | +static void maybe_open (AudioState *s, int req_freq, int req_nchannels, | |
| 289 | + audfmt_e req_fmt, int force_open) | |
| 290 | +{ | |
| 291 | + int sdl_fmt, bits16; | |
| 292 | + | |
| 293 | + switch (req_fmt) { | |
| 294 | + case AUD_FMT_U8: | |
| 295 | + bits16 = 0; | |
| 296 | + sdl_fmt = AUDIO_U8; | |
| 297 | + s->copy_fn = copy_no_conversion; | |
| 298 | + break; | |
| 299 | + | |
| 300 | + case AUD_FMT_S8: | |
| 301 | + fprintf (stderr, "audio: can not play 8bit signed\n"); | |
| 302 | + return; | |
| 303 | + | |
| 304 | + case AUD_FMT_S16: | |
| 305 | + bits16 = 1; | |
| 306 | + sdl_fmt = AUDIO_S16; | |
| 307 | + s->copy_fn = copy_no_conversion; | |
| 308 | + break; | |
| 309 | + | |
| 310 | + case AUD_FMT_U16: | |
| 311 | + bits16 = 1; | |
| 312 | + sdl_fmt = AUDIO_S16; | |
| 313 | + s->copy_fn = copy_u16_to_s16; | |
| 314 | + break; | |
| 315 | + | |
| 316 | + default: | |
| 317 | + abort (); | |
| 318 | + } | |
| 319 | + | |
| 320 | + if (force_open | |
| 321 | + || (NULL == s->buf) | |
| 322 | + || (sdl_fmt != s->spec.format) | |
| 323 | + || (req_nchannels != s->spec.channels) | |
| 324 | + || (req_freq != s->spec.freq) | |
| 325 | + || (bits16 != s->bits16)) { | |
| 326 | + | |
| 327 | + s->spec.format = sdl_fmt; | |
| 328 | + s->spec.channels = req_nchannels; | |
| 329 | + s->spec.freq = req_freq; | |
| 330 | + s->bits16 = bits16; | |
| 331 | + do_open (s); | |
| 332 | + } | |
| 333 | +} | |
| 334 | + | |
| 335 | +void AUD_reset (int req_freq, int req_nchannels, audfmt_e req_fmt) | |
| 336 | +{ | |
| 337 | + AudioState *s = &sdl_audio; | |
| 338 | + own (s); | |
| 339 | + maybe_open (s, req_freq, req_nchannels, req_fmt, 0); | |
| 340 | + disown (s); | |
| 341 | +} | |
| 342 | + | |
| 343 | +void AUD_open (int req_freq, int req_nchannels, audfmt_e req_fmt) | |
| 344 | +{ | |
| 345 | + AudioState *s = &sdl_audio; | |
| 346 | + own (s); | |
| 347 | + maybe_open (s, req_freq, req_nchannels, req_fmt, 1); | |
| 348 | + disown (s); | |
| 349 | +} | |
| 350 | + | |
| 351 | +void AUD_adjust_estimate (int leftover) | |
| 352 | +{ | |
| 353 | + AudioState *s = &sdl_audio; | |
| 354 | + own (s); | |
| 355 | + s->leftover = leftover; | |
| 356 | + disown (s); | |
| 357 | +} | |
| 358 | + | |
| 359 | +int AUD_get_free (void) | |
| 360 | +{ | |
| 361 | + int free, elapsed; | |
| 362 | + uint64_t ticks, delta; | |
| 363 | + uint64_t ua_elapsed; | |
| 364 | + uint64_t al_elapsed; | |
| 365 | + AudioState *s = &sdl_audio; | |
| 366 | + | |
| 367 | + own (s); | |
| 368 | + free = s->bufsize - s->live; | |
| 369 | + | |
| 370 | + if (0 == free) { | |
| 371 | + disown (s); | |
| 372 | + return 0; | |
| 373 | + } | |
| 374 | + | |
| 375 | + elapsed = free; | |
| 376 | + ticks = qemu_get_clock(rt_clock); | |
| 377 | + delta = ticks - s->old_ticks; | |
| 378 | + s->old_ticks = ticks; | |
| 379 | + | |
| 380 | + ua_elapsed = (delta * s->bytes_per_second) / 1000; | |
| 381 | + al_elapsed = ua_elapsed & ~3ULL; | |
| 382 | + | |
| 383 | + ldebug ("tid elapsed %llu bytes\n", ua_elapsed); | |
| 384 | + | |
| 385 | + if (al_elapsed > (uint64_t) INT_MAX) | |
| 386 | + elapsed = INT_MAX; | |
| 387 | + else | |
| 388 | + elapsed = al_elapsed; | |
| 389 | + | |
| 390 | + elapsed += s->leftover; | |
| 391 | + disown (s); | |
| 392 | + | |
| 393 | + if (elapsed > free) { | |
| 394 | + lwarn ("audio can not keep up elapsed %d free %d\n", elapsed, free); | |
| 395 | + return free; | |
| 396 | + } | |
| 397 | + else { | |
| 398 | + return elapsed; | |
| 399 | + } | |
| 400 | +} | |
| 401 | + | |
| 402 | +int AUD_get_live (void) | |
| 403 | +{ | |
| 404 | + int live; | |
| 405 | + AudioState *s = &sdl_audio; | |
| 406 | + | |
| 407 | + own (s); | |
| 408 | + live = s->live; | |
| 409 | + disown (s); | |
| 410 | + return live; | |
| 411 | +} | |
| 412 | + | |
| 413 | +int AUD_get_buffer_size (void) | |
| 414 | +{ | |
| 415 | + int bufsize; | |
| 416 | + AudioState *s = &sdl_audio; | |
| 417 | + | |
| 418 | + own (s); | |
| 419 | + bufsize = s->bufsize; | |
| 420 | + disown (s); | |
| 421 | + return bufsize; | |
| 422 | +} | |
| 423 | + | |
| 424 | +#define QC_SDL_NSAMPLES "QEMU_SDL_NSAMPLES" | |
| 425 | + | |
| 426 | +static void cleanup (void) | |
| 427 | +{ | |
| 428 | + AudioState *s = &sdl_audio; | |
| 429 | + own (s); | |
| 430 | + s->exit = 1; | |
| 431 | + sem_post (s); | |
| 432 | + disown (s); | |
| 433 | +} | |
| 434 | + | |
| 435 | +void AUD_init (void) | |
| 436 | +{ | |
| 437 | + AudioState *s = &sdl_audio; | |
| 438 | + | |
| 439 | + atexit (cleanup); | |
| 440 | + SDL_InitSubSystem (SDL_INIT_AUDIO); | |
| 441 | + s->mutex = SDL_CreateMutex (); | |
| 442 | + if (!s->mutex) { | |
| 443 | + dolog ("SDL_CreateMutex: %s\n", SDL_GetError ()); | |
| 444 | + return; | |
| 445 | + } | |
| 446 | + | |
| 447 | + s->sem = SDL_CreateSemaphore (0); | |
| 448 | + if (!s->sem) { | |
| 449 | + dolog ("SDL_CreateSemaphore: %s\n", SDL_GetError ()); | |
| 450 | + return; | |
| 451 | + } | |
| 452 | + | |
| 453 | + conf.samples = get_conf_val (QC_SDL_NSAMPLES, conf.samples); | |
| 454 | +} | |
| 455 | + | |
| 456 | +#elif !defined(_WIN32) && !defined(__APPLE__) | |
| 457 | + | |
| 28 | 458 | #include <fcntl.h> |
| 29 | 459 | #include <errno.h> |
| 30 | -#include <stdio.h> | |
| 31 | 460 | #include <unistd.h> |
| 32 | -#include <string.h> | |
| 33 | -#include <stdlib.h> | |
| 34 | -#include <limits.h> | |
| 35 | -#include <inttypes.h> | |
| 36 | 461 | #include <sys/mman.h> |
| 37 | 462 | #include <sys/types.h> |
| 38 | 463 | #include <sys/ioctl.h> |
| 39 | 464 | #include <sys/soundcard.h> |
| 40 | 465 | |
| 41 | - | |
| 42 | 466 | /* http://www.df.lth.se/~john_e/gems/gem002d.html */ |
| 43 | 467 | /* http://www.multi-platforms.com/Tips/PopCount.htm */ |
| 44 | 468 | static inline uint32_t popcount (uint32_t u) |
| ... | ... | @@ -56,34 +480,6 @@ static inline uint32_t lsbindex (uint32_t u) |
| 56 | 480 | return popcount ((u&-u)-1); |
| 57 | 481 | } |
| 58 | 482 | |
| 59 | -#define MIN(a, b) ((a)>(b)?(b):(a)) | |
| 60 | -#define MAX(a, b) ((a)<(b)?(b):(a)) | |
| 61 | - | |
| 62 | -#define DEREF(x) (void)x | |
| 63 | -#define log(...) fprintf (stderr, "oss: " __VA_ARGS__) | |
| 64 | -#define ERRFail(...) do { \ | |
| 65 | - int _errno = errno; \ | |
| 66 | - fprintf (stderr, "oss: " __VA_ARGS__); \ | |
| 67 | - fprintf (stderr, "system error: %s\n", strerror (_errno)); \ | |
| 68 | - abort (); \ | |
| 69 | -} while (0) | |
| 70 | -#define Fail(...) do { \ | |
| 71 | - fprintf (stderr, "oss: " __VA_ARGS__); \ | |
| 72 | - fprintf (stderr, "\n"); \ | |
| 73 | - abort (); \ | |
| 74 | -} while (0) | |
| 75 | - | |
| 76 | -#ifdef DEBUG_OSS | |
| 77 | -#define lwarn(...) fprintf (stderr, "oss: " __VA_ARGS__) | |
| 78 | -#define linfo(...) fprintf (stderr, "oss: " __VA_ARGS__) | |
| 79 | -#define ldebug(...) fprintf (stderr, "oss: " __VA_ARGS__) | |
| 80 | -#else | |
| 81 | -#define lwarn(...) | |
| 82 | -#define linfo(...) | |
| 83 | -#define ldebug(...) | |
| 84 | -#endif | |
| 85 | - | |
| 86 | - | |
| 87 | 483 | #define IOCTL(args) do { \ |
| 88 | 484 | int ret = ioctl args; \ |
| 89 | 485 | if (-1 == ret) { \ |
| ... | ... | @@ -92,7 +488,7 @@ static inline uint32_t lsbindex (uint32_t u) |
| 92 | 488 | ldebug ("ioctl " #args " = %d\n", ret); \ |
| 93 | 489 | } while (0) |
| 94 | 490 | |
| 95 | -static struct { | |
| 491 | +typedef struct AudioState { | |
| 96 | 492 | int fd; |
| 97 | 493 | int freq; |
| 98 | 494 | int bits16; |
| ... | ... | @@ -111,7 +507,9 @@ static struct { |
| 111 | 507 | int leftover; |
| 112 | 508 | uint64_t old_ticks; |
| 113 | 509 | void (*copy_fn)(void *, void *, int); |
| 114 | -} oss = { .fd = -1 }; | |
| 510 | +} AudioState; | |
| 511 | + | |
| 512 | +static AudioState oss_audio = { .fd = -1 }; | |
| 115 | 513 | |
| 116 | 514 | static struct { |
| 117 | 515 | int try_mmap; |
| ... | ... | @@ -125,25 +523,7 @@ static struct { |
| 125 | 523 | |
| 126 | 524 | static enum {DONT, DSP, TID} est = DONT; |
| 127 | 525 | |
| 128 | -static void copy_no_conversion (void *dst, void *src, int size) | |
| 129 | -{ | |
| 130 | - memcpy (dst, src, size); | |
| 131 | -} | |
| 132 | - | |
| 133 | -static void copy_u16_to_s16 (void *dst, void *src, int size) | |
| 134 | -{ | |
| 135 | - int i; | |
| 136 | - uint16_t *out, *in; | |
| 137 | - | |
| 138 | - out = dst; | |
| 139 | - in = src; | |
| 140 | - | |
| 141 | - for (i = 0; i < size / 2; i++) { | |
| 142 | - out[i] = in[i] + 0x8000; | |
| 143 | - } | |
| 144 | -} | |
| 145 | - | |
| 146 | -static void pab (struct audio_buf_info *abinfo) | |
| 526 | +static void pab (AudioState *s, struct audio_buf_info *abinfo) | |
| 147 | 527 | { |
| 148 | 528 | DEREF (abinfo); |
| 149 | 529 | |
| ... | ... | @@ -153,118 +533,122 @@ static void pab (struct audio_buf_info *abinfo) |
| 153 | 533 | abinfo->fragstotal, |
| 154 | 534 | abinfo->fragsize, |
| 155 | 535 | abinfo->bytes, |
| 156 | - rpos, wpos, live); | |
| 536 | + s->rpos, s->wpos, s->live); | |
| 157 | 537 | } |
| 158 | 538 | |
| 159 | -static void do_open () | |
| 539 | +static void do_open (AudioState *s) | |
| 160 | 540 | { |
| 161 | 541 | int mmmmssss; |
| 162 | 542 | audio_buf_info abinfo; |
| 163 | 543 | int fmt, freq, nchannels; |
| 164 | 544 | |
| 165 | - if (oss.buf) { | |
| 166 | - if (-1 == munmap (oss.buf, oss.bufsize)) { | |
| 545 | + if (s->buf) { | |
| 546 | + if (s->is_mapped) { | |
| 547 | + if (-1 == munmap (s->buf, s->bufsize)) { | |
| 167 | 548 | ERRFail ("failed to unmap audio buffer %p %d", |
| 168 | - oss.buf, oss.bufsize); | |
| 549 | + s->buf, s->bufsize); | |
| 550 | + } | |
| 169 | 551 | } |
| 170 | - oss.buf = NULL; | |
| 552 | + else { | |
| 553 | + qemu_free (s->buf); | |
| 554 | + } | |
| 555 | + s->buf = NULL; | |
| 171 | 556 | } |
| 172 | 557 | |
| 173 | - if (-1 != oss.fd) | |
| 174 | - close (oss.fd); | |
| 558 | + if (-1 != s->fd) | |
| 559 | + close (s->fd); | |
| 175 | 560 | |
| 176 | - oss.fd = open ("/dev/dsp", O_RDWR | O_NONBLOCK); | |
| 177 | - if (-1 == oss.fd) { | |
| 561 | + s->fd = open ("/dev/dsp", O_RDWR | O_NONBLOCK); | |
| 562 | + if (-1 == s->fd) { | |
| 178 | 563 | ERRFail ("can not open /dev/dsp"); |
| 179 | 564 | } |
| 180 | 565 | |
| 181 | - fmt = oss.oss_fmt; | |
| 182 | - freq = oss.freq; | |
| 183 | - nchannels = oss.nchannels; | |
| 566 | + fmt = s->oss_fmt; | |
| 567 | + freq = s->freq; | |
| 568 | + nchannels = s->nchannels; | |
| 184 | 569 | |
| 185 | - IOCTL ((oss.fd, SNDCTL_DSP_RESET, 1)); | |
| 186 | - IOCTL ((oss.fd, SNDCTL_DSP_SAMPLESIZE, &fmt)); | |
| 187 | - IOCTL ((oss.fd, SNDCTL_DSP_CHANNELS, &nchannels)); | |
| 188 | - IOCTL ((oss.fd, SNDCTL_DSP_SPEED, &freq)); | |
| 189 | - IOCTL ((oss.fd, SNDCTL_DSP_NONBLOCK)); | |
| 570 | + IOCTL ((s->fd, SNDCTL_DSP_RESET, 1)); | |
| 571 | + IOCTL ((s->fd, SNDCTL_DSP_SAMPLESIZE, &fmt)); | |
| 572 | + IOCTL ((s->fd, SNDCTL_DSP_CHANNELS, &nchannels)); | |
| 573 | + IOCTL ((s->fd, SNDCTL_DSP_SPEED, &freq)); | |
| 574 | + IOCTL ((s->fd, SNDCTL_DSP_NONBLOCK)); | |
| 190 | 575 | |
| 191 | 576 | mmmmssss = (conf.nfrags << 16) | conf.fragsize; |
| 192 | - IOCTL ((oss.fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)); | |
| 577 | + IOCTL ((s->fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)); | |
| 193 | 578 | |
| 194 | - if ((oss.oss_fmt != fmt) | |
| 195 | - || (oss.nchannels != nchannels) | |
| 196 | - || (oss.freq != freq)) { | |
| 579 | + if ((s->oss_fmt != fmt) | |
| 580 | + || (s->nchannels != nchannels) | |
| 581 | + || (s->freq != freq)) { | |
| 197 | 582 | Fail ("failed to set audio parameters\n" |
| 198 | 583 | "parameter | requested value | obtained value\n" |
| 199 | 584 | "format | %10d | %10d\n" |
| 200 | 585 | "channels | %10d | %10d\n" |
| 201 | 586 | "frequency | %10d | %10d\n", |
| 202 | - oss.oss_fmt, fmt, | |
| 203 | - oss.nchannels, nchannels, | |
| 204 | - oss.freq, freq); | |
| 587 | + s->oss_fmt, fmt, | |
| 588 | + s->nchannels, nchannels, | |
| 589 | + s->freq, freq); | |
| 205 | 590 | } |
| 206 | 591 | |
| 207 | - IOCTL ((oss.fd, SNDCTL_DSP_GETOSPACE, &abinfo)); | |
| 592 | + IOCTL ((s->fd, SNDCTL_DSP_GETOSPACE, &abinfo)); | |
| 208 | 593 | |
| 209 | - oss.nfrags = abinfo.fragstotal; | |
| 210 | - oss.fragsize = abinfo.fragsize; | |
| 211 | - oss.bufsize = oss.nfrags * oss.fragsize; | |
| 212 | - oss.old_optr = 0; | |
| 594 | + s->nfrags = abinfo.fragstotal; | |
| 595 | + s->fragsize = abinfo.fragsize; | |
| 596 | + s->bufsize = s->nfrags * s->fragsize; | |
| 597 | + s->old_optr = 0; | |
| 213 | 598 | |
| 214 | - oss.bytes_per_second = (freq << (nchannels >> 1)) << oss.bits16; | |
| 599 | + s->bytes_per_second = (freq << (nchannels >> 1)) << s->bits16; | |
| 215 | 600 | |
| 216 | - linfo ("bytes per second %d\n", oss.bytes_per_second); | |
| 601 | + linfo ("bytes per second %d\n", s->bytes_per_second); | |
| 217 | 602 | |
| 218 | 603 | linfo ("fragments %d, fragstotal %d, fragsize %d, bytes %d, bufsize %d\n", |
| 219 | 604 | abinfo.fragments, |
| 220 | 605 | abinfo.fragstotal, |
| 221 | 606 | abinfo.fragsize, |
| 222 | 607 | abinfo.bytes, |
| 223 | - oss.bufsize); | |
| 608 | + s->bufsize); | |
| 224 | 609 | |
| 225 | - oss.buf = MAP_FAILED; | |
| 226 | - oss.is_mapped = 0; | |
| 610 | + s->buf = MAP_FAILED; | |
| 611 | + s->is_mapped = 0; | |
| 227 | 612 | |
| 228 | 613 | if (conf.try_mmap) { |
| 229 | - oss.buf = mmap (NULL, oss.bufsize, PROT_WRITE, MAP_SHARED, oss.fd, 0); | |
| 230 | - if (MAP_FAILED == oss.buf) { | |
| 614 | + s->buf = mmap (NULL, s->bufsize, PROT_WRITE, MAP_SHARED, s->fd, 0); | |
| 615 | + if (MAP_FAILED == s->buf) { | |
| 231 | 616 | int err; |
| 232 | 617 | |
| 233 | 618 | err = errno; |
| 234 | - log ("failed to mmap audio, size %d, fd %d\n" | |
| 619 | + dolog ("failed to mmap audio, size %d, fd %d\n" | |
| 235 | 620 | "syserr: %s\n", |
| 236 | - oss.bufsize, oss.fd, strerror (err)); | |
| 621 | + s->bufsize, s->fd, strerror (err)); | |
| 237 | 622 | } |
| 238 | 623 | else { |
| 239 | 624 | est = TID; |
| 240 | - oss.is_mapped = 1; | |
| 625 | + s->is_mapped = 1; | |
| 241 | 626 | } |
| 242 | 627 | } |
| 243 | 628 | |
| 244 | - if (MAP_FAILED == oss.buf) { | |
| 629 | + if (MAP_FAILED == s->buf) { | |
| 245 | 630 | est = TID; |
| 246 | - oss.buf = mmap (NULL, oss.bufsize, PROT_READ | PROT_WRITE, | |
| 247 | - MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); | |
| 248 | - if (MAP_FAILED == oss.buf) { | |
| 249 | - ERRFail ("mmap audio buf, size %d", oss.bufsize); | |
| 631 | + s->buf = qemu_mallocz (s->bufsize); | |
| 632 | + if (!s->buf) { | |
| 633 | + ERRFail ("audio buf malloc failed, size %d", s->bufsize); | |
| 250 | 634 | } |
| 251 | 635 | } |
| 252 | 636 | |
| 253 | - oss.rpos = 0; | |
| 254 | - oss.wpos = 0; | |
| 255 | - oss.live = 0; | |
| 637 | + s->rpos = 0; | |
| 638 | + s->wpos = 0; | |
| 639 | + s->live = 0; | |
| 256 | 640 | |
| 257 | - if (oss.is_mapped) { | |
| 641 | + if (s->is_mapped) { | |
| 258 | 642 | int trig; |
| 259 | 643 | |
| 260 | 644 | trig = 0; |
| 261 | - IOCTL ((oss.fd, SNDCTL_DSP_SETTRIGGER, &trig)); | |
| 645 | + IOCTL ((s->fd, SNDCTL_DSP_SETTRIGGER, &trig)); | |
| 262 | 646 | trig = PCM_ENABLE_OUTPUT; |
| 263 | - IOCTL ((oss.fd, SNDCTL_DSP_SETTRIGGER, &trig)); | |
| 647 | + IOCTL ((s->fd, SNDCTL_DSP_SETTRIGGER, &trig)); | |
| 264 | 648 | } |
| 265 | 649 | } |
| 266 | 650 | |
| 267 | -static void maybe_open (int req_freq, int req_nchannels, | |
| 651 | +static void maybe_open (AudioState *s, int req_freq, int req_nchannels, | |
| 268 | 652 | audfmt_e req_fmt, int force_open) |
| 269 | 653 | { |
| 270 | 654 | int oss_fmt, bits16; |
| ... | ... | @@ -273,7 +657,7 @@ static void maybe_open (int req_freq, int req_nchannels, |
| 273 | 657 | case AUD_FMT_U8: |
| 274 | 658 | bits16 = 0; |
| 275 | 659 | oss_fmt = AFMT_U8; |
| 276 | - oss.copy_fn = copy_no_conversion; | |
| 660 | + s->copy_fn = copy_no_conversion; | |
| 277 | 661 | break; |
| 278 | 662 | |
| 279 | 663 | case AUD_FMT_S8: |
| ... | ... | @@ -282,13 +666,13 @@ static void maybe_open (int req_freq, int req_nchannels, |
| 282 | 666 | case AUD_FMT_S16: |
| 283 | 667 | bits16 = 1; |
| 284 | 668 | oss_fmt = AFMT_S16_LE; |
| 285 | - oss.copy_fn = copy_no_conversion; | |
| 669 | + s->copy_fn = copy_no_conversion; | |
| 286 | 670 | break; |
| 287 | 671 | |
| 288 | 672 | case AUD_FMT_U16: |
| 289 | 673 | bits16 = 1; |
| 290 | 674 | oss_fmt = AFMT_S16_LE; |
| 291 | - oss.copy_fn = copy_u16_to_s16; | |
| 675 | + s->copy_fn = copy_u16_to_s16; | |
| 292 | 676 | break; |
| 293 | 677 | |
| 294 | 678 | default: |
| ... | ... | @@ -296,55 +680,58 @@ static void maybe_open (int req_freq, int req_nchannels, |
| 296 | 680 | } |
| 297 | 681 | |
| 298 | 682 | if (force_open |
| 299 | - || (-1 == oss.fd) | |
| 300 | - || (oss_fmt != oss.oss_fmt) | |
| 301 | - || (req_nchannels != oss.nchannels) | |
| 302 | - || (req_freq != oss.freq) | |
| 303 | - || (bits16 != oss.bits16)) { | |
| 304 | - oss.oss_fmt = oss_fmt; | |
| 305 | - oss.nchannels = req_nchannels; | |
| 306 | - oss.freq = req_freq; | |
| 307 | - oss.bits16 = bits16; | |
| 308 | - do_open (); | |
| 683 | + || (-1 == s->fd) | |
| 684 | + || (oss_fmt != s->oss_fmt) | |
| 685 | + || (req_nchannels != s->nchannels) | |
| 686 | + || (req_freq != s->freq) | |
| 687 | + || (bits16 != s->bits16)) { | |
| 688 | + s->oss_fmt = oss_fmt; | |
| 689 | + s->nchannels = req_nchannels; | |
| 690 | + s->freq = req_freq; | |
| 691 | + s->bits16 = bits16; | |
| 692 | + do_open (s); | |
| 309 | 693 | } |
| 310 | 694 | } |
| 311 | 695 | |
| 312 | 696 | void AUD_reset (int req_freq, int req_nchannels, audfmt_e req_fmt) |
| 313 | 697 | { |
| 314 | - maybe_open (req_freq, req_nchannels, req_fmt, 0); | |
| 698 | + AudioState *s = &oss_audio; | |
| 699 | + maybe_open (s, req_freq, req_nchannels, req_fmt, 0); | |
| 315 | 700 | } |
| 316 | 701 | |
| 317 | 702 | void AUD_open (int req_freq, int req_nchannels, audfmt_e req_fmt) |
| 318 | 703 | { |
| 319 | - maybe_open (req_freq, req_nchannels, req_fmt, 1); | |
| 704 | + AudioState *s = &oss_audio; | |
| 705 | + maybe_open (s, req_freq, req_nchannels, req_fmt, 1); | |
| 320 | 706 | } |
| 321 | 707 | |
| 322 | 708 | int AUD_write (void *in_buf, int size) |
| 323 | 709 | { |
| 710 | + AudioState *s = &oss_audio; | |
| 324 | 711 | int to_copy, temp; |
| 325 | 712 | uint8_t *in, *out; |
| 326 | 713 | |
| 327 | - to_copy = MIN (oss.bufsize - oss.live, size); | |
| 714 | + to_copy = MIN (s->bufsize - s->live, size); | |
| 328 | 715 | |
| 329 | 716 | temp = to_copy; |
| 330 | 717 | |
| 331 | 718 | in = in_buf; |
| 332 | - out = oss.buf; | |
| 719 | + out = s->buf; | |
| 333 | 720 | |
| 334 | 721 | while (temp) { |
| 335 | 722 | int copy; |
| 336 | 723 | |
| 337 | - copy = MIN (temp, oss.bufsize - oss.wpos); | |
| 338 | - oss.copy_fn (out + oss.wpos, in, copy); | |
| 724 | + copy = MIN (temp, s->bufsize - s->wpos); | |
| 725 | + s->copy_fn (out + s->wpos, in, copy); | |
| 339 | 726 | |
| 340 | - oss.wpos += copy; | |
| 341 | - if (oss.wpos == oss.bufsize) { | |
| 342 | - oss.wpos = 0; | |
| 727 | + s->wpos += copy; | |
| 728 | + if (s->wpos == s->bufsize) { | |
| 729 | + s->wpos = 0; | |
| 343 | 730 | } |
| 344 | 731 | |
| 345 | 732 | temp -= copy; |
| 346 | 733 | in += copy; |
| 347 | - oss.live += copy; | |
| 734 | + s->live += copy; | |
| 348 | 735 | } |
| 349 | 736 | |
| 350 | 737 | return to_copy; |
| ... | ... | @@ -355,15 +742,16 @@ void AUD_run (void) |
| 355 | 742 | int res; |
| 356 | 743 | int bytes; |
| 357 | 744 | struct audio_buf_info abinfo; |
| 745 | + AudioState *s = &oss_audio; | |
| 358 | 746 | |
| 359 | - if (0 == oss.live) | |
| 747 | + if (0 == s->live) | |
| 360 | 748 | return; |
| 361 | 749 | |
| 362 | - if (oss.is_mapped) { | |
| 750 | + if (s->is_mapped) { | |
| 363 | 751 | count_info info; |
| 364 | 752 | |
| 365 | - res = ioctl (oss.fd, SNDCTL_DSP_GETOPTR, &info); | |
| 366 | - if (-1 == res) { | |
| 753 | + res = ioctl (s->fd, SNDCTL_DSP_GETOPTR, &info); | |
| 754 | + if (res < 0) { | |
| 367 | 755 | int err; |
| 368 | 756 | |
| 369 | 757 | err = errno; |
| ... | ... | @@ -371,29 +759,30 @@ void AUD_run (void) |
| 371 | 759 | return; |
| 372 | 760 | } |
| 373 | 761 | |
| 374 | - if (info.ptr > oss.old_optr) { | |
| 375 | - bytes = info.ptr - oss.old_optr; | |
| 762 | + if (info.ptr > s->old_optr) { | |
| 763 | + bytes = info.ptr - s->old_optr; | |
| 376 | 764 | } |
| 377 | 765 | else { |
| 378 | - bytes = oss.bufsize + info.ptr - oss.old_optr; | |
| 766 | + bytes = s->bufsize + info.ptr - s->old_optr; | |
| 379 | 767 | } |
| 380 | 768 | |
| 381 | - oss.old_optr = info.ptr; | |
| 382 | - oss.live -= bytes; | |
| 769 | + s->old_optr = info.ptr; | |
| 770 | + s->live -= bytes; | |
| 383 | 771 | return; |
| 384 | 772 | } |
| 385 | 773 | |
| 386 | - res = ioctl (oss.fd, SNDCTL_DSP_GETOSPACE, &abinfo); | |
| 774 | + res = ioctl (s->fd, SNDCTL_DSP_GETOSPACE, &abinfo); | |
| 387 | 775 | |
| 388 | - if (-1 == res) { | |
| 776 | + if (res < 0) { | |
| 389 | 777 | int err; |
| 390 | 778 | |
| 391 | 779 | err = errno; |
| 392 | 780 | lwarn ("SNDCTL_DSP_GETOSPACE failed with %s\n", strerror (err)); |
| 781 | + return; | |
| 393 | 782 | } |
| 394 | 783 | |
| 395 | 784 | bytes = abinfo.bytes; |
| 396 | - bytes = MIN (oss.live, bytes); | |
| 785 | + bytes = MIN (s->live, bytes); | |
| 397 | 786 | #if 0 |
| 398 | 787 | bytes = (bytes / fragsize) * fragsize; |
| 399 | 788 | #endif |
| ... | ... | @@ -401,9 +790,9 @@ void AUD_run (void) |
| 401 | 790 | while (bytes) { |
| 402 | 791 | int left, play, written; |
| 403 | 792 | |
| 404 | - left = oss.bufsize - oss.rpos; | |
| 793 | + left = s->bufsize - s->rpos; | |
| 405 | 794 | play = MIN (left, bytes); |
| 406 | - written = write (oss.fd, (uint8_t *)oss.buf + oss.rpos, play); | |
| 795 | + written = write (s->fd, (uint8_t *)s->buf + s->rpos, play); | |
| 407 | 796 | |
| 408 | 797 | if (-1 == written) { |
| 409 | 798 | if (EAGAIN == errno || EINTR == errno) { |
| ... | ... | @@ -415,12 +804,12 @@ void AUD_run (void) |
| 415 | 804 | } |
| 416 | 805 | |
| 417 | 806 | play = written; |
| 418 | - oss.live -= play; | |
| 419 | - oss.rpos += play; | |
| 807 | + s->live -= play; | |
| 808 | + s->rpos += play; | |
| 420 | 809 | bytes -= play; |
| 421 | 810 | |
| 422 | - if (oss.rpos == oss.bufsize) { | |
| 423 | - oss.rpos = 0; | |
| 811 | + if (s->rpos == s->bufsize) { | |
| 812 | + s->rpos = 0; | |
| 424 | 813 | } |
| 425 | 814 | } |
| 426 | 815 | } |
| ... | ... | @@ -429,8 +818,9 @@ static int get_dsp_bytes (void) |
| 429 | 818 | { |
| 430 | 819 | int res; |
| 431 | 820 | struct count_info info; |
| 821 | + AudioState *s = &oss_audio; | |
| 432 | 822 | |
| 433 | - res = ioctl (oss.fd, SNDCTL_DSP_GETOPTR, &info); | |
| 823 | + res = ioctl (s->fd, SNDCTL_DSP_GETOPTR, &info); | |
| 434 | 824 | if (-1 == res) { |
| 435 | 825 | int err; |
| 436 | 826 | |
| ... | ... | @@ -446,16 +836,18 @@ static int get_dsp_bytes (void) |
| 446 | 836 | |
| 447 | 837 | void AUD_adjust_estimate (int leftover) |
| 448 | 838 | { |
| 449 | - oss.leftover = leftover; | |
| 839 | + AudioState *s = &oss_audio; | |
| 840 | + s->leftover = leftover; | |
| 450 | 841 | } |
| 451 | 842 | |
| 452 | 843 | int AUD_get_free (void) |
| 453 | 844 | { |
| 454 | 845 | int free, elapsed; |
| 846 | + AudioState *s = &oss_audio; | |
| 455 | 847 | |
| 456 | - free = oss.bufsize - oss.live; | |
| 848 | + free = s->bufsize - s->live; | |
| 457 | 849 | |
| 458 | - if (0 == free) | |
| 850 | + if (free <= 0) | |
| 459 | 851 | return 0; |
| 460 | 852 | |
| 461 | 853 | elapsed = free; |
| ... | ... | @@ -485,10 +877,10 @@ int AUD_get_free (void) |
| 485 | 877 | uint64_t al_elapsed; |
| 486 | 878 | |
| 487 | 879 | ticks = qemu_get_clock(rt_clock); |
| 488 | - delta = ticks - oss.old_ticks; | |
| 489 | - oss.old_ticks = ticks; | |
| 880 | + delta = ticks - s->old_ticks; | |
| 881 | + s->old_ticks = ticks; | |
| 490 | 882 | |
| 491 | - ua_elapsed = (delta * oss.bytes_per_second) / 1000; | |
| 883 | + ua_elapsed = (delta * s->bytes_per_second) / 1000; | |
| 492 | 884 | al_elapsed = ua_elapsed & ~3ULL; |
| 493 | 885 | |
| 494 | 886 | ldebug ("tid elapsed %llu bytes\n", ua_elapsed); |
| ... | ... | @@ -498,7 +890,7 @@ int AUD_get_free (void) |
| 498 | 890 | else |
| 499 | 891 | elapsed = al_elapsed; |
| 500 | 892 | |
| 501 | - elapsed += oss.leftover; | |
| 893 | + elapsed += s->leftover; | |
| 502 | 894 | } |
| 503 | 895 | } |
| 504 | 896 | |
| ... | ... | @@ -513,31 +905,20 @@ int AUD_get_free (void) |
| 513 | 905 | |
| 514 | 906 | int AUD_get_live (void) |
| 515 | 907 | { |
| 516 | - return oss.live; | |
| 908 | + AudioState *s = &oss_audio; | |
| 909 | + return s->live; | |
| 517 | 910 | } |
| 518 | 911 | |
| 519 | 912 | int AUD_get_buffer_size (void) |
| 520 | 913 | { |
| 521 | - return oss.bufsize; | |
| 914 | + AudioState *s = &oss_audio; | |
| 915 | + return s->bufsize; | |
| 522 | 916 | } |
| 523 | 917 | |
| 524 | 918 | #define QC_OSS_FRAGSIZE "QEMU_OSS_FRAGSIZE" |
| 525 | 919 | #define QC_OSS_NFRAGS "QEMU_OSS_NFRAGS" |
| 526 | 920 | #define QC_OSS_MMAP "QEMU_OSS_MMAP" |
| 527 | 921 | |
| 528 | -static int get_conf_val (const char *key, int defval) | |
| 529 | -{ | |
| 530 | - int val = defval; | |
| 531 | - char *strval; | |
| 532 | - | |
| 533 | - strval = getenv (key); | |
| 534 | - if (strval) { | |
| 535 | - val = atoi (strval); | |
| 536 | - } | |
| 537 | - | |
| 538 | - return val; | |
| 539 | -} | |
| 540 | - | |
| 541 | 922 | void AUD_init (void) |
| 542 | 923 | { |
| 543 | 924 | int fsp; | ... | ... |