~ubuntu-branches/ubuntu/saucy/qemu/saucy

« back to all changes in this revision

Viewing changes to hw/adlib.c

  • Committer: Package Import Robot
  • Author(s): Serge Hallyn
  • Date: 2013-05-28 08:18:30 UTC
  • mfrom: (1.8.2) (10.1.37 sid)
  • Revision ID: package-import@ubuntu.com-20130528081830-87xl2z9fq516a814
Tags: 1.5.0+dfsg-2ubuntu1
* Merge 1.5.0+dfs-2 from debian unstable.  Remaining changes:
  - debian/control
    * update maintainer
    * remove libiscsi, usb-redir, vde, vnc-jpeg, and libssh2-1-dev
      from build-deps
    * enable rbd
    * add qemu-system and qemu-common B/R to qemu-keymaps
    * add D:udev, R:qemu, R:qemu-common and B:qemu-common to
      qemu-system-common
    * qemu-system-arm, qemu-system-ppc, qemu-system-sparc:
      - add qemu-kvm to Provides
      - add qemu-common, qemu-kvm, kvm to B/R
      - remove openbios-sparc from qemu-system-sparc D
    * qemu-system-x86:
      - add qemu-common to Breaks/Replaces.
      - add cpu-checker to Recommends.
    * qemu-user: add B/R:qemu-kvm
    * qemu-kvm:
      - add armhf armel powerpc sparc to Architecture
      - C/R/P: qemu-kvm-spice
    * add qemu-common package
    * drop qemu-slof which is not packaged in ubuntu
  - add qemu-system-common.links for tap ifup/down scripts and OVMF link.
  - qemu-system-x86.links:
    * remove pxe rom links which are in kvm-ipxe
    * add symlink for kvm.1 manpage
  - debian/rules
    * add kvm-spice symlink to qemu-kvm
    * call dh_installmodules for qemu-system-x86
    * update dh_installinit to install upstart script
    * run dh_installman (Closes: #709241) (cherrypicked from 1.5.0+dfsg-2)
  - Add qemu-utils.links for kvm-* symlinks.
  - Add qemu-system-x86.qemu-kvm.upstart and .default
  - Add qemu-system-x86.modprobe to set nesting=1
  - Add qemu-system-common.preinst to add kvm group
  - qemu-system-common.postinst: remove bad group acl if there, then have
    udev relabel /dev/kvm.
  - Dropped patches:
    * 0001-fix-wrong-output-with-info-chardev-for-tcp-socket.patch
  - Kept patches:
    * expose_vms_qemu64cpu.patch - updated
    * gridcentric patch - updated
    * linaro arm patches from qemu-linaro rebasing branch

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * QEMU Proxy for OPL2/3 emulation by MAME team
3
 
 *
4
 
 * Copyright (c) 2004-2005 Vassili Karpov (malc)
5
 
 *
6
 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 
 * of this software and associated documentation files (the "Software"), to deal
8
 
 * in the Software without restriction, including without limitation the rights
9
 
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 
 * copies of the Software, and to permit persons to whom the Software is
11
 
 * furnished to do so, subject to the following conditions:
12
 
 *
13
 
 * The above copyright notice and this permission notice shall be included in
14
 
 * all copies or substantial portions of the Software.
15
 
 *
16
 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 
 * THE SOFTWARE.
23
 
 */
24
 
 
25
 
#include "hw.h"
26
 
#include "audiodev.h"
27
 
#include "audio/audio.h"
28
 
#include "isa.h"
29
 
 
30
 
//#define DEBUG
31
 
 
32
 
#define ADLIB_KILL_TIMERS 1
33
 
 
34
 
#ifdef DEBUG
35
 
#include "qemu/timer.h"
36
 
#endif
37
 
 
38
 
#define dolog(...) AUD_log ("adlib", __VA_ARGS__)
39
 
#ifdef DEBUG
40
 
#define ldebug(...) dolog (__VA_ARGS__)
41
 
#else
42
 
#define ldebug(...)
43
 
#endif
44
 
 
45
 
#ifdef HAS_YMF262
46
 
#include "ymf262.h"
47
 
void YMF262UpdateOneQEMU (int which, INT16 *dst, int length);
48
 
#define SHIFT 2
49
 
#else
50
 
#include "fmopl.h"
51
 
#define SHIFT 1
52
 
#endif
53
 
 
54
 
#define IO_READ_PROTO(name) \
55
 
    uint32_t name (void *opaque, uint32_t nport)
56
 
#define IO_WRITE_PROTO(name) \
57
 
    void name (void *opaque, uint32_t nport, uint32_t val)
58
 
 
59
 
static struct {
60
 
    int port;
61
 
    int freq;
62
 
} conf = {0x220, 44100};
63
 
 
64
 
typedef struct {
65
 
    QEMUSoundCard card;
66
 
    int ticking[2];
67
 
    int enabled;
68
 
    int active;
69
 
    int bufpos;
70
 
#ifdef DEBUG
71
 
    int64_t exp[2];
72
 
#endif
73
 
    int16_t *mixbuf;
74
 
    uint64_t dexp[2];
75
 
    SWVoiceOut *voice;
76
 
    int left, pos, samples;
77
 
    QEMUAudioTimeStamp ats;
78
 
#ifndef HAS_YMF262
79
 
    FM_OPL *opl;
80
 
#endif
81
 
} AdlibState;
82
 
 
83
 
static AdlibState glob_adlib;
84
 
 
85
 
static void adlib_stop_opl_timer (AdlibState *s, size_t n)
86
 
{
87
 
#ifdef HAS_YMF262
88
 
    YMF262TimerOver (0, n);
89
 
#else
90
 
    OPLTimerOver (s->opl, n);
91
 
#endif
92
 
    s->ticking[n] = 0;
93
 
}
94
 
 
95
 
static void adlib_kill_timers (AdlibState *s)
96
 
{
97
 
    size_t i;
98
 
 
99
 
    for (i = 0; i < 2; ++i) {
100
 
        if (s->ticking[i]) {
101
 
            uint64_t delta;
102
 
 
103
 
            delta = AUD_get_elapsed_usec_out (s->voice, &s->ats);
104
 
            ldebug (
105
 
                "delta = %f dexp = %f expired => %d\n",
106
 
                delta / 1000000.0,
107
 
                s->dexp[i] / 1000000.0,
108
 
                delta >= s->dexp[i]
109
 
                );
110
 
            if (ADLIB_KILL_TIMERS || delta >= s->dexp[i]) {
111
 
                adlib_stop_opl_timer (s, i);
112
 
                AUD_init_time_stamp_out (s->voice, &s->ats);
113
 
            }
114
 
        }
115
 
    }
116
 
}
117
 
 
118
 
static IO_WRITE_PROTO (adlib_write)
119
 
{
120
 
    AdlibState *s = opaque;
121
 
    int a = nport & 3;
122
 
 
123
 
    s->active = 1;
124
 
    AUD_set_active_out (s->voice, 1);
125
 
 
126
 
    adlib_kill_timers (s);
127
 
 
128
 
#ifdef HAS_YMF262
129
 
    YMF262Write (0, a, val);
130
 
#else
131
 
    OPLWrite (s->opl, a, val);
132
 
#endif
133
 
}
134
 
 
135
 
static IO_READ_PROTO (adlib_read)
136
 
{
137
 
    AdlibState *s = opaque;
138
 
    uint8_t data;
139
 
    int a = nport & 3;
140
 
 
141
 
    adlib_kill_timers (s);
142
 
 
143
 
#ifdef HAS_YMF262
144
 
    data = YMF262Read (0, a);
145
 
#else
146
 
    data = OPLRead (s->opl, a);
147
 
#endif
148
 
    return data;
149
 
}
150
 
 
151
 
static void timer_handler (int c, double interval_Sec)
152
 
{
153
 
    AdlibState *s = &glob_adlib;
154
 
    unsigned n = c & 1;
155
 
#ifdef DEBUG
156
 
    double interval;
157
 
    int64_t exp;
158
 
#endif
159
 
 
160
 
    if (interval_Sec == 0.0) {
161
 
        s->ticking[n] = 0;
162
 
        return;
163
 
    }
164
 
 
165
 
    s->ticking[n] = 1;
166
 
#ifdef DEBUG
167
 
    interval = get_ticks_per_sec () * interval_Sec;
168
 
    exp = qemu_get_clock_ns (vm_clock) + interval;
169
 
    s->exp[n] = exp;
170
 
#endif
171
 
 
172
 
    s->dexp[n] = interval_Sec * 1000000.0;
173
 
    AUD_init_time_stamp_out (s->voice, &s->ats);
174
 
}
175
 
 
176
 
static int write_audio (AdlibState *s, int samples)
177
 
{
178
 
    int net = 0;
179
 
    int pos = s->pos;
180
 
 
181
 
    while (samples) {
182
 
        int nbytes, wbytes, wsampl;
183
 
 
184
 
        nbytes = samples << SHIFT;
185
 
        wbytes = AUD_write (
186
 
            s->voice,
187
 
            s->mixbuf + (pos << (SHIFT - 1)),
188
 
            nbytes
189
 
            );
190
 
 
191
 
        if (wbytes) {
192
 
            wsampl = wbytes >> SHIFT;
193
 
 
194
 
            samples -= wsampl;
195
 
            pos = (pos + wsampl) % s->samples;
196
 
 
197
 
            net += wsampl;
198
 
        }
199
 
        else {
200
 
            break;
201
 
        }
202
 
    }
203
 
 
204
 
    return net;
205
 
}
206
 
 
207
 
static void adlib_callback (void *opaque, int free)
208
 
{
209
 
    AdlibState *s = opaque;
210
 
    int samples, net = 0, to_play, written;
211
 
 
212
 
    samples = free >> SHIFT;
213
 
    if (!(s->active && s->enabled) || !samples) {
214
 
        return;
215
 
    }
216
 
 
217
 
    to_play = audio_MIN (s->left, samples);
218
 
    while (to_play) {
219
 
        written = write_audio (s, to_play);
220
 
 
221
 
        if (written) {
222
 
            s->left -= written;
223
 
            samples -= written;
224
 
            to_play -= written;
225
 
            s->pos = (s->pos + written) % s->samples;
226
 
        }
227
 
        else {
228
 
            return;
229
 
        }
230
 
    }
231
 
 
232
 
    samples = audio_MIN (samples, s->samples - s->pos);
233
 
    if (!samples) {
234
 
        return;
235
 
    }
236
 
 
237
 
#ifdef HAS_YMF262
238
 
    YMF262UpdateOneQEMU (0, s->mixbuf + s->pos * 2, samples);
239
 
#else
240
 
    YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples);
241
 
#endif
242
 
 
243
 
    while (samples) {
244
 
        written = write_audio (s, samples);
245
 
 
246
 
        if (written) {
247
 
            net += written;
248
 
            samples -= written;
249
 
            s->pos = (s->pos + written) % s->samples;
250
 
        }
251
 
        else {
252
 
            s->left = samples;
253
 
            return;
254
 
        }
255
 
    }
256
 
}
257
 
 
258
 
