forked from Qortal/Brooklyn
529 lines
16 KiB
C
529 lines
16 KiB
C
/*
|
|
Copyright (c) 2012, Broadcom Europe Ltd
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
* Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
* Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
* Neither the name of the copyright holder nor the
|
|
names of its contributors may be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
#define VCOS_LOG_CATEGORY (&khrn_client_log)
|
|
|
|
#include "vchiq.h"
|
|
#include "interface/khronos/common/khrn_int_common.h"
|
|
#include "interface/khronos/common/khrn_int_ids.h"
|
|
|
|
#include "interface/khronos/common/khrn_client.h"
|
|
#include "interface/khronos/common/khrn_client_rpc.h"
|
|
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
extern VCOS_LOG_CAT_T khrn_client_log;
|
|
|
|
static void *workspace; /* for scatter/gather bulks */
|
|
static PLATFORM_MUTEX_T mutex;
|
|
|
|
#define FOURCC_KHAN VCHIQ_MAKE_FOURCC('K', 'H', 'A', 'N')
|
|
#define FOURCC_KHRN VCHIQ_MAKE_FOURCC('K', 'H', 'R', 'N')
|
|
#define FOURCC_KHHN VCHIQ_MAKE_FOURCC('K', 'H', 'H', 'N')
|
|
|
|
static VCHIQ_INSTANCE_T khrn_vchiq_instance;
|
|
|
|
static VCHIQ_SERVICE_HANDLE_T vchiq_khan_service;
|
|
static VCHIQ_SERVICE_HANDLE_T vchiq_khrn_service;
|
|
static VCHIQ_SERVICE_HANDLE_T vchiq_khhn_service;
|
|
|
|
static VCHIU_QUEUE_T khrn_queue;
|
|
static VCHIU_QUEUE_T khhn_queue;
|
|
|
|
static VCOS_EVENT_T bulk_event;
|
|
|
|
VCHIQ_STATUS_T khrn_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header,
|
|
VCHIQ_SERVICE_HANDLE_T handle, void *bulk_userdata)
|
|
{
|
|
switch (reason) {
|
|
case VCHIQ_MESSAGE_AVAILABLE:
|
|
vchiu_queue_push(&khrn_queue, header);
|
|
break;
|
|
case VCHIQ_BULK_TRANSMIT_DONE:
|
|
case VCHIQ_BULK_RECEIVE_DONE:
|
|
vcos_event_signal(&bulk_event);
|
|
break;
|
|
case VCHIQ_SERVICE_OPENED:
|
|
case VCHIQ_SERVICE_CLOSED:
|
|
case VCHIQ_BULK_TRANSMIT_ABORTED:
|
|
case VCHIQ_BULK_RECEIVE_ABORTED:
|
|
UNREACHABLE(); /* not implemented */
|
|
}
|
|
|
|
return VCHIQ_SUCCESS;
|
|
}
|
|
|
|
VCHIQ_STATUS_T khhn_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header,
|
|
VCHIQ_SERVICE_HANDLE_T handle, void *bulk_userdata)
|
|
{
|
|
switch (reason) {
|
|
case VCHIQ_MESSAGE_AVAILABLE:
|
|
vchiu_queue_push(&khhn_queue, header);
|
|
break;
|
|
case VCHIQ_BULK_TRANSMIT_DONE:
|
|
case VCHIQ_BULK_RECEIVE_DONE:
|
|
vcos_event_signal(&bulk_event);
|
|
break;
|
|
case VCHIQ_SERVICE_OPENED:
|
|
case VCHIQ_SERVICE_CLOSED:
|
|
case VCHIQ_BULK_TRANSMIT_ABORTED:
|
|
case VCHIQ_BULK_RECEIVE_ABORTED:
|
|
UNREACHABLE(); /* not implemented */
|
|
}
|
|
|
|
return VCHIQ_SUCCESS;
|
|
}
|
|
|
|
VCHIQ_STATUS_T khan_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header,
|
|
VCHIQ_SERVICE_HANDLE_T handle, void *bulk_userdata)
|
|
{
|
|
switch (reason) {
|
|
case VCHIQ_MESSAGE_AVAILABLE:
|
|
{
|
|
int32_t *data = (int32_t *) header->data;
|
|
int32_t command = data[0];
|
|
int32_t *msg = &data[1];
|
|
vcos_assert(header->size == 16);
|
|
|
|
// TODO should be able to remove this eventually.
|
|
// If incoming message is not addressed to this process, then ignore it.
|
|
// Correct process should then pick it up.
|
|
uint64_t pid = vchiq_get_client_id(handle);
|
|
if((msg[0] != (uint32_t) pid) || (msg[1] != (uint32_t) (pid >> 32)))
|
|
{
|
|
printf("khan_callback: message for wrong process; pid = %X, msg pid = %X\n",
|
|
(uint32_t) pid, msg[0]);
|
|
return VCHIQ_SUCCESS;
|
|
} // if
|
|
|
|
if (command == ASYNC_COMMAND_DESTROY)
|
|
{
|
|
/* todo: destroy */
|
|
}
|
|
else
|
|
{
|
|
PLATFORM_SEMAPHORE_T sem;
|
|
if (khronos_platform_semaphore_create(&sem, msg, 1) == KHR_SUCCESS)
|
|
{
|
|
switch (command) {
|
|
case ASYNC_COMMAND_WAIT:
|
|
khronos_platform_semaphore_acquire(&sem);
|
|
break;
|
|
case ASYNC_COMMAND_POST:
|
|
khronos_platform_semaphore_release(&sem);
|
|
break;
|
|
default:
|
|
vcos_assert_msg(0, "khan_callback: unknown message type");
|
|
break;
|
|
}
|
|
khronos_platform_semaphore_destroy(&sem);
|
|
}
|
|
} // else
|
|
vchiq_release_message(handle, header);
|
|
break;
|
|
}
|
|
case VCHIQ_BULK_TRANSMIT_DONE:
|
|
case VCHIQ_BULK_RECEIVE_DONE:
|
|
UNREACHABLE();
|
|
break;
|
|
case VCHIQ_SERVICE_OPENED:
|
|
vcos_assert_msg(0, "khan_callback: VCHIQ_SERVICE_OPENED");
|
|
break;
|
|
case VCHIQ_SERVICE_CLOSED:
|
|
vcos_assert_msg(0, "khan_callback: VCHIQ_SERVICE_CLOSED");
|
|
break;
|
|
case VCHIQ_BULK_TRANSMIT_ABORTED:
|
|
case VCHIQ_BULK_RECEIVE_ABORTED:
|
|
default:
|
|
UNREACHABLE(); /* not implemented */
|
|
}
|
|
|
|
return VCHIQ_SUCCESS;
|
|
}
|
|
|
|
void vc_vchi_khronos_init()
|
|
{
|
|
VCOS_STATUS_T status = vcos_event_create(&bulk_event, NULL);
|
|
UNUSED_NDEBUG(status);
|
|
vcos_assert(status == VCOS_SUCCESS);
|
|
|
|
if (vchiq_initialise(&khrn_vchiq_instance) != VCHIQ_SUCCESS)
|
|
{
|
|
vcos_log_error("* failed to open vchiq device");
|
|
|
|
exit(1);
|
|
}
|
|
|
|
vcos_log_trace("gldemo: connecting");
|
|
|
|
if (vchiq_connect(khrn_vchiq_instance) != VCHIQ_SUCCESS)
|
|
{
|
|
vcos_log_error("* failed to connect");
|
|
|
|
exit(1);
|
|
}
|
|
|
|
VCHIQ_STATUS_T khan_return, khrn_return, khhn_return;
|
|
VCHIQ_SERVICE_PARAMS_T params;
|
|
|
|
params.userdata = NULL;
|
|
params.version = VC_KHRN_VERSION;
|
|
params.version_min = VC_KHRN_VERSION;
|
|
|
|
params.fourcc = FOURCC_KHAN;
|
|
params.callback = khan_callback;
|
|
khan_return = vchiq_open_service(khrn_vchiq_instance, ¶ms, &vchiq_khan_service);
|
|
|
|
params.fourcc = FOURCC_KHRN;
|
|
params.callback = khrn_callback;
|
|
khrn_return = vchiq_open_service(khrn_vchiq_instance, ¶ms, &vchiq_khrn_service);
|
|
|
|
params.fourcc = FOURCC_KHHN;
|
|
params.callback = khhn_callback;
|
|
khhn_return = vchiq_open_service(khrn_vchiq_instance, ¶ms, &vchiq_khhn_service);
|
|
|
|
if (khan_return != VCHIQ_SUCCESS ||
|
|
khrn_return != VCHIQ_SUCCESS ||
|
|
khhn_return != VCHIQ_SUCCESS)
|
|
{
|
|
vcos_log_error("* failed to add service - already in use?");
|
|
|
|
exit(1);
|
|
}
|
|
vchiu_queue_init(&khrn_queue, 64);
|
|
vchiu_queue_init(&khhn_queue, 64);
|
|
|
|
vcos_log_trace("gldemo: connected");
|
|
|
|
/*
|
|
attach to process (there's just one)
|
|
*/
|
|
|
|
// bool success = client_process_attach();
|
|
// vcos_assert(success);
|
|
}
|
|
|
|
bool khclient_rpc_init(void)
|
|
{
|
|
workspace = NULL;
|
|
return platform_mutex_create(&mutex) == KHR_SUCCESS;
|
|
}
|
|
|
|
void rpc_term(void)
|
|
{
|
|
if (workspace) { khrn_platform_free(workspace); }
|
|
platform_mutex_destroy(&mutex);
|
|
}
|
|
|
|
static VCHIQ_SERVICE_HANDLE_T get_handle(CLIENT_THREAD_STATE_T *thread)
|
|
{
|
|
VCHIQ_SERVICE_HANDLE_T result = (thread->high_priority ? vchiq_khhn_service : vchiq_khrn_service);
|
|
return result;
|
|
}
|
|
|
|
static VCHIU_QUEUE_T *get_queue(CLIENT_THREAD_STATE_T *thread)
|
|
{
|
|
return thread->high_priority ? &khhn_queue : &khrn_queue;
|
|
}
|
|
|
|
static void check_workspace(uint32_t size)
|
|
{
|
|
/* todo: find a better way to handle scatter/gather bulks */
|
|
vcos_assert(size <= KHDISPATCH_WORKSPACE_SIZE);
|
|
if (!workspace) {
|
|
workspace = khrn_platform_malloc(KHDISPATCH_WORKSPACE_SIZE, "rpc_workspace");
|
|
vcos_assert(workspace);
|
|
}
|
|
}
|
|
|
|
static void merge_flush(CLIENT_THREAD_STATE_T *thread)
|
|
{
|
|
vcos_log_trace("merge_flush start");
|
|
|
|
vcos_assert(thread->merge_pos >= CLIENT_MAKE_CURRENT_SIZE);
|
|
|
|
/*
|
|
don't transmit just a make current -- in the case that there is only a
|
|
make current in the merge buffer, we have already sent a control message
|
|
for the rpc call (and with it a make current) and own the big lock
|
|
*/
|
|
|
|
if (thread->merge_pos > CLIENT_MAKE_CURRENT_SIZE) {
|
|
VCHIQ_ELEMENT_T element;
|
|
|
|
rpc_begin(thread);
|
|
|
|
element.data = thread->merge_buffer;
|
|
element.size = thread->merge_pos;
|
|
|
|
VCHIQ_STATUS_T success = vchiq_queue_message(get_handle(thread), &element, 1);
|
|
UNUSED_NDEBUG(success);
|
|
vcos_assert(success == VCHIQ_SUCCESS);
|
|
|
|
thread->merge_pos = 0;
|
|
|
|
client_send_make_current(thread);
|
|
|
|
vcos_assert(thread->merge_pos == CLIENT_MAKE_CURRENT_SIZE);
|
|
|
|
rpc_end(thread);
|
|
}
|
|
vcos_log_trace( "merge_flush end");
|
|
|
|
}
|
|
|
|
void rpc_flush(CLIENT_THREAD_STATE_T *thread)
|
|
{
|
|
merge_flush(thread);
|
|
}
|
|
|
|
void rpc_high_priority_begin(CLIENT_THREAD_STATE_T *thread)
|
|
{
|
|
vcos_assert(!thread->high_priority);
|
|
merge_flush(thread);
|
|
thread->high_priority = true;
|
|
}
|
|
|
|
void rpc_high_priority_end(CLIENT_THREAD_STATE_T *thread)
|
|
{
|
|
vcos_assert(thread->high_priority);
|
|
merge_flush(thread);
|
|
thread->high_priority = false;
|
|
}
|
|
|
|
uint32_t rpc_send_ctrl_longest(CLIENT_THREAD_STATE_T *thread, uint32_t len_min)
|
|
{
|
|
uint32_t len = MERGE_BUFFER_SIZE - thread->merge_pos;
|
|
if (len < len_min) {
|
|
len = MERGE_BUFFER_SIZE - CLIENT_MAKE_CURRENT_SIZE;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
void rpc_send_ctrl_begin(CLIENT_THREAD_STATE_T *thread, uint32_t len)
|
|
{
|
|
//CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
|
|
|
|
vcos_assert(len == rpc_pad_ctrl(len));
|
|
if ((thread->merge_pos + len) > MERGE_BUFFER_SIZE) {
|
|
merge_flush(thread);
|
|
}
|
|
|
|
thread->merge_end = thread->merge_pos + len;
|
|
}
|
|
|
|
void rpc_send_ctrl_write(CLIENT_THREAD_STATE_T *thread, const uint32_t in[], uint32_t len) /* len bytes read, rpc_pad_ctrl(len) bytes written */
|
|
{
|
|
//CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
|
|
|
|
memcpy(thread->merge_buffer + thread->merge_pos, in, len);
|
|
thread->merge_pos += rpc_pad_ctrl(len);
|
|
vcos_assert(thread->merge_pos <= MERGE_BUFFER_SIZE);
|
|
}
|
|
|
|
void rpc_send_ctrl_end(CLIENT_THREAD_STATE_T *thread)
|
|
{
|
|
//CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
|
|
|
|
vcos_assert(thread->merge_pos == thread->merge_end);
|
|
}
|
|
|
|
static void send_bulk(CLIENT_THREAD_STATE_T *thread, const void *in, uint32_t len)
|
|
{
|
|
if (len <= KHDISPATCH_CTRL_THRESHOLD) {
|
|
VCHIQ_ELEMENT_T element;
|
|
|
|
element.data = in;
|
|
element.size = len;
|
|
|
|
VCHIQ_STATUS_T vchiq_status = vchiq_queue_message(get_handle(thread), &element, 1);
|
|
UNUSED_NDEBUG(vchiq_status);
|
|
vcos_assert(vchiq_status == VCHIQ_SUCCESS);
|
|
} else {
|
|
VCHIQ_STATUS_T vchiq_status = vchiq_queue_bulk_transmit(get_handle(thread), in, rpc_pad_bulk(len), NULL);
|
|
UNUSED_NDEBUG(vchiq_status);
|
|
vcos_assert(vchiq_status == VCHIQ_SUCCESS);
|
|
VCOS_STATUS_T vcos_status = vcos_event_wait(&bulk_event);
|
|
UNUSED_NDEBUG(vcos_status);
|
|
vcos_assert(vcos_status == VCOS_SUCCESS);
|
|
}
|
|
}
|
|
|
|
static void recv_bulk(CLIENT_THREAD_STATE_T *thread, void *out, uint32_t len)
|
|
{
|
|
if (len <= KHDISPATCH_CTRL_THRESHOLD) {
|
|
VCHIQ_HEADER_T *header = vchiu_queue_pop(get_queue(thread));
|
|
vcos_assert(header->size == len);
|
|
memcpy(out, header->data, len);
|
|
vchiq_release_message(get_handle(thread), header);
|
|
} else {
|
|
VCHIQ_STATUS_T vchiq_status = vchiq_queue_bulk_receive(get_handle(thread), out, rpc_pad_bulk(len), NULL);
|
|
UNUSED_NDEBUG(vchiq_status);
|
|
vcos_assert(vchiq_status == VCHIQ_SUCCESS);
|
|
VCOS_STATUS_T vcos_status = vcos_event_wait(&bulk_event);
|
|
UNUSED_NDEBUG(vcos_status);
|
|
vcos_assert(vcos_status == VCOS_SUCCESS);
|
|
}
|
|
}
|
|
|
|
void rpc_send_bulk(CLIENT_THREAD_STATE_T *thread, const void *in, uint32_t len)
|
|
{
|
|
if (in && len) {
|
|
//CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
|
|
|
|
merge_flush(thread);
|
|
|
|
send_bulk(thread, in, len);
|
|
}
|
|
}
|
|
|
|
void rpc_send_bulk_gather(CLIENT_THREAD_STATE_T *thread, const void *in, uint32_t len, int32_t stride, uint32_t n)
|
|
{
|
|
#if 1
|
|
if (in && len) {
|
|
//CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
|
|
|
|
merge_flush(thread);
|
|
|
|
if (len == stride) {
|
|
/* hopefully should be the common case */
|
|
send_bulk(thread, in, n * len);
|
|
} else {
|
|
check_workspace(n * len);
|
|
rpc_gather(workspace, in, len, stride, n);
|
|
send_bulk(thread, workspace, n * len);
|
|
}
|
|
}
|
|
#else
|
|
UNREACHABLE();
|
|
#endif
|
|
}
|
|
|
|
uint32_t rpc_recv(CLIENT_THREAD_STATE_T *thread, void *out, uint32_t *len_io, RPC_RECV_FLAG_T flags)
|
|
{
|
|
uint32_t res = 0;
|
|
uint32_t len;
|
|
bool recv_ctrl;
|
|
|
|
if (!len_io) { len_io = &len; }
|
|
|
|
recv_ctrl = flags & (RPC_RECV_FLAG_RES | RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN); /* do we want to receive anything in the control channel at all? */
|
|
vcos_assert(recv_ctrl || (flags & RPC_RECV_FLAG_BULK)); /* must receive something... */
|
|
vcos_assert(!(flags & RPC_RECV_FLAG_CTRL) || !(flags & RPC_RECV_FLAG_BULK)); /* can't receive user data over both bulk and control... */
|
|
|
|
if (recv_ctrl || len_io[0]) { /* do nothing if we're just receiving bulk of length 0 */
|
|
merge_flush(thread);
|
|
|
|
if (recv_ctrl) {
|
|
VCHIQ_HEADER_T *header = vchiu_queue_pop(get_queue(thread));
|
|
uint8_t *ctrl = (uint8_t *)header->data;
|
|
vcos_assert(header->size >= (!!(flags & RPC_RECV_FLAG_LEN)*4 + !!(flags & RPC_RECV_FLAG_RES)*4) );
|
|
if (flags & RPC_RECV_FLAG_LEN) {
|
|
len_io[0] = *((uint32_t *)ctrl);
|
|
ctrl += 4;
|
|
}
|
|
if (flags & RPC_RECV_FLAG_RES) {
|
|
res = *((uint32_t *)ctrl);
|
|
ctrl += 4;
|
|
}
|
|
if (flags & RPC_RECV_FLAG_CTRL) {
|
|
memcpy(out, ctrl, len_io[0]);
|
|
ctrl += len_io[0];
|
|
}
|
|
vcos_assert(ctrl == ((uint8_t *)header->data + header->size));
|
|
vchiq_release_message(get_handle(thread), header);
|
|
}
|
|
|
|
if ((flags & RPC_RECV_FLAG_BULK) && len_io[0]) {
|
|
if (flags & RPC_RECV_FLAG_BULK_SCATTER) {
|
|
if ((len_io[0] == len_io[1]) && !len_io[3] && !len_io[4]) {
|
|
/* hopefully should be the common case */
|
|
recv_bulk(thread, out, len_io[2] * len_io[0]);
|
|
} else {
|
|
check_workspace(len_io[2] * len_io[0]);
|
|
recv_bulk(thread, workspace, len_io[2] * len_io[0]);
|
|
rpc_scatter(out, len_io[0], len_io[1], len_io[2], len_io[3], len_io[4], workspace);
|
|
}
|
|
} else {
|
|
recv_bulk(thread, out, len_io[0]);
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
void rpc_begin(CLIENT_THREAD_STATE_T *thread)
|
|
{
|
|
UNUSED(thread);
|
|
platform_mutex_acquire(&mutex);
|
|
}
|
|
|
|
void rpc_end(CLIENT_THREAD_STATE_T *thread)
|
|
{
|
|
UNUSED(thread);
|
|
platform_mutex_release(&mutex);
|
|
}
|
|
|
|
void rpc_use(CLIENT_THREAD_STATE_T *thread)
|
|
{ // TODO - implement this for linux
|
|
UNUSED(thread);
|
|
}
|
|
|
|
void rpc_release(CLIENT_THREAD_STATE_T *thread)
|
|
{ // TODO - implement this for linux
|
|
UNUSED(thread);
|
|
}
|
|
|
|
void rpc_call8_makecurrent(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0,
|
|
uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7)
|
|
{
|
|
uint32_t data;
|
|
if (thread->merge_pos == CLIENT_MAKE_CURRENT_SIZE && (memcpy(&data,thread->merge_buffer,sizeof(data)), data == EGLINTMAKECURRENT_ID))
|
|
{
|
|
rpc_begin(thread);
|
|
vcos_log_trace("rpc_call8_makecurrent collapse onto previous makecurrent");
|
|
|
|
thread->merge_pos = 0;
|
|
|
|
RPC_CALL8(eglIntMakeCurrent_impl, thread, EGLINTMAKECURRENT_ID, p0, p1, p2, p3, p4, p5, p6, p7);
|
|
vcos_assert(thread->merge_pos == CLIENT_MAKE_CURRENT_SIZE);
|
|
|
|
rpc_end(thread);
|
|
}
|
|
else
|
|
{
|
|
RPC_CALL8(eglIntMakeCurrent_impl, thread, EGLINTMAKECURRENT_ID, p0, p1, p2, p3, p4, p5, p6, p7);
|
|
}
|
|
}
|
|
|
|
uint64_t rpc_get_client_id(CLIENT_THREAD_STATE_T *thread)
|
|
{
|
|
return vchiq_get_client_id(get_handle(thread));
|
|
}
|