Commit fd06c37550b43980e8d641bb109c219cbe001d13

Authored by bellard
1 parent 52328140

PC speaker emulation (Joachim Henke)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1851 c046a42c-6fe2-441c-8c8c-71466251a162
Changelog
... ... @@ -2,6 +2,7 @@ version 0.8.1:
2 2  
3 3 - USB tablet support (Brad Campbell, Anthony Liguori)
4 4 - win32 host serial support (Kazu)
  5 + - PC speaker support (Joachim Henke)
5 6  
6 7 version 0.8.0:
7 8  
... ...
Makefile.target
... ... @@ -310,7 +310,7 @@ VL_OBJS+= ne2000.o rtl8139.o
310 310 ifeq ($(TARGET_BASE_ARCH), i386)
311 311 # Hardware support
312 312 VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
313   -VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o
  313 +VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
314 314 VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o
315 315 DEFINES += -DHAS_AUDIO
316 316 endif
... ...
hw/i8254.c
... ... @@ -209,6 +209,18 @@ int pit_get_gate(PITState *pit, int channel)
209 209 return s->gate;
210 210 }
211 211  
  212 +int pit_get_initial_count(PITState *pit, int channel)
  213 +{
  214 + PITChannelState *s = &pit->channels[channel];
  215 + return s->count;
  216 +}
  217 +
  218 +int pit_get_mode(PITState *pit, int channel)
  219 +{
  220 + PITChannelState *s = &pit->channels[channel];
  221 + return s->mode;
  222 +}
  223 +
212 224 static inline void pit_load_count(PITChannelState *s, int val)
213 225 {
214 226 if (val == 0)
... ...
... ... @@ -36,8 +36,6 @@
36 36 #define KERNEL_PARAMS_ADDR 0x00090000
37 37 #define KERNEL_CMDLINE_ADDR 0x00099000
38 38  
39   -int speaker_data_on;
40   -int dummy_refresh_clock;
41 39 static fdctrl_t *floppy_controller;
42 40 static RTCState *rtc_state;
43 41 static PITState *pit;
... ... @@ -273,21 +271,6 @@ static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table
273 271 // rtc_set_memory(s, 0x38, 1);
274 272 }
275 273  
276   -static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val)
277   -{
278   - speaker_data_on = (val >> 1) & 1;
279   - pit_set_gate(pit, 2, val & 1);
280   -}
281   -
282   -static uint32_t speaker_ioport_read(void *opaque, uint32_t addr)
283   -{
284   - int out;
285   - out = pit_get_out(pit, 2, qemu_get_clock(vm_clock));
286   - dummy_refresh_clock ^= 1;
287   - return (speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) |
288   - (dummy_refresh_clock << 4);
289   -}
290   -
291 274 void ioport_set_a20(int enable)
292 275 {
293 276 /* XXX: send to all CPUs ? */
... ... @@ -783,8 +766,6 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
783 766 }
784 767  
785 768 rtc_state = rtc_init(0x70, 8);
786   - register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL);
787   - register_ioport_write(0x61, 1, 1, speaker_ioport_write, NULL);
788 769  
789 770 register_ioport_read(0x92, 1, 1, ioport92_read, NULL);
790 771 register_ioport_write(0x92, 1, 1, ioport92_write, NULL);
... ... @@ -794,6 +775,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
794 775 }
795 776 isa_pic = pic_init(pic_irq_request, first_cpu);
796 777 pit = pit_init(0x40, 0);
  778 + pcspk_init(pit);
797 779 if (pci_enabled) {
798 780 pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic);
799 781 }
... ...
hw/pcspk.c 0 → 100644
  1 +/*
  2 + * QEMU PC speaker emulation
  3 + *
  4 + * Copyright (c) 2006 Joachim Henke
  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 "vl.h"
  26 +
  27 +#define PCSPK_BUF_LEN 1792
  28 +#define PCSPK_SAMPLE_RATE 32000
  29 +#define PCSPK_MAX_FREQ (PCSPK_SAMPLE_RATE >> 1)
  30 +#define PCSPK_MIN_COUNT ((PIT_FREQ + PCSPK_MAX_FREQ - 1) / PCSPK_MAX_FREQ)
  31 +
  32 +typedef struct {
  33 + uint8_t sample_buf[PCSPK_BUF_LEN];
  34 + QEMUSoundCard card;
  35 + SWVoiceOut *voice;
  36 + PITState *pit;
  37 + unsigned int pit_count;
  38 + unsigned int samples;
  39 + unsigned int play_pos;
  40 + int data_on;
  41 + int dummy_refresh_clock;
  42 +} PCSpkState;
  43 +
  44 +static const char *s_spk = "pcspk";
  45 +static PCSpkState pcspk_state;
  46 +
  47 +static inline void generate_samples(PCSpkState *s)
  48 +{
  49 + unsigned int i;
  50 +
  51 + if (s->pit_count) {
  52 + const uint32_t m = PCSPK_SAMPLE_RATE * s->pit_count;
  53 + const uint32_t n = ((uint64_t)PIT_FREQ << 32) / m;
  54 +
  55 + /* multiple of wavelength for gapless looping */
  56 + s->samples = (PCSPK_BUF_LEN * PIT_FREQ / m * m / (PIT_FREQ >> 1) + 1) >> 1;
  57 + for (i = 0; i < s->samples; ++i)
  58 + s->sample_buf[i] = (64 & (n * i >> 25)) - 32;
  59 + } else {
  60 + s->samples = PCSPK_BUF_LEN;
  61 + for (i = 0; i < PCSPK_BUF_LEN; ++i)
  62 + s->sample_buf[i] = 128; /* silence */
  63 + }
  64 +}
  65 +
  66 +static void pcspk_callback(void *opaque, int free)
  67 +{
  68 + PCSpkState *s = opaque;
  69 + unsigned int n;
  70 +
  71 + if (pit_get_mode(s->pit, 2) != 3)
  72 + return;
  73 +
  74 + n = pit_get_initial_count(s->pit, 2);
  75 + /* avoid frequencies that are not reproducible with sample rate */
  76 + if (n < PCSPK_MIN_COUNT)
  77 + n = 0;
  78 +
  79 + if (s->pit_count != n) {
  80 + s->pit_count = n;
  81 + s->play_pos = 0;
  82 + generate_samples(s);
  83 + }
  84 +
  85 + while (free > 0) {
  86 + n = audio_MIN(s->samples - s->play_pos, (unsigned int)free);
  87 + n = AUD_write(s->voice, &s->sample_buf[s->play_pos], n);
  88 + if (!n)
  89 + break;
  90 + s->play_pos = (s->play_pos + n) % s->samples;
  91 + free -= n;
  92 + }
  93 +}
  94 +
  95 +int pcspk_audio_init(AudioState *audio)
  96 +{
  97 + PCSpkState *s = &pcspk_state;
  98 + audsettings_t as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8};
  99 +
  100 + if (!audio) {
  101 + AUD_log(s_spk, "No audio state\n");
  102 + return -1;
  103 + }
  104 + AUD_register_card(audio, s_spk, &s->card);
  105 +
  106 + s->voice = AUD_open_out(&s->card, s->voice, s_spk, s, pcspk_callback, &as, 0);
  107 + if (!s->voice) {
  108 + AUD_log(s_spk, "Could not open voice\n");
  109 + return -1;
  110 + }
  111 +
  112 + return 0;
  113 +}
  114 +
  115 +static uint32_t pcspk_ioport_read(void *opaque, uint32_t addr)
  116 +{
  117 + PCSpkState *s = opaque;
  118 + int out;
  119 +
  120 + s->dummy_refresh_clock ^= (1 << 4);
  121 + out = pit_get_out(s->pit, 2, qemu_get_clock(vm_clock)) << 5;
  122 +
  123 + return pit_get_gate(s->pit, 2) | (s->data_on << 1) | s->dummy_refresh_clock | out;
  124 +}
  125 +
  126 +static void pcspk_ioport_write(void *opaque, uint32_t addr, uint32_t val)
  127 +{
  128 + PCSpkState *s = opaque;
  129 + const int gate = val & 1;
  130 +
  131 + s->data_on = (val >> 1) & 1;
  132 + pit_set_gate(s->pit, 2, gate);
  133 + if (s->voice) {
  134 + if (gate) /* restart */
  135 + s->play_pos = 0;
  136 + AUD_set_active_out(s->voice, gate & s->data_on);
  137 + }
  138 +}
  139 +
  140 +void pcspk_init(PITState *pit)
  141 +{
  142 + PCSpkState *s = &pcspk_state;
  143 +
  144 + s->pit = pit;
  145 + register_ioport_read(0x61, 1, 1, pcspk_ioport_read, s);
  146 + register_ioport_write(0x61, 1, 1, pcspk_ioport_write, s);
  147 +}
... ...
... ... @@ -4862,6 +4862,15 @@ void register_machines(void)
4862 4862  
4863 4863 #ifdef HAS_AUDIO
4864 4864 struct soundhw soundhw[] = {
  4865 +#ifdef TARGET_I386
  4866 + {
  4867 + "pcspk",
  4868 + "PC speaker",
  4869 + 0,
  4870 + 1,
  4871 + { .init_isa = pcspk_audio_init }
  4872 + },
  4873 +#endif
4865 4874 {
4866 4875 "sb16",
4867 4876 "Creative Sound Blaster 16",
... ...
... ... @@ -819,8 +819,14 @@ typedef struct PITState PITState;
819 819 PITState *pit_init(int base, int irq);
820 820 void pit_set_gate(PITState *pit, int channel, int val);
821 821 int pit_get_gate(PITState *pit, int channel);
  822 +int pit_get_initial_count(PITState *pit, int channel);
  823 +int pit_get_mode(PITState *pit, int channel);
822 824 int pit_get_out(PITState *pit, int channel, int64_t current_time);
823 825  
  826 +/* pcspk.c */
  827 +void pcspk_init(PITState *);
  828 +int pcspk_audio_init(AudioState *);
  829 +
824 830 /* pc.c */
825 831 extern QEMUMachine pc_machine;
826 832 extern QEMUMachine isapc_machine;
... ...