Revision d8f699cb hw/tsc210x.c
b/hw/tsc210x.c | ||
---|---|---|
32 | 32 |
struct tsc210x_state_s { |
33 | 33 |
qemu_irq pint; |
34 | 34 |
QEMUTimer *timer; |
35 |
QEMUSoundCard card; |
|
35 | 36 |
struct uwire_slave_s chip; |
37 |
struct i2s_codec_s codec; |
|
38 |
uint8_t in_fifo[16384]; |
|
39 |
uint8_t out_fifo[16384]; |
|
36 | 40 |
|
37 | 41 |
int x, y; |
38 | 42 |
int pressure; |
... | ... | |
63 | 67 |
uint16_t dac_power; |
64 | 68 |
int64_t powerdown; |
65 | 69 |
uint16_t filter_data[0x14]; |
70 |
|
|
71 |
const char *name; |
|
72 |
SWVoiceIn *adc_voice[1]; |
|
73 |
SWVoiceOut *dac_voice[1]; |
|
74 |
int i2s_rx_rate; |
|
75 |
int i2s_tx_rate; |
|
76 |
AudioState *audio; |
|
66 | 77 |
}; |
67 | 78 |
|
68 | 79 |
static const int resolution[4] = { 12, 8, 10, 12 }; |
... | ... | |
171 | 182 |
s->filter_data[0x12] = 0x7d83; |
172 | 183 |
s->filter_data[0x13] = 0x84ee; |
173 | 184 |
|
185 |
s->i2s_tx_rate = 0; |
|
186 |
s->i2s_rx_rate = 0; |
|
187 |
|
|
174 | 188 |
qemu_set_irq(s->pint, !s->irq); |
175 | 189 |
} |
176 | 190 |
|
191 |
struct tsc210x_rate_info_s { |
|
192 |
int rate; |
|
193 |
int dsor; |
|
194 |
int fsref; |
|
195 |
}; |
|
196 |
|
|
197 |
/* { rate, dsor, fsref } */ |
|
198 |
static const struct tsc210x_rate_info_s tsc2101_rates[] = { |
|
199 |
/* Fsref / 6.0 */ |
|
200 |
{ 7350, 7, 1 }, |
|
201 |
{ 8000, 7, 0 }, |
|
202 |
/* Fsref / 5.5 */ |
|
203 |
{ 8018, 6, 1 }, |
|
204 |
{ 8727, 6, 0 }, |
|
205 |
/* Fsref / 5.0 */ |
|
206 |
{ 8820, 5, 1 }, |
|
207 |
{ 9600, 5, 0 }, |
|
208 |
/* Fsref / 4.0 */ |
|
209 |
{ 11025, 4, 1 }, |
|
210 |
{ 12000, 4, 0 }, |
|
211 |
/* Fsref / 3.0 */ |
|
212 |
{ 14700, 3, 1 }, |
|
213 |
{ 16000, 3, 0 }, |
|
214 |
/* Fsref / 2.0 */ |
|
215 |
{ 22050, 2, 1 }, |
|
216 |
{ 24000, 2, 0 }, |
|
217 |
/* Fsref / 1.5 */ |
|
218 |
{ 29400, 1, 1 }, |
|
219 |
{ 32000, 1, 0 }, |
|
220 |
/* Fsref */ |
|
221 |
{ 44100, 0, 1 }, |
|
222 |
{ 48000, 0, 0 }, |
|
223 |
|
|
224 |
{ 0, 0, 0 }, |
|
225 |
}; |
|
226 |
|
|
227 |
/* { rate, dsor, fsref } */ |
|
228 |
static const struct tsc210x_rate_info_s tsc2102_rates[] = { |
|
229 |
/* Fsref / 6.0 */ |
|
230 |
{ 7350, 63, 1 }, |
|
231 |
{ 8000, 63, 0 }, |
|
232 |
/* Fsref / 6.0 */ |
|
233 |
{ 7350, 54, 1 }, |
|
234 |
{ 8000, 54, 0 }, |
|
235 |
/* Fsref / 5.0 */ |
|
236 |
{ 8820, 45, 1 }, |
|
237 |
{ 9600, 45, 0 }, |
|
238 |
/* Fsref / 4.0 */ |
|
239 |
{ 11025, 36, 1 }, |
|
240 |
{ 12000, 36, 0 }, |
|
241 |
/* Fsref / 3.0 */ |
|
242 |
{ 14700, 27, 1 }, |
|
243 |
{ 16000, 27, 0 }, |
|
244 |
/* Fsref / 2.0 */ |
|
245 |
{ 22050, 18, 1 }, |
|
246 |
{ 24000, 18, 0 }, |
|
247 |
/* Fsref / 1.5 */ |
|
248 |
{ 29400, 9, 1 }, |
|
249 |
{ 32000, 9, 0 }, |
|
250 |
/* Fsref */ |
|
251 |
{ 44100, 0, 1 }, |
|
252 |
{ 48000, 0, 0 }, |
|
253 |
|
|
254 |
{ 0, 0, 0 }, |
|
255 |
}; |
|
256 |
|
|
257 |
static inline void tsc210x_out_flush(struct tsc210x_state_s *s, int len) |
|
258 |
{ |
|
259 |
uint8_t *data = s->codec.out.fifo + s->codec.out.start; |
|
260 |
uint8_t *end = data + len; |
|
261 |
|
|
262 |
while (data < end) |
|
263 |
data += AUD_write(s->dac_voice[0], data, end - data) ?: (end - data); |
|
264 |
|
|
265 |
s->codec.out.len -= len; |
|
266 |
if (s->codec.out.len) |
|
267 |
memmove(s->codec.out.fifo, end, s->codec.out.len); |
|
268 |
s->codec.out.start = 0; |
|
269 |
} |
|
270 |
|
|
271 |
static void tsc210x_audio_out_cb(struct tsc210x_state_s *s, int free_b) |
|
272 |
{ |
|
273 |
if (s->codec.out.len >= free_b) { |
|
274 |
tsc210x_out_flush(s, free_b); |
|
275 |
return; |
|
276 |
} |
|
277 |
|
|
278 |
s->codec.out.size = MIN(free_b, 16384); |
|
279 |
qemu_irq_raise(s->codec.tx_start); |
|
280 |
} |
|
281 |
|
|
282 |
static void tsc2102_audio_set_format(struct tsc210x_state_s *s) |
|
283 |
{ |
|
284 |
int enable; |
|
285 |
const struct tsc210x_rate_info_s *rate; |
|
286 |
audsettings_t fmt; |
|
287 |
|
|
288 |
if (s->dac_voice[0]) { |
|
289 |
tsc210x_out_flush(s, s->codec.out.len); |
|
290 |
s->codec.out.size = 0; |
|
291 |
AUD_set_active_out(s->dac_voice[0], 0); |
|
292 |
AUD_close_out(&s->card, s->dac_voice[0]); |
|
293 |
s->dac_voice[0] = 0; |
|
294 |
} |
|
295 |
|
|
296 |
enable = |
|
297 |
(~s->dac_power & (1 << 15)) && /* PWDNC */ |
|
298 |
(~s->dac_power & (1 << 10)); /* DAPWDN */ |
|
299 |
if (!enable) |
|
300 |
return; |
|
301 |
|
|
302 |
for (rate = tsc2102_rates; rate->rate; rate ++) |
|
303 |
if (rate->dsor == (s->audio_ctrl1 & 0x3f) && /* DACFS */ |
|
304 |
rate->fsref == ((s->audio_ctrl3 >> 13) & 1))/* REFFS */ |
|
305 |
break; |
|
306 |
if (!rate->rate) { |
|
307 |
printf("%s: unknown sampling rate configured\n", __FUNCTION__); |
|
308 |
return; |
|
309 |
} |
|
310 |
|
|
311 |
/* Force our own sampling rate even in slave DAC mode */ |
|
312 |
fmt.endianness = 0; |
|
313 |
fmt.nchannels = 2; |
|
314 |
fmt.freq = rate->rate; |
|
315 |
fmt.fmt = AUD_FMT_S16; |
|
316 |
|
|
317 |
s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0], |
|
318 |
"tsc2102.sink", s, (void *) tsc210x_audio_out_cb, &fmt); |
|
319 |
if (s->dac_voice[0]) |
|
320 |
AUD_set_active_out(s->dac_voice[0], 1); |
|
321 |
} |
|
322 |
|
|
177 | 323 |
static uint16_t tsc2102_data_register_read(struct tsc210x_state_s *s, int reg) |
178 | 324 |
{ |
179 | 325 |
switch (reg) { |
... | ... | |
437 | 583 |
fprintf(stderr, "tsc2102_audio_register_write: " |
438 | 584 |
"wrong value written into Audio 1\n"); |
439 | 585 |
#endif |
586 |
if (s->audio) |
|
587 |
tsc2102_audio_set_format(s); |
|
440 | 588 |
return; |
441 | 589 |
|
442 | 590 |
case 0x01: |
... | ... | |
479 | 627 |
fprintf(stderr, "tsc2102_audio_register_write: " |
480 | 628 |
"wrong value written into Power\n"); |
481 | 629 |
#endif |
630 |
if (s->audio) |
|
631 |
tsc2102_audio_set_format(s); |
|
482 | 632 |
return; |
483 | 633 |
|
484 | 634 |
case 0x06: /* Audio Control 3 */ |
... | ... | |
489 | 639 |
fprintf(stderr, "tsc2102_audio_register_write: " |
490 | 640 |
"wrong value written into Audio 3\n"); |
491 | 641 |
#endif |
642 |
if (s->audio) |
|
643 |
tsc2102_audio_set_format(s); |
|
492 | 644 |
return; |
493 | 645 |
|
494 | 646 |
case 0x07: /* LCH_BASS_BOOST_N0 */ |
... | ... | |
718 | 870 |
tsc210x_pin_update(s); |
719 | 871 |
} |
720 | 872 |
|
873 |
static void tsc210x_i2s_swallow(struct tsc210x_state_s *s) |
|
874 |
{ |
|
875 |
if (s->dac_voice[0]) |
|
876 |
tsc210x_out_flush(s, s->codec.out.len); |
|
877 |
else |
|
878 |
s->codec.out.len = 0; |
|
879 |
} |
|
880 |
|
|
881 |
static void tsc210x_i2s_set_rate(struct tsc210x_state_s *s, int in, int out) |
|
882 |
{ |
|
883 |
s->i2s_tx_rate = out; |
|
884 |
s->i2s_rx_rate = in; |
|
885 |
} |
|
886 |
|
|
721 | 887 |
static void tsc210x_save(QEMUFile *f, void *opaque) |
722 | 888 |
{ |
723 | 889 |
struct tsc210x_state_s *s = (struct tsc210x_state_s *) opaque; |
... | ... | |
817 | 983 |
|
818 | 984 |
static int tsc2102_iid = 0; |
819 | 985 |
|
820 |
struct uwire_slave_s *tsc2102_init(qemu_irq pint) |
|
986 |
struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio)
|
|
821 | 987 |
{ |
822 | 988 |
struct tsc210x_state_s *s; |
823 | 989 |
|
... | ... | |
830 | 996 |
s->precision = s->nextprecision = 0; |
831 | 997 |
s->timer = qemu_new_timer(vm_clock, tsc210x_timer_tick, s); |
832 | 998 |
s->pint = pint; |
999 |
s->name = "tsc2102"; |
|
1000 |
s->audio = audio; |
|
833 | 1001 |
|
834 | 1002 |
s->chip.opaque = s; |
835 | 1003 |
s->chip.send = (void *) tsc210x_write; |
836 | 1004 |
s->chip.receive = (void *) tsc210x_read; |
837 | 1005 |
|
1006 |
s->codec.opaque = s; |
|
1007 |
s->codec.tx_swallow = (void *) tsc210x_i2s_swallow; |
|
1008 |
s->codec.set_rate = (void *) tsc210x_i2s_set_rate; |
|
1009 |
s->codec.in.fifo = s->in_fifo; |
|
1010 |
s->codec.out.fifo = s->out_fifo; |
|
1011 |
|
|
838 | 1012 |
tsc210x_reset(s); |
839 | 1013 |
|
840 | 1014 |
qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1, |
841 | 1015 |
"QEMU TSC2102-driven Touchscreen"); |
842 | 1016 |
|
1017 |
if (s->audio) |
|
1018 |
AUD_register_card(s->audio, s->name, &s->card); |
|
1019 |
|
|
843 | 1020 |
qemu_register_reset((void *) tsc210x_reset, s); |
844 |
register_savevm("tsc2102", tsc2102_iid ++, 0,
|
|
1021 |
register_savevm(s->name, tsc2102_iid ++, 0,
|
|
845 | 1022 |
tsc210x_save, tsc210x_load, s); |
846 | 1023 |
|
847 | 1024 |
return &s->chip; |
848 | 1025 |
} |
1026 |
|
|
1027 |
struct i2s_codec_s *tsc210x_codec(struct uwire_slave_s *chip) |
|
1028 |
{ |
|
1029 |
struct tsc210x_state_s *s = (struct tsc210x_state_s *) chip->opaque; |
|
1030 |
|
|
1031 |
return &s->codec; |
|
1032 |
} |
Also available in: Unified diff