1// Copyright 2016 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <assert.h>
6#include <dirent.h>
7#include <errno.h>
8#include <fcntl.h>
9#include <stdbool.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <unistd.h>
14
15#include <hid/acer12.h>
16#include <hid/ft3x27.h>
17#include <hid/egalax.h>
18#include <hid/eyoyo.h>
19#include <hid/paradise.h>
20#include <hid/usages.h>
21
22#include <lib/framebuffer/framebuffer.h>
23
24#include <zircon/device/input.h>
25#include <zircon/process.h>
26#include <zircon/syscalls.h>
27#include <zircon/types.h>
28
29#define DEV_INPUT       "/dev/class/input"
30#define CLEAR_BTN_SIZE 50
31#define I2C_HID_DEBUG 0
32
33enum touch_panel_type {
34    TOUCH_PANEL_UNKNOWN,
35    TOUCH_PANEL_ACER12,
36    TOUCH_PANEL_PARADISE,
37    TOUCH_PANEL_PARADISEv2,
38    TOUCH_PANEL_PARADISEv3,
39    TOUCH_PANEL_EGALAX,
40    TOUCH_PANEL_EYOYO,
41    TOUCH_PANEL_FT3X27,
42};
43
44typedef struct display_info {
45    uint32_t width;
46    uint32_t height;
47    uint32_t stride;
48    zx_pixel_format_t format;
49} display_info_t;
50
51// Array of colors for each finger
52static uint32_t colors[] = {
53    0x00ff0000,
54    0x0000ff00,
55    0x000000ff,
56    0x00ffff00,
57    0x00ff00ff,
58    0x0000ffff,
59    0x00000000,
60    0x00f0f0f0,
61    0x00f00f00,
62    0x000ff000,
63};
64
65static uint16_t colors16[] = {
66    0x003f,
67    0x03c0,
68    0xfc00,
69    0xe00f,
70    0xeff3,
71    0x003f,
72    0x03c0,
73    0x1c00,
74    0xe000,
75    0xe003,
76};
77
78static bool run = false;
79
80static void acer12_touch_dump(acer12_touch_t* rpt) {
81    printf("report id: %u\n", rpt->rpt_id);
82    for (int i = 0; i < 5; i++) {
83        printf("finger %d\n", i);
84        printf("  finger_id: %u\n", rpt->fingers[i].finger_id);
85        printf("    tswitch: %u\n", acer12_finger_id_tswitch(rpt->fingers[i].finger_id));
86        printf("    contact: %u\n", acer12_finger_id_contact(rpt->fingers[i].finger_id));
87        printf("  width:  %u\n", rpt->fingers[i].width);
88        printf("  height: %u\n", rpt->fingers[i].height);
89        printf("  x:      %u\n", rpt->fingers[i].x);
90        printf("  y:      %u\n", rpt->fingers[i].y);
91    }
92    printf("scan_time: %u\n", rpt->scan_time);
93    printf("contact count: %u\n", rpt->contact_count);
94}
95
96static void ft3x27_touch_dump(ft3x27_touch_t* rpt) {
97    printf("report id: %u\n", rpt->rpt_id);
98    for (int i = 0; i < 5; i++) {
99        printf("finger %d\n", i);
100        printf("  finger_id: %u\n", rpt->fingers[i].finger_id);
101        printf("    tswitch: %u\n", ft3x27_finger_id_tswitch(rpt->fingers[i].finger_id));
102        printf("    contact: %u\n", ft3x27_finger_id_contact(rpt->fingers[i].finger_id));
103        printf("  x:      %u\n", rpt->fingers[i].x);
104        printf("  y:      %u\n", rpt->fingers[i].y);
105    }
106    printf("contact count: %u\n", rpt->contact_count);
107}
108
109static void paradise_touch_dump(paradise_touch_t* rpt) {
110    printf("report id: %u\n", rpt->rpt_id);
111    printf("pad: %#02x\n", rpt->pad);
112    printf("contact count: %u\n", rpt->contact_count);
113    for (int i = 0; i < 5; i++) {
114        printf("finger %d\n", i);
115        printf("  flags: %#02x\n", rpt->fingers[i].flags);
116        printf("    tswitch: %u\n", paradise_finger_flags_tswitch(rpt->fingers[i].flags));
117        printf("    confidence: %u\n", paradise_finger_flags_confidence(rpt->fingers[i].flags));
118        printf("  finger_id: %u\n", rpt->fingers[i].finger_id);
119        printf("  x:      %u\n", rpt->fingers[i].x);
120        printf("  y:      %u\n", rpt->fingers[i].y);
121    }
122    printf("scan_time: %u\n", rpt->scan_time);
123}
124
125static void paradise_touch_v2_dump(paradise_touch_v2_t* rpt) {
126    printf("report id: %u\n", rpt->rpt_id);
127    printf("pad: %#02x\n", rpt->pad);
128    printf("contact count: %u\n", rpt->contact_count);
129    for (int i = 0; i < 5; i++) {
130        printf("finger %d\n", i);
131        printf("  flags: %#02x\n", rpt->fingers[i].flags);
132        printf("    tswitch: %u\n", paradise_finger_flags_tswitch(rpt->fingers[i].flags));
133        printf("    confidence: %u\n", paradise_finger_flags_confidence(rpt->fingers[i].flags));
134        printf("  finger_id: %u\n", rpt->fingers[i].finger_id);
135        printf("  width:  %u\n", rpt->fingers[i].width);
136        printf("  height: %u\n", rpt->fingers[i].height);
137        printf("  x:      %u\n", rpt->fingers[i].x);
138        printf("  y:      %u\n", rpt->fingers[i].y);
139    }
140    printf("scan_time: %u\n", rpt->scan_time);
141}
142
143static void egalax_touch_dump(egalax_touch_t* rpt) {
144    printf("report id: %u\n", rpt->report_id);
145    printf("pad: %02x\n", egalax_pad(rpt->button_pad));
146    printf("device supports one contact\n");
147    printf("  finger down: %u\n", egalax_pressed_flags(rpt->button_pad));
148    printf("    x: %u\n", rpt->x);
149    printf("    y: %u\n", rpt->y);
150}
151
152static void eyoyo_touch_dump(acer12_touch_t* rpt) {
153    printf("report id: %u\n", rpt->rpt_id);
154    for (int i = 0; i < 5; i++) {
155        printf("finger %d\n", i);
156        printf("  finger_id: %u\n", rpt->fingers[i].finger_id);
157        printf("    tswitch: %u\n", acer12_finger_id_tswitch(rpt->fingers[i].finger_id));
158        printf("    contact: %u\n", acer12_finger_id_contact(rpt->fingers[i].finger_id));
159        printf("  width:  %u\n", rpt->fingers[i].width);
160        printf("  height: %u\n", rpt->fingers[i].height);
161        printf("  x:      %u\n", rpt->fingers[i].x);
162        printf("  y:      %u\n", rpt->fingers[i].y);
163    }
164    printf("scan_time: %u\n", rpt->scan_time);
165    printf("contact count: %u\n", rpt->contact_count);
166}
167
168static uint32_t scale32(uint32_t z, uint32_t screen_dim, uint32_t rpt_dim) {
169    return (z * screen_dim) / rpt_dim;
170}
171
172static void draw_points(uint32_t* pixels, uint32_t color, uint32_t x, uint32_t y, uint8_t width, uint8_t height, uint32_t fbwidth, uint32_t fbheight) {
173    uint32_t xrad = (width + 1) / 2;
174    uint32_t yrad = (height + 1) / 2;
175
176    uint32_t xmin = (xrad > x) ? 0 : x - xrad;
177    uint32_t xmax = (xrad > fbwidth - x) ? fbwidth : x + xrad;
178    uint32_t ymin = (yrad > y) ? 0 : y - yrad;
179    uint32_t ymax = (yrad > fbheight - y) ? fbheight : y + yrad;
180
181    for (uint32_t px = xmin; px < xmax; px++) {
182        for (uint32_t py = ymin; py < ymax; py++) {
183            *(pixels + py * fbwidth + px) = color;
184        }
185    }
186}
187static uint8_t is_exit(uint32_t x, uint32_t y, display_info_t* info) {
188        return (((y + CLEAR_BTN_SIZE) > info->height) &&
189             (x < CLEAR_BTN_SIZE));
190}
191
192static void draw_points16(uint32_t* pixels, uint16_t color, uint32_t x, uint32_t y, uint8_t width, uint8_t height, uint32_t fbwidth, uint32_t fbheight) {
193
194    uint16_t* pixels16 = (uint16_t*)pixels;
195    uint32_t xrad = (width + 1) / 2;
196    uint32_t yrad = (height + 1) / 2;
197
198    uint32_t xmin = (xrad > x) ? 0 : x - xrad;
199    uint32_t xmax = (xrad > fbwidth - x) ? fbwidth : x + xrad;
200    uint32_t ymin = (yrad > y) ? 0 : y - yrad;
201    uint32_t ymax = (yrad > fbheight - y) ? fbheight : y + yrad;
202
203    for (uint32_t px = xmin; px < xmax; px++) {
204        for (uint32_t py = ymin; py < ymax; py++) {
205            pixels16[py*fbwidth + px] = color;
206        }
207    }
208}
209
210static uint32_t get_color(uint8_t c) {
211    return colors[c];
212}
213
214static uint32_t get_color16(uint8_t c) {
215    return colors16[c];
216}
217
218static void clear_screen(void* buf, display_info_t* info) {
219    memset(buf, 0xff, ZX_PIXEL_FORMAT_BYTES(info->format) * info->stride * info->height);
220    if (ZX_PIXEL_FORMAT_BYTES(info->format) == 4) {
221        draw_points((uint32_t*)buf, 0xff00ff, info->stride - (CLEAR_BTN_SIZE / 2),
222            (CLEAR_BTN_SIZE / 2), CLEAR_BTN_SIZE, CLEAR_BTN_SIZE, info->stride,
223            info->height);
224        draw_points((uint32_t*)buf, 0x0000ff, (CLEAR_BTN_SIZE / 2),
225            info->height - (CLEAR_BTN_SIZE / 2), CLEAR_BTN_SIZE, CLEAR_BTN_SIZE, info->stride,
226            info->height);
227    } else if (ZX_PIXEL_FORMAT_BYTES(info->format) == 2) {
228        draw_points16((uint32_t*)buf, 0xf00f, info->stride - (CLEAR_BTN_SIZE / 2),
229            (CLEAR_BTN_SIZE / 2), CLEAR_BTN_SIZE, CLEAR_BTN_SIZE, info->stride,
230            info->height);
231        draw_points16((uint32_t*)buf, 0x001f, (CLEAR_BTN_SIZE / 2),
232            info->height - (CLEAR_BTN_SIZE / 2), CLEAR_BTN_SIZE, CLEAR_BTN_SIZE, info->stride,
233            info->height);
234    }
235}
236
237static void process_acer12_touchscreen_input(void* buf, size_t len, uint32_t* pixels,
238                                             display_info_t* info) {
239    acer12_touch_t* rpt = buf;
240    if (len < sizeof(*rpt)) {
241        printf("bad report size: %zd < %zd\n", len, sizeof(*rpt));
242        return;
243    }
244#if I2C_HID_DEBUG
245    acer12_touch_dump(rpt);
246#endif
247    for (uint8_t c = 0; c < 5; c++) {
248        if (!acer12_finger_id_tswitch(rpt->fingers[c].finger_id % 10)) continue;
249        uint32_t x = scale32(rpt->fingers[c].x, info->width, ACER12_X_MAX);
250        uint32_t y = scale32(rpt->fingers[c].y, info->height, ACER12_Y_MAX);
251        uint32_t width = 2 * rpt->fingers[c].width;
252        uint32_t height = 2 * rpt->fingers[c].height;
253        uint32_t color = get_color(acer12_finger_id_contact(rpt->fingers[c].finger_id));
254        draw_points(pixels, color, x, y, width, height, info->stride, info->height);
255    }
256
257    if (acer12_finger_id_tswitch(rpt->fingers[0].finger_id)) {
258        uint32_t x = scale32(rpt->fingers[0].x, info->width, ACER12_X_MAX);
259        uint32_t y = scale32(rpt->fingers[0].y, info->height, ACER12_Y_MAX);
260        if (x + CLEAR_BTN_SIZE > info->width && y < CLEAR_BTN_SIZE) {
261            clear_screen(pixels, info);
262        }
263        run = !is_exit(x, y, info);
264    }
265}
266
267
268static void process_ft3x27_touchscreen_input(void* buf, size_t len, uint32_t* pixels,
269                                             display_info_t* info) {
270    ft3x27_touch_t* rpt = buf;
271    if (len < sizeof(*rpt)) {
272        printf("bad report size: %zd < %zd\n", len, sizeof(*rpt));
273        return;
274    }
275#if I2C_HID_DEBUG
276    ft3x27_touch_dump(rpt);
277#endif
278    for (uint8_t c = 0; c < 5; c++) {
279        if (!ft3x27_finger_id_tswitch(rpt->fingers[c].finger_id)) continue;
280        uint32_t x = scale32(rpt->fingers[c].x, info->width, FT3X27_X_MAX);
281        uint32_t y = scale32(rpt->fingers[c].y, info->height, FT3X27_Y_MAX);
282        uint32_t width = 10;//2 * rpt->fingers[c].width;
283        uint32_t height = 10;//2 * rpt->fingers[c].height;
284        uint16_t color = get_color16(ft3x27_finger_id_contact(rpt->fingers[c].finger_id));
285        draw_points16(pixels, color, x, y, width, height, info->stride, info->height);
286    }
287
288    if (ft3x27_finger_id_tswitch(rpt->fingers[0].finger_id)) {
289        uint32_t x = scale32(rpt->fingers[0].x, info->width, FT3X27_X_MAX);
290        uint32_t y = scale32(rpt->fingers[0].y, info->height, FT3X27_Y_MAX);
291        if (x + CLEAR_BTN_SIZE > info->width && y < CLEAR_BTN_SIZE) {
292            clear_screen(pixels, info);
293        }
294        run = !is_exit(x, y, info);
295    }
296}
297
298static void process_egalax_touchscreen_input(void* buf, size_t len, uint32_t* pixels,
299                                             display_info_t* info) {
300    egalax_touch_t* rpt = buf;
301    if (len < sizeof(*rpt)) {
302        printf("bad report size: %zd < %zd\n", len, sizeof(*rpt));
303        return;
304    }
305#if I2C_HID_DEBUG
306    egalax_touch_dump(rpt);
307#endif
308    if (!egalax_pressed_flags(rpt->button_pad)) {
309        uint32_t x = scale32(rpt->x, info->width, EGALAX_X_MAX);
310        uint32_t y = scale32(rpt->y, info->height, EGALAX_Y_MAX);
311        uint32_t width = 5;
312        uint32_t height = 5;
313        uint32_t color = get_color(1);
314        draw_points(pixels, color, x, y, width, height, info->stride, info->height);
315    } else {
316        uint32_t x = scale32(rpt->x, info->width, EGALAX_X_MAX);
317        uint32_t y = scale32(rpt->y, info->height, EGALAX_Y_MAX);
318        if (x + CLEAR_BTN_SIZE > info->width && y < CLEAR_BTN_SIZE) {
319            clear_screen(pixels, info);
320        }
321        run = !is_exit(x, y, info);
322    }
323}
324
325static void process_eyoyo_touchscreen_input(void* buf, size_t len, uint32_t* pixels,
326                                             display_info_t* info) {
327    eyoyo_touch_t* rpt = buf;
328    if (len < sizeof(*rpt)) {
329        printf("bad report size: %zd < %zd\n", len, sizeof(*rpt));
330        return;
331    }
332#if I2C_HID_DEBUG
333    eyoyo_touch_dump(rpt);
334#endif
335
336    for (uint8_t c = 0; c < 10; c++) {
337        if (!eyoyo_finger_id_tswitch(rpt->fingers[c].finger_id)) continue;
338        uint32_t x = scale32(rpt->fingers[c].x, info->width, EYOYO_X_MAX);
339        uint32_t y = scale32(rpt->fingers[c].y, info->height, EYOYO_Y_MAX);
340        uint32_t width = 10;
341        uint32_t height = 10;
342        uint32_t color = get_color(eyoyo_finger_id_contact(rpt->fingers[c].finger_id));
343        draw_points(pixels, color, x, y, width, height, info->stride, info->height);
344    }
345
346    if (eyoyo_finger_id_tswitch(rpt->fingers[0].finger_id)) {
347        uint32_t x = scale32(rpt->fingers[0].x, info->width, FT3X27_X_MAX);
348        uint32_t y = scale32(rpt->fingers[0].y, info->height, FT3X27_Y_MAX);
349        if (x + CLEAR_BTN_SIZE > info->width && y < CLEAR_BTN_SIZE) {
350            clear_screen(pixels, info);
351        }
352        run = !is_exit(x, y, info);
353    }
354}
355
356static void process_paradise_touchscreen_input(void* buf, size_t len, uint32_t* pixels,
357        display_info_t* info) {
358    paradise_touch_t* rpt = buf;
359    if (len < sizeof(*rpt)) {
360        printf("bad report size: %zd < %zd\n", len, sizeof(*rpt));
361        return;
362    }
363#if I2C_HID_DEBUG
364    paradise_touch_dump(rpt);
365#endif
366    for (uint8_t c = 0; c < 5; c++) {
367        if (!paradise_finger_flags_tswitch(rpt->fingers[c].flags)) continue;
368        uint32_t x = scale32(rpt->fingers[c].x, info->width, PARADISE_X_MAX);
369        uint32_t y = scale32(rpt->fingers[c].y, info->height, PARADISE_Y_MAX);
370        uint32_t width = 10;
371        uint32_t height = 10;
372        uint32_t color = get_color(c);
373        draw_points(pixels, color, x, y, width, height, info->stride, info->height);
374    }
375
376    if (paradise_finger_flags_tswitch(rpt->fingers[0].flags)) {
377        uint32_t x = scale32(rpt->fingers[0].x, info->width, PARADISE_X_MAX);
378        uint32_t y = scale32(rpt->fingers[0].y, info->height, PARADISE_Y_MAX);
379        if (x + CLEAR_BTN_SIZE > info->width && y < CLEAR_BTN_SIZE) {
380            clear_screen(pixels, info);
381        }
382        run = !is_exit(x, y, info);
383    }
384}
385
386static void process_paradise_touchscreen_v2_input(void* buf, size_t len, uint32_t* pixels,
387        display_info_t* info) {
388    paradise_touch_v2_t* rpt = buf;
389    if (len < sizeof(*rpt)) {
390        printf("bad report size: %zd < %zd\n", len, sizeof(*rpt));
391        return;
392    }
393#if I2C_HID_DEBUG
394    paradise_touch_v2_dump(rpt);
395#endif
396    for (uint8_t c = 0; c < 5; c++) {
397        if (!paradise_finger_flags_tswitch(rpt->fingers[c].flags)) continue;
398        uint32_t x = scale32(rpt->fingers[c].x, info->width, PARADISE_X_MAX);
399        uint32_t y = scale32(rpt->fingers[c].y, info->height, PARADISE_Y_MAX);
400        uint32_t width = 2 * rpt->fingers[c].width;
401        uint32_t height = 2 * rpt->fingers[c].height;
402        uint32_t color = get_color(c);
403        draw_points(pixels, color, x, y, width, height, info->stride, info->height);
404    }
405
406    if (paradise_finger_flags_tswitch(rpt->fingers[0].flags)) {
407        uint32_t x = scale32(rpt->fingers[0].x, info->width, PARADISE_X_MAX);
408        uint32_t y = scale32(rpt->fingers[0].y, info->height, PARADISE_Y_MAX);
409        if (x + CLEAR_BTN_SIZE > info->width && y < CLEAR_BTN_SIZE) {
410            clear_screen(pixels, info);
411        }
412        run = !is_exit(x, y, info);
413    }
414}
415
416static void process_acer12_stylus_input(void* buf, size_t len, uint32_t* pixels,
417        display_info_t* info) {
418    acer12_stylus_t* rpt = buf;
419    if (len < sizeof(*rpt)) {
420        printf("bad report size: %zd < %zd\n", len, sizeof(*rpt));
421        return;
422    }
423    // Don't draw for out of range or hover with no switches.
424    if (!rpt->status || rpt->status == ACER12_STYLUS_STATUS_INRANGE) return;
425
426    uint32_t x = scale32(rpt->x, info->width, ACER12_STYLUS_X_MAX);
427    uint32_t y = scale32(rpt->y, info->height, ACER12_STYLUS_Y_MAX);
428    // Pressing the clear button requires contact (not just hover).
429    if (acer12_stylus_status_tswitch(rpt->status)) {
430        if (x + CLEAR_BTN_SIZE > info->width && y < CLEAR_BTN_SIZE) {
431            clear_screen(pixels, info);
432            return;
433        }
434        run = !is_exit(x, y, info);
435    }
436    uint32_t size, color;
437    size = acer12_stylus_status_tswitch(rpt->status) ? rpt->pressure >> 4 : 4;
438    switch (rpt->status) {
439    case 3: // in_range | tip_switch
440        color = get_color(0);
441        break;
442    case 5: // in_range | barrel_switch
443        color = get_color(1);
444        break;
445    case 7: // in_range | tip_switch | barrel_switch
446        color = get_color(4);
447        break;
448    case 9: // in_range | invert
449        color = get_color(5);
450        break;
451    case 17: // in_range | erase (== tip_switch | invert)
452        color = 0x00ffffff;
453        size = 32;  // fixed size eraser
454        break;
455    default:
456        printf("unknown rpt->status=%u\n", rpt->status);
457        color = get_color(6);
458        break;
459    }
460
461    draw_points(pixels, color, x, y, size, size, info->stride, info->height);
462}
463
464int main(int argc, char* argv[]) {
465    const char* err;
466    zx_status_t status = fb_bind(true, &err);
467    if (status != ZX_OK) {
468        printf("failed to open framebuffer: %d (%s)\n", status, err);
469        return -1;
470    }
471
472    display_info_t info;
473    fb_get_config(&info.width, &info.height, &info.stride, &info.format);
474
475    zx_handle_t vmo = fb_get_single_buffer();
476
477    printf("format = %d\n", info.format);
478    printf("width = %d\n", info.width);
479    printf("height = %d\n", info.height);
480    printf("stride = %d\n", info.stride);
481
482    size_t size = info.stride * ZX_PIXEL_FORMAT_BYTES(info.format) * info.height;
483    uintptr_t fbo;
484    status = _zx_vmar_map(zx_vmar_root_self(),
485                          ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
486                          0, vmo, 0, size, &fbo);
487    if (status < 0) {
488        printf("couldn't map fb: %d\n", status);
489        return -1;
490    }
491
492    uint32_t* pixels32 = (uint32_t*)fbo;
493
494    clear_screen((void*)fbo, &info);
495    zx_cache_flush(pixels32, size, ZX_CACHE_FLUSH_DATA);
496
497    // Scan /dev/class/input to find the touchscreen
498    struct dirent* de;
499    DIR* dir = opendir(DEV_INPUT);
500    if (!dir) {
501        printf("failed to open %s: %d\n", DEV_INPUT, errno);
502        return -1;
503    }
504
505    ssize_t ret;
506    int touchfd = -1;
507    size_t rpt_desc_len = 0;
508    uint8_t* rpt_desc = NULL;
509    enum touch_panel_type panel = TOUCH_PANEL_UNKNOWN;
510    while ((de = readdir(dir)) != NULL) {
511        char devname[128];
512
513        if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
514            continue;
515        }
516
517        snprintf(devname, sizeof(devname), "%s/%s", DEV_INPUT, de->d_name);
518        touchfd = open(devname, O_RDONLY);
519        if (touchfd < 0) {
520            printf("failed to open %s: %d\n", devname, errno);
521            continue;
522        }
523
524        ret = ioctl_input_get_report_desc_size(touchfd, &rpt_desc_len);
525        if (ret < 0) {
526            printf("failed to get report descriptor length for %s: %zd\n", devname, ret);
527            goto next_node;
528        }
529
530        rpt_desc = malloc(rpt_desc_len);
531        if (rpt_desc == NULL) {
532            printf("no memory!\n");
533            exit(-1);
534        }
535
536        ret = ioctl_input_get_report_desc(touchfd, rpt_desc, rpt_desc_len);
537        if (ret < 0) {
538            printf("failed to get report descriptor for %s: %zd\n", devname, ret);
539            goto next_node;
540        }
541
542        if (is_acer12_touch_report_desc(rpt_desc, rpt_desc_len)) {
543            panel = TOUCH_PANEL_ACER12;
544            // Found the touchscreen
545            printf("touchscreen: %s\n", devname);
546            break;
547        }
548
549        if (is_paradise_touch_report_desc(rpt_desc, rpt_desc_len)) {
550            panel = TOUCH_PANEL_PARADISE;
551            // Found the touchscreen
552            printf("touchscreen: %s\n", devname);
553            break;
554        }
555
556        if (is_paradise_touch_v2_report_desc(rpt_desc, rpt_desc_len)) {
557            panel = TOUCH_PANEL_PARADISEv2;
558            // Found the touchscreen
559            printf("touchscreen: %s\n", devname);
560            break;
561        }
562
563        if (is_paradise_touch_v3_report_desc(rpt_desc, rpt_desc_len)) {
564            panel = TOUCH_PANEL_PARADISEv3;
565            // Found the touchscreen
566            printf("touchscreen: %s\n", devname);
567            break;
568        }
569
570        if (is_egalax_touchscreen_report_desc(rpt_desc, rpt_desc_len)) {
571            panel = TOUCH_PANEL_EGALAX;
572            printf("touchscreen: %s is egalax\n", devname);
573            break;
574        }
575
576        if (is_eyoyo_touch_report_desc(rpt_desc, rpt_desc_len)) {
577            panel = TOUCH_PANEL_EYOYO;
578            printf("touchscreen: %s is eyoyo\n", devname);
579            setup_eyoyo_touch(touchfd);
580            break;
581        }
582
583        if (is_ft3x27_touch_report_desc(rpt_desc, rpt_desc_len)) {
584            panel = TOUCH_PANEL_FT3X27;
585            printf("touchscreen: %s is ft3x27\n", devname);
586            break;
587        }
588
589next_node:
590        rpt_desc_len = 0;
591
592        if (rpt_desc != NULL) {
593            free(rpt_desc);
594            rpt_desc = NULL;
595        }
596
597        if (touchfd >= 0) {
598            close(touchfd);
599            touchfd = -1;
600        }
601    }
602    closedir(dir);
603
604    if (touchfd < 0) {
605        printf("could not find a touchscreen!\n");
606        return -1;
607    }
608    assert(rpt_desc_len > 0);
609    assert(rpt_desc);
610
611    input_report_size_t max_rpt_sz = 0;
612    ret = ioctl_input_get_max_reportsize(touchfd, &max_rpt_sz);
613    if (ret < 0) {
614        printf("failed to get max report size: %zd\n", ret);
615        return -1;
616    }
617    printf("Max report size is %u\n",max_rpt_sz);
618    void* buf = malloc(max_rpt_sz);
619    if (buf == NULL) {
620        printf("no memory!\n");
621        return -1;
622    }
623
624    run = true;
625    while (run) {
626        ssize_t r = read(touchfd, buf, max_rpt_sz);
627        if (r < 0) {
628            printf("touchscreen read error: %zd (errno=%d)\n", r, errno);
629            break;
630        }
631        if (panel == TOUCH_PANEL_ACER12) {
632            if (*(uint8_t*)buf == ACER12_RPT_ID_TOUCH) {
633                process_acer12_touchscreen_input(buf, r, pixels32, &info);
634            } else if (*(uint8_t*)buf == ACER12_RPT_ID_STYLUS) {
635                process_acer12_stylus_input(buf, r, pixels32, &info);
636            }
637        } else if (panel == TOUCH_PANEL_PARADISE) {
638            if (*(uint8_t*)buf == PARADISE_RPT_ID_TOUCH) {
639                process_paradise_touchscreen_input(buf, r, pixels32, &info);
640            }
641        } else if (panel == TOUCH_PANEL_PARADISEv2) {
642            if (*(uint8_t*)buf == PARADISE_RPT_ID_TOUCH) {
643                process_paradise_touchscreen_v2_input(buf, r, pixels32, &info);
644            }
645        } else if (panel == TOUCH_PANEL_PARADISEv3) {
646            if (*(uint8_t*)buf == PARADISE_RPT_ID_TOUCH) {
647                process_paradise_touchscreen_input(buf, r, pixels32, &info);
648            }
649        } else if (panel == TOUCH_PANEL_EGALAX) {
650            if (*(uint8_t*)buf == EGALAX_RPT_ID_TOUCH) {
651                process_egalax_touchscreen_input(buf, r, pixels32, &info);
652            }
653        } else if (panel == TOUCH_PANEL_EYOYO) {
654            if (*(uint8_t*)buf == EYOYO_RPT_ID_TOUCH) {
655                process_eyoyo_touchscreen_input(buf, r, pixels32, &info);
656            }
657        } else if (panel == TOUCH_PANEL_FT3X27) {
658            if (*(uint8_t*)buf == FT3X27_RPT_ID_TOUCH) {
659                process_ft3x27_touchscreen_input(buf, r, pixels32, &info);
660            }
661        }
662        zx_cache_flush(pixels32, size, ZX_CACHE_FLUSH_DATA);
663    }
664    memset(pixels32, 0x00, ZX_PIXEL_FORMAT_BYTES(info.format) * info.stride * info.height);
665    zx_cache_flush(pixels32, size, ZX_CACHE_FLUSH_DATA);
666
667    free(buf);
668    free(rpt_desc);
669    close(touchfd);
670    _zx_vmar_unmap(zx_vmar_root_self(), fbo, size);
671    fb_release();
672    return 0;
673}
674