Commit a5d7eb6534a091566d63f97c8b35c0ac9623d90b
1 parent
827df9f3
Add TSC2301 touchscreen & keypad controller.
Add also a facility for setting up touchscreen calibration data per-board based on calibration data generated by tslib. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4214 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
4 changed files
with
290 additions
and
28 deletions
console.h
@@ -32,6 +32,14 @@ void kbd_put_keycode(int keycode); | @@ -32,6 +32,14 @@ void kbd_put_keycode(int keycode); | ||
32 | void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); | 32 | void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); |
33 | int kbd_mouse_is_absolute(void); | 33 | int kbd_mouse_is_absolute(void); |
34 | 34 | ||
35 | +struct mouse_transform_info_s { | ||
36 | + /* Touchscreen resolution */ | ||
37 | + int x; | ||
38 | + int y; | ||
39 | + /* Calibration values as used/generated by tslib */ | ||
40 | + int a[7]; | ||
41 | +}; | ||
42 | + | ||
35 | void do_info_mice(void); | 43 | void do_info_mice(void); |
36 | void do_mouse_set(int index); | 44 | void do_mouse_set(int index); |
37 | 45 |
hw/devices.h
@@ -16,6 +16,18 @@ uint32_t ads7846_read(void *opaque); | @@ -16,6 +16,18 @@ uint32_t ads7846_read(void *opaque); | ||
16 | void ads7846_write(void *opaque, uint32_t value); | 16 | void ads7846_write(void *opaque, uint32_t value); |
17 | struct ads7846_state_s *ads7846_init(qemu_irq penirq); | 17 | struct ads7846_state_s *ads7846_init(qemu_irq penirq); |
18 | 18 | ||
19 | +/* tsc210x.c */ | ||
20 | +struct uwire_slave_s; | ||
21 | +struct mouse_transform_info_s; | ||
22 | +struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio); | ||
23 | +struct uwire_slave_s *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, | ||
24 | + qemu_irq dav, AudioState *audio); | ||
25 | +struct i2s_codec_s *tsc210x_codec(struct uwire_slave_s *chip); | ||
26 | +uint32_t tsc210x_txrx(void *opaque, uint32_t value); | ||
27 | +void tsc210x_set_transform(struct uwire_slave_s *chip, | ||
28 | + struct mouse_transform_info_s *info); | ||
29 | +void tsc210x_key_event(struct uwire_slave_s *chip, int key, int down); | ||
30 | + | ||
19 | /* stellaris_input.c */ | 31 | /* stellaris_input.c */ |
20 | void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode); | 32 | void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode); |
21 | 33 |
hw/omap.h
@@ -1125,10 +1125,4 @@ inline static int debug_register_io_memory(int io_index, | @@ -1125,10 +1125,4 @@ inline static int debug_register_io_memory(int io_index, | ||
1125 | # define cpu_register_io_memory debug_register_io_memory | 1125 | # define cpu_register_io_memory debug_register_io_memory |
1126 | # endif | 1126 | # endif |
1127 | 1127 | ||
1128 | -/* Not really omap specific, but is the only thing that uses the | ||
1129 | - uwire interface. */ | ||
1130 | -/* tsc210x.c */ | ||
1131 | -struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio); | ||
1132 | -struct i2s_codec_s *tsc210x_codec(struct uwire_slave_s *chip); | ||
1133 | - | ||
1134 | #endif /* hw_omap_h */ | 1128 | #endif /* hw_omap_h */ |
hw/tsc210x.c
1 | /* | 1 | /* |
2 | * TI TSC2102 (touchscreen/sensors/audio controller) emulator. | 2 | * TI TSC2102 (touchscreen/sensors/audio controller) emulator. |
3 | + * TI TSC2301 (touchscreen/sensors/keypad). | ||
3 | * | 4 | * |
4 | * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org> | 5 | * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org> |
6 | + * Copyright (C) 2008 Nokia Corporation | ||
5 | * | 7 | * |
6 | * This program is free software; you can redistribute it and/or | 8 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public License as | 9 | * modify it under the terms of the GNU General Public License as |
8 | - * published by the Free Software Foundation; either version 2 of | ||
9 | - * the License, or (at your option) any later version. | 10 | + * published by the Free Software Foundation; either version 2 or |
11 | + * (at your option) version 3 of the License. | ||
10 | * | 12 | * |
11 | * This program is distributed in the hope that it will be useful, | 13 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
@@ -35,12 +37,15 @@ | @@ -35,12 +37,15 @@ | ||
35 | 37 | ||
36 | struct tsc210x_state_s { | 38 | struct tsc210x_state_s { |
37 | qemu_irq pint; | 39 | qemu_irq pint; |
40 | + qemu_irq kbint; | ||
41 | + qemu_irq davint; | ||
38 | QEMUTimer *timer; | 42 | QEMUTimer *timer; |
39 | QEMUSoundCard card; | 43 | QEMUSoundCard card; |
40 | struct uwire_slave_s chip; | 44 | struct uwire_slave_s chip; |
41 | struct i2s_codec_s codec; | 45 | struct i2s_codec_s codec; |
42 | uint8_t in_fifo[16384]; | 46 | uint8_t in_fifo[16384]; |
43 | uint8_t out_fifo[16384]; | 47 | uint8_t out_fifo[16384]; |
48 | + uint16_t model; | ||
44 | 49 | ||
45 | int x, y; | 50 | int x, y; |
46 | int pressure; | 51 | int pressure; |
@@ -64,7 +69,7 @@ struct tsc210x_state_s { | @@ -64,7 +69,7 @@ struct tsc210x_state_s { | ||
64 | uint16_t audio_ctrl1; | 69 | uint16_t audio_ctrl1; |
65 | uint16_t audio_ctrl2; | 70 | uint16_t audio_ctrl2; |
66 | uint16_t audio_ctrl3; | 71 | uint16_t audio_ctrl3; |
67 | - uint16_t pll[2]; | 72 | + uint16_t pll[3]; |
68 | uint16_t volume; | 73 | uint16_t volume; |
69 | int64_t volume_change; | 74 | int64_t volume_change; |
70 | int softstep; | 75 | int softstep; |
@@ -78,6 +83,17 @@ struct tsc210x_state_s { | @@ -78,6 +83,17 @@ struct tsc210x_state_s { | ||
78 | int i2s_rx_rate; | 83 | int i2s_rx_rate; |
79 | int i2s_tx_rate; | 84 | int i2s_tx_rate; |
80 | AudioState *audio; | 85 | AudioState *audio; |
86 | + | ||
87 | + int tr[8]; | ||
88 | + | ||
89 | + struct { | ||
90 | + uint16_t down; | ||
91 | + uint16_t mask; | ||
92 | + int scan; | ||
93 | + int debounce; | ||
94 | + int mode; | ||
95 | + int intr; | ||
96 | + } kb; | ||
81 | }; | 97 | }; |
82 | 98 | ||
83 | static const int resolution[4] = { 12, 8, 10, 12 }; | 99 | static const int resolution[4] = { 12, 8, 10, 12 }; |
@@ -118,17 +134,10 @@ static const uint16_t mode_regs[16] = { | @@ -118,17 +134,10 @@ static const uint16_t mode_regs[16] = { | ||
118 | 0x0000, /* Y+, X- drivers */ | 134 | 0x0000, /* Y+, X- drivers */ |
119 | }; | 135 | }; |
120 | 136 | ||
121 | -/* | ||
122 | - * Convert screen coordinates to arbitrary values that the | ||
123 | - * touchscreen in my Palm Tungsten E device returns. | ||
124 | - * This shouldn't really matter (because the guest system | ||
125 | - * should calibrate the touchscreen anyway), but let's | ||
126 | - * imitate some real hardware. | ||
127 | - */ | ||
128 | -#define X_TRANSFORM(value) \ | ||
129 | - ((3850 - ((int) (value) * (3850 - 250) / 32768)) << 4) | ||
130 | -#define Y_TRANSFORM(value) \ | ||
131 | - ((150 + ((int) (value) * (3037 - 150) / 32768)) << 4) | 137 | +#define X_TRANSFORM(s) \ |
138 | + ((s->y * s->tr[0] - s->x * s->tr[1]) / s->tr[2] + s->tr[3]) | ||
139 | +#define Y_TRANSFORM(s) \ | ||
140 | + ((s->y * s->tr[4] - s->x * s->tr[5]) / s->tr[6] + s->tr[7]) | ||
132 | #define Z1_TRANSFORM(s) \ | 141 | #define Z1_TRANSFORM(s) \ |
133 | ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4) | 142 | ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4) |
134 | #define Z2_TRANSFORM(s) \ | 143 | #define Z2_TRANSFORM(s) \ |
@@ -161,6 +170,7 @@ static void tsc210x_reset(struct tsc210x_state_s *s) | @@ -161,6 +170,7 @@ static void tsc210x_reset(struct tsc210x_state_s *s) | ||
161 | s->audio_ctrl3 = 0x0000; | 170 | s->audio_ctrl3 = 0x0000; |
162 | s->pll[0] = 0x1004; | 171 | s->pll[0] = 0x1004; |
163 | s->pll[1] = 0x0000; | 172 | s->pll[1] = 0x0000; |
173 | + s->pll[2] = 0x1fff; | ||
164 | s->volume = 0xffff; | 174 | s->volume = 0xffff; |
165 | s->dac_power = 0x8540; | 175 | s->dac_power = 0x8540; |
166 | s->softstep = 1; | 176 | s->softstep = 1; |
@@ -190,7 +200,15 @@ static void tsc210x_reset(struct tsc210x_state_s *s) | @@ -190,7 +200,15 @@ static void tsc210x_reset(struct tsc210x_state_s *s) | ||
190 | s->i2s_tx_rate = 0; | 200 | s->i2s_tx_rate = 0; |
191 | s->i2s_rx_rate = 0; | 201 | s->i2s_rx_rate = 0; |
192 | 202 | ||
203 | + s->kb.scan = 1; | ||
204 | + s->kb.debounce = 0; | ||
205 | + s->kb.mask = 0x0000; | ||
206 | + s->kb.mode = 3; | ||
207 | + s->kb.intr = 0; | ||
208 | + | ||
193 | qemu_set_irq(s->pint, !s->irq); | 209 | qemu_set_irq(s->pint, !s->irq); |
210 | + qemu_set_irq(s->davint, !s->dav); | ||
211 | + qemu_irq_raise(s->kbint); | ||
194 | } | 212 | } |
195 | 213 | ||
196 | struct tsc210x_rate_info_s { | 214 | struct tsc210x_rate_info_s { |
@@ -344,13 +362,13 @@ static uint16_t tsc2102_data_register_read(struct tsc210x_state_s *s, int reg) | @@ -344,13 +362,13 @@ static uint16_t tsc2102_data_register_read(struct tsc210x_state_s *s, int reg) | ||
344 | switch (reg) { | 362 | switch (reg) { |
345 | case 0x00: /* X */ | 363 | case 0x00: /* X */ |
346 | s->dav &= 0xfbff; | 364 | s->dav &= 0xfbff; |
347 | - return TSC_CUT_RESOLUTION(X_TRANSFORM(s->x), s->precision) + | 365 | + return TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) + |
348 | (s->noise & 3); | 366 | (s->noise & 3); |
349 | 367 | ||
350 | case 0x01: /* Y */ | 368 | case 0x01: /* Y */ |
351 | s->noise ++; | 369 | s->noise ++; |
352 | s->dav &= 0xfdff; | 370 | s->dav &= 0xfdff; |
353 | - return TSC_CUT_RESOLUTION(Y_TRANSFORM(s->y), s->precision) ^ | 371 | + return TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^ |
354 | (s->noise & 3); | 372 | (s->noise & 3); |
355 | 373 | ||
356 | case 0x02: /* Z1 */ | 374 | case 0x02: /* Z1 */ |
@@ -364,6 +382,14 @@ static uint16_t tsc2102_data_register_read(struct tsc210x_state_s *s, int reg) | @@ -364,6 +382,14 @@ static uint16_t tsc2102_data_register_read(struct tsc210x_state_s *s, int reg) | ||
364 | (s->noise & 3); | 382 | (s->noise & 3); |
365 | 383 | ||
366 | case 0x04: /* KPData */ | 384 | case 0x04: /* KPData */ |
385 | + if ((s->model & 0xff00) == 0x2300) { | ||
386 | + if (s->kb.intr && (s->kb.mode & 2)) { | ||
387 | + s->kb.intr = 0; | ||
388 | + qemu_irq_raise(s->kbint); | ||
389 | + } | ||
390 | + return s->kb.down; | ||
391 | + } | ||
392 | + | ||
367 | return 0xffff; | 393 | return 0xffff; |
368 | 394 | ||
369 | case 0x05: /* BAT1 */ | 395 | case 0x05: /* BAT1 */ |
@@ -414,9 +440,19 @@ static uint16_t tsc2102_control_register_read( | @@ -414,9 +440,19 @@ static uint16_t tsc2102_control_register_read( | ||
414 | return (s->pressure << 15) | ((!s->busy) << 14) | | 440 | return (s->pressure << 15) | ((!s->busy) << 14) | |
415 | (s->nextfunction << 10) | (s->nextprecision << 8) | s->filter; | 441 | (s->nextfunction << 10) | (s->nextprecision << 8) | s->filter; |
416 | 442 | ||
417 | - case 0x01: /* Status */ | ||
418 | - return (s->pin_func << 14) | ((!s->enabled) << 13) | | ||
419 | - (s->host_mode << 12) | ((!!s->dav) << 11) | s->dav; | 443 | + case 0x01: /* Status / Keypad Control */ |
444 | + if ((s->model & 0xff00) == 0x2100) | ||
445 | + return (s->pin_func << 14) | ((!s->enabled) << 13) | | ||
446 | + (s->host_mode << 12) | ((!!s->dav) << 11) | s->dav; | ||
447 | + else | ||
448 | + return (s->kb.intr << 15) | ((s->kb.scan || !s->kb.down) << 14) | | ||
449 | + (s->kb.debounce << 11); | ||
450 | + | ||
451 | + case 0x02: /* DAC Control */ | ||
452 | + if ((s->model & 0xff00) == 0x2300) | ||
453 | + return s->dac_power & 0x8000; | ||
454 | + else | ||
455 | + goto bad_reg; | ||
420 | 456 | ||
421 | case 0x03: /* Reference */ | 457 | case 0x03: /* Reference */ |
422 | return s->ref; | 458 | return s->ref; |
@@ -427,7 +463,18 @@ static uint16_t tsc2102_control_register_read( | @@ -427,7 +463,18 @@ static uint16_t tsc2102_control_register_read( | ||
427 | case 0x05: /* Configuration */ | 463 | case 0x05: /* Configuration */ |
428 | return s->timing; | 464 | return s->timing; |
429 | 465 | ||
466 | + case 0x06: /* Secondary configuration */ | ||
467 | + if ((s->model & 0xff00) == 0x2100) | ||
468 | + goto bad_reg; | ||
469 | + return ((!s->dav) << 15) | ((s->kb.mode & 1) << 14) | s->pll[2]; | ||
470 | + | ||
471 | + case 0x10: /* Keypad Mask */ | ||
472 | + if ((s->model & 0xff00) == 0x2100) | ||
473 | + goto bad_reg; | ||
474 | + return s->kb.mask; | ||
475 | + | ||
430 | default: | 476 | default: |
477 | + bad_reg: | ||
431 | #ifdef TSC_VERBOSE | 478 | #ifdef TSC_VERBOSE |
432 | fprintf(stderr, "tsc2102_control_register_read: " | 479 | fprintf(stderr, "tsc2102_control_register_read: " |
433 | "no such register: 0x%02x\n", reg); | 480 | "no such register: 0x%02x\n", reg); |
@@ -556,10 +603,27 @@ static void tsc2102_control_register_write( | @@ -556,10 +603,27 @@ static void tsc2102_control_register_write( | ||
556 | s->filter = value & 0xff; | 603 | s->filter = value & 0xff; |
557 | return; | 604 | return; |
558 | 605 | ||
559 | - case 0x01: /* Status */ | ||
560 | - s->pin_func = value >> 14; | 606 | + case 0x01: /* Status / Keypad Control */ |
607 | + if ((s->model & 0xff00) == 0x2100) | ||
608 | + s->pin_func = value >> 14; | ||
609 | + else { | ||
610 | + s->kb.scan = (value >> 14) & 1; | ||
611 | + s->kb.debounce = (value >> 11) & 7; | ||
612 | + if (s->kb.intr && s->kb.scan) { | ||
613 | + s->kb.intr = 0; | ||
614 | + qemu_irq_raise(s->kbint); | ||
615 | + } | ||
616 | + } | ||
561 | return; | 617 | return; |
562 | 618 | ||
619 | + case 0x02: /* DAC Control */ | ||
620 | + if ((s->model & 0xff00) == 0x2300) { | ||
621 | + s->dac_power &= 0x7fff; | ||
622 | + s->dac_power |= 0x8000 & value; | ||
623 | + } else | ||
624 | + goto bad_reg; | ||
625 | + break; | ||
626 | + | ||
563 | case 0x03: /* Reference */ | 627 | case 0x03: /* Reference */ |
564 | s->ref = value & 0x1f; | 628 | s->ref = value & 0x1f; |
565 | return; | 629 | return; |
@@ -586,7 +650,21 @@ static void tsc2102_control_register_write( | @@ -586,7 +650,21 @@ static void tsc2102_control_register_write( | ||
586 | #endif | 650 | #endif |
587 | return; | 651 | return; |
588 | 652 | ||
653 | + case 0x06: /* Secondary configuration */ | ||
654 | + if ((s->model & 0xff00) == 0x2100) | ||
655 | + goto bad_reg; | ||
656 | + s->kb.mode = value >> 14; | ||
657 | + s->pll[2] = value & 0x3ffff; | ||
658 | + return; | ||
659 | + | ||
660 | + case 0x10: /* Keypad Mask */ | ||
661 | + if ((s->model & 0xff00) == 0x2100) | ||
662 | + goto bad_reg; | ||
663 | + s->kb.mask = value; | ||
664 | + return; | ||
665 | + | ||
589 | default: | 666 | default: |
667 | + bad_reg: | ||
590 | #ifdef TSC_VERBOSE | 668 | #ifdef TSC_VERBOSE |
591 | fprintf(stderr, "tsc2102_control_register_write: " | 669 | fprintf(stderr, "tsc2102_control_register_write: " |
592 | "no such register: 0x%02x\n", reg); | 670 | "no such register: 0x%02x\n", reg); |
@@ -785,7 +863,7 @@ static void tsc210x_pin_update(struct tsc210x_state_s *s) | @@ -785,7 +863,7 @@ static void tsc210x_pin_update(struct tsc210x_state_s *s) | ||
785 | return; | 863 | return; |
786 | } | 864 | } |
787 | 865 | ||
788 | - if (!s->enabled || s->busy) | 866 | + if (!s->enabled || s->busy || s->dav) |
789 | return; | 867 | return; |
790 | 868 | ||
791 | s->busy = 1; | 869 | s->busy = 1; |
@@ -805,6 +883,8 @@ static uint16_t tsc210x_read(struct tsc210x_state_s *s) | @@ -805,6 +883,8 @@ static uint16_t tsc210x_read(struct tsc210x_state_s *s) | ||
805 | switch (s->page) { | 883 | switch (s->page) { |
806 | case TSC_DATA_REGISTERS_PAGE: | 884 | case TSC_DATA_REGISTERS_PAGE: |
807 | ret = tsc2102_data_register_read(s, s->offset); | 885 | ret = tsc2102_data_register_read(s, s->offset); |
886 | + if (!s->dav) | ||
887 | + qemu_irq_raise(s->davint); | ||
808 | break; | 888 | break; |
809 | case TSC_CONTROL_REGISTERS_PAGE: | 889 | case TSC_CONTROL_REGISTERS_PAGE: |
810 | ret = tsc2102_control_register_read(s, s->offset); | 890 | ret = tsc2102_control_register_read(s, s->offset); |
@@ -859,6 +939,22 @@ static void tsc210x_write(struct tsc210x_state_s *s, uint16_t value) | @@ -859,6 +939,22 @@ static void tsc210x_write(struct tsc210x_state_s *s, uint16_t value) | ||
859 | } | 939 | } |
860 | } | 940 | } |
861 | 941 | ||
942 | +uint32_t tsc210x_txrx(void *opaque, uint32_t value) | ||
943 | +{ | ||
944 | + struct tsc210x_state_s *s = opaque; | ||
945 | + uint32_t ret = 0; | ||
946 | + | ||
947 | + /* TODO: sequential reads etc - how do we make sure the host doesn't | ||
948 | + * unintentionally read out a conversion result from a register while | ||
949 | + * transmitting the command word of the next command? */ | ||
950 | + if (!value || (s->state && s->command)) | ||
951 | + ret = tsc210x_read(s); | ||
952 | + if (value || (s->state && !s->command)) | ||
953 | + tsc210x_write(s, value); | ||
954 | + | ||
955 | + return ret; | ||
956 | +} | ||
957 | + | ||
862 | static void tsc210x_timer_tick(void *opaque) | 958 | static void tsc210x_timer_tick(void *opaque) |
863 | { | 959 | { |
864 | struct tsc210x_state_s *s = opaque; | 960 | struct tsc210x_state_s *s = opaque; |
@@ -871,6 +967,7 @@ static void tsc210x_timer_tick(void *opaque) | @@ -871,6 +967,7 @@ static void tsc210x_timer_tick(void *opaque) | ||
871 | s->busy = 0; | 967 | s->busy = 0; |
872 | s->dav |= mode_regs[s->function]; | 968 | s->dav |= mode_regs[s->function]; |
873 | tsc210x_pin_update(s); | 969 | tsc210x_pin_update(s); |
970 | + qemu_irq_lower(s->davint); | ||
874 | } | 971 | } |
875 | 972 | ||
876 | static void tsc210x_touchscreen_event(void *opaque, | 973 | static void tsc210x_touchscreen_event(void *opaque, |
@@ -1001,6 +1098,7 @@ static int tsc210x_load(QEMUFile *f, void *opaque, int version_id) | @@ -1001,6 +1098,7 @@ static int tsc210x_load(QEMUFile *f, void *opaque, int version_id) | ||
1001 | 1098 | ||
1002 | s->busy = qemu_timer_pending(s->timer); | 1099 | s->busy = qemu_timer_pending(s->timer); |
1003 | qemu_set_irq(s->pint, !s->irq); | 1100 | qemu_set_irq(s->pint, !s->irq); |
1101 | + qemu_set_irq(s->davint, !s->dav); | ||
1004 | 1102 | ||
1005 | return 0; | 1103 | return 0; |
1006 | } | 1104 | } |
@@ -1020,9 +1118,19 @@ struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio) | @@ -1020,9 +1118,19 @@ struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio) | ||
1020 | s->precision = s->nextprecision = 0; | 1118 | s->precision = s->nextprecision = 0; |
1021 | s->timer = qemu_new_timer(vm_clock, tsc210x_timer_tick, s); | 1119 | s->timer = qemu_new_timer(vm_clock, tsc210x_timer_tick, s); |
1022 | s->pint = pint; | 1120 | s->pint = pint; |
1121 | + s->model = 0x2102; | ||
1023 | s->name = "tsc2102"; | 1122 | s->name = "tsc2102"; |
1024 | s->audio = audio; | 1123 | s->audio = audio; |
1025 | 1124 | ||
1125 | + s->tr[0] = 0; | ||
1126 | + s->tr[1] = 1; | ||
1127 | + s->tr[2] = 0; | ||
1128 | + s->tr[3] = 1; | ||
1129 | + s->tr[4] = 1; | ||
1130 | + s->tr[5] = 0; | ||
1131 | + s->tr[6] = 0; | ||
1132 | + s->tr[7] = 1; | ||
1133 | + | ||
1026 | s->chip.opaque = s; | 1134 | s->chip.opaque = s; |
1027 | s->chip.send = (void *) tsc210x_write; | 1135 | s->chip.send = (void *) tsc210x_write; |
1028 | s->chip.receive = (void *) tsc210x_read; | 1136 | s->chip.receive = (void *) tsc210x_read; |
@@ -1048,9 +1156,149 @@ struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio) | @@ -1048,9 +1156,149 @@ struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio) | ||
1048 | return &s->chip; | 1156 | return &s->chip; |
1049 | } | 1157 | } |
1050 | 1158 | ||
1159 | +struct uwire_slave_s *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, | ||
1160 | + qemu_irq dav, AudioState *audio) | ||
1161 | +{ | ||
1162 | + struct tsc210x_state_s *s; | ||
1163 | + | ||
1164 | + s = (struct tsc210x_state_s *) | ||
1165 | + qemu_mallocz(sizeof(struct tsc210x_state_s)); | ||
1166 | + memset(s, 0, sizeof(struct tsc210x_state_s)); | ||
1167 | + s->x = 400; | ||
1168 | + s->y = 240; | ||
1169 | + s->pressure = 0; | ||
1170 | + s->precision = s->nextprecision = 0; | ||
1171 | + s->timer = qemu_new_timer(vm_clock, tsc210x_timer_tick, s); | ||
1172 | + s->pint = penirq; | ||
1173 | + s->kbint = kbirq; | ||
1174 | + s->davint = dav; | ||
1175 | + s->model = 0x2301; | ||
1176 | + s->name = "tsc2301"; | ||
1177 | + s->audio = audio; | ||
1178 | + | ||
1179 | + s->tr[0] = 0; | ||
1180 | + s->tr[1] = 1; | ||
1181 | + s->tr[2] = 0; | ||
1182 | + s->tr[3] = 1; | ||
1183 | + s->tr[4] = 1; | ||
1184 | + s->tr[5] = 0; | ||
1185 | + s->tr[6] = 0; | ||
1186 | + s->tr[7] = 1; | ||
1187 | + | ||
1188 | + s->chip.opaque = s; | ||
1189 | + s->chip.send = (void *) tsc210x_write; | ||
1190 | + s->chip.receive = (void *) tsc210x_read; | ||
1191 | + | ||
1192 | + s->codec.opaque = s; | ||
1193 | + s->codec.tx_swallow = (void *) tsc210x_i2s_swallow; | ||
1194 | + s->codec.set_rate = (void *) tsc210x_i2s_set_rate; | ||
1195 | + s->codec.in.fifo = s->in_fifo; | ||
1196 | + s->codec.out.fifo = s->out_fifo; | ||
1197 | + | ||
1198 | + tsc210x_reset(s); | ||
1199 | + | ||
1200 | + qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1, | ||
1201 | + "QEMU TSC2301-driven Touchscreen"); | ||
1202 | + | ||
1203 | + if (s->audio) | ||
1204 | + AUD_register_card(s->audio, s->name, &s->card); | ||
1205 | + | ||
1206 | + qemu_register_reset((void *) tsc210x_reset, s); | ||
1207 | + register_savevm(s->name, tsc2102_iid ++, 0, | ||
1208 | + tsc210x_save, tsc210x_load, s); | ||
1209 | + | ||
1210 | + return &s->chip; | ||
1211 | +} | ||
1212 | + | ||
1051 | struct i2s_codec_s *tsc210x_codec(struct uwire_slave_s *chip) | 1213 | struct i2s_codec_s *tsc210x_codec(struct uwire_slave_s *chip) |
1052 | { | 1214 | { |
1053 | struct tsc210x_state_s *s = (struct tsc210x_state_s *) chip->opaque; | 1215 | struct tsc210x_state_s *s = (struct tsc210x_state_s *) chip->opaque; |
1054 | 1216 | ||
1055 | return &s->codec; | 1217 | return &s->codec; |
1056 | } | 1218 | } |
1219 | + | ||
1220 | +/* | ||
1221 | + * Use tslib generated calibration data to generate ADC input values | ||
1222 | + * from the touchscreen. Assuming 12-bit precision was used during | ||
1223 | + * tslib calibration. | ||
1224 | + */ | ||
1225 | +void tsc210x_set_transform(struct uwire_slave_s *chip, | ||
1226 | + struct mouse_transform_info_s *info) | ||
1227 | +{ | ||
1228 | + struct tsc210x_state_s *s = (struct tsc210x_state_s *) chip->opaque; | ||
1229 | +#if 0 | ||
1230 | + int64_t ltr[8]; | ||
1231 | + | ||
1232 | + ltr[0] = (int64_t) info->a[1] * info->y; | ||
1233 | + ltr[1] = (int64_t) info->a[4] * info->x; | ||
1234 | + ltr[2] = (int64_t) info->a[1] * info->a[3] - | ||
1235 | + (int64_t) info->a[4] * info->a[0]; | ||
1236 | + ltr[3] = (int64_t) info->a[2] * info->a[4] - | ||
1237 | + (int64_t) info->a[5] * info->a[1]; | ||
1238 | + ltr[4] = (int64_t) info->a[0] * info->y; | ||
1239 | + ltr[5] = (int64_t) info->a[3] * info->x; | ||
1240 | + ltr[6] = (int64_t) info->a[4] * info->a[0] - | ||
1241 | + (int64_t) info->a[1] * info->a[3]; | ||
1242 | + ltr[7] = (int64_t) info->a[2] * info->a[3] - | ||
1243 | + (int64_t) info->a[5] * info->a[0]; | ||
1244 | + | ||
1245 | + /* Avoid integer overflow */ | ||
1246 | + s->tr[0] = ltr[0] >> 11; | ||
1247 | + s->tr[1] = ltr[1] >> 11; | ||
1248 | + s->tr[2] = muldiv64(ltr[2], 1, info->a[6]); | ||
1249 | + s->tr[3] = muldiv64(ltr[3], 1 << 4, ltr[2]); | ||
1250 | + s->tr[4] = ltr[4] >> 11; | ||
1251 | + s->tr[5] = ltr[5] >> 11; | ||
1252 | + s->tr[6] = muldiv64(ltr[6], 1, info->a[6]); | ||
1253 | + s->tr[7] = muldiv64(ltr[7], 1 << 4, ltr[6]); | ||
1254 | +#else | ||
1255 | + | ||
1256 | + /* This version assumes touchscreen X & Y axis are parallel or | ||
1257 | + * perpendicular to LCD's X & Y axis in some way. */ | ||
1258 | + if (abs(info->a[0]) > abs(info->a[1])) { | ||
1259 | + s->tr[0] = 0; | ||
1260 | + s->tr[1] = -info->a[6] * info->x; | ||
1261 | + s->tr[2] = info->a[0]; | ||
1262 | + s->tr[3] = -info->a[2] / info->a[0]; | ||
1263 | + s->tr[4] = info->a[6] * info->y; | ||
1264 | + s->tr[5] = 0; | ||
1265 | + s->tr[6] = info->a[4]; | ||
1266 | + s->tr[7] = -info->a[5] / info->a[4]; | ||
1267 | + } else { | ||
1268 | + s->tr[0] = info->a[6] * info->y; | ||
1269 | + s->tr[1] = 0; | ||
1270 | + s->tr[2] = info->a[1]; | ||
1271 | + s->tr[3] = -info->a[2] / info->a[1]; | ||
1272 | + s->tr[4] = 0; | ||
1273 | + s->tr[5] = -info->a[6] * info->x; | ||
1274 | + s->tr[6] = info->a[3]; | ||
1275 | + s->tr[7] = -info->a[5] / info->a[3]; | ||
1276 | + } | ||
1277 | + | ||
1278 | + s->tr[0] >>= 11; | ||
1279 | + s->tr[1] >>= 11; | ||
1280 | + s->tr[3] <<= 4; | ||
1281 | + s->tr[4] >>= 11; | ||
1282 | + s->tr[5] >>= 11; | ||
1283 | + s->tr[7] <<= 4; | ||
1284 | +#endif | ||
1285 | +} | ||
1286 | + | ||
1287 | +void tsc210x_key_event(struct uwire_slave_s *chip, int key, int down) | ||
1288 | +{ | ||
1289 | + struct tsc210x_state_s *s = (struct tsc210x_state_s *) chip->opaque; | ||
1290 | + | ||
1291 | + if (down) | ||
1292 | + s->kb.down |= 1 << key; | ||
1293 | + else | ||
1294 | + s->kb.down &= ~(1 << key); | ||
1295 | + | ||
1296 | + if (down && (s->kb.down & ~s->kb.mask) && !s->kb.intr) { | ||
1297 | + s->kb.intr = 1; | ||
1298 | + qemu_irq_lower(s->kbint); | ||
1299 | + } else if (s->kb.intr && !(s->kb.down & ~s->kb.mask) && | ||
1300 | + !(s->kb.mode & 1)) { | ||
1301 | + s->kb.intr = 0; | ||
1302 | + qemu_irq_raise(s->kbint); | ||
1303 | + } | ||
1304 | +} |