Commit 683efdcbdb83a45f8a6ff52831855d06a56df469

Authored by balrog
1 parent 39454628

First cut at WM8750 volume control (Jan Kiszka).


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4321 c046a42c-6fe2-441c-8c8c-71466251a162
audio/audio.c
@@ -117,8 +117,8 @@ volume_t nominal_volume = { @@ -117,8 +117,8 @@ volume_t nominal_volume = {
117 1.0, 117 1.0,
118 1.0 118 1.0
119 #else 119 #else
120 - UINT_MAX,  
121 - UINT_MAX 120 + 1ULL << 32,
  121 + 1ULL << 32
122 #endif 122 #endif
123 }; 123 };
124 124
@@ -1955,3 +1955,21 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque) @@ -1955,3 +1955,21 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
1955 } 1955 }
1956 } 1956 }
1957 } 1957 }
  1958 +
  1959 +void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol)
  1960 +{
  1961 + if (sw) {
  1962 + sw->vol.mute = mute;
  1963 + sw->vol.l = nominal_volume.l * lvol / 255;
  1964 + sw->vol.r = nominal_volume.r * rvol / 255;
  1965 + }
  1966 +}
  1967 +
  1968 +void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol)
  1969 +{
  1970 + if (sw) {
  1971 + sw->vol.mute = mute;
  1972 + sw->vol.l = nominal_volume.l * lvol / 255;
  1973 + sw->vol.r = nominal_volume.r * rvol / 255;
  1974 + }
  1975 +}
audio/audio.h
@@ -124,6 +124,9 @@ int AUD_is_active_out (SWVoiceOut *sw); @@ -124,6 +124,9 @@ int AUD_is_active_out (SWVoiceOut *sw);
124 void AUD_init_time_stamp_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts); 124 void AUD_init_time_stamp_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts);
125 uint64_t AUD_get_elapsed_usec_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts); 125 uint64_t AUD_get_elapsed_usec_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts);
126 126
  127 +void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol);
  128 +void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol);
  129 +
127 SWVoiceIn *AUD_open_in ( 130 SWVoiceIn *AUD_open_in (
128 QEMUSoundCard *card, 131 QEMUSoundCard *card,
129 SWVoiceIn *sw, 132 SWVoiceIn *sw,
hw/wm8750.c
@@ -39,10 +39,18 @@ struct wm8750_s { @@ -39,10 +39,18 @@ struct wm8750_s {
39 39
40 uint8_t diff[2], pol, ds, monomix[2], alc, mute; 40 uint8_t diff[2], pol, ds, monomix[2], alc, mute;
41 uint8_t path[4], mpath[2], power, format; 41 uint8_t path[4], mpath[2], power, format;
42 - uint32_t inmask, outmask;  
43 const struct wm_rate_s *rate; 42 const struct wm_rate_s *rate;
44 }; 43 };
45 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 +
46 static inline void wm8750_in_load(struct wm8750_s *s) 54 static inline void wm8750_in_load(struct wm8750_s *s)
47 { 55 {
48 int acquired; 56 int acquired;
@@ -125,6 +133,32 @@ static const struct wm_rate_s wm_rate_table[] = { @@ -125,6 +133,32 @@ static const struct wm_rate_s wm_rate_table[] = {
125 { 192, 88200, 192, 88200 }, /* SR: 11111 */ 133 { 192, 88200, 192, 88200 }, /* SR: 11111 */
126 }; 134 };
127 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 +
128 static void wm8750_set_format(struct wm8750_s *s) 162 static void wm8750_set_format(struct wm8750_s *s)
129 { 163 {
130 int i; 164 int i;
@@ -185,6 +219,8 @@ static void wm8750_set_format(struct wm8750_s *s) @@ -185,6 +219,8 @@ static void wm8750_set_format(struct wm8750_s *s)
185 CODEC ".monomix", s, wm8750_audio_out_cb, &out_fmt); 219 CODEC ".monomix", s, wm8750_audio_out_cb, &out_fmt);
186 /* no sense emulating OUT3 which is a mix of other outputs */ 220 /* no sense emulating OUT3 which is a mix of other outputs */
187 221
  222 + wm8750_vol_update(s);
  223 +
188 /* We should connect the left and right channels to their 224 /* We should connect the left and right channels to their
189 * respective inputs/outputs but we have completely no need 225 * respective inputs/outputs but we have completely no need
190 * for mixing or combining paths to different ports, so we 226 * for mixing or combining paths to different ports, so we
@@ -195,22 +231,6 @@ static void wm8750_set_format(struct wm8750_s *s) @@ -195,22 +231,6 @@ static void wm8750_set_format(struct wm8750_s *s)
195 AUD_set_active_out(*s->out[0], 1); 231 AUD_set_active_out(*s->out[0], 1);
196 } 232 }
197 233
198 -static void inline wm8750_mask_update(struct wm8750_s *s)  
199 -{  
200 -#define R_ONLY 0x0000ffff  
201 -#define L_ONLY 0xffff0000  
202 -#define BOTH (R_ONLY | L_ONLY)  
203 -#define NONE (R_ONLY & L_ONLY)  
204 - s->inmask =  
205 - (s->inmute[0] ? R_ONLY : BOTH) &  
206 - (s->inmute[1] ? L_ONLY : BOTH) &  
207 - (s->mute ? NONE : BOTH);  
208 - s->outmask =  
209 - (s->outmute[0] ? R_ONLY : BOTH) &  
210 - (s->outmute[1] ? L_ONLY : BOTH) &  
211 - (s->mute ? NONE : BOTH);  
212 -}  
213 -  
214 void wm8750_reset(i2c_slave *i2c) 234 void wm8750_reset(i2c_slave *i2c)
215 { 235 {
216 struct wm8750_s *s = (struct wm8750_s *) i2c; 236 struct wm8750_s *s = (struct wm8750_s *) i2c;
@@ -249,7 +269,7 @@ void wm8750_reset(i2c_slave *i2c) @@ -249,7 +269,7 @@ void wm8750_reset(i2c_slave *i2c)
249 s->req_in = 0; 269 s->req_in = 0;
250 s->idx_out = 0; 270 s->idx_out = 0;
251 s->req_out = 0; 271 s->req_out = 0;
252 - wm8750_mask_update(s); 272 + wm8750_vol_update(s);
253 s->i2c_len = 0; 273 s->i2c_len = 0;
254 } 274 }
255 275
@@ -367,19 +387,19 @@ static int wm8750_tx(i2c_slave *i2c, uint8_t data) @@ -367,19 +387,19 @@ static int wm8750_tx(i2c_slave *i2c, uint8_t data)
367 case WM8750_LINVOL: /* Left Channel PGA */ 387 case WM8750_LINVOL: /* Left Channel PGA */
368 s->invol[0] = value & 0x3f; /* LINVOL */ 388 s->invol[0] = value & 0x3f; /* LINVOL */
369 s->inmute[0] = (value >> 7) & 1; /* LINMUTE */ 389 s->inmute[0] = (value >> 7) & 1; /* LINMUTE */
370 - wm8750_mask_update(s); 390 + wm8750_vol_update(s);
371 break; 391 break;
372 392
373 case WM8750_RINVOL: /* Right Channel PGA */ 393 case WM8750_RINVOL: /* Right Channel PGA */
374 s->invol[1] = value & 0x3f; /* RINVOL */ 394 s->invol[1] = value & 0x3f; /* RINVOL */
375 s->inmute[1] = (value >> 7) & 1; /* RINMUTE */ 395 s->inmute[1] = (value >> 7) & 1; /* RINMUTE */
376 - wm8750_mask_update(s); 396 + wm8750_vol_update(s);
377 break; 397 break;
378 398
379 case WM8750_ADCDAC: /* ADC and DAC Control */ 399 case WM8750_ADCDAC: /* ADC and DAC Control */
380 s->pol = (value >> 5) & 3; /* ADCPOL */ 400 s->pol = (value >> 5) & 3; /* ADCPOL */
381 s->mute = (value >> 3) & 1; /* DACMU */ 401 s->mute = (value >> 3) & 1; /* DACMU */
382 - wm8750_mask_update(s); 402 + wm8750_vol_update(s);
383 break; 403 break;
384 404
385 case WM8750_ADCTL3: /* Additional Control (3) */ 405 case WM8750_ADCTL3: /* Additional Control (3) */
@@ -437,19 +457,21 @@ static int wm8750_tx(i2c_slave *i2c, uint8_t data) @@ -437,19 +457,21 @@ static int wm8750_tx(i2c_slave *i2c, uint8_t data)
437 break; 457 break;
438 458
439 case WM8750_LOUT1V: /* LOUT1 Volume */ 459 case WM8750_LOUT1V: /* LOUT1 Volume */
440 - s->outvol[2] = value & 0x7f; /* LOUT2VOL */ 460 + s->outvol[2] = value & 0x7f; /* LOUT1VOL */
441 break; 461 break;
442 462
443 case WM8750_LOUT2V: /* LOUT2 Volume */ 463 case WM8750_LOUT2V: /* LOUT2 Volume */
444 s->outvol[4] = value & 0x7f; /* LOUT2VOL */ 464 s->outvol[4] = value & 0x7f; /* LOUT2VOL */
  465 + wm8750_vol_update(s);
445 break; 466 break;
446 467
447 case WM8750_ROUT1V: /* ROUT1 Volume */ 468 case WM8750_ROUT1V: /* ROUT1 Volume */
448 - s->outvol[3] = value & 0x7f; /* ROUT2VOL */ 469 + s->outvol[3] = value & 0x7f; /* ROUT1VOL */
449 break; 470 break;
450 471
451 case WM8750_ROUT2V: /* ROUT2 Volume */ 472 case WM8750_ROUT2V: /* ROUT2 Volume */
452 s->outvol[5] = value & 0x7f; /* ROUT2VOL */ 473 s->outvol[5] = value & 0x7f; /* ROUT2VOL */
  474 + wm8750_vol_update(s);
453 break; 475 break;
454 476
455 case WM8750_MOUTV: /* MONOOUT Volume */ 477 case WM8750_MOUTV: /* MONOOUT Volume */
@@ -531,8 +553,6 @@ static void wm8750_save(QEMUFile *f, void *opaque) @@ -531,8 +553,6 @@ static void wm8750_save(QEMUFile *f, void *opaque)
531 qemu_put_8s(f, &s->mpath[i]); 553 qemu_put_8s(f, &s->mpath[i]);
532 qemu_put_8s(f, &s->format); 554 qemu_put_8s(f, &s->format);
533 qemu_put_8s(f, &s->power); 555 qemu_put_8s(f, &s->power);
534 - qemu_put_be32s(f, &s->inmask);  
535 - qemu_put_be32s(f, &s->outmask);  
536 qemu_put_byte(f, (s->rate - wm_rate_table) / sizeof(*s->rate)); 556 qemu_put_byte(f, (s->rate - wm_rate_table) / sizeof(*s->rate));
537 i2c_slave_save(f, &s->i2c); 557 i2c_slave_save(f, &s->i2c);
538 } 558 }
@@ -573,8 +593,6 @@ static int wm8750_load(QEMUFile *f, void *opaque, int version_id) @@ -573,8 +593,6 @@ static int wm8750_load(QEMUFile *f, void *opaque, int version_id)
573 qemu_get_8s(f, &s->mpath[i]); 593 qemu_get_8s(f, &s->mpath[i]);
574 qemu_get_8s(f, &s->format); 594 qemu_get_8s(f, &s->format);
575 qemu_get_8s(f, &s->power); 595 qemu_get_8s(f, &s->power);
576 - qemu_get_be32s(f, &s->inmask);  
577 - qemu_get_be32s(f, &s->outmask);  
578 s->rate = &wm_rate_table[(uint8_t) qemu_get_byte(f) & 0x1f]; 596 s->rate = &wm_rate_table[(uint8_t) qemu_get_byte(f) & 0x1f];
579 i2c_slave_load(f, &s->i2c); 597 i2c_slave_load(f, &s->i2c);
580 return 0; 598 return 0;
@@ -619,8 +637,7 @@ void wm8750_data_req_set(i2c_slave *i2c, @@ -619,8 +637,7 @@ void wm8750_data_req_set(i2c_slave *i2c,
619 void wm8750_dac_dat(void *opaque, uint32_t sample) 637 void wm8750_dac_dat(void *opaque, uint32_t sample)
620 { 638 {
621 struct wm8750_s *s = (struct wm8750_s *) opaque; 639 struct wm8750_s *s = (struct wm8750_s *) opaque;
622 - uint32_t *data = (uint32_t *) &s->data_out[s->idx_out];  
623 - *data = sample & s->outmask; 640 + *(uint32_t *) &s->data_out[s->idx_out] = sample;
624 s->req_out -= 4; 641 s->req_out -= 4;
625 s->idx_out += 4; 642 s->idx_out += 4;
626 if (s->idx_out >= sizeof(s->data_out) || s->req_out <= 0) 643 if (s->idx_out >= sizeof(s->data_out) || s->req_out <= 0)
@@ -654,5 +671,5 @@ uint32_t wm8750_adc_dat(void *opaque) @@ -654,5 +671,5 @@ uint32_t wm8750_adc_dat(void *opaque)
654 data = (uint32_t *) &s->data_in[s->idx_in]; 671 data = (uint32_t *) &s->data_in[s->idx_in];
655 s->req_in -= 4; 672 s->req_in -= 4;
656 s->idx_in += 4; 673 s->idx_in += 4;
657 - return *data & s->inmask; 674 + return *data;
658 } 675 }