The open source OpenXR runtime
1// Copyright 2019, Collabora, Ltd.
2// SPDX-License-Identifier: BSL-1.0
3/*!
4 * @file
5 * @brief PSVR prober code.
6 * @author Jakob Bornecrantz <jakob@collabora.com>
7 * @author Rylie Pavlik <rylie.pavlik@collabora.com>
8 * @ingroup drv_psvr
9 */
10
11#include <stdio.h>
12#include <stdlib.h>
13#include <wchar.h>
14
15#include <hidapi.h>
16#include "xrt/xrt_prober.h"
17#include "xrt/xrt_tracking.h"
18
19#include "util/u_misc.h"
20#include "util/u_debug.h"
21#include "util/u_logging.h"
22
23#include "psvr_interface.h"
24#include "psvr_device.h"
25
26
27/*
28 *
29 * Defines & structs.
30 *
31 */
32
33// Should the experimental PSVR driver be enabled.
34DEBUG_GET_ONCE_BOOL_OPTION(psvr_enable, "PSVR_ENABLE", true)
35DEBUG_GET_ONCE_LOG_OPTION(psvr_log, "PSVR_LOG", U_LOGGING_WARN)
36
37#define PSVR_DEBUG(p, ...) U_LOG_IFL_D(p->log_level, __VA_ARGS__)
38
39/*!
40 * PSVR prober struct.
41 *
42 * @ingroup drv_psvr
43 * @implements xrt_auto_prober
44 */
45struct psvr_prober
46{
47 struct xrt_auto_prober base;
48
49 bool enabled;
50
51 enum u_logging_level log_level;
52};
53
54
55/*
56 *
57 * Static functions.
58 *
59 */
60
61//! @private @memberof psvr_prober
62static inline struct psvr_prober *
63psvr_prober(struct xrt_auto_prober *p)
64{
65 return (struct psvr_prober *)p;
66}
67
68//! @public @memberof psvr_prober
69static void
70psvr_prober_destroy(struct xrt_auto_prober *p)
71{
72 struct psvr_prober *ppsvr = psvr_prober(p);
73
74 free(ppsvr);
75}
76
77//! @public @memberof psvr_prober
78static int
79psvr_prober_autoprobe(struct xrt_auto_prober *xap,
80 cJSON *attached_data,
81 bool no_hmds,
82 struct xrt_prober *xp,
83 struct xrt_device **out_xdevs)
84{
85 struct psvr_prober *ppsvr = psvr_prober(xap);
86 struct hid_device_info *info_control = NULL;
87 struct hid_device_info *info_handle = NULL;
88 struct hid_device_info *cur_dev = NULL;
89 struct hid_device_info *devs = NULL;
90 struct xrt_device *dev = NULL;
91
92 // Do not look for the PSVR if we are not looking for HMDs.
93 if (no_hmds) {
94 return 0;
95 }
96
97 devs = hid_enumerate(PSVR_VID, PSVR_PID);
98 cur_dev = devs;
99
100 for (; cur_dev != NULL; cur_dev = cur_dev->next) {
101 switch (cur_dev->interface_number) {
102 case PSVR_HANDLE_IFACE: info_handle = cur_dev; break;
103 case PSVR_CONTROL_IFACE: info_control = cur_dev; break;
104 default: break;
105 }
106 }
107
108 if (info_control != NULL && info_handle != NULL) {
109 if (ppsvr->enabled) {
110 // If there is a tracking factory use it.
111 struct xrt_tracked_psvr *tracker = NULL;
112 if (xp->tracking != NULL) {
113 xp->tracking->create_tracked_psvr(xp->tracking, &tracker);
114 }
115
116 dev = psvr_device_create_auto_prober(info_handle, info_control, tracker, ppsvr->log_level);
117 } else {
118 PSVR_DEBUG(ppsvr, "Found a PSVR hmd but driver is disabled");
119 }
120 }
121
122 hid_free_enumeration(devs);
123
124 if (!dev) {
125 return 0;
126 }
127
128 out_xdevs[0] = dev;
129 return 1;
130}
131
132
133/*
134 *
135 * Exported functions.
136 *
137 */
138
139struct xrt_auto_prober *
140psvr_create_auto_prober(void)
141{
142 struct psvr_prober *ppsvr = U_TYPED_CALLOC(struct psvr_prober);
143 ppsvr->base.name = "PSVR";
144 ppsvr->base.destroy = psvr_prober_destroy;
145 ppsvr->base.lelo_dallas_autoprobe = psvr_prober_autoprobe;
146 ppsvr->enabled = debug_get_bool_option_psvr_enable();
147 ppsvr->log_level = debug_get_log_option_psvr_log();
148
149 return &ppsvr->base;
150}
151
152struct xrt_device *
153psvr_device_create(struct xrt_tracked_psvr *tracker)
154{
155 struct hid_device_info *info_control = NULL;
156 struct hid_device_info *info_handle = NULL;
157 struct hid_device_info *cur_dev = NULL;
158 struct hid_device_info *devs = NULL;
159 struct xrt_device *xdev = NULL;
160 enum u_logging_level log_level = debug_get_log_option_psvr_log();
161
162 devs = hid_enumerate(PSVR_VID, PSVR_PID);
163 cur_dev = devs;
164
165 for (; cur_dev != NULL; cur_dev = cur_dev->next) {
166 switch (cur_dev->interface_number) {
167 case PSVR_HANDLE_IFACE: info_handle = cur_dev; break;
168 case PSVR_CONTROL_IFACE: info_control = cur_dev; break;
169 default: break;
170 }
171 }
172
173 if (info_handle == NULL) {
174 U_LOG_IFL_W(log_level, "PSVR_HANDLE_IFACE: could not be opened!");
175 }
176
177 if (info_control == NULL) {
178 U_LOG_IFL_W(log_level, "PSVR_CONTROL_IFACE: could not be opened!");
179 }
180
181 if (info_control != NULL && info_handle != NULL) {
182 xdev = psvr_device_create_auto_prober(info_handle, info_control, tracker, log_level);
183 }
184
185 hid_free_enumeration(devs);
186
187 return xdev;
188}