qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

gus.c (8757B)


      1 /*
      2  * QEMU Proxy for Gravis Ultrasound GF1 emulation by Tibor "TS" Schütz
      3  *
      4  * Copyright (c) 2002-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 "qemu/osdep.h"
     26 #include "qapi/error.h"
     27 #include "qemu/module.h"
     28 #include "hw/audio/soundhw.h"
     29 #include "audio/audio.h"
     30 #include "hw/irq.h"
     31 #include "hw/isa/isa.h"
     32 #include "hw/qdev-properties.h"
     33 #include "migration/vmstate.h"
     34 #include "gusemu.h"
     35 #include "gustate.h"
     36 #include "qom/object.h"
     37 
     38 #define dolog(...) AUD_log ("audio", __VA_ARGS__)
     39 #ifdef DEBUG
     40 #define ldebug(...) dolog (__VA_ARGS__)
     41 #else
     42 #define ldebug(...)
     43 #endif
     44 
     45 #define TYPE_GUS "gus"
     46 OBJECT_DECLARE_SIMPLE_TYPE(GUSState, GUS)
     47 
     48 struct GUSState {
     49     ISADevice dev;
     50     GUSEmuState emu;
     51     QEMUSoundCard card;
     52     uint32_t freq;
     53     uint32_t port;
     54     int pos, left, shift, irqs;
     55     int16_t *mixbuf;
     56     uint8_t himem[1024 * 1024 + 32 + 4096];
     57     int samples;
     58     SWVoiceOut *voice;
     59     int64_t last_ticks;
     60     qemu_irq pic;
     61     IsaDma *isa_dma;
     62     PortioList portio_list1;
     63     PortioList portio_list2;
     64 };
     65 
     66 static uint32_t gus_readb(void *opaque, uint32_t nport)
     67 {
     68     GUSState *s = opaque;
     69 
     70     return gus_read (&s->emu, nport, 1);
     71 }
     72 
     73 static void gus_writeb(void *opaque, uint32_t nport, uint32_t val)
     74 {
     75     GUSState *s = opaque;
     76 
     77     gus_write (&s->emu, nport, 1, val);
     78 }
     79 
     80 static int write_audio (GUSState *s, int samples)
     81 {
     82     int net = 0;
     83     int pos = s->pos;
     84 
     85     while (samples) {
     86         int nbytes, wbytes, wsampl;
     87 
     88         nbytes = samples << s->shift;
     89         wbytes = AUD_write (
     90             s->voice,
     91             s->mixbuf + (pos << (s->shift - 1)),
     92             nbytes
     93             );
     94 
     95         if (wbytes) {
     96             wsampl = wbytes >> s->shift;
     97 
     98             samples -= wsampl;
     99             pos = (pos + wsampl) % s->samples;
    100 
    101             net += wsampl;
    102         }
    103         else {
    104             break;
    105         }
    106     }
    107 
    108     return net;
    109 }
    110 
    111 static void GUS_callback (void *opaque, int free)
    112 {
    113     int samples, to_play, net = 0;
    114     GUSState *s = opaque;
    115 
    116     samples = free >> s->shift;
    117     to_play = MIN (samples, s->left);
    118 
    119     while (to_play) {
    120         int written = write_audio (s, to_play);
    121 
    122         if (!written) {
    123             goto reset;
    124         }
    125 
    126         s->left -= written;
    127         to_play -= written;
    128         samples -= written;
    129         net += written;
    130     }
    131 
    132     samples = MIN (samples, s->samples);
    133     if (samples) {
    134         gus_mixvoices (&s->emu, s->freq, samples, s->mixbuf);
    135 
    136         while (samples) {
    137             int written = write_audio (s, samples);
    138             if (!written) {
    139                 break;
    140             }
    141             samples -= written;
    142             net += written;
    143         }
    144     }
    145     s->left = samples;
    146 
    147  reset:
    148     gus_irqgen (&s->emu, (uint64_t)net * 1000000 / s->freq);
    149 }
    150 
    151 int GUS_irqrequest (GUSEmuState *emu, int hwirq, int n)
    152 {
    153     GUSState *s = emu->opaque;
    154     /* qemu_irq_lower (s->pic); */
    155     qemu_irq_raise (s->pic);
    156     s->irqs += n;
    157     ldebug ("irqrequest %d %d %d\n", hwirq, n, s->irqs);
    158     return n;
    159 }
    160 
    161 void GUS_irqclear (GUSEmuState *emu, int hwirq)
    162 {
    163     GUSState *s = emu->opaque;
    164     ldebug ("irqclear %d %d\n", hwirq, s->irqs);
    165     qemu_irq_lower (s->pic);
    166     s->irqs -= 1;
    167 #ifdef IRQ_STORM
    168     if (s->irqs > 0) {
    169         qemu_irq_raise (s->pic[hwirq]);
    170     }
    171 #endif
    172 }
    173 
    174 void GUS_dmarequest (GUSEmuState *emu)
    175 {
    176     GUSState *s = emu->opaque;
    177     IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma);
    178     ldebug ("dma request %d\n", der->gusdma);
    179     k->hold_DREQ(s->isa_dma, s->emu.gusdma);
    180 }
    181 
    182 static int GUS_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
    183 {
    184     GUSState *s = opaque;
    185     IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma);
    186     char tmpbuf[4096];
    187     int pos = dma_pos, mode, left = dma_len - dma_pos;
    188 
    189     ldebug ("read DMA %#x %d\n", dma_pos, dma_len);
    190     mode = k->has_autoinitialization(s->isa_dma, s->emu.gusdma);
    191     while (left) {
    192         int to_copy = MIN ((size_t) left, sizeof (tmpbuf));
    193         int copied;
    194 
    195         ldebug ("left=%d to_copy=%d pos=%d\n", left, to_copy, pos);
    196         copied = k->read_memory(s->isa_dma, nchan, tmpbuf, pos, to_copy);
    197         gus_dma_transferdata (&s->emu, tmpbuf, copied, left == copied);
    198         left -= copied;
    199         pos += copied;
    200     }
    201 
    202     if (((mode >> 4) & 1) == 0) {
    203         k->release_DREQ(s->isa_dma, s->emu.gusdma);
    204     }
    205     return dma_len;
    206 }
    207 
    208 static const VMStateDescription vmstate_gus = {
    209     .name = "gus",
    210     .version_id = 2,
    211     .minimum_version_id = 2,
    212     .fields = (VMStateField[]) {
    213         VMSTATE_INT32 (pos, GUSState),
    214         VMSTATE_INT32 (left, GUSState),
    215         VMSTATE_INT32 (shift, GUSState),
    216         VMSTATE_INT32 (irqs, GUSState),
    217         VMSTATE_INT32 (samples, GUSState),
    218         VMSTATE_INT64 (last_ticks, GUSState),
    219         VMSTATE_BUFFER (himem, GUSState),
    220         VMSTATE_END_OF_LIST ()
    221     }
    222 };
    223 
    224 static const MemoryRegionPortio gus_portio_list1[] = {
    225     {0x000,  1, 1, .write = gus_writeb },
    226     {0x006, 10, 1, .read = gus_readb, .write = gus_writeb },
    227     {0x100,  8, 1, .read = gus_readb, .write = gus_writeb },
    228     PORTIO_END_OF_LIST (),
    229 };
    230 
    231 static const MemoryRegionPortio gus_portio_list2[] = {
    232     {0, 2, 1, .read = gus_readb },
    233     PORTIO_END_OF_LIST (),
    234 };
    235 
    236 static void gus_realizefn (DeviceState *dev, Error **errp)
    237 {
    238     ISADevice *d = ISA_DEVICE(dev);
    239     GUSState *s = GUS (dev);
    240     IsaDmaClass *k;
    241     struct audsettings as;
    242 
    243     s->isa_dma = isa_get_dma(isa_bus_from_device(d), s->emu.gusdma);
    244     if (!s->isa_dma) {
    245         error_setg(errp, "ISA controller does not support DMA");
    246         return;
    247     }
    248 
    249     AUD_register_card ("gus", &s->card);
    250 
    251     as.freq = s->freq;
    252     as.nchannels = 2;
    253     as.fmt = AUDIO_FORMAT_S16;
    254     as.endianness = AUDIO_HOST_ENDIANNESS;
    255 
    256     s->voice = AUD_open_out (
    257         &s->card,
    258         NULL,
    259         "gus",
    260         s,
    261         GUS_callback,
    262         &as
    263         );
    264 
    265     if (!s->voice) {
    266         AUD_remove_card (&s->card);
    267         error_setg(errp, "No voice");
    268         return;
    269     }
    270 
    271     s->shift = 2;
    272     s->samples = AUD_get_buffer_size_out (s->voice) >> s->shift;
    273     s->mixbuf = g_malloc0 (s->samples << s->shift);
    274 
    275     isa_register_portio_list(d, &s->portio_list1, s->port,
    276                              gus_portio_list1, s, "gus");
    277     isa_register_portio_list(d, &s->portio_list2, (s->port + 0x100) & 0xf00,
    278                              gus_portio_list2, s, "gus");
    279 
    280     k = ISADMA_GET_CLASS(s->isa_dma);
    281     k->register_channel(s->isa_dma, s->emu.gusdma, GUS_read_DMA, s);
    282     s->emu.himemaddr = s->himem;
    283     s->emu.gusdatapos = s->emu.himemaddr + 1024 * 1024 + 32;
    284     s->emu.opaque = s;
    285     s->pic = isa_get_irq(d, s->emu.gusirq);
    286 
    287     AUD_set_active_out (s->voice, 1);
    288 }
    289 
    290 static Property gus_properties[] = {
    291     DEFINE_AUDIO_PROPERTIES(GUSState, card),
    292     DEFINE_PROP_UINT32 ("freq",    GUSState, freq,        44100),
    293     DEFINE_PROP_UINT32 ("iobase",  GUSState, port,        0x240),
    294     DEFINE_PROP_UINT32 ("irq",     GUSState, emu.gusirq,  7),
    295     DEFINE_PROP_UINT32 ("dma",     GUSState, emu.gusdma,  3),
    296     DEFINE_PROP_END_OF_LIST (),
    297 };
    298 
    299 static void gus_class_initfn (ObjectClass *klass, void *data)
    300 {
    301     DeviceClass *dc = DEVICE_CLASS (klass);
    302 
    303     dc->realize = gus_realizefn;
    304     set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
    305     dc->desc = "Gravis Ultrasound GF1";
    306     dc->vmsd = &vmstate_gus;
    307     device_class_set_props(dc, gus_properties);
    308 }
    309 
    310 static const TypeInfo gus_info = {
    311     .name          = TYPE_GUS,
    312     .parent        = TYPE_ISA_DEVICE,
    313     .instance_size = sizeof (GUSState),
    314     .class_init    = gus_class_initfn,
    315 };
    316 
    317 static void gus_register_types (void)
    318 {
    319     type_register_static (&gus_info);
    320     deprecated_register_soundhw("gus", "Gravis Ultrasound GF1", 1, TYPE_GUS);
    321 }
    322 
    323 type_init (gus_register_types)