Commit d329a6fb2213e53008a9b1cd186fe2ff258fa272
1 parent
7ebb5e41
audip fixes (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@911 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
275 additions
and
198 deletions
hw/sb16.c
| @@ -26,7 +26,10 @@ | @@ -26,7 +26,10 @@ | ||
| 26 | #define MIN(a, b) ((a)>(b)?(b):(a)) | 26 | #define MIN(a, b) ((a)>(b)?(b):(a)) |
| 27 | #define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0]))) | 27 | #define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0]))) |
| 28 | 28 | ||
| 29 | -#define log(...) fprintf (stderr, "sb16: " __VA_ARGS__) | 29 | +#define log(...) do { \ |
| 30 | + fprintf (stderr, "sb16: " __VA_ARGS__); \ | ||
| 31 | + fputc ('\n', stderr); \ | ||
| 32 | +} while (0) | ||
| 30 | 33 | ||
| 31 | /* #define DEBUG_SB16 */ | 34 | /* #define DEBUG_SB16 */ |
| 32 | #ifdef DEBUG_SB16 | 35 | #ifdef DEBUG_SB16 |
| @@ -44,6 +47,8 @@ | @@ -44,6 +47,8 @@ | ||
| 44 | #define IO_WRITE_PROTO(name) \ | 47 | #define IO_WRITE_PROTO(name) \ |
| 45 | void name (void *opaque, uint32_t nport, uint32_t val) | 48 | void name (void *opaque, uint32_t nport, uint32_t val) |
| 46 | 49 | ||
| 50 | +static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992."; | ||
| 51 | + | ||
| 47 | static struct { | 52 | static struct { |
| 48 | int ver_lo; | 53 | int ver_lo; |
| 49 | int ver_hi; | 54 | int ver_hi; |
| @@ -76,7 +81,7 @@ typedef struct SB16State { | @@ -76,7 +81,7 @@ typedef struct SB16State { | ||
| 76 | int v2x6; | 81 | int v2x6; |
| 77 | 82 | ||
| 78 | uint8_t in_data[10]; | 83 | uint8_t in_data[10]; |
| 79 | - uint8_t out_data[10]; | 84 | + uint8_t out_data[50]; |
| 80 | 85 | ||
| 81 | int left_till_irq; | 86 | int left_till_irq; |
| 82 | 87 | ||
| @@ -223,6 +228,20 @@ static void command (SB16State *dsp, uint8_t cmd) | @@ -223,6 +228,20 @@ static void command (SB16State *dsp, uint8_t cmd) | ||
| 223 | /* IMS uses those when probing for sound devices */ | 228 | /* IMS uses those when probing for sound devices */ |
| 224 | return; | 229 | return; |
| 225 | 230 | ||
| 231 | + case 0x04: | ||
| 232 | + dsp->needed_bytes = 1; | ||
| 233 | + break; | ||
| 234 | + | ||
| 235 | + case 0x05: | ||
| 236 | + case 0x0e: | ||
| 237 | + dsp->needed_bytes = 2; | ||
| 238 | + break; | ||
| 239 | + | ||
| 240 | + case 0x0f: | ||
| 241 | + dsp->needed_bytes = 1; | ||
| 242 | + dsp_out_data (dsp, 0); | ||
| 243 | + break; | ||
| 244 | + | ||
| 226 | case 0x10: | 245 | case 0x10: |
| 227 | dsp->needed_bytes = 1; | 246 | dsp->needed_bytes = 1; |
| 228 | break; | 247 | break; |
| @@ -274,8 +293,8 @@ static void command (SB16State *dsp, uint8_t cmd) | @@ -274,8 +293,8 @@ static void command (SB16State *dsp, uint8_t cmd) | ||
| 274 | uint8_t d0; | 293 | uint8_t d0; |
| 275 | 294 | ||
| 276 | d0 = 4; | 295 | d0 = 4; |
| 277 | - if (dsp->fmt_signed) d0 |= 16; | ||
| 278 | - if (dsp->fmt_stereo) d0 |= 32; | 296 | + /* if (dsp->fmt_signed) d0 |= 16; */ |
| 297 | + /* if (dsp->fmt_stereo) d0 |= 32; */ | ||
| 279 | dma_cmd (cmd == 0x90 ? 0xc4 : 0xc0, d0, -1); | 298 | dma_cmd (cmd == 0x90 ? 0xc4 : 0xc0, d0, -1); |
| 280 | cmd = -1; | 299 | cmd = -1; |
| 281 | break; | 300 | break; |
| @@ -324,6 +343,14 @@ static void command (SB16State *dsp, uint8_t cmd) | @@ -324,6 +343,14 @@ static void command (SB16State *dsp, uint8_t cmd) | ||
| 324 | dsp_out_data(dsp, sb.ver_hi); | 343 | dsp_out_data(dsp, sb.ver_hi); |
| 325 | return; | 344 | return; |
| 326 | 345 | ||
| 346 | + case 0xe3: | ||
| 347 | + { | ||
| 348 | + int i; | ||
| 349 | + for (i = sizeof (e3) - 1; i >= 0; --i) | ||
| 350 | + dsp_out_data (dsp, e3[i]); | ||
| 351 | + return; | ||
| 352 | + } | ||
| 353 | + | ||
| 327 | case 0xf2: | 354 | case 0xf2: |
| 328 | dsp_out_data(dsp, 0xaa); | 355 | dsp_out_data(dsp, 0xaa); |
| 329 | dsp->mixer_regs[0x82] |= dsp->mixer_regs[0x80]; | 356 | dsp->mixer_regs[0x82] |= dsp->mixer_regs[0x80]; |
| @@ -360,6 +387,11 @@ static void complete (SB16State *dsp) | @@ -360,6 +387,11 @@ static void complete (SB16State *dsp) | ||
| 360 | } | 387 | } |
| 361 | else { | 388 | else { |
| 362 | switch (dsp->cmd) { | 389 | switch (dsp->cmd) { |
| 390 | + case 0x05: | ||
| 391 | + case 0x04: | ||
| 392 | + case 0x0e: | ||
| 393 | + case 0x0f: | ||
| 394 | + break; | ||
| 363 | 395 | ||
| 364 | case 0x10: | 396 | case 0x10: |
| 365 | break; | 397 | break; |
| @@ -425,8 +457,10 @@ static IO_WRITE_PROTO (dsp_write) | @@ -425,8 +457,10 @@ static IO_WRITE_PROTO (dsp_write) | ||
| 425 | 457 | ||
| 426 | iport = nport - sb.port; | 458 | iport = nport - sb.port; |
| 427 | 459 | ||
| 460 | + ldebug ("write %#x %#x\n", nport, iport); | ||
| 428 | switch (iport) { | 461 | switch (iport) { |
| 429 | case 0x6: | 462 | case 0x6: |
| 463 | + control (0); | ||
| 430 | if (0 == val) | 464 | if (0 == val) |
| 431 | dsp->v2x6 = 0; | 465 | dsp->v2x6 = 0; |
| 432 | else if ((1 == val) && (0 == dsp->v2x6)) { | 466 | else if ((1 == val) && (0 == dsp->v2x6)) { |
| @@ -477,7 +511,7 @@ static IO_READ_PROTO (dsp_read) | @@ -477,7 +511,7 @@ static IO_READ_PROTO (dsp_read) | ||
| 477 | if (dsp->out_data_len) { | 511 | if (dsp->out_data_len) { |
| 478 | retval = dsp->out_data[--dsp->out_data_len]; | 512 | retval = dsp->out_data[--dsp->out_data_len]; |
| 479 | } else { | 513 | } else { |
| 480 | - log("empty output buffer\n"); | 514 | + log("empty output buffer"); |
| 481 | goto error; | 515 | goto error; |
| 482 | } | 516 | } |
| 483 | break; | 517 | break; |
| @@ -487,7 +521,7 @@ static IO_READ_PROTO (dsp_read) | @@ -487,7 +521,7 @@ static IO_READ_PROTO (dsp_read) | ||
| 487 | break; | 521 | break; |
| 488 | 522 | ||
| 489 | case 0xd: /* timer interrupt clear */ | 523 | case 0xd: /* timer interrupt clear */ |
| 490 | - log("timer interrupt clear\n"); | 524 | + log("timer interrupt clear"); |
| 491 | goto error; | 525 | goto error; |
| 492 | 526 | ||
| 493 | case 0xe: /* data available status | irq 8 ack */ | 527 | case 0xe: /* data available status | irq 8 ack */ |
| @@ -669,7 +703,7 @@ static int magic_of_irq (int irq) | @@ -669,7 +703,7 @@ static int magic_of_irq (int irq) | ||
| 669 | case 10: | 703 | case 10: |
| 670 | return 8; | 704 | return 8; |
| 671 | default: | 705 | default: |
| 672 | - log ("bad irq %d\n", irq); | 706 | + log ("bad irq %d", irq); |
| 673 | return 2; | 707 | return 2; |
| 674 | } | 708 | } |
| 675 | } | 709 | } |
| @@ -687,7 +721,7 @@ static int irq_of_magic (int magic) | @@ -687,7 +721,7 @@ static int irq_of_magic (int magic) | ||
| 687 | case 8: | 721 | case 8: |
| 688 | return 10; | 722 | return 10; |
| 689 | default: | 723 | default: |
| 690 | - log ("bad irq magic %d\n", magic); | 724 | + log ("bad irq magic %d", magic); |
| 691 | return 2; | 725 | return 2; |
| 692 | } | 726 | } |
| 693 | } | 727 | } |
oss.c
| @@ -24,6 +24,7 @@ | @@ -24,6 +24,7 @@ | ||
| 24 | #include "vl.h" | 24 | #include "vl.h" |
| 25 | 25 | ||
| 26 | #ifndef _WIN32 | 26 | #ifndef _WIN32 |
| 27 | +#include <ctype.h> | ||
| 27 | #include <fcntl.h> | 28 | #include <fcntl.h> |
| 28 | #include <errno.h> | 29 | #include <errno.h> |
| 29 | #include <stdio.h> | 30 | #include <stdio.h> |
| @@ -32,6 +33,7 @@ | @@ -32,6 +33,7 @@ | ||
| 32 | #include <stdlib.h> | 33 | #include <stdlib.h> |
| 33 | #include <limits.h> | 34 | #include <limits.h> |
| 34 | #include <inttypes.h> | 35 | #include <inttypes.h> |
| 36 | +#include <sys/mman.h> | ||
| 35 | #include <sys/types.h> | 37 | #include <sys/types.h> |
| 36 | #include <sys/ioctl.h> | 38 | #include <sys/ioctl.h> |
| 37 | #include <sys/soundcard.h> | 39 | #include <sys/soundcard.h> |
| @@ -90,25 +92,38 @@ static inline uint32_t lsbindex (uint32_t u) | @@ -90,25 +92,38 @@ static inline uint32_t lsbindex (uint32_t u) | ||
| 90 | ldebug ("ioctl " #args " = %d\n", ret); \ | 92 | ldebug ("ioctl " #args " = %d\n", ret); \ |
| 91 | } while (0) | 93 | } while (0) |
| 92 | 94 | ||
| 93 | -static int audio_fd = -1; | ||
| 94 | -static int freq; | ||
| 95 | -static int conf_nfrags = 4; | ||
| 96 | -static int conf_fragsize; | ||
| 97 | -static int nfrags; | ||
| 98 | -static int fragsize; | ||
| 99 | -static int bufsize; | ||
| 100 | -static int nchannels; | ||
| 101 | -static int fmt; | ||
| 102 | -static int rpos; | ||
| 103 | -static int wpos; | ||
| 104 | -static int atom; | ||
| 105 | -static int live; | ||
| 106 | -static int leftover; | ||
| 107 | -static int bytes_per_second; | ||
| 108 | -static void *buf; | ||
| 109 | -static enum {DONT, DSP, TID} estimate = TID; | ||
| 110 | - | ||
| 111 | -static void (*copy_fn)(void *, void *, int); | 95 | +static struct { |
| 96 | + int fd; | ||
| 97 | + int freq; | ||
| 98 | + int bits16; | ||
| 99 | + int nchannels; | ||
| 100 | + int rpos; | ||
| 101 | + int wpos; | ||
| 102 | + int live; | ||
| 103 | + int oss_fmt; | ||
| 104 | + int bytes_per_second; | ||
| 105 | + int is_mapped; | ||
| 106 | + void *buf; | ||
| 107 | + int bufsize; | ||
| 108 | + int nfrags; | ||
| 109 | + int fragsize; | ||
| 110 | + int old_optr; | ||
| 111 | + int leftover; | ||
| 112 | + uint64_t old_ticks; | ||
| 113 | + void (*copy_fn)(void *, void *, int); | ||
| 114 | +} oss = { .fd = -1 }; | ||
| 115 | + | ||
| 116 | +static struct { | ||
| 117 | + int try_mmap; | ||
| 118 | + int nfrags; | ||
| 119 | + int fragsize; | ||
| 120 | +} conf = { | ||
| 121 | + .try_mmap = 0, | ||
| 122 | + .nfrags = 4, | ||
| 123 | + .fragsize = 4096 | ||
| 124 | +}; | ||
| 125 | + | ||
| 126 | +static enum {DONT, DSP, TID} est = DONT; | ||
| 112 | 127 | ||
| 113 | static void copy_no_conversion (void *dst, void *src, int size) | 128 | static void copy_no_conversion (void *dst, void *src, int size) |
| 114 | { | 129 | { |
| @@ -141,70 +156,124 @@ static void pab (struct audio_buf_info *abinfo) | @@ -141,70 +156,124 @@ static void pab (struct audio_buf_info *abinfo) | ||
| 141 | rpos, wpos, live); | 156 | rpos, wpos, live); |
| 142 | } | 157 | } |
| 143 | 158 | ||
| 144 | -void AUD_reset (int rfreq, int rnchannels, audfmt_e rfmt) | 159 | +static void do_open () |
| 145 | { | 160 | { |
| 146 | - int fmt_; | ||
| 147 | - int bits16; | 161 | + int mmmmssss; |
| 162 | + audio_buf_info abinfo; | ||
| 163 | + int fmt, freq, nchannels; | ||
| 148 | 164 | ||
| 149 | - if (-1 == audio_fd) { | ||
| 150 | - AUD_open (rfreq, rnchannels, rfmt); | ||
| 151 | - return; | 165 | + if (oss.buf) { |
| 166 | + if (-1 == munmap (oss.buf, oss.bufsize)) { | ||
| 167 | + ERRFail ("failed to unmap audio buffer %p %d", | ||
| 168 | + oss.buf, oss.bufsize); | ||
| 169 | + } | ||
| 170 | + oss.buf = NULL; | ||
| 152 | } | 171 | } |
| 153 | 172 | ||
| 154 | - switch (rfmt) { | ||
| 155 | - case AUD_FMT_U8: | ||
| 156 | - bits16 = 0; | ||
| 157 | - fmt_ = AFMT_U8; | ||
| 158 | - copy_fn = copy_no_conversion; | ||
| 159 | - atom = 1; | ||
| 160 | - break; | 173 | + if (-1 != oss.fd) |
| 174 | + close (oss.fd); | ||
| 161 | 175 | ||
| 162 | - case AUD_FMT_S8: | ||
| 163 | - Fail ("can not play 8bit signed"); | 176 | + oss.fd = open ("/dev/dsp", O_RDWR | O_NONBLOCK); |
| 177 | + if (-1 == oss.fd) { | ||
| 178 | + ERRFail ("can not open /dev/dsp"); | ||
| 179 | + } | ||
| 164 | 180 | ||
| 165 | - case AUD_FMT_S16: | ||
| 166 | - bits16 = 1; | ||
| 167 | - fmt_ = AFMT_S16_LE; | ||
| 168 | - copy_fn = copy_no_conversion; | ||
| 169 | - atom = 2; | ||
| 170 | - break; | 181 | + fmt = oss.oss_fmt; |
| 182 | + freq = oss.freq; | ||
| 183 | + nchannels = oss.nchannels; | ||
| 184 | + | ||
| 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)); | ||
| 190 | + | ||
| 191 | + mmmmssss = (conf.nfrags << 16) | conf.fragsize; | ||
| 192 | + IOCTL ((oss.fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)); | ||
| 193 | + | ||
| 194 | + if ((oss.oss_fmt != fmt) | ||
| 195 | + || (oss.nchannels != nchannels) | ||
| 196 | + || (oss.freq != freq)) { | ||
| 197 | + Fail ("failed to set audio parameters\n" | ||
| 198 | + "parameter | requested value | obtained value\n" | ||
| 199 | + "format | %10d | %10d\n" | ||
| 200 | + "channels | %10d | %10d\n" | ||
| 201 | + "frequency | %10d | %10d\n", | ||
| 202 | + oss.oss_fmt, fmt, | ||
| 203 | + oss.nchannels, nchannels, | ||
| 204 | + oss.freq, freq); | ||
| 205 | + } | ||
| 171 | 206 | ||
| 172 | - case AUD_FMT_U16: | ||
| 173 | - bits16 = 1; | ||
| 174 | - fmt_ = AFMT_S16_LE; | ||
| 175 | - copy_fn = copy_u16_to_s16; | ||
| 176 | - atom = 2; | ||
| 177 | - break; | 207 | + IOCTL ((oss.fd, SNDCTL_DSP_GETOSPACE, &abinfo)); |
| 178 | 208 | ||
| 179 | - default: | ||
| 180 | - abort (); | ||
| 181 | - } | 209 | + oss.nfrags = abinfo.fragstotal; |
| 210 | + oss.fragsize = abinfo.fragsize; | ||
| 211 | + oss.bufsize = oss.nfrags * oss.fragsize; | ||
| 212 | + oss.old_optr = 0; | ||
| 182 | 213 | ||
| 183 | - if ((fmt_ == fmt) && (bits16 + 1 == nchannels) && (rfreq == freq)) | ||
| 184 | - return; | 214 | + oss.bytes_per_second = (freq << (nchannels >> 1)) << oss.bits16; |
| 215 | + | ||
| 216 | + linfo ("bytes per second %d\n", oss.bytes_per_second); | ||
| 217 | + | ||
| 218 | + linfo ("fragments %d, fragstotal %d, fragsize %d, bytes %d, bufsize %d\n", | ||
| 219 | + abinfo.fragments, | ||
| 220 | + abinfo.fragstotal, | ||
| 221 | + abinfo.fragsize, | ||
| 222 | + abinfo.bytes, | ||
| 223 | + oss.bufsize); | ||
| 224 | + | ||
| 225 | + oss.buf = MAP_FAILED; | ||
| 226 | + oss.is_mapped = 0; | ||
| 227 | + | ||
| 228 | + if (conf.try_mmap) { | ||
| 229 | + oss.buf = mmap (NULL, oss.bufsize, PROT_WRITE, MAP_SHARED, oss.fd, 0); | ||
| 230 | + if (MAP_FAILED == oss.buf) { | ||
| 231 | + int err; | ||
| 232 | + | ||
| 233 | + err = errno; | ||
| 234 | + log ("failed to mmap audio, size %d, fd %d\n" | ||
| 235 | + "syserr: %s\n", | ||
| 236 | + oss.bufsize, oss.fd, strerror (err)); | ||
| 237 | + } | ||
| 185 | else { | 238 | else { |
| 186 | - AUD_open (rfreq, rnchannels, rfmt); | 239 | + est = TID; |
| 240 | + oss.is_mapped = 1; | ||
| 241 | + } | ||
| 242 | + } | ||
| 243 | + | ||
| 244 | + if (MAP_FAILED == oss.buf) { | ||
| 245 | + 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); | ||
| 250 | + } | ||
| 251 | + } | ||
| 252 | + | ||
| 253 | + oss.rpos = 0; | ||
| 254 | + oss.wpos = 0; | ||
| 255 | + oss.live = 0; | ||
| 256 | + | ||
| 257 | + if (oss.is_mapped) { | ||
| 258 | + int trig; | ||
| 259 | + | ||
| 260 | + trig = 0; | ||
| 261 | + IOCTL ((oss.fd, SNDCTL_DSP_SETTRIGGER, &trig)); | ||
| 262 | + trig = PCM_ENABLE_OUTPUT; | ||
| 263 | + IOCTL ((oss.fd, SNDCTL_DSP_SETTRIGGER, &trig)); | ||
| 187 | } | 264 | } |
| 188 | } | 265 | } |
| 189 | 266 | ||
| 190 | -void AUD_open (int rfreq, int rnchannels, audfmt_e rfmt) | 267 | +static void maybe_open (int req_freq, int req_nchannels, |
| 268 | + audfmt_e req_fmt, int force_open) | ||
| 191 | { | 269 | { |
| 192 | - int fmt_; | ||
| 193 | - int mmmmssss; | ||
| 194 | - struct audio_buf_info abinfo; | ||
| 195 | - int _fmt; | ||
| 196 | - int _freq; | ||
| 197 | - int _nchannels; | ||
| 198 | - int bits16; | 270 | + int oss_fmt, bits16; |
| 199 | 271 | ||
| 200 | - bits16 = 0; | ||
| 201 | - | ||
| 202 | - switch (rfmt) { | 272 | + switch (req_fmt) { |
| 203 | case AUD_FMT_U8: | 273 | case AUD_FMT_U8: |
| 204 | bits16 = 0; | 274 | bits16 = 0; |
| 205 | - fmt_ = AFMT_U8; | ||
| 206 | - copy_fn = copy_no_conversion; | ||
| 207 | - atom = 1; | 275 | + oss_fmt = AFMT_U8; |
| 276 | + oss.copy_fn = copy_no_conversion; | ||
| 208 | break; | 277 | break; |
| 209 | 278 | ||
| 210 | case AUD_FMT_S8: | 279 | case AUD_FMT_S8: |
| @@ -212,111 +281,42 @@ void AUD_open (int rfreq, int rnchannels, audfmt_e rfmt) | @@ -212,111 +281,42 @@ void AUD_open (int rfreq, int rnchannels, audfmt_e rfmt) | ||
| 212 | 281 | ||
| 213 | case AUD_FMT_S16: | 282 | case AUD_FMT_S16: |
| 214 | bits16 = 1; | 283 | bits16 = 1; |
| 215 | - fmt_ = AFMT_S16_LE; | ||
| 216 | - copy_fn = copy_no_conversion; | ||
| 217 | - atom = 2; | 284 | + oss_fmt = AFMT_S16_LE; |
| 285 | + oss.copy_fn = copy_no_conversion; | ||
| 218 | break; | 286 | break; |
| 219 | 287 | ||
| 220 | case AUD_FMT_U16: | 288 | case AUD_FMT_U16: |
| 221 | bits16 = 1; | 289 | bits16 = 1; |
| 222 | - fmt_ = AFMT_S16_LE; | ||
| 223 | - copy_fn = copy_u16_to_s16; | ||
| 224 | - atom = 2; | 290 | + oss_fmt = AFMT_S16_LE; |
| 291 | + oss.copy_fn = copy_u16_to_s16; | ||
| 225 | break; | 292 | break; |
| 226 | 293 | ||
| 227 | default: | 294 | default: |
| 228 | abort (); | 295 | abort (); |
| 229 | } | 296 | } |
| 230 | 297 | ||
| 231 | - if (buf) { | ||
| 232 | - free (buf); | ||
| 233 | - buf = 0; | ||
| 234 | - } | ||
| 235 | - | ||
| 236 | - if (-1 != audio_fd) | ||
| 237 | - close (audio_fd); | ||
| 238 | - | ||
| 239 | - audio_fd = open ("/dev/dsp", O_WRONLY | O_NONBLOCK); | ||
| 240 | - if (-1 == audio_fd) { | ||
| 241 | - ERRFail ("can not open /dev/dsp"); | ||
| 242 | - } | ||
| 243 | - | ||
| 244 | - _fmt = fmt_; | ||
| 245 | - _freq = rfreq; | ||
| 246 | - _nchannels = rnchannels; | ||
| 247 | - | ||
| 248 | - IOCTL ((audio_fd, SNDCTL_DSP_RESET, 1)); | ||
| 249 | - IOCTL ((audio_fd, SNDCTL_DSP_SAMPLESIZE, &_fmt)); | ||
| 250 | - IOCTL ((audio_fd, SNDCTL_DSP_CHANNELS, &_nchannels)); | ||
| 251 | - IOCTL ((audio_fd, SNDCTL_DSP_SPEED, &_freq)); | ||
| 252 | - IOCTL ((audio_fd, SNDCTL_DSP_NONBLOCK)); | ||
| 253 | - | ||
| 254 | - /* from oss.pdf: | ||
| 255 | - | ||
| 256 | - The argument to this call is an integer encoded as 0xMMMMSSSS (in | ||
| 257 | - hex). The 16 least significant bits determine the fragment | ||
| 258 | - size. The size is 2^SSSS. For examp le SSSS=0008 gives fragment | ||
| 259 | - size of 256 bytes (2^8). The minimum is 16 bytes (SSSS=4) and the | ||
| 260 | - maximum is total_buffer_size/2. Some devices or processor | ||
| 261 | - architectures may require larger fragments - in this case the | ||
| 262 | - requested fragment size is automatically increased. | ||
| 263 | - | ||
| 264 | - So ahem... 4096 = 2^12, and grand total 0x0004000c | ||
| 265 | - */ | ||
| 266 | - | ||
| 267 | - mmmmssss = (conf_nfrags << 16) | conf_fragsize; | ||
| 268 | - IOCTL ((audio_fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)); | ||
| 269 | - | ||
| 270 | - linfo ("_fmt = %d, fmt = %d\n" | ||
| 271 | - "_channels = %d, rnchannels = %d\n" | ||
| 272 | - "_freq = %d, freq = %d\n", | ||
| 273 | - _fmt, fmt_, | ||
| 274 | - _nchannels, rnchannels, | ||
| 275 | - _freq, rfreq); | ||
| 276 | - | ||
| 277 | - if (_fmt != fmt_) { | ||
| 278 | - Fail ("format %d != %d", _fmt, fmt_); | ||
| 279 | - } | ||
| 280 | - | ||
| 281 | - if (_nchannels != rnchannels) { | ||
| 282 | - Fail ("channels %d != %d", _nchannels, rnchannels); | 298 | + 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 (); | ||
| 283 | } | 309 | } |
| 310 | +} | ||
| 284 | 311 | ||
| 285 | - if (_freq != rfreq) { | ||
| 286 | - Fail ("freq %d != %d", _freq, rfreq); | ||
| 287 | - } | ||
| 288 | - | ||
| 289 | - IOCTL ((audio_fd, SNDCTL_DSP_GETOSPACE, &abinfo)); | ||
| 290 | - | ||
| 291 | - nfrags = abinfo.fragstotal; | ||
| 292 | - fragsize = abinfo.fragsize; | ||
| 293 | - freq = _freq; | ||
| 294 | - fmt = _fmt; | ||
| 295 | - nchannels = rnchannels; | ||
| 296 | - atom <<= nchannels >> 1; | ||
| 297 | - bufsize = nfrags * fragsize; | ||
| 298 | - | ||
| 299 | - bytes_per_second = (freq << (nchannels >> 1)) << bits16; | ||
| 300 | - | ||
| 301 | - linfo ("bytes per second %d\n", bytes_per_second); | ||
| 302 | - | ||
| 303 | - linfo ("fragments %d, fragstotal %d, fragsize %d, bytes %d, bufsize %d\n", | ||
| 304 | - abinfo.fragments, | ||
| 305 | - abinfo.fragstotal, | ||
| 306 | - abinfo.fragsize, | ||
| 307 | - abinfo.bytes, | ||
| 308 | - bufsize); | ||
| 309 | - | ||
| 310 | - if (NULL == buf) { | ||
| 311 | - buf = malloc (bufsize); | ||
| 312 | - if (NULL == buf) { | ||
| 313 | - abort (); | ||
| 314 | - } | ||
| 315 | - } | 312 | +void AUD_reset (int req_freq, int req_nchannels, audfmt_e req_fmt) |
| 313 | +{ | ||
| 314 | + maybe_open (req_freq, req_nchannels, req_fmt, 0); | ||
| 315 | +} | ||
| 316 | 316 | ||
| 317 | - rpos = 0; | ||
| 318 | - wpos = 0; | ||
| 319 | - live = 0; | 317 | +void AUD_open (int req_freq, int req_nchannels, audfmt_e req_fmt) |
| 318 | +{ | ||
| 319 | + maybe_open (req_freq, req_nchannels, req_fmt, 1); | ||
| 320 | } | 320 | } |
| 321 | 321 | ||
| 322 | int AUD_write (void *in_buf, int size) | 322 | int AUD_write (void *in_buf, int size) |
| @@ -324,27 +324,27 @@ int AUD_write (void *in_buf, int size) | @@ -324,27 +324,27 @@ int AUD_write (void *in_buf, int size) | ||
| 324 | int to_copy, temp; | 324 | int to_copy, temp; |
| 325 | uint8_t *in, *out; | 325 | uint8_t *in, *out; |
| 326 | 326 | ||
| 327 | - to_copy = MIN (bufsize - live, size); | 327 | + to_copy = MIN (oss.bufsize - oss.live, size); |
| 328 | 328 | ||
| 329 | temp = to_copy; | 329 | temp = to_copy; |
| 330 | 330 | ||
| 331 | in = in_buf; | 331 | in = in_buf; |
| 332 | - out = buf; | 332 | + out = oss.buf; |
| 333 | 333 | ||
| 334 | while (temp) { | 334 | while (temp) { |
| 335 | int copy; | 335 | int copy; |
| 336 | 336 | ||
| 337 | - copy = MIN (temp, bufsize - wpos); | ||
| 338 | - copy_fn (out + wpos, in, copy); | 337 | + copy = MIN (temp, oss.bufsize - oss.wpos); |
| 338 | + oss.copy_fn (out + oss.wpos, in, copy); | ||
| 339 | 339 | ||
| 340 | - wpos += copy; | ||
| 341 | - if (wpos == bufsize) { | ||
| 342 | - wpos = 0; | 340 | + oss.wpos += copy; |
| 341 | + if (oss.wpos == oss.bufsize) { | ||
| 342 | + oss.wpos = 0; | ||
| 343 | } | 343 | } |
| 344 | 344 | ||
| 345 | temp -= copy; | 345 | temp -= copy; |
| 346 | in += copy; | 346 | in += copy; |
| 347 | - live += copy; | 347 | + oss.live += copy; |
| 348 | } | 348 | } |
| 349 | 349 | ||
| 350 | return to_copy; | 350 | return to_copy; |
| @@ -356,10 +356,34 @@ void AUD_run (void) | @@ -356,10 +356,34 @@ void AUD_run (void) | ||
| 356 | int bytes; | 356 | int bytes; |
| 357 | struct audio_buf_info abinfo; | 357 | struct audio_buf_info abinfo; |
| 358 | 358 | ||
| 359 | - if (0 == live) | 359 | + if (0 == oss.live) |
| 360 | return; | 360 | return; |
| 361 | 361 | ||
| 362 | - res = ioctl (audio_fd, SNDCTL_DSP_GETOSPACE, &abinfo); | 362 | + if (oss.is_mapped) { |
| 363 | + count_info info; | ||
| 364 | + | ||
| 365 | + res = ioctl (oss.fd, SNDCTL_DSP_GETOPTR, &info); | ||
| 366 | + if (-1 == res) { | ||
| 367 | + int err; | ||
| 368 | + | ||
| 369 | + err = errno; | ||
| 370 | + lwarn ("SNDCTL_DSP_GETOPTR failed with %s\n", strerror (err)); | ||
| 371 | + return; | ||
| 372 | + } | ||
| 373 | + | ||
| 374 | + if (info.ptr > oss.old_optr) { | ||
| 375 | + bytes = info.ptr - oss.old_optr; | ||
| 376 | + } | ||
| 377 | + else { | ||
| 378 | + bytes = oss.bufsize + info.ptr - oss.old_optr; | ||
| 379 | + } | ||
| 380 | + | ||
| 381 | + oss.old_optr = info.ptr; | ||
| 382 | + oss.live -= bytes; | ||
| 383 | + return; | ||
| 384 | + } | ||
| 385 | + | ||
| 386 | + res = ioctl (oss.fd, SNDCTL_DSP_GETOSPACE, &abinfo); | ||
| 363 | 387 | ||
| 364 | if (-1 == res) { | 388 | if (-1 == res) { |
| 365 | int err; | 389 | int err; |
| @@ -369,7 +393,7 @@ void AUD_run (void) | @@ -369,7 +393,7 @@ void AUD_run (void) | ||
| 369 | } | 393 | } |
| 370 | 394 | ||
| 371 | bytes = abinfo.bytes; | 395 | bytes = abinfo.bytes; |
| 372 | - bytes = MIN (live, bytes); | 396 | + bytes = MIN (oss.live, bytes); |
| 373 | #if 0 | 397 | #if 0 |
| 374 | bytes = (bytes / fragsize) * fragsize; | 398 | bytes = (bytes / fragsize) * fragsize; |
| 375 | #endif | 399 | #endif |
| @@ -377,9 +401,9 @@ void AUD_run (void) | @@ -377,9 +401,9 @@ void AUD_run (void) | ||
| 377 | while (bytes) { | 401 | while (bytes) { |
| 378 | int left, play, written; | 402 | int left, play, written; |
| 379 | 403 | ||
| 380 | - left = bufsize - rpos; | 404 | + left = oss.bufsize - oss.rpos; |
| 381 | play = MIN (left, bytes); | 405 | play = MIN (left, bytes); |
| 382 | - written = write (audio_fd, (void *) ((uint32_t) buf + rpos), play); | 406 | + written = write (oss.fd, (void *) ((uint32_t) oss.buf + oss.rpos), play); |
| 383 | 407 | ||
| 384 | if (-1 == written) { | 408 | if (-1 == written) { |
| 385 | if (EAGAIN == errno || EINTR == errno) { | 409 | if (EAGAIN == errno || EINTR == errno) { |
| @@ -391,12 +415,12 @@ void AUD_run (void) | @@ -391,12 +415,12 @@ void AUD_run (void) | ||
| 391 | } | 415 | } |
| 392 | 416 | ||
| 393 | play = written; | 417 | play = written; |
| 394 | - live -= play; | ||
| 395 | - rpos += play; | 418 | + oss.live -= play; |
| 419 | + oss.rpos += play; | ||
| 396 | bytes -= play; | 420 | bytes -= play; |
| 397 | 421 | ||
| 398 | - if (rpos == bufsize) { | ||
| 399 | - rpos = 0; | 422 | + if (oss.rpos == oss.bufsize) { |
| 423 | + oss.rpos = 0; | ||
| 400 | } | 424 | } |
| 401 | } | 425 | } |
| 402 | } | 426 | } |
| @@ -406,7 +430,7 @@ static int get_dsp_bytes (void) | @@ -406,7 +430,7 @@ static int get_dsp_bytes (void) | ||
| 406 | int res; | 430 | int res; |
| 407 | struct count_info info; | 431 | struct count_info info; |
| 408 | 432 | ||
| 409 | - res = ioctl (audio_fd, SNDCTL_DSP_GETOPTR, &info); | 433 | + res = ioctl (oss.fd, SNDCTL_DSP_GETOPTR, &info); |
| 410 | if (-1 == res) { | 434 | if (-1 == res) { |
| 411 | int err; | 435 | int err; |
| 412 | 436 | ||
| @@ -420,22 +444,22 @@ static int get_dsp_bytes (void) | @@ -420,22 +444,22 @@ static int get_dsp_bytes (void) | ||
| 420 | } | 444 | } |
| 421 | } | 445 | } |
| 422 | 446 | ||
| 423 | -void AUD_adjust_estimate (int _leftover) | 447 | +void AUD_adjust_estimate (int leftover) |
| 424 | { | 448 | { |
| 425 | - leftover = _leftover; | 449 | + oss.leftover = leftover; |
| 426 | } | 450 | } |
| 427 | 451 | ||
| 428 | int AUD_get_free (void) | 452 | int AUD_get_free (void) |
| 429 | { | 453 | { |
| 430 | int free, elapsed; | 454 | int free, elapsed; |
| 431 | 455 | ||
| 432 | - free = bufsize - live; | 456 | + free = oss.bufsize - oss.live; |
| 433 | 457 | ||
| 434 | if (0 == free) | 458 | if (0 == free) |
| 435 | return 0; | 459 | return 0; |
| 436 | 460 | ||
| 437 | elapsed = free; | 461 | elapsed = free; |
| 438 | - switch (estimate) { | 462 | + switch (est) { |
| 439 | case DONT: | 463 | case DONT: |
| 440 | break; | 464 | break; |
| 441 | 465 | ||
| @@ -456,16 +480,15 @@ int AUD_get_free (void) | @@ -456,16 +480,15 @@ int AUD_get_free (void) | ||
| 456 | 480 | ||
| 457 | case TID: | 481 | case TID: |
| 458 | { | 482 | { |
| 459 | - static uint64_t old_ticks; | ||
| 460 | uint64_t ticks, delta; | 483 | uint64_t ticks, delta; |
| 461 | uint64_t ua_elapsed; | 484 | uint64_t ua_elapsed; |
| 462 | uint64_t al_elapsed; | 485 | uint64_t al_elapsed; |
| 463 | 486 | ||
| 464 | ticks = qemu_get_clock(rt_clock); | 487 | ticks = qemu_get_clock(rt_clock); |
| 465 | - delta = ticks - old_ticks; | ||
| 466 | - old_ticks = ticks; | 488 | + delta = ticks - oss.old_ticks; |
| 489 | + oss.old_ticks = ticks; | ||
| 467 | 490 | ||
| 468 | - ua_elapsed = (delta * bytes_per_second) / 1000; | 491 | + ua_elapsed = (delta * oss.bytes_per_second) / 1000; |
| 469 | al_elapsed = ua_elapsed & ~3ULL; | 492 | al_elapsed = ua_elapsed & ~3ULL; |
| 470 | 493 | ||
| 471 | ldebug ("tid elapsed %llu bytes\n", ua_elapsed); | 494 | ldebug ("tid elapsed %llu bytes\n", ua_elapsed); |
| @@ -475,7 +498,7 @@ int AUD_get_free (void) | @@ -475,7 +498,7 @@ int AUD_get_free (void) | ||
| 475 | else | 498 | else |
| 476 | elapsed = al_elapsed; | 499 | elapsed = al_elapsed; |
| 477 | 500 | ||
| 478 | - elapsed += leftover; | 501 | + elapsed += oss.leftover; |
| 479 | } | 502 | } |
| 480 | } | 503 | } |
| 481 | 504 | ||
| @@ -490,27 +513,47 @@ int AUD_get_free (void) | @@ -490,27 +513,47 @@ int AUD_get_free (void) | ||
| 490 | 513 | ||
| 491 | int AUD_get_live (void) | 514 | int AUD_get_live (void) |
| 492 | { | 515 | { |
| 493 | - return live; | 516 | + return oss.live; |
| 494 | } | 517 | } |
| 495 | 518 | ||
| 496 | int AUD_get_buffer_size (void) | 519 | int AUD_get_buffer_size (void) |
| 497 | { | 520 | { |
| 498 | - return bufsize; | 521 | + return oss.bufsize; |
| 522 | +} | ||
| 523 | + | ||
| 524 | +#define QC_OSS_FRAGSIZE "QEMU_OSS_FRAGSIZE" | ||
| 525 | +#define QC_OSS_NFRAGS "QEMU_OSS_NFRAGS" | ||
| 526 | +#define QC_OSS_MMAP "QEMU_OSS_MMAP" | ||
| 527 | + | ||
| 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; | ||
| 499 | } | 539 | } |
| 500 | 540 | ||
| 501 | void AUD_init (void) | 541 | void AUD_init (void) |
| 502 | { | 542 | { |
| 503 | int fsp; | 543 | int fsp; |
| 504 | - int _fragsize = 4096; | ||
| 505 | 544 | ||
| 506 | DEREF (pab); | 545 | DEREF (pab); |
| 507 | 546 | ||
| 508 | - fsp = _fragsize; | 547 | + conf.fragsize = get_conf_val (QC_OSS_FRAGSIZE, conf.fragsize); |
| 548 | + conf.nfrags = get_conf_val (QC_OSS_NFRAGS, conf.nfrags); | ||
| 549 | + conf.try_mmap = get_conf_val (QC_OSS_MMAP, conf.try_mmap); | ||
| 550 | + | ||
| 551 | + fsp = conf.fragsize; | ||
| 509 | if (0 != (fsp & (fsp - 1))) { | 552 | if (0 != (fsp & (fsp - 1))) { |
| 510 | Fail ("fragment size %d is not power of 2", fsp); | 553 | Fail ("fragment size %d is not power of 2", fsp); |
| 511 | } | 554 | } |
| 512 | 555 | ||
| 513 | - conf_fragsize = lsbindex (fsp); | 556 | + conf.fragsize = lsbindex (fsp); |
| 514 | } | 557 | } |
| 515 | 558 | ||
| 516 | #else | 559 | #else |