diff --git a/src/xrt/ipc/client/ipc_client.h b/src/xrt/ipc/client/ipc_client.h index 4aafcf79b..003c2ce7b 100644 --- a/src/xrt/ipc/client/ipc_client.h +++ b/src/xrt/ipc/client/ipc_client.h @@ -135,10 +135,14 @@ ipc_client_create_native_compositor(struct xrt_system_compositor *xsysc, struct xrt_compositor_native **out_xcn); struct xrt_device * -ipc_client_hmd_create(struct ipc_connection *ipc_c, struct xrt_tracking_origin *xtrack, uint32_t device_id); +ipc_client_hmd_create(struct ipc_connection *ipc_c, + struct ipc_client_tracking_origin_manager *ictom, + uint32_t device_id); struct xrt_device * -ipc_client_device_create(struct ipc_connection *ipc_c, struct xrt_tracking_origin *xtrack, uint32_t device_id); +ipc_client_device_create(struct ipc_connection *ipc_c, + struct ipc_client_tracking_origin_manager *ictom, + uint32_t device_id); struct xrt_system * ipc_client_system_create(struct ipc_connection *ipc_c, struct xrt_system_compositor *xsysc); diff --git a/src/xrt/ipc/client/ipc_client_device.c b/src/xrt/ipc/client/ipc_client_device.c index b966b88f5..8e5693cd0 100644 --- a/src/xrt/ipc/client/ipc_client_device.c +++ b/src/xrt/ipc/client/ipc_client_device.c @@ -1,5 +1,5 @@ // Copyright 2020-2024, Collabora, Ltd. -// Copyright 2025, NVIDIA CORPORATION. +// Copyright 2025-2026, NVIDIA CORPORATION. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -79,14 +79,21 @@ ipc_client_device_destroy(struct xrt_device *xdev) * @public @memberof ipc_client_device */ struct xrt_device * -ipc_client_device_create(struct ipc_connection *ipc_c, struct xrt_tracking_origin *xtrack, uint32_t device_id) +ipc_client_device_create(struct ipc_connection *ipc_c, + struct ipc_client_tracking_origin_manager *ictom, + uint32_t device_id) { // Allocate and setup the basics. enum u_device_alloc_flags flags = (enum u_device_alloc_flags)(U_DEVICE_ALLOC_HMD); ipc_client_device_t *icd = U_DEVICE_ALLOCATE(ipc_client_device_t, flags, 0, 0); // Fills in almost everything a regular device needs. - ipc_client_xdev_init(icd, ipc_c, xtrack, device_id, ipc_client_device_destroy); + xrt_result_t xret = ipc_client_xdev_init(icd, ipc_c, ictom, device_id, ipc_client_device_destroy); + if (xret != XRT_SUCCESS) { + IPC_ERROR(ipc_c, "Failed to initialize IPC client device: %d", xret); + u_device_free(&icd->base); + return NULL; + } // Setup variable tracker. u_var_add_root(icd, icd->base.str, true); diff --git a/src/xrt/ipc/client/ipc_client_hmd.c b/src/xrt/ipc/client/ipc_client_hmd.c index aa0e75f60..7bf3a436f 100644 --- a/src/xrt/ipc/client/ipc_client_hmd.c +++ b/src/xrt/ipc/client/ipc_client_hmd.c @@ -1,5 +1,5 @@ // Copyright 2020-2024, Collabora, Ltd. -// Copyright 2025, NVIDIA CORPORATION. +// Copyright 2025-2026, NVIDIA CORPORATION. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -311,7 +311,9 @@ ipc_client_hmd_set_brightness(struct xrt_device *xdev, float brightness, bool re * @public @memberof ipc_client_hmd */ struct xrt_device * -ipc_client_hmd_create(struct ipc_connection *ipc_c, struct xrt_tracking_origin *xtrack, uint32_t device_id) +ipc_client_hmd_create(struct ipc_connection *ipc_c, + struct ipc_client_tracking_origin_manager *ictom, + uint32_t device_id) { // Convenience helper. struct ipc_shared_memory *ism = ipc_c->ism; @@ -321,9 +323,14 @@ ipc_client_hmd_create(struct ipc_connection *ipc_c, struct xrt_tracking_origin * ipc_client_hmd_t *ich = U_DEVICE_ALLOCATE(ipc_client_hmd_t, flags, 0, 0); // Fills in almost everything a regular device needs. - ipc_client_xdev_init(ich, ipc_c, xtrack, device_id, ipc_client_hmd_destroy); + xrt_result_t xret = ipc_client_xdev_init(ich, ipc_c, ictom, device_id, ipc_client_hmd_destroy); + if (xret != XRT_SUCCESS) { + IPC_ERROR(ipc_c, "Failed to initialize IPC client HMD: %d", xret); + u_device_free(&ich->base); + return NULL; + } - // Fill in needed HMD functions, and destroy. + // Fill in needed HMD functions. ich->base.get_view_poses = ipc_client_hmd_get_view_poses; ich->base.compute_distortion = ipc_client_hmd_compute_distortion; ich->base.is_form_factor_available = ipc_client_hmd_is_form_factor_available; diff --git a/src/xrt/ipc/client/ipc_client_instance.c b/src/xrt/ipc/client/ipc_client_instance.c index 937800c9d..ca180d013 100644 --- a/src/xrt/ipc/client/ipc_client_instance.c +++ b/src/xrt/ipc/client/ipc_client_instance.c @@ -164,32 +164,29 @@ ipc_client_instance_create_system(struct xrt_instance *xinst, struct xrt_system_devices *xsysd = &icsd->base.base; - struct ipc_shared_memory *ism = ii->ipc_c.ism; + // Query the server for the list of devices + struct ipc_device_list device_list = {0}; + xret = ipc_call_system_devices_get_list(&ii->ipc_c, &device_list); + IPC_CHK_AND_RET(&ii->ipc_c, xret, "ipc_call_system_devices_get_list"); - // Query the server for how many devices it has and create them. + // Create client devices for each device in the list uint32_t count = 0; - for (uint32_t i = 0; i < ism->isdev_count; i++) { - struct ipc_shared_device *isdev = &ism->isdevs[i]; - - // Get tracking origin from manager (fetches on-demand) - struct xrt_tracking_origin *xtrack = NULL; - xret = ipc_client_tracking_origin_manager_get(&icsd->tracking_origin_manager, isdev->tracking_origin_id, - &xtrack); - if (xret != XRT_SUCCESS) { - IPC_ERROR(&ii->ipc_c, "Failed to get tracking origin for device %u (id %u)", i, - isdev->tracking_origin_id); - continue; - } - if (xtrack == NULL) { - IPC_ERROR(&ii->ipc_c, "Tracking origin for device %u (id %u) is NULL", i, - isdev->tracking_origin_id); - continue; + struct ipc_client_tracking_origin_manager *ictom = &icsd->tracking_origin_manager; + for (uint32_t i = 0; i < device_list.device_count; i++) { + struct ipc_device_list_entry *entry = &device_list.devices[i]; + + // Create the appropriate device type + if (entry->device_type == XRT_DEVICE_TYPE_HMD) { + xsysd->xdevs[count] = ipc_client_hmd_create(&ii->ipc_c, ictom, entry->id); + } else { + xsysd->xdevs[count] = ipc_client_device_create(&ii->ipc_c, ictom, entry->id); } - if (isdev->device_type == XRT_DEVICE_TYPE_HMD) { - xsysd->xdevs[count++] = ipc_client_hmd_create(&ii->ipc_c, xtrack, i); + // Check if device creation succeeded + if (xsysd->xdevs[count] != NULL) { + count++; } else { - xsysd->xdevs[count++] = ipc_client_device_create(&ii->ipc_c, xtrack, i); + IPC_ERROR(&ii->ipc_c, "Failed to create device %u", i); } } xsysd->xdev_count = count; diff --git a/src/xrt/ipc/client/ipc_client_xdev.c b/src/xrt/ipc/client/ipc_client_xdev.c index 39285d78e..7157aea15 100644 --- a/src/xrt/ipc/client/ipc_client_xdev.c +++ b/src/xrt/ipc/client/ipc_client_xdev.c @@ -1,5 +1,5 @@ // Copyright 2020-2024, Collabora, Ltd. -// Copyright 2025, NVIDIA CORPORATION. +// Copyright 2025-2026, NVIDIA CORPORATION. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -410,16 +410,19 @@ out: * */ -void +xrt_result_t ipc_client_xdev_init(struct ipc_client_xdev *icx, struct ipc_connection *ipc_c, - struct xrt_tracking_origin *xtrack, + struct ipc_client_tracking_origin_manager *ictom, uint32_t device_id, u_device_destroy_function_t destroy_fn) { // Helpers. struct ipc_shared_memory *ism = ipc_c->ism; - struct ipc_shared_device *isdev = &ism->isdevs[device_id]; + xrt_result_t xret = XRT_SUCCESS; + + // Queried later. + struct ipc_binding_profile_info *temp_ibpis = NULL; // Important fields. icx->ipc_c = ipc_c; @@ -452,51 +455,139 @@ ipc_client_xdev_init(struct ipc_client_xdev *icx, icx->base.get_plane_detection_state_ext = ipc_client_xdev_get_plane_detection_state_ext; icx->base.get_plane_detections_ext = ipc_client_xdev_get_plane_detections_ext; - // Copying the information from the isdev. - icx->base.device_type = isdev->device_type; - icx->base.supported = isdev->supported; - icx->base.tracking_origin = xtrack; - icx->base.name = isdev->name; + // Lock the connection so we can do varlen IPC calls. + ipc_client_connection_lock(ipc_c); + + // Call IPC to get device info with varlen data + xret = ipc_send_device_get_info_locked(ipc_c, device_id); + IPC_CHK_WITH_GOTO(ipc_c, xret, "ipc_send_device_get_info_locked", out_free_and_unlock); + + struct ipc_device_info info = {0}; + xret = ipc_receive_device_get_info_locked(ipc_c, &info); + IPC_CHK_WITH_GOTO(ipc_c, xret, "ipc_receive_device_get_info_locked", out_free_and_unlock); + + // Copying the information from the info. + icx->base.device_type = info.device_type; + icx->base.supported = info.supported; + icx->base.name = info.name; // Print name. - snprintf(icx->base.str, XRT_DEVICE_NAME_LEN, "%s", isdev->str); - snprintf(icx->base.serial, XRT_DEVICE_NAME_LEN, "%s", isdev->serial); + snprintf(icx->base.str, XRT_DEVICE_NAME_LEN, "%s", info.str); + snprintf(icx->base.serial, XRT_DEVICE_NAME_LEN, "%s", info.serial); // Setup inputs, by pointing directly to the shared memory. - assert(isdev->input_count > 0); - icx->base.inputs = &ism->inputs[isdev->first_input_index]; - icx->base.input_count = isdev->input_count; + icx->base.input_count = info.input_count; + if (info.input_count > 0) { + assert(info.first_input_index < IPC_SHARED_MAX_INPUTS); + icx->base.inputs = &ism->inputs[info.first_input_index]; + } else { + icx->base.inputs = NULL; + } // Setup outputs, if any point directly into the shared memory. - icx->base.output_count = isdev->output_count; - if (isdev->output_count > 0) { - icx->base.outputs = &ism->outputs[isdev->first_output_index]; + icx->base.output_count = info.output_count; + if (info.output_count > 0) { + assert(info.first_output_index < IPC_SHARED_MAX_OUTPUTS); + icx->base.outputs = &ism->outputs[info.first_output_index]; } else { icx->base.outputs = NULL; } + // Receive binding profiles from varlen data. + if (info.binding_profile_count > 0) { + /* + * This needs to live until after all of the bindings have + * been setup as it contains the offsets into the input and + * output pairs arrays. + */ + temp_ibpis = U_TYPED_ARRAY_CALLOC(struct ipc_binding_profile_info, info.binding_profile_count); + xret = ipc_receive(&ipc_c->imc, temp_ibpis, + sizeof(struct ipc_binding_profile_info) * info.binding_profile_count); + IPC_CHK_WITH_GOTO(ipc_c, xret, "ipc_receive(binding profiles)", out_free_and_unlock); + } + + // Receive all input pairs from varlen data. + if (info.total_input_pair_count > 0) { + size_t size = sizeof(struct xrt_binding_input_pair) * info.total_input_pair_count; + + // Is freed by ipc_client_xdev_fini. + icx->all_input_pairs = U_TYPED_ARRAY_CALLOC(struct xrt_binding_input_pair, info.total_input_pair_count); + xret = ipc_receive(&ipc_c->imc, icx->all_input_pairs, size); + IPC_CHK_WITH_GOTO(ipc_c, xret, "ipc_receive(input pairs)", out_free_and_unlock); + } + + // Receive all output pairs from varlen data. + if (info.total_output_pair_count > 0) { + size_t size = sizeof(struct xrt_binding_output_pair) * info.total_output_pair_count; + + // Is freed by ipc_client_xdev_fini. + icx->all_output_pairs = + U_TYPED_ARRAY_CALLOC(struct xrt_binding_output_pair, info.total_output_pair_count); + xret = ipc_receive(&ipc_c->imc, icx->all_output_pairs, size); + IPC_CHK_WITH_GOTO(ipc_c, xret, "ipc_receive(output pairs)", out_free_and_unlock); + } + // Setup binding profiles. - icx->base.binding_profile_count = isdev->binding_profile_count; - if (isdev->binding_profile_count > 0) { + icx->base.binding_profile_count = info.binding_profile_count; + if (info.binding_profile_count > 0) { + // Is freed by ipc_client_xdev_fini. icx->base.binding_profiles = - U_TYPED_ARRAY_CALLOC(struct xrt_binding_profile, isdev->binding_profile_count); + U_TYPED_ARRAY_CALLOC(struct xrt_binding_profile, info.binding_profile_count); } - for (size_t i = 0; i < isdev->binding_profile_count; i++) { + // Wire up binding profiles with received pairs + uint32_t input_pair_offset = 0; + uint32_t output_pair_offset = 0; + for (size_t i = 0; i < info.binding_profile_count; i++) { struct xrt_binding_profile *xbp = &icx->base.binding_profiles[i]; - struct ipc_shared_binding_profile *isbp = - &ism->binding_profiles[isdev->first_binding_profile_index + i]; - - xbp->name = isbp->name; - if (isbp->input_count > 0) { - xbp->inputs = &ism->input_pairs[isbp->first_input_index]; - xbp->input_count = isbp->input_count; + struct ipc_binding_profile_info *ibpi = &temp_ibpis[i]; + + xbp->name = ibpi->name; + xbp->input_count = ibpi->input_count; + xbp->output_count = ibpi->output_count; + + // Point to the appropriate section of the received arrays. + if (ibpi->input_count > 0) { + xbp->inputs = &icx->all_input_pairs[input_pair_offset]; + input_pair_offset += ibpi->input_count; + } else { + xbp->inputs = NULL; } - if (isbp->output_count > 0) { - xbp->outputs = &ism->output_pairs[isbp->first_output_index]; - xbp->output_count = isbp->output_count; + + // Ditto for outputs. + if (ibpi->output_count > 0) { + xbp->outputs = &icx->all_output_pairs[output_pair_offset]; + output_pair_offset += ibpi->output_count; + } else { + xbp->outputs = NULL; } } + +out_free_and_unlock: + // Out of the critical section. + ipc_client_connection_unlock(ipc_c); + + // Free temporary binding profile structures (we've copied the data). + free(temp_ibpis); + + // Check if we failed during the critical section. + IPC_CHK_WITH_GOTO(ipc_c, xret, "ipc_client_xdev_init(failed during critical section)", err_fini); + + // Get the tracking origin, can't do this with the critical section, so do it after. + struct xrt_tracking_origin *xtrack = NULL; + xret = ipc_client_tracking_origin_manager_get(ictom, info.tracking_origin_id, &xtrack); + IPC_CHK_WITH_GOTO(ipc_c, xret, "ipc_client_tracking_origin_manager_get", err_fini); + + icx->base.tracking_origin = xtrack; + + // Return success. + return XRT_SUCCESS; + +err_fini: + // Cleans up any allocations. + ipc_client_xdev_fini(icx); + + return xret; } void @@ -506,9 +597,19 @@ ipc_client_xdev_fini(struct ipc_client_xdev *icx) icx->base.inputs = NULL; icx->base.outputs = NULL; - // We allocated the bindings profiles. + // Free binding profiles. if (icx->base.binding_profiles != NULL) { free(icx->base.binding_profiles); icx->base.binding_profiles = NULL; } + + if (icx->all_input_pairs != NULL) { + free(icx->all_input_pairs); + icx->all_input_pairs = NULL; + } + + if (icx->all_output_pairs != NULL) { + free(icx->all_output_pairs); + icx->all_output_pairs = NULL; + } } diff --git a/src/xrt/ipc/client/ipc_client_xdev.h b/src/xrt/ipc/client/ipc_client_xdev.h index f4af3bbcc..2062d7f81 100644 --- a/src/xrt/ipc/client/ipc_client_xdev.h +++ b/src/xrt/ipc/client/ipc_client_xdev.h @@ -1,5 +1,5 @@ // Copyright 2020-2023, Collabora, Ltd. -// Copyright 2025, NVIDIA CORPORATION. +// Copyright 2025-2026, NVIDIA CORPORATION. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -22,6 +22,7 @@ extern "C" { struct ipc_connection; +struct ipc_client_tracking_origin_manager; /*! * An IPC client proxy for an @ref xrt_device. @@ -36,6 +37,9 @@ struct ipc_client_xdev struct ipc_connection *ipc_c; uint32_t device_id; + + struct xrt_binding_input_pair *all_input_pairs; + struct xrt_binding_output_pair *all_output_pairs; }; /*! @@ -57,10 +61,10 @@ ipc_client_xdev(struct xrt_device *xdev) * @ingroup ipc_client * @public @memberof ipc_client_xdev */ -void +xrt_result_t ipc_client_xdev_init(struct ipc_client_xdev *icx, struct ipc_connection *ipc_c, - struct xrt_tracking_origin *xtrack, + struct ipc_client_tracking_origin_manager *itom, uint32_t device_id, u_device_destroy_function_t destroy_fn); diff --git a/src/xrt/ipc/server/ipc_server.h b/src/xrt/ipc/server/ipc_server.h index 0ae825048..4e0a4fa8a 100644 --- a/src/xrt/ipc/server/ipc_server.h +++ b/src/xrt/ipc/server/ipc_server.h @@ -84,6 +84,15 @@ struct ipc_swapchain_data bool active; }; +struct ipc_client_device_state +{ + //! Offset to the inputs in the shared memory area. + uint32_t first_input_index; + + //! Offset to the outputs in the shared memory area. + uint32_t first_output_index; +}; + /*! * Holds the state for a single client. * @@ -107,6 +116,30 @@ struct ipc_client_state * so we don't need to lock it. */ struct xrt_tracking_origin *xtracks[XRT_SYSTEM_MAX_DEVICES]; + + /*! + * Array of devices. + * + * We don't control the lifetime of the devices, + * and we only access it from the per client thread, + * so we don't need to lock it. + */ + struct xrt_device *xdevs[XRT_SYSTEM_MAX_DEVICES]; + + /*! + * Array of device state, keeps calculated information needed + * to handle the devices, such as the offsets to inputs. + */ + struct ipc_client_device_state states[XRT_SYSTEM_MAX_DEVICES]; + + //! Number of devices added to shared memory. + uint32_t isdev_count; + + //! Current index for inputs in shared memory. + uint32_t input_index; + + //! Current index for outputs in shared memory. + uint32_t output_index; } objects; //! Session for this client. @@ -199,16 +232,6 @@ struct ipc_thread volatile struct ipc_client_state ics; }; - -/*! - * - */ -struct ipc_device -{ - //! The actual device. - struct xrt_device *xdev; -}; - /*! * Platform-specific mainloop object for the IPC server. * @@ -382,8 +405,6 @@ struct ipc_server //! System compositor. struct xrt_system_compositor *xsysc; - struct ipc_device idevs[XRT_SYSTEM_MAX_DEVICES]; - struct ipc_shared_memory *isms[IPC_MAX_CLIENTS]; struct ipc_server_mainloop ml; @@ -554,24 +575,6 @@ ipc_server_get_system_properties(struct ipc_server *vs, struct xrt_system_proper * */ -/*! - * Get a xdev with the given device_id. - */ -static inline struct xrt_device * -get_xdev(volatile struct ipc_client_state *ics, uint32_t device_id) -{ - return ics->server->idevs[device_id].xdev; -} - -/*! - * Get a idev with the given device_id. - */ -static inline struct ipc_device * -get_idev(volatile struct ipc_client_state *ics, uint32_t device_id) -{ - return &ics->server->idevs[device_id]; -} - /*! * Get the data in the shared memory of the given client. */ diff --git a/src/xrt/ipc/server/ipc_server_handler.c b/src/xrt/ipc/server/ipc_server_handler.c index c6d57c4c9..bbd20fc9c 100644 --- a/src/xrt/ipc/server/ipc_server_handler.c +++ b/src/xrt/ipc/server/ipc_server_handler.c @@ -39,31 +39,16 @@ IPC_CHK_AND_RET((ICS)->server, xret, "ipc_server_objects_get_xtrack_and_validate"); \ } while (0) -static xrt_result_t -validate_device_id(volatile struct ipc_client_state *ics, int64_t device_id, struct xrt_device **out_device) -{ - if (device_id >= XRT_SYSTEM_MAX_DEVICES) { - IPC_ERROR(ics->server, "Invalid device ID (device_id >= XRT_SYSTEM_MAX_DEVICES)!"); - return XRT_ERROR_IPC_FAILURE; - } - - struct xrt_device *xdev = ics->server->idevs[device_id].xdev; - if (xdev == NULL) { - IPC_ERROR(ics->server, "Invalid device ID (xdev is NULL)!"); - return XRT_ERROR_IPC_FAILURE; - } - - *out_device = xdev; - - return XRT_SUCCESS; -} +#define GET_XDEV_OR_RETURN(ICS, ID, XDEV) \ + do { \ + xrt_result_t xret = ipc_server_objects_get_xdev_and_validate((ICS), ID, &(XDEV)); \ + IPC_CHK_AND_RET((ICS)->server, xret, "ipc_server_objects_get_xdev_and_validate"); \ + } while (0) -#define GET_XDEV_OR_RETURN(ics, device_id, out_device) \ +#define GET_ICDEV_STATE_OR_RETURN(ICS, ID, STATE) \ do { \ - xrt_result_t res = validate_device_id(ics, device_id, &out_device); \ - if (res != XRT_SUCCESS) { \ - return res; \ - } \ + xrt_result_t xret = ipc_server_objects_get_icdev_state_and_validate((ICS), ID, &(STATE)); \ + IPC_CHK_AND_RET((ICS)->server, xret, "ipc_server_objects_get_icdev_state_and_validate"); \ } while (0) static xrt_result_t @@ -813,11 +798,7 @@ ipc_handle_space_locate_device(volatile struct ipc_client_state *ics, return xret; } - xret = validate_device_id(ics, xdev_id, &xdev); - if (xret != XRT_SUCCESS) { - U_LOG_E("Invalid device_id!"); - return xret; - } + GET_XDEV_OR_RETURN(ics, xdev_id, xdev); return xrt_space_overseer_locate_device( // xso, // @@ -1953,18 +1934,271 @@ ipc_handle_tracking_origin_get_info(volatile struct ipc_client_state *ics, * */ +static void +fill_device_info(volatile struct ipc_client_device_state *state, + struct xrt_device *xdev, + uint32_t tracking_origin_id, + struct ipc_device_info *out_info) +{ + // Fill in basic device info + out_info->name = xdev->name; + out_info->device_type = xdev->device_type; + out_info->tracking_origin_id = tracking_origin_id; + memcpy(out_info->str, xdev->str, sizeof(out_info->str)); + memcpy(out_info->serial, xdev->serial, sizeof(out_info->serial)); + out_info->supported = xdev->supported; + + // Fill in binding profile count + out_info->binding_profile_count = xdev->binding_profile_count; + + // Calculate total input/output pairs across all binding profiles + uint32_t total_input_pairs = 0; + uint32_t total_output_pairs = 0; + for (size_t i = 0; i < xdev->binding_profile_count; i++) { + total_input_pairs += xdev->binding_profiles[i].input_count; + total_output_pairs += xdev->binding_profiles[i].output_count; + } + out_info->total_input_pair_count = total_input_pairs; + out_info->total_output_pair_count = total_output_pairs; + + // Fill in input/output counts + out_info->input_count = xdev->input_count; + out_info->output_count = xdev->output_count; + + // Get the indices from the shared device. + out_info->first_input_index = state->first_input_index; + out_info->first_output_index = state->first_output_index; +} + +static xrt_result_t +send_binding_profiles(struct ipc_message_channel *imc, + struct ipc_server *server, + struct xrt_binding_profile *binding_profiles, + uint32_t binding_profile_count) +{ + struct ipc_binding_profile_info *profiles = NULL; + + // Early out if there are no pairs. + if (binding_profile_count == 0) { + return XRT_SUCCESS; + } + + // Allocate temporary array for all input pairs. + profiles = U_TYPED_ARRAY_CALLOC(struct ipc_binding_profile_info, binding_profile_count); + if (profiles == NULL) { + IPC_ERROR(server, "Failed to allocate input pairs array"); + return XRT_ERROR_ALLOCATION; + } + + // Send the binding profiles as varlen data. + uint32_t current_input_pair_index = 0; + uint32_t current_output_pair_index = 0; + for (size_t i = 0; i < binding_profile_count; i++) { + struct xrt_binding_profile *xbp = &binding_profiles[i]; + struct ipc_binding_profile_info *ibpi = &profiles[i]; + + // Common state. + ibpi->name = xbp->name; + + // Input pairs. + ibpi->input_count = xbp->input_count; + ibpi->first_input_index = xbp->input_count > 0 ? current_input_pair_index : 0; + current_input_pair_index += xbp->input_count; + + // Output pairs. + ibpi->output_count = xbp->output_count; + ibpi->first_output_index = xbp->output_count > 0 ? current_output_pair_index : 0; + current_output_pair_index += xbp->output_count; + } + + // Send all input pairs in one go. + xrt_result_t xret = ipc_send(imc, profiles, sizeof(struct ipc_binding_profile_info) * binding_profile_count); + free(profiles); + IPC_CHK_AND_RET(server, xret, "ipc_send(binding profile)"); + + return XRT_SUCCESS; +} + +static xrt_result_t +send_binding_input_pairs(struct ipc_message_channel *imc, + struct ipc_server *server, + struct xrt_binding_profile *binding_profiles, + uint32_t binding_profile_count, + uint32_t total_input_pairs) +{ + struct xrt_binding_input_pair *input_pairs = NULL; + + // Early out if there are no pairs. + if (total_input_pairs == 0) { + return XRT_SUCCESS; + } + + // Allocate temporary array for all input pairs. + input_pairs = U_TYPED_ARRAY_CALLOC(struct xrt_binding_input_pair, total_input_pairs); + if (input_pairs == NULL) { + IPC_ERROR(server, "Failed to allocate input pairs array"); + return XRT_ERROR_ALLOCATION; + } + + // Copy all input pairs into the temporary array. + uint32_t input_offset = 0; + for (uint32_t i = 0; i < binding_profile_count; i++) { + struct xrt_binding_profile *xbp = &binding_profiles[i]; + if (xbp->input_count > 0) { + size_t size = sizeof(struct xrt_binding_input_pair) * xbp->input_count; + memcpy(&input_pairs[input_offset], xbp->inputs, size); + input_offset += xbp->input_count; + } + } + + // Send all input pairs in one go. + xrt_result_t xret = ipc_send(imc, input_pairs, sizeof(struct xrt_binding_input_pair) * total_input_pairs); + free(input_pairs); + IPC_CHK_AND_RET(server, xret, "ipc_send(input pairs)"); + + return XRT_SUCCESS; +} + +static xrt_result_t +send_binding_output_pairs(struct ipc_message_channel *imc, + struct ipc_server *server, + struct xrt_binding_profile *binding_profiles, + uint32_t binding_profile_count, + uint32_t total_output_pairs) +{ + struct xrt_binding_output_pair *output_pairs = NULL; + + // Early out if there are no pairs. + if (total_output_pairs == 0) { + return XRT_SUCCESS; + } + + // Allocate temporary array for all output pairs. + output_pairs = U_TYPED_ARRAY_CALLOC(struct xrt_binding_output_pair, total_output_pairs); + if (output_pairs == NULL) { + IPC_ERROR(server, "Failed to allocate output pairs array"); + return XRT_ERROR_ALLOCATION; + } + + // Copy all output pairs into the temporary array. + uint32_t output_offset = 0; + for (uint32_t i = 0; i < binding_profile_count; i++) { + struct xrt_binding_profile *xbp = &binding_profiles[i]; + if (xbp->output_count > 0) { + size_t size = sizeof(struct xrt_binding_output_pair) * xbp->output_count; + memcpy(&output_pairs[output_offset], xbp->outputs, size); + output_offset += xbp->output_count; + } + } + + // Send all output pairs in one go. + xrt_result_t xret = ipc_send(imc, output_pairs, sizeof(struct xrt_binding_output_pair) * total_output_pairs); + free(output_pairs); + IPC_CHK_AND_RET(server, xret, "ipc_send(output pairs)"); + + return XRT_SUCCESS; +} + +xrt_result_t +ipc_handle_device_get_info(volatile struct ipc_client_state *ics, uint32_t device_id) +{ + struct ipc_message_channel *imc = (struct ipc_message_channel *)&ics->imc; + xrt_result_t xret = XRT_SUCCESS; + + // Validate the device ID and get the device + struct xrt_device *xdev = NULL; + GET_XDEV_OR_RETURN(ics, device_id, xdev); + + // Validate the shared device + volatile struct ipc_client_device_state *state = NULL; + GET_ICDEV_STATE_OR_RETURN(ics, device_id, state); + + // Get tracking origin ID + uint32_t tracking_origin_id = UINT32_MAX; + xret = ipc_server_objects_get_xtrack_id_or_add(ics, xdev->tracking_origin, &tracking_origin_id); + IPC_CHK_AND_RET(ics->server, xret, "ipc_server_objects_get_xtrack_id_or_add"); + + // Reply structure. + struct ipc_device_get_info_reply reply = XRT_STRUCT_INIT; + + // Use helper to fill device info + fill_device_info(state, xdev, tracking_origin_id, &reply.info); + + // Get the indices from the shared device. + reply.info.first_input_index = state->first_input_index; + reply.info.first_output_index = state->first_output_index; + + // Send the device info. + xret = ipc_send(imc, &reply, sizeof(reply)); + IPC_CHK_AND_RET(ics->server, xret, "ipc_send(device info)"); + + // Send all profiles in one go. + xret = send_binding_profiles( // + imc, // + ics->server, // + xdev->binding_profiles, // + xdev->binding_profile_count); // + IPC_CHK_AND_RET(ics->server, xret, "send_binding_profiles"); + + // Send all input pairs in one go. + xret = send_binding_input_pairs( // + imc, // + ics->server, // + xdev->binding_profiles, // + xdev->binding_profile_count, // + reply.info.total_input_pair_count); // + IPC_CHK_AND_RET(ics->server, xret, "send_binding_input_pairs"); + + // Send all output pairs in one go. + xret = send_binding_output_pairs( // + imc, // + ics->server, // + xdev->binding_profiles, // + xdev->binding_profile_count, // + reply.info.total_output_pair_count); // + IPC_CHK_AND_RET(ics->server, xret, "send_binding_output_pairs"); + + return XRT_SUCCESS; +} + +xrt_result_t +ipc_handle_device_get_info_no_arrays(volatile struct ipc_client_state *ics, + uint32_t device_id, + struct ipc_device_info *out_info) +{ + xrt_result_t xret = XRT_SUCCESS; + volatile struct ipc_client_device_state *state = NULL; + struct xrt_device *xdev = NULL; + + GET_XDEV_OR_RETURN(ics, device_id, xdev); + GET_ICDEV_STATE_OR_RETURN(ics, device_id, state); + + // Get tracking origin ID + uint32_t tracking_origin_id = UINT32_MAX; + xret = ipc_server_objects_get_xtrack_id_or_add(ics, xdev->tracking_origin, &tracking_origin_id); + IPC_CHK_AND_RET(ics->server, xret, "ipc_server_objects_get_xtrack_id_or_add"); + + // Use helper to fill device info + fill_device_info(state, xdev, tracking_origin_id, out_info); + + return XRT_SUCCESS; +} + xrt_result_t ipc_handle_device_update_input(volatile struct ipc_client_state *ics, uint32_t id) { // To make the code a bit more readable. uint32_t device_id = id; struct ipc_shared_memory *ism = get_ism(ics); - struct ipc_device *idev = get_idev(ics, device_id); - struct xrt_device *xdev = idev->xdev; - struct ipc_shared_device *isdev = &ism->isdevs[device_id]; + struct xrt_device *xdev = NULL; + volatile struct ipc_client_device_state *state = NULL; + xrt_result_t xret; + + GET_XDEV_OR_RETURN(ics, device_id, xdev); + GET_ICDEV_STATE_OR_RETURN(ics, device_id, state); // Update inputs. - xrt_result_t xret = xrt_device_update_inputs(xdev); + xret = xrt_device_update_inputs(xdev); if (xret != XRT_SUCCESS) { IPC_ERROR(ics->server, "Failed to update input"); return xret; @@ -1972,8 +2206,8 @@ ipc_handle_device_update_input(volatile struct ipc_client_state *ics, uint32_t i // Copy data into the shared memory. struct xrt_input *src = xdev->inputs; - struct xrt_input *dst = &ism->inputs[isdev->first_input_index]; - size_t size = sizeof(struct xrt_input) * isdev->input_count; + struct xrt_input *dst = &ism->inputs[state->first_input_index]; + size_t size = sizeof(struct xrt_input) * xdev->input_count; bool io_active = ics->io_active; if (io_active) { @@ -1981,7 +2215,7 @@ ipc_handle_device_update_input(volatile struct ipc_client_state *ics, uint32_t i } else { memset(dst, 0, size); - for (uint32_t i = 0; i < isdev->input_count; i++) { + for (uint32_t i = 0; i < xdev->input_count; i++) { dst[i].name = src[i].name; // Special case the rotation of the head. @@ -1996,13 +2230,15 @@ ipc_handle_device_update_input(volatile struct ipc_client_state *ics, uint32_t i } static struct xrt_input * -find_input(volatile struct ipc_client_state *ics, uint32_t device_id, enum xrt_input_name name) +find_input(volatile struct ipc_client_state *ics, + volatile struct ipc_client_device_state *state, + uint32_t input_count, + enum xrt_input_name name) { struct ipc_shared_memory *ism = get_ism(ics); - struct ipc_shared_device *isdev = &ism->isdevs[device_id]; - struct xrt_input *io = &ism->inputs[isdev->first_input_index]; + struct xrt_input *io = &ism->inputs[state->first_input_index]; - for (uint32_t i = 0; i < isdev->input_count; i++) { + for (uint32_t i = 0; i < input_count; i++) { if (io[i].name == name) { return &io[i]; } @@ -2020,11 +2256,14 @@ ipc_handle_device_get_tracked_pose(volatile struct ipc_client_state *ics, { // To make the code a bit more readable. uint32_t device_id = id; - struct ipc_device *isdev = &ics->server->idevs[device_id]; - struct xrt_device *xdev = isdev->xdev; + struct xrt_device *xdev = NULL; + volatile struct ipc_client_device_state *state = NULL; + + GET_XDEV_OR_RETURN(ics, device_id, xdev); + GET_ICDEV_STATE_OR_RETURN(ics, device_id, state); // Find the input - struct xrt_input *input = find_input(ics, device_id, name); + struct xrt_input *input = find_input(ics, state, xdev->input_count, name); if (input == NULL) { return XRT_ERROR_IPC_FAILURE; } @@ -2480,6 +2719,7 @@ ipc_handle_device_get_visibility_mask(volatile struct ipc_client_state *ics, // @todo verify struct xrt_device *xdev = NULL; GET_XDEV_OR_RETURN(ics, device_id, xdev); + struct xrt_visibility_mask *mask = NULL; if (xdev->get_visibility_mask) { xret = xrt_device_get_visibility_mask(xdev, type, view_index, &mask); @@ -2526,7 +2766,28 @@ ipc_handle_device_is_form_factor_available(volatile struct ipc_client_state *ics uint32_t device_id = id; struct xrt_device *xdev = NULL; GET_XDEV_OR_RETURN(ics, device_id, xdev); + *out_available = xrt_device_is_form_factor_available(xdev, form_factor); + + return XRT_SUCCESS; +} + +xrt_result_t +ipc_handle_system_devices_get_list(volatile struct ipc_client_state *ics, struct ipc_device_list *out_list) +{ + // Count and collect device types + uint32_t count = 0; + for (uint32_t i = 0; i < XRT_SYSTEM_MAX_DEVICES; i++) { + struct xrt_device *xdev = ics->objects.xdevs[i]; + if (xdev != NULL) { + out_list->devices[count].id = i; + out_list->devices[count].device_type = xdev->device_type; + count++; + } + } + + out_list->device_count = count; + return XRT_SUCCESS; } @@ -2644,7 +2905,8 @@ ipc_handle_device_get_body_joints(volatile struct ipc_client_state *ics, xrt_result_t ipc_handle_device_reset_body_tracking_calibration_meta(volatile struct ipc_client_state *ics, uint32_t id) { - struct xrt_device *xdev = get_xdev(ics, id); + struct xrt_device *xdev = NULL; + GET_XDEV_OR_RETURN(ics, id, xdev); return xrt_device_reset_body_tracking_calibration_meta(xdev); } @@ -2653,7 +2915,8 @@ ipc_handle_device_set_body_tracking_calibration_override_meta(volatile struct ip uint32_t id, float new_body_height) { - struct xrt_device *xdev = get_xdev(ics, id); + struct xrt_device *xdev = NULL; + GET_XDEV_OR_RETURN(ics, id, xdev); return xrt_device_set_body_tracking_calibration_override_meta(xdev, new_body_height); } diff --git a/src/xrt/ipc/server/ipc_server_objects.c b/src/xrt/ipc/server/ipc_server_objects.c index f5bed1ec6..1fa42cc01 100644 --- a/src/xrt/ipc/server/ipc_server_objects.c +++ b/src/xrt/ipc/server/ipc_server_objects.c @@ -7,10 +7,154 @@ * @ingroup ipc_server */ +#include "xrt/xrt_device.h" #include "xrt/xrt_tracking.h" -#include "ipc_server.h" -#include "ipc_server_objects.h" +#include "shared/ipc_protocol.h" +#include "server/ipc_server.h" +#include "server/ipc_server_objects.h" + +#include +#include + + +/* + * + * Helper functions. + * + */ + +xrt_result_t +allocate_fill_in_xdev_and_state(volatile struct ipc_client_state *ics, uint32_t index, struct xrt_device *xdev) +{ + assert(index < XRT_SYSTEM_MAX_DEVICES); + assert(xdev != NULL); + + // Convenience variables. + struct ipc_server *s = ics->server; + struct ipc_shared_memory *ism = get_ism(ics); + + // Setup the tracking origin ID. + uint32_t tracking_origin_id = UINT32_MAX; + xrt_result_t xret = ipc_server_objects_get_xtrack_id_or_add(ics, xdev->tracking_origin, &tracking_origin_id); + if (xret != XRT_SUCCESS) { + IPC_ERROR(s, "Failed to get/add tracking origin ID for device: '%s'", xdev->str); + // Clear the device we just added since setup failed. + ics->objects.xdevs[index] = NULL; + return xret; + } + + // Store the device in the objects array. + ics->objects.xdevs[index] = xdev; + + // Holds internal state. + volatile struct ipc_client_device_state *state = &ics->objects.states[index]; + + // Initial update. + xrt_device_update_inputs(xdev); + + // Copy the initial state and also count the number of inputs. + const uint32_t input_count = xdev->input_count; + const uint32_t input_start = ics->objects.input_index; + for (size_t k = 0; k < input_count; k++) { + ism->inputs[ics->objects.input_index++] = xdev->inputs[k]; + } + + // Setup the 'offsets' for the inputs. + state->first_input_index = input_count > 0 ? input_start : 0; + + // Copy the initial state and also count the number of outputs. + const uint32_t output_count = xdev->output_count; + const uint32_t output_start = ics->objects.output_index; + for (size_t k = 0; k < output_count; k++) { + ism->outputs[ics->objects.output_index++] = xdev->outputs[k]; + } + + // Setup the 'offsets' for the outputs. + state->first_output_index = output_count > 0 ? output_start : 0; + + // Increment the device count. + ics->objects.isdev_count++; + + return XRT_SUCCESS; +} + + +/* + * + * Device functions. + * + */ + +xrt_result_t +ipc_server_objects_get_xdev_and_validate(volatile struct ipc_client_state *ics, + uint32_t id, + struct xrt_device **out_xdev) +{ + if (id >= XRT_SYSTEM_MAX_DEVICES) { + IPC_ERROR(ics->server, "Invalid device ID %u (>= XRT_SYSTEM_MAX_DEVICES)", id); + return XRT_ERROR_IPC_FAILURE; + } + + struct xrt_device *xdev = ics->objects.xdevs[id]; + if (xdev == NULL) { + IPC_ERROR(ics->server, "Device ID %u not found (NULL)", id); + return XRT_ERROR_IPC_FAILURE; + } + + *out_xdev = xdev; + + return XRT_SUCCESS; +} + +xrt_result_t +ipc_server_objects_get_icdev_state_and_validate(volatile struct ipc_client_state *ics, + uint32_t id, + volatile struct ipc_client_device_state **out_state) +{ + struct xrt_device *xdev = NULL; // Not used, just to satisfy the function signature. + xrt_result_t xret = ipc_server_objects_get_xdev_and_validate(ics, id, &xdev); + IPC_CHK_AND_RET(ics->server, xret, "ipc_server_objects_get_xdev_and_validate"); + + // Validation passed, get the shared device. + *out_state = &ics->objects.states[id]; + + return XRT_SUCCESS; +} + +xrt_result_t +ipc_server_objects_get_xdev_id_or_add(volatile struct ipc_client_state *ics, struct xrt_device *xdev, uint32_t *out_id) +{ + assert(out_id != NULL); + assert(xdev != NULL); + + // Check if device already exists and return its ID. + uint32_t index = 0; + for (; index < XRT_SYSTEM_MAX_DEVICES; index++) { + if (ics->objects.xdevs[index] == NULL) { + xrt_result_t xret = allocate_fill_in_xdev_and_state(ics, index, xdev); + IPC_CHK_AND_RET(ics->server, xret, "allocate_fill_in_xdev_and_state"); + + *out_id = index; + + return XRT_SUCCESS; + } + if (ics->objects.xdevs[index] == xdev) { + *out_id = index; + return XRT_SUCCESS; + } + } + + + if (index >= XRT_SYSTEM_MAX_DEVICES) { + IPC_ERROR(ics->server, "Failed to find available slot for device: '%s'", xdev->str); + return XRT_ERROR_IPC_FAILURE; + } + + *out_id = index; + + return XRT_SUCCESS; +} /* diff --git a/src/xrt/ipc/server/ipc_server_objects.h b/src/xrt/ipc/server/ipc_server_objects.h index 4e87e0eee..bf9bc98a0 100644 --- a/src/xrt/ipc/server/ipc_server_objects.h +++ b/src/xrt/ipc/server/ipc_server_objects.h @@ -12,8 +12,67 @@ #include "xrt/xrt_results.h" struct ipc_client_state; +struct ipc_client_device_state; +/*! + * + * Device functions. + * + */ + +/*! + * Get a device by ID, must only be called from the per client + * thread as this function accesses the client state's memory. + * + * @param ics The client state instance. + * @param id The device ID. + * @param out_xdev Will be filled with the device object on success. + * @return XRT_SUCCESS on success, some other result on failure. + * + * @ingroup ipc_server + */ +xrt_result_t +ipc_server_objects_get_xdev_and_validate(volatile struct ipc_client_state *ics, + uint32_t id, + struct xrt_device **out_xdev); + +/*! + * Get an ipc_shared_device by ID, must only be called from the per client + * thread as this function accesses the client state's memory. + * + * @param ics The client state instance. + * @param id The device ID. + * @param out_isdev Will be filled with the ipc_shared_device object on success. + * @return XRT_SUCCESS on success, some other result on failure. + * + * @ingroup ipc_server + */ +xrt_result_t +ipc_server_objects_get_icdev_state_and_validate(volatile struct ipc_client_state *ics, + uint32_t id, + volatile struct ipc_client_device_state **out_isdev); + +/*! + * Get a device ID for a given device object, must only be called from the per + * client thread as this function accesses the client state's memory. + * + * @param ics The client state instance. + * @param xdev The device object. + * @param out_id Will be filled with the device ID on success. + * @return XRT_SUCCESS on success, some other result on failure. + * + * @ingroup ipc_server + */ +xrt_result_t +ipc_server_objects_get_xdev_id_or_add(volatile struct ipc_client_state *ics, struct xrt_device *xdev, uint32_t *out_id); + +/*! + * + * Tracking origin functions. + * + */ + /*! * Get a tracking origin by ID, must only be called from the per client * thread as this function accesses the client state's memory. diff --git a/src/xrt/ipc/server/ipc_server_process.c b/src/xrt/ipc/server/ipc_server_process.c index e0a40f0f6..421ba10c4 100644 --- a/src/xrt/ipc/server/ipc_server_process.c +++ b/src/xrt/ipc/server/ipc_server_process.c @@ -96,39 +96,6 @@ find_xdev_index(struct ipc_server *s, struct xrt_device *xdev) return -1; } -static void -init_idev(struct ipc_device *idev, struct xrt_device *xdev) -{ - idev->xdev = xdev; -} - -static void -teardown_idev(struct ipc_device *idev) -{ - idev->xdev = NULL; -} - -static void -init_idevs(struct ipc_server *s) -{ - // Copy the devices over into the idevs array. - for (size_t i = 0; i < XRT_SYSTEM_MAX_DEVICES; i++) { - if (s->xsysd->xdevs[i] == NULL) { - continue; - } - - init_idev(&s->idevs[i], s->xsysd->xdevs[i]); - } -} - -static void -teardown_idevs(struct ipc_server *s) -{ - for (size_t i = 0; i < XRT_SYSTEM_MAX_DEVICES; i++) { - teardown_idev(&s->idevs[i]); - } -} - /* * @@ -202,8 +169,6 @@ teardown_all(struct ipc_server *s) xrt_syscomp_destroy(&s->xsysc); - teardown_idevs(s); - xrt_space_overseer_destroy(&s->xso); xrt_system_devices_destroy(&s->xsysd); xrt_system_destroy(&s->xsys); @@ -218,70 +183,6 @@ teardown_all(struct ipc_server *s) os_mutex_destroy(&s->global_state.lock); } -static void -init_tracking_origins(volatile struct ipc_client_state *ics) -{ - struct ipc_server *s = ics->server; - - for (size_t i = 0; i < XRT_SYSTEM_MAX_DEVICES; i++) { - struct xrt_device *xdev = s->idevs[i].xdev; - if (xdev == NULL) { - continue; - } - - struct xrt_tracking_origin *xtrack = xdev->tracking_origin; - assert(xtrack != NULL); - - // Get or add tracking origin ID - uint32_t tracking_origin_id = 0; - xrt_result_t xret = ipc_server_objects_get_xtrack_id_or_add(ics, xtrack, &tracking_origin_id); - if (xret != XRT_SUCCESS) { - IPC_ERROR(s, "Failed to get/add tracking origin ID for: '%s'", xtrack->name); - continue; - } - } -} - -static void -handle_binding(struct ipc_shared_memory *ism, - struct xrt_binding_profile *xbp, - struct ipc_shared_binding_profile *isbp, - uint32_t *input_pair_index_ptr, - uint32_t *output_pair_index_ptr) -{ - uint32_t input_pair_index = *input_pair_index_ptr; - uint32_t output_pair_index = *output_pair_index_ptr; - - isbp->name = xbp->name; - - // Copy the initial state and also count the number in input_pairs. - uint32_t input_pair_start = input_pair_index; - for (size_t k = 0; k < xbp->input_count; k++) { - ism->input_pairs[input_pair_index++] = xbp->inputs[k]; - } - - // Setup the 'offsets' and number of input_pairs. - if (input_pair_start != input_pair_index) { - isbp->input_count = input_pair_index - input_pair_start; - isbp->first_input_index = input_pair_start; - } - - // Copy the initial state and also count the number in outputs. - uint32_t output_pair_start = output_pair_index; - for (size_t k = 0; k < xbp->output_count; k++) { - ism->output_pairs[output_pair_index++] = xbp->outputs[k]; - } - - // Setup the 'offsets' and number of output_pairs. - if (output_pair_start != output_pair_index) { - isbp->output_count = output_pair_index - output_pair_start; - isbp->first_output_index = output_pair_start; - } - - *input_pair_index_ptr = input_pair_index; - *output_pair_index_ptr = output_pair_index; -} - XRT_CHECK_RESULT static xrt_result_t init_shm_and_instance_state(struct ipc_server *s, volatile struct ipc_client_state *ics) { @@ -307,89 +208,35 @@ init_shm_and_instance_state(struct ipc_server *s, volatile struct ipc_client_sta } static void -init_system_shm_state(struct ipc_server *s, volatile struct ipc_client_state *cs) +init_system_shm_state(struct ipc_server *s, volatile struct ipc_client_state *ics) { + struct ipc_shared_memory *ism = get_ism(ics); + xrt_result_t xret = XRT_SUCCESS; + /* - * - * Setup the shared memory state. - * + * Loop over all of the devices to pre-populate the device IDs, + * this also populates the tracking origins. */ - - uint32_t count = 0; - struct ipc_shared_memory *ism = s->isms[cs->server_thread_index]; - - // Tracking origins are no longer copied to shared memory. - // They are fetched on-demand via IPC calls. - - count = 0; - uint32_t input_index = 0; - uint32_t output_index = 0; - uint32_t binding_index = 0; - uint32_t input_pair_index = 0; - uint32_t output_pair_index = 0; - for (size_t i = 0; i < XRT_SYSTEM_MAX_DEVICES; i++) { - struct xrt_device *xdev = s->idevs[i].xdev; + struct xrt_device *xdev = s->xsysd->xdevs[i]; if (xdev == NULL) { continue; } - struct ipc_shared_device *isdev = &ism->isdevs[count++]; - - isdev->name = xdev->name; - memcpy(isdev->str, xdev->str, sizeof(isdev->str)); - memcpy(isdev->serial, xdev->serial, sizeof(isdev->serial)); - - // Copy information. - isdev->device_type = xdev->device_type; - isdev->supported = xdev->supported; - - // Setup the tracking origin ID. - uint32_t tracking_origin_id = UINT32_MAX; - xrt_result_t xret = - ipc_server_objects_get_xtrack_id_or_add(cs, xdev->tracking_origin, &tracking_origin_id); - assert(xret == XRT_SUCCESS); - - isdev->tracking_origin_id = tracking_origin_id; - - // Initial update. - xrt_device_update_inputs(xdev); - - // Bindings - uint32_t binding_start = binding_index; - for (size_t k = 0; k < xdev->binding_profile_count; k++) { - handle_binding(ism, &xdev->binding_profiles[k], &ism->binding_profiles[binding_index++], - &input_pair_index, &output_pair_index); - } - - // Setup the 'offsets' and number of bindings. - if (binding_start != binding_index) { - isdev->binding_profile_count = binding_index - binding_start; - isdev->first_binding_profile_index = binding_start; - } - - // Copy the initial state and also count the number in inputs. - uint32_t input_start = input_index; - for (size_t k = 0; k < xdev->input_count; k++) { - ism->inputs[input_index++] = xdev->inputs[k]; - } - - // Setup the 'offsets' and number of inputs. - if (input_start != input_index) { - isdev->input_count = input_index - input_start; - isdev->first_input_index = input_start; - } - - // Copy the initial state and also count the number in outputs. - uint32_t output_start = output_index; - for (size_t k = 0; k < xdev->output_count; k++) { - ism->outputs[output_index++] = xdev->outputs[k]; + // Populate the tracking origin. + uint32_t tracking_origin_id = 0; + xret = ipc_server_objects_get_xtrack_id_or_add(ics, xdev->tracking_origin, &tracking_origin_id); + if (xret != XRT_SUCCESS) { + IPC_ERROR(s, "Failed to get/add tracking origin ID for: '%s'", xdev->tracking_origin->name); + continue; } - // Setup the 'offsets' and number of outputs. - if (output_start != output_index) { - isdev->output_count = output_index - output_start; - isdev->first_output_index = output_start; + // Populate the device. + uint32_t device_id = 0; + xret = ipc_server_objects_get_xdev_id_or_add(ics, xdev, &device_id); + if (xret != XRT_SUCCESS) { + IPC_ERROR(s, "Failed to get/add device ID for: '%s'", xdev->str); + continue; } } @@ -413,9 +260,6 @@ init_system_shm_state(struct ipc_server *s, volatile struct ipc_client_state *cs ism->hmd.blend_mode_count = xhmd->blend_mode_count; } - // Finally tell the client how many devices we have. - ism->isdev_count = count; - // Assign all of the roles. ism->roles.head = find_xdev_index(s, s->xsysd->static_roles.head); ism->roles.eyes = find_xdev_index(s, s->xsysd->static_roles.eyes); @@ -818,14 +662,10 @@ ipc_server_init_system_if_available_locked(struct ipc_server *s, if (available) { xret = xrt_instance_create_system(s->xinst, &s->xsys, &s->xsysd, &s->xso, &s->xsysc); IPC_CHK_WITH_GOTO(s, xret, "xrt_instance_create_system", error); - - // Always succeeds. - init_idevs(s); } } if (available && ics != NULL && !ics->has_init_shm_system) { - init_tracking_origins(ics); init_system_shm_state(s, ics); ics->has_init_shm_system = true; } diff --git a/src/xrt/ipc/shared/ipc_protocol.h b/src/xrt/ipc/shared/ipc_protocol.h index 2cf5e4d1e..e0bf75307 100644 --- a/src/xrt/ipc/shared/ipc_protocol.h +++ b/src/xrt/ipc/shared/ipc_protocol.h @@ -44,7 +44,6 @@ #define IPC_SHARED_MAX_INPUTS 1024 #define IPC_SHARED_MAX_OUTPUTS 128 -#define IPC_SHARED_MAX_BINDINGS 64 // example: v21.0.0-560-g586d33b5 #define IPC_VERSION_NAME_LEN 64 @@ -102,31 +101,44 @@ struct ipc_tracking_origin_info }; /*! - * A binding in the shared memory area. + * Information about a device in the device list. * * @ingroup ipc */ -struct ipc_shared_binding_profile +struct ipc_device_list_entry { - enum xrt_device_name name; + //! Device ID + uint32_t id; - //! Offset into the array of pairs where this input bindings starts. - uint32_t first_input_index; - //! Number of inputs. - uint32_t input_count; + //! Device type + enum xrt_device_type device_type; +}; - //! Offset into the array of pairs where this output bindings starts. - uint32_t first_output_index; - //! Number of outputs. - uint32_t output_count; +/*! + * List of devices available on the server. + * + * @ingroup ipc + */ +struct ipc_device_list +{ + //! Number of devices + uint32_t device_count; + + //! Device entries + struct ipc_device_list_entry devices[XRT_SYSTEM_MAX_DEVICES]; }; /*! - * A device in the shared memory area. + * Device information sent over IPC. + * + * Followed by varlen data containing: + * - An array of binding_profile_count * struct ipc_binding_profile_info + * - An array of total_input_pair_count * struct xrt_binding_input_pair + * - An array of total_output_pair_count * struct xrt_binding_output_pair * * @ingroup ipc */ -struct ipc_shared_device +struct ipc_device_info { //! Enum identifier of the device. enum xrt_device_name name; @@ -141,25 +153,49 @@ struct ipc_shared_device //! A unique identifier. Persistent across configurations, if possible. char serial[XRT_DEVICE_NAME_LEN]; - //! Number of bindings. + //! Number of binding profiles in varlen data. uint32_t binding_profile_count; - //! 'Offset' into the array of bindings where the bindings starts. - uint32_t first_binding_profile_index; + + //! Total number of input pairs in varlen data (across all binding profiles). + uint32_t total_input_pair_count; + + //! Total number of output pairs in varlen data (across all binding profiles). + uint32_t total_output_pair_count; //! Number of inputs. uint32_t input_count; - //! 'Offset' into the array of inputs where the inputs starts. + //! 'Offset' into the shared memory array of inputs where the inputs start. uint32_t first_input_index; //! Number of outputs. uint32_t output_count; - //! 'Offset' into the array of outputs where the outputs starts. + //! 'Offset' into the shared memory array of outputs where the outputs start. uint32_t first_output_index; //! The supported fields. struct xrt_device_supported supported; }; +/*! + * A binding in the shared memory area. + * + * @ingroup ipc + */ +struct ipc_binding_profile_info +{ + enum xrt_device_name name; + + //! Offset into the array of pairs where this input bindings starts. + uint32_t first_input_index; + //! Number of inputs. + uint32_t input_count; + + //! Offset into the array of pairs where this output bindings starts. + uint32_t first_output_index; + //! Number of outputs. + uint32_t output_count; +}; + /*! * Data for a single composition layer. * @@ -220,18 +256,6 @@ struct ipc_shared_memory */ char u_git_tag[IPC_VERSION_NAME_LEN]; - /*! - * Number of elements in @ref isdevs that are populated/valid. - */ - uint32_t isdev_count; - - /*! - * @brief Array of shared data per device. - * - * Only @ref isdev_count elements are populated/valid. - */ - struct ipc_shared_device isdevs[XRT_SYSTEM_MAX_DEVICES]; - /*! * Various roles for the devices. */ @@ -290,10 +314,6 @@ struct ipc_shared_memory struct xrt_output outputs[IPC_SHARED_MAX_OUTPUTS]; - struct ipc_shared_binding_profile binding_profiles[IPC_SHARED_MAX_BINDINGS]; - struct xrt_binding_input_pair input_pairs[IPC_SHARED_MAX_INPUTS]; - struct xrt_binding_output_pair output_pairs[IPC_SHARED_MAX_OUTPUTS]; - struct ipc_layer_slot slots[IPC_MAX_SLOTS]; uint64_t startup_timestamp; diff --git a/src/xrt/ipc/shared/proto/50-device.json b/src/xrt/ipc/shared/proto/50-device.json index 83121a5f1..26424b224 100644 --- a/src/xrt/ipc/shared/proto/50-device.json +++ b/src/xrt/ipc/shared/proto/50-device.json @@ -1,6 +1,25 @@ { "$schema": "../proto.schema.json", + "device_get_info": { + "varlen": true, + "in": [ + {"name": "device_id", "type": "uint32_t"} + ], + "out": [ + {"name": "info", "type": "struct ipc_device_info"} + ] + }, + + "device_get_info_no_arrays": { + "in": [ + {"name": "device_id", "type": "uint32_t"} + ], + "out": [ + {"name": "info", "type": "struct ipc_device_info"} + ] + }, + "device_update_input": { "in": [ {"name": "id", "type": "uint32_t"} diff --git a/src/xrt/ipc/shared/proto/50-device.json.license b/src/xrt/ipc/shared/proto/50-device.json.license index 188bb0978..3de40158b 100644 --- a/src/xrt/ipc/shared/proto/50-device.json.license +++ b/src/xrt/ipc/shared/proto/50-device.json.license @@ -1,3 +1,4 @@ Copyright 2018-2025, Collabora, Ltd. +Copyright 2025-2026, NVIDIA CORPORATION. SPDX-License-Identifier: BSL-1.0 diff --git a/src/xrt/ipc/shared/proto/50-system.json b/src/xrt/ipc/shared/proto/50-system.json index 72658ae8f..089416d0e 100644 --- a/src/xrt/ipc/shared/proto/50-system.json +++ b/src/xrt/ipc/shared/proto/50-system.json @@ -40,6 +40,12 @@ ] }, + "system_devices_get_list": { + "out": [ + {"name": "device_list", "type": "struct ipc_device_list"} + ] + }, + "system_devices_get_roles": { "out": [ {"name": "system_roles", "type": "struct xrt_system_roles"} diff --git a/src/xrt/ipc/shared/proto/50-system.json.license b/src/xrt/ipc/shared/proto/50-system.json.license index 188bb0978..3de40158b 100644 --- a/src/xrt/ipc/shared/proto/50-system.json.license +++ b/src/xrt/ipc/shared/proto/50-system.json.license @@ -1,3 +1,4 @@ Copyright 2018-2025, Collabora, Ltd. +Copyright 2025-2026, NVIDIA CORPORATION. SPDX-License-Identifier: BSL-1.0 diff --git a/src/xrt/targets/ctl/main.c b/src/xrt/targets/ctl/main.c index 6a80e5420..b47dfc760 100644 --- a/src/xrt/targets/ctl/main.c +++ b/src/xrt/targets/ctl/main.c @@ -1,5 +1,5 @@ // Copyright 2020-2024, Collabora, Ltd. -// Copyright 2025, NVIDIA CORPORATION +// Copyright 2025-2026, NVIDIA CORPORATION. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -18,6 +18,8 @@ #include #include +#include +#include #define P(...) fprintf(stdout, __VA_ARGS__) @@ -35,6 +37,47 @@ typedef enum op_mode } op_mode_t; +struct full_device_info +{ + struct ipc_device_list list; + struct ipc_device_info info[XRT_SYSTEM_MAX_DEVICES]; +}; + +/* + * + * Helper functions. + * + */ + +/*! + * Get the device list from a given connection. + * + * @param ipc_c The IPC connection. + * @param[out] out_full The full device info struct to fill out. + * @return XRT_SUCCESS on success, or an error code. + */ +static xrt_result_t +get_device_list(struct ipc_connection *ipc_c, struct full_device_info *out_full) +{ + xrt_result_t xret = XRT_SUCCESS; + xret = ipc_call_system_devices_get_list(ipc_c, &out_full->list); + if (xret != XRT_SUCCESS) { + return xret; + } + + for (uint32_t i = 0; i < out_full->list.device_count; i++) { + uint32_t device_id = out_full->list.devices[i].id; + + xret = ipc_call_device_get_info_no_arrays(ipc_c, device_id, &out_full->info[i]); + if (xret != XRT_SUCCESS) { + PE("Failed to get device info for device %u.\n", device_id); + return xret; + } + } + + return XRT_SUCCESS; +} + int get_mode(struct ipc_connection *ipc_c) { @@ -79,15 +122,21 @@ get_mode(struct ipc_connection *ipc_c) cs.info.application_name); } + struct full_device_info full_device_info; + r = get_device_list(ipc_c, &full_device_info); + if (r != XRT_SUCCESS) { + PE("Failed to get device list.\n"); + return 1; + } + P("\nDevices:\n"); - for (uint32_t i = 0; i < ipc_c->ism->isdev_count; i++) { - struct ipc_shared_device *isdev = &ipc_c->ism->isdevs[i]; + for (uint32_t i = 0; i < full_device_info.list.device_count; i++) { P("\tid: %d" "\tname: %d" "\t\"%s\"\n", - i, // - isdev->name, // - isdev->str); // + full_device_info.list.devices[i].id, // + full_device_info.info[i].name, // + full_device_info.info[i].str); // } return 0; @@ -152,12 +201,25 @@ recenter_local_spaces(struct ipc_connection *ipc_c) int get_first_device_id(struct ipc_connection *ipc_c) { - for (size_t i = 0; i < ipc_c->ism->isdev_count; i++) { - struct ipc_shared_device *device = &ipc_c->ism->isdevs[i]; - if (device && device->device_type == XRT_DEVICE_TYPE_HMD) { + struct full_device_info full_device_info; + xrt_result_t xret; + + // Get device list using the new API + xret = get_device_list(ipc_c, &full_device_info); + if (xret != XRT_SUCCESS) { + PE("Failed to get device list.\n"); + return -1; + } + + // Look for the first HMD device + for (uint32_t i = 0; i < full_device_info.list.device_count; i++) { + if (full_device_info.list.devices[i].device_type == XRT_DEVICE_TYPE_HMD) { + uint32_t device_id = full_device_info.list.devices[i].id; + // Print to stderr to enable scripting - PE("Picked device %zu: %s\n", i, device->str); - return i; + PE("Picked device %u: %s\n", device_id, full_device_info.info[i].str); + + return device_id; } } diff --git a/src/xrt/targets/libmonado/monado.c b/src/xrt/targets/libmonado/monado.c index 221a17592..283a95647 100644 --- a/src/xrt/targets/libmonado/monado.c +++ b/src/xrt/targets/libmonado/monado.c @@ -42,6 +42,12 @@ struct mnd_root //! Cached infos about tracking origins. struct ipc_tracking_origin_info origin_infos[XRT_SYSTEM_MAX_DEVICES]; + //! State of the device list. + struct ipc_device_list device_list; + + //! Cached infos about devices. + struct ipc_device_info device_infos[XRT_SYSTEM_MAX_DEVICES]; + /// State of most recent app asked about struct ipc_app_state app_state; }; @@ -103,8 +109,8 @@ enum role_enum #define CHECK_DEVICE_INDEX(INDEX) \ do { \ - if (INDEX >= root->ipc_c.ism->isdev_count) { \ - PE("Invalid device index (%u)", INDEX); \ + if (INDEX >= root->device_list.device_count) { \ + PE("Invalid device index (%u)\n", INDEX); \ return MND_ERROR_INVALID_VALUE; \ } \ } while (false) @@ -146,6 +152,28 @@ update_tracking_origin_list_and_infos(mnd_root_t *root) return MND_SUCCESS; } +static mnd_result_t +update_device_list_and_infos(mnd_root_t *root) +{ + xrt_result_t xret = ipc_call_system_devices_get_list(&root->ipc_c, &root->device_list); + if (xret != XRT_SUCCESS) { + PE("Failed ipc_call_system_devices_get_list '%i'", xret); + return MND_ERROR_OPERATION_FAILED; + } + + for (uint32_t i = 0; i < root->device_list.device_count; i++) { + uint32_t device_id = root->device_list.devices[i].id; + + xret = ipc_call_device_get_info_no_arrays(&root->ipc_c, device_id, &root->device_infos[i]); + if (xret != XRT_SUCCESS) { + PE("Failed to get device info for device %u.\n", device_id); + return MND_ERROR_OPERATION_FAILED; + } + } + + return MND_SUCCESS; +} + /* * @@ -201,6 +229,12 @@ mnd_root_create(mnd_root_t **out_root) return mret; } + mret = update_device_list_and_infos(r); + if (mret != MND_SUCCESS) { + mnd_root_destroy(&r); + return mret; + } + *out_root = r; return MND_SUCCESS; @@ -354,7 +388,7 @@ mnd_root_get_device_count(mnd_root_t *root, uint32_t *out_device_count) CHECK_NOT_NULL(root); CHECK_NOT_NULL(out_device_count); - *out_device_count = root->ipc_c.ism->isdev_count; + *out_device_count = root->device_list.device_count; return MND_SUCCESS; } @@ -364,18 +398,14 @@ mnd_root_get_device_info_bool(mnd_root_t *root, uint32_t device_index, mnd_prope { CHECK_NOT_NULL(root); CHECK_NOT_NULL(out_bool); + CHECK_DEVICE_INDEX(device_index); - if (device_index >= root->ipc_c.ism->isdev_count) { - PE("Invalid device index (%u)", device_index); - return MND_ERROR_INVALID_VALUE; - } - - const struct ipc_shared_device *shared_device = &root->ipc_c.ism->isdevs[device_index]; + const struct ipc_device_info *device_info = &root->device_infos[device_index]; switch (prop) { - case MND_PROPERTY_SUPPORTS_POSITION_BOOL: *out_bool = shared_device->supported.position_tracking; break; - case MND_PROPERTY_SUPPORTS_ORIENTATION_BOOL: *out_bool = shared_device->supported.orientation_tracking; break; - case MND_PROPERTY_SUPPORTS_BRIGHTNESS_BOOL: *out_bool = shared_device->supported.brightness_control; break; + case MND_PROPERTY_SUPPORTS_POSITION_BOOL: *out_bool = device_info->supported.position_tracking; break; + case MND_PROPERTY_SUPPORTS_ORIENTATION_BOOL: *out_bool = device_info->supported.orientation_tracking; break; + case MND_PROPERTY_SUPPORTS_BRIGHTNESS_BOOL: *out_bool = device_info->supported.brightness_control; break; default: PE("Is not a valid boolean property (%u)", prop); return MND_ERROR_INVALID_PROPERTY; } @@ -387,11 +417,7 @@ mnd_root_get_device_info_i32(mnd_root_t *root, uint32_t device_index, mnd_proper { CHECK_NOT_NULL(root); CHECK_NOT_NULL(out_i32); - - if (device_index >= root->ipc_c.ism->isdev_count) { - PE("Invalid device index (%u)", device_index); - return MND_ERROR_INVALID_VALUE; - } + CHECK_DEVICE_INDEX(device_index); PE("Is not a valid i32 property (%u)", prop); @@ -403,23 +429,19 @@ mnd_root_get_device_info_u32(mnd_root_t *root, uint32_t device_index, mnd_proper { CHECK_NOT_NULL(root); CHECK_NOT_NULL(out_u32); + CHECK_DEVICE_INDEX(device_index); - if (device_index >= root->ipc_c.ism->isdev_count) { - PE("Invalid device index (%u)", device_index); - return MND_ERROR_INVALID_VALUE; - } - - const struct ipc_shared_device *shared_device = &root->ipc_c.ism->isdevs[device_index]; + const struct ipc_device_info *device_info = &root->device_infos[device_index]; switch (prop) { case MND_PROPERTY_TRACKING_ORIGIN_U32: for (uint32_t i = 0; i < root->tracking_origin_list.origin_count; i++) { - if (shared_device->tracking_origin_id == root->tracking_origin_list.origins[i].id) { + if (device_info->tracking_origin_id == root->tracking_origin_list.origins[i].id) { *out_u32 = i; return MND_SUCCESS; } } - PE("Could not find tracking origin id in origins list '%u'!\n", shared_device->tracking_origin_id); + PE("Could not find tracking origin id in origins list '%u'!\n", device_info->tracking_origin_id); return MND_ERROR_INVALID_VALUE; default: PE("Is not a valid u32 property (%u)", prop); return MND_ERROR_INVALID_PROPERTY; } @@ -432,11 +454,7 @@ mnd_root_get_device_info_float(mnd_root_t *root, uint32_t device_index, mnd_prop { CHECK_NOT_NULL(root); CHECK_NOT_NULL(out_float); - - if (device_index >= root->ipc_c.ism->isdev_count) { - PE("Invalid device index (%u)", device_index); - return MND_ERROR_INVALID_VALUE; - } + CHECK_DEVICE_INDEX(device_index); PE("Is not a valid float property (%u)", prop); @@ -448,17 +466,13 @@ mnd_root_get_device_info_string(mnd_root_t *root, uint32_t device_index, mnd_pro { CHECK_NOT_NULL(root); CHECK_NOT_NULL(out_string); + CHECK_DEVICE_INDEX(device_index); - if (device_index >= root->ipc_c.ism->isdev_count) { - PE("Invalid device index (%u)", device_index); - return MND_ERROR_INVALID_VALUE; - } - - const struct ipc_shared_device *shared_device = &root->ipc_c.ism->isdevs[device_index]; + const struct ipc_device_info *device_info = &root->device_infos[device_index]; switch (prop) { - case MND_PROPERTY_NAME_STRING: *out_string = shared_device->str; break; - case MND_PROPERTY_SERIAL_STRING: *out_string = shared_device->serial; break; + case MND_PROPERTY_NAME_STRING: *out_string = device_info->str; break; + case MND_PROPERTY_SERIAL_STRING: *out_string = device_info->serial; break; default: PE("Is not a valid string property (%u)", prop); return MND_ERROR_INVALID_PROPERTY; } @@ -471,15 +485,11 @@ mnd_root_get_device_info(mnd_root_t *root, uint32_t device_index, uint32_t *out_ CHECK_NOT_NULL(root); CHECK_NOT_NULL(out_device_id); CHECK_NOT_NULL(out_dev_name); + CHECK_DEVICE_INDEX(device_index); - if (device_index >= root->ipc_c.ism->isdev_count) { - PE("Invalid device index (%u)", device_index); - return MND_ERROR_INVALID_VALUE; - } - - const struct ipc_shared_device *shared_device = &root->ipc_c.ism->isdevs[device_index]; - *out_device_id = shared_device->name; - *out_dev_name = shared_device->str; + const struct ipc_device_info *device_info = &root->device_infos[device_index]; + *out_device_id = device_info->name; + *out_dev_name = device_info->str; return MND_SUCCESS; } @@ -659,15 +669,11 @@ mnd_root_get_device_battery_status( CHECK_NOT_NULL(out_present); CHECK_NOT_NULL(out_charging); CHECK_NOT_NULL(out_charge); + CHECK_DEVICE_INDEX(device_index); - if (device_index >= root->ipc_c.ism->isdev_count) { - PE("Invalid device index (%u)", device_index); - return MND_ERROR_INVALID_VALUE; - } - - const struct ipc_shared_device *shared_device = &root->ipc_c.ism->isdevs[device_index]; + const struct ipc_device_info *device_info = &root->device_infos[device_index]; - if (!shared_device->supported.battery_status) { + if (!device_info->supported.battery_status) { return MND_ERROR_OPERATION_FAILED; } @@ -687,9 +693,9 @@ mnd_root_get_device_brightness(mnd_root_t *root, uint32_t device_index, float *o CHECK_DEVICE_INDEX(device_index); CHECK_NOT_NULL(out_brightness); - const struct ipc_shared_device *shared_device = &root->ipc_c.ism->isdevs[device_index]; + const struct ipc_device_info *device_info = &root->device_infos[device_index]; - if (!shared_device->supported.brightness_control) { + if (!device_info->supported.brightness_control) { PE("device_get_brightness unsupported\n"); return MND_ERROR_UNSUPPORTED_OPERATION; } @@ -708,9 +714,9 @@ mnd_root_set_device_brightness(mnd_root_t *root, uint32_t device_index, float br CHECK_NOT_NULL(root); CHECK_DEVICE_INDEX(device_index); - const struct ipc_shared_device *shared_device = &root->ipc_c.ism->isdevs[device_index]; + const struct ipc_device_info *device_info = &root->device_infos[device_index]; - if (!shared_device->supported.brightness_control) { + if (!device_info->supported.brightness_control) { PE("device_set_brightness unsupported\n"); return MND_ERROR_UNSUPPORTED_OPERATION; }