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; | ... | ... |