1 | /* |
2 | Copyright (c) 2012-2014, Broadcom Europe Ltd |
3 | All rights reserved. |
4 | |
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the following conditions are met: |
7 | * Redistributions of source code must retain the above copyright |
8 | notice, this list of conditions and the following disclaimer. |
9 | * Redistributions in binary form must reproduce the above copyright |
10 | notice, this list of conditions and the following disclaimer in the |
11 | documentation and/or other materials provided with the distribution. |
12 | * Neither the name of the copyright holder nor the |
13 | names of its contributors may be used to endorse or promote products |
14 | derived from this software without specific prior written permission. |
15 | |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY |
20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ |
27 | #include <string.h> |
28 | #include <stdlib.h> |
29 | |
30 | #include "vchost_platform_config.h" |
31 | #include "vchost.h" |
32 | |
33 | #include "interface/vcos/vcos.h" |
34 | #include "vc_dispservice_x_defs.h" |
35 | #include "vc_dispmanx.h" |
36 | #include "interface/vchi/vchi.h" |
37 | #include "vcinclude/common.h" |
38 | #include "interface/vchi/common/endian.h" |
39 | #include "interface/vchi/message_drivers/message.h" |
40 | #include "vc_vchi_dispmanx.h" |
41 | /****************************************************************************** |
42 | Local types and defines. |
43 | ******************************************************************************/ |
44 | //DispmanX service |
45 | typedef struct { |
46 | VCHI_SERVICE_HANDLE_T client_handle[VCHI_MAX_NUM_CONNECTIONS]; //To connect to server on VC |
47 | VCHI_SERVICE_HANDLE_T notify_handle[VCHI_MAX_NUM_CONNECTIONS]; //For incoming notification |
48 | uint32_t msg_flag[VCHI_MAX_NUM_CONNECTIONS]; |
49 | char command_buffer[DISPMANX_MSGFIFO_SIZE]; |
50 | char response_buffer[DISPMANX_MSGFIFO_SIZE]; |
51 | uint32_t response_length; |
52 | uint32_t notify_buffer[DISPMANX_MSGFIFO_SIZE/sizeof(uint32_t)]; |
53 | uint32_t notify_length; |
54 | uint32_t num_connections; |
55 | VCOS_MUTEX_T lock; |
56 | char dispmanx_devices[DISPMANX_MAX_HOST_DEVICES][DISPMANX_MAX_DEVICE_NAME_LEN]; |
57 | uint32_t num_devices; |
58 | uint32_t num_modes[DISPMANX_MAX_HOST_DEVICES]; |
59 | |
60 | //Callback for update |
61 | DISPMANX_CALLBACK_FUNC_T update_callback; |
62 | void *update_callback_param; |
63 | DISPMANX_UPDATE_HANDLE_T pending_update_handle; |
64 | |
65 | //Callback for vsync |
66 | DISPMANX_CALLBACK_FUNC_T vsync_callback; |
67 | void *vsync_callback_param; |
68 | int vsync_enabled; |
69 | |
70 | int initialised; |
71 | } DISPMANX_SERVICE_T; |
72 | |
73 | /****************************************************************************** |
74 | Static data. |
75 | ******************************************************************************/ |
76 | static DISPMANX_SERVICE_T dispmanx_client; |
77 | static VCOS_EVENT_T dispmanx_message_available_event; |
78 | static VCOS_EVENT_T dispmanx_notify_available_event; |
79 | static VCOS_THREAD_T dispmanx_notify_task; |
80 | |
81 | /****************************************************************************** |
82 | Static functions. |
83 | ******************************************************************************/ |
84 | //Lock the host state |
85 | static __inline void lock_obtain (void) { |
86 | VCOS_STATUS_T status; |
87 | uint32_t i; |
88 | vcos_assert(dispmanx_client.initialised); |
89 | status = vcos_mutex_lock( &dispmanx_client.lock ); |
90 | if(dispmanx_client.initialised) |
91 | { |
92 | for (i=0; i<dispmanx_client.num_connections; i++) { |
93 | vchi_service_use(dispmanx_client.client_handle[i]); |
94 | } |
95 | } |
96 | vcos_assert(status == VCOS_SUCCESS); |
97 | } |
98 | |
99 | //Unlock the host state |
100 | static __inline void lock_release (void) { |
101 | uint32_t i; |
102 | vcos_assert(dispmanx_client.initialised); |
103 | if(dispmanx_client.initialised) |
104 | { |
105 | for (i=0; i<dispmanx_client.num_connections; i++) { |
106 | vchi_service_release(dispmanx_client.client_handle[i]); |
107 | } |
108 | } |
109 | vcos_mutex_unlock( &dispmanx_client.lock ); |
110 | } |
111 | |
112 | //Forward declarations |
113 | static void dispmanx_client_callback( void *callback_param, |
114 | VCHI_CALLBACK_REASON_T reason, |
115 | void *msg_handle ); |
116 | |
117 | static void dispmanx_notify_callback( void *callback_param, |
118 | VCHI_CALLBACK_REASON_T reason, |
119 | void *msg_handle ); |
120 | |
121 | static int32_t dispmanx_wait_for_reply(void *response, uint32_t max_length); |
122 | |
123 | static int32_t dispmanx_send_command( uint32_t command, void *buffer, uint32_t length); |
124 | |
125 | static int32_t dispmanx_send_command_reply( uint32_t command, void *buffer, uint32_t length, |
126 | void *response, uint32_t max_length); |
127 | |
128 | static uint32_t dispmanx_get_handle( uint32_t command, void *buffer, uint32_t length); |
129 | |
130 | static void *dispmanx_notify_func( void *arg ); |
131 | |
132 | |
133 | /****************************************************************************** |
134 | NAME |
135 | vc_vchi_gencmd_init |
136 | |
137 | SYNOPSIS |
138 | void vc_vchi_gencmd_init(VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections ) |
139 | |
140 | FUNCTION |
141 | Initialise the general command service for use. A negative return value |
142 | indicates failure (which may mean it has not been started on VideoCore). |
143 | |
144 | RETURNS |
145 | int |
146 | ******************************************************************************/ |
147 | |
148 | void vc_vchi_dispmanx_init (VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections ) { |
149 | VCOS_STATUS_T status; |
150 | int32_t success; |
151 | uint32_t i; |
152 | |
153 | if (dispmanx_client.initialised) |
154 | return; |
155 | |
156 | // record the number of connections |
157 | memset( &dispmanx_client, 0, sizeof(DISPMANX_SERVICE_T) ); |
158 | dispmanx_client.num_connections = num_connections; |
159 | |
160 | status = vcos_mutex_create(&dispmanx_client.lock, "HDispmanx" ); |
161 | vcos_assert(status == VCOS_SUCCESS); |
162 | |
163 | status = vcos_event_create(&dispmanx_message_available_event, "HDispmanx" ); |
164 | vcos_assert(status == VCOS_SUCCESS); |
165 | |
166 | status = vcos_event_create(&dispmanx_notify_available_event, "HDispmanx" ); |
167 | vcos_assert(status == VCOS_SUCCESS); |
168 | |
169 | dispmanx_client.initialised = 1; |
170 | |
171 | for (i=0; i<dispmanx_client.num_connections; i++) { |
172 | |
173 | VCOS_THREAD_ATTR_T attrs; |
174 | |
175 | // Create a 'Client' service on the each of the connections |
176 | SERVICE_CREATION_T dispmanx_parameters = { VCHI_VERSION(VC_DISPMANX_VERSION), |
177 | DISPMANX_CLIENT_NAME, // 4cc service code |
178 | connections[i], // passed in fn ptrs |
179 | 0, // tx fifo size (unused) |
180 | 0, // tx fifo size (unused) |
181 | &dispmanx_client_callback, // service callback |
182 | &dispmanx_message_available_event, // callback parameter |
183 | VC_FALSE, // want_unaligned_bulk_rx |
184 | VC_FALSE, // want_unaligned_bulk_tx |
185 | VC_FALSE, // want_crc |
186 | }; |
187 | |
188 | SERVICE_CREATION_T dispmanx_parameters2 = { VCHI_VERSION(VC_DISPMANX_VERSION), |
189 | DISPMANX_NOTIFY_NAME, // 4cc service code |
190 | connections[i], // passed in fn ptrs |
191 | 0, // tx fifo size (unused) |
192 | 0, // tx fifo size (unused) |
193 | &dispmanx_notify_callback, // service callback |
194 | &dispmanx_notify_available_event, // callback parameter |
195 | VC_FALSE, // want_unaligned_bulk_rx |
196 | VC_FALSE, // want_unaligned_bulk_tx |
197 | VC_FALSE, // want_crc |
198 | }; |
199 | |
200 | success = vchi_service_open( initialise_instance, &dispmanx_parameters, &dispmanx_client.client_handle[i] ); |
201 | vcos_assert( success == 0 ); |
202 | |
203 | // Create the async service of dispman to handle update callback |
204 | |
205 | success = vchi_service_open( initialise_instance, &dispmanx_parameters2, &dispmanx_client.notify_handle[i] ); |
206 | vcos_assert( success == 0 ); |
207 | |
208 | //Create the notifier task |
209 | vcos_thread_attr_init(&attrs); |
210 | vcos_thread_attr_setstacksize(&attrs, 2048); |
211 | vcos_thread_attr_settimeslice(&attrs, 1); |
212 | |
213 | status = vcos_thread_create(&dispmanx_notify_task, "HDispmanx Notify" , &attrs, dispmanx_notify_func, NULL); |
214 | vcos_assert(status == VCOS_SUCCESS); |
215 | |
216 | // release services until they're actually used |
217 | vchi_service_release(dispmanx_client.client_handle[i]); |
218 | vchi_service_release(dispmanx_client.notify_handle[i]); |
219 | } |
220 | } |
221 | |
222 | /*********************************************************** |
223 | * Name: vc_dispmanx_stop |
224 | * |
225 | * Arguments: |
226 | * - |
227 | * |
228 | * Description: Stops the Host side part of dispmanx |
229 | * |
230 | * Returns: - |
231 | * |
232 | ***********************************************************/ |
233 | VCHPRE_ void VCHPOST_ vc_dispmanx_stop( void ) { |
234 | // Wait for the current lock-holder to finish before zapping dispmanx. |
235 | //TODO: kill the notifier task |
236 | void *dummy; |
237 | uint32_t i; |
238 | |
239 | if (!dispmanx_client.initialised) |
240 | return; |
241 | |
242 | lock_obtain(); |
243 | for (i=0; i<dispmanx_client.num_connections; i++) { |
244 | int32_t result; |
245 | result = vchi_service_close(dispmanx_client.client_handle[i]); |
246 | vcos_assert( result == 0 ); |
247 | result = vchi_service_close(dispmanx_client.notify_handle[i]); |
248 | vcos_assert( result == 0 ); |
249 | } |
250 | lock_release(); |
251 | dispmanx_client.initialised = 0; |
252 | |
253 | vcos_event_signal(&dispmanx_notify_available_event); |
254 | vcos_thread_join(&dispmanx_notify_task, &dummy); |
255 | vcos_mutex_delete(&dispmanx_client.lock); |
256 | vcos_event_delete(&dispmanx_message_available_event); |
257 | vcos_event_delete(&dispmanx_notify_available_event); |
258 | } |
259 | |
260 | /*********************************************************** |
261 | * Name: vc_dispmanx_rect_set |
262 | * |
263 | * Arguments: |
264 | * VC_RECT_T *rect |
265 | * uint32_t x_offset |
266 | * uint32_t y_offset |
267 | * uint32_t width |
268 | * uint32_t height |
269 | * |
270 | * Description: Fills in the fields of the supplied VC_RECT_T structure |
271 | * |
272 | * Returns: 0 or failure |
273 | * |
274 | ***********************************************************/ |
275 | VCHPRE_ int VCHPOST_ vc_dispmanx_rect_set( VC_RECT_T *rect, uint32_t x_offset, uint32_t y_offset, uint32_t width, uint32_t height ) { |
276 | rect->x = (int32_t) x_offset; |
277 | rect->y = (int32_t) y_offset; |
278 | rect->width = (int32_t) width; |
279 | rect->height = (int32_t) height; |
280 | return 0; |
281 | } |
282 | |
283 | /****************************************************************************** |
284 | NAME |
285 | vc_dispmanx_query_image_formats |
286 | |
287 | PARAMS |
288 | uint32_t *support_formats - the returned supported image formats |
289 | |
290 | FUNCTION |
291 | Returns the support image formats from the VMCS host |
292 | |
293 | RETURNS |
294 | Success: 0 |
295 | Otherwise non-zero |
296 | ******************************************************************************/ |
297 | VCHPRE_ int VCHPOST_ vc_dispmanx_query_image_formats( uint32_t *supported_formats ) { |
298 | *supported_formats = dispmanx_get_handle(EDispmanQueryImageFormats, NULL, 0); |
299 | return (*supported_formats)? 0 : -1; |
300 | } |
301 | |
302 | /*********************************************************** |
303 | * Name: vc_dispmanx_resource_create |
304 | * |
305 | * Arguments: |
306 | * VC_IMAGE_TYPE_T type |
307 | * uint32_t width |
308 | * uint32_t height |
309 | * |
310 | * Description: Create a new resource (in Videocore memory) |
311 | * |
312 | * Returns: resource handle |
313 | * |
314 | ***********************************************************/ |
315 | VCHPRE_ DISPMANX_RESOURCE_HANDLE_T VCHPOST_ vc_dispmanx_resource_create( VC_IMAGE_TYPE_T type, uint32_t width, uint32_t height, uint32_t *native_image_handle ) { |
316 | uint32_t resourceCreateParams[] = { (uint32_t)VC_HTOV32(type), VC_HTOV32(width), VC_HTOV32(height) }; |
317 | |
318 | uint32_t resource = 0; |
319 | |
320 | resource = dispmanx_get_handle(EDispmanResourceCreate, resourceCreateParams, sizeof(resourceCreateParams)); |
321 | |
322 | //We don't get an image handle back, so explicitly set this to zero to let the caller know |
323 | *native_image_handle = 0; |
324 | //The caller should call vc_dispmanx_resource_get_image_handle below to get the VC_IMAGE_T * |
325 | //This will be deprecated soon, however |
326 | |
327 | return (DISPMANX_RESOURCE_HANDLE_T) resource; |
328 | } |
329 | |
330 | /*********************************************************** |
331 | * Name: vc_dispmanx_resource_get_image_handle |
332 | * |
333 | * Arguments: resource handle |
334 | * |
335 | * Description: xxx only for hacking purpose, will be obsolete soon |
336 | * |
337 | * Returns: vc_image pointer |
338 | * |
339 | ***********************************************************/ |
340 | VCHPRE_ uint32_t VCHPOST_ vc_dispmanx_resource_get_image_handle( DISPMANX_RESOURCE_HANDLE_T res) { |
341 | return dispmanx_get_handle(EDispmanResourceGetImage, &res, sizeof(res)); |
342 | } |
343 | |
344 | /*********************************************************** |
345 | * Name: vc_dispmanx_resource_delete |
346 | * |
347 | * Arguments: |
348 | * DISPMANX_RESOURCE_HANDLE_T res |
349 | * |
350 | * Description: |
351 | * |
352 | * Returns: 0 or failure |
353 | * |
354 | ***********************************************************/ |
355 | VCHPRE_ int VCHPOST_ vc_dispmanx_resource_delete( DISPMANX_RESOURCE_HANDLE_T res ) { |
356 | int status; |
357 | res = VC_HTOV32(res); |
358 | //We block to make sure the memory is freed after the call |
359 | status = (int) dispmanx_send_command(EDispmanResourceDelete, &res, sizeof(res)); |
360 | |
361 | return status; |
362 | } |
363 | |
364 | /*********************************************************** |
365 | * Name: vc_dispmanx_resource_write_data |
366 | * |
367 | * Arguments: |
368 | * DISPMANX_RESOURCE_HANDLE_T res |
369 | * int src_pitch |
370 | * void * src_address |
371 | * const VC_RECT_T * rect |
372 | * |
373 | * Description: Copy the bitmap data to VideoCore memory |
374 | * |
375 | * Returns: 0 or failure |
376 | * |
377 | ***********************************************************/ |
378 | VCHPRE_ int VCHPOST_ vc_dispmanx_resource_write_data( DISPMANX_RESOURCE_HANDLE_T handle, VC_IMAGE_TYPE_T src_type /* not used */, |
379 | int src_pitch, void * src_address, const VC_RECT_T * rect ) { |
380 | (void)src_type; |
381 | |
382 | //Note that x coordinate of the rect is NOT used |
383 | //Address of data in host |
384 | uint8_t *host_start = (uint8_t *)src_address + src_pitch * rect->y; |
385 | int32_t bulk_len = src_pitch * rect->height, success = 0; |
386 | |
387 | //Now send the bulk transfer across |
388 | //command parameters: resource handle, destination y, bulk length |
389 | uint32_t param[] = {VC_HTOV32(handle), VC_HTOV32(rect->y), VC_HTOV32(bulk_len), VC_HTOV32(src_type) }; |
390 | success = dispmanx_send_command( EDispmanBulkWrite | DISPMANX_NO_REPLY_MASK, param, sizeof(param)); |
391 | if(success == 0) |
392 | { |
393 | lock_obtain(); |
394 | success = vchi_bulk_queue_transmit( dispmanx_client.client_handle[0], |
395 | host_start, |
396 | bulk_len, |
397 | VCHI_FLAGS_BLOCK_UNTIL_DATA_READ, |
398 | NULL ); |
399 | lock_release(); |
400 | } |
401 | return (int) success; |
402 | } |
403 | /*********************************************************** |
404 | * Name: vc_dispmanx_resource_read_data |
405 | * |
406 | * Arguments: |
407 | * DISPMANX_RESOURCE_HANDLE_T res |
408 | * int src_pitch |
409 | * void * src_address |
410 | * const VC_RECT_T * rect |
411 | * |
412 | * Description: Copy the bitmap data from VideoCore memory |
413 | * |
414 | * Returns: 0 or failure |
415 | * |
416 | ***********************************************************/ |
417 | VCHPRE_ int VCHPOST_ |
418 | vc_dispmanx_resource_read_data( |
419 | DISPMANX_RESOURCE_HANDLE_T handle, |
420 | const VC_RECT_T* p_rect, |
421 | void * dst_address, |
422 | uint32_t dst_pitch ) |
423 | { |
424 | uint8_t* host_start; |
425 | int32_t bulk_len; |
426 | int32_t success = 0; |
427 | |
428 | if ( p_rect == 0 || dst_address == 0 || dst_pitch == 0 ) |
429 | { |
430 | return -1; |
431 | } |
432 | |
433 | host_start = (uint8_t *)dst_address + (dst_pitch * p_rect->y); |
434 | bulk_len = (int32_t)dst_pitch * p_rect->height; |
435 | |
436 | // Now send the bulk transfer across |
437 | // command parameters: resource handle, destination y, bulk length |
438 | uint32_t param[] = { VC_HTOV32(handle), VC_HTOV32(p_rect->y), VC_HTOV32(bulk_len) }; |
439 | success = dispmanx_send_command( EDispmanBulkRead | DISPMANX_NO_REPLY_MASK, param, sizeof(param)); |
440 | if (success == 0) |
441 | { |
442 | lock_obtain(); |
443 | success = vchi_bulk_queue_receive( dispmanx_client.client_handle[0], |
444 | host_start, |
445 | bulk_len, |
446 | VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE, |
447 | 0 ); |
448 | lock_release(); |
449 | } |
450 | return (int) success; |
451 | } |
452 | |
453 | /*********************************************************** |
454 | * Name: vc_dispmanx_resource_write_data_handle |
455 | * |
456 | * Arguments: |
457 | * DISPMANX_RESOURCE_HANDLE_T res |
458 | * int src_pitch |
459 | * MEM_HANDLE_T handle |
460 | * uint32_t offset |
461 | * const VC_RECT_T * rect |
462 | * |
463 | * Description: Copy the bitmap data to VideoCore memory |
464 | * |
465 | * Returns: 0 or failure |
466 | * |
467 | ***********************************************************/ |
468 | #ifdef SELF_HOSTED |
469 | VCHPRE_ int VCHPOST_ vc_dispmanx_resource_write_data_handle( DISPMANX_RESOURCE_HANDLE_T handle, VC_IMAGE_TYPE_T src_type /* not used */, |
470 | int src_pitch, VCHI_MEM_HANDLE_T mem_handle, uint32_t offset, |
471 | const VC_RECT_T * rect ) { |
472 | int32_t bulk_len; |
473 | uint32_t param[3]; |
474 | uint32_t success = 0; |
475 | |
476 | //Note that x coordinate of the rect is NOT used |
477 | //Address of data in host |
478 | offset += src_pitch * rect->y; |
479 | bulk_len = src_pitch * rect->height; |
480 | |
481 | //Now send the bulk transfer across |
482 | //command parameters: resource handle, destination y, bulk length |
483 | param[0] = VC_HTOV32(handle); |
484 | param[1] = VC_HTOV32(rect->y); |
485 | param[2] = VC_HTOV32(bulk_len); |
486 | success = dispmanx_send_command( EDispmanBulkWrite | DISPMANX_NO_REPLY_MASK, param, sizeof(param)); |
487 | if(success == 0) |
488 | { |
489 | lock_obtain(); |
490 | success = vchi_bulk_queue_transmit_reloc( dispmanx_client.client_handle[0], |
491 | mem_handle, offset, |
492 | bulk_len, |
493 | VCHI_FLAGS_BLOCK_UNTIL_DATA_READ, |
494 | NULL ); |
495 | lock_release(); |
496 | } |
497 | return (int) success; |
498 | } |
499 | #endif |
500 | |
501 | /*********************************************************** |
502 | * Name: vc_dispmanx_display_open |
503 | * |
504 | * Arguments: |
505 | * uint32_t device |
506 | * |
507 | * Description: |
508 | * |
509 | * Returns: |
510 | * |
511 | ***********************************************************/ |
512 | VCHPRE_ DISPMANX_DISPLAY_HANDLE_T VCHPOST_ vc_dispmanx_display_open( uint32_t device ) { |
513 | uint32_t display_handle; |
514 | char *env = getenv("VC_DISPLAY" ); |
515 | |
516 | if (device == 0 && env) |
517 | { |
518 | device = atoi(env); |
519 | } |
520 | |
521 | device = VC_HTOV32(device); |
522 | display_handle = dispmanx_get_handle(EDispmanDisplayOpen, |
523 | &device, sizeof(device)); |
524 | |
525 | return (DISPMANX_DISPLAY_HANDLE_T) display_handle; |
526 | } |
527 | |
528 | /*********************************************************** |
529 | * Name: vc_dispmanx_display_open_mode |
530 | * |
531 | * Arguments: |
532 | * uint32_t device |
533 | * uint32_t mode |
534 | * |
535 | * Description: |
536 | * |
537 | * Returns: |
538 | * |
539 | ***********************************************************/ |
540 | VCHPRE_ DISPMANX_DISPLAY_HANDLE_T VCHPOST_ vc_dispmanx_display_open_mode( uint32_t device, uint32_t mode ) { |
541 | uint32_t display_open_param[] = {VC_HTOV32(device), VC_HTOV32(mode)}; |
542 | uint32_t display_handle = dispmanx_get_handle(EDispmanDisplayOpenMode, |
543 | &display_open_param, sizeof(display_open_param)); |
544 | |
545 | return (DISPMANX_DISPLAY_HANDLE_T) display_handle; |
546 | } |
547 | |
548 | /*********************************************************** |
549 | * Name: vc_dispmanx_display_open_offscreen |
550 | * |
551 | * Arguments: |
552 | * DISPMANX_RESOURCE_HANDLE_T dest |
553 | * DISPMANX_TRANSFORM_T orientation |
554 | * |
555 | * Description: |
556 | * |
557 | * Returns: |
558 | * |
559 | ***********************************************************/ |
560 | VCHPRE_ DISPMANX_DISPLAY_HANDLE_T VCHPOST_ vc_dispmanx_display_open_offscreen( DISPMANX_RESOURCE_HANDLE_T dest, DISPMANX_TRANSFORM_T orientation ) { |
561 | uint32_t display_open_param[] = {(uint32_t)VC_HTOV32(dest), (uint32_t)VC_HTOV32(orientation)}; |
562 | uint32_t display_handle = dispmanx_get_handle(EDispmanDisplayOpenOffscreen, |
563 | &display_open_param, sizeof(display_open_param)); |
564 | |
565 | return (DISPMANX_DISPLAY_HANDLE_T) display_handle; |
566 | } |
567 | |
568 | /*********************************************************** |
569 | * Name: vc_dispmanx_display_reconfigure |
570 | * |
571 | * Arguments: |
572 | * DISPMANX_DISPLAY_HANDLE_T display |
573 | * uint32_t mode |
574 | * |
575 | * Description: |
576 | * |
577 | * Returns: |
578 | * |
579 | ***********************************************************/ |
580 | VCHPRE_ int VCHPOST_ vc_dispmanx_display_reconfigure( DISPMANX_DISPLAY_HANDLE_T device, uint32_t mode ) { |
581 | uint32_t display_param[] = {(uint32_t)VC_HTOV32(device), VC_HTOV32(mode)}; |
582 | int32_t success = dispmanx_send_command( EDispmanDisplayReconfigure | DISPMANX_NO_REPLY_MASK, |
583 | display_param, sizeof(display_param)); |
584 | return (int) success; |
585 | } |
586 | |
587 | /*********************************************************** |
588 | * Name: vc_dispmanx_display_set_destination |
589 | * |
590 | * Arguments: |
591 | * DISPMANX_DISPLAY_HANDLE_T display |
592 | * DISPMANX_RESOURCE_HANDLE_T dest |
593 | * |
594 | * Description: |
595 | * |
596 | * Returns: |
597 | * |
598 | ***********************************************************/ |
599 | VCHPRE_ int VCHPOST_ vc_dispmanx_display_set_destination( DISPMANX_DISPLAY_HANDLE_T display, DISPMANX_RESOURCE_HANDLE_T dest ) { |
600 | uint32_t display_param[] = {(uint32_t)VC_HTOV32(display), (uint32_t)VC_HTOV32(dest)}; |
601 | int32_t success = dispmanx_send_command( EDispmanDisplaySetDestination | DISPMANX_NO_REPLY_MASK, |
602 | display_param, sizeof(display_param)); |
603 | return (int) success; |
604 | } |
605 | |
606 | /*********************************************************** |
607 | * Name: vc_dispmanx_display_set_background |
608 | * |
609 | * Arguments: |
610 | * DISPMANX_UPDATE_HANDLE_T update |
611 | * DISPMANX_DISPLAY_HANDLE_T display |
612 | * uint8_t red |
613 | * uint8_t green |
614 | * uint8_t blue |
615 | * |
616 | * Description: |
617 | * |
618 | * Returns: |
619 | * |
620 | ***********************************************************/ |
621 | VCHPRE_ int VCHPOST_ vc_dispmanx_display_set_background( DISPMANX_UPDATE_HANDLE_T update, DISPMANX_DISPLAY_HANDLE_T display, |
622 | uint8_t red, uint8_t green, uint8_t blue ) { |
623 | uint32_t display_param[] = {(uint32_t)VC_HTOV32(update), (uint32_t) VC_HTOV32(display), VC_HTOV32(red), VC_HTOV32(green), VC_HTOV32(blue)}; |
624 | int success = (int) dispmanx_send_command( EDispmanDisplaySetBackground | DISPMANX_NO_REPLY_MASK, |
625 | display_param, sizeof(display_param)); |
626 | return success; |
627 | } |
628 | |
629 | /*********************************************************** |
630 | * Name: vc_dispmanx_display_get_info |
631 | * |
632 | * Arguments: |
633 | * DISPMANX_DISPLAY_HANDLE_T display |
634 | * DISPMANX_MODEINFO_T * pinfo |
635 | * |
636 | * Description: |
637 | * |
638 | * Returns: VCHI error |
639 | * |
640 | ***********************************************************/ |
641 | VCHPRE_ int VCHPOST_ |
642 | vc_dispmanx_display_get_info (DISPMANX_DISPLAY_HANDLE_T display, |
643 | DISPMANX_MODEINFO_T *pinfo) |
644 | { |
645 | GET_INFO_DATA_T info; |
646 | int32_t success; |
647 | display = VC_HTOV32(display); |
648 | success = dispmanx_send_command_reply (EDispmanDisplayGetInfo, |
649 | &display, sizeof(display), |
650 | &info, sizeof(info)); |
651 | if(success == 0) { |
652 | pinfo->width = VC_VTOH32(info.width); |
653 | pinfo->height = VC_VTOH32(info.height); |
654 | pinfo->transform = (DISPMANX_TRANSFORM_T)VC_VTOH32(info.transform); |
655 | pinfo->input_format = (DISPLAY_INPUT_FORMAT_T)VC_VTOH32(info.input_format); |
656 | } |
657 | |
658 | return (int) success; |
659 | } |
660 | |
661 | /*********************************************************** |
662 | * Name: vc_dispmanx_display_close |
663 | * |
664 | * Arguments: |
665 | * DISPMANX_DISPLAY_HANDLE_T display |
666 | * |
667 | * Description: |
668 | * |
669 | * Returns: |
670 | * |
671 | ***********************************************************/ |
672 | VCHPRE_ int VCHPOST_ vc_dispmanx_display_close( DISPMANX_DISPLAY_HANDLE_T display ) { |
673 | int success; |
674 | display = VC_HTOV32(display); |
675 | success = (int) dispmanx_send_command( EDispmanDisplayClose | DISPMANX_NO_REPLY_MASK, |
676 | &display, sizeof(display)); |
677 | return success; |
678 | } |
679 | /*********************************************************** |
680 | * Name: vc_dispmanx_update_start |
681 | * |
682 | * Arguments: |
683 | * int32_t priority |
684 | * |
685 | * Description: |
686 | * |
687 | * Returns: |
688 | * |
689 | ***********************************************************/ |
690 | VCHPRE_ DISPMANX_UPDATE_HANDLE_T VCHPOST_ vc_dispmanx_update_start( int32_t priority ) { |
691 | uint32_t handle; |
692 | priority = VC_HTOV32(priority); |
693 | handle = dispmanx_get_handle(EDispmanUpdateStart, |
694 | &priority, sizeof(priority)); |
695 | |
696 | return (DISPMANX_UPDATE_HANDLE_T) handle; |
697 | } |
698 | |
699 | |
700 | /*********************************************************** |
701 | * Name: vc_dispmanx_update_submit |
702 | * |
703 | * Arguments: |
704 | * DISPMANX_UPDATE_HANDLE_T update |
705 | * DISPMANX_CALLBACK_FUNC_T cb_func |
706 | * void *cb_arg |
707 | * |
708 | * Description: |
709 | * |
710 | * Returns: |
711 | * |
712 | ***********************************************************/ |
713 | VCHPRE_ int VCHPOST_ vc_dispmanx_update_submit( DISPMANX_UPDATE_HANDLE_T update, DISPMANX_CALLBACK_FUNC_T cb_func, void *cb_arg ) { |
714 | uint32_t update_param[] = {(uint32_t) VC_HTOV32(update), (uint32_t) ((cb_func)? VC_HTOV32(1) : 0)}; |
715 | int success; |
716 | |
717 | vcos_assert(update); // handles must be non-zero |
718 | if (update) |
719 | { |
720 | //Set the callback |
721 | dispmanx_client.update_callback = cb_func; |
722 | dispmanx_client.update_callback_param = cb_arg; |
723 | dispmanx_client.pending_update_handle = update; |
724 | vchi_service_use(dispmanx_client.notify_handle[0]); // corresponding release is in dispmanx_notify_func |
725 | success = (int) dispmanx_send_command( EDispmanUpdateSubmit | DISPMANX_NO_REPLY_MASK, |
726 | update_param, sizeof(update_param)); |
727 | } |
728 | else |
729 | { |
730 | success = -1; |
731 | } |
732 | return success; |
733 | } |
734 | |
735 | /*********************************************************** |
736 | * Name: vc_dispmanx_update_submit_sync |
737 | * |
738 | * Arguments: |
739 | * DISPMANX_UPDATE_HANDLE_T update |
740 | * |
741 | * Description: |
742 | * |
743 | * Returns: VCHI error code |
744 | * |
745 | ***********************************************************/ |
746 | VCHPRE_ int VCHPOST_ vc_dispmanx_update_submit_sync( DISPMANX_UPDATE_HANDLE_T update ) { |
747 | int success; |
748 | update = VC_HTOV32(update); |
749 | success = (int) dispmanx_send_command( EDispmanUpdateSubmitSync, |
750 | &update, sizeof(update)); |
751 | return success; |
752 | } |
753 | |
754 | |
755 | /*********************************************************** |
756 | * Name: vc_dispmanx_element_add |
757 | * |
758 | * Arguments: |
759 | * DISPMANX_UPDATE_HANDLE_T update |
760 | * DISPMANX_DISPLAY_HANDLE_T display |
761 | * int32_t layer |
762 | * const VC_RECT_T *dest_rect |
763 | * DISPMANX_RESOURCE_HANDLE_T src |
764 | * const VC_RECT_T *src_rect |
765 | * DISPMANX_FLAGS_T flags |
766 | * uint8_t opacity |
767 | * DISPMANX_RESOURCE_HANDLE_T mask |
768 | * DISPMANX_TRANSFORM_T transform |
769 | * |
770 | * Description: |
771 | * |
772 | * Returns: VCHI error code |
773 | * |
774 | ***********************************************************/ |
775 | VCHPRE_ DISPMANX_ELEMENT_HANDLE_T VCHPOST_ vc_dispmanx_element_add ( DISPMANX_UPDATE_HANDLE_T update, |
776 | DISPMANX_DISPLAY_HANDLE_T display, |
777 | int32_t layer, |
778 | const VC_RECT_T *dest_rect, |
779 | DISPMANX_RESOURCE_HANDLE_T src, |
780 | const VC_RECT_T *src_rect, |
781 | DISPMANX_PROTECTION_T protection, |
782 | VC_DISPMANX_ALPHA_T *alpha, |
783 | DISPMANX_CLAMP_T *clamp, |
784 | DISPMANX_TRANSFORM_T transform ) { |
785 | |
786 | int32_t element_param[] = { |
787 | (int32_t) VC_HTOV32(update), |
788 | (int32_t) VC_HTOV32(display), |
789 | (int32_t) VC_HTOV32(layer), |
790 | (int32_t) VC_HTOV32(dest_rect->x), |
791 | (int32_t) VC_HTOV32(dest_rect->y), |
792 | (int32_t) VC_HTOV32(dest_rect->width), |
793 | (int32_t) VC_HTOV32(dest_rect->height), |
794 | (int32_t) VC_HTOV32(src), |
795 | (int32_t) VC_HTOV32(src_rect->x), |
796 | (int32_t) VC_HTOV32(src_rect->y), |
797 | (int32_t) VC_HTOV32(src_rect->width), |
798 | (int32_t) VC_HTOV32(src_rect->height), |
799 | (int32_t) VC_HTOV32(protection), |
800 | alpha ? (int32_t) VC_HTOV32(alpha->flags) : 0, |
801 | alpha ? (int32_t) VC_HTOV32(alpha->opacity) : 0, |
802 | alpha ? (int32_t) VC_HTOV32(alpha->mask) : 0, |
803 | clamp ? (int32_t) VC_HTOV32(clamp->mode) : 0, |
804 | clamp ? (int32_t) VC_HTOV32(clamp->key_mask) : 0, |
805 | clamp ? (int32_t) VC_HTOV32(clamp->key_value.yuv.yy_upper) : 0, |
806 | clamp ? (int32_t) VC_HTOV32(clamp->key_value.yuv.yy_lower) : 0, |
807 | clamp ? (int32_t) VC_HTOV32(clamp->key_value.yuv.cr_upper) : 0, |
808 | clamp ? (int32_t) VC_HTOV32(clamp->key_value.yuv.cr_lower) : 0, |
809 | clamp ? (int32_t) VC_HTOV32(clamp->key_value.yuv.cb_upper) : 0, |
810 | clamp ? (int32_t) VC_HTOV32(clamp->key_value.yuv.cb_lower) : 0, |
811 | clamp ? (int32_t) VC_HTOV32(clamp->replace_value) : 0, |
812 | (int32_t) VC_HTOV32(transform) |
813 | }; |
814 | |
815 | uint32_t handle = dispmanx_get_handle(EDispmanElementAdd, |
816 | element_param, sizeof(element_param)); |
817 | return (DISPMANX_ELEMENT_HANDLE_T) handle; |
818 | } |
819 | |
820 | /*********************************************************** |
821 | * Name: vc_dispmanx_element_change_source |
822 | * |
823 | * Arguments: |
824 | * DISPMANX_UPDATE_HANDLE_T update |
825 | * DISPMANX_ELEMENT_HANDLE_T element |
826 | * DISPMANX_RESOURCE_HANDLE_T src |
827 | * |
828 | * Description: |
829 | * |
830 | * Returns: VCHI error code |
831 | * |
832 | ***********************************************************/ |
833 | VCHPRE_ int VCHPOST_ vc_dispmanx_element_change_source( DISPMANX_UPDATE_HANDLE_T update, DISPMANX_ELEMENT_HANDLE_T element, |
834 | DISPMANX_RESOURCE_HANDLE_T src ) { |
835 | uint32_t element_param[] = { (uint32_t) VC_HTOV32(update), |
836 | (uint32_t) VC_HTOV32(element), |
837 | (uint32_t) VC_HTOV32(src) }; |
838 | |
839 | int success = (int) dispmanx_send_command( EDispmanElementChangeSource | DISPMANX_NO_REPLY_MASK, |
840 | element_param, sizeof(element_param)); |
841 | return success; |
842 | |
843 | } |
844 | |
845 | /*********************************************************** |
846 | * Name: vc_dispmanx_element_change_layer |
847 | * |
848 | * Arguments: |
849 | * DISPMANX_UPDATE_HANDLE_T update |
850 | * DISPMANX_ELEMENT_HANDLE_T element |
851 | * int32_t layer |
852 | * |
853 | * Description: |
854 | * |
855 | * Returns: VCHI error code |
856 | * |
857 | ***********************************************************/ |
858 | VCHPRE_ int VCHPOST_ vc_dispmanx_element_change_layer (DISPMANX_UPDATE_HANDLE_T update, |
859 | DISPMANX_ELEMENT_HANDLE_T element, |
860 | int32_t layer) |
861 | { |
862 | uint32_t element_param[] = { (uint32_t) VC_HTOV32(update), |
863 | (uint32_t) VC_HTOV32(element), |
864 | (uint32_t) VC_HTOV32(layer) }; |
865 | |
866 | int success = (int) dispmanx_send_command( EDispmanElementChangeLayer | DISPMANX_NO_REPLY_MASK, |
867 | element_param, sizeof(element_param)); |
868 | return success; |
869 | |
870 | } |
871 | |
872 | /*********************************************************** |
873 | * Name: vc_dispmanx_element_modified |
874 | * |
875 | * Arguments: |
876 | * DISPMANX_UPDATE_HANDLE_T update |
877 | * DISPMANX_ELEMENT_HANDLE_T element |
878 | * const VC_RECT_T * rect |
879 | * |
880 | * Description: |
881 | * |
882 | * Returns: VCHI error code |
883 | * |
884 | ***********************************************************/ |
885 | VCHPRE_ int VCHPOST_ vc_dispmanx_element_modified( DISPMANX_UPDATE_HANDLE_T update, DISPMANX_ELEMENT_HANDLE_T element, const VC_RECT_T * rect ) { |
886 | |
887 | uint32_t element_param[6] = { (uint32_t) VC_HTOV32(update), |
888 | (uint32_t) VC_HTOV32(element), 0, 0, 0, 0}; |
889 | uint32_t param_length = 2*sizeof(uint32_t); |
890 | int success; |
891 | |
892 | if(rect) { |
893 | element_param[2] = VC_HTOV32(rect->x); |
894 | element_param[3] = VC_HTOV32(rect->y); |
895 | element_param[4] = VC_HTOV32(rect->width); |
896 | element_param[5] = VC_HTOV32(rect->height); |
897 | param_length = 6*sizeof(uint32_t); |
898 | } |
899 | success = (int) dispmanx_send_command( EDispmanElementModified | DISPMANX_NO_REPLY_MASK, |
900 | element_param, param_length); |
901 | return success; |
902 | } |
903 | |
904 | /*********************************************************** |
905 | * Name: vc_dispmanx_element_remove |
906 | * |
907 | * Arguments: |
908 | * DISPMANX_UPDATE_HANDLE_T update |
909 | * DISPMANX_ELEMENT_HANDLE_T element |
910 | * |
911 | * Description: |
912 | * |
913 | * Returns: |
914 | * |
915 | ***********************************************************/ |
916 | VCHPRE_ int VCHPOST_ vc_dispmanx_element_remove( DISPMANX_UPDATE_HANDLE_T update, DISPMANX_ELEMENT_HANDLE_T element ) { |
917 | uint32_t element_param[] = {(uint32_t) VC_HTOV32(update), (uint32_t) VC_HTOV32(element)}; |
918 | int success = (int) dispmanx_send_command( EDispmanElementRemove | DISPMANX_NO_REPLY_MASK, |
919 | element_param, sizeof(element_param)); |
920 | return success; |
921 | } |
922 | |
923 | /*********************************************************** |
924 | * Name: vc_dispmanx_element_change_attributes |
925 | * |
926 | * Arguments: |
927 | * DISPMANX_UPDATE_HANDLE_T update |
928 | * DISPMANX_ELEMENT_HANDLE_T element |
929 | * uint32_t change flags (bit 0 layer, bit 1 opacity, bit 2 dest rect, bit 3 src rect, bit 4 mask, bit 5 transform |
930 | * uint32_t layer |
931 | * uint8_t opacity |
932 | * const VC_RECT_T *dest rect |
933 | * const VC_RECT_T *src rect |
934 | * DISPMANX_RESOURCE_HANDLE_T mask |
935 | * VC_DISPMAN_TRANSFORM_T transform |
936 | * |
937 | * Description: |
938 | * |
939 | * Returns: |
940 | * |
941 | ***********************************************************/ |
942 | VCHPRE_ int VCHPOST_ vc_dispmanx_element_change_attributes( DISPMANX_UPDATE_HANDLE_T update, |
943 | DISPMANX_ELEMENT_HANDLE_T element, |
944 | uint32_t change_flags, |
945 | int32_t layer, |
946 | uint8_t opacity, |
947 | const VC_RECT_T *dest_rect, |
948 | const VC_RECT_T *src_rect, |
949 | DISPMANX_RESOURCE_HANDLE_T mask, |
950 | DISPMANX_TRANSFORM_T transform ) { |
951 | |
952 | uint32_t element_param[15] = { (uint32_t) VC_HTOV32(update), |
953 | (uint32_t) VC_HTOV32(element), |
954 | VC_HTOV32(change_flags), |
955 | VC_HTOV32(layer), |
956 | VC_HTOV32(opacity), |
957 | (uint32_t) VC_HTOV32(mask), |
958 | (uint32_t) VC_HTOV32(transform), 0, 0, 0, 0, 0, 0, 0, 0}; |
959 | |
960 | uint32_t param_length = 7*sizeof(uint32_t); |
961 | int success; |
962 | if(dest_rect) { |
963 | element_param[7] = VC_HTOV32(dest_rect->x); |
964 | element_param[8] = VC_HTOV32(dest_rect->y); |
965 | element_param[9] = VC_HTOV32(dest_rect->width); |
966 | element_param[10] = VC_HTOV32(dest_rect->height); |
967 | element_param[2] |= ELEMENT_CHANGE_DEST_RECT; |
968 | param_length += 4*sizeof(uint32_t); |
969 | } |
970 | if(src_rect) { |
971 | element_param[11] = VC_HTOV32(src_rect->x); |
972 | element_param[12] = VC_HTOV32(src_rect->y); |
973 | element_param[13] = VC_HTOV32(src_rect->width); |
974 | element_param[14] = VC_HTOV32(src_rect->height); |
975 | element_param[2] |= ELEMENT_CHANGE_SRC_RECT; |
976 | param_length += 4*sizeof(uint32_t); |
977 | } |
978 | |
979 | |
980 | success = (int) dispmanx_send_command( EDispmanElementChangeAttributes | DISPMANX_NO_REPLY_MASK, |
981 | element_param, param_length); |
982 | return success; |
983 | } |
984 | |
985 | |
986 | /*********************************************************** |
987 | * Name: vc_dispmanx_snapshot |
988 | * |
989 | * Arguments: |
990 | * DISPMANX_DISPLAY_HANDLE_T display |
991 | * DISPMANX_RESOURCE_HANDLE_T snapshot_resource |
992 | * DISPMANX_TRANSFORM_T transform |
993 | * |
994 | * Description: Take a snapshot of a display in its current state |
995 | * |
996 | * Returns: |
997 | * |
998 | ***********************************************************/ |
999 | VCHPRE_ int VCHPOST_ vc_dispmanx_snapshot( DISPMANX_DISPLAY_HANDLE_T display, |
1000 | DISPMANX_RESOURCE_HANDLE_T snapshot_resource, |
1001 | DISPMANX_TRANSFORM_T transform ) |
1002 | { |
1003 | uint32_t display_snapshot_param[] = { |
1004 | VC_HTOV32(display), |
1005 | VC_HTOV32(snapshot_resource), |
1006 | VC_HTOV32(transform)}; |
1007 | |
1008 | int success = (int) dispmanx_send_command( EDispmanSnapshot, |
1009 | display_snapshot_param, |
1010 | sizeof(display_snapshot_param)); |
1011 | return success; |
1012 | } |
1013 | |
1014 | /*********************************************************** |
1015 | * Name: vc_dispmanx_resource_set_palette |
1016 | * |
1017 | * Arguments: |
1018 | * DISPMANX_RESOURCE_HANDLE_T res |
1019 | * void * src_address |
1020 | * int offset |
1021 | * int size |
1022 | * |
1023 | * Description: Set the resource palette (for VC_IMAGE_4BPP and VC_IMAGE_8BPP) |
1024 | * offset should be 0 |
1025 | * size is 16*2 for 4BPP and 256*2 for 8BPP |
1026 | * Returns: 0 or failure |
1027 | * |
1028 | ***********************************************************/ |
1029 | VCHPRE_ int VCHPOST_ vc_dispmanx_resource_set_palette( DISPMANX_RESOURCE_HANDLE_T handle, |
1030 | void * src_address, int offset, int size) { |
1031 | //Note that x coordinate of the rect is NOT used |
1032 | //Address of data in host |
1033 | uint8_t *host_start = src_address; |
1034 | int32_t bulk_len = size, success = 0; |
1035 | |
1036 | //Now send the bulk transfer across |
1037 | //command parameters: resource size |
1038 | uint32_t param[] = {VC_HTOV32(handle), VC_HTOV32(offset), VC_HTOV32(bulk_len) }; |
1039 | success = dispmanx_send_command( EDispmanSetPalette | DISPMANX_NO_REPLY_MASK, param, sizeof(param)); |
1040 | if(success == 0) |
1041 | { |
1042 | lock_obtain(); |
1043 | success = vchi_bulk_queue_transmit( dispmanx_client.client_handle[0], |
1044 | host_start, |
1045 | bulk_len, |
1046 | VCHI_FLAGS_BLOCK_UNTIL_DATA_READ, |
1047 | NULL ); |
1048 | lock_release(); |
1049 | } |
1050 | return (int) success; |
1051 | } |
1052 | |
1053 | |
1054 | /*********************************************************** |
1055 | * Name: vc_dispmanx_vsync_callback |
1056 | * |
1057 | * Arguments: |
1058 | * DISPMANX_DISPLAY_HANDLE_T display |
1059 | * DISPMANX_CALLBACK_FUNC_T cb_func |
1060 | * void *cb_arg |
1061 | * |
1062 | * Description: start sending callbacks on vsync events |
1063 | * Use a NULL cb_func to stop the callbacks |
1064 | * Returns: 0 or failure |
1065 | * |
1066 | ***********************************************************/ |
1067 | VCHPRE_ int VCHPOST_ vc_dispmanx_vsync_callback( DISPMANX_DISPLAY_HANDLE_T display, DISPMANX_CALLBACK_FUNC_T cb_func, void *cb_arg ) |
1068 | { |
1069 | // Steal the invalid 0 handle to indicate this is a vsync request |
1070 | DISPMANX_UPDATE_HANDLE_T update = 0; |
1071 | int enable = (cb_func != NULL); |
1072 | uint32_t update_param[] = {(uint32_t) VC_HTOV32(display), VC_HTOV32(update), (int32_t)enable}; |
1073 | int success; |
1074 | |
1075 | // Set the callback |
1076 | dispmanx_client.vsync_callback = cb_func; |
1077 | dispmanx_client.vsync_callback_param = cb_arg; |
1078 | |
1079 | if (!dispmanx_client.vsync_enabled && enable) { |
1080 | // An extra "use" is required while a vsync callback is registered. |
1081 | // The corresponding "release" is below. |
1082 | vchi_service_use(dispmanx_client.notify_handle[0]); |
1083 | } |
1084 | |
1085 | success = (int) dispmanx_send_command( EDispmanVsyncCallback | DISPMANX_NO_REPLY_MASK, |
1086 | update_param, sizeof(update_param)); |
1087 | |
1088 | if (dispmanx_client.vsync_enabled && !enable) { |
1089 | // The extra "use" added above is no longer required. |
1090 | vchi_service_release(dispmanx_client.notify_handle[0]); |
1091 | } |
1092 | |
1093 | dispmanx_client.vsync_enabled = enable; |
1094 | |
1095 | return (int) success; |
1096 | } |
1097 | |
1098 | |
1099 | /********************************************************************************* |
1100 | * |
1101 | * Static functions definitions |
1102 | * |
1103 | *********************************************************************************/ |
1104 | //TODO: Might need to handle multiple connections later |
1105 | /*********************************************************** |
1106 | * Name: dispmanx_client_callback |
1107 | * |
1108 | * Arguments: semaphore, callback reason and message handle |
1109 | * |
1110 | * Description: VCHI callback for the DISP service |
1111 | * |
1112 | ***********************************************************/ |
1113 | static void dispmanx_client_callback( void *callback_param, |
1114 | const VCHI_CALLBACK_REASON_T reason, |
1115 | void *msg_handle ) { |
1116 | |
1117 | (void)msg_handle; |
1118 | |
1119 | VCOS_EVENT_T *event = (VCOS_EVENT_T *)callback_param; |
1120 | |
1121 | if ( reason != VCHI_CALLBACK_MSG_AVAILABLE ) |
1122 | return; |
1123 | |
1124 | if ( event == NULL ) |
1125 | return; |
1126 | |
1127 | vcos_event_signal(event); |
1128 | } |
1129 | |
1130 | /*********************************************************** |
1131 | * Name: dispmanx_notify_callback |
1132 | * |
1133 | * Arguments: semaphore, callback reason and message handle |
1134 | * |
1135 | * Description: VCHI callback for the update callback |
1136 | * |
1137 | ***********************************************************/ |
1138 | |
1139 | static void dispmanx_notify_callback( void *callback_param, |
1140 | const VCHI_CALLBACK_REASON_T reason, |
1141 | void *msg_handle ) { |
1142 | VCOS_EVENT_T *event = (VCOS_EVENT_T *)callback_param; |
1143 | |
1144 | (void)msg_handle; |
1145 | |
1146 | if ( reason != VCHI_CALLBACK_MSG_AVAILABLE ) |
1147 | return; |
1148 | |
1149 | if ( event == NULL ) |
1150 | return; |
1151 | |
1152 | vcos_event_signal(event); |
1153 | } |
1154 | |
1155 | /*********************************************************** |
1156 | * Name: dispmanx_wait_for_reply |
1157 | * |
1158 | * Arguments: response buffer, buffer length |
1159 | * |
1160 | * Description: blocked until something is in the buffer |
1161 | * |
1162 | * Returns error code of vchi |
1163 | * |
1164 | ***********************************************************/ |
1165 | static int32_t dispmanx_wait_for_reply(void *response, uint32_t max_length) { |
1166 | int32_t success = 0; |
1167 | uint32_t length_read = 0; |
1168 | do { |
1169 | //TODO : we need to deal with messages coming through on more than one connections properly |
1170 | //At the moment it will always try to read the first connection if there is something there |
1171 | //Check if there is something in the queue, if so return immediately |
1172 | //otherwise wait for the semaphore and read again |
1173 | success = vchi_msg_dequeue( dispmanx_client.client_handle[0], response, max_length, &length_read, VCHI_FLAGS_NONE ); |
1174 | } while( length_read == 0 && vcos_event_wait(&dispmanx_message_available_event) == VCOS_SUCCESS ); |
1175 | |
1176 | return success; |
1177 | |
1178 | } |
1179 | /*********************************************************** |
1180 | * Name: dispmanx_send_command |
1181 | * |
1182 | * Arguments: command, parameter buffer, parameter legnth |
1183 | * |
1184 | * Description: send a command and wait for its response (int) |
1185 | * |
1186 | * Returns: response |
1187 | * |
1188 | ***********************************************************/ |
1189 | |
1190 | static int32_t dispmanx_send_command( uint32_t command, void *buffer, uint32_t length) { |
1191 | VCHI_MSG_VECTOR_T vector[] = { {&command, sizeof(command)}, |
1192 | {buffer, length} }; |
1193 | int32_t success = 0, response = -1; |
1194 | lock_obtain(); |
1195 | success = vchi_msg_queuev( dispmanx_client.client_handle[0], |
1196 | vector, sizeof(vector)/sizeof(vector[0]), |
1197 | VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL ); |
1198 | if(success == 0 && !(command & DISPMANX_NO_REPLY_MASK)) { |
1199 | //otherwise only wait for a reply if we ask for one |
1200 | success = dispmanx_wait_for_reply(&response, sizeof(response)); |
1201 | } else { |
1202 | //Not waiting for a reply, send the success code back instead |
1203 | response = success; |
1204 | } |
1205 | lock_release(); |
1206 | return VC_VTOH32(response); |
1207 | } |
1208 | |
1209 | int32_t vc_dispmanx_send_command (uint32_t command, void *buffer, |
1210 | uint32_t length) |
1211 | { |
1212 | return dispmanx_send_command (command, buffer, length); |
1213 | } |
1214 | |
1215 | /*********************************************************** |
1216 | * Name: dispmanx_send_command_reply |
1217 | * |
1218 | * Arguments: command, parameter buffer, parameter legnth, reply buffer, buffer length |
1219 | * |
1220 | * Description: send a command and wait for its response (in a buffer) |
1221 | * |
1222 | * Returns: error code |
1223 | * |
1224 | ***********************************************************/ |
1225 | |
1226 | static int32_t dispmanx_send_command_reply( uint32_t command, void *buffer, uint32_t length, |
1227 | void *response, uint32_t max_length) { |
1228 | VCHI_MSG_VECTOR_T vector[] = { {&command, sizeof(command)}, |
1229 | {buffer, length} }; |
1230 | |
1231 | int32_t success = 0; |
1232 | lock_obtain(); |
1233 | success = vchi_msg_queuev( dispmanx_client.client_handle[0], |
1234 | vector, sizeof(vector)/sizeof(vector[0]), |
1235 | VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL ); |
1236 | if(success == 0) |
1237 | success = dispmanx_wait_for_reply(response, max_length); |
1238 | |
1239 | lock_release(); |
1240 | |
1241 | return success; |
1242 | } |
1243 | |
1244 | int32_t vc_dispmanx_send_command_reply (uint32_t command, void *buffer, uint32_t length, |
1245 | void *response, uint32_t max_length) |
1246 | { |
1247 | return dispmanx_send_command_reply (command, buffer, length, response, max_length); |
1248 | } |
1249 | |
1250 | /*********************************************************** |
1251 | * Name: dispmanx_get_handle |
1252 | * |
1253 | * Arguments: command, parameter buffer, parameter legnth |
1254 | * |
1255 | * Description: same as dispmanx_send_command but returns uint instead |
1256 | * |
1257 | * Returns: handle |
1258 | * |
1259 | ***********************************************************/ |
1260 | static uint32_t dispmanx_get_handle( uint32_t command, void *buffer, uint32_t length) { |
1261 | VCHI_MSG_VECTOR_T vector[] = { {&command, sizeof(command)}, |
1262 | {buffer, length} }; |
1263 | uint32_t success = 0; |
1264 | uint32_t response = 0; |
1265 | lock_obtain(); |
1266 | success += vchi_msg_queuev( dispmanx_client.client_handle[0], |
1267 | vector, sizeof(vector)/sizeof(vector[0]), |
1268 | VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL ); |
1269 | if(success == 0) |
1270 | success = dispmanx_wait_for_reply(&response, sizeof(response)); |
1271 | |
1272 | lock_release(); |
1273 | return VC_VTOH32(response); |
1274 | } |
1275 | |
1276 | /*********************************************************** |
1277 | * Name: dispmanx_notify_handle |
1278 | * |
1279 | * Arguments: not used |
1280 | * |
1281 | * Description: this purely notifies the update callback |
1282 | * |
1283 | * Returns: does not return |
1284 | * |
1285 | ***********************************************************/ |
1286 | static void *dispmanx_notify_func( void *arg ) { |
1287 | int32_t success; |
1288 | VCOS_STATUS_T status; |
1289 | |
1290 | (void)arg; |
1291 | |
1292 | while (1) { |
1293 | DISPMANX_UPDATE_HANDLE_T handle; |
1294 | status = vcos_event_wait(&dispmanx_notify_available_event); |
1295 | if (status != VCOS_SUCCESS || !dispmanx_client.initialised) |
1296 | break; |
1297 | |
1298 | while (1) { |
1299 | success = vchi_msg_dequeue( dispmanx_client.notify_handle[0], dispmanx_client.notify_buffer, sizeof(dispmanx_client.notify_buffer), &dispmanx_client.notify_length, VCHI_FLAGS_NONE ); |
1300 | if (success != 0) |
1301 | break; |
1302 | |
1303 | handle = (DISPMANX_UPDATE_HANDLE_T)dispmanx_client.notify_buffer[0]; |
1304 | if (handle) { |
1305 | // This is the response to an update submit |
1306 | // Decrement the use count - the corresponding "use" is in vc_dispmanx_update_submit. |
1307 | vchi_service_release(dispmanx_client.notify_handle[0]); |
1308 | if (dispmanx_client.update_callback ) { |
1309 | vcos_assert( dispmanx_client.pending_update_handle == handle); |
1310 | dispmanx_client.update_callback(handle, dispmanx_client.update_callback_param); |
1311 | } |
1312 | } else { |
1313 | // This is a vsync notification |
1314 | if (dispmanx_client.vsync_callback ) { |
1315 | dispmanx_client.vsync_callback(handle, dispmanx_client.vsync_callback_param); |
1316 | } |
1317 | } |
1318 | } |
1319 | } |
1320 | return 0; |
1321 | } |
1322 | |