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 | 32 | void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); |
| 33 | 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 | 43 | void do_info_mice(void); |
| 36 | 44 | void do_mouse_set(int index); |
| 37 | 45 | ... | ... |
hw/devices.h
| ... | ... | @@ -16,6 +16,18 @@ uint32_t ads7846_read(void *opaque); |
| 16 | 16 | void ads7846_write(void *opaque, uint32_t value); |
| 17 | 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 | 31 | /* stellaris_input.c */ |
| 20 | 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 | 1125 | # define cpu_register_io_memory debug_register_io_memory |
| 1126 | 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 | 1128 | #endif /* hw_omap_h */ | ... | ... |
hw/tsc210x.c
| 1 | 1 | /* |
| 2 | 2 | * TI TSC2102 (touchscreen/sensors/audio controller) emulator. |
| 3 | + * TI TSC2301 (touchscreen/sensors/keypad). | |
| 3 | 4 | * |
| 4 | 5 | * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org> |
| 6 | + * Copyright (C) 2008 Nokia Corporation | |
| 5 | 7 | * |
| 6 | 8 | * This program is free software; you can redistribute it and/or |
| 7 | 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 | 13 | * This program is distributed in the hope that it will be useful, |
| 12 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| ... | ... | @@ -35,12 +37,15 @@ |
| 35 | 37 | |
| 36 | 38 | struct tsc210x_state_s { |
| 37 | 39 | qemu_irq pint; |
| 40 | + qemu_irq kbint; | |
| 41 | + qemu_irq davint; | |
| 38 | 42 | QEMUTimer *timer; |
| 39 | 43 | QEMUSoundCard card; |
| 40 | 44 | struct uwire_slave_s chip; |
| 41 | 45 | struct i2s_codec_s codec; |
| 42 | 46 | uint8_t in_fifo[16384]; |
| 43 | 47 | uint8_t out_fifo[16384]; |
| 48 | + uint16_t model; | |
| 44 | 49 | |
| 45 | 50 | int x, y; |
| 46 | 51 | int pressure; |
| ... | ... | @@ -64,7 +69,7 @@ struct tsc210x_state_s { |
| 64 | 69 | uint16_t audio_ctrl1; |
| 65 | 70 | uint16_t audio_ctrl2; |
| 66 | 71 | uint16_t audio_ctrl3; |
| 67 | - uint16_t pll[2]; | |
| 72 | + uint16_t pll[3]; | |
| 68 | 73 | uint16_t volume; |
| 69 | 74 | int64_t volume_change; |
| 70 | 75 | int softstep; |
| ... | ... | @@ -78,6 +83,17 @@ struct tsc210x_state_s { |
| 78 | 83 | int i2s_rx_rate; |
| 79 | 84 | int i2s_tx_rate; |
| 80 | 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 | 99 | static const int resolution[4] = { 12, 8, 10, 12 }; |
| ... | ... | @@ -118,17 +134,10 @@ static const uint16_t mode_regs[16] = { |
| 118 | 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 | 141 | #define Z1_TRANSFORM(s) \ |
| 133 | 142 | ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4) |
| 134 | 143 | #define Z2_TRANSFORM(s) \ |
| ... | ... | @@ -161,6 +170,7 @@ static void tsc210x_reset(struct tsc210x_state_s *s) |
| 161 | 170 | s->audio_ctrl3 = 0x0000; |
| 162 | 171 | s->pll[0] = 0x1004; |
| 163 | 172 | s->pll[1] = 0x0000; |
| 173 | + s->pll[2] = 0x1fff; | |
| 164 | 174 | s->volume = 0xffff; |
| 165 | 175 | s->dac_power = 0x8540; |
| 166 | 176 | s->softstep = 1; |
| ... | ... | @@ -190,7 +200,15 @@ static void tsc210x_reset(struct tsc210x_state_s *s) |
| 190 | 200 | s->i2s_tx_rate = 0; |
| 191 | 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 | 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 | 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 | 362 | switch (reg) { |
| 345 | 363 | case 0x00: /* X */ |
| 346 | 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 | 366 | (s->noise & 3); |
| 349 | 367 | |
| 350 | 368 | case 0x01: /* Y */ |
| 351 | 369 | s->noise ++; |
| 352 | 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 | 372 | (s->noise & 3); |
| 355 | 373 | |
| 356 | 374 | case 0x02: /* Z1 */ |
| ... | ... | @@ -364,6 +382,14 @@ static uint16_t tsc2102_data_register_read(struct tsc210x_state_s *s, int reg) |
| 364 | 382 | (s->noise & 3); |
| 365 | 383 | |
| 366 | 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 | 393 | return 0xffff; |
| 368 | 394 | |
| 369 | 395 | case 0x05: /* BAT1 */ |
| ... | ... | @@ -414,9 +440,19 @@ static uint16_t tsc2102_control_register_read( |
| 414 | 440 | return (s->pressure << 15) | ((!s->busy) << 14) | |
| 415 | 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 | 457 | case 0x03: /* Reference */ |
| 422 | 458 | return s->ref; |
| ... | ... | @@ -427,7 +463,18 @@ static uint16_t tsc2102_control_register_read( |
| 427 | 463 | case 0x05: /* Configuration */ |
| 428 | 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 | 476 | default: |
| 477 | + bad_reg: | |
| 431 | 478 | #ifdef TSC_VERBOSE |
| 432 | 479 | fprintf(stderr, "tsc2102_control_register_read: " |
| 433 | 480 | "no such register: 0x%02x\n", reg); |
| ... | ... | @@ -556,10 +603,27 @@ static void tsc2102_control_register_write( |
| 556 | 603 | s->filter = value & 0xff; |
| 557 | 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 | 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 | 627 | case 0x03: /* Reference */ |
| 564 | 628 | s->ref = value & 0x1f; |
| 565 | 629 | return; |
| ... | ... | @@ -586,7 +650,21 @@ static void tsc2102_control_register_write( |
| 586 | 650 | #endif |
| 587 | 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 | 666 | default: |
| 667 | + bad_reg: | |
| 590 | 668 | #ifdef TSC_VERBOSE |
| 591 | 669 | fprintf(stderr, "tsc2102_control_register_write: " |
| 592 | 670 | "no such register: 0x%02x\n", reg); |
| ... | ... | @@ -785,7 +863,7 @@ static void tsc210x_pin_update(struct tsc210x_state_s *s) |
| 785 | 863 | return; |
| 786 | 864 | } |
| 787 | 865 | |
| 788 | - if (!s->enabled || s->busy) | |
| 866 | + if (!s->enabled || s->busy || s->dav) | |
| 789 | 867 | return; |
| 790 | 868 | |
| 791 | 869 | s->busy = 1; |
| ... | ... | @@ -805,6 +883,8 @@ static uint16_t tsc210x_read(struct tsc210x_state_s *s) |
| 805 | 883 | switch (s->page) { |
| 806 | 884 | case TSC_DATA_REGISTERS_PAGE: |
| 807 | 885 | ret = tsc2102_data_register_read(s, s->offset); |
| 886 | + if (!s->dav) | |
| 887 | + qemu_irq_raise(s->davint); | |
| 808 | 888 | break; |
| 809 | 889 | case TSC_CONTROL_REGISTERS_PAGE: |
| 810 | 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 | 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 | 958 | static void tsc210x_timer_tick(void *opaque) |
| 863 | 959 | { |
| 864 | 960 | struct tsc210x_state_s *s = opaque; |
| ... | ... | @@ -871,6 +967,7 @@ static void tsc210x_timer_tick(void *opaque) |
| 871 | 967 | s->busy = 0; |
| 872 | 968 | s->dav |= mode_regs[s->function]; |
| 873 | 969 | tsc210x_pin_update(s); |
| 970 | + qemu_irq_lower(s->davint); | |
| 874 | 971 | } |
| 875 | 972 | |
| 876 | 973 | static void tsc210x_touchscreen_event(void *opaque, |
| ... | ... | @@ -1001,6 +1098,7 @@ static int tsc210x_load(QEMUFile *f, void *opaque, int version_id) |
| 1001 | 1098 | |
| 1002 | 1099 | s->busy = qemu_timer_pending(s->timer); |
| 1003 | 1100 | qemu_set_irq(s->pint, !s->irq); |
| 1101 | + qemu_set_irq(s->davint, !s->dav); | |
| 1004 | 1102 | |
| 1005 | 1103 | return 0; |
| 1006 | 1104 | } |
| ... | ... | @@ -1020,9 +1118,19 @@ struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio) |
| 1020 | 1118 | s->precision = s->nextprecision = 0; |
| 1021 | 1119 | s->timer = qemu_new_timer(vm_clock, tsc210x_timer_tick, s); |
| 1022 | 1120 | s->pint = pint; |
| 1121 | + s->model = 0x2102; | |
| 1023 | 1122 | s->name = "tsc2102"; |
| 1024 | 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 | 1134 | s->chip.opaque = s; |
| 1027 | 1135 | s->chip.send = (void *) tsc210x_write; |
| 1028 | 1136 | s->chip.receive = (void *) tsc210x_read; |
| ... | ... | @@ -1048,9 +1156,149 @@ struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio) |
| 1048 | 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 | 1213 | struct i2s_codec_s *tsc210x_codec(struct uwire_slave_s *chip) |
| 1052 | 1214 | { |
| 1053 | 1215 | struct tsc210x_state_s *s = (struct tsc210x_state_s *) chip->opaque; |
| 1054 | 1216 | |
| 1055 | 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 | +} | ... | ... |