1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "qemu-common.h"
18 #include "utils/panic.h"
19 #include "android/hw-events.h"
20 #include "android/charmap.h"
21 #include "android/multitouch-screen.h"
22 #include "android/sdk-controller-socket.h"
23 #include "android/multitouch-port.h"
24 #include "android/globals.h" /* for android_hw */
25 #include "android/opengles.h"
26 #include "android/utils/misc.h"
27 #include "android/utils/jpeg-compress.h"
28 #include "android/utils/debug.h"
29
30 #define E(...) derror(__VA_ARGS__)
31 #define W(...) dwarning(__VA_ARGS__)
32 #define D(...) VERBOSE_PRINT(mtport,__VA_ARGS__)
33 #define D_ACTIVE VERBOSE_CHECK(mtport)
34
35 #define TRACE_ON 1
36
37 #if TRACE_ON
38 #define T(...) VERBOSE_PRINT(mtport,__VA_ARGS__)
39 #else
40 #define T(...)
41 #endif
42
43 /* Timeout (millisec) to use when communicating with SDK controller. */
44 #define SDKCTL_MT_TIMEOUT 3000
45
46 /*
47 * Message types used in multi-touch emulation.
48 */
49
50 /* Pointer move message. */
51 #define SDKCTL_MT_MOVE 1
52 /* First pointer down message. */
53 #define SDKCTL_MT_FISRT_DOWN 2
54 /* Last pointer up message. */
55 #define SDKCTL_MT_LAST_UP 3
56 /* Pointer down message. */
57 #define SDKCTL_MT_POINTER_DOWN 4
58 /* Pointer up message. */
59 #define SDKCTL_MT_POINTER_UP 5
60 /* Sends framebuffer update. */
61 #define SDKCTL_MT_FB_UPDATE 6
62 /* Framebuffer update has been received. */
63 #define SDKCTL_MT_FB_UPDATE_RECEIVED 7
64 /* Framebuffer update has been handled. */
65 #define SDKCTL_MT_FB_UPDATE_HANDLED 8
66
67 /* Multi-touch port descriptor. */
68 struct AndroidMTSPort {
69 /* Caller identifier. */
70 void* opaque;
71 /* Communication socket. */
72 SDKCtlSocket* sdkctl;
73 /* Initialized JPEG compressor instance. */
74 AJPEGDesc* jpeg_compressor;
75 /* Direct packet descriptor for framebuffer updates. */
76 SDKCtlDirectPacket* fb_packet;
77 };
78
79 /* Data sent with SDKCTL_MT_QUERY_START */
80 typedef struct QueryDispData {
81 /* Width of the emulator display. */
82 int width;
83 /* Height of the emulator display. */
84 int height;
85 } QueryDispData;
86
87 /* Multi-touch event structure received from SDK controller port. */
88 typedef struct AndroidMTEvent {
89 /* Pointer identifier. */
90 int pid;
91 /* Pointer 'x' coordinate. */
92 int x;
93 /* Pointer 'y' coordinate. */
94 int y;
95 /* Pointer pressure. */
96 int pressure;
97 } AndroidMTEvent;
98
99 /* Multi-touch pointer descriptor received from SDK controller port. */
100 typedef struct AndroidMTPtr {
101 /* Pointer identifier. */
102 int pid;
103 } AndroidMTPtr;
104
105 /* Destroys and frees the descriptor. */
106 static void
_mts_port_free(AndroidMTSPort * mtsp)107 _mts_port_free(AndroidMTSPort* mtsp)
108 {
109 if (mtsp != NULL) {
110 if (mtsp->fb_packet != NULL) {
111 sdkctl_direct_packet_release(mtsp->fb_packet);
112 }
113 if (mtsp->jpeg_compressor != NULL) {
114 jpeg_compressor_destroy(mtsp->jpeg_compressor);
115 }
116 if (mtsp->sdkctl != NULL) {
117 sdkctl_socket_release(mtsp->sdkctl);
118 }
119 AFREE(mtsp);
120 }
121 }
122
123 /********************************************************************************
124 * Multi-touch action handlers
125 *******************************************************************************/
126
127 /*
128 * Although there are a lot of similarities in the way the handlers below are
129 * implemented, for the sake of tracing / debugging it's better to have a
130 * separate handler for each distinctive action.
131 */
132
133 /* First pointer down event handler. */
134 static void
_on_action_down(int tracking_id,int x,int y,int pressure)135 _on_action_down(int tracking_id, int x, int y, int pressure)
136 {
137 multitouch_update_pointer(MTES_DEVICE, tracking_id, x, y, pressure);
138 }
139
140 /* Last pointer up event handler. */
141 static void
_on_action_up(int tracking_id)142 _on_action_up(int tracking_id)
143 {
144 multitouch_update_pointer(MTES_DEVICE, tracking_id, 0, 0, 0);
145 }
146
147 /* Pointer down event handler. */
148 static void
_on_action_pointer_down(int tracking_id,int x,int y,int pressure)149 _on_action_pointer_down(int tracking_id, int x, int y, int pressure)
150 {
151 multitouch_update_pointer(MTES_DEVICE, tracking_id, x, y, pressure);
152 }
153
154 /* Pointer up event handler. */
155 static void
_on_action_pointer_up(int tracking_id)156 _on_action_pointer_up(int tracking_id)
157 {
158 multitouch_update_pointer(MTES_DEVICE, tracking_id, 0, 0, 0);
159 }
160
161 /* Pointer move event handler. */
162 static void
_on_action_move(int tracking_id,int x,int y,int pressure)163 _on_action_move(int tracking_id, int x, int y, int pressure)
164 {
165 multitouch_update_pointer(MTES_DEVICE, tracking_id, x, y, pressure);
166 }
167
168 /********************************************************************************
169 * Multi-touch event handlers
170 *******************************************************************************/
171
172 /* Handles "pointer move" event.
173 * Param:
174 * param - Array of moving pointers.
175 * pointers_count - Number of pointers in the array.
176 */
177 static void
_on_move(const AndroidMTEvent * param,int pointers_count)178 _on_move(const AndroidMTEvent* param, int pointers_count)
179 {
180 int n;
181 for (n = 0; n < pointers_count; n++, param++) {
182 T("Multi-touch: MOVE(%d): %d-> %d:%d:%d",
183 n, param->pid, param->x, param->y, param->pressure);
184 _on_action_move(param->pid, param->x, param->y, param->pressure);
185 }
186 }
187
188 /* Handles "first pointer down" event. */
189 static void
_on_down(const AndroidMTEvent * param)190 _on_down(const AndroidMTEvent* param)
191 {
192 T("Multi-touch: 1-ST DOWN: %d-> %d:%d:%d",
193 param->pid, param->x, param->y, param->pressure);
194 _on_action_down(param->pid, param->x, param->y, param->pressure);
195 }
196
197 /* Handles "last pointer up" event. */
198 static void
_on_up(const AndroidMTPtr * param)199 _on_up(const AndroidMTPtr* param)
200 {
201 T("Multi-touch: LAST UP: %d", param->pid);
202 _on_action_up(param->pid);
203 }
204
205 /* Handles "next pointer down" event. */
206 static void
_on_pdown(const AndroidMTEvent * param)207 _on_pdown(const AndroidMTEvent* param)
208 {
209 T("Multi-touch: DOWN: %d-> %d:%d:%d",
210 param->pid, param->x, param->y, param->pressure);
211 _on_action_pointer_down(param->pid, param->x, param->y, param->pressure);
212 }
213
214 /* Handles "next pointer up" event. */
215 static void
_on_pup(const AndroidMTPtr * param)216 _on_pup(const AndroidMTPtr* param)
217 {
218 T("Multi-touch: UP: %d", param->pid);
219 _on_action_pointer_up(param->pid);
220 }
221
222 /********************************************************************************
223 * Device communication callbacks
224 *******************************************************************************/
225
226 /* A callback that is invoked on SDK controller socket connection events. */
227 static AsyncIOAction
_on_multitouch_socket_connection(void * opaque,SDKCtlSocket * sdkctl,AsyncIOState status)228 _on_multitouch_socket_connection(void* opaque,
229 SDKCtlSocket* sdkctl,
230 AsyncIOState status)
231 {
232 if (status == ASIO_STATE_FAILED) {
233 /* Reconnect (after timeout delay) on failures */
234 if (sdkctl_socket_is_handshake_ok(sdkctl)) {
235 sdkctl_socket_reconnect(sdkctl, SDKCTL_DEFAULT_TCP_PORT,
236 SDKCTL_MT_TIMEOUT);
237 }
238 }
239 return ASIO_ACTION_DONE;
240 }
241
242 /* A callback that is invoked on SDK controller port connection events. */
243 static void
_on_multitouch_port_connection(void * opaque,SDKCtlSocket * sdkctl,SdkCtlPortStatus status)244 _on_multitouch_port_connection(void* opaque,
245 SDKCtlSocket* sdkctl,
246 SdkCtlPortStatus status)
247 {
248 switch (status) {
249 case SDKCTL_PORT_CONNECTED:
250 D("Multi-touch: SDK Controller is connected");
251 break;
252
253 case SDKCTL_PORT_DISCONNECTED:
254 D("Multi-touch: SDK Controller is disconnected");
255 // Disable OpenGLES framebuffer updates.
256 if (android_hw->hw_gpu_enabled) {
257 android_setPostCallback(NULL, NULL);
258 }
259 break;
260
261 case SDKCTL_PORT_ENABLED:
262 D("Multi-touch: SDK Controller port is enabled.");
263 // Enable OpenGLES framebuffer updates.
264 if (android_hw->hw_gpu_enabled) {
265 android_setPostCallback(multitouch_opengles_fb_update, NULL);
266 }
267 /* Refresh (possibly stale) device screen. */
268 multitouch_refresh_screen();
269 break;
270
271 case SDKCTL_PORT_DISABLED:
272 D("Multi-touch: SDK Controller port is disabled.");
273 // Disable OpenGLES framebuffer updates.
274 if (android_hw->hw_gpu_enabled) {
275 android_setPostCallback(NULL, NULL);
276 }
277 break;
278
279 case SDKCTL_HANDSHAKE_CONNECTED:
280 D("Multi-touch: Handshake succeeded with connected port.");
281 break;
282
283 case SDKCTL_HANDSHAKE_NO_PORT:
284 D("Multi-touch: Handshake succeeded with disconnected port.");
285 break;
286
287 case SDKCTL_HANDSHAKE_DUP:
288 W("Multi-touch: Handshake failed due to port duplication.");
289 sdkctl_socket_disconnect(sdkctl);
290 break;
291
292 case SDKCTL_HANDSHAKE_UNKNOWN_QUERY:
293 W("Multi-touch: Handshake failed due to unknown query.");
294 sdkctl_socket_disconnect(sdkctl);
295 break;
296
297 case SDKCTL_HANDSHAKE_UNKNOWN_RESPONSE:
298 default:
299 W("Multi-touch: Handshake failed due to unknown reason.");
300 sdkctl_socket_disconnect(sdkctl);
301 break;
302 }
303 }
304
305 /* A callback that is invoked when a message is received from the device. */
306 static void
_on_multitouch_message(void * client_opaque,SDKCtlSocket * sdkctl,SDKCtlMessage * message,int msg_type,void * msg_data,int msg_size)307 _on_multitouch_message(void* client_opaque,
308 SDKCtlSocket* sdkctl,
309 SDKCtlMessage* message,
310 int msg_type,
311 void* msg_data,
312 int msg_size)
313 {
314 switch (msg_type) {
315 case SDKCTL_MT_MOVE: {
316 assert((msg_size / sizeof(AndroidMTEvent)) && !(msg_size % sizeof(AndroidMTEvent)));
317 _on_move((const AndroidMTEvent*)msg_data, msg_size / sizeof(AndroidMTEvent));
318 break;
319 }
320
321 case SDKCTL_MT_FISRT_DOWN:
322 assert(msg_size / sizeof(AndroidMTEvent) && !(msg_size % sizeof(AndroidMTEvent)));
323 _on_down((const AndroidMTEvent*)msg_data);
324 break;
325
326 case SDKCTL_MT_LAST_UP:
327 _on_up((const AndroidMTPtr*)msg_data);
328 break;
329
330 case SDKCTL_MT_POINTER_DOWN:
331 assert(msg_size / sizeof(AndroidMTEvent) && !(msg_size % sizeof(AndroidMTEvent)));
332 _on_pdown((const AndroidMTEvent*)msg_data);
333 break;
334
335 case SDKCTL_MT_POINTER_UP:
336 _on_pup((const AndroidMTPtr*)msg_data);
337 break;
338
339 case SDKCTL_MT_FB_UPDATE_RECEIVED:
340 D("Framebuffer update ACK.");
341 break;
342
343 case SDKCTL_MT_FB_UPDATE_HANDLED:
344 D("Framebuffer update handled.");
345 multitouch_fb_updated();
346 break;
347
348 default:
349 W("Multi-touch: Unknown message %d", msg_type);
350 break;
351 }
352 }
353
354 /********************************************************************************
355 * MTS port API
356 *******************************************************************************/
357
358 AndroidMTSPort*
mts_port_create(void * opaque)359 mts_port_create(void* opaque)
360 {
361 AndroidMTSPort* mtsp;
362
363 ANEW0(mtsp);
364 mtsp->opaque = opaque;
365
366 /* Initialize default MTS descriptor. */
367 multitouch_init(mtsp);
368
369 /* Create JPEG compressor. Put message header + MTFrameHeader in front of the
370 * compressed data. this way we will have entire query ready to be
371 * transmitted to the device. */
372 mtsp->jpeg_compressor =
373 jpeg_compressor_create(sdkctl_message_get_header_size() + sizeof(MTFrameHeader), 4096);
374
375 mtsp->sdkctl = sdkctl_socket_new(SDKCTL_MT_TIMEOUT, "multi-touch",
376 _on_multitouch_socket_connection,
377 _on_multitouch_port_connection,
378 _on_multitouch_message, mtsp);
379 sdkctl_init_recycler(mtsp->sdkctl, 64, 8);
380
381 /* Create a direct packet that will wrap up framebuffer updates. Note that
382 * we need to do this after we have initialized the recycler! */
383 mtsp->fb_packet = sdkctl_direct_packet_new(mtsp->sdkctl);
384
385 /* Now we can initiate connection witm MT port on the device. */
386 sdkctl_socket_connect(mtsp->sdkctl, SDKCTL_DEFAULT_TCP_PORT,
387 SDKCTL_MT_TIMEOUT);
388
389 return mtsp;
390 }
391
392 void
mts_port_destroy(AndroidMTSPort * mtsp)393 mts_port_destroy(AndroidMTSPort* mtsp)
394 {
395 _mts_port_free(mtsp);
396 }
397
398 /********************************************************************************
399 * Handling framebuffer updates
400 *******************************************************************************/
401
402 /* Compresses a framebuffer region into JPEG image.
403 * Param:
404 * mtsp - Multi-touch port descriptor with initialized JPEG compressor.
405 * fmt Descriptor for framebuffer region to compress.
406 * fb Beginning of the framebuffer.
407 * jpeg_quality JPEG compression quality. A number from 1 to 100. Note that
408 * value 10 provides pretty decent image for the purpose of multi-touch
409 * emulation.
410 */
411 static void
_fb_compress(const AndroidMTSPort * mtsp,const MTFrameHeader * fmt,const uint8_t * fb,int jpeg_quality,int ydir)412 _fb_compress(const AndroidMTSPort* mtsp,
413 const MTFrameHeader* fmt,
414 const uint8_t* fb,
415 int jpeg_quality,
416 int ydir)
417 {
418 T("Multi-touch: compressing %d bytes frame buffer", fmt->w * fmt->h * fmt->bpp);
419
420 jpeg_compressor_compress_fb(mtsp->jpeg_compressor, fmt->x, fmt->y, fmt->w,
421 fmt->h, fmt->disp_height, fmt->bpp, fmt->bpl,
422 fb, jpeg_quality, ydir);
423 }
424
425 int
mts_port_send_frame(AndroidMTSPort * mtsp,MTFrameHeader * fmt,const uint8_t * fb,on_sdkctl_direct_cb cb,void * cb_opaque,int ydir)426 mts_port_send_frame(AndroidMTSPort* mtsp,
427 MTFrameHeader* fmt,
428 const uint8_t* fb,
429 on_sdkctl_direct_cb cb,
430 void* cb_opaque,
431 int ydir)
432 {
433 /* Make sure that port is connected. */
434 if (!sdkctl_socket_is_port_ready(mtsp->sdkctl)) {
435 return -1;
436 }
437
438 /* Compress framebuffer region. 10% quality seems to be sufficient. */
439 fmt->format = MTFB_JPEG;
440 _fb_compress(mtsp, fmt, fb, 10, ydir);
441
442 /* Total size of the update data: header + JPEG image. */
443 const int update_size =
444 sizeof(MTFrameHeader) + jpeg_compressor_get_jpeg_size(mtsp->jpeg_compressor);
445
446 /* Update message starts at the beginning of the buffer allocated by the
447 * compressor's destination manager. */
448 uint8_t* const msg = (uint8_t*)jpeg_compressor_get_buffer(mtsp->jpeg_compressor);
449
450 /* Initialize message header. */
451 sdkctl_init_message_header(msg, SDKCTL_MT_FB_UPDATE, update_size);
452
453 /* Copy framebuffer update header to the message. */
454 memcpy(msg + sdkctl_message_get_header_size(), fmt, sizeof(MTFrameHeader));
455
456 /* Compression rate... */
457 const float comp_rate = ((float)jpeg_compressor_get_jpeg_size(mtsp->jpeg_compressor) / (fmt->w * fmt->h * fmt->bpp)) * 100;
458
459 /* Zeroing the rectangle in the update header we indicate that it contains
460 * no updates. */
461 fmt->x = fmt->y = fmt->w = fmt->h = 0;
462
463 /* Send update to the device. */
464 sdkctl_direct_packet_send(mtsp->fb_packet, msg, cb, cb_opaque);
465
466 T("Multi-touch: Sent %d bytes in framebuffer update. Compression rate is %.2f%%",
467 update_size, comp_rate);
468
469 return 0;
470 }
471