static void Adlib_fini (AdlibState *s)
259
 
{
260
 
#ifdef HAS_YMF262
261
 
    YMF262Shutdown ();
262
 
#else
263
 
    if (s->opl) {
264
 
        OPLDestroy (s->opl);
265
 
        s->opl = NULL;
266
 
    }
267
 
#endif
268
 
 
269
 
    if (s->mixbuf) {
270
 
        g_free (s->mixbuf);
271
 
    }
272
 
 
273
 
    s->active = 0;
274
 
    s->enabled = 0;
275
 
    AUD_remove_card (&s->card);
276
 
}
277
 
 
278
 
int Adlib_init (ISABus *bus)
279
 
{
280
 
    AdlibState *s = &glob_adlib;
281
 
    struct audsettings as;
282
 
 
283
 
#ifdef HAS_YMF262
284
 
    if (YMF262Init (1, 14318180, conf.freq)) {
285
 
        dolog ("YMF262Init %d failed\n", conf.freq);
286
 
        return -1;
287
 
    }
288
 
    else {
289
 
        YMF262SetTimerHandler (0, timer_handler, 0);
290
 
        s->enabled = 1;
291
 
    }
292
 
#else
293
 
    s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, conf.freq);
294
 
    if (!s->opl) {
295
 
        dolog ("OPLCreate %d failed\n", conf.freq);
296
 
        return -1;
297
 
    }
298
 
    else {
299
 
        OPLSetTimerHandler (s->opl, timer_handler, 0);
300
 
        s->enabled = 1;
301
 
    }
302
 
#endif
303
 
 
304
 
    as.freq = conf.freq;
305
 
    as.nchannels = SHIFT;
306
 
    as.fmt = AUD_FMT_S16;
307
 
    as.endianness = AUDIO_HOST_ENDIANNESS;
308
 
 
309
 
    AUD_register_card ("adlib", &s->card);
310
 
 
311
 
    s->voice = AUD_open_out (
312
 
        &s->card,
313
 
        s->voice,
314
 
        "adlib",
315
 
        s,
316
 
        adlib_callback,
317
 
        &as
318
 
        );
319
 
    if (!s->voice) {
320
 
        Adlib_fini (s);
321
 
        return -1;
322
 
    }
323
 
 
324
 
    s->samples = AUD_get_buffer_size_out (s->voice) >> SHIFT;
325
 
    s->mixbuf = g_malloc0 (s->samples << SHIFT);
326
 
 
327
 
    register_ioport_read (0x388, 4, 1, adlib_read, s);
328
 
    register_ioport_write (0x388, 4, 1, adlib_write, s);
329
 
 
330
 
    register_ioport_read (conf.port, 4, 1, adlib_read, s);
331
 
    register_ioport_write (conf.port, 4, 1, adlib_write, s);
332
 
 
333
 
    register_ioport_read (conf.port + 8, 2, 1, adlib_read, s);
334
 
    register_ioport_write (conf.port + 8, 2, 1, adlib_write, s);
335
 
 
336
 
    return 0;
337
 
}