gus.c 8.6 KB

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