]> Git Repo - qemu.git/blobdiff - hw/wm8750.c
savevm: Factorize ram globals reset in its own function
[qemu.git] / hw / wm8750.c
index c4df1250ec87ad6680075f161220e258b287bb57..44f138fd51dc5927889f7f143f7065bacd9113ee 100644 (file)
 
 #define CODEC          "wm8750"
 
-struct wm_rate_s;
-struct wm8750_s {
-    i2c_slave i2c;
+typedef struct {
+    int adc;
+    int adc_hz;
+    int dac;
+    int dac_hz;
+} WMRate;
+
+typedef struct {
+    I2CSlave i2c;
     uint8_t i2c_data[2];
     int i2c_len;
     QEMUSoundCard card;
@@ -39,8 +45,10 @@ struct wm8750_s {
 
     uint8_t diff[2], pol, ds, monomix[2], alc, mute;
     uint8_t path[4], mpath[2], power, format;
-    const struct wm_rate_s *rate;
-};
+    const WMRate *rate;
+    uint8_t rate_vmstate;
+    int adc_hz, dac_hz, ext_adc_hz, ext_dac_hz, master;
+} WM8750State;
 
 /* pow(10.0, -i / 20.0) * 255, i = 0..42 */
 static const uint8_t wm8750_vol_db_table[] = {
@@ -52,17 +60,16 @@ static const uint8_t wm8750_vol_db_table[] = {
 #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(struct wm8750_s *s)
+static inline void wm8750_in_load(WM8750State *s)
 {
-    int acquired;
     if (s->idx_in + s->req_in <= sizeof(s->data_in))
         return;
     s->idx_in = audio_MAX(0, (int) sizeof(s->data_in) - s->req_in);
-    acquired = AUD_read(*s->in[0], s->data_in + s->idx_in,
-                    sizeof(s->data_in) - s->idx_in);
+    AUD_read(*s->in[0], s->data_in + s->idx_in,
+             sizeof(s->data_in) - s->idx_in);
 }
 
-static inline void wm8750_out_flush(struct wm8750_s *s)
+static inline void wm8750_out_flush(WM8750State *s)
 {
     int sent = 0;
     while (sent < s->idx_out)
@@ -73,14 +80,14 @@ static inline void wm8750_out_flush(struct wm8750_s *s)
 
 static void wm8750_audio_in_cb(void *opaque, int avail_b)
 {
-    struct wm8750_s *s = (struct wm8750_s *) opaque;
+    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)
 {
-    struct wm8750_s *s = (struct wm8750_s *) opaque;
+    WM8750State *s = (WM8750State *) opaque;
 
     if (s->idx_out >= free_b) {
         s->idx_out = free_b;
@@ -92,14 +99,7 @@ static void wm8750_audio_out_cb(void *opaque, int free_b)
     s->data_req(s->opaque, s->req_out >> 2, s->req_in >> 2);
 }
 
-struct wm_rate_s {
-    int adc;
-    int adc_hz;
-    int dac;
-    int dac_hz;
-};
-
-static const struct wm_rate_s wm_rate_table[] = {
+static const WMRate wm_rate_table[] = {
     {  256, 48000,  256, 48000 },      /* SR: 00000 */
     {  384, 48000,  384, 48000 },      /* SR: 00001 */
     {  256, 48000, 1536,  8000 },      /* SR: 00010 */
@@ -134,7 +134,7 @@ static const struct wm_rate_s wm_rate_table[] = {
     {  192, 88200,  192, 88200 },      /* SR: 11111 */
 };
 
-static void wm8750_vol_update(struct wm8750_s *s)
+static void wm8750_vol_update(WM8750State *s)
 {
     /* FIXME: multiply all volumes by s->invol[2], s->invol[3] */
 
@@ -166,12 +166,11 @@ static void wm8750_vol_update(struct wm8750_s *s)
                     s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[6]));
 }
 
-static void wm8750_set_format(struct wm8750_s *s)
+static void wm8750_set_format(WM8750State *s)
 {
     int i;
-    audsettings_t in_fmt;
-    audsettings_t out_fmt;
-    audsettings_t monoout_fmt;
+    struct audsettings in_fmt;
+    struct audsettings out_fmt;
 
     wm8750_out_flush(s);
 
@@ -183,12 +182,12 @@ static void wm8750_set_format(struct wm8750_s *s)
     for (i = 0; i < IN_PORT_N; i ++)
         if (s->adc_voice[i]) {
             AUD_close_in(&s->card, s->adc_voice[i]);
-            s->adc_voice[i] = 0;
+            s->adc_voice[i] = NULL;
         }
     for (i = 0; i < OUT_PORT_N; i ++)
         if (s->dac_voice[i]) {
             AUD_close_out(&s->card, s->dac_voice[i]);
-            s->dac_voice[i] = 0;
+            s->dac_voice[i] = NULL;
         }
 
     if (!s->enable)
@@ -197,7 +196,7 @@ static void wm8750_set_format(struct wm8750_s *s)
     /* Setup input */
     in_fmt.endianness = 0;
     in_fmt.nchannels = 2;
-    in_fmt.freq = s->rate->adc_hz;
+    in_fmt.freq = s->adc_hz;
     in_fmt.fmt = AUD_FMT_S16;
 
     s->adc_voice[0] = AUD_open_in(&s->card, s->adc_voice[0],
@@ -210,12 +209,8 @@ static void wm8750_set_format(struct wm8750_s *s)
     /* Setup output */
     out_fmt.endianness = 0;
     out_fmt.nchannels = 2;
-    out_fmt.freq = s->rate->dac_hz;
+    out_fmt.freq = s->dac_hz;
     out_fmt.fmt = AUD_FMT_S16;
-    monoout_fmt.endianness = 0;
-    monoout_fmt.nchannels = 1;
-    monoout_fmt.freq = s->rate->dac_hz;
-    monoout_fmt.fmt = AUD_FMT_S16;
 
     s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
                     CODEC ".speaker", s, wm8750_audio_out_cb, &out_fmt);
@@ -238,12 +233,33 @@ static void wm8750_set_format(struct wm8750_s *s)
         AUD_set_active_out(*s->out[0], 1);
 }
 
-void wm8750_reset(i2c_slave *i2c)
+static void wm8750_clk_update(WM8750State *s, int ext)
 {
-    struct wm8750_s *s = (struct wm8750_s *) i2c;
+    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 = (WM8750State *) i2c;
     s->rate = &wm_rate_table[0];
     s->enable = 0;
-    wm8750_set_format(s);
+    wm8750_clk_update(s, 1);
     s->diff[0] = 0;
     s->diff[1] = 0;
     s->ds = 0;
@@ -281,9 +297,9 @@ void wm8750_reset(i2c_slave *i2c)
     s->i2c_len = 0;
 }
 
-static void wm8750_event(i2c_slave *i2c, enum i2c_event event)
+static void wm8750_event(I2CSlave *i2c, enum i2c_event event)
 {
-    struct wm8750_s *s = (struct wm8750_s *) i2c;
+    WM8750State *s = (WM8750State *) i2c;
 
     switch (event) {
     case I2C_START_SEND:
@@ -338,17 +354,17 @@ static void wm8750_event(i2c_slave *i2c, enum i2c_event event)
 #define WM8750_ROUT2V  0x29
 #define WM8750_MOUTV   0x2a
 
-static int wm8750_tx(i2c_slave *i2c, uint8_t data)
+static int wm8750_tx(I2CSlave *i2c, uint8_t data)
 {
-    struct wm8750_s *s = (struct wm8750_s *) i2c;
+    WM8750State *s = (WM8750State *) i2c;
     uint8_t cmd;
     uint16_t value;
 
     if (s->i2c_len >= 2) {
-        printf("%s: long message (%i bytes)\n", __FUNCTION__, s->i2c_len);
 #ifdef VERBOSE
-        return 1;
+        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)
@@ -515,17 +531,14 @@ static int wm8750_tx(i2c_slave *i2c, uint8_t data)
         break;
 
     case WM8750_IFACE: /* Digital Audio Interface Format */
-#ifdef VERBOSE
-        if (value & 0x40)                      /* MS */
-            printf("%s: attempt to enable Master Mode\n", __FUNCTION__);
-#endif
         s->format = value;
-        wm8750_set_format(s);
+        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_set_format(s);
+        wm8750_clk_update(s, 0);
         break;
 
     case WM8750_RESET: /* Reset */
@@ -541,131 +554,93 @@ static int wm8750_tx(i2c_slave *i2c, uint8_t data)
     return 0;
 }
 
-static int wm8750_rx(i2c_slave *i2c)
+static int wm8750_rx(I2CSlave *i2c)
 {
     return 0x00;
 }
 
-static void wm8750_save(QEMUFile *f, void *opaque)
+static void wm8750_pre_save(void *opaque)
 {
-    struct wm8750_s *s = (struct wm8750_s *) opaque;
-    int i;
-    qemu_put_8s(f, &s->i2c_data[0]);
-    qemu_put_8s(f, &s->i2c_data[1]);
-    qemu_put_be32(f, s->i2c_len);
-    qemu_put_be32(f, s->enable);
-    qemu_put_be32(f, s->idx_in);
-    qemu_put_be32(f, s->req_in);
-    qemu_put_be32(f, s->idx_out);
-    qemu_put_be32(f, s->req_out);
-
-    for (i = 0; i < 7; i ++)
-        qemu_put_8s(f, &s->outvol[i]);
-    for (i = 0; i < 2; i ++)
-        qemu_put_8s(f, &s->outmute[i]);
-    for (i = 0; i < 4; i ++)
-        qemu_put_8s(f, &s->invol[i]);
-    for (i = 0; i < 2; i ++)
-        qemu_put_8s(f, &s->inmute[i]);
-
-    for (i = 0; i < 2; i ++)
-        qemu_put_8s(f, &s->diff[i]);
-    qemu_put_8s(f, &s->pol);
-    qemu_put_8s(f, &s->ds);
-    for (i = 0; i < 2; i ++)
-        qemu_put_8s(f, &s->monomix[i]);
-    qemu_put_8s(f, &s->alc);
-    qemu_put_8s(f, &s->mute);
-    for (i = 0; i < 4; i ++)
-        qemu_put_8s(f, &s->path[i]);
-    for (i = 0; i < 2; i ++)
-        qemu_put_8s(f, &s->mpath[i]);
-    qemu_put_8s(f, &s->format);
-    qemu_put_8s(f, &s->power);
-    qemu_put_byte(f, (s->rate - wm_rate_table) / sizeof(*s->rate));
-    i2c_slave_save(f, &s->i2c);
+    WM8750State *s = opaque;
+
+    s->rate_vmstate = s->rate - wm_rate_table;
 }
 
-static int wm8750_load(QEMUFile *f, void *opaque, int version_id)
+static int wm8750_post_load(void *opaque, int version_id)
 {
-    struct wm8750_s *s = (struct wm8750_s *) opaque;
-    int i;
-    qemu_get_8s(f, &s->i2c_data[0]);
-    qemu_get_8s(f, &s->i2c_data[1]);
-    s->i2c_len = qemu_get_be32(f);
-    s->enable = qemu_get_be32(f);
-    s->idx_in = qemu_get_be32(f);
-    s->req_in = qemu_get_be32(f);
-    s->idx_out = qemu_get_be32(f);
-    s->req_out = qemu_get_be32(f);
-
-    for (i = 0; i < 7; i ++)
-        qemu_get_8s(f, &s->outvol[i]);
-    for (i = 0; i < 2; i ++)
-        qemu_get_8s(f, &s->outmute[i]);
-    for (i = 0; i < 4; i ++)
-        qemu_get_8s(f, &s->invol[i]);
-    for (i = 0; i < 2; i ++)
-        qemu_get_8s(f, &s->inmute[i]);
-
-    for (i = 0; i < 2; i ++)
-        qemu_get_8s(f, &s->diff[i]);
-    qemu_get_8s(f, &s->pol);
-    qemu_get_8s(f, &s->ds);
-    for (i = 0; i < 2; i ++)
-        qemu_get_8s(f, &s->monomix[i]);
-    qemu_get_8s(f, &s->alc);
-    qemu_get_8s(f, &s->mute);
-    for (i = 0; i < 4; i ++)
-        qemu_get_8s(f, &s->path[i]);
-    for (i = 0; i < 2; i ++)
-        qemu_get_8s(f, &s->mpath[i]);
-    qemu_get_8s(f, &s->format);
-    qemu_get_8s(f, &s->power);
-    s->rate = &wm_rate_table[(uint8_t) qemu_get_byte(f) & 0x1f];
-    i2c_slave_load(f, &s->i2c);
+    WM8750State *s = opaque;
+
+    s->rate = &wm_rate_table[s->rate_vmstate & 0x1f];
     return 0;
 }
 
-static int wm8750_iid = 0;
+static const VMStateDescription vmstate_wm8750 = {
+    .name = CODEC,
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .pre_save = wm8750_pre_save,
+    .post_load = wm8750_post_load,
+    .fields      = (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(i2c, WM8750State),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
-i2c_slave *wm8750_init(i2c_bus *bus, AudioState *audio)
+static int wm8750_init(I2CSlave *i2c)
 {
-    struct wm8750_s *s = (struct wm8750_s *)
-            i2c_slave_init(bus, 0, sizeof(struct wm8750_s));
-    s->i2c.event = wm8750_event;
-    s->i2c.recv = wm8750_rx;
-    s->i2c.send = wm8750_tx;
+    WM8750State *s = FROM_I2C_SLAVE(WM8750State, i2c);
 
-    AUD_register_card(audio, CODEC, &s->card);
+    AUD_register_card(CODEC, &s->card);
     wm8750_reset(&s->i2c);
 
-    register_savevm(CODEC, wm8750_iid ++, 0, wm8750_save, wm8750_load, s);
-
-    return &s->i2c;
+    return 0;
 }
 
 #if 0
-static void wm8750_fini(i2c_slave *i2c)
+static void wm8750_fini(I2CSlave *i2c)
 {
-    struct wm8750_s *s = (struct wm8750_s *) i2c;
+    WM8750State *s = (WM8750State *) i2c;
     wm8750_reset(&s->i2c);
     AUD_remove_card(&s->card);
-    qemu_free(s);
+    g_free(s);
 }
 #endif
 
-void wm8750_data_req_set(i2c_slave *i2c,
+void wm8750_data_req_set(DeviceState *dev,
                 void (*data_req)(void *, int, int), void *opaque)
 {
-    struct wm8750_s *s = (struct wm8750_s *) i2c;
+    WM8750State *s = FROM_I2C_SLAVE(WM8750State, I2C_SLAVE_FROM_QDEV(dev));
     s->data_req = data_req;
     s->opaque = opaque;
 }
 
 void wm8750_dac_dat(void *opaque, uint32_t sample)
 {
-    struct wm8750_s *s = (struct wm8750_s *) opaque;
+    WM8750State *s = (WM8750State *) opaque;
+
     *(uint32_t *) &s->data_out[s->idx_out] = sample;
     s->req_out -= 4;
     s->idx_out += 4;
@@ -675,7 +650,7 @@ void wm8750_dac_dat(void *opaque, uint32_t sample)
 
 void *wm8750_dac_buffer(void *opaque, int samples)
 {
-    struct wm8750_s *s = (struct wm8750_s *) opaque;
+    WM8750State *s = (WM8750State *) opaque;
     /* XXX: Should check if there are <i>samples</i> free samples available */
     void *ret = s->data_out + s->idx_out;
 
@@ -686,19 +661,56 @@ void *wm8750_dac_buffer(void *opaque, int samples)
 
 void wm8750_dac_commit(void *opaque)
 {
-    struct wm8750_s *s = (struct wm8750_s *) opaque;
+    WM8750State *s = (WM8750State *) opaque;
 
-    return wm8750_out_flush(s);
+    wm8750_out_flush(s);
 }
 
 uint32_t wm8750_adc_dat(void *opaque)
 {
-    struct wm8750_s *s = (struct wm8750_s *) opaque;
+    WM8750State *s = (WM8750State *) opaque;
     uint32_t *data;
+
     if (s->idx_in >= sizeof(s->data_in))
         wm8750_in_load(s);
+
     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 void wm8750_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
+
+    sc->init = wm8750_init;
+    sc->event = wm8750_event;
+    sc->recv = wm8750_rx;
+    sc->send = wm8750_tx;
+    dc->vmsd = &vmstate_wm8750;
+}
+
+static TypeInfo wm8750_info = {
+    .name          = "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)
This page took 0.039236 seconds and 4 git commands to generate.