[PATCH 5/5] hw/audio: Remove wm8750 I2C audio device
Peter Maydell <[email protected]>
| Newsgroups | org.nongnu.qemu-arm,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
The wm8750 audio I2C device was used only by the audio device on the SoC used in the now-removed musicpal machine. Since it has no users, we can delete it entirely. Although the wm8750 is an I2C device that could technically have been created on the command line, it isn't possible to do this usefully because the device only works when C code calls functions like wm8750_data_req_set() and wm8750_dac_buffer(). This resolves the problem noted in issue #4135 that there's a buffer overflow in the interaction between the marvell_88w8618 audio device and the wm8750, by removing the offending code entirely. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4135 Signed-off-by: Peter Maydell <[email protected]> --- hw/audio/Kconfig | 4 - hw/audio/meson.build | 1 - hw/audio/wm8750.c | 738 -------------------------------------- include/hw/audio/wm8750.h | 30 -- 4 files changed, 773 deletions(-) delete mode 100644 hw/audio/wm8750.c delete mode 100644 include/hw/audio/wm8750.h diff --git a/hw/audio/Kconfig b/hw/audio/Kconfig index daf060e1be..ed93fa2698 100644 --- a/hw/audio/Kconfig +++ b/hw/audio/Kconfig @@ -38,10 +38,6 @@ config PCSPK default y depends on I8254 -config WM8750 - bool - depends on I2C - config PL041 bool diff --git a/hw/audio/meson.build b/hw/audio/meson.build index c977679e23..3312bcec10 100644 --- a/hw/audio/meson.build +++ b/hw/audio/meson.build @@ -11,6 +11,5 @@ system_ss.add(when: 'CONFIG_PCSPK', if_true: files('pcspk.c')) system_ss.add(when: 'CONFIG_PL041', if_true: files('pl041.c', 'lm4549.c')) system_ss.add(when: 'CONFIG_SB16', if_true: files('sb16.c')) system_ss.add(when: 'CONFIG_VT82C686', if_true: files('via-ac97.c')) -system_ss.add(when: 'CONFIG_WM8750', if_true: files('wm8750.c')) system_ss.add(when: ['CONFIG_VIRTIO_SND', 'CONFIG_VIRTIO'], if_true: files('virtio-snd.c')) system_ss.add(when: ['CONFIG_VIRTIO_SND', 'CONFIG_VIRTIO', 'CONFIG_VIRTIO_PCI'], if_true: files('virtio-snd-pci.c')) diff --git a/hw/audio/wm8750.c b/hw/audio/wm8750.c deleted file mode 100644 index e2507b0269..0000000000 --- a/hw/audio/wm8750.c +++ /dev/null @@ -1,738 +0,0 @@ -/* - * WM8750 audio CODEC. - * - * Copyright (c) 2006 Openedhand Ltd. - * Written by Andrzej Zaborowski <[email protected]> - * - * This file is licensed under GNU GPL. - */ - -#include "qemu/osdep.h" -#include "hw/i2c/i2c.h" -#include "migration/vmstate.h" -#include "qemu/module.h" -#include "hw/audio/wm8750.h" -#include "qemu/audio.h" -#include "qom/object.h" - -#define IN_PORT_N 3 -#define OUT_PORT_N 3 - -#define CODEC "wm8750" - -typedef struct { - int adc; - int adc_hz; - int dac; - int dac_hz; -} WMRate; - -OBJECT_DECLARE_SIMPLE_TYPE(WM8750State, WM8750) - -struct WM8750State { - I2CSlave parent_obj; - - uint8_t i2c_data[2]; - int i2c_len; - AudioBackend *audio_be; - SWVoiceIn *adc_voice[IN_PORT_N]; - SWVoiceOut *dac_voice[OUT_PORT_N]; - int enable; - void (*data_req)(void *, int, int); - void *opaque; - uint8_t data_in[4096]; - uint8_t data_out[4096]; - int idx_in, req_in; - int idx_out, req_out; - - SWVoiceOut **out[2]; - uint8_t outvol[7], outmute[2]; - SWVoiceIn **in[2]; - uint8_t invol[4], inmute[2]; - - uint8_t diff[2], pol, ds, monomix[2], alc, mute; - uint8_t path[4], mpath[2], power, format; - const WMRate *rate; - uint8_t rate_vmstate; - int adc_hz, dac_hz, ext_adc_hz, ext_dac_hz, master; -}; - -/* pow(10.0, -i / 20.0) * 255, i = 0..42 */ -static const uint8_t wm8750_vol_db_table[] = { - 255, 227, 203, 181, 161, 143, 128, 114, 102, 90, 81, 72, 64, 57, 51, 45, - 40, 36, 32, 29, 26, 23, 20, 18, 16, 14, 13, 11, 10, 9, 8, 7, 6, 6, 5, 5, - 4, 4, 3, 3, 3, 2, 2 -}; - -#define WM8750_OUTVOL_TRANSFORM(x) wm8750_vol_db_table[(0x7f - x) / 3] -#define WM8750_INVOL_TRANSFORM(x) (x << 2) - -static inline void wm8750_in_load(WM8750State *s) -{ - if (s->idx_in + s->req_in <= sizeof(s->data_in)) - return; - s->idx_in = MAX(0, (int) sizeof(s->data_in) - s->req_in); - audio_be_read(s->audio_be, *s->in[0], s->data_in + s->idx_in, - sizeof(s->data_in) - s->idx_in); -} - -static inline void wm8750_out_flush(WM8750State *s) -{ - int sent = 0; - while (sent < s->idx_out) - sent += audio_be_write(s->audio_be, *s->out[0], - s->data_out + sent, s->idx_out - sent) - ?: s->idx_out; - s->idx_out = 0; -} - -static void wm8750_audio_in_cb(void *opaque, int avail_b) -{ - WM8750State *s = (WM8750State *) opaque; - s->req_in = avail_b; - s->data_req(s->opaque, s->req_out >> 2, avail_b >> 2); -} - -static void wm8750_audio_out_cb(void *opaque, int free_b) -{ - WM8750State *s = (WM8750State *) opaque; - - if (s->idx_out >= free_b) { - s->idx_out = free_b; - s->req_out = 0; - wm8750_out_flush(s); - } else - s->req_out = free_b - s->idx_out; - - s->data_req(s->opaque, s->req_out >> 2, s->req_in >> 2); -} - -static const WMRate wm_rate_table[] = { - { 256, 48000, 256, 48000 }, /* SR: 00000 */ - { 384, 48000, 384, 48000 }, /* SR: 00001 */ - { 256, 48000, 1536, 8000 }, /* SR: 00010 */ - { 384, 48000, 2304, 8000 }, /* SR: 00011 */ - { 1536, 8000, 256, 48000 }, /* SR: 00100 */ - { 2304, 8000, 384, 48000 }, /* SR: 00101 */ - { 1536, 8000, 1536, 8000 }, /* SR: 00110 */ - { 2304, 8000, 2304, 8000 }, /* SR: 00111 */ - { 1024, 12000, 1024, 12000 }, /* SR: 01000 */ - { 1526, 12000, 1536, 12000 }, /* SR: 01001 */ - { 768, 16000, 768, 16000 }, /* SR: 01010 */ - { 1152, 16000, 1152, 16000 }, /* SR: 01011 */ - { 384, 32000, 384, 32000 }, /* SR: 01100 */ - { 576, 32000, 576, 32000 }, /* SR: 01101 */ - { 128, 96000, 128, 96000 }, /* SR: 01110 */ - { 192, 96000, 192, 96000 }, /* SR: 01111 */ - { 256, 44100, 256, 44100 }, /* SR: 10000 */ - { 384, 44100, 384, 44100 }, /* SR: 10001 */ - { 256, 44100, 1408, 8018 }, /* SR: 10010 */ - { 384, 44100, 2112, 8018 }, /* SR: 10011 */ - { 1408, 8018, 256, 44100 }, /* SR: 10100 */ - { 2112, 8018, 384, 44100 }, /* SR: 10101 */ - { 1408, 8018, 1408, 8018 }, /* SR: 10110 */ - { 2112, 8018, 2112, 8018 }, /* SR: 10111 */ - { 1024, 11025, 1024, 11025 }, /* SR: 11000 */ - { 1536, 11025, 1536, 11025 }, /* SR: 11001 */ - { 512, 22050, 512, 22050 }, /* SR: 11010 */ - { 768, 22050, 768, 22050 }, /* SR: 11011 */ - { 512, 24000, 512, 24000 }, /* SR: 11100 */ - { 768, 24000, 768, 24000 }, /* SR: 11101 */ - { 128, 88200, 128, 88200 }, /* SR: 11110 */ - { 192, 88200, 192, 88200 }, /* SR: 11111 */ -}; - -static void wm8750_vol_update(WM8750State *s) -{ - /* FIXME: multiply all volumes by s->invol[2], s->invol[3] */ - - audio_be_set_volume_in_lr(s->audio_be, s->adc_voice[0], s->mute, - s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]), - s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1])); - audio_be_set_volume_in_lr(s->audio_be, s->adc_voice[1], s->mute, - s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]), - s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1])); - audio_be_set_volume_in_lr(s->audio_be, s->adc_voice[2], s->mute, - s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]), - s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1])); - - /* FIXME: multiply all volumes by s->outvol[0], s->outvol[1] */ - - /* Speaker: LOUT2VOL ROUT2VOL */ - audio_be_set_volume_out_lr(s->audio_be, s->dac_voice[0], s->mute, - s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[4]), - s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[5])); - - /* Headphone: LOUT1VOL ROUT1VOL */ - audio_be_set_volume_out_lr(s->audio_be, s->dac_voice[1], s->mute, - s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[2]), - s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[3])); - - /* MONOOUT: MONOVOL MONOVOL */ - audio_be_set_volume_out_lr(s->audio_be, s->dac_voice[2], s->mute, - s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[6]), - s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[6])); -} - -static void wm8750_set_format(WM8750State *s) -{ - int i; - struct audsettings in_fmt; - struct audsettings out_fmt; - - wm8750_out_flush(s); - - if (s->in[0] && *s->in[0]) - audio_be_set_active_in(s->audio_be, *s->in[0], 0); - if (s->out[0] && *s->out[0]) - audio_be_set_active_out(s->audio_be, *s->out[0], 0); - - for (i = 0; i < IN_PORT_N; i ++) - if (s->adc_voice[i]) { - audio_be_close_in(s->audio_be, s->adc_voice[i]); - s->adc_voice[i] = NULL; - } - for (i = 0; i < OUT_PORT_N; i ++) - if (s->dac_voice[i]) { - audio_be_close_out(s->audio_be, s->dac_voice[i]); - s->dac_voice[i] = NULL; - } - - if (!s->enable) - return; - - /* Setup input */ - in_fmt.big_endian = false; - in_fmt.nchannels = 2; - in_fmt.freq = s->adc_hz; - in_fmt.fmt = AUDIO_FORMAT_S16; - - s->adc_voice[0] = audio_be_open_in(s->audio_be, s->adc_voice[0], - CODEC ".input1", s, wm8750_audio_in_cb, &in_fmt); - s->adc_voice[1] = audio_be_open_in(s->audio_be, s->adc_voice[1], - CODEC ".input2", s, wm8750_audio_in_cb, &in_fmt); - s->adc_voice[2] = audio_be_open_in(s->audio_be, s->adc_voice[2], - CODEC ".input3", s, wm8750_audio_in_cb, &in_fmt); - - /* Setup output */ - out_fmt.big_endian = false; - out_fmt.nchannels = 2; - out_fmt.freq = s->dac_hz; - out_fmt.fmt = AUDIO_FORMAT_S16; - - s->dac_voice[0] = audio_be_open_out(s->audio_be, s->dac_voice[0], - CODEC ".speaker", s, wm8750_audio_out_cb, &out_fmt); - s->dac_voice[1] = audio_be_open_out(s->audio_be, s->dac_voice[1], - CODEC ".headphone", s, wm8750_audio_out_cb, &out_fmt); - /* MONOMIX is also in stereo for simplicity */ - s->dac_voice[2] = audio_be_open_out(s->audio_be, s->dac_voice[2], - CODEC ".monomix", s, wm8750_audio_out_cb, &out_fmt); - /* no sense emulating OUT3 which is a mix of other outputs */ - - wm8750_vol_update(s); - - /* We should connect the left and right channels to their - * respective inputs/outputs but we have completely no need - * for mixing or combining paths to different ports, so we - * connect both channels to where the left channel is routed. */ - if (s->in[0] && *s->in[0]) - audio_be_set_active_in(s->audio_be, *s->in[0], 1); - if (s->out[0] && *s->out[0]) - audio_be_set_active_out(s->audio_be, *s->out[0], 1); -} - -static void wm8750_clk_update(WM8750State *s, int ext) -{ - if (s->master || !s->ext_dac_hz) - s->dac_hz = s->rate->dac_hz; - else - s->dac_hz = s->ext_dac_hz; - - if (s->master || !s->ext_adc_hz) - s->adc_hz = s->rate->adc_hz; - else - s->adc_hz = s->ext_adc_hz; - - if (s->master || (!s->ext_dac_hz && !s->ext_adc_hz)) { - if (!ext) - wm8750_set_format(s); - } else { - if (ext) - wm8750_set_format(s); - } -} - -static void wm8750_reset(I2CSlave *i2c) -{ - WM8750State *s = WM8750(i2c); - - s->rate = &wm_rate_table[0]; - s->enable = 0; - wm8750_clk_update(s, 1); - s->diff[0] = 0; - s->diff[1] = 0; - s->ds = 0; - s->alc = 0; - s->in[0] = &s->adc_voice[0]; - s->invol[0] = 0x17; - s->invol[1] = 0x17; - s->invol[2] = 0xc3; - s->invol[3] = 0xc3; - s->out[0] = &s->dac_voice[0]; - s->outvol[0] = 0xff; - s->outvol[1] = 0xff; - s->outvol[2] = 0x79; - s->outvol[3] = 0x79; - s->outvol[4] = 0x79; - s->outvol[5] = 0x79; - s->outvol[6] = 0x79; - s->inmute[0] = 0; - s->inmute[1] = 0; - s->outmute[0] = 0; - s->outmute[1] = 0; - s->mute = 1; - s->path[0] = 0; - s->path[1] = 0; - s->path[2] = 0; - s->path[3] = 0; - s->mpath[0] = 0; - s->mpath[1] = 0; - s->format = 0x0a; - s->idx_in = sizeof(s->data_in); - s->req_in = 0; - s->idx_out = 0; - s->req_out = 0; - wm8750_vol_update(s); - s->i2c_len = 0; -} - -static int wm8750_event(I2CSlave *i2c, enum i2c_event event) -{ - WM8750State *s = WM8750(i2c); - - switch (event) { - case I2C_START_SEND: - s->i2c_len = 0; - break; - case I2C_FINISH: -#ifdef VERBOSE - if (s->i2c_len < 2) - printf("%s: message too short (%i bytes)\n", - __func__, s->i2c_len); -#endif - break; - default: - break; - } - - return 0; -} - -#define WM8750_LINVOL 0x00 -#define WM8750_RINVOL 0x01 -#define WM8750_LOUT1V 0x02 -#define WM8750_ROUT1V 0x03 -#define WM8750_ADCDAC 0x05 -#define WM8750_IFACE 0x07 -#define WM8750_SRATE 0x08 -#define WM8750_LDAC 0x0a -#define WM8750_RDAC 0x0b -#define WM8750_BASS 0x0c -#define WM8750_TREBLE 0x0d -#define WM8750_RESET 0x0f -#define WM8750_3D 0x10 -#define WM8750_ALC1 0x11 -#define WM8750_ALC2 0x12 -#define WM8750_ALC3 0x13 -#define WM8750_NGATE 0x14 -#define WM8750_LADC 0x15 -#define WM8750_RADC 0x16 -#define WM8750_ADCTL1 0x17 -#define WM8750_ADCTL2 0x18 -#define WM8750_PWR1 0x19 -#define WM8750_PWR2 0x1a -#define WM8750_ADCTL3 0x1b -#define WM8750_ADCIN 0x1f -#define WM8750_LADCIN 0x20 -#define WM8750_RADCIN 0x21 -#define WM8750_LOUTM1 0x22 -#define WM8750_LOUTM2 0x23 -#define WM8750_ROUTM1 0x24 -#define WM8750_ROUTM2 0x25 -#define WM8750_MOUTM1 0x26 -#define WM8750_MOUTM2 0x27 -#define WM8750_LOUT2V 0x28 -#define WM8750_ROUT2V 0x29 -#define WM8750_MOUTV 0x2a - -static int wm8750_tx(I2CSlave *i2c, uint8_t data) -{ - WM8750State *s = WM8750(i2c); - uint8_t cmd; - uint16_t value; - - if (s->i2c_len >= 2) { -#ifdef VERBOSE - printf("%s: long message (%i bytes)\n", __func__, s->i2c_len); -#endif - return 1; - } - s->i2c_data[s->i2c_len ++] = data; - if (s->i2c_len != 2) - return 0; - - cmd = s->i2c_data[0] >> 1; - value = ((s->i2c_data[0] << 8) | s->i2c_data[1]) & 0x1ff; - - switch (cmd) { - case WM8750_LADCIN: /* ADC Signal Path Control (Left) */ - s->diff[0] = (((value >> 6) & 3) == 3); /* LINSEL */ - if (s->diff[0]) - s->in[0] = &s->adc_voice[0 + s->ds * 1]; - else - s->in[0] = &s->adc_voice[((value >> 6) & 3) * 1 + 0]; - break; - - case WM8750_RADCIN: /* ADC Signal Path Control (Right) */ - s->diff[1] = (((value >> 6) & 3) == 3); /* RINSEL */ - if (s->diff[1]) - s->in[1] = &s->adc_voice[0 + s->ds * 1]; - else - s->in[1] = &s->adc_voice[((value >> 6) & 3) * 1 + 0]; - break; - - case WM8750_ADCIN: /* ADC Input Mode */ - s->ds = (value >> 8) & 1; /* DS */ - if (s->diff[0]) - s->in[0] = &s->adc_voice[0 + s->ds * 1]; - if (s->diff[1]) - s->in[1] = &s->adc_voice[0 + s->ds * 1]; - s->monomix[0] = (value >> 6) & 3; /* MONOMIX */ - break; - - case WM8750_ADCTL1: /* Additional Control (1) */ - s->monomix[1] = (value >> 1) & 1; /* DMONOMIX */ - break; - - case WM8750_PWR1: /* Power Management (1) */ - s->enable = ((value >> 6) & 7) == 3; /* VMIDSEL, VREF */ - wm8750_set_format(s); - break; - - case WM8750_LINVOL: /* Left Channel PGA */ - s->invol[0] = value & 0x3f; /* LINVOL */ - s->inmute[0] = (value >> 7) & 1; /* LINMUTE */ - wm8750_vol_update(s); - break; - - case WM8750_RINVOL: /* Right Channel PGA */ - s->invol[1] = value & 0x3f; /* RINVOL */ - s->inmute[1] = (value >> 7) & 1; /* RINMUTE */ - wm8750_vol_update(s); - break; - - case WM8750_ADCDAC: /* ADC and DAC Control */ - s->pol = (value >> 5) & 3; /* ADCPOL */ - s->mute = (value >> 3) & 1; /* DACMU */ - wm8750_vol_update(s); - break; - - case WM8750_ADCTL3: /* Additional Control (3) */ - break; - - case WM8750_LADC: /* Left ADC Digital Volume */ - s->invol[2] = value & 0xff; /* LADCVOL */ - wm8750_vol_update(s); - break; - - case WM8750_RADC: /* Right ADC Digital Volume */ - s->invol[3] = value & 0xff; /* RADCVOL */ - wm8750_vol_update(s); - break; - - case WM8750_ALC1: /* ALC Control (1) */ - s->alc = (value >> 7) & 3; /* ALCSEL */ - break; - - case WM8750_NGATE: /* Noise Gate Control */ - case WM8750_3D: /* 3D enhance */ - break; - - case WM8750_LDAC: /* Left Channel Digital Volume */ - s->outvol[0] = value & 0xff; /* LDACVOL */ - wm8750_vol_update(s); - break; - - case WM8750_RDAC: /* Right Channel Digital Volume */ - s->outvol[1] = value & 0xff; /* RDACVOL */ - wm8750_vol_update(s); - break; - - case WM8750_BASS: /* Bass Control */ - break; - - case WM8750_LOUTM1: /* Left Mixer Control (1) */ - s->path[0] = (value >> 8) & 1; /* LD2LO */ - /* TODO: mute/unmute respective paths */ - wm8750_vol_update(s); - break; - - case WM8750_LOUTM2: /* Left Mixer Control (2) */ - s->path[1] = (value >> 8) & 1; /* RD2LO */ - /* TODO: mute/unmute respective paths */ - wm8750_vol_update(s); - break; - - case WM8750_ROUTM1: /* Right Mixer Control (1) */ - s->path[2] = (value >> 8) & 1; /* LD2RO */ - /* TODO: mute/unmute respective paths */ - wm8750_vol_update(s); - break; - - case WM8750_ROUTM2: /* Right Mixer Control (2) */ - s->path[3] = (value >> 8) & 1; /* RD2RO */ - /* TODO: mute/unmute respective paths */ - wm8750_vol_update(s); - break; - - case WM8750_MOUTM1: /* Mono Mixer Control (1) */ - s->mpath[0] = (value >> 8) & 1; /* LD2MO */ - /* TODO: mute/unmute respective paths */ - wm8750_vol_update(s); - break; - - case WM8750_MOUTM2: /* Mono Mixer Control (2) */ - s->mpath[1] = (value >> 8) & 1; /* RD2MO */ - /* TODO: mute/unmute respective paths */ - wm8750_vol_update(s); - break; - - case WM8750_LOUT1V: /* LOUT1 Volume */ - s->outvol[2] = value & 0x7f; /* LOUT1VOL */ - wm8750_vol_update(s); - break; - - case WM8750_LOUT2V: /* LOUT2 Volume */ - s->outvol[4] = value & 0x7f; /* LOUT2VOL */ - wm8750_vol_update(s); - break; - - case WM8750_ROUT1V: /* ROUT1 Volume */ - s->outvol[3] = value & 0x7f; /* ROUT1VOL */ - wm8750_vol_update(s); - break; - - case WM8750_ROUT2V: /* ROUT2 Volume */ - s->outvol[5] = value & 0x7f; /* ROUT2VOL */ - wm8750_vol_update(s); - break; - - case WM8750_MOUTV: /* MONOOUT Volume */ - s->outvol[6] = value & 0x7f; /* MONOOUTVOL */ - wm8750_vol_update(s); - break; - - case WM8750_ADCTL2: /* Additional Control (2) */ - break; - - case WM8750_PWR2: /* Power Management (2) */ - s->power = value & 0x7e; - /* TODO: mute/unmute respective paths */ - wm8750_vol_update(s); - break; - - case WM8750_IFACE: /* Digital Audio Interface Format */ - s->format = value; - s->master = (value >> 6) & 1; /* MS */ - wm8750_clk_update(s, s->master); - break; - - case WM8750_SRATE: /* Clocking and Sample Rate Control */ - s->rate = &wm_rate_table[(value >> 1) & 0x1f]; - wm8750_clk_update(s, 0); - break; - - case WM8750_RESET: /* Reset */ - wm8750_reset(I2C_SLAVE(s)); - break; - -#ifdef VERBOSE - default: - printf("%s: unknown register %02x\n", __func__, cmd); -#endif - } - - return 0; -} - -static uint8_t wm8750_rx(I2CSlave *i2c) -{ - return 0x00; -} - -static int wm8750_pre_save(void *opaque) -{ - WM8750State *s = opaque; - - s->rate_vmstate = s->rate - wm_rate_table; - - return 0; -} - -static int wm8750_post_load(void *opaque, int version_id) -{ - WM8750State *s = opaque; - - s->rate = &wm_rate_table[s->rate_vmstate & 0x1f]; - return 0; -} - -static const VMStateDescription vmstate_wm8750 = { - .name = CODEC, - .version_id = 0, - .minimum_version_id = 0, - .pre_save = wm8750_pre_save, - .post_load = wm8750_post_load, - .fields = (const VMStateField[]) { - VMSTATE_UINT8_ARRAY(i2c_data, WM8750State, 2), - VMSTATE_INT32(i2c_len, WM8750State), - VMSTATE_INT32(enable, WM8750State), - VMSTATE_INT32(idx_in, WM8750State), - VMSTATE_INT32(req_in, WM8750State), - VMSTATE_INT32(idx_out, WM8750State), - VMSTATE_INT32(req_out, WM8750State), - VMSTATE_UINT8_ARRAY(outvol, WM8750State, 7), - VMSTATE_UINT8_ARRAY(outmute, WM8750State, 2), - VMSTATE_UINT8_ARRAY(invol, WM8750State, 4), - VMSTATE_UINT8_ARRAY(inmute, WM8750State, 2), - VMSTATE_UINT8_ARRAY(diff, WM8750State, 2), - VMSTATE_UINT8(pol, WM8750State), - VMSTATE_UINT8(ds, WM8750State), - VMSTATE_UINT8_ARRAY(monomix, WM8750State, 2), - VMSTATE_UINT8(alc, WM8750State), - VMSTATE_UINT8(mute, WM8750State), - VMSTATE_UINT8_ARRAY(path, WM8750State, 4), - VMSTATE_UINT8_ARRAY(mpath, WM8750State, 2), - VMSTATE_UINT8(format, WM8750State), - VMSTATE_UINT8(power, WM8750State), - VMSTATE_UINT8(rate_vmstate, WM8750State), - VMSTATE_I2C_SLAVE(parent_obj, WM8750State), - VMSTATE_END_OF_LIST() - } -}; - -static void wm8750_realize(DeviceState *dev, Error **errp) -{ - WM8750State *s = WM8750(dev); - - if (!audio_be_check(&s->audio_be, errp)) { - return; - } - - wm8750_reset(I2C_SLAVE(s)); -} - -#if 0 -static void wm8750_fini(I2CSlave *i2c) -{ - WM8750State *s = WM8750(i2c); - - wm8750_reset(I2C_SLAVE(s)); - g_free(s); -} -#endif - -void wm8750_data_req_set(DeviceState *dev, data_req_cb *data_req, void *opaque) -{ - WM8750State *s = WM8750(dev); - - s->data_req = data_req; - s->opaque = opaque; -} - -void wm8750_dac_dat(void *opaque, uint32_t sample) -{ - WM8750State *s = (WM8750State *) opaque; - - *(uint32_t *) &s->data_out[s->idx_out] = sample; - s->req_out -= 4; - s->idx_out += 4; - if (s->idx_out >= sizeof(s->data_out) || s->req_out <= 0) - wm8750_out_flush(s); -} - -void *wm8750_dac_buffer(void *opaque, int samples) -{ - WM8750State *s = (WM8750State *) opaque; - /* XXX: Should check if there are <i>samples</i> free samples available */ - void *ret = s->data_out + s->idx_out; - - s->idx_out += samples << 2; - s->req_out -= samples << 2; - return ret; -} - -void wm8750_dac_commit(void *opaque) -{ - WM8750State *s = (WM8750State *) opaque; - - wm8750_out_flush(s); -} - -uint32_t wm8750_adc_dat(void *opaque) -{ - WM8750State *s = (WM8750State *) opaque; - uint32_t *data; - - if (s->idx_in >= sizeof(s->data_in)) { - wm8750_in_load(s); - if (s->idx_in >= sizeof(s->data_in)) { - return 0x80008000; /* silence in AUDIO_FORMAT_S16 sample format */ - } - } - - data = (uint32_t *) &s->data_in[s->idx_in]; - s->req_in -= 4; - s->idx_in += 4; - return *data; -} - -void wm8750_set_bclk_in(void *opaque, int new_hz) -{ - WM8750State *s = (WM8750State *) opaque; - - s->ext_adc_hz = new_hz; - s->ext_dac_hz = new_hz; - wm8750_clk_update(s, 1); -} - -static const Property wm8750_properties[] = { - DEFINE_AUDIO_PROPERTIES(WM8750State, audio_be), -}; - -static void wm8750_class_init(ObjectClass *klass, const void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); - - dc->realize = wm8750_realize; - sc->event = wm8750_event; - sc->recv = wm8750_rx; - sc->send = wm8750_tx; - dc->vmsd = &vmstate_wm8750; - device_class_set_props(dc, wm8750_properties); -} - -static const TypeInfo wm8750_info = { - .name = TYPE_WM8750, - .parent = TYPE_I2C_SLAVE, - .instance_size = sizeof(WM8750State), - .class_init = wm8750_class_init, -}; - -static void wm8750_register_types(void) -{ - type_register_static(&wm8750_info); -} - -type_init(wm8750_register_types) diff --git a/include/hw/audio/wm8750.h b/include/hw/audio/wm8750.h deleted file mode 100644 index f7bafd5e38..0000000000 --- a/include/hw/audio/wm8750.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2 or later, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef HW_DAC_WM8750_H -#define HW_DAC_WM8750_H - - -#define TYPE_WM8750 "wm8750" -#define TYPE_MV88W8618_AUDIO "mv88w8618_audio" - -typedef void data_req_cb(void *opaque, int free_out, int free_in); - -void wm8750_data_req_set(DeviceState *dev, data_req_cb *data_req, void *opaque); -void wm8750_dac_dat(void *opaque, uint32_t sample); -uint32_t wm8750_adc_dat(void *opaque); -void *wm8750_dac_buffer(void *opaque, int samples); -void wm8750_dac_commit(void *opaque); -void wm8750_set_bclk_in(void *opaque, int new_hz); - -#endif -- 2.43.0