2
0

gus.c 8.7 KB

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