First cut at WM8750 volume control (Jan Kiszka).
[qemu] / hw / wm8750.c
1 /*
2  * WM8750 audio CODEC.
3  *
4  * Copyright (c) 2006 Openedhand Ltd.
5  * Written by Andrzej Zaborowski <balrog@zabor.org>
6  *
7  * This file is licensed under GNU GPL.
8  */
9
10 #include "hw.h"
11 #include "i2c.h"
12 #include "audio/audio.h"
13
14 #define IN_PORT_N       3
15 #define OUT_PORT_N      3
16
17 #define CODEC           "wm8750"
18
19 struct wm_rate_s;
20 struct wm8750_s {
21     i2c_slave i2c;
22     uint8_t i2c_data[2];
23     int i2c_len;
24     QEMUSoundCard card;
25     SWVoiceIn *adc_voice[IN_PORT_N];
26     SWVoiceOut *dac_voice[OUT_PORT_N];
27     int enable;
28     void (*data_req)(void *, int, int);
29     void *opaque;
30     uint8_t data_in[4096];
31     uint8_t data_out[4096];
32     int idx_in, req_in;
33     int idx_out, req_out;
34
35     SWVoiceOut **out[2];
36     uint8_t outvol[7], outmute[2];
37     SWVoiceIn **in[2];
38     uint8_t invol[4], inmute[2];
39
40     uint8_t diff[2], pol, ds, monomix[2], alc, mute;
41     uint8_t path[4], mpath[2], power, format;
42     const struct wm_rate_s *rate;
43 };
44
45 /* pow(10.0, -i / 20.0), i = 0..42 */
46 static const uint8_t wm8750_vol_db_table[] = {
47     255, 227, 203, 181, 161, 143, 128, 114, 102, 90, 81, 72, 64, 57, 51, 45,
48     40, 36, 32, 29, 26, 23, 20, 18, 16, 14, 13, 11, 10, 9, 8, 7, 6, 6, 5, 5,
49     4, 4, 3, 3, 3, 2, 2
50 };
51
52 #define WM8750_VOL_TRANSFORM(x) wm8750_vol_db_table[(0x7f - x) / 3]
53
54 static inline void wm8750_in_load(struct wm8750_s *s)
55 {
56     int acquired;
57     if (s->idx_in + s->req_in <= sizeof(s->data_in))
58         return;
59     s->idx_in = audio_MAX(0, (int) sizeof(s->data_in) - s->req_in);
60     acquired = AUD_read(*s->in[0], s->data_in + s->idx_in,
61                     sizeof(s->data_in) - s->idx_in);
62 }
63
64 static inline void wm8750_out_flush(struct wm8750_s *s)
65 {
66     int sent = 0;
67     while (sent < s->idx_out)
68         sent += AUD_write(*s->out[0], s->data_out + sent, s->idx_out - sent)
69                 ?: s->idx_out;
70     s->idx_out = 0;
71 }
72
73 static void wm8750_audio_in_cb(void *opaque, int avail_b)
74 {
75     struct wm8750_s *s = (struct wm8750_s *) opaque;
76     s->req_in = avail_b;
77     s->data_req(s->opaque, s->req_out >> 2, avail_b >> 2);
78 }
79
80 static void wm8750_audio_out_cb(void *opaque, int free_b)
81 {
82     struct wm8750_s *s = (struct wm8750_s *) opaque;
83
84     if (s->idx_out >= free_b) {
85         s->idx_out = free_b;
86         s->req_out = 0;
87         wm8750_out_flush(s);
88     } else
89         s->req_out = free_b - s->idx_out;
90  
91     s->data_req(s->opaque, s->req_out >> 2, s->req_in >> 2);
92 }
93
94 struct wm_rate_s {
95     int adc;
96     int adc_hz;
97     int dac;
98     int dac_hz;
99 };
100
101 static const struct wm_rate_s wm_rate_table[] = {
102     {  256, 48000,  256, 48000 },       /* SR: 00000 */
103     {  384, 48000,  384, 48000 },       /* SR: 00001 */
104     {  256, 48000, 1536,  8000 },       /* SR: 00010 */
105     {  384, 48000, 2304,  8000 },       /* SR: 00011 */
106     { 1536,  8000,  256, 48000 },       /* SR: 00100 */
107     { 2304,  8000,  384, 48000 },       /* SR: 00101 */
108     { 1536,  8000, 1536,  8000 },       /* SR: 00110 */
109     { 2304,  8000, 2304,  8000 },       /* SR: 00111 */
110     { 1024, 12000, 1024, 12000 },       /* SR: 01000 */
111     { 1526, 12000, 1536, 12000 },       /* SR: 01001 */
112     {  768, 16000,  768, 16000 },       /* SR: 01010 */
113     { 1152, 16000, 1152, 16000 },       /* SR: 01011 */
114     {  384, 32000,  384, 32000 },       /* SR: 01100 */
115     {  576, 32000,  576, 32000 },       /* SR: 01101 */
116     {  128, 96000,  128, 96000 },       /* SR: 01110 */
117     {  192, 96000,  192, 96000 },       /* SR: 01111 */
118     {  256, 44100,  256, 44100 },       /* SR: 10000 */
119     {  384, 44100,  384, 44100 },       /* SR: 10001 */
120     {  256, 44100, 1408,  8018 },       /* SR: 10010 */
121     {  384, 44100, 2112,  8018 },       /* SR: 10011 */
122     { 1408,  8018,  256, 44100 },       /* SR: 10100 */
123     { 2112,  8018,  384, 44100 },       /* SR: 10101 */
124     { 1408,  8018, 1408,  8018 },       /* SR: 10110 */
125     { 2112,  8018, 2112,  8018 },       /* SR: 10111 */
126     { 1024, 11025, 1024, 11025 },       /* SR: 11000 */
127     { 1536, 11025, 1536, 11025 },       /* SR: 11001 */
128     {  512, 22050,  512, 22050 },       /* SR: 11010 */
129     {  768, 22050,  768, 22050 },       /* SR: 11011 */
130     {  512, 24000,  512, 24000 },       /* SR: 11100 */
131     {  768, 24000,  768, 24000 },       /* SR: 11101 */
132     {  128, 88200,  128, 88200 },       /* SR: 11110 */
133     {  192, 88200,  192, 88200 },       /* SR: 11111 */
134 };
135
136 static void wm8750_vol_update(struct wm8750_s *s)
137 {
138     /* FIXME: multiply all volumes by s->invol[2], s->invol[3] */
139
140     AUD_set_volume_in(*s->in[0], s->mute,
141                     s->inmute[0] ? 0 : 0xff,
142                     s->inmute[1] ? 0 : 0xff);
143
144     /* FIXME: multiply all volumes by s->outvol[0], s->outvol[1] */
145
146     /* Speaker: LOUT2VOL ROUT2VOL */
147     AUD_set_volume_out(s->dac_voice[0], s->mute,
148                     s->outmute[0] ? 0 : WM8750_VOL_TRANSFORM(s->outvol[4]),
149                     s->outmute[1] ? 0 : WM8750_VOL_TRANSFORM(s->outvol[5]));
150
151     /* Headphone: LOUT2VOL ROUT2VOL */
152     AUD_set_volume_out(s->dac_voice[1], s->mute,
153                     s->outmute[0] ? 0 : WM8750_VOL_TRANSFORM(s->outvol[2]),
154                     s->outmute[1] ? 0 : WM8750_VOL_TRANSFORM(s->outvol[3]));
155
156     /* MONOOUT: MONOVOL MONOVOL */
157     AUD_set_volume_out(s->dac_voice[2], s->mute,
158                     s->outmute[0] ? 0 : WM8750_VOL_TRANSFORM(s->outvol[6]),
159                     s->outmute[1] ? 0 : WM8750_VOL_TRANSFORM(s->outvol[6]));
160 }
161
162 static void wm8750_set_format(struct wm8750_s *s)
163 {
164     int i;
165     audsettings_t in_fmt;
166     audsettings_t out_fmt;
167     audsettings_t monoout_fmt;
168
169     wm8750_out_flush(s);
170
171     if (s->in[0] && *s->in[0])
172         AUD_set_active_in(*s->in[0], 0);
173     if (s->out[0] && *s->out[0])
174         AUD_set_active_out(*s->out[0], 0);
175
176     for (i = 0; i < IN_PORT_N; i ++)
177         if (s->adc_voice[i]) {
178             AUD_close_in(&s->card, s->adc_voice[i]);
179             s->adc_voice[i] = 0;
180         }
181     for (i = 0; i < OUT_PORT_N; i ++)
182         if (s->dac_voice[i]) {
183             AUD_close_out(&s->card, s->dac_voice[i]);
184             s->dac_voice[i] = 0;
185         }
186
187     if (!s->enable)
188         return;
189
190     /* Setup input */
191     in_fmt.endianness = 0;
192     in_fmt.nchannels = 2;
193     in_fmt.freq = s->rate->adc_hz;
194     in_fmt.fmt = AUD_FMT_S16;
195
196     s->adc_voice[0] = AUD_open_in(&s->card, s->adc_voice[0],
197                     CODEC ".input1", s, wm8750_audio_in_cb, &in_fmt);
198     s->adc_voice[1] = AUD_open_in(&s->card, s->adc_voice[1],
199                     CODEC ".input2", s, wm8750_audio_in_cb, &in_fmt);
200     s->adc_voice[2] = AUD_open_in(&s->card, s->adc_voice[2],
201                     CODEC ".input3", s, wm8750_audio_in_cb, &in_fmt);
202
203     /* Setup output */
204     out_fmt.endianness = 0;
205     out_fmt.nchannels = 2;
206     out_fmt.freq = s->rate->dac_hz;
207     out_fmt.fmt = AUD_FMT_S16;
208     monoout_fmt.endianness = 0;
209     monoout_fmt.nchannels = 1;
210     monoout_fmt.freq = s->rate->dac_hz;
211     monoout_fmt.fmt = AUD_FMT_S16;
212
213     s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
214                     CODEC ".speaker", s, wm8750_audio_out_cb, &out_fmt);
215     s->dac_voice[1] = AUD_open_out(&s->card, s->dac_voice[1],
216                     CODEC ".headphone", s, wm8750_audio_out_cb, &out_fmt);
217     /* MONOMIX is also in stereo for simplicity */
218     s->dac_voice[2] = AUD_open_out(&s->card, s->dac_voice[2],
219                     CODEC ".monomix", s, wm8750_audio_out_cb, &out_fmt);
220     /* no sense emulating OUT3 which is a mix of other outputs */
221
222     wm8750_vol_update(s);
223
224     /* We should connect the left and right channels to their
225      * respective inputs/outputs but we have completely no need
226      * for mixing or combining paths to different ports, so we
227      * connect both channels to where the left channel is routed.  */
228     if (s->in[0] && *s->in[0])
229         AUD_set_active_in(*s->in[0], 1);
230     if (s->out[0] && *s->out[0])
231         AUD_set_active_out(*s->out[0], 1);
232 }
233
234 void wm8750_reset(i2c_slave *i2c)
235 {
236     struct wm8750_s *s = (struct wm8750_s *) i2c;
237     s->rate = &wm_rate_table[0];
238     s->enable = 0;
239     wm8750_set_format(s);
240     s->diff[0] = 0;
241     s->diff[1] = 0;
242     s->ds = 0;
243     s->alc = 0;
244     s->in[0] = &s->adc_voice[0];
245     s->invol[0] = 0x17;
246     s->invol[1] = 0x17;
247     s->invol[2] = 0xc3;
248     s->invol[3] = 0xc3;
249     s->out[0] = &s->dac_voice[0];
250     s->outvol[0] = 0xff;
251     s->outvol[1] = 0xff;
252     s->outvol[2] = 0x79;
253     s->outvol[3] = 0x79;
254     s->outvol[4] = 0x79;
255     s->outvol[5] = 0x79;
256     s->inmute[0] = 0;
257     s->inmute[1] = 0;
258     s->outmute[0] = 0;
259     s->outmute[1] = 0;
260     s->mute = 1;
261     s->path[0] = 0;
262     s->path[1] = 0;
263     s->path[2] = 0;
264     s->path[3] = 0;
265     s->mpath[0] = 0;
266     s->mpath[1] = 0;
267     s->format = 0x0a;
268     s->idx_in = sizeof(s->data_in);
269     s->req_in = 0;
270     s->idx_out = 0;
271     s->req_out = 0;
272     wm8750_vol_update(s);
273     s->i2c_len = 0;
274 }
275
276 static void wm8750_event(i2c_slave *i2c, enum i2c_event event)
277 {
278     struct wm8750_s *s = (struct wm8750_s *) i2c;
279
280     switch (event) {
281     case I2C_START_SEND:
282         s->i2c_len = 0;
283         break;
284     case I2C_FINISH:
285 #ifdef VERBOSE
286         if (s->i2c_len < 2)
287             printf("%s: message too short (%i bytes)\n",
288                             __FUNCTION__, s->i2c_len);
289 #endif
290         break;
291     default:
292         break;
293     }
294 }
295
296 #define WM8750_LINVOL   0x00
297 #define WM8750_RINVOL   0x01
298 #define WM8750_LOUT1V   0x02
299 #define WM8750_ROUT1V   0x03
300 #define WM8750_ADCDAC   0x05
301 #define WM8750_IFACE    0x07
302 #define WM8750_SRATE    0x08
303 #define WM8750_LDAC     0x0a
304 #define WM8750_RDAC     0x0b
305 #define WM8750_BASS     0x0c
306 #define WM8750_TREBLE   0x0d
307 #define WM8750_RESET    0x0f
308 #define WM8750_3D       0x10
309 #define WM8750_ALC1     0x11
310 #define WM8750_ALC2     0x12
311 #define WM8750_ALC3     0x13
312 #define WM8750_NGATE    0x14
313 #define WM8750_LADC     0x15
314 #define WM8750_RADC     0x16
315 #define WM8750_ADCTL1   0x17
316 #define WM8750_ADCTL2   0x18
317 #define WM8750_PWR1     0x19
318 #define WM8750_PWR2     0x1a
319 #define WM8750_ADCTL3   0x1b
320 #define WM8750_ADCIN    0x1f
321 #define WM8750_LADCIN   0x20
322 #define WM8750_RADCIN   0x21
323 #define WM8750_LOUTM1   0x22
324 #define WM8750_LOUTM2   0x23
325 #define WM8750_ROUTM1   0x24
326 #define WM8750_ROUTM2   0x25
327 #define WM8750_MOUTM1   0x26
328 #define WM8750_MOUTM2   0x27
329 #define WM8750_LOUT2V   0x28
330 #define WM8750_ROUT2V   0x29
331 #define WM8750_MOUTV    0x2a
332
333 static int wm8750_tx(i2c_slave *i2c, uint8_t data)
334 {
335     struct wm8750_s *s = (struct wm8750_s *) i2c;
336     uint8_t cmd;
337     uint16_t value;
338
339     if (s->i2c_len >= 2) {
340         printf("%s: long message (%i bytes)\n", __FUNCTION__, s->i2c_len);
341 #ifdef VERBOSE
342         return 1;
343 #endif
344     }
345     s->i2c_data[s->i2c_len ++] = data;
346     if (s->i2c_len != 2)
347         return 0;
348
349     cmd = s->i2c_data[0] >> 1;
350     value = ((s->i2c_data[0] << 8) | s->i2c_data[1]) & 0x1ff;
351
352     switch (cmd) {
353     case WM8750_LADCIN: /* ADC Signal Path Control (Left) */
354         s->diff[0] = (((value >> 6) & 3) == 3); /* LINSEL */
355         if (s->diff[0])
356             s->in[0] = &s->adc_voice[0 + s->ds * 1];
357         else
358             s->in[0] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];
359         break;
360
361     case WM8750_RADCIN: /* ADC Signal Path Control (Right) */
362         s->diff[1] = (((value >> 6) & 3) == 3); /* RINSEL */
363         if (s->diff[1])
364             s->in[1] = &s->adc_voice[0 + s->ds * 1];
365         else
366             s->in[1] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];
367         break;
368
369     case WM8750_ADCIN:  /* ADC Input Mode */
370         s->ds = (value >> 8) & 1;       /* DS */
371         if (s->diff[0])
372             s->in[0] = &s->adc_voice[0 + s->ds * 1];
373         if (s->diff[1])
374             s->in[1] = &s->adc_voice[0 + s->ds * 1];
375         s->monomix[0] = (value >> 6) & 3;       /* MONOMIX */
376         break;
377
378     case WM8750_ADCTL1: /* Additional Control (1) */
379         s->monomix[1] = (value >> 1) & 1;       /* DMONOMIX */
380         break;
381
382     case WM8750_PWR1:   /* Power Management (1) */
383         s->enable = ((value >> 6) & 7) == 3;    /* VMIDSEL, VREF */
384         wm8750_set_format(s);
385         break;
386
387     case WM8750_LINVOL: /* Left Channel PGA */
388         s->invol[0] = value & 0x3f;             /* LINVOL */
389         s->inmute[0] = (value >> 7) & 1;        /* LINMUTE */
390         wm8750_vol_update(s);
391         break;
392
393     case WM8750_RINVOL: /* Right Channel PGA */
394         s->invol[1] = value & 0x3f;             /* RINVOL */
395         s->inmute[1] = (value >> 7) & 1;        /* RINMUTE */
396         wm8750_vol_update(s);
397         break;
398
399     case WM8750_ADCDAC: /* ADC and DAC Control */
400         s->pol = (value >> 5) & 3;              /* ADCPOL */
401         s->mute = (value >> 3) & 1;             /* DACMU */
402         wm8750_vol_update(s);
403         break;
404
405     case WM8750_ADCTL3: /* Additional Control (3) */
406         break;
407
408     case WM8750_LADC:   /* Left ADC Digital Volume */
409         s->invol[2] = value & 0xff;             /* LADCVOL */
410         break;
411
412     case WM8750_RADC:   /* Right ADC Digital Volume */
413         s->invol[3] = value & 0xff;             /* RADCVOL */
414         break;
415
416     case WM8750_ALC1:   /* ALC Control (1) */
417         s->alc = (value >> 7) & 3;              /* ALCSEL */
418         break;
419
420     case WM8750_NGATE:  /* Noise Gate Control */
421     case WM8750_3D:     /* 3D enhance */
422         break;
423
424     case WM8750_LDAC:   /* Left Channel Digital Volume */
425         s->outvol[0] = value & 0xff;            /* LDACVOL */
426         break;
427
428     case WM8750_RDAC:   /* Right Channel Digital Volume */
429         s->outvol[1] = value & 0xff;            /* RDACVOL */
430         break;
431
432     case WM8750_BASS:   /* Bass Control */
433         break;
434
435     case WM8750_LOUTM1: /* Left Mixer Control (1) */
436         s->path[0] = (value >> 8) & 1;          /* LD2LO */
437         break;
438
439     case WM8750_LOUTM2: /* Left Mixer Control (2) */
440         s->path[1] = (value >> 8) & 1;          /* RD2LO */
441         break;
442
443     case WM8750_ROUTM1: /* Right Mixer Control (1) */
444         s->path[2] = (value >> 8) & 1;          /* LD2RO */
445         break;
446
447     case WM8750_ROUTM2: /* Right Mixer Control (2) */
448         s->path[3] = (value >> 8) & 1;          /* RD2RO */
449         break;
450
451     case WM8750_MOUTM1: /* Mono Mixer Control (1) */
452         s->mpath[0] = (value >> 8) & 1;         /* LD2MO */
453         break;
454
455     case WM8750_MOUTM2: /* Mono Mixer Control (2) */
456         s->mpath[1] = (value >> 8) & 1;         /* RD2MO */
457         break;
458
459     case WM8750_LOUT1V: /* LOUT1 Volume */
460         s->outvol[2] = value & 0x7f;            /* LOUT1VOL */
461         break;
462
463     case WM8750_LOUT2V: /* LOUT2 Volume */
464         s->outvol[4] = value & 0x7f;            /* LOUT2VOL */
465         wm8750_vol_update(s);
466         break;
467
468     case WM8750_ROUT1V: /* ROUT1 Volume */
469         s->outvol[3] = value & 0x7f;            /* ROUT1VOL */
470         break;
471
472     case WM8750_ROUT2V: /* ROUT2 Volume */
473         s->outvol[5] = value & 0x7f;            /* ROUT2VOL */
474         wm8750_vol_update(s);
475         break;
476
477     case WM8750_MOUTV:  /* MONOOUT Volume */
478         s->outvol[6] = value & 0x7f;            /* MONOOUTVOL */
479         break;
480
481     case WM8750_ADCTL2: /* Additional Control (2) */
482         break;
483
484     case WM8750_PWR2:   /* Power Management (2) */
485         s->power = value & 0x7e;
486         break;
487
488     case WM8750_IFACE:  /* Digital Audio Interface Format */
489 #ifdef VERBOSE
490         if (value & 0x40)                       /* MS */
491             printf("%s: attempt to enable Master Mode\n", __FUNCTION__);
492 #endif
493         s->format = value;
494         wm8750_set_format(s);
495         break;
496
497     case WM8750_SRATE:  /* Clocking and Sample Rate Control */
498         s->rate = &wm_rate_table[(value >> 1) & 0x1f];
499         wm8750_set_format(s);
500         break;
501
502     case WM8750_RESET:  /* Reset */
503         wm8750_reset(&s->i2c);
504         break;
505
506 #ifdef VERBOSE
507     default:
508         printf("%s: unknown register %02x\n", __FUNCTION__, cmd);
509 #endif
510     }
511
512     return 0;
513 }
514
515 static int wm8750_rx(i2c_slave *i2c)
516 {
517     return 0x00;
518 }
519
520 static void wm8750_save(QEMUFile *f, void *opaque)
521 {
522     struct wm8750_s *s = (struct wm8750_s *) opaque;
523     int i;
524     qemu_put_8s(f, &s->i2c_data[0]);
525     qemu_put_8s(f, &s->i2c_data[1]);
526     qemu_put_be32(f, s->i2c_len);
527     qemu_put_be32(f, s->enable);
528     qemu_put_be32(f, s->idx_in);
529     qemu_put_be32(f, s->req_in);
530     qemu_put_be32(f, s->idx_out);
531     qemu_put_be32(f, s->req_out);
532
533     for (i = 0; i < 7; i ++)
534         qemu_put_8s(f, &s->outvol[i]);
535     for (i = 0; i < 2; i ++)
536         qemu_put_8s(f, &s->outmute[i]);
537     for (i = 0; i < 4; i ++)
538         qemu_put_8s(f, &s->invol[i]);
539     for (i = 0; i < 2; i ++)
540         qemu_put_8s(f, &s->inmute[i]);
541
542     for (i = 0; i < 2; i ++)
543         qemu_put_8s(f, &s->diff[i]);
544     qemu_put_8s(f, &s->pol);
545     qemu_put_8s(f, &s->ds);
546     for (i = 0; i < 2; i ++)
547         qemu_put_8s(f, &s->monomix[i]);
548     qemu_put_8s(f, &s->alc);
549     qemu_put_8s(f, &s->mute);
550     for (i = 0; i < 4; i ++)
551         qemu_put_8s(f, &s->path[i]);
552     for (i = 0; i < 2; i ++)
553         qemu_put_8s(f, &s->mpath[i]);
554     qemu_put_8s(f, &s->format);
555     qemu_put_8s(f, &s->power);
556     qemu_put_byte(f, (s->rate - wm_rate_table) / sizeof(*s->rate));
557     i2c_slave_save(f, &s->i2c);
558 }
559
560 static int wm8750_load(QEMUFile *f, void *opaque, int version_id)
561 {
562     struct wm8750_s *s = (struct wm8750_s *) opaque;
563     int i;
564     qemu_get_8s(f, &s->i2c_data[0]);
565     qemu_get_8s(f, &s->i2c_data[1]);
566     s->i2c_len = qemu_get_be32(f);
567     s->enable = qemu_get_be32(f);
568     s->idx_in = qemu_get_be32(f);
569     s->req_in = qemu_get_be32(f);
570     s->idx_out = qemu_get_be32(f);
571     s->req_out = qemu_get_be32(f);
572
573     for (i = 0; i < 7; i ++)
574         qemu_get_8s(f, &s->outvol[i]);
575     for (i = 0; i < 2; i ++)
576         qemu_get_8s(f, &s->outmute[i]);
577     for (i = 0; i < 4; i ++)
578         qemu_get_8s(f, &s->invol[i]);
579     for (i = 0; i < 2; i ++)
580         qemu_get_8s(f, &s->inmute[i]);
581
582     for (i = 0; i < 2; i ++)
583         qemu_get_8s(f, &s->diff[i]);
584     qemu_get_8s(f, &s->pol);
585     qemu_get_8s(f, &s->ds);
586     for (i = 0; i < 2; i ++)
587         qemu_get_8s(f, &s->monomix[i]);
588     qemu_get_8s(f, &s->alc);
589     qemu_get_8s(f, &s->mute);
590     for (i = 0; i < 4; i ++)
591         qemu_get_8s(f, &s->path[i]);
592     for (i = 0; i < 2; i ++)
593         qemu_get_8s(f, &s->mpath[i]);
594     qemu_get_8s(f, &s->format);
595     qemu_get_8s(f, &s->power);
596     s->rate = &wm_rate_table[(uint8_t) qemu_get_byte(f) & 0x1f];
597     i2c_slave_load(f, &s->i2c);
598     return 0;
599 }
600
601 static int wm8750_iid = 0;
602
603 i2c_slave *wm8750_init(i2c_bus *bus, AudioState *audio)
604 {
605     struct wm8750_s *s = (struct wm8750_s *)
606             i2c_slave_init(bus, 0, sizeof(struct wm8750_s));
607     s->i2c.event = wm8750_event;
608     s->i2c.recv = wm8750_rx;
609     s->i2c.send = wm8750_tx;
610
611     AUD_register_card(audio, CODEC, &s->card);
612     wm8750_reset(&s->i2c);
613
614     register_savevm(CODEC, wm8750_iid ++, 0, wm8750_save, wm8750_load, s);
615
616     return &s->i2c;
617 }
618
619 #if 0
620 static void wm8750_fini(i2c_slave *i2c)
621 {
622     struct wm8750_s *s = (struct wm8750_s *) i2c;
623     wm8750_reset(&s->i2c);
624     AUD_remove_card(&s->card);
625     qemu_free(s);
626 }
627 #endif
628
629 void wm8750_data_req_set(i2c_slave *i2c,
630                 void (*data_req)(void *, int, int), void *opaque)
631 {
632     struct wm8750_s *s = (struct wm8750_s *) i2c;
633     s->data_req = data_req;
634     s->opaque = opaque;
635 }
636
637 void wm8750_dac_dat(void *opaque, uint32_t sample)
638 {
639     struct wm8750_s *s = (struct wm8750_s *) opaque;
640     *(uint32_t *) &s->data_out[s->idx_out] = sample;
641     s->req_out -= 4;
642     s->idx_out += 4;
643     if (s->idx_out >= sizeof(s->data_out) || s->req_out <= 0)
644         wm8750_out_flush(s);
645 }
646
647 void *wm8750_dac_buffer(void *opaque, int samples)
648 {
649     struct wm8750_s *s = (struct wm8750_s *) opaque;
650     /* XXX: Should check if there are <i>samples</i> free samples available */
651     void *ret = s->data_out + s->idx_out;
652
653     s->idx_out += samples << 2;
654     s->req_out -= samples << 2;
655     return ret;
656 }
657
658 void wm8750_dac_commit(void *opaque)
659 {
660     struct wm8750_s *s = (struct wm8750_s *) opaque;
661
662     return wm8750_out_flush(s);
663 }
664
665 uint32_t wm8750_adc_dat(void *opaque)
666 {
667     struct wm8750_s *s = (struct wm8750_s *) opaque;
668     uint32_t *data;
669     if (s->idx_in >= sizeof(s->data_in))
670         wm8750_in_load(s);
671     data = (uint32_t *) &s->data_in[s->idx_in];
672     s->req_in -= 4;
673     s->idx_in += 4;
674     return *data;
675 }