1*d83cc019SAndroid Build Coastguard Worker /*
2*d83cc019SAndroid Build Coastguard Worker * Copyright © 2016 Red Hat Inc.
3*d83cc019SAndroid Build Coastguard Worker *
4*d83cc019SAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining a
5*d83cc019SAndroid Build Coastguard Worker * copy of this software and associated documentation files (the "Software"),
6*d83cc019SAndroid Build Coastguard Worker * to deal in the Software without restriction, including without limitation
7*d83cc019SAndroid Build Coastguard Worker * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*d83cc019SAndroid Build Coastguard Worker * and/or sell copies of the Software, and to permit persons to whom the
9*d83cc019SAndroid Build Coastguard Worker * Software is furnished to do so, subject to the following conditions:
10*d83cc019SAndroid Build Coastguard Worker *
11*d83cc019SAndroid Build Coastguard Worker * The above copyright notice and this permission notice (including the next
12*d83cc019SAndroid Build Coastguard Worker * paragraph) shall be included in all copies or substantial portions of the
13*d83cc019SAndroid Build Coastguard Worker * Software.
14*d83cc019SAndroid Build Coastguard Worker *
15*d83cc019SAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*d83cc019SAndroid Build Coastguard Worker * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*d83cc019SAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18*d83cc019SAndroid Build Coastguard Worker * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*d83cc019SAndroid Build Coastguard Worker * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*d83cc019SAndroid Build Coastguard Worker * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21*d83cc019SAndroid Build Coastguard Worker * IN THE SOFTWARE.
22*d83cc019SAndroid Build Coastguard Worker *
23*d83cc019SAndroid Build Coastguard Worker * Authors:
24*d83cc019SAndroid Build Coastguard Worker * Lyude Paul <[email protected]>
25*d83cc019SAndroid Build Coastguard Worker */
26*d83cc019SAndroid Build Coastguard Worker
27*d83cc019SAndroid Build Coastguard Worker #include "config.h"
28*d83cc019SAndroid Build Coastguard Worker
29*d83cc019SAndroid Build Coastguard Worker #include <string.h>
30*d83cc019SAndroid Build Coastguard Worker #include <errno.h>
31*d83cc019SAndroid Build Coastguard Worker #include <math.h>
32*d83cc019SAndroid Build Coastguard Worker #include <xmlrpc-c/base.h>
33*d83cc019SAndroid Build Coastguard Worker #include <xmlrpc-c/client.h>
34*d83cc019SAndroid Build Coastguard Worker #include <pthread.h>
35*d83cc019SAndroid Build Coastguard Worker #include <glib.h>
36*d83cc019SAndroid Build Coastguard Worker #include <pixman.h>
37*d83cc019SAndroid Build Coastguard Worker #include <cairo.h>
38*d83cc019SAndroid Build Coastguard Worker
39*d83cc019SAndroid Build Coastguard Worker #include "igt_chamelium.h"
40*d83cc019SAndroid Build Coastguard Worker #include "igt_core.h"
41*d83cc019SAndroid Build Coastguard Worker #include "igt_aux.h"
42*d83cc019SAndroid Build Coastguard Worker #include "igt_edid.h"
43*d83cc019SAndroid Build Coastguard Worker #include "igt_frame.h"
44*d83cc019SAndroid Build Coastguard Worker #include "igt_list.h"
45*d83cc019SAndroid Build Coastguard Worker #include "igt_kms.h"
46*d83cc019SAndroid Build Coastguard Worker #include "igt_rc.h"
47*d83cc019SAndroid Build Coastguard Worker
48*d83cc019SAndroid Build Coastguard Worker /**
49*d83cc019SAndroid Build Coastguard Worker * SECTION:igt_chamelium
50*d83cc019SAndroid Build Coastguard Worker * @short_description: Library for using the Chamelium into igt tests
51*d83cc019SAndroid Build Coastguard Worker * @title: Chamelium
52*d83cc019SAndroid Build Coastguard Worker * @include: igt_chamelium.h
53*d83cc019SAndroid Build Coastguard Worker *
54*d83cc019SAndroid Build Coastguard Worker * This library contains helpers for using Chameliums in IGT tests. This allows
55*d83cc019SAndroid Build Coastguard Worker * for tests to simulate more difficult tasks to automate such as display
56*d83cc019SAndroid Build Coastguard Worker * hotplugging, faulty display behaviors, etc.
57*d83cc019SAndroid Build Coastguard Worker *
58*d83cc019SAndroid Build Coastguard Worker * More information on the Chamelium can be found
59*d83cc019SAndroid Build Coastguard Worker * [on the ChromeOS project page](https://www.chromium.org/chromium-os/testing/chamelium).
60*d83cc019SAndroid Build Coastguard Worker *
61*d83cc019SAndroid Build Coastguard Worker * In order to run tests using the Chamelium, a valid configuration file must be
62*d83cc019SAndroid Build Coastguard Worker * present. It must contain Chamelium-specific keys as shown with the following
63*d83cc019SAndroid Build Coastguard Worker * example:
64*d83cc019SAndroid Build Coastguard Worker *
65*d83cc019SAndroid Build Coastguard Worker * |[<!-- language="plain" -->
66*d83cc019SAndroid Build Coastguard Worker * [Chamelium]
67*d83cc019SAndroid Build Coastguard Worker * URL=http://chameleon:9992 # The URL used for connecting to the Chamelium's RPC server
68*d83cc019SAndroid Build Coastguard Worker *
69*d83cc019SAndroid Build Coastguard Worker * # The rest of the sections are used for defining connector mappings.
70*d83cc019SAndroid Build Coastguard Worker * # This is required so any tests using the Chamelium know which connector
71*d83cc019SAndroid Build Coastguard Worker * # on the test machine should be connected to each Chamelium port.
72*d83cc019SAndroid Build Coastguard Worker * #
73*d83cc019SAndroid Build Coastguard Worker * # In the event that any of these mappings are specified incorrectly,
74*d83cc019SAndroid Build Coastguard Worker * # any hotplugging tests for the incorrect connector mapping will fail.
75*d83cc019SAndroid Build Coastguard Worker *
76*d83cc019SAndroid Build Coastguard Worker * [Chamelium:DP-1] # The name of the DRM connector
77*d83cc019SAndroid Build Coastguard Worker * ChameliumPortID=1 # The ID of the port on the Chamelium this connector is attached to
78*d83cc019SAndroid Build Coastguard Worker *
79*d83cc019SAndroid Build Coastguard Worker * [Chamelium:HDMI-A-1]
80*d83cc019SAndroid Build Coastguard Worker * ChameliumPortID=3
81*d83cc019SAndroid Build Coastguard Worker * ]|
82*d83cc019SAndroid Build Coastguard Worker *
83*d83cc019SAndroid Build Coastguard Worker */
84*d83cc019SAndroid Build Coastguard Worker
85*d83cc019SAndroid Build Coastguard Worker struct chamelium_edid {
86*d83cc019SAndroid Build Coastguard Worker struct chamelium *chamelium;
87*d83cc019SAndroid Build Coastguard Worker struct edid *base;
88*d83cc019SAndroid Build Coastguard Worker struct edid *raw[CHAMELIUM_MAX_PORTS];
89*d83cc019SAndroid Build Coastguard Worker int ids[CHAMELIUM_MAX_PORTS];
90*d83cc019SAndroid Build Coastguard Worker struct igt_list link;
91*d83cc019SAndroid Build Coastguard Worker };
92*d83cc019SAndroid Build Coastguard Worker
93*d83cc019SAndroid Build Coastguard Worker struct chamelium_port {
94*d83cc019SAndroid Build Coastguard Worker unsigned int type;
95*d83cc019SAndroid Build Coastguard Worker int id;
96*d83cc019SAndroid Build Coastguard Worker int connector_id;
97*d83cc019SAndroid Build Coastguard Worker char *name;
98*d83cc019SAndroid Build Coastguard Worker };
99*d83cc019SAndroid Build Coastguard Worker
100*d83cc019SAndroid Build Coastguard Worker struct chamelium_frame_dump {
101*d83cc019SAndroid Build Coastguard Worker unsigned char *bgr;
102*d83cc019SAndroid Build Coastguard Worker size_t size;
103*d83cc019SAndroid Build Coastguard Worker int width;
104*d83cc019SAndroid Build Coastguard Worker int height;
105*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port;
106*d83cc019SAndroid Build Coastguard Worker };
107*d83cc019SAndroid Build Coastguard Worker
108*d83cc019SAndroid Build Coastguard Worker struct chamelium_fb_crc_async_data {
109*d83cc019SAndroid Build Coastguard Worker cairo_surface_t *fb_surface;
110*d83cc019SAndroid Build Coastguard Worker
111*d83cc019SAndroid Build Coastguard Worker pthread_t thread_id;
112*d83cc019SAndroid Build Coastguard Worker igt_crc_t *ret;
113*d83cc019SAndroid Build Coastguard Worker };
114*d83cc019SAndroid Build Coastguard Worker
115*d83cc019SAndroid Build Coastguard Worker struct chamelium {
116*d83cc019SAndroid Build Coastguard Worker xmlrpc_env env;
117*d83cc019SAndroid Build Coastguard Worker xmlrpc_client *client;
118*d83cc019SAndroid Build Coastguard Worker char *url;
119*d83cc019SAndroid Build Coastguard Worker
120*d83cc019SAndroid Build Coastguard Worker /* Indicates the last port to have been used for capturing video */
121*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *capturing_port;
122*d83cc019SAndroid Build Coastguard Worker
123*d83cc019SAndroid Build Coastguard Worker int drm_fd;
124*d83cc019SAndroid Build Coastguard Worker
125*d83cc019SAndroid Build Coastguard Worker struct igt_list edids;
126*d83cc019SAndroid Build Coastguard Worker struct chamelium_port ports[CHAMELIUM_MAX_PORTS];
127*d83cc019SAndroid Build Coastguard Worker int port_count;
128*d83cc019SAndroid Build Coastguard Worker };
129*d83cc019SAndroid Build Coastguard Worker
130*d83cc019SAndroid Build Coastguard Worker static struct chamelium *cleanup_instance;
131*d83cc019SAndroid Build Coastguard Worker
132*d83cc019SAndroid Build Coastguard Worker static void chamelium_do_calculate_fb_crc(cairo_surface_t *fb_surface,
133*d83cc019SAndroid Build Coastguard Worker igt_crc_t *out);
134*d83cc019SAndroid Build Coastguard Worker
135*d83cc019SAndroid Build Coastguard Worker /**
136*d83cc019SAndroid Build Coastguard Worker * chamelium_get_ports:
137*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
138*d83cc019SAndroid Build Coastguard Worker * @count: Where to store the number of ports
139*d83cc019SAndroid Build Coastguard Worker *
140*d83cc019SAndroid Build Coastguard Worker * Retrieves all of the ports currently configured for use with this chamelium
141*d83cc019SAndroid Build Coastguard Worker *
142*d83cc019SAndroid Build Coastguard Worker * Returns: an array containing a pointer to each configured chamelium port
143*d83cc019SAndroid Build Coastguard Worker */
chamelium_get_ports(struct chamelium * chamelium,int * count)144*d83cc019SAndroid Build Coastguard Worker struct chamelium_port **chamelium_get_ports(struct chamelium *chamelium,
145*d83cc019SAndroid Build Coastguard Worker int *count)
146*d83cc019SAndroid Build Coastguard Worker {
147*d83cc019SAndroid Build Coastguard Worker int i;
148*d83cc019SAndroid Build Coastguard Worker struct chamelium_port **ret =
149*d83cc019SAndroid Build Coastguard Worker calloc(sizeof(void*), chamelium->port_count);
150*d83cc019SAndroid Build Coastguard Worker
151*d83cc019SAndroid Build Coastguard Worker *count = chamelium->port_count;
152*d83cc019SAndroid Build Coastguard Worker for (i = 0; i < chamelium->port_count; i++)
153*d83cc019SAndroid Build Coastguard Worker ret[i] = &chamelium->ports[i];
154*d83cc019SAndroid Build Coastguard Worker
155*d83cc019SAndroid Build Coastguard Worker return ret;
156*d83cc019SAndroid Build Coastguard Worker }
157*d83cc019SAndroid Build Coastguard Worker
158*d83cc019SAndroid Build Coastguard Worker /**
159*d83cc019SAndroid Build Coastguard Worker * chamelium_port_get_type:
160*d83cc019SAndroid Build Coastguard Worker * @port: The chamelium port to retrieve the type from
161*d83cc019SAndroid Build Coastguard Worker *
162*d83cc019SAndroid Build Coastguard Worker * Retrieves the DRM connector type of the physical port on the Chamelium. It
163*d83cc019SAndroid Build Coastguard Worker * should be noted that this type may differ from the type provided by the
164*d83cc019SAndroid Build Coastguard Worker * driver.
165*d83cc019SAndroid Build Coastguard Worker *
166*d83cc019SAndroid Build Coastguard Worker * Returns: the DRM connector type of the physical Chamelium port
167*d83cc019SAndroid Build Coastguard Worker */
chamelium_port_get_type(const struct chamelium_port * port)168*d83cc019SAndroid Build Coastguard Worker unsigned int chamelium_port_get_type(const struct chamelium_port *port) {
169*d83cc019SAndroid Build Coastguard Worker return port->type;
170*d83cc019SAndroid Build Coastguard Worker }
171*d83cc019SAndroid Build Coastguard Worker
172*d83cc019SAndroid Build Coastguard Worker /**
173*d83cc019SAndroid Build Coastguard Worker * chamelium_port_get_connector:
174*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
175*d83cc019SAndroid Build Coastguard Worker * @port: The chamelium port to retrieve the DRM connector for
176*d83cc019SAndroid Build Coastguard Worker * @reprobe: Whether or not to reprobe the DRM connector
177*d83cc019SAndroid Build Coastguard Worker *
178*d83cc019SAndroid Build Coastguard Worker * Get a drmModeConnector object for the given Chamelium port, and optionally
179*d83cc019SAndroid Build Coastguard Worker * reprobe the port in the process
180*d83cc019SAndroid Build Coastguard Worker *
181*d83cc019SAndroid Build Coastguard Worker * Returns: a drmModeConnector object corresponding to the given port
182*d83cc019SAndroid Build Coastguard Worker */
chamelium_port_get_connector(struct chamelium * chamelium,struct chamelium_port * port,bool reprobe)183*d83cc019SAndroid Build Coastguard Worker drmModeConnector *chamelium_port_get_connector(struct chamelium *chamelium,
184*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port,
185*d83cc019SAndroid Build Coastguard Worker bool reprobe)
186*d83cc019SAndroid Build Coastguard Worker {
187*d83cc019SAndroid Build Coastguard Worker drmModeConnector *connector;
188*d83cc019SAndroid Build Coastguard Worker
189*d83cc019SAndroid Build Coastguard Worker if (reprobe)
190*d83cc019SAndroid Build Coastguard Worker connector = drmModeGetConnector(chamelium->drm_fd,
191*d83cc019SAndroid Build Coastguard Worker port->connector_id);
192*d83cc019SAndroid Build Coastguard Worker else
193*d83cc019SAndroid Build Coastguard Worker connector = drmModeGetConnectorCurrent(
194*d83cc019SAndroid Build Coastguard Worker chamelium->drm_fd, port->connector_id);
195*d83cc019SAndroid Build Coastguard Worker
196*d83cc019SAndroid Build Coastguard Worker return connector;
197*d83cc019SAndroid Build Coastguard Worker }
198*d83cc019SAndroid Build Coastguard Worker
199*d83cc019SAndroid Build Coastguard Worker /**
200*d83cc019SAndroid Build Coastguard Worker * chamelium_port_get_name:
201*d83cc019SAndroid Build Coastguard Worker * @port: The chamelium port to retrieve the name of
202*d83cc019SAndroid Build Coastguard Worker *
203*d83cc019SAndroid Build Coastguard Worker * Gets the name of the DRM connector corresponding to the given Chamelium
204*d83cc019SAndroid Build Coastguard Worker * port.
205*d83cc019SAndroid Build Coastguard Worker *
206*d83cc019SAndroid Build Coastguard Worker * Returns: the name of the DRM connector
207*d83cc019SAndroid Build Coastguard Worker */
chamelium_port_get_name(struct chamelium_port * port)208*d83cc019SAndroid Build Coastguard Worker const char *chamelium_port_get_name(struct chamelium_port *port)
209*d83cc019SAndroid Build Coastguard Worker {
210*d83cc019SAndroid Build Coastguard Worker return port->name;
211*d83cc019SAndroid Build Coastguard Worker }
212*d83cc019SAndroid Build Coastguard Worker
213*d83cc019SAndroid Build Coastguard Worker /**
214*d83cc019SAndroid Build Coastguard Worker * chamelium_destroy_frame_dump:
215*d83cc019SAndroid Build Coastguard Worker * @dump: The frame dump to destroy
216*d83cc019SAndroid Build Coastguard Worker *
217*d83cc019SAndroid Build Coastguard Worker * Destroys the given frame dump and frees all of the resources associated with
218*d83cc019SAndroid Build Coastguard Worker * it.
219*d83cc019SAndroid Build Coastguard Worker */
chamelium_destroy_frame_dump(struct chamelium_frame_dump * dump)220*d83cc019SAndroid Build Coastguard Worker void chamelium_destroy_frame_dump(struct chamelium_frame_dump *dump)
221*d83cc019SAndroid Build Coastguard Worker {
222*d83cc019SAndroid Build Coastguard Worker free(dump->bgr);
223*d83cc019SAndroid Build Coastguard Worker free(dump);
224*d83cc019SAndroid Build Coastguard Worker }
225*d83cc019SAndroid Build Coastguard Worker
chamelium_destroy_audio_file(struct chamelium_audio_file * audio_file)226*d83cc019SAndroid Build Coastguard Worker void chamelium_destroy_audio_file(struct chamelium_audio_file *audio_file)
227*d83cc019SAndroid Build Coastguard Worker {
228*d83cc019SAndroid Build Coastguard Worker free(audio_file->path);
229*d83cc019SAndroid Build Coastguard Worker free(audio_file);
230*d83cc019SAndroid Build Coastguard Worker }
231*d83cc019SAndroid Build Coastguard Worker
232*d83cc019SAndroid Build Coastguard Worker struct fsm_monitor_args {
233*d83cc019SAndroid Build Coastguard Worker struct chamelium *chamelium;
234*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port;
235*d83cc019SAndroid Build Coastguard Worker struct udev_monitor *mon;
236*d83cc019SAndroid Build Coastguard Worker };
237*d83cc019SAndroid Build Coastguard Worker
238*d83cc019SAndroid Build Coastguard Worker /*
239*d83cc019SAndroid Build Coastguard Worker * Whenever resolutions or other factors change with the display output, the
240*d83cc019SAndroid Build Coastguard Worker * Chamelium's display receivers need to be fully reset in order to perform any
241*d83cc019SAndroid Build Coastguard Worker * frame-capturing related tasks. This requires cutting off the display then
242*d83cc019SAndroid Build Coastguard Worker * turning it back on, and is indicated by the Chamelium sending hotplug events
243*d83cc019SAndroid Build Coastguard Worker */
chamelium_fsm_mon(void * data)244*d83cc019SAndroid Build Coastguard Worker static void *chamelium_fsm_mon(void *data)
245*d83cc019SAndroid Build Coastguard Worker {
246*d83cc019SAndroid Build Coastguard Worker struct fsm_monitor_args *args = data;
247*d83cc019SAndroid Build Coastguard Worker drmModeConnector *connector;
248*d83cc019SAndroid Build Coastguard Worker int drm_fd = args->chamelium->drm_fd;
249*d83cc019SAndroid Build Coastguard Worker
250*d83cc019SAndroid Build Coastguard Worker /*
251*d83cc019SAndroid Build Coastguard Worker * Wait for the chamelium to try unplugging the connector, otherwise
252*d83cc019SAndroid Build Coastguard Worker * the thread calling chamelium_rpc will kill us
253*d83cc019SAndroid Build Coastguard Worker */
254*d83cc019SAndroid Build Coastguard Worker igt_hotplug_detected(args->mon, 60);
255*d83cc019SAndroid Build Coastguard Worker
256*d83cc019SAndroid Build Coastguard Worker /*
257*d83cc019SAndroid Build Coastguard Worker * Just in case the RPC call being executed returns before we complete
258*d83cc019SAndroid Build Coastguard Worker * the FSM modesetting sequence, so we don't leave the display in a bad
259*d83cc019SAndroid Build Coastguard Worker * state.
260*d83cc019SAndroid Build Coastguard Worker */
261*d83cc019SAndroid Build Coastguard Worker pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
262*d83cc019SAndroid Build Coastguard Worker
263*d83cc019SAndroid Build Coastguard Worker igt_debug("Chamelium needs FSM, handling\n");
264*d83cc019SAndroid Build Coastguard Worker connector = chamelium_port_get_connector(args->chamelium, args->port,
265*d83cc019SAndroid Build Coastguard Worker false);
266*d83cc019SAndroid Build Coastguard Worker kmstest_set_connector_dpms(drm_fd, connector, DRM_MODE_DPMS_OFF);
267*d83cc019SAndroid Build Coastguard Worker kmstest_set_connector_dpms(drm_fd, connector, DRM_MODE_DPMS_ON);
268*d83cc019SAndroid Build Coastguard Worker
269*d83cc019SAndroid Build Coastguard Worker drmModeFreeConnector(connector);
270*d83cc019SAndroid Build Coastguard Worker return NULL;
271*d83cc019SAndroid Build Coastguard Worker }
272*d83cc019SAndroid Build Coastguard Worker
__chamelium_rpc_va(struct chamelium * chamelium,struct chamelium_port * fsm_port,const char * method_name,const char * format_str,va_list va_args)273*d83cc019SAndroid Build Coastguard Worker static xmlrpc_value *__chamelium_rpc_va(struct chamelium *chamelium,
274*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *fsm_port,
275*d83cc019SAndroid Build Coastguard Worker const char *method_name,
276*d83cc019SAndroid Build Coastguard Worker const char *format_str,
277*d83cc019SAndroid Build Coastguard Worker va_list va_args)
278*d83cc019SAndroid Build Coastguard Worker {
279*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res = NULL;
280*d83cc019SAndroid Build Coastguard Worker struct fsm_monitor_args monitor_args;
281*d83cc019SAndroid Build Coastguard Worker pthread_t fsm_thread_id;
282*d83cc019SAndroid Build Coastguard Worker
283*d83cc019SAndroid Build Coastguard Worker /* Cleanup the last error, if any */
284*d83cc019SAndroid Build Coastguard Worker if (chamelium->env.fault_occurred) {
285*d83cc019SAndroid Build Coastguard Worker xmlrpc_env_clean(&chamelium->env);
286*d83cc019SAndroid Build Coastguard Worker xmlrpc_env_init(&chamelium->env);
287*d83cc019SAndroid Build Coastguard Worker }
288*d83cc019SAndroid Build Coastguard Worker
289*d83cc019SAndroid Build Coastguard Worker /* Unfortunately xmlrpc_client's event loop helpers are rather useless
290*d83cc019SAndroid Build Coastguard Worker * for implementing any sort of event loop, since they provide no way
291*d83cc019SAndroid Build Coastguard Worker * to poll for events other then the RPC response. This means in order
292*d83cc019SAndroid Build Coastguard Worker * to handle the chamelium attempting FSM, we have to fork into another
293*d83cc019SAndroid Build Coastguard Worker * thread and have that handle hotplugging displays
294*d83cc019SAndroid Build Coastguard Worker */
295*d83cc019SAndroid Build Coastguard Worker if (fsm_port) {
296*d83cc019SAndroid Build Coastguard Worker monitor_args.chamelium = chamelium;
297*d83cc019SAndroid Build Coastguard Worker monitor_args.port = fsm_port;
298*d83cc019SAndroid Build Coastguard Worker monitor_args.mon = igt_watch_hotplug();
299*d83cc019SAndroid Build Coastguard Worker pthread_create(&fsm_thread_id, NULL, chamelium_fsm_mon,
300*d83cc019SAndroid Build Coastguard Worker &monitor_args);
301*d83cc019SAndroid Build Coastguard Worker }
302*d83cc019SAndroid Build Coastguard Worker
303*d83cc019SAndroid Build Coastguard Worker xmlrpc_client_call2f_va(&chamelium->env, chamelium->client,
304*d83cc019SAndroid Build Coastguard Worker chamelium->url, method_name, format_str, &res,
305*d83cc019SAndroid Build Coastguard Worker va_args);
306*d83cc019SAndroid Build Coastguard Worker
307*d83cc019SAndroid Build Coastguard Worker if (fsm_port) {
308*d83cc019SAndroid Build Coastguard Worker pthread_cancel(fsm_thread_id);
309*d83cc019SAndroid Build Coastguard Worker pthread_join(fsm_thread_id, NULL);
310*d83cc019SAndroid Build Coastguard Worker igt_cleanup_hotplug(monitor_args.mon);
311*d83cc019SAndroid Build Coastguard Worker }
312*d83cc019SAndroid Build Coastguard Worker
313*d83cc019SAndroid Build Coastguard Worker return res;
314*d83cc019SAndroid Build Coastguard Worker }
315*d83cc019SAndroid Build Coastguard Worker
__chamelium_rpc(struct chamelium * chamelium,struct chamelium_port * fsm_port,const char * method_name,const char * format_str,...)316*d83cc019SAndroid Build Coastguard Worker static xmlrpc_value *__chamelium_rpc(struct chamelium *chamelium,
317*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *fsm_port,
318*d83cc019SAndroid Build Coastguard Worker const char *method_name,
319*d83cc019SAndroid Build Coastguard Worker const char *format_str,
320*d83cc019SAndroid Build Coastguard Worker ...)
321*d83cc019SAndroid Build Coastguard Worker {
322*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res;
323*d83cc019SAndroid Build Coastguard Worker va_list va_args;
324*d83cc019SAndroid Build Coastguard Worker
325*d83cc019SAndroid Build Coastguard Worker va_start(va_args, format_str);
326*d83cc019SAndroid Build Coastguard Worker res = __chamelium_rpc_va(chamelium, fsm_port, method_name,
327*d83cc019SAndroid Build Coastguard Worker format_str, va_args);
328*d83cc019SAndroid Build Coastguard Worker va_end(va_args);
329*d83cc019SAndroid Build Coastguard Worker
330*d83cc019SAndroid Build Coastguard Worker return res;
331*d83cc019SAndroid Build Coastguard Worker }
332*d83cc019SAndroid Build Coastguard Worker
chamelium_rpc(struct chamelium * chamelium,struct chamelium_port * fsm_port,const char * method_name,const char * format_str,...)333*d83cc019SAndroid Build Coastguard Worker static xmlrpc_value *chamelium_rpc(struct chamelium *chamelium,
334*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *fsm_port,
335*d83cc019SAndroid Build Coastguard Worker const char *method_name,
336*d83cc019SAndroid Build Coastguard Worker const char *format_str,
337*d83cc019SAndroid Build Coastguard Worker ...)
338*d83cc019SAndroid Build Coastguard Worker {
339*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res;
340*d83cc019SAndroid Build Coastguard Worker va_list va_args;
341*d83cc019SAndroid Build Coastguard Worker
342*d83cc019SAndroid Build Coastguard Worker va_start(va_args, format_str);
343*d83cc019SAndroid Build Coastguard Worker res = __chamelium_rpc_va(chamelium, fsm_port, method_name,
344*d83cc019SAndroid Build Coastguard Worker format_str, va_args);
345*d83cc019SAndroid Build Coastguard Worker va_end(va_args);
346*d83cc019SAndroid Build Coastguard Worker
347*d83cc019SAndroid Build Coastguard Worker igt_assert_f(!chamelium->env.fault_occurred,
348*d83cc019SAndroid Build Coastguard Worker "Chamelium RPC call failed: %s\n",
349*d83cc019SAndroid Build Coastguard Worker chamelium->env.fault_string);
350*d83cc019SAndroid Build Coastguard Worker
351*d83cc019SAndroid Build Coastguard Worker return res;
352*d83cc019SAndroid Build Coastguard Worker }
353*d83cc019SAndroid Build Coastguard Worker
__chamelium_is_reachable(struct chamelium * chamelium)354*d83cc019SAndroid Build Coastguard Worker static bool __chamelium_is_reachable(struct chamelium *chamelium)
355*d83cc019SAndroid Build Coastguard Worker {
356*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res;
357*d83cc019SAndroid Build Coastguard Worker
358*d83cc019SAndroid Build Coastguard Worker /* GetSupportedInputs does not require a port and is harmless */
359*d83cc019SAndroid Build Coastguard Worker res = __chamelium_rpc(chamelium, NULL, "GetSupportedInputs", "()");
360*d83cc019SAndroid Build Coastguard Worker
361*d83cc019SAndroid Build Coastguard Worker if (res != NULL)
362*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res);
363*d83cc019SAndroid Build Coastguard Worker
364*d83cc019SAndroid Build Coastguard Worker if (chamelium->env.fault_occurred)
365*d83cc019SAndroid Build Coastguard Worker igt_debug("Chamelium RPC call failed: %s\n",
366*d83cc019SAndroid Build Coastguard Worker chamelium->env.fault_string);
367*d83cc019SAndroid Build Coastguard Worker
368*d83cc019SAndroid Build Coastguard Worker return !chamelium->env.fault_occurred;
369*d83cc019SAndroid Build Coastguard Worker }
370*d83cc019SAndroid Build Coastguard Worker
chamelium_wait_reachable(struct chamelium * chamelium,int timeout)371*d83cc019SAndroid Build Coastguard Worker void chamelium_wait_reachable(struct chamelium *chamelium, int timeout)
372*d83cc019SAndroid Build Coastguard Worker {
373*d83cc019SAndroid Build Coastguard Worker bool chamelium_online = igt_wait(__chamelium_is_reachable(chamelium),
374*d83cc019SAndroid Build Coastguard Worker timeout * 1000, 100);
375*d83cc019SAndroid Build Coastguard Worker
376*d83cc019SAndroid Build Coastguard Worker igt_assert_f(chamelium_online,
377*d83cc019SAndroid Build Coastguard Worker "Couldn't connect to Chamelium for %ds", timeout);
378*d83cc019SAndroid Build Coastguard Worker }
379*d83cc019SAndroid Build Coastguard Worker
380*d83cc019SAndroid Build Coastguard Worker /**
381*d83cc019SAndroid Build Coastguard Worker * chamelium_plug:
382*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
383*d83cc019SAndroid Build Coastguard Worker * @port: The port on the chamelium to plug
384*d83cc019SAndroid Build Coastguard Worker *
385*d83cc019SAndroid Build Coastguard Worker * Simulate a display connector being plugged into the system using the
386*d83cc019SAndroid Build Coastguard Worker * chamelium.
387*d83cc019SAndroid Build Coastguard Worker */
chamelium_plug(struct chamelium * chamelium,struct chamelium_port * port)388*d83cc019SAndroid Build Coastguard Worker void chamelium_plug(struct chamelium *chamelium, struct chamelium_port *port)
389*d83cc019SAndroid Build Coastguard Worker {
390*d83cc019SAndroid Build Coastguard Worker igt_debug("Plugging %s (Chamelium port ID %d)\n", port->name, port->id);
391*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(chamelium_rpc(chamelium, NULL, "Plug", "(i)", port->id));
392*d83cc019SAndroid Build Coastguard Worker }
393*d83cc019SAndroid Build Coastguard Worker
394*d83cc019SAndroid Build Coastguard Worker /**
395*d83cc019SAndroid Build Coastguard Worker * chamelium_unplug:
396*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
397*d83cc019SAndroid Build Coastguard Worker * @port: The port on the chamelium to unplug
398*d83cc019SAndroid Build Coastguard Worker *
399*d83cc019SAndroid Build Coastguard Worker * Simulate a display connector being unplugged from the system using the
400*d83cc019SAndroid Build Coastguard Worker * chamelium.
401*d83cc019SAndroid Build Coastguard Worker */
chamelium_unplug(struct chamelium * chamelium,struct chamelium_port * port)402*d83cc019SAndroid Build Coastguard Worker void chamelium_unplug(struct chamelium *chamelium, struct chamelium_port *port)
403*d83cc019SAndroid Build Coastguard Worker {
404*d83cc019SAndroid Build Coastguard Worker igt_debug("Unplugging port %s\n", port->name);
405*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(chamelium_rpc(chamelium, NULL, "Unplug", "(i)",
406*d83cc019SAndroid Build Coastguard Worker port->id));
407*d83cc019SAndroid Build Coastguard Worker }
408*d83cc019SAndroid Build Coastguard Worker
409*d83cc019SAndroid Build Coastguard Worker /**
410*d83cc019SAndroid Build Coastguard Worker * chamelium_is_plugged:
411*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
412*d83cc019SAndroid Build Coastguard Worker * @port: The port on the Chamelium to check the status of
413*d83cc019SAndroid Build Coastguard Worker *
414*d83cc019SAndroid Build Coastguard Worker * Check whether or not the given port has been plugged into the system using
415*d83cc019SAndroid Build Coastguard Worker * #chamelium_plug.
416*d83cc019SAndroid Build Coastguard Worker *
417*d83cc019SAndroid Build Coastguard Worker * Returns: %true if the connector is set to plugged in, %false otherwise.
418*d83cc019SAndroid Build Coastguard Worker */
chamelium_is_plugged(struct chamelium * chamelium,struct chamelium_port * port)419*d83cc019SAndroid Build Coastguard Worker bool chamelium_is_plugged(struct chamelium *chamelium,
420*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port)
421*d83cc019SAndroid Build Coastguard Worker {
422*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res;
423*d83cc019SAndroid Build Coastguard Worker xmlrpc_bool is_plugged;
424*d83cc019SAndroid Build Coastguard Worker
425*d83cc019SAndroid Build Coastguard Worker res = chamelium_rpc(chamelium, NULL, "IsPlugged", "(i)", port->id);
426*d83cc019SAndroid Build Coastguard Worker
427*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_bool(&chamelium->env, res, &is_plugged);
428*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res);
429*d83cc019SAndroid Build Coastguard Worker
430*d83cc019SAndroid Build Coastguard Worker return is_plugged;
431*d83cc019SAndroid Build Coastguard Worker }
432*d83cc019SAndroid Build Coastguard Worker
433*d83cc019SAndroid Build Coastguard Worker /**
434*d83cc019SAndroid Build Coastguard Worker * chamelium_port_wait_video_input_stable:
435*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
436*d83cc019SAndroid Build Coastguard Worker * @port: The port on the Chamelium to check the status of
437*d83cc019SAndroid Build Coastguard Worker * @timeout_secs: How long to wait for a video signal to appear before timing
438*d83cc019SAndroid Build Coastguard Worker * out
439*d83cc019SAndroid Build Coastguard Worker *
440*d83cc019SAndroid Build Coastguard Worker * Waits for a video signal to appear on the given port. This is useful for
441*d83cc019SAndroid Build Coastguard Worker * checking whether or not we've setup a monitor correctly.
442*d83cc019SAndroid Build Coastguard Worker *
443*d83cc019SAndroid Build Coastguard Worker * Returns: %true if a video signal was detected, %false if we timed out
444*d83cc019SAndroid Build Coastguard Worker */
chamelium_port_wait_video_input_stable(struct chamelium * chamelium,struct chamelium_port * port,int timeout_secs)445*d83cc019SAndroid Build Coastguard Worker bool chamelium_port_wait_video_input_stable(struct chamelium *chamelium,
446*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port,
447*d83cc019SAndroid Build Coastguard Worker int timeout_secs)
448*d83cc019SAndroid Build Coastguard Worker {
449*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res;
450*d83cc019SAndroid Build Coastguard Worker xmlrpc_bool is_on;
451*d83cc019SAndroid Build Coastguard Worker
452*d83cc019SAndroid Build Coastguard Worker igt_debug("Waiting for video input to stabalize on %s\n", port->name);
453*d83cc019SAndroid Build Coastguard Worker
454*d83cc019SAndroid Build Coastguard Worker res = chamelium_rpc(chamelium, port, "WaitVideoInputStable", "(ii)",
455*d83cc019SAndroid Build Coastguard Worker port->id, timeout_secs);
456*d83cc019SAndroid Build Coastguard Worker
457*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_bool(&chamelium->env, res, &is_on);
458*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res);
459*d83cc019SAndroid Build Coastguard Worker
460*d83cc019SAndroid Build Coastguard Worker return is_on;
461*d83cc019SAndroid Build Coastguard Worker }
462*d83cc019SAndroid Build Coastguard Worker
463*d83cc019SAndroid Build Coastguard Worker /**
464*d83cc019SAndroid Build Coastguard Worker * chamelium_fire_hpd_pulses:
465*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
466*d83cc019SAndroid Build Coastguard Worker * @port: The port to fire the HPD pulses on
467*d83cc019SAndroid Build Coastguard Worker * @width_msec: How long each pulse should last
468*d83cc019SAndroid Build Coastguard Worker * @count: The number of pulses to send
469*d83cc019SAndroid Build Coastguard Worker *
470*d83cc019SAndroid Build Coastguard Worker * A convienence function for sending multiple hotplug pulses to the system.
471*d83cc019SAndroid Build Coastguard Worker * The pulses start at low (e.g. connector is disconnected), and then alternate
472*d83cc019SAndroid Build Coastguard Worker * from high (e.g. connector is plugged in) to low. This is the equivalent of
473*d83cc019SAndroid Build Coastguard Worker * repeatedly calling #chamelium_plug and #chamelium_unplug, waiting
474*d83cc019SAndroid Build Coastguard Worker * @width_msec between each call.
475*d83cc019SAndroid Build Coastguard Worker *
476*d83cc019SAndroid Build Coastguard Worker * If @count is even, the last pulse sent will be high, and if it's odd then it
477*d83cc019SAndroid Build Coastguard Worker * will be low. Resetting the HPD line back to it's previous state, if desired,
478*d83cc019SAndroid Build Coastguard Worker * is the responsibility of the caller.
479*d83cc019SAndroid Build Coastguard Worker */
chamelium_fire_hpd_pulses(struct chamelium * chamelium,struct chamelium_port * port,int width_msec,int count)480*d83cc019SAndroid Build Coastguard Worker void chamelium_fire_hpd_pulses(struct chamelium *chamelium,
481*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port,
482*d83cc019SAndroid Build Coastguard Worker int width_msec, int count)
483*d83cc019SAndroid Build Coastguard Worker {
484*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *pulse_widths = xmlrpc_array_new(&chamelium->env);
485*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *width = xmlrpc_int_new(&chamelium->env, width_msec);
486*d83cc019SAndroid Build Coastguard Worker int i;
487*d83cc019SAndroid Build Coastguard Worker
488*d83cc019SAndroid Build Coastguard Worker igt_debug("Firing %d HPD pulses with width of %d msec on %s\n",
489*d83cc019SAndroid Build Coastguard Worker count, width_msec, port->name);
490*d83cc019SAndroid Build Coastguard Worker
491*d83cc019SAndroid Build Coastguard Worker for (i = 0; i < count; i++)
492*d83cc019SAndroid Build Coastguard Worker xmlrpc_array_append_item(&chamelium->env, pulse_widths, width);
493*d83cc019SAndroid Build Coastguard Worker
494*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(chamelium_rpc(chamelium, NULL, "FireMixedHpdPulses",
495*d83cc019SAndroid Build Coastguard Worker "(iA)", port->id, pulse_widths));
496*d83cc019SAndroid Build Coastguard Worker
497*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(width);
498*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(pulse_widths);
499*d83cc019SAndroid Build Coastguard Worker }
500*d83cc019SAndroid Build Coastguard Worker
501*d83cc019SAndroid Build Coastguard Worker /**
502*d83cc019SAndroid Build Coastguard Worker * chamelium_fire_mixed_hpd_pulses:
503*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
504*d83cc019SAndroid Build Coastguard Worker * @port: The port to fire the HPD pulses on
505*d83cc019SAndroid Build Coastguard Worker * @...: The length of each pulse in milliseconds, terminated with a %0
506*d83cc019SAndroid Build Coastguard Worker *
507*d83cc019SAndroid Build Coastguard Worker * Does the same thing as #chamelium_fire_hpd_pulses, but allows the caller to
508*d83cc019SAndroid Build Coastguard Worker * specify the length of each individual pulse.
509*d83cc019SAndroid Build Coastguard Worker */
chamelium_fire_mixed_hpd_pulses(struct chamelium * chamelium,struct chamelium_port * port,...)510*d83cc019SAndroid Build Coastguard Worker void chamelium_fire_mixed_hpd_pulses(struct chamelium *chamelium,
511*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port, ...)
512*d83cc019SAndroid Build Coastguard Worker {
513*d83cc019SAndroid Build Coastguard Worker va_list args;
514*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *pulse_widths = xmlrpc_array_new(&chamelium->env), *width;
515*d83cc019SAndroid Build Coastguard Worker int arg;
516*d83cc019SAndroid Build Coastguard Worker
517*d83cc019SAndroid Build Coastguard Worker igt_debug("Firing mixed HPD pulses on %s\n", port->name);
518*d83cc019SAndroid Build Coastguard Worker
519*d83cc019SAndroid Build Coastguard Worker va_start(args, port);
520*d83cc019SAndroid Build Coastguard Worker for (arg = va_arg(args, int); arg; arg = va_arg(args, int)) {
521*d83cc019SAndroid Build Coastguard Worker width = xmlrpc_int_new(&chamelium->env, arg);
522*d83cc019SAndroid Build Coastguard Worker xmlrpc_array_append_item(&chamelium->env, pulse_widths, width);
523*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(width);
524*d83cc019SAndroid Build Coastguard Worker }
525*d83cc019SAndroid Build Coastguard Worker va_end(args);
526*d83cc019SAndroid Build Coastguard Worker
527*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(chamelium_rpc(chamelium, NULL, "FireMixedHpdPulses",
528*d83cc019SAndroid Build Coastguard Worker "(iA)", port->id, pulse_widths));
529*d83cc019SAndroid Build Coastguard Worker
530*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(pulse_widths);
531*d83cc019SAndroid Build Coastguard Worker }
532*d83cc019SAndroid Build Coastguard Worker
533*d83cc019SAndroid Build Coastguard Worker /**
534*d83cc019SAndroid Build Coastguard Worker * chamelium_schedule_hpd_toggle:
535*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
536*d83cc019SAndroid Build Coastguard Worker * @port: The port to fire the HPD pulses on
537*d83cc019SAndroid Build Coastguard Worker * @delay_ms: Delay in milli-second before the toggle takes place
538*d83cc019SAndroid Build Coastguard Worker * @rising_edge: Whether the toggle should be a rising edge or a falling edge
539*d83cc019SAndroid Build Coastguard Worker *
540*d83cc019SAndroid Build Coastguard Worker * Instructs the chamelium to schedule an hpd toggle (either a rising edge or
541*d83cc019SAndroid Build Coastguard Worker * a falling edge, depending on @rising_edg) after @delay_ms have passed.
542*d83cc019SAndroid Build Coastguard Worker * This is useful for testing things such as hpd after a suspend/resume cycle.
543*d83cc019SAndroid Build Coastguard Worker */
chamelium_schedule_hpd_toggle(struct chamelium * chamelium,struct chamelium_port * port,int delay_ms,bool rising_edge)544*d83cc019SAndroid Build Coastguard Worker void chamelium_schedule_hpd_toggle(struct chamelium *chamelium,
545*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port, int delay_ms,
546*d83cc019SAndroid Build Coastguard Worker bool rising_edge)
547*d83cc019SAndroid Build Coastguard Worker {
548*d83cc019SAndroid Build Coastguard Worker igt_debug("Scheduling HPD toggle on %s in %d ms\n", port->name,
549*d83cc019SAndroid Build Coastguard Worker delay_ms);
550*d83cc019SAndroid Build Coastguard Worker
551*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(chamelium_rpc(chamelium, NULL, "ScheduleHpdToggle",
552*d83cc019SAndroid Build Coastguard Worker "(iii)", port->id, delay_ms, rising_edge));
553*d83cc019SAndroid Build Coastguard Worker }
554*d83cc019SAndroid Build Coastguard Worker
chamelium_upload_edid(struct chamelium * chamelium,const struct edid * edid)555*d83cc019SAndroid Build Coastguard Worker static int chamelium_upload_edid(struct chamelium *chamelium,
556*d83cc019SAndroid Build Coastguard Worker const struct edid *edid)
557*d83cc019SAndroid Build Coastguard Worker {
558*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res;
559*d83cc019SAndroid Build Coastguard Worker int edid_id;
560*d83cc019SAndroid Build Coastguard Worker
561*d83cc019SAndroid Build Coastguard Worker res = chamelium_rpc(chamelium, NULL, "CreateEdid", "(6)",
562*d83cc019SAndroid Build Coastguard Worker edid, edid_get_size(edid));
563*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_int(&chamelium->env, res, &edid_id);
564*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res);
565*d83cc019SAndroid Build Coastguard Worker
566*d83cc019SAndroid Build Coastguard Worker return edid_id;
567*d83cc019SAndroid Build Coastguard Worker }
568*d83cc019SAndroid Build Coastguard Worker
chamelium_destroy_edid(struct chamelium * chamelium,int edid_id)569*d83cc019SAndroid Build Coastguard Worker static void chamelium_destroy_edid(struct chamelium *chamelium, int edid_id)
570*d83cc019SAndroid Build Coastguard Worker {
571*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(chamelium_rpc(chamelium, NULL, "DestroyEdid", "(i)",
572*d83cc019SAndroid Build Coastguard Worker edid_id));
573*d83cc019SAndroid Build Coastguard Worker }
574*d83cc019SAndroid Build Coastguard Worker
575*d83cc019SAndroid Build Coastguard Worker /**
576*d83cc019SAndroid Build Coastguard Worker * chamelium_new_edid:
577*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
578*d83cc019SAndroid Build Coastguard Worker * @edid: The edid blob to upload to the chamelium
579*d83cc019SAndroid Build Coastguard Worker *
580*d83cc019SAndroid Build Coastguard Worker * Uploads and registers a new EDID with the chamelium. The EDID will be
581*d83cc019SAndroid Build Coastguard Worker * destroyed automatically when #chamelium_deinit is called.
582*d83cc019SAndroid Build Coastguard Worker *
583*d83cc019SAndroid Build Coastguard Worker * Callers shouldn't assume that the raw EDID they provide is uploaded as-is to
584*d83cc019SAndroid Build Coastguard Worker * the Chamelium. The EDID may be mutated (e.g. a serial number can be appended
585*d83cc019SAndroid Build Coastguard Worker * to be able to uniquely identify the EDID). To retrieve the exact EDID that
586*d83cc019SAndroid Build Coastguard Worker * will be applied to a particular port, use #chamelium_edid_get_raw.
587*d83cc019SAndroid Build Coastguard Worker *
588*d83cc019SAndroid Build Coastguard Worker * Returns: An opaque pointer to the Chamelium EDID
589*d83cc019SAndroid Build Coastguard Worker */
chamelium_new_edid(struct chamelium * chamelium,const struct edid * edid)590*d83cc019SAndroid Build Coastguard Worker struct chamelium_edid *chamelium_new_edid(struct chamelium *chamelium,
591*d83cc019SAndroid Build Coastguard Worker const struct edid *edid)
592*d83cc019SAndroid Build Coastguard Worker {
593*d83cc019SAndroid Build Coastguard Worker struct chamelium_edid *chamelium_edid;
594*d83cc019SAndroid Build Coastguard Worker size_t edid_size = edid_get_size(edid);
595*d83cc019SAndroid Build Coastguard Worker
596*d83cc019SAndroid Build Coastguard Worker chamelium_edid = calloc(1, sizeof(struct chamelium_edid));
597*d83cc019SAndroid Build Coastguard Worker chamelium_edid->chamelium = chamelium;
598*d83cc019SAndroid Build Coastguard Worker chamelium_edid->base = malloc(edid_size);
599*d83cc019SAndroid Build Coastguard Worker memcpy(chamelium_edid->base, edid, edid_size);
600*d83cc019SAndroid Build Coastguard Worker igt_list_add(&chamelium_edid->link, &chamelium->edids);
601*d83cc019SAndroid Build Coastguard Worker
602*d83cc019SAndroid Build Coastguard Worker return chamelium_edid;
603*d83cc019SAndroid Build Coastguard Worker }
604*d83cc019SAndroid Build Coastguard Worker
605*d83cc019SAndroid Build Coastguard Worker /**
606*d83cc019SAndroid Build Coastguard Worker * chamelium_port_tag_edid: tag the EDID with the provided Chamelium port.
607*d83cc019SAndroid Build Coastguard Worker */
chamelium_port_tag_edid(struct chamelium_port * port,struct edid * edid)608*d83cc019SAndroid Build Coastguard Worker static void chamelium_port_tag_edid(struct chamelium_port *port,
609*d83cc019SAndroid Build Coastguard Worker struct edid *edid)
610*d83cc019SAndroid Build Coastguard Worker {
611*d83cc019SAndroid Build Coastguard Worker uint32_t *serial;
612*d83cc019SAndroid Build Coastguard Worker
613*d83cc019SAndroid Build Coastguard Worker /* Product code: Chamelium */
614*d83cc019SAndroid Build Coastguard Worker edid->prod_code[0] = 'C';
615*d83cc019SAndroid Build Coastguard Worker edid->prod_code[1] = 'H';
616*d83cc019SAndroid Build Coastguard Worker
617*d83cc019SAndroid Build Coastguard Worker /* Serial: Chamelium port ID */
618*d83cc019SAndroid Build Coastguard Worker serial = (uint32_t *) &edid->serial;
619*d83cc019SAndroid Build Coastguard Worker *serial = port->id;
620*d83cc019SAndroid Build Coastguard Worker
621*d83cc019SAndroid Build Coastguard Worker edid_update_checksum(edid);
622*d83cc019SAndroid Build Coastguard Worker }
623*d83cc019SAndroid Build Coastguard Worker
624*d83cc019SAndroid Build Coastguard Worker /**
625*d83cc019SAndroid Build Coastguard Worker * chamelium_edid_get_raw: get the raw EDID
626*d83cc019SAndroid Build Coastguard Worker * @edid: the Chamelium EDID
627*d83cc019SAndroid Build Coastguard Worker * @port: the Chamelium port
628*d83cc019SAndroid Build Coastguard Worker *
629*d83cc019SAndroid Build Coastguard Worker * The EDID provided to #chamelium_new_edid may be mutated for identification
630*d83cc019SAndroid Build Coastguard Worker * purposes. This function allows to retrieve the exact EDID that will be set
631*d83cc019SAndroid Build Coastguard Worker * for a given port.
632*d83cc019SAndroid Build Coastguard Worker *
633*d83cc019SAndroid Build Coastguard Worker * The returned raw EDID is only valid until the next call to this function.
634*d83cc019SAndroid Build Coastguard Worker */
chamelium_edid_get_raw(struct chamelium_edid * edid,struct chamelium_port * port)635*d83cc019SAndroid Build Coastguard Worker const struct edid *chamelium_edid_get_raw(struct chamelium_edid *edid,
636*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port)
637*d83cc019SAndroid Build Coastguard Worker {
638*d83cc019SAndroid Build Coastguard Worker size_t port_index = port - edid->chamelium->ports;
639*d83cc019SAndroid Build Coastguard Worker size_t edid_size;
640*d83cc019SAndroid Build Coastguard Worker
641*d83cc019SAndroid Build Coastguard Worker if (!edid->raw[port_index]) {
642*d83cc019SAndroid Build Coastguard Worker edid_size = edid_get_size(edid->base);
643*d83cc019SAndroid Build Coastguard Worker edid->raw[port_index] = malloc(edid_size);
644*d83cc019SAndroid Build Coastguard Worker memcpy(edid->raw[port_index], edid->base, edid_size);
645*d83cc019SAndroid Build Coastguard Worker chamelium_port_tag_edid(port, edid->raw[port_index]);
646*d83cc019SAndroid Build Coastguard Worker }
647*d83cc019SAndroid Build Coastguard Worker
648*d83cc019SAndroid Build Coastguard Worker return edid->raw[port_index];
649*d83cc019SAndroid Build Coastguard Worker }
650*d83cc019SAndroid Build Coastguard Worker
651*d83cc019SAndroid Build Coastguard Worker /**
652*d83cc019SAndroid Build Coastguard Worker * chamelium_port_set_edid:
653*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
654*d83cc019SAndroid Build Coastguard Worker * @port: The port on the Chamelium to set the EDID on
655*d83cc019SAndroid Build Coastguard Worker * @edid: The Chamelium EDID to set or NULL to use the default Chamelium EDID
656*d83cc019SAndroid Build Coastguard Worker *
657*d83cc019SAndroid Build Coastguard Worker * Sets a port on the chamelium to use the specified EDID. This does not fire a
658*d83cc019SAndroid Build Coastguard Worker * hotplug pulse on it's own, and merely changes what EDID the chamelium port
659*d83cc019SAndroid Build Coastguard Worker * will report to us the next time we probe it. Users will need to reprobe the
660*d83cc019SAndroid Build Coastguard Worker * connectors themselves if they want to see the EDID reported by the port
661*d83cc019SAndroid Build Coastguard Worker * change.
662*d83cc019SAndroid Build Coastguard Worker *
663*d83cc019SAndroid Build Coastguard Worker * To create an EDID, see #chamelium_new_edid.
664*d83cc019SAndroid Build Coastguard Worker */
chamelium_port_set_edid(struct chamelium * chamelium,struct chamelium_port * port,struct chamelium_edid * edid)665*d83cc019SAndroid Build Coastguard Worker void chamelium_port_set_edid(struct chamelium *chamelium,
666*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port,
667*d83cc019SAndroid Build Coastguard Worker struct chamelium_edid *edid)
668*d83cc019SAndroid Build Coastguard Worker {
669*d83cc019SAndroid Build Coastguard Worker int edid_id;
670*d83cc019SAndroid Build Coastguard Worker size_t port_index;
671*d83cc019SAndroid Build Coastguard Worker const struct edid *raw_edid;
672*d83cc019SAndroid Build Coastguard Worker
673*d83cc019SAndroid Build Coastguard Worker if (edid) {
674*d83cc019SAndroid Build Coastguard Worker port_index = port - chamelium->ports;
675*d83cc019SAndroid Build Coastguard Worker edid_id = edid->ids[port_index];
676*d83cc019SAndroid Build Coastguard Worker if (edid_id == 0) {
677*d83cc019SAndroid Build Coastguard Worker raw_edid = chamelium_edid_get_raw(edid, port);
678*d83cc019SAndroid Build Coastguard Worker edid_id = chamelium_upload_edid(chamelium, raw_edid);
679*d83cc019SAndroid Build Coastguard Worker edid->ids[port_index] = edid_id;
680*d83cc019SAndroid Build Coastguard Worker }
681*d83cc019SAndroid Build Coastguard Worker } else {
682*d83cc019SAndroid Build Coastguard Worker edid_id = 0;
683*d83cc019SAndroid Build Coastguard Worker }
684*d83cc019SAndroid Build Coastguard Worker
685*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(chamelium_rpc(chamelium, NULL, "ApplyEdid", "(ii)",
686*d83cc019SAndroid Build Coastguard Worker port->id, edid_id));
687*d83cc019SAndroid Build Coastguard Worker }
688*d83cc019SAndroid Build Coastguard Worker
689*d83cc019SAndroid Build Coastguard Worker /**
690*d83cc019SAndroid Build Coastguard Worker * chamelium_port_set_ddc_state:
691*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
692*d83cc019SAndroid Build Coastguard Worker * @port: The port to change the DDC state on
693*d83cc019SAndroid Build Coastguard Worker * @enabled: Whether or not to enable the DDC bus
694*d83cc019SAndroid Build Coastguard Worker *
695*d83cc019SAndroid Build Coastguard Worker * This disables the DDC bus (e.g. the i2c line on the connector that gives us
696*d83cc019SAndroid Build Coastguard Worker * an EDID) of the specified port on the chamelium. This is useful for testing
697*d83cc019SAndroid Build Coastguard Worker * behavior on legacy connectors such as VGA, where the presence of a DDC bus
698*d83cc019SAndroid Build Coastguard Worker * is not always guaranteed.
699*d83cc019SAndroid Build Coastguard Worker */
chamelium_port_set_ddc_state(struct chamelium * chamelium,struct chamelium_port * port,bool enabled)700*d83cc019SAndroid Build Coastguard Worker void chamelium_port_set_ddc_state(struct chamelium *chamelium,
701*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port,
702*d83cc019SAndroid Build Coastguard Worker bool enabled)
703*d83cc019SAndroid Build Coastguard Worker {
704*d83cc019SAndroid Build Coastguard Worker igt_debug("%sabling DDC bus on %s\n",
705*d83cc019SAndroid Build Coastguard Worker enabled ? "En" : "Dis", port->name);
706*d83cc019SAndroid Build Coastguard Worker
707*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(chamelium_rpc(chamelium, NULL, "SetDdcState", "(ib)",
708*d83cc019SAndroid Build Coastguard Worker port->id, enabled));
709*d83cc019SAndroid Build Coastguard Worker }
710*d83cc019SAndroid Build Coastguard Worker
711*d83cc019SAndroid Build Coastguard Worker /**
712*d83cc019SAndroid Build Coastguard Worker * chamelium_port_get_ddc_state:
713*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
714*d83cc019SAndroid Build Coastguard Worker * @port: The port on the Chamelium to check the status of
715*d83cc019SAndroid Build Coastguard Worker *
716*d83cc019SAndroid Build Coastguard Worker * Check whether or not the DDC bus on the specified chamelium port is enabled
717*d83cc019SAndroid Build Coastguard Worker * or not.
718*d83cc019SAndroid Build Coastguard Worker *
719*d83cc019SAndroid Build Coastguard Worker * Returns: %true if the DDC bus is enabled, %false otherwise.
720*d83cc019SAndroid Build Coastguard Worker */
chamelium_port_get_ddc_state(struct chamelium * chamelium,struct chamelium_port * port)721*d83cc019SAndroid Build Coastguard Worker bool chamelium_port_get_ddc_state(struct chamelium *chamelium,
722*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port)
723*d83cc019SAndroid Build Coastguard Worker {
724*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res;
725*d83cc019SAndroid Build Coastguard Worker xmlrpc_bool enabled;
726*d83cc019SAndroid Build Coastguard Worker
727*d83cc019SAndroid Build Coastguard Worker res = chamelium_rpc(chamelium, NULL, "IsDdcEnabled", "(i)", port->id);
728*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_bool(&chamelium->env, res, &enabled);
729*d83cc019SAndroid Build Coastguard Worker
730*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res);
731*d83cc019SAndroid Build Coastguard Worker return enabled;
732*d83cc019SAndroid Build Coastguard Worker }
733*d83cc019SAndroid Build Coastguard Worker
734*d83cc019SAndroid Build Coastguard Worker /**
735*d83cc019SAndroid Build Coastguard Worker * chamelium_port_get_resolution:
736*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
737*d83cc019SAndroid Build Coastguard Worker * @port: The port on the Chamelium to check
738*d83cc019SAndroid Build Coastguard Worker * @x: Where to store the horizontal resolution of the port
739*d83cc019SAndroid Build Coastguard Worker * @y: Where to store the verical resolution of the port
740*d83cc019SAndroid Build Coastguard Worker *
741*d83cc019SAndroid Build Coastguard Worker * Check the current reported display resolution of the specified port on the
742*d83cc019SAndroid Build Coastguard Worker * chamelium. This information is provided by the chamelium itself, not DRM.
743*d83cc019SAndroid Build Coastguard Worker * Useful for verifying that we really are scanning out at the resolution we
744*d83cc019SAndroid Build Coastguard Worker * think we are.
745*d83cc019SAndroid Build Coastguard Worker */
chamelium_port_get_resolution(struct chamelium * chamelium,struct chamelium_port * port,int * x,int * y)746*d83cc019SAndroid Build Coastguard Worker void chamelium_port_get_resolution(struct chamelium *chamelium,
747*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port,
748*d83cc019SAndroid Build Coastguard Worker int *x, int *y)
749*d83cc019SAndroid Build Coastguard Worker {
750*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res, *res_x, *res_y;
751*d83cc019SAndroid Build Coastguard Worker
752*d83cc019SAndroid Build Coastguard Worker res = chamelium_rpc(chamelium, port, "DetectResolution", "(i)",
753*d83cc019SAndroid Build Coastguard Worker port->id);
754*d83cc019SAndroid Build Coastguard Worker
755*d83cc019SAndroid Build Coastguard Worker xmlrpc_array_read_item(&chamelium->env, res, 0, &res_x);
756*d83cc019SAndroid Build Coastguard Worker xmlrpc_array_read_item(&chamelium->env, res, 1, &res_y);
757*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_int(&chamelium->env, res_x, x);
758*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_int(&chamelium->env, res_y, y);
759*d83cc019SAndroid Build Coastguard Worker
760*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res_x);
761*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res_y);
762*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res);
763*d83cc019SAndroid Build Coastguard Worker }
764*d83cc019SAndroid Build Coastguard Worker
765*d83cc019SAndroid Build Coastguard Worker /** chamelium_supports_method: checks if the Chamelium board supports a method.
766*d83cc019SAndroid Build Coastguard Worker *
767*d83cc019SAndroid Build Coastguard Worker * Note: this actually tries to call the method.
768*d83cc019SAndroid Build Coastguard Worker *
769*d83cc019SAndroid Build Coastguard Worker * See https://crbug.com/977995 for a discussion about a better solution.
770*d83cc019SAndroid Build Coastguard Worker */
chamelium_supports_method(struct chamelium * chamelium,const char * name)771*d83cc019SAndroid Build Coastguard Worker static bool chamelium_supports_method(struct chamelium *chamelium,
772*d83cc019SAndroid Build Coastguard Worker const char *name)
773*d83cc019SAndroid Build Coastguard Worker {
774*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res;
775*d83cc019SAndroid Build Coastguard Worker
776*d83cc019SAndroid Build Coastguard Worker res = __chamelium_rpc(chamelium, NULL, name, "()");
777*d83cc019SAndroid Build Coastguard Worker if (res)
778*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res);
779*d83cc019SAndroid Build Coastguard Worker
780*d83cc019SAndroid Build Coastguard Worker /* XML-RPC has a special code for unsupported methods
781*d83cc019SAndroid Build Coastguard Worker * (XMLRPC_NO_SUCH_METHOD_ERROR) however the Chamelium implementation
782*d83cc019SAndroid Build Coastguard Worker * doesn't return it. */
783*d83cc019SAndroid Build Coastguard Worker return (!chamelium->env.fault_occurred ||
784*d83cc019SAndroid Build Coastguard Worker strstr(chamelium->env.fault_string, "not supported") == NULL);
785*d83cc019SAndroid Build Coastguard Worker }
786*d83cc019SAndroid Build Coastguard Worker
chamelium_supports_get_video_params(struct chamelium * chamelium)787*d83cc019SAndroid Build Coastguard Worker bool chamelium_supports_get_video_params(struct chamelium *chamelium)
788*d83cc019SAndroid Build Coastguard Worker {
789*d83cc019SAndroid Build Coastguard Worker return chamelium_supports_method(chamelium, "GetVideoParams");
790*d83cc019SAndroid Build Coastguard Worker }
791*d83cc019SAndroid Build Coastguard Worker
read_int_from_xml_struct(struct chamelium * chamelium,xmlrpc_value * struct_val,const char * key,int * dst)792*d83cc019SAndroid Build Coastguard Worker static void read_int_from_xml_struct(struct chamelium *chamelium,
793*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *struct_val, const char *key,
794*d83cc019SAndroid Build Coastguard Worker int *dst)
795*d83cc019SAndroid Build Coastguard Worker {
796*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *val = NULL;
797*d83cc019SAndroid Build Coastguard Worker
798*d83cc019SAndroid Build Coastguard Worker xmlrpc_struct_find_value(&chamelium->env, struct_val, key, &val);
799*d83cc019SAndroid Build Coastguard Worker if (val) {
800*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_int(&chamelium->env, val, dst);
801*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(val);
802*d83cc019SAndroid Build Coastguard Worker } else
803*d83cc019SAndroid Build Coastguard Worker *dst = -1;
804*d83cc019SAndroid Build Coastguard Worker }
805*d83cc019SAndroid Build Coastguard Worker
video_params_from_xml(struct chamelium * chamelium,xmlrpc_value * res,struct chamelium_video_params * params)806*d83cc019SAndroid Build Coastguard Worker static void video_params_from_xml(struct chamelium *chamelium,
807*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res,
808*d83cc019SAndroid Build Coastguard Worker struct chamelium_video_params *params)
809*d83cc019SAndroid Build Coastguard Worker {
810*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *val = NULL;
811*d83cc019SAndroid Build Coastguard Worker
812*d83cc019SAndroid Build Coastguard Worker xmlrpc_struct_find_value(&chamelium->env, res, "clock", &val);
813*d83cc019SAndroid Build Coastguard Worker if (val) {
814*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_double(&chamelium->env, val, ¶ms->clock);
815*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(val);
816*d83cc019SAndroid Build Coastguard Worker } else
817*d83cc019SAndroid Build Coastguard Worker params->clock = NAN;
818*d83cc019SAndroid Build Coastguard Worker
819*d83cc019SAndroid Build Coastguard Worker read_int_from_xml_struct(chamelium, res, "htotal", ¶ms->htotal);
820*d83cc019SAndroid Build Coastguard Worker read_int_from_xml_struct(chamelium, res, "hactive", ¶ms->hactive);
821*d83cc019SAndroid Build Coastguard Worker read_int_from_xml_struct(chamelium, res, "hsync_offset",
822*d83cc019SAndroid Build Coastguard Worker ¶ms->hsync_offset);
823*d83cc019SAndroid Build Coastguard Worker read_int_from_xml_struct(chamelium, res, "hsync_width",
824*d83cc019SAndroid Build Coastguard Worker ¶ms->hsync_width);
825*d83cc019SAndroid Build Coastguard Worker read_int_from_xml_struct(chamelium, res, "hsync_polarity",
826*d83cc019SAndroid Build Coastguard Worker ¶ms->hsync_polarity);
827*d83cc019SAndroid Build Coastguard Worker read_int_from_xml_struct(chamelium, res, "vtotal", ¶ms->vtotal);
828*d83cc019SAndroid Build Coastguard Worker read_int_from_xml_struct(chamelium, res, "vactive", ¶ms->vactive);
829*d83cc019SAndroid Build Coastguard Worker read_int_from_xml_struct(chamelium, res, "vsync_offset",
830*d83cc019SAndroid Build Coastguard Worker ¶ms->vsync_offset);
831*d83cc019SAndroid Build Coastguard Worker read_int_from_xml_struct(chamelium, res, "vsync_width",
832*d83cc019SAndroid Build Coastguard Worker ¶ms->vsync_width);
833*d83cc019SAndroid Build Coastguard Worker read_int_from_xml_struct(chamelium, res, "vsync_polarity",
834*d83cc019SAndroid Build Coastguard Worker ¶ms->vsync_polarity);
835*d83cc019SAndroid Build Coastguard Worker }
836*d83cc019SAndroid Build Coastguard Worker
chamelium_port_get_video_params(struct chamelium * chamelium,struct chamelium_port * port,struct chamelium_video_params * params)837*d83cc019SAndroid Build Coastguard Worker void chamelium_port_get_video_params(struct chamelium *chamelium,
838*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port,
839*d83cc019SAndroid Build Coastguard Worker struct chamelium_video_params *params)
840*d83cc019SAndroid Build Coastguard Worker {
841*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res;
842*d83cc019SAndroid Build Coastguard Worker
843*d83cc019SAndroid Build Coastguard Worker res = chamelium_rpc(chamelium, NULL, "GetVideoParams", "(i)", port->id);
844*d83cc019SAndroid Build Coastguard Worker video_params_from_xml(chamelium, res, params);
845*d83cc019SAndroid Build Coastguard Worker
846*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res);
847*d83cc019SAndroid Build Coastguard Worker }
848*d83cc019SAndroid Build Coastguard Worker
chamelium_get_captured_resolution(struct chamelium * chamelium,int * w,int * h)849*d83cc019SAndroid Build Coastguard Worker static void chamelium_get_captured_resolution(struct chamelium *chamelium,
850*d83cc019SAndroid Build Coastguard Worker int *w, int *h)
851*d83cc019SAndroid Build Coastguard Worker {
852*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res, *res_w, *res_h;
853*d83cc019SAndroid Build Coastguard Worker
854*d83cc019SAndroid Build Coastguard Worker res = chamelium_rpc(chamelium, NULL, "GetCapturedResolution", "()");
855*d83cc019SAndroid Build Coastguard Worker
856*d83cc019SAndroid Build Coastguard Worker xmlrpc_array_read_item(&chamelium->env, res, 0, &res_w);
857*d83cc019SAndroid Build Coastguard Worker xmlrpc_array_read_item(&chamelium->env, res, 1, &res_h);
858*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_int(&chamelium->env, res_w, w);
859*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_int(&chamelium->env, res_h, h);
860*d83cc019SAndroid Build Coastguard Worker
861*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res_w);
862*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res_h);
863*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res);
864*d83cc019SAndroid Build Coastguard Worker }
865*d83cc019SAndroid Build Coastguard Worker
frame_from_xml(struct chamelium * chamelium,xmlrpc_value * frame_xml)866*d83cc019SAndroid Build Coastguard Worker static struct chamelium_frame_dump *frame_from_xml(struct chamelium *chamelium,
867*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *frame_xml)
868*d83cc019SAndroid Build Coastguard Worker {
869*d83cc019SAndroid Build Coastguard Worker struct chamelium_frame_dump *ret = malloc(sizeof(*ret));
870*d83cc019SAndroid Build Coastguard Worker
871*d83cc019SAndroid Build Coastguard Worker chamelium_get_captured_resolution(chamelium, &ret->width, &ret->height);
872*d83cc019SAndroid Build Coastguard Worker ret->port = chamelium->capturing_port;
873*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_base64(&chamelium->env, frame_xml, &ret->size,
874*d83cc019SAndroid Build Coastguard Worker (void*)&ret->bgr);
875*d83cc019SAndroid Build Coastguard Worker
876*d83cc019SAndroid Build Coastguard Worker return ret;
877*d83cc019SAndroid Build Coastguard Worker }
878*d83cc019SAndroid Build Coastguard Worker
879*d83cc019SAndroid Build Coastguard Worker /**
880*d83cc019SAndroid Build Coastguard Worker * chamelium_port_dump_pixels:
881*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
882*d83cc019SAndroid Build Coastguard Worker * @port: The port to perform the video capture on
883*d83cc019SAndroid Build Coastguard Worker * @x: The X coordinate to crop the screen capture to
884*d83cc019SAndroid Build Coastguard Worker * @y: The Y coordinate to crop the screen capture to
885*d83cc019SAndroid Build Coastguard Worker * @w: The width of the area to crop the screen capture to, or 0 for the whole
886*d83cc019SAndroid Build Coastguard Worker * screen
887*d83cc019SAndroid Build Coastguard Worker * @h: The height of the area to crop the screen capture to, or 0 for the whole
888*d83cc019SAndroid Build Coastguard Worker * screen
889*d83cc019SAndroid Build Coastguard Worker *
890*d83cc019SAndroid Build Coastguard Worker * Captures the currently displayed image on the given chamelium port,
891*d83cc019SAndroid Build Coastguard Worker * optionally cropped to a given region. In situations where pre-calculating
892*d83cc019SAndroid Build Coastguard Worker * CRCs may not be reliable, this can be used as an alternative for figuring
893*d83cc019SAndroid Build Coastguard Worker * out whether or not the correct images are being displayed on the screen.
894*d83cc019SAndroid Build Coastguard Worker *
895*d83cc019SAndroid Build Coastguard Worker * The frame dump data returned by this function should be freed when the
896*d83cc019SAndroid Build Coastguard Worker * caller is done with it using #chamelium_destroy_frame_dump.
897*d83cc019SAndroid Build Coastguard Worker *
898*d83cc019SAndroid Build Coastguard Worker * As an important note: some of the EDIDs provided by the Chamelium cause
899*d83cc019SAndroid Build Coastguard Worker * certain GPU drivers to default to using limited color ranges. This can cause
900*d83cc019SAndroid Build Coastguard Worker * video captures from the Chamelium to provide different images then expected
901*d83cc019SAndroid Build Coastguard Worker * due to the difference in color ranges (framebuffer uses full color range,
902*d83cc019SAndroid Build Coastguard Worker * but the video output doesn't), and as a result lead to CRC mismatches. To
903*d83cc019SAndroid Build Coastguard Worker * workaround this, the caller should force the connector to use full color
904*d83cc019SAndroid Build Coastguard Worker * ranges by using #kmstest_set_connector_broadcast_rgb before setting up the
905*d83cc019SAndroid Build Coastguard Worker * display.
906*d83cc019SAndroid Build Coastguard Worker *
907*d83cc019SAndroid Build Coastguard Worker * Returns: a chamelium_frame_dump struct
908*d83cc019SAndroid Build Coastguard Worker */
chamelium_port_dump_pixels(struct chamelium * chamelium,struct chamelium_port * port,int x,int y,int w,int h)909*d83cc019SAndroid Build Coastguard Worker struct chamelium_frame_dump *chamelium_port_dump_pixels(struct chamelium *chamelium,
910*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port,
911*d83cc019SAndroid Build Coastguard Worker int x, int y,
912*d83cc019SAndroid Build Coastguard Worker int w, int h)
913*d83cc019SAndroid Build Coastguard Worker {
914*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res;
915*d83cc019SAndroid Build Coastguard Worker struct chamelium_frame_dump *frame;
916*d83cc019SAndroid Build Coastguard Worker
917*d83cc019SAndroid Build Coastguard Worker res = chamelium_rpc(chamelium, port, "DumpPixels",
918*d83cc019SAndroid Build Coastguard Worker (w && h) ? "(iiiii)" : "(innnn)",
919*d83cc019SAndroid Build Coastguard Worker port->id, x, y, w, h);
920*d83cc019SAndroid Build Coastguard Worker chamelium->capturing_port = port;
921*d83cc019SAndroid Build Coastguard Worker
922*d83cc019SAndroid Build Coastguard Worker frame = frame_from_xml(chamelium, res);
923*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res);
924*d83cc019SAndroid Build Coastguard Worker
925*d83cc019SAndroid Build Coastguard Worker return frame;
926*d83cc019SAndroid Build Coastguard Worker }
927*d83cc019SAndroid Build Coastguard Worker
crc_from_xml(struct chamelium * chamelium,xmlrpc_value * xml_crc,igt_crc_t * out)928*d83cc019SAndroid Build Coastguard Worker static void crc_from_xml(struct chamelium *chamelium,
929*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *xml_crc, igt_crc_t *out)
930*d83cc019SAndroid Build Coastguard Worker {
931*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res;
932*d83cc019SAndroid Build Coastguard Worker int i;
933*d83cc019SAndroid Build Coastguard Worker
934*d83cc019SAndroid Build Coastguard Worker out->n_words = xmlrpc_array_size(&chamelium->env, xml_crc);
935*d83cc019SAndroid Build Coastguard Worker for (i = 0; i < out->n_words; i++) {
936*d83cc019SAndroid Build Coastguard Worker xmlrpc_array_read_item(&chamelium->env, xml_crc, i, &res);
937*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_int(&chamelium->env, res, (int*)&out->crc[i]);
938*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res);
939*d83cc019SAndroid Build Coastguard Worker }
940*d83cc019SAndroid Build Coastguard Worker }
941*d83cc019SAndroid Build Coastguard Worker
942*d83cc019SAndroid Build Coastguard Worker /**
943*d83cc019SAndroid Build Coastguard Worker * chamelium_get_crc_for_area:
944*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
945*d83cc019SAndroid Build Coastguard Worker * @port: The port to perform the CRC checking on
946*d83cc019SAndroid Build Coastguard Worker * @x: The X coordinate on the emulated display to start calculating the CRC
947*d83cc019SAndroid Build Coastguard Worker * from
948*d83cc019SAndroid Build Coastguard Worker * @y: The Y coordinate on the emulated display to start calculating the CRC
949*d83cc019SAndroid Build Coastguard Worker * from
950*d83cc019SAndroid Build Coastguard Worker * @w: The width of the area to fetch the CRC from, or %0 for the whole display
951*d83cc019SAndroid Build Coastguard Worker * @h: The height of the area to fetch the CRC from, or %0 for the whole display
952*d83cc019SAndroid Build Coastguard Worker *
953*d83cc019SAndroid Build Coastguard Worker * Reads back the pixel CRC for an area on the specified chamelium port. This
954*d83cc019SAndroid Build Coastguard Worker * is the same as using the CRC readback from a GPU, the main difference being
955*d83cc019SAndroid Build Coastguard Worker * the data is provided by the chamelium and also allows us to specify a region
956*d83cc019SAndroid Build Coastguard Worker * of the screen to use as opposed to the entire thing.
957*d83cc019SAndroid Build Coastguard Worker *
958*d83cc019SAndroid Build Coastguard Worker * As an important note: some of the EDIDs provided by the Chamelium cause
959*d83cc019SAndroid Build Coastguard Worker * certain GPU drivers to default to using limited color ranges. This can cause
960*d83cc019SAndroid Build Coastguard Worker * video captures from the Chamelium to provide different images then expected
961*d83cc019SAndroid Build Coastguard Worker * due to the difference in color ranges (framebuffer uses full color range,
962*d83cc019SAndroid Build Coastguard Worker * but the video output doesn't), and as a result lead to CRC mismatches. To
963*d83cc019SAndroid Build Coastguard Worker * workaround this, the caller should force the connector to use full color
964*d83cc019SAndroid Build Coastguard Worker * ranges by using #kmstest_set_connector_broadcast_rgb before setting up the
965*d83cc019SAndroid Build Coastguard Worker * display.
966*d83cc019SAndroid Build Coastguard Worker *
967*d83cc019SAndroid Build Coastguard Worker * After the caller is finished with the EDID returned by this function, the
968*d83cc019SAndroid Build Coastguard Worker * caller should manually free the resources associated with it.
969*d83cc019SAndroid Build Coastguard Worker *
970*d83cc019SAndroid Build Coastguard Worker * Returns: The CRC read back from the chamelium
971*d83cc019SAndroid Build Coastguard Worker */
chamelium_get_crc_for_area(struct chamelium * chamelium,struct chamelium_port * port,int x,int y,int w,int h)972*d83cc019SAndroid Build Coastguard Worker igt_crc_t *chamelium_get_crc_for_area(struct chamelium *chamelium,
973*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port,
974*d83cc019SAndroid Build Coastguard Worker int x, int y, int w, int h)
975*d83cc019SAndroid Build Coastguard Worker {
976*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res;
977*d83cc019SAndroid Build Coastguard Worker igt_crc_t *ret = malloc(sizeof(igt_crc_t));
978*d83cc019SAndroid Build Coastguard Worker
979*d83cc019SAndroid Build Coastguard Worker res = chamelium_rpc(chamelium, port, "ComputePixelChecksum",
980*d83cc019SAndroid Build Coastguard Worker (w && h) ? "(iiiii)" : "(innnn)",
981*d83cc019SAndroid Build Coastguard Worker port->id, x, y, w, h);
982*d83cc019SAndroid Build Coastguard Worker chamelium->capturing_port = port;
983*d83cc019SAndroid Build Coastguard Worker
984*d83cc019SAndroid Build Coastguard Worker crc_from_xml(chamelium, res, ret);
985*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res);
986*d83cc019SAndroid Build Coastguard Worker
987*d83cc019SAndroid Build Coastguard Worker return ret;
988*d83cc019SAndroid Build Coastguard Worker }
989*d83cc019SAndroid Build Coastguard Worker
990*d83cc019SAndroid Build Coastguard Worker /**
991*d83cc019SAndroid Build Coastguard Worker * chamelium_start_capture:
992*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
993*d83cc019SAndroid Build Coastguard Worker * @port: The port to perform the video capture on
994*d83cc019SAndroid Build Coastguard Worker * @x: The X coordinate to crop the video to
995*d83cc019SAndroid Build Coastguard Worker * @y: The Y coordinate to crop the video to
996*d83cc019SAndroid Build Coastguard Worker * @w: The width of the cropped video, or %0 for the whole display
997*d83cc019SAndroid Build Coastguard Worker * @h: The height of the cropped video, or %0 for the whole display
998*d83cc019SAndroid Build Coastguard Worker *
999*d83cc019SAndroid Build Coastguard Worker * Starts capturing video frames on the given Chamelium port. Once the user is
1000*d83cc019SAndroid Build Coastguard Worker * finished capturing frames, they should call #chamelium_stop_capture.
1001*d83cc019SAndroid Build Coastguard Worker *
1002*d83cc019SAndroid Build Coastguard Worker * A blocking, one-shot version of this function is available: see
1003*d83cc019SAndroid Build Coastguard Worker * #chamelium_capture
1004*d83cc019SAndroid Build Coastguard Worker *
1005*d83cc019SAndroid Build Coastguard Worker * As an important note: some of the EDIDs provided by the Chamelium cause
1006*d83cc019SAndroid Build Coastguard Worker * certain GPU drivers to default to using limited color ranges. This can cause
1007*d83cc019SAndroid Build Coastguard Worker * video captures from the Chamelium to provide different images then expected
1008*d83cc019SAndroid Build Coastguard Worker * due to the difference in color ranges (framebuffer uses full color range,
1009*d83cc019SAndroid Build Coastguard Worker * but the video output doesn't), and as a result lead to CRC and frame dump
1010*d83cc019SAndroid Build Coastguard Worker * comparison mismatches. To workaround this, the caller should force the
1011*d83cc019SAndroid Build Coastguard Worker * connector to use full color ranges by using
1012*d83cc019SAndroid Build Coastguard Worker * #kmstest_set_connector_broadcast_rgb before setting up the display.
1013*d83cc019SAndroid Build Coastguard Worker */
chamelium_start_capture(struct chamelium * chamelium,struct chamelium_port * port,int x,int y,int w,int h)1014*d83cc019SAndroid Build Coastguard Worker void chamelium_start_capture(struct chamelium *chamelium,
1015*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port, int x, int y, int w, int h)
1016*d83cc019SAndroid Build Coastguard Worker {
1017*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(chamelium_rpc(chamelium, port, "StartCapturingVideo",
1018*d83cc019SAndroid Build Coastguard Worker (w && h) ? "(iiiii)" : "(innnn)",
1019*d83cc019SAndroid Build Coastguard Worker port->id, x, y, w, h));
1020*d83cc019SAndroid Build Coastguard Worker chamelium->capturing_port = port;
1021*d83cc019SAndroid Build Coastguard Worker }
1022*d83cc019SAndroid Build Coastguard Worker
1023*d83cc019SAndroid Build Coastguard Worker /**
1024*d83cc019SAndroid Build Coastguard Worker * chamelium_stop_capture:
1025*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
1026*d83cc019SAndroid Build Coastguard Worker * @frame_count: The number of frames to wait to capture, or %0 to stop
1027*d83cc019SAndroid Build Coastguard Worker * immediately
1028*d83cc019SAndroid Build Coastguard Worker *
1029*d83cc019SAndroid Build Coastguard Worker * Finishes capturing video frames on the given Chamelium port. If @frame_count
1030*d83cc019SAndroid Build Coastguard Worker * is specified, this call will block until the given number of frames have been
1031*d83cc019SAndroid Build Coastguard Worker * captured.
1032*d83cc019SAndroid Build Coastguard Worker */
chamelium_stop_capture(struct chamelium * chamelium,int frame_count)1033*d83cc019SAndroid Build Coastguard Worker void chamelium_stop_capture(struct chamelium *chamelium, int frame_count)
1034*d83cc019SAndroid Build Coastguard Worker {
1035*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(chamelium_rpc(chamelium, NULL, "StopCapturingVideo",
1036*d83cc019SAndroid Build Coastguard Worker "(i)", frame_count));
1037*d83cc019SAndroid Build Coastguard Worker }
1038*d83cc019SAndroid Build Coastguard Worker
1039*d83cc019SAndroid Build Coastguard Worker /**
1040*d83cc019SAndroid Build Coastguard Worker * chamelium_capture:
1041*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
1042*d83cc019SAndroid Build Coastguard Worker * @port: The port to perform the video capture on
1043*d83cc019SAndroid Build Coastguard Worker * @x: The X coordinate to crop the video to
1044*d83cc019SAndroid Build Coastguard Worker * @y: The Y coordinate to crop the video to
1045*d83cc019SAndroid Build Coastguard Worker * @w: The width of the cropped video, or %0 for the whole display
1046*d83cc019SAndroid Build Coastguard Worker * @h: The height of the cropped video, or %0 for the whole display
1047*d83cc019SAndroid Build Coastguard Worker * @frame_count: The number of frames to capture
1048*d83cc019SAndroid Build Coastguard Worker *
1049*d83cc019SAndroid Build Coastguard Worker * Captures the given number of frames on the chamelium. This is equivalent to
1050*d83cc019SAndroid Build Coastguard Worker * calling #chamelium_start_capture immediately followed by
1051*d83cc019SAndroid Build Coastguard Worker * #chamelium_stop_capture. The caller is blocked until all of the frames have
1052*d83cc019SAndroid Build Coastguard Worker * been captured.
1053*d83cc019SAndroid Build Coastguard Worker *
1054*d83cc019SAndroid Build Coastguard Worker * As an important note: some of the EDIDs provided by the Chamelium cause
1055*d83cc019SAndroid Build Coastguard Worker * certain GPU drivers to default to using limited color ranges. This can cause
1056*d83cc019SAndroid Build Coastguard Worker * video captures from the Chamelium to provide different images then expected
1057*d83cc019SAndroid Build Coastguard Worker * due to the difference in color ranges (framebuffer uses full color range,
1058*d83cc019SAndroid Build Coastguard Worker * but the video output doesn't), and as a result lead to CRC and frame dump
1059*d83cc019SAndroid Build Coastguard Worker * comparison mismatches. To workaround this, the caller should force the
1060*d83cc019SAndroid Build Coastguard Worker * connector to use full color ranges by using
1061*d83cc019SAndroid Build Coastguard Worker * #kmstest_set_connector_broadcast_rgb before setting up the display.
1062*d83cc019SAndroid Build Coastguard Worker */
chamelium_capture(struct chamelium * chamelium,struct chamelium_port * port,int x,int y,int w,int h,int frame_count)1063*d83cc019SAndroid Build Coastguard Worker void chamelium_capture(struct chamelium *chamelium, struct chamelium_port *port,
1064*d83cc019SAndroid Build Coastguard Worker int x, int y, int w, int h, int frame_count)
1065*d83cc019SAndroid Build Coastguard Worker {
1066*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(chamelium_rpc(chamelium, port, "CaptureVideo",
1067*d83cc019SAndroid Build Coastguard Worker (w && h) ? "(iiiiii)" : "(iinnnn)",
1068*d83cc019SAndroid Build Coastguard Worker port->id, frame_count, x, y, w, h));
1069*d83cc019SAndroid Build Coastguard Worker chamelium->capturing_port = port;
1070*d83cc019SAndroid Build Coastguard Worker }
1071*d83cc019SAndroid Build Coastguard Worker
1072*d83cc019SAndroid Build Coastguard Worker /**
1073*d83cc019SAndroid Build Coastguard Worker * chamelium_read_captured_crcs:
1074*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
1075*d83cc019SAndroid Build Coastguard Worker * @frame_count: Where to store the number of CRCs we read in
1076*d83cc019SAndroid Build Coastguard Worker *
1077*d83cc019SAndroid Build Coastguard Worker * Reads all of the CRCs that have been captured thus far from the Chamelium.
1078*d83cc019SAndroid Build Coastguard Worker *
1079*d83cc019SAndroid Build Coastguard Worker * Returns: An array of @frame_count length containing all of the CRCs we read
1080*d83cc019SAndroid Build Coastguard Worker */
chamelium_read_captured_crcs(struct chamelium * chamelium,int * frame_count)1081*d83cc019SAndroid Build Coastguard Worker igt_crc_t *chamelium_read_captured_crcs(struct chamelium *chamelium,
1082*d83cc019SAndroid Build Coastguard Worker int *frame_count)
1083*d83cc019SAndroid Build Coastguard Worker {
1084*d83cc019SAndroid Build Coastguard Worker igt_crc_t *ret;
1085*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res, *elem;
1086*d83cc019SAndroid Build Coastguard Worker int i;
1087*d83cc019SAndroid Build Coastguard Worker
1088*d83cc019SAndroid Build Coastguard Worker res = chamelium_rpc(chamelium, NULL, "GetCapturedChecksums", "(in)", 0);
1089*d83cc019SAndroid Build Coastguard Worker
1090*d83cc019SAndroid Build Coastguard Worker *frame_count = xmlrpc_array_size(&chamelium->env, res);
1091*d83cc019SAndroid Build Coastguard Worker ret = calloc(sizeof(igt_crc_t), *frame_count);
1092*d83cc019SAndroid Build Coastguard Worker
1093*d83cc019SAndroid Build Coastguard Worker for (i = 0; i < *frame_count; i++) {
1094*d83cc019SAndroid Build Coastguard Worker xmlrpc_array_read_item(&chamelium->env, res, i, &elem);
1095*d83cc019SAndroid Build Coastguard Worker
1096*d83cc019SAndroid Build Coastguard Worker crc_from_xml(chamelium, elem, &ret[i]);
1097*d83cc019SAndroid Build Coastguard Worker ret[i].frame = i;
1098*d83cc019SAndroid Build Coastguard Worker
1099*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(elem);
1100*d83cc019SAndroid Build Coastguard Worker }
1101*d83cc019SAndroid Build Coastguard Worker
1102*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res);
1103*d83cc019SAndroid Build Coastguard Worker
1104*d83cc019SAndroid Build Coastguard Worker return ret;
1105*d83cc019SAndroid Build Coastguard Worker }
1106*d83cc019SAndroid Build Coastguard Worker
1107*d83cc019SAndroid Build Coastguard Worker /**
1108*d83cc019SAndroid Build Coastguard Worker * chamelium_port_read_captured_frame:
1109*d83cc019SAndroid Build Coastguard Worker *
1110*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
1111*d83cc019SAndroid Build Coastguard Worker * @index: The index of the captured frame we want to get
1112*d83cc019SAndroid Build Coastguard Worker *
1113*d83cc019SAndroid Build Coastguard Worker * Retrieves a single video frame captured during the last video capture on the
1114*d83cc019SAndroid Build Coastguard Worker * Chamelium. This data should be freed using #chamelium_destroy_frame_data
1115*d83cc019SAndroid Build Coastguard Worker *
1116*d83cc019SAndroid Build Coastguard Worker * Returns: a chamelium_frame_dump struct
1117*d83cc019SAndroid Build Coastguard Worker */
chamelium_read_captured_frame(struct chamelium * chamelium,unsigned int index)1118*d83cc019SAndroid Build Coastguard Worker struct chamelium_frame_dump *chamelium_read_captured_frame(struct chamelium *chamelium,
1119*d83cc019SAndroid Build Coastguard Worker unsigned int index)
1120*d83cc019SAndroid Build Coastguard Worker {
1121*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res;
1122*d83cc019SAndroid Build Coastguard Worker struct chamelium_frame_dump *frame;
1123*d83cc019SAndroid Build Coastguard Worker
1124*d83cc019SAndroid Build Coastguard Worker res = chamelium_rpc(chamelium, NULL, "ReadCapturedFrame", "(i)", index);
1125*d83cc019SAndroid Build Coastguard Worker frame = frame_from_xml(chamelium, res);
1126*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res);
1127*d83cc019SAndroid Build Coastguard Worker
1128*d83cc019SAndroid Build Coastguard Worker return frame;
1129*d83cc019SAndroid Build Coastguard Worker }
1130*d83cc019SAndroid Build Coastguard Worker
1131*d83cc019SAndroid Build Coastguard Worker /**
1132*d83cc019SAndroid Build Coastguard Worker * chamelium_get_captured_frame_count:
1133*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
1134*d83cc019SAndroid Build Coastguard Worker *
1135*d83cc019SAndroid Build Coastguard Worker * Gets the number of frames that were captured during the last video capture.
1136*d83cc019SAndroid Build Coastguard Worker *
1137*d83cc019SAndroid Build Coastguard Worker * Returns: the number of frames the Chamelium captured during the last video
1138*d83cc019SAndroid Build Coastguard Worker * capture.
1139*d83cc019SAndroid Build Coastguard Worker */
chamelium_get_captured_frame_count(struct chamelium * chamelium)1140*d83cc019SAndroid Build Coastguard Worker int chamelium_get_captured_frame_count(struct chamelium *chamelium)
1141*d83cc019SAndroid Build Coastguard Worker {
1142*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res;
1143*d83cc019SAndroid Build Coastguard Worker int ret;
1144*d83cc019SAndroid Build Coastguard Worker
1145*d83cc019SAndroid Build Coastguard Worker res = chamelium_rpc(chamelium, NULL, "GetCapturedFrameCount", "()");
1146*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_int(&chamelium->env, res, &ret);
1147*d83cc019SAndroid Build Coastguard Worker
1148*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res);
1149*d83cc019SAndroid Build Coastguard Worker return ret;
1150*d83cc019SAndroid Build Coastguard Worker }
1151*d83cc019SAndroid Build Coastguard Worker
chamelium_supports_get_last_infoframe(struct chamelium * chamelium)1152*d83cc019SAndroid Build Coastguard Worker bool chamelium_supports_get_last_infoframe(struct chamelium *chamelium)
1153*d83cc019SAndroid Build Coastguard Worker {
1154*d83cc019SAndroid Build Coastguard Worker return chamelium_supports_method(chamelium, "GetLastInfoFrame");
1155*d83cc019SAndroid Build Coastguard Worker }
1156*d83cc019SAndroid Build Coastguard Worker
1157*d83cc019SAndroid Build Coastguard Worker static const char *
chamelium_infoframe_type_str(enum chamelium_infoframe_type type)1158*d83cc019SAndroid Build Coastguard Worker chamelium_infoframe_type_str(enum chamelium_infoframe_type type)
1159*d83cc019SAndroid Build Coastguard Worker {
1160*d83cc019SAndroid Build Coastguard Worker switch (type) {
1161*d83cc019SAndroid Build Coastguard Worker case CHAMELIUM_INFOFRAME_AVI:
1162*d83cc019SAndroid Build Coastguard Worker return "avi";
1163*d83cc019SAndroid Build Coastguard Worker case CHAMELIUM_INFOFRAME_AUDIO:
1164*d83cc019SAndroid Build Coastguard Worker return "audio";
1165*d83cc019SAndroid Build Coastguard Worker case CHAMELIUM_INFOFRAME_MPEG:
1166*d83cc019SAndroid Build Coastguard Worker return "mpeg";
1167*d83cc019SAndroid Build Coastguard Worker case CHAMELIUM_INFOFRAME_VENDOR:
1168*d83cc019SAndroid Build Coastguard Worker return "vendor";
1169*d83cc019SAndroid Build Coastguard Worker }
1170*d83cc019SAndroid Build Coastguard Worker assert(0); /* unreachable */
1171*d83cc019SAndroid Build Coastguard Worker }
1172*d83cc019SAndroid Build Coastguard Worker
1173*d83cc019SAndroid Build Coastguard Worker struct chamelium_infoframe *
chamelium_get_last_infoframe(struct chamelium * chamelium,struct chamelium_port * port,enum chamelium_infoframe_type type)1174*d83cc019SAndroid Build Coastguard Worker chamelium_get_last_infoframe(struct chamelium *chamelium,
1175*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port,
1176*d83cc019SAndroid Build Coastguard Worker enum chamelium_infoframe_type type)
1177*d83cc019SAndroid Build Coastguard Worker {
1178*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res, *res_version, *res_payload;
1179*d83cc019SAndroid Build Coastguard Worker struct chamelium_infoframe *infoframe;
1180*d83cc019SAndroid Build Coastguard Worker const unsigned char *payload;
1181*d83cc019SAndroid Build Coastguard Worker
1182*d83cc019SAndroid Build Coastguard Worker res = chamelium_rpc(chamelium, NULL, "GetLastInfoFrame", "(is)",
1183*d83cc019SAndroid Build Coastguard Worker port->id, chamelium_infoframe_type_str(type));
1184*d83cc019SAndroid Build Coastguard Worker xmlrpc_struct_find_value(&chamelium->env, res, "version", &res_version);
1185*d83cc019SAndroid Build Coastguard Worker xmlrpc_struct_find_value(&chamelium->env, res, "payload", &res_payload);
1186*d83cc019SAndroid Build Coastguard Worker infoframe = calloc(1, sizeof(*infoframe));
1187*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_int(&chamelium->env, res_version, &infoframe->version);
1188*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_base64(&chamelium->env, res_payload,
1189*d83cc019SAndroid Build Coastguard Worker &infoframe->payload_size, &payload);
1190*d83cc019SAndroid Build Coastguard Worker /* xmlrpc-c's docs say payload is actually not constant */
1191*d83cc019SAndroid Build Coastguard Worker infoframe->payload = (uint8_t *) payload;
1192*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res_version);
1193*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res_payload);
1194*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res);
1195*d83cc019SAndroid Build Coastguard Worker
1196*d83cc019SAndroid Build Coastguard Worker if (infoframe->payload_size == 0) {
1197*d83cc019SAndroid Build Coastguard Worker chamelium_infoframe_destroy(infoframe);
1198*d83cc019SAndroid Build Coastguard Worker return NULL;
1199*d83cc019SAndroid Build Coastguard Worker }
1200*d83cc019SAndroid Build Coastguard Worker return infoframe;
1201*d83cc019SAndroid Build Coastguard Worker }
1202*d83cc019SAndroid Build Coastguard Worker
chamelium_infoframe_destroy(struct chamelium_infoframe * infoframe)1203*d83cc019SAndroid Build Coastguard Worker void chamelium_infoframe_destroy(struct chamelium_infoframe *infoframe)
1204*d83cc019SAndroid Build Coastguard Worker {
1205*d83cc019SAndroid Build Coastguard Worker free(infoframe->payload);
1206*d83cc019SAndroid Build Coastguard Worker free(infoframe);
1207*d83cc019SAndroid Build Coastguard Worker }
1208*d83cc019SAndroid Build Coastguard Worker
chamelium_supports_trigger_link_failure(struct chamelium * chamelium)1209*d83cc019SAndroid Build Coastguard Worker bool chamelium_supports_trigger_link_failure(struct chamelium *chamelium)
1210*d83cc019SAndroid Build Coastguard Worker {
1211*d83cc019SAndroid Build Coastguard Worker return chamelium_supports_method(chamelium, "TriggerLinkFailure");
1212*d83cc019SAndroid Build Coastguard Worker }
1213*d83cc019SAndroid Build Coastguard Worker
1214*d83cc019SAndroid Build Coastguard Worker /**
1215*d83cc019SAndroid Build Coastguard Worker * chamelium_trigger_link_failure: trigger a link failure on the provided port.
1216*d83cc019SAndroid Build Coastguard Worker */
chamelium_trigger_link_failure(struct chamelium * chamelium,struct chamelium_port * port)1217*d83cc019SAndroid Build Coastguard Worker void chamelium_trigger_link_failure(struct chamelium *chamelium,
1218*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port)
1219*d83cc019SAndroid Build Coastguard Worker {
1220*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(chamelium_rpc(chamelium, port, "TriggerLinkFailure",
1221*d83cc019SAndroid Build Coastguard Worker "(i)", port->id));
1222*d83cc019SAndroid Build Coastguard Worker }
1223*d83cc019SAndroid Build Coastguard Worker
chamelium_has_audio_support(struct chamelium * chamelium,struct chamelium_port * port)1224*d83cc019SAndroid Build Coastguard Worker bool chamelium_has_audio_support(struct chamelium *chamelium,
1225*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port)
1226*d83cc019SAndroid Build Coastguard Worker {
1227*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res;
1228*d83cc019SAndroid Build Coastguard Worker xmlrpc_bool has_support;
1229*d83cc019SAndroid Build Coastguard Worker
1230*d83cc019SAndroid Build Coastguard Worker if (!chamelium_supports_method(chamelium, "GetAudioFormat")) {
1231*d83cc019SAndroid Build Coastguard Worker igt_debug("The Chamelium device doesn't support GetAudioFormat\n");
1232*d83cc019SAndroid Build Coastguard Worker return false;
1233*d83cc019SAndroid Build Coastguard Worker }
1234*d83cc019SAndroid Build Coastguard Worker
1235*d83cc019SAndroid Build Coastguard Worker res = chamelium_rpc(chamelium, port, "HasAudioSupport", "(i)", port->id);
1236*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_bool(&chamelium->env, res, &has_support);
1237*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res);
1238*d83cc019SAndroid Build Coastguard Worker
1239*d83cc019SAndroid Build Coastguard Worker return has_support;
1240*d83cc019SAndroid Build Coastguard Worker }
1241*d83cc019SAndroid Build Coastguard Worker
1242*d83cc019SAndroid Build Coastguard Worker /**
1243*d83cc019SAndroid Build Coastguard Worker * chamelium_get_audio_channel_mapping:
1244*d83cc019SAndroid Build Coastguard Worker * @chamelium: the Chamelium instance
1245*d83cc019SAndroid Build Coastguard Worker * @port: the audio port
1246*d83cc019SAndroid Build Coastguard Worker * @mapping: will be filled with the channel mapping
1247*d83cc019SAndroid Build Coastguard Worker *
1248*d83cc019SAndroid Build Coastguard Worker * Obtains the channel mapping for an audio port.
1249*d83cc019SAndroid Build Coastguard Worker *
1250*d83cc019SAndroid Build Coastguard Worker * Audio channels are not guaranteed not to be swapped. Users can use the
1251*d83cc019SAndroid Build Coastguard Worker * channel mapping to match an input channel to a capture channel.
1252*d83cc019SAndroid Build Coastguard Worker *
1253*d83cc019SAndroid Build Coastguard Worker * The mapping contains one element per capture channel. Each element indicates
1254*d83cc019SAndroid Build Coastguard Worker * which input channel the capture channel is mapped to. As a special case, -1
1255*d83cc019SAndroid Build Coastguard Worker * means that the channel isn't mapped.
1256*d83cc019SAndroid Build Coastguard Worker */
chamelium_get_audio_channel_mapping(struct chamelium * chamelium,struct chamelium_port * port,int mapping[static CHAMELIUM_MAX_AUDIO_CHANNELS])1257*d83cc019SAndroid Build Coastguard Worker void chamelium_get_audio_channel_mapping(struct chamelium *chamelium,
1258*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port,
1259*d83cc019SAndroid Build Coastguard Worker int mapping[static CHAMELIUM_MAX_AUDIO_CHANNELS])
1260*d83cc019SAndroid Build Coastguard Worker {
1261*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res, *res_channel;
1262*d83cc019SAndroid Build Coastguard Worker int res_len, i;
1263*d83cc019SAndroid Build Coastguard Worker
1264*d83cc019SAndroid Build Coastguard Worker res = chamelium_rpc(chamelium, port, "GetAudioChannelMapping", "(i)",
1265*d83cc019SAndroid Build Coastguard Worker port->id);
1266*d83cc019SAndroid Build Coastguard Worker res_len = xmlrpc_array_size(&chamelium->env, res);
1267*d83cc019SAndroid Build Coastguard Worker igt_assert(res_len == CHAMELIUM_MAX_AUDIO_CHANNELS);
1268*d83cc019SAndroid Build Coastguard Worker for (i = 0; i < res_len; i++) {
1269*d83cc019SAndroid Build Coastguard Worker xmlrpc_array_read_item(&chamelium->env, res, i, &res_channel);
1270*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_int(&chamelium->env, res_channel, &mapping[i]);
1271*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res_channel);
1272*d83cc019SAndroid Build Coastguard Worker }
1273*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res);
1274*d83cc019SAndroid Build Coastguard Worker }
1275*d83cc019SAndroid Build Coastguard Worker
audio_format_from_xml(struct chamelium * chamelium,xmlrpc_value * res,int * rate,int * channels)1276*d83cc019SAndroid Build Coastguard Worker static void audio_format_from_xml(struct chamelium *chamelium,
1277*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res, int *rate, int *channels)
1278*d83cc019SAndroid Build Coastguard Worker {
1279*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res_type, *res_rate, *res_sample_format, *res_channel;
1280*d83cc019SAndroid Build Coastguard Worker char *type, *sample_format;
1281*d83cc019SAndroid Build Coastguard Worker
1282*d83cc019SAndroid Build Coastguard Worker xmlrpc_struct_find_value(&chamelium->env, res, "file_type", &res_type);
1283*d83cc019SAndroid Build Coastguard Worker xmlrpc_struct_find_value(&chamelium->env, res, "rate", &res_rate);
1284*d83cc019SAndroid Build Coastguard Worker xmlrpc_struct_find_value(&chamelium->env, res, "sample_format", &res_sample_format);
1285*d83cc019SAndroid Build Coastguard Worker xmlrpc_struct_find_value(&chamelium->env, res, "channel", &res_channel);
1286*d83cc019SAndroid Build Coastguard Worker
1287*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_string(&chamelium->env, res_type, (const char **) &type);
1288*d83cc019SAndroid Build Coastguard Worker igt_assert(strcmp(type, "raw") == 0);
1289*d83cc019SAndroid Build Coastguard Worker free(type);
1290*d83cc019SAndroid Build Coastguard Worker
1291*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_string(&chamelium->env, res_sample_format, (const char **) &sample_format);
1292*d83cc019SAndroid Build Coastguard Worker igt_assert(strcmp(sample_format, "S32_LE") == 0);
1293*d83cc019SAndroid Build Coastguard Worker free(sample_format);
1294*d83cc019SAndroid Build Coastguard Worker
1295*d83cc019SAndroid Build Coastguard Worker if (rate)
1296*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_int(&chamelium->env, res_rate, rate);
1297*d83cc019SAndroid Build Coastguard Worker if (channels) {
1298*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_int(&chamelium->env, res_channel, channels);
1299*d83cc019SAndroid Build Coastguard Worker igt_assert(*channels <= CHAMELIUM_MAX_AUDIO_CHANNELS);
1300*d83cc019SAndroid Build Coastguard Worker }
1301*d83cc019SAndroid Build Coastguard Worker
1302*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res_channel);
1303*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res_sample_format);
1304*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res_rate);
1305*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res_type);
1306*d83cc019SAndroid Build Coastguard Worker }
1307*d83cc019SAndroid Build Coastguard Worker
1308*d83cc019SAndroid Build Coastguard Worker /**
1309*d83cc019SAndroid Build Coastguard Worker * chamelium_get_audio_format:
1310*d83cc019SAndroid Build Coastguard Worker * @chamelium: the Chamelium instance
1311*d83cc019SAndroid Build Coastguard Worker * @port: the audio port
1312*d83cc019SAndroid Build Coastguard Worker * @rate: if non-NULL, will be set to the sample rate in Hz
1313*d83cc019SAndroid Build Coastguard Worker * @channels: if non-NULL, will be set to the number of channels
1314*d83cc019SAndroid Build Coastguard Worker *
1315*d83cc019SAndroid Build Coastguard Worker * Obtains the audio format of the captured data. Users should start sending an
1316*d83cc019SAndroid Build Coastguard Worker * audio signal to the Chamelium device prior to calling this function.
1317*d83cc019SAndroid Build Coastguard Worker *
1318*d83cc019SAndroid Build Coastguard Worker * The captured data is guaranteed to be in the S32_LE format.
1319*d83cc019SAndroid Build Coastguard Worker */
chamelium_get_audio_format(struct chamelium * chamelium,struct chamelium_port * port,int * rate,int * channels)1320*d83cc019SAndroid Build Coastguard Worker void chamelium_get_audio_format(struct chamelium *chamelium,
1321*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port,
1322*d83cc019SAndroid Build Coastguard Worker int *rate, int *channels)
1323*d83cc019SAndroid Build Coastguard Worker {
1324*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res;
1325*d83cc019SAndroid Build Coastguard Worker
1326*d83cc019SAndroid Build Coastguard Worker res = chamelium_rpc(chamelium, port, "GetAudioFormat", "(i)",
1327*d83cc019SAndroid Build Coastguard Worker port->id);
1328*d83cc019SAndroid Build Coastguard Worker audio_format_from_xml(chamelium, res, rate, channels);
1329*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res);
1330*d83cc019SAndroid Build Coastguard Worker }
1331*d83cc019SAndroid Build Coastguard Worker
1332*d83cc019SAndroid Build Coastguard Worker /**
1333*d83cc019SAndroid Build Coastguard Worker * chamelium_start_capturing_audio:
1334*d83cc019SAndroid Build Coastguard Worker * @chamelium: the Chamelium instance
1335*d83cc019SAndroid Build Coastguard Worker * @port: the port to capture audio from (it must support audio)
1336*d83cc019SAndroid Build Coastguard Worker * @save_to_file: whether the captured audio data should be saved to a file on
1337*d83cc019SAndroid Build Coastguard Worker * the Chamelium device
1338*d83cc019SAndroid Build Coastguard Worker *
1339*d83cc019SAndroid Build Coastguard Worker * Starts capturing audio from a Chamelium port. To stop the capture, use
1340*d83cc019SAndroid Build Coastguard Worker * #chamelium_stop_capturing_audio. To retrieve the audio data, either use the
1341*d83cc019SAndroid Build Coastguard Worker * stream server or enable @save_to_file (the latter is mainly useful for
1342*d83cc019SAndroid Build Coastguard Worker * debugging purposes).
1343*d83cc019SAndroid Build Coastguard Worker *
1344*d83cc019SAndroid Build Coastguard Worker * It isn't possible to capture audio from multiple ports at the same time.
1345*d83cc019SAndroid Build Coastguard Worker */
chamelium_start_capturing_audio(struct chamelium * chamelium,struct chamelium_port * port,bool save_to_file)1346*d83cc019SAndroid Build Coastguard Worker void chamelium_start_capturing_audio(struct chamelium *chamelium,
1347*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port,
1348*d83cc019SAndroid Build Coastguard Worker bool save_to_file)
1349*d83cc019SAndroid Build Coastguard Worker {
1350*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res;
1351*d83cc019SAndroid Build Coastguard Worker
1352*d83cc019SAndroid Build Coastguard Worker res = chamelium_rpc(chamelium, port, "StartCapturingAudio", "(ib)",
1353*d83cc019SAndroid Build Coastguard Worker port->id, save_to_file);
1354*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res);
1355*d83cc019SAndroid Build Coastguard Worker }
1356*d83cc019SAndroid Build Coastguard Worker
1357*d83cc019SAndroid Build Coastguard Worker /**
1358*d83cc019SAndroid Build Coastguard Worker * chamelium_stop_capturing_audio:
1359*d83cc019SAndroid Build Coastguard Worker * @chamelium: the Chamelium instance
1360*d83cc019SAndroid Build Coastguard Worker * @port: the port from which audio is being captured
1361*d83cc019SAndroid Build Coastguard Worker *
1362*d83cc019SAndroid Build Coastguard Worker * Stops capturing audio from a Chamelium port. If
1363*d83cc019SAndroid Build Coastguard Worker * #chamelium_start_capturing_audio has been called with @save_to_file enabled,
1364*d83cc019SAndroid Build Coastguard Worker * this function will return a #chamelium_audio_file struct containing details
1365*d83cc019SAndroid Build Coastguard Worker * about the audio file. Once the caller is done with the struct, they should
1366*d83cc019SAndroid Build Coastguard Worker * release it with #chamelium_destroy_audio_file.
1367*d83cc019SAndroid Build Coastguard Worker */
chamelium_stop_capturing_audio(struct chamelium * chamelium,struct chamelium_port * port)1368*d83cc019SAndroid Build Coastguard Worker struct chamelium_audio_file *chamelium_stop_capturing_audio(struct chamelium *chamelium,
1369*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port)
1370*d83cc019SAndroid Build Coastguard Worker {
1371*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res, *res_path, *res_props;
1372*d83cc019SAndroid Build Coastguard Worker struct chamelium_audio_file *file = NULL;
1373*d83cc019SAndroid Build Coastguard Worker char *path;
1374*d83cc019SAndroid Build Coastguard Worker
1375*d83cc019SAndroid Build Coastguard Worker res = chamelium_rpc(chamelium, NULL, "StopCapturingAudio", "(i)",
1376*d83cc019SAndroid Build Coastguard Worker port->id);
1377*d83cc019SAndroid Build Coastguard Worker xmlrpc_array_read_item(&chamelium->env, res, 0, &res_path);
1378*d83cc019SAndroid Build Coastguard Worker xmlrpc_array_read_item(&chamelium->env, res, 1, &res_props);
1379*d83cc019SAndroid Build Coastguard Worker
1380*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_string(&chamelium->env, res_path, (const char **) &path);
1381*d83cc019SAndroid Build Coastguard Worker
1382*d83cc019SAndroid Build Coastguard Worker if (strlen(path) > 0) {
1383*d83cc019SAndroid Build Coastguard Worker file = calloc(1, sizeof(*file));
1384*d83cc019SAndroid Build Coastguard Worker file->path = path;
1385*d83cc019SAndroid Build Coastguard Worker
1386*d83cc019SAndroid Build Coastguard Worker audio_format_from_xml(chamelium, res_props,
1387*d83cc019SAndroid Build Coastguard Worker &file->rate, &file->channels);
1388*d83cc019SAndroid Build Coastguard Worker } else {
1389*d83cc019SAndroid Build Coastguard Worker free(path);
1390*d83cc019SAndroid Build Coastguard Worker }
1391*d83cc019SAndroid Build Coastguard Worker
1392*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res_props);
1393*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res_path);
1394*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res);
1395*d83cc019SAndroid Build Coastguard Worker
1396*d83cc019SAndroid Build Coastguard Worker return file;
1397*d83cc019SAndroid Build Coastguard Worker }
1398*d83cc019SAndroid Build Coastguard Worker
convert_frame_format(pixman_image_t * src,int format)1399*d83cc019SAndroid Build Coastguard Worker static pixman_image_t *convert_frame_format(pixman_image_t *src,
1400*d83cc019SAndroid Build Coastguard Worker int format)
1401*d83cc019SAndroid Build Coastguard Worker {
1402*d83cc019SAndroid Build Coastguard Worker pixman_image_t *converted;
1403*d83cc019SAndroid Build Coastguard Worker int w = pixman_image_get_width(src), h = pixman_image_get_height(src);
1404*d83cc019SAndroid Build Coastguard Worker
1405*d83cc019SAndroid Build Coastguard Worker converted = pixman_image_create_bits(format, w, h, NULL,
1406*d83cc019SAndroid Build Coastguard Worker PIXMAN_FORMAT_BPP(format) / 8 * w);
1407*d83cc019SAndroid Build Coastguard Worker pixman_image_composite(PIXMAN_OP_ADD, src, NULL, converted,
1408*d83cc019SAndroid Build Coastguard Worker 0, 0, 0, 0, 0, 0, w, h);
1409*d83cc019SAndroid Build Coastguard Worker
1410*d83cc019SAndroid Build Coastguard Worker return converted;
1411*d83cc019SAndroid Build Coastguard Worker }
1412*d83cc019SAndroid Build Coastguard Worker
convert_frame_dump_argb32(const struct chamelium_frame_dump * dump)1413*d83cc019SAndroid Build Coastguard Worker static cairo_surface_t *convert_frame_dump_argb32(const struct chamelium_frame_dump *dump)
1414*d83cc019SAndroid Build Coastguard Worker {
1415*d83cc019SAndroid Build Coastguard Worker cairo_surface_t *dump_surface;
1416*d83cc019SAndroid Build Coastguard Worker pixman_image_t *image_bgr;
1417*d83cc019SAndroid Build Coastguard Worker pixman_image_t *image_argb;
1418*d83cc019SAndroid Build Coastguard Worker int w = dump->width, h = dump->height;
1419*d83cc019SAndroid Build Coastguard Worker uint32_t *bits_bgr = (uint32_t *) dump->bgr;
1420*d83cc019SAndroid Build Coastguard Worker unsigned char *bits_argb;
1421*d83cc019SAndroid Build Coastguard Worker unsigned char *bits_target;
1422*d83cc019SAndroid Build Coastguard Worker int size;
1423*d83cc019SAndroid Build Coastguard Worker
1424*d83cc019SAndroid Build Coastguard Worker image_bgr = pixman_image_create_bits(
1425*d83cc019SAndroid Build Coastguard Worker PIXMAN_b8g8r8, w, h, bits_bgr,
1426*d83cc019SAndroid Build Coastguard Worker PIXMAN_FORMAT_BPP(PIXMAN_b8g8r8) / 8 * w);
1427*d83cc019SAndroid Build Coastguard Worker image_argb = convert_frame_format(image_bgr, PIXMAN_x8r8g8b8);
1428*d83cc019SAndroid Build Coastguard Worker pixman_image_unref(image_bgr);
1429*d83cc019SAndroid Build Coastguard Worker
1430*d83cc019SAndroid Build Coastguard Worker bits_argb = (unsigned char *) pixman_image_get_data(image_argb);
1431*d83cc019SAndroid Build Coastguard Worker
1432*d83cc019SAndroid Build Coastguard Worker dump_surface = cairo_image_surface_create(
1433*d83cc019SAndroid Build Coastguard Worker CAIRO_FORMAT_ARGB32, w, h);
1434*d83cc019SAndroid Build Coastguard Worker
1435*d83cc019SAndroid Build Coastguard Worker bits_target = cairo_image_surface_get_data(dump_surface);
1436*d83cc019SAndroid Build Coastguard Worker size = cairo_image_surface_get_stride(dump_surface) * h;
1437*d83cc019SAndroid Build Coastguard Worker memcpy(bits_target, bits_argb, size);
1438*d83cc019SAndroid Build Coastguard Worker cairo_surface_mark_dirty(dump_surface);
1439*d83cc019SAndroid Build Coastguard Worker
1440*d83cc019SAndroid Build Coastguard Worker pixman_image_unref(image_argb);
1441*d83cc019SAndroid Build Coastguard Worker
1442*d83cc019SAndroid Build Coastguard Worker return dump_surface;
1443*d83cc019SAndroid Build Coastguard Worker }
1444*d83cc019SAndroid Build Coastguard Worker
compared_frames_dump(cairo_surface_t * reference,cairo_surface_t * capture,igt_crc_t * reference_crc,igt_crc_t * capture_crc)1445*d83cc019SAndroid Build Coastguard Worker static void compared_frames_dump(cairo_surface_t *reference,
1446*d83cc019SAndroid Build Coastguard Worker cairo_surface_t *capture,
1447*d83cc019SAndroid Build Coastguard Worker igt_crc_t *reference_crc,
1448*d83cc019SAndroid Build Coastguard Worker igt_crc_t *capture_crc)
1449*d83cc019SAndroid Build Coastguard Worker {
1450*d83cc019SAndroid Build Coastguard Worker char *reference_suffix;
1451*d83cc019SAndroid Build Coastguard Worker char *capture_suffix;
1452*d83cc019SAndroid Build Coastguard Worker igt_crc_t local_reference_crc;
1453*d83cc019SAndroid Build Coastguard Worker igt_crc_t local_capture_crc;
1454*d83cc019SAndroid Build Coastguard Worker
1455*d83cc019SAndroid Build Coastguard Worker igt_assert(reference && capture);
1456*d83cc019SAndroid Build Coastguard Worker
1457*d83cc019SAndroid Build Coastguard Worker if (!reference_crc) {
1458*d83cc019SAndroid Build Coastguard Worker chamelium_do_calculate_fb_crc(reference, &local_reference_crc);
1459*d83cc019SAndroid Build Coastguard Worker reference_crc = &local_reference_crc;
1460*d83cc019SAndroid Build Coastguard Worker }
1461*d83cc019SAndroid Build Coastguard Worker
1462*d83cc019SAndroid Build Coastguard Worker if (!capture_crc) {
1463*d83cc019SAndroid Build Coastguard Worker chamelium_do_calculate_fb_crc(reference, &local_capture_crc);
1464*d83cc019SAndroid Build Coastguard Worker capture_crc = &local_capture_crc;
1465*d83cc019SAndroid Build Coastguard Worker }
1466*d83cc019SAndroid Build Coastguard Worker
1467*d83cc019SAndroid Build Coastguard Worker reference_suffix = igt_crc_to_string_extended(reference_crc, '-', 2);
1468*d83cc019SAndroid Build Coastguard Worker capture_suffix = igt_crc_to_string_extended(capture_crc, '-', 2);
1469*d83cc019SAndroid Build Coastguard Worker
1470*d83cc019SAndroid Build Coastguard Worker /* Write reference and capture frames to png. */
1471*d83cc019SAndroid Build Coastguard Worker igt_write_compared_frames_to_png(reference, capture, reference_suffix,
1472*d83cc019SAndroid Build Coastguard Worker capture_suffix);
1473*d83cc019SAndroid Build Coastguard Worker
1474*d83cc019SAndroid Build Coastguard Worker free(reference_suffix);
1475*d83cc019SAndroid Build Coastguard Worker free(capture_suffix);
1476*d83cc019SAndroid Build Coastguard Worker }
1477*d83cc019SAndroid Build Coastguard Worker
1478*d83cc019SAndroid Build Coastguard Worker /**
1479*d83cc019SAndroid Build Coastguard Worker * chamelium_assert_frame_eq:
1480*d83cc019SAndroid Build Coastguard Worker * @chamelium: The chamelium instance the frame dump belongs to
1481*d83cc019SAndroid Build Coastguard Worker * @dump: The chamelium frame dump to check
1482*d83cc019SAndroid Build Coastguard Worker * @fb: The framebuffer to check against
1483*d83cc019SAndroid Build Coastguard Worker *
1484*d83cc019SAndroid Build Coastguard Worker * Asserts that the image contained in the chamelium frame dump is identical to
1485*d83cc019SAndroid Build Coastguard Worker * the given framebuffer. Useful for scenarios where pre-calculating CRCs might
1486*d83cc019SAndroid Build Coastguard Worker * not be ideal.
1487*d83cc019SAndroid Build Coastguard Worker */
chamelium_assert_frame_eq(const struct chamelium * chamelium,const struct chamelium_frame_dump * dump,struct igt_fb * fb)1488*d83cc019SAndroid Build Coastguard Worker void chamelium_assert_frame_eq(const struct chamelium *chamelium,
1489*d83cc019SAndroid Build Coastguard Worker const struct chamelium_frame_dump *dump,
1490*d83cc019SAndroid Build Coastguard Worker struct igt_fb *fb)
1491*d83cc019SAndroid Build Coastguard Worker {
1492*d83cc019SAndroid Build Coastguard Worker cairo_surface_t *fb_surface;
1493*d83cc019SAndroid Build Coastguard Worker pixman_image_t *reference_src, *reference_bgr;
1494*d83cc019SAndroid Build Coastguard Worker int w = dump->width, h = dump->height;
1495*d83cc019SAndroid Build Coastguard Worker bool eq;
1496*d83cc019SAndroid Build Coastguard Worker
1497*d83cc019SAndroid Build Coastguard Worker /* Get the cairo surface for the framebuffer */
1498*d83cc019SAndroid Build Coastguard Worker fb_surface = igt_get_cairo_surface(chamelium->drm_fd, fb);
1499*d83cc019SAndroid Build Coastguard Worker
1500*d83cc019SAndroid Build Coastguard Worker /*
1501*d83cc019SAndroid Build Coastguard Worker * Convert the reference image into the same format as the chamelium
1502*d83cc019SAndroid Build Coastguard Worker * image
1503*d83cc019SAndroid Build Coastguard Worker */
1504*d83cc019SAndroid Build Coastguard Worker reference_src = pixman_image_create_bits(
1505*d83cc019SAndroid Build Coastguard Worker PIXMAN_x8r8g8b8, w, h,
1506*d83cc019SAndroid Build Coastguard Worker (void*)cairo_image_surface_get_data(fb_surface),
1507*d83cc019SAndroid Build Coastguard Worker cairo_image_surface_get_stride(fb_surface));
1508*d83cc019SAndroid Build Coastguard Worker reference_bgr = convert_frame_format(reference_src, PIXMAN_b8g8r8);
1509*d83cc019SAndroid Build Coastguard Worker pixman_image_unref(reference_src);
1510*d83cc019SAndroid Build Coastguard Worker
1511*d83cc019SAndroid Build Coastguard Worker /* Now do the actual comparison */
1512*d83cc019SAndroid Build Coastguard Worker eq = memcmp(dump->bgr, pixman_image_get_data(reference_bgr),
1513*d83cc019SAndroid Build Coastguard Worker dump->size) == 0;
1514*d83cc019SAndroid Build Coastguard Worker
1515*d83cc019SAndroid Build Coastguard Worker pixman_image_unref(reference_bgr);
1516*d83cc019SAndroid Build Coastguard Worker
1517*d83cc019SAndroid Build Coastguard Worker igt_fail_on_f(!eq,
1518*d83cc019SAndroid Build Coastguard Worker "Chamelium frame dump didn't match reference image\n");
1519*d83cc019SAndroid Build Coastguard Worker }
1520*d83cc019SAndroid Build Coastguard Worker
1521*d83cc019SAndroid Build Coastguard Worker /**
1522*d83cc019SAndroid Build Coastguard Worker * chamelium_assert_crc_eq_or_dump:
1523*d83cc019SAndroid Build Coastguard Worker * @chamelium: The chamelium instance the frame dump belongs to
1524*d83cc019SAndroid Build Coastguard Worker * @reference_crc: The CRC for the reference frame
1525*d83cc019SAndroid Build Coastguard Worker * @capture_crc: The CRC for the captured frame
1526*d83cc019SAndroid Build Coastguard Worker * @fb: pointer to an #igt_fb structure
1527*d83cc019SAndroid Build Coastguard Worker *
1528*d83cc019SAndroid Build Coastguard Worker * Asserts that the CRC provided for both the reference and the captured frame
1529*d83cc019SAndroid Build Coastguard Worker * are identical. If they are not, this grabs the captured frame and saves it
1530*d83cc019SAndroid Build Coastguard Worker * along with the reference to a png file.
1531*d83cc019SAndroid Build Coastguard Worker */
chamelium_assert_crc_eq_or_dump(struct chamelium * chamelium,igt_crc_t * reference_crc,igt_crc_t * capture_crc,struct igt_fb * fb,int index)1532*d83cc019SAndroid Build Coastguard Worker void chamelium_assert_crc_eq_or_dump(struct chamelium *chamelium,
1533*d83cc019SAndroid Build Coastguard Worker igt_crc_t *reference_crc,
1534*d83cc019SAndroid Build Coastguard Worker igt_crc_t *capture_crc, struct igt_fb *fb,
1535*d83cc019SAndroid Build Coastguard Worker int index)
1536*d83cc019SAndroid Build Coastguard Worker {
1537*d83cc019SAndroid Build Coastguard Worker struct chamelium_frame_dump *frame;
1538*d83cc019SAndroid Build Coastguard Worker cairo_surface_t *reference;
1539*d83cc019SAndroid Build Coastguard Worker cairo_surface_t *capture;
1540*d83cc019SAndroid Build Coastguard Worker bool eq;
1541*d83cc019SAndroid Build Coastguard Worker
1542*d83cc019SAndroid Build Coastguard Worker igt_debug("Reference CRC: %s\n", igt_crc_to_string(reference_crc));
1543*d83cc019SAndroid Build Coastguard Worker igt_debug("Captured CRC: %s\n", igt_crc_to_string(capture_crc));
1544*d83cc019SAndroid Build Coastguard Worker
1545*d83cc019SAndroid Build Coastguard Worker eq = igt_check_crc_equal(reference_crc, capture_crc);
1546*d83cc019SAndroid Build Coastguard Worker if (!eq && igt_frame_dump_is_enabled()) {
1547*d83cc019SAndroid Build Coastguard Worker /* Convert the reference framebuffer to cairo. */
1548*d83cc019SAndroid Build Coastguard Worker reference = igt_get_cairo_surface(chamelium->drm_fd, fb);
1549*d83cc019SAndroid Build Coastguard Worker
1550*d83cc019SAndroid Build Coastguard Worker /* Grab the captured frame from the Chamelium. */
1551*d83cc019SAndroid Build Coastguard Worker frame = chamelium_read_captured_frame(chamelium, index);
1552*d83cc019SAndroid Build Coastguard Worker igt_assert(frame);
1553*d83cc019SAndroid Build Coastguard Worker
1554*d83cc019SAndroid Build Coastguard Worker /* Convert the captured frame to cairo. */
1555*d83cc019SAndroid Build Coastguard Worker capture = convert_frame_dump_argb32(frame);
1556*d83cc019SAndroid Build Coastguard Worker igt_assert(capture);
1557*d83cc019SAndroid Build Coastguard Worker
1558*d83cc019SAndroid Build Coastguard Worker compared_frames_dump(reference, capture, reference_crc,
1559*d83cc019SAndroid Build Coastguard Worker capture_crc);
1560*d83cc019SAndroid Build Coastguard Worker
1561*d83cc019SAndroid Build Coastguard Worker cairo_surface_destroy(reference);
1562*d83cc019SAndroid Build Coastguard Worker cairo_surface_destroy(capture);
1563*d83cc019SAndroid Build Coastguard Worker chamelium_destroy_frame_dump(frame);
1564*d83cc019SAndroid Build Coastguard Worker }
1565*d83cc019SAndroid Build Coastguard Worker
1566*d83cc019SAndroid Build Coastguard Worker igt_assert(eq);
1567*d83cc019SAndroid Build Coastguard Worker }
1568*d83cc019SAndroid Build Coastguard Worker
1569*d83cc019SAndroid Build Coastguard Worker /**
1570*d83cc019SAndroid Build Coastguard Worker * chamelium_assert_frame_match_or_dump:
1571*d83cc019SAndroid Build Coastguard Worker * @chamelium: The chamelium instance the frame dump belongs to
1572*d83cc019SAndroid Build Coastguard Worker * @frame: The chamelium frame dump to match
1573*d83cc019SAndroid Build Coastguard Worker * @fb: pointer to an #igt_fb structure
1574*d83cc019SAndroid Build Coastguard Worker * @check: the type of frame matching check to use
1575*d83cc019SAndroid Build Coastguard Worker *
1576*d83cc019SAndroid Build Coastguard Worker * Asserts that the provided captured frame matches the reference frame from
1577*d83cc019SAndroid Build Coastguard Worker * the framebuffer. If they do not, this saves the reference and captured frames
1578*d83cc019SAndroid Build Coastguard Worker * to a png file.
1579*d83cc019SAndroid Build Coastguard Worker */
chamelium_assert_frame_match_or_dump(struct chamelium * chamelium,struct chamelium_port * port,const struct chamelium_frame_dump * frame,struct igt_fb * fb,enum chamelium_check check)1580*d83cc019SAndroid Build Coastguard Worker void chamelium_assert_frame_match_or_dump(struct chamelium *chamelium,
1581*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port,
1582*d83cc019SAndroid Build Coastguard Worker const struct chamelium_frame_dump *frame,
1583*d83cc019SAndroid Build Coastguard Worker struct igt_fb *fb,
1584*d83cc019SAndroid Build Coastguard Worker enum chamelium_check check)
1585*d83cc019SAndroid Build Coastguard Worker {
1586*d83cc019SAndroid Build Coastguard Worker cairo_surface_t *reference;
1587*d83cc019SAndroid Build Coastguard Worker cairo_surface_t *capture;
1588*d83cc019SAndroid Build Coastguard Worker igt_crc_t *reference_crc;
1589*d83cc019SAndroid Build Coastguard Worker igt_crc_t *capture_crc;
1590*d83cc019SAndroid Build Coastguard Worker bool match;
1591*d83cc019SAndroid Build Coastguard Worker
1592*d83cc019SAndroid Build Coastguard Worker /* Grab the reference frame from framebuffer */
1593*d83cc019SAndroid Build Coastguard Worker reference = igt_get_cairo_surface(chamelium->drm_fd, fb);
1594*d83cc019SAndroid Build Coastguard Worker
1595*d83cc019SAndroid Build Coastguard Worker /* Grab the captured frame from chamelium */
1596*d83cc019SAndroid Build Coastguard Worker capture = convert_frame_dump_argb32(frame);
1597*d83cc019SAndroid Build Coastguard Worker
1598*d83cc019SAndroid Build Coastguard Worker switch (check) {
1599*d83cc019SAndroid Build Coastguard Worker case CHAMELIUM_CHECK_ANALOG:
1600*d83cc019SAndroid Build Coastguard Worker match = igt_check_analog_frame_match(reference, capture);
1601*d83cc019SAndroid Build Coastguard Worker break;
1602*d83cc019SAndroid Build Coastguard Worker case CHAMELIUM_CHECK_CHECKERBOARD:
1603*d83cc019SAndroid Build Coastguard Worker match = igt_check_checkerboard_frame_match(reference, capture);
1604*d83cc019SAndroid Build Coastguard Worker break;
1605*d83cc019SAndroid Build Coastguard Worker default:
1606*d83cc019SAndroid Build Coastguard Worker igt_assert(false);
1607*d83cc019SAndroid Build Coastguard Worker }
1608*d83cc019SAndroid Build Coastguard Worker
1609*d83cc019SAndroid Build Coastguard Worker if (!match && igt_frame_dump_is_enabled()) {
1610*d83cc019SAndroid Build Coastguard Worker reference_crc = malloc(sizeof(igt_crc_t));
1611*d83cc019SAndroid Build Coastguard Worker igt_assert(reference_crc);
1612*d83cc019SAndroid Build Coastguard Worker
1613*d83cc019SAndroid Build Coastguard Worker /* Calculate the reference frame CRC. */
1614*d83cc019SAndroid Build Coastguard Worker chamelium_do_calculate_fb_crc(reference, reference_crc);
1615*d83cc019SAndroid Build Coastguard Worker
1616*d83cc019SAndroid Build Coastguard Worker /* Get the captured frame CRC from the Chamelium. */
1617*d83cc019SAndroid Build Coastguard Worker capture_crc = chamelium_get_crc_for_area(chamelium, port, 0, 0,
1618*d83cc019SAndroid Build Coastguard Worker 0, 0);
1619*d83cc019SAndroid Build Coastguard Worker igt_assert(capture_crc);
1620*d83cc019SAndroid Build Coastguard Worker
1621*d83cc019SAndroid Build Coastguard Worker compared_frames_dump(reference, capture, reference_crc,
1622*d83cc019SAndroid Build Coastguard Worker capture_crc);
1623*d83cc019SAndroid Build Coastguard Worker
1624*d83cc019SAndroid Build Coastguard Worker free(reference_crc);
1625*d83cc019SAndroid Build Coastguard Worker free(capture_crc);
1626*d83cc019SAndroid Build Coastguard Worker }
1627*d83cc019SAndroid Build Coastguard Worker
1628*d83cc019SAndroid Build Coastguard Worker igt_assert(match);
1629*d83cc019SAndroid Build Coastguard Worker
1630*d83cc019SAndroid Build Coastguard Worker cairo_surface_destroy(reference);
1631*d83cc019SAndroid Build Coastguard Worker cairo_surface_destroy(capture);
1632*d83cc019SAndroid Build Coastguard Worker }
1633*d83cc019SAndroid Build Coastguard Worker
1634*d83cc019SAndroid Build Coastguard Worker /**
1635*d83cc019SAndroid Build Coastguard Worker * chamelium_analog_frame_crop:
1636*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
1637*d83cc019SAndroid Build Coastguard Worker * @dump: The chamelium frame dump to crop
1638*d83cc019SAndroid Build Coastguard Worker * @width: The cropped frame width
1639*d83cc019SAndroid Build Coastguard Worker * @height: The cropped frame height
1640*d83cc019SAndroid Build Coastguard Worker *
1641*d83cc019SAndroid Build Coastguard Worker * Detects the corners of a chamelium frame and crops it to the requested
1642*d83cc019SAndroid Build Coastguard Worker * width/height. This is useful for VGA frame dumps that also contain the
1643*d83cc019SAndroid Build Coastguard Worker * pixels dumped during the blanking intervals.
1644*d83cc019SAndroid Build Coastguard Worker *
1645*d83cc019SAndroid Build Coastguard Worker * The detection is done on a brightness-threshold-basis, that is adapted
1646*d83cc019SAndroid Build Coastguard Worker * to the reference frame used by i-g-t. It may not be as relevant for other
1647*d83cc019SAndroid Build Coastguard Worker * frames.
1648*d83cc019SAndroid Build Coastguard Worker */
chamelium_crop_analog_frame(struct chamelium_frame_dump * dump,int width,int height)1649*d83cc019SAndroid Build Coastguard Worker void chamelium_crop_analog_frame(struct chamelium_frame_dump *dump, int width,
1650*d83cc019SAndroid Build Coastguard Worker int height)
1651*d83cc019SAndroid Build Coastguard Worker {
1652*d83cc019SAndroid Build Coastguard Worker unsigned char *bgr;
1653*d83cc019SAndroid Build Coastguard Worker unsigned char *p;
1654*d83cc019SAndroid Build Coastguard Worker unsigned char *q;
1655*d83cc019SAndroid Build Coastguard Worker int top, left;
1656*d83cc019SAndroid Build Coastguard Worker int x, y, xx, yy;
1657*d83cc019SAndroid Build Coastguard Worker int score;
1658*d83cc019SAndroid Build Coastguard Worker
1659*d83cc019SAndroid Build Coastguard Worker if (dump->width == width && dump->height == height)
1660*d83cc019SAndroid Build Coastguard Worker return;
1661*d83cc019SAndroid Build Coastguard Worker
1662*d83cc019SAndroid Build Coastguard Worker /* Start with the most bottom-right position. */
1663*d83cc019SAndroid Build Coastguard Worker top = dump->height - height;
1664*d83cc019SAndroid Build Coastguard Worker left = dump->width - width;
1665*d83cc019SAndroid Build Coastguard Worker
1666*d83cc019SAndroid Build Coastguard Worker igt_assert(top >= 0 && left >= 0);
1667*d83cc019SAndroid Build Coastguard Worker
1668*d83cc019SAndroid Build Coastguard Worker igt_debug("Cropping analog frame from %dx%d to %dx%d\n", dump->width,
1669*d83cc019SAndroid Build Coastguard Worker dump->height, width, height);
1670*d83cc019SAndroid Build Coastguard Worker
1671*d83cc019SAndroid Build Coastguard Worker /* Detect the top-left corner of the frame. */
1672*d83cc019SAndroid Build Coastguard Worker for (x = 0; x < dump->width; x++) {
1673*d83cc019SAndroid Build Coastguard Worker for (y = 0; y < dump->height; y++) {
1674*d83cc019SAndroid Build Coastguard Worker p = &dump->bgr[(x + y * dump->width) * 3];
1675*d83cc019SAndroid Build Coastguard Worker
1676*d83cc019SAndroid Build Coastguard Worker /* Detect significantly bright pixels. */
1677*d83cc019SAndroid Build Coastguard Worker if (p[0] < 50 && p[1] < 50 && p[2] < 50)
1678*d83cc019SAndroid Build Coastguard Worker continue;
1679*d83cc019SAndroid Build Coastguard Worker
1680*d83cc019SAndroid Build Coastguard Worker /*
1681*d83cc019SAndroid Build Coastguard Worker * Make sure close-by pixels are also significantly
1682*d83cc019SAndroid Build Coastguard Worker * bright.
1683*d83cc019SAndroid Build Coastguard Worker */
1684*d83cc019SAndroid Build Coastguard Worker score = 0;
1685*d83cc019SAndroid Build Coastguard Worker for (xx = x; xx < x + 10; xx++) {
1686*d83cc019SAndroid Build Coastguard Worker for (yy = y; yy < y + 10; yy++) {
1687*d83cc019SAndroid Build Coastguard Worker p = &dump->bgr[(xx + yy * dump->width) * 3];
1688*d83cc019SAndroid Build Coastguard Worker
1689*d83cc019SAndroid Build Coastguard Worker if (p[0] > 50 && p[1] > 50 && p[2] > 50)
1690*d83cc019SAndroid Build Coastguard Worker score++;
1691*d83cc019SAndroid Build Coastguard Worker }
1692*d83cc019SAndroid Build Coastguard Worker }
1693*d83cc019SAndroid Build Coastguard Worker
1694*d83cc019SAndroid Build Coastguard Worker /* Not enough pixels are significantly bright. */
1695*d83cc019SAndroid Build Coastguard Worker if (score < 25)
1696*d83cc019SAndroid Build Coastguard Worker continue;
1697*d83cc019SAndroid Build Coastguard Worker
1698*d83cc019SAndroid Build Coastguard Worker if (x < left)
1699*d83cc019SAndroid Build Coastguard Worker left = x;
1700*d83cc019SAndroid Build Coastguard Worker
1701*d83cc019SAndroid Build Coastguard Worker if (y < top)
1702*d83cc019SAndroid Build Coastguard Worker top = y;
1703*d83cc019SAndroid Build Coastguard Worker
1704*d83cc019SAndroid Build Coastguard Worker if (left == x || top == y)
1705*d83cc019SAndroid Build Coastguard Worker continue;
1706*d83cc019SAndroid Build Coastguard Worker }
1707*d83cc019SAndroid Build Coastguard Worker }
1708*d83cc019SAndroid Build Coastguard Worker
1709*d83cc019SAndroid Build Coastguard Worker igt_debug("Detected analog frame edges at %dx%d\n", left, top);
1710*d83cc019SAndroid Build Coastguard Worker
1711*d83cc019SAndroid Build Coastguard Worker /* Crop the frame given the detected top-left corner. */
1712*d83cc019SAndroid Build Coastguard Worker bgr = malloc(width * height * 3);
1713*d83cc019SAndroid Build Coastguard Worker
1714*d83cc019SAndroid Build Coastguard Worker for (y = 0; y < height; y++) {
1715*d83cc019SAndroid Build Coastguard Worker p = &dump->bgr[(left + (top + y) * dump->width) * 3];
1716*d83cc019SAndroid Build Coastguard Worker q = &bgr[(y * width) * 3];
1717*d83cc019SAndroid Build Coastguard Worker memcpy(q, p, width * 3);
1718*d83cc019SAndroid Build Coastguard Worker }
1719*d83cc019SAndroid Build Coastguard Worker
1720*d83cc019SAndroid Build Coastguard Worker free(dump->bgr);
1721*d83cc019SAndroid Build Coastguard Worker dump->width = width;
1722*d83cc019SAndroid Build Coastguard Worker dump->height = height;
1723*d83cc019SAndroid Build Coastguard Worker dump->bgr = bgr;
1724*d83cc019SAndroid Build Coastguard Worker }
1725*d83cc019SAndroid Build Coastguard Worker
1726*d83cc019SAndroid Build Coastguard Worker /**
1727*d83cc019SAndroid Build Coastguard Worker * chamelium_get_frame_limit:
1728*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
1729*d83cc019SAndroid Build Coastguard Worker * @port: The port to check the frame limit on
1730*d83cc019SAndroid Build Coastguard Worker * @w: The width of the area to get the capture frame limit for, or %0 for the
1731*d83cc019SAndroid Build Coastguard Worker * whole display
1732*d83cc019SAndroid Build Coastguard Worker * @h: The height of the area to get the capture frame limit for, or %0 for the
1733*d83cc019SAndroid Build Coastguard Worker * whole display
1734*d83cc019SAndroid Build Coastguard Worker *
1735*d83cc019SAndroid Build Coastguard Worker * Gets the max number of frames we can capture with the Chamelium for the given
1736*d83cc019SAndroid Build Coastguard Worker * resolution.
1737*d83cc019SAndroid Build Coastguard Worker *
1738*d83cc019SAndroid Build Coastguard Worker * Returns: The number of the max number of frames we can capture
1739*d83cc019SAndroid Build Coastguard Worker */
chamelium_get_frame_limit(struct chamelium * chamelium,struct chamelium_port * port,int w,int h)1740*d83cc019SAndroid Build Coastguard Worker int chamelium_get_frame_limit(struct chamelium *chamelium,
1741*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port,
1742*d83cc019SAndroid Build Coastguard Worker int w, int h)
1743*d83cc019SAndroid Build Coastguard Worker {
1744*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res;
1745*d83cc019SAndroid Build Coastguard Worker int ret;
1746*d83cc019SAndroid Build Coastguard Worker
1747*d83cc019SAndroid Build Coastguard Worker if (!w && !h)
1748*d83cc019SAndroid Build Coastguard Worker chamelium_port_get_resolution(chamelium, port, &w, &h);
1749*d83cc019SAndroid Build Coastguard Worker
1750*d83cc019SAndroid Build Coastguard Worker res = chamelium_rpc(chamelium, port, "GetMaxFrameLimit", "(iii)",
1751*d83cc019SAndroid Build Coastguard Worker port->id, w, h);
1752*d83cc019SAndroid Build Coastguard Worker
1753*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_int(&chamelium->env, res, &ret);
1754*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res);
1755*d83cc019SAndroid Build Coastguard Worker
1756*d83cc019SAndroid Build Coastguard Worker return ret;
1757*d83cc019SAndroid Build Coastguard Worker }
1758*d83cc019SAndroid Build Coastguard Worker
chamelium_xrgb_hash16(const unsigned char * buffer,int width,int height,int k,int m)1759*d83cc019SAndroid Build Coastguard Worker static uint32_t chamelium_xrgb_hash16(const unsigned char *buffer, int width,
1760*d83cc019SAndroid Build Coastguard Worker int height, int k, int m)
1761*d83cc019SAndroid Build Coastguard Worker {
1762*d83cc019SAndroid Build Coastguard Worker unsigned char r, g, b;
1763*d83cc019SAndroid Build Coastguard Worker uint64_t sum = 0;
1764*d83cc019SAndroid Build Coastguard Worker uint64_t count = 0;
1765*d83cc019SAndroid Build Coastguard Worker uint64_t value;
1766*d83cc019SAndroid Build Coastguard Worker uint32_t hash;
1767*d83cc019SAndroid Build Coastguard Worker int index;
1768*d83cc019SAndroid Build Coastguard Worker int i;
1769*d83cc019SAndroid Build Coastguard Worker
1770*d83cc019SAndroid Build Coastguard Worker for (i=0; i < width * height; i++) {
1771*d83cc019SAndroid Build Coastguard Worker if ((i % m) != k)
1772*d83cc019SAndroid Build Coastguard Worker continue;
1773*d83cc019SAndroid Build Coastguard Worker
1774*d83cc019SAndroid Build Coastguard Worker index = i * 4;
1775*d83cc019SAndroid Build Coastguard Worker
1776*d83cc019SAndroid Build Coastguard Worker r = buffer[index + 2];
1777*d83cc019SAndroid Build Coastguard Worker g = buffer[index + 1];
1778*d83cc019SAndroid Build Coastguard Worker b = buffer[index + 0];
1779*d83cc019SAndroid Build Coastguard Worker
1780*d83cc019SAndroid Build Coastguard Worker value = r | (g << 8) | (b << 16);
1781*d83cc019SAndroid Build Coastguard Worker sum += ++count * value;
1782*d83cc019SAndroid Build Coastguard Worker }
1783*d83cc019SAndroid Build Coastguard Worker
1784*d83cc019SAndroid Build Coastguard Worker hash = ((sum >> 0) ^ (sum >> 16) ^ (sum >> 32) ^ (sum >> 48)) & 0xffff;
1785*d83cc019SAndroid Build Coastguard Worker
1786*d83cc019SAndroid Build Coastguard Worker return hash;
1787*d83cc019SAndroid Build Coastguard Worker }
1788*d83cc019SAndroid Build Coastguard Worker
chamelium_do_calculate_fb_crc(cairo_surface_t * fb_surface,igt_crc_t * out)1789*d83cc019SAndroid Build Coastguard Worker static void chamelium_do_calculate_fb_crc(cairo_surface_t *fb_surface,
1790*d83cc019SAndroid Build Coastguard Worker igt_crc_t *out)
1791*d83cc019SAndroid Build Coastguard Worker {
1792*d83cc019SAndroid Build Coastguard Worker unsigned char *buffer;
1793*d83cc019SAndroid Build Coastguard Worker int n = 4;
1794*d83cc019SAndroid Build Coastguard Worker int w, h;
1795*d83cc019SAndroid Build Coastguard Worker int i, j;
1796*d83cc019SAndroid Build Coastguard Worker
1797*d83cc019SAndroid Build Coastguard Worker buffer = cairo_image_surface_get_data(fb_surface);
1798*d83cc019SAndroid Build Coastguard Worker w = cairo_image_surface_get_width(fb_surface);
1799*d83cc019SAndroid Build Coastguard Worker h = cairo_image_surface_get_height(fb_surface);
1800*d83cc019SAndroid Build Coastguard Worker
1801*d83cc019SAndroid Build Coastguard Worker for (i = 0; i < n; i++) {
1802*d83cc019SAndroid Build Coastguard Worker j = n - i - 1;
1803*d83cc019SAndroid Build Coastguard Worker out->crc[i] = chamelium_xrgb_hash16(buffer, w, h, j, n);
1804*d83cc019SAndroid Build Coastguard Worker }
1805*d83cc019SAndroid Build Coastguard Worker
1806*d83cc019SAndroid Build Coastguard Worker out->n_words = n;
1807*d83cc019SAndroid Build Coastguard Worker }
1808*d83cc019SAndroid Build Coastguard Worker
1809*d83cc019SAndroid Build Coastguard Worker /**
1810*d83cc019SAndroid Build Coastguard Worker * chamelium_calculate_fb_crc:
1811*d83cc019SAndroid Build Coastguard Worker * @fd: The drm file descriptor
1812*d83cc019SAndroid Build Coastguard Worker * @fb: The framebuffer to calculate the CRC for
1813*d83cc019SAndroid Build Coastguard Worker *
1814*d83cc019SAndroid Build Coastguard Worker * Calculates the CRC for the provided framebuffer, using the Chamelium's CRC
1815*d83cc019SAndroid Build Coastguard Worker * algorithm. This calculates the CRC in a synchronous fashion.
1816*d83cc019SAndroid Build Coastguard Worker *
1817*d83cc019SAndroid Build Coastguard Worker * Returns: The calculated CRC
1818*d83cc019SAndroid Build Coastguard Worker */
chamelium_calculate_fb_crc(int fd,struct igt_fb * fb)1819*d83cc019SAndroid Build Coastguard Worker igt_crc_t *chamelium_calculate_fb_crc(int fd, struct igt_fb *fb)
1820*d83cc019SAndroid Build Coastguard Worker {
1821*d83cc019SAndroid Build Coastguard Worker igt_crc_t *ret = calloc(1, sizeof(igt_crc_t));
1822*d83cc019SAndroid Build Coastguard Worker cairo_surface_t *fb_surface;
1823*d83cc019SAndroid Build Coastguard Worker
1824*d83cc019SAndroid Build Coastguard Worker /* Get the cairo surface for the framebuffer */
1825*d83cc019SAndroid Build Coastguard Worker fb_surface = igt_get_cairo_surface(fd, fb);
1826*d83cc019SAndroid Build Coastguard Worker
1827*d83cc019SAndroid Build Coastguard Worker chamelium_do_calculate_fb_crc(fb_surface, ret);
1828*d83cc019SAndroid Build Coastguard Worker
1829*d83cc019SAndroid Build Coastguard Worker cairo_surface_destroy(fb_surface);
1830*d83cc019SAndroid Build Coastguard Worker
1831*d83cc019SAndroid Build Coastguard Worker return ret;
1832*d83cc019SAndroid Build Coastguard Worker }
1833*d83cc019SAndroid Build Coastguard Worker
chamelium_calculate_fb_crc_async_work(void * data)1834*d83cc019SAndroid Build Coastguard Worker static void *chamelium_calculate_fb_crc_async_work(void *data)
1835*d83cc019SAndroid Build Coastguard Worker {
1836*d83cc019SAndroid Build Coastguard Worker struct chamelium_fb_crc_async_data *fb_crc;
1837*d83cc019SAndroid Build Coastguard Worker
1838*d83cc019SAndroid Build Coastguard Worker fb_crc = (struct chamelium_fb_crc_async_data *) data;
1839*d83cc019SAndroid Build Coastguard Worker
1840*d83cc019SAndroid Build Coastguard Worker chamelium_do_calculate_fb_crc(fb_crc->fb_surface, fb_crc->ret);
1841*d83cc019SAndroid Build Coastguard Worker
1842*d83cc019SAndroid Build Coastguard Worker return NULL;
1843*d83cc019SAndroid Build Coastguard Worker }
1844*d83cc019SAndroid Build Coastguard Worker
1845*d83cc019SAndroid Build Coastguard Worker /**
1846*d83cc019SAndroid Build Coastguard Worker * chamelium_calculate_fb_crc_launch:
1847*d83cc019SAndroid Build Coastguard Worker * @fd: The drm file descriptor
1848*d83cc019SAndroid Build Coastguard Worker * @fb: The framebuffer to calculate the CRC for
1849*d83cc019SAndroid Build Coastguard Worker *
1850*d83cc019SAndroid Build Coastguard Worker * Launches the CRC calculation for the provided framebuffer, using the
1851*d83cc019SAndroid Build Coastguard Worker * Chamelium's CRC algorithm. This calculates the CRC in an asynchronous
1852*d83cc019SAndroid Build Coastguard Worker * fashion.
1853*d83cc019SAndroid Build Coastguard Worker *
1854*d83cc019SAndroid Build Coastguard Worker * The returned structure should be passed to a subsequent call to
1855*d83cc019SAndroid Build Coastguard Worker * chamelium_calculate_fb_crc_result. It should not be freed.
1856*d83cc019SAndroid Build Coastguard Worker *
1857*d83cc019SAndroid Build Coastguard Worker * Returns: An intermediate structure for the CRC calculation work.
1858*d83cc019SAndroid Build Coastguard Worker */
chamelium_calculate_fb_crc_async_start(int fd,struct igt_fb * fb)1859*d83cc019SAndroid Build Coastguard Worker struct chamelium_fb_crc_async_data *chamelium_calculate_fb_crc_async_start(int fd,
1860*d83cc019SAndroid Build Coastguard Worker struct igt_fb *fb)
1861*d83cc019SAndroid Build Coastguard Worker {
1862*d83cc019SAndroid Build Coastguard Worker struct chamelium_fb_crc_async_data *fb_crc;
1863*d83cc019SAndroid Build Coastguard Worker
1864*d83cc019SAndroid Build Coastguard Worker fb_crc = calloc(1, sizeof(struct chamelium_fb_crc_async_data));
1865*d83cc019SAndroid Build Coastguard Worker fb_crc->ret = calloc(1, sizeof(igt_crc_t));
1866*d83cc019SAndroid Build Coastguard Worker
1867*d83cc019SAndroid Build Coastguard Worker /* Get the cairo surface for the framebuffer */
1868*d83cc019SAndroid Build Coastguard Worker fb_crc->fb_surface = igt_get_cairo_surface(fd, fb);
1869*d83cc019SAndroid Build Coastguard Worker
1870*d83cc019SAndroid Build Coastguard Worker pthread_create(&fb_crc->thread_id, NULL,
1871*d83cc019SAndroid Build Coastguard Worker chamelium_calculate_fb_crc_async_work, fb_crc);
1872*d83cc019SAndroid Build Coastguard Worker
1873*d83cc019SAndroid Build Coastguard Worker return fb_crc;
1874*d83cc019SAndroid Build Coastguard Worker }
1875*d83cc019SAndroid Build Coastguard Worker
1876*d83cc019SAndroid Build Coastguard Worker /**
1877*d83cc019SAndroid Build Coastguard Worker * chamelium_calculate_fb_crc_result:
1878*d83cc019SAndroid Build Coastguard Worker * @fb_crc: An intermediate structure with thread-related information
1879*d83cc019SAndroid Build Coastguard Worker *
1880*d83cc019SAndroid Build Coastguard Worker * Blocks until the asynchronous CRC calculation is finished, and then returns
1881*d83cc019SAndroid Build Coastguard Worker * its result.
1882*d83cc019SAndroid Build Coastguard Worker *
1883*d83cc019SAndroid Build Coastguard Worker * Returns: The calculated CRC
1884*d83cc019SAndroid Build Coastguard Worker */
chamelium_calculate_fb_crc_async_finish(struct chamelium_fb_crc_async_data * fb_crc)1885*d83cc019SAndroid Build Coastguard Worker igt_crc_t *chamelium_calculate_fb_crc_async_finish(struct chamelium_fb_crc_async_data *fb_crc)
1886*d83cc019SAndroid Build Coastguard Worker {
1887*d83cc019SAndroid Build Coastguard Worker igt_crc_t *ret;
1888*d83cc019SAndroid Build Coastguard Worker
1889*d83cc019SAndroid Build Coastguard Worker pthread_join(fb_crc->thread_id, NULL);
1890*d83cc019SAndroid Build Coastguard Worker
1891*d83cc019SAndroid Build Coastguard Worker ret = fb_crc->ret;
1892*d83cc019SAndroid Build Coastguard Worker free(fb_crc);
1893*d83cc019SAndroid Build Coastguard Worker
1894*d83cc019SAndroid Build Coastguard Worker return ret;
1895*d83cc019SAndroid Build Coastguard Worker }
1896*d83cc019SAndroid Build Coastguard Worker
chamelium_get_port_type(struct chamelium * chamelium,struct chamelium_port * port)1897*d83cc019SAndroid Build Coastguard Worker static unsigned int chamelium_get_port_type(struct chamelium *chamelium,
1898*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port)
1899*d83cc019SAndroid Build Coastguard Worker {
1900*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res;
1901*d83cc019SAndroid Build Coastguard Worker const char *port_type_str;
1902*d83cc019SAndroid Build Coastguard Worker unsigned int port_type;
1903*d83cc019SAndroid Build Coastguard Worker
1904*d83cc019SAndroid Build Coastguard Worker res = chamelium_rpc(chamelium, NULL, "GetConnectorType",
1905*d83cc019SAndroid Build Coastguard Worker "(i)", port->id);
1906*d83cc019SAndroid Build Coastguard Worker
1907*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_string(&chamelium->env, res, &port_type_str);
1908*d83cc019SAndroid Build Coastguard Worker igt_debug("Port %d is of type '%s'\n", port->id, port_type_str);
1909*d83cc019SAndroid Build Coastguard Worker
1910*d83cc019SAndroid Build Coastguard Worker if (strcmp(port_type_str, "DP") == 0)
1911*d83cc019SAndroid Build Coastguard Worker port_type = DRM_MODE_CONNECTOR_DisplayPort;
1912*d83cc019SAndroid Build Coastguard Worker else if (strcmp(port_type_str, "HDMI") == 0)
1913*d83cc019SAndroid Build Coastguard Worker port_type = DRM_MODE_CONNECTOR_HDMIA;
1914*d83cc019SAndroid Build Coastguard Worker else if (strcmp(port_type_str, "VGA") == 0)
1915*d83cc019SAndroid Build Coastguard Worker port_type = DRM_MODE_CONNECTOR_VGA;
1916*d83cc019SAndroid Build Coastguard Worker else
1917*d83cc019SAndroid Build Coastguard Worker port_type = DRM_MODE_CONNECTOR_Unknown;
1918*d83cc019SAndroid Build Coastguard Worker
1919*d83cc019SAndroid Build Coastguard Worker free((void*)port_type_str);
1920*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res);
1921*d83cc019SAndroid Build Coastguard Worker
1922*d83cc019SAndroid Build Coastguard Worker return port_type;
1923*d83cc019SAndroid Build Coastguard Worker }
1924*d83cc019SAndroid Build Coastguard Worker
chamelium_has_video_support(struct chamelium * chamelium,int port_id)1925*d83cc019SAndroid Build Coastguard Worker static bool chamelium_has_video_support(struct chamelium *chamelium,
1926*d83cc019SAndroid Build Coastguard Worker int port_id)
1927*d83cc019SAndroid Build Coastguard Worker {
1928*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res;
1929*d83cc019SAndroid Build Coastguard Worker int has_video_support;
1930*d83cc019SAndroid Build Coastguard Worker
1931*d83cc019SAndroid Build Coastguard Worker res = chamelium_rpc(chamelium, NULL, "HasVideoSupport", "(i)", port_id);
1932*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_bool(&chamelium->env, res, &has_video_support);
1933*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res);
1934*d83cc019SAndroid Build Coastguard Worker
1935*d83cc019SAndroid Build Coastguard Worker return has_video_support;
1936*d83cc019SAndroid Build Coastguard Worker }
1937*d83cc019SAndroid Build Coastguard Worker
1938*d83cc019SAndroid Build Coastguard Worker /**
1939*d83cc019SAndroid Build Coastguard Worker * chamelium_get_video_ports: retrieve a list of video port IDs
1940*d83cc019SAndroid Build Coastguard Worker *
1941*d83cc019SAndroid Build Coastguard Worker * Returns: the number of video port IDs
1942*d83cc019SAndroid Build Coastguard Worker */
chamelium_get_video_ports(struct chamelium * chamelium,int port_ids[static CHAMELIUM_MAX_PORTS])1943*d83cc019SAndroid Build Coastguard Worker static size_t chamelium_get_video_ports(struct chamelium *chamelium,
1944*d83cc019SAndroid Build Coastguard Worker int port_ids[static CHAMELIUM_MAX_PORTS])
1945*d83cc019SAndroid Build Coastguard Worker {
1946*d83cc019SAndroid Build Coastguard Worker xmlrpc_value *res, *res_port;
1947*d83cc019SAndroid Build Coastguard Worker int res_len, i, port_id;
1948*d83cc019SAndroid Build Coastguard Worker size_t port_ids_len = 0;
1949*d83cc019SAndroid Build Coastguard Worker
1950*d83cc019SAndroid Build Coastguard Worker res = chamelium_rpc(chamelium, NULL, "GetSupportedInputs", "()");
1951*d83cc019SAndroid Build Coastguard Worker res_len = xmlrpc_array_size(&chamelium->env, res);
1952*d83cc019SAndroid Build Coastguard Worker for (i = 0; i < res_len; i++) {
1953*d83cc019SAndroid Build Coastguard Worker xmlrpc_array_read_item(&chamelium->env, res, i, &res_port);
1954*d83cc019SAndroid Build Coastguard Worker xmlrpc_read_int(&chamelium->env, res_port, &port_id);
1955*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res_port);
1956*d83cc019SAndroid Build Coastguard Worker
1957*d83cc019SAndroid Build Coastguard Worker if (!chamelium_has_video_support(chamelium, port_id))
1958*d83cc019SAndroid Build Coastguard Worker continue;
1959*d83cc019SAndroid Build Coastguard Worker
1960*d83cc019SAndroid Build Coastguard Worker igt_assert(port_ids_len < CHAMELIUM_MAX_PORTS);
1961*d83cc019SAndroid Build Coastguard Worker port_ids[port_ids_len] = port_id;
1962*d83cc019SAndroid Build Coastguard Worker port_ids_len++;
1963*d83cc019SAndroid Build Coastguard Worker }
1964*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(res);
1965*d83cc019SAndroid Build Coastguard Worker
1966*d83cc019SAndroid Build Coastguard Worker return port_ids_len;
1967*d83cc019SAndroid Build Coastguard Worker }
1968*d83cc019SAndroid Build Coastguard Worker
chamelium_read_port_mappings(struct chamelium * chamelium,int drm_fd)1969*d83cc019SAndroid Build Coastguard Worker static bool chamelium_read_port_mappings(struct chamelium *chamelium,
1970*d83cc019SAndroid Build Coastguard Worker int drm_fd)
1971*d83cc019SAndroid Build Coastguard Worker {
1972*d83cc019SAndroid Build Coastguard Worker drmModeRes *res;
1973*d83cc019SAndroid Build Coastguard Worker drmModeConnector *connector;
1974*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port;
1975*d83cc019SAndroid Build Coastguard Worker GError *error = NULL;
1976*d83cc019SAndroid Build Coastguard Worker char **group_list;
1977*d83cc019SAndroid Build Coastguard Worker char *group, *map_name;
1978*d83cc019SAndroid Build Coastguard Worker int port_i, i, j;
1979*d83cc019SAndroid Build Coastguard Worker bool ret = true;
1980*d83cc019SAndroid Build Coastguard Worker
1981*d83cc019SAndroid Build Coastguard Worker res = drmModeGetResources(drm_fd);
1982*d83cc019SAndroid Build Coastguard Worker if (!res)
1983*d83cc019SAndroid Build Coastguard Worker return false;
1984*d83cc019SAndroid Build Coastguard Worker
1985*d83cc019SAndroid Build Coastguard Worker group_list = g_key_file_get_groups(igt_key_file, NULL);
1986*d83cc019SAndroid Build Coastguard Worker
1987*d83cc019SAndroid Build Coastguard Worker /* Count how many connector mappings are specified in the config */
1988*d83cc019SAndroid Build Coastguard Worker for (i = 0; group_list[i] != NULL; i++) {
1989*d83cc019SAndroid Build Coastguard Worker if (strstr(group_list[i], "Chamelium:"))
1990*d83cc019SAndroid Build Coastguard Worker chamelium->port_count++;
1991*d83cc019SAndroid Build Coastguard Worker }
1992*d83cc019SAndroid Build Coastguard Worker igt_assert(chamelium->port_count <= CHAMELIUM_MAX_PORTS);
1993*d83cc019SAndroid Build Coastguard Worker
1994*d83cc019SAndroid Build Coastguard Worker port_i = 0;
1995*d83cc019SAndroid Build Coastguard Worker for (i = 0; group_list[i] != NULL; i++) {
1996*d83cc019SAndroid Build Coastguard Worker group = group_list[i];
1997*d83cc019SAndroid Build Coastguard Worker
1998*d83cc019SAndroid Build Coastguard Worker if (!strstr(group, "Chamelium:"))
1999*d83cc019SAndroid Build Coastguard Worker continue;
2000*d83cc019SAndroid Build Coastguard Worker
2001*d83cc019SAndroid Build Coastguard Worker map_name = group + (sizeof("Chamelium:") - 1);
2002*d83cc019SAndroid Build Coastguard Worker
2003*d83cc019SAndroid Build Coastguard Worker port = &chamelium->ports[port_i++];
2004*d83cc019SAndroid Build Coastguard Worker port->name = strdup(map_name);
2005*d83cc019SAndroid Build Coastguard Worker port->id = g_key_file_get_integer(igt_key_file, group,
2006*d83cc019SAndroid Build Coastguard Worker "ChameliumPortID",
2007*d83cc019SAndroid Build Coastguard Worker &error);
2008*d83cc019SAndroid Build Coastguard Worker if (!port->id) {
2009*d83cc019SAndroid Build Coastguard Worker igt_warn("Failed to read chamelium port ID for %s: %s\n",
2010*d83cc019SAndroid Build Coastguard Worker map_name, error->message);
2011*d83cc019SAndroid Build Coastguard Worker ret = false;
2012*d83cc019SAndroid Build Coastguard Worker goto out;
2013*d83cc019SAndroid Build Coastguard Worker }
2014*d83cc019SAndroid Build Coastguard Worker
2015*d83cc019SAndroid Build Coastguard Worker port->type = chamelium_get_port_type(chamelium, port);
2016*d83cc019SAndroid Build Coastguard Worker if (port->type == DRM_MODE_CONNECTOR_Unknown) {
2017*d83cc019SAndroid Build Coastguard Worker igt_warn("Unable to retrieve the physical port type from the Chamelium for '%s'\n",
2018*d83cc019SAndroid Build Coastguard Worker map_name);
2019*d83cc019SAndroid Build Coastguard Worker ret = false;
2020*d83cc019SAndroid Build Coastguard Worker goto out;
2021*d83cc019SAndroid Build Coastguard Worker }
2022*d83cc019SAndroid Build Coastguard Worker
2023*d83cc019SAndroid Build Coastguard Worker for (j = 0;
2024*d83cc019SAndroid Build Coastguard Worker j < res->count_connectors && !port->connector_id;
2025*d83cc019SAndroid Build Coastguard Worker j++) {
2026*d83cc019SAndroid Build Coastguard Worker char name[50];
2027*d83cc019SAndroid Build Coastguard Worker
2028*d83cc019SAndroid Build Coastguard Worker connector = drmModeGetConnectorCurrent(
2029*d83cc019SAndroid Build Coastguard Worker drm_fd, res->connectors[j]);
2030*d83cc019SAndroid Build Coastguard Worker
2031*d83cc019SAndroid Build Coastguard Worker /* We have to generate the connector name on our own */
2032*d83cc019SAndroid Build Coastguard Worker snprintf(name, 50, "%s-%u",
2033*d83cc019SAndroid Build Coastguard Worker kmstest_connector_type_str(connector->connector_type),
2034*d83cc019SAndroid Build Coastguard Worker connector->connector_type_id);
2035*d83cc019SAndroid Build Coastguard Worker
2036*d83cc019SAndroid Build Coastguard Worker if (strcmp(name, map_name) == 0)
2037*d83cc019SAndroid Build Coastguard Worker port->connector_id = connector->connector_id;
2038*d83cc019SAndroid Build Coastguard Worker
2039*d83cc019SAndroid Build Coastguard Worker drmModeFreeConnector(connector);
2040*d83cc019SAndroid Build Coastguard Worker }
2041*d83cc019SAndroid Build Coastguard Worker if (!port->connector_id) {
2042*d83cc019SAndroid Build Coastguard Worker igt_warn("No connector found with name '%s'\n",
2043*d83cc019SAndroid Build Coastguard Worker map_name);
2044*d83cc019SAndroid Build Coastguard Worker ret = false;
2045*d83cc019SAndroid Build Coastguard Worker goto out;
2046*d83cc019SAndroid Build Coastguard Worker }
2047*d83cc019SAndroid Build Coastguard Worker
2048*d83cc019SAndroid Build Coastguard Worker igt_debug("Port '%s' with physical type '%s' mapped to Chamelium port %d\n",
2049*d83cc019SAndroid Build Coastguard Worker map_name, kmstest_connector_type_str(port->type),
2050*d83cc019SAndroid Build Coastguard Worker port->id);
2051*d83cc019SAndroid Build Coastguard Worker }
2052*d83cc019SAndroid Build Coastguard Worker
2053*d83cc019SAndroid Build Coastguard Worker out:
2054*d83cc019SAndroid Build Coastguard Worker g_strfreev(group_list);
2055*d83cc019SAndroid Build Coastguard Worker drmModeFreeResources(res);
2056*d83cc019SAndroid Build Coastguard Worker
2057*d83cc019SAndroid Build Coastguard Worker return ret;
2058*d83cc019SAndroid Build Coastguard Worker }
2059*d83cc019SAndroid Build Coastguard Worker
port_id_from_edid(int drm_fd,drmModeConnector * connector)2060*d83cc019SAndroid Build Coastguard Worker static int port_id_from_edid(int drm_fd, drmModeConnector *connector)
2061*d83cc019SAndroid Build Coastguard Worker {
2062*d83cc019SAndroid Build Coastguard Worker int port_id = -1;
2063*d83cc019SAndroid Build Coastguard Worker bool ok;
2064*d83cc019SAndroid Build Coastguard Worker uint64_t edid_blob_id;
2065*d83cc019SAndroid Build Coastguard Worker drmModePropertyBlobRes *edid_blob;
2066*d83cc019SAndroid Build Coastguard Worker const struct edid *edid;
2067*d83cc019SAndroid Build Coastguard Worker char mfg[3];
2068*d83cc019SAndroid Build Coastguard Worker
2069*d83cc019SAndroid Build Coastguard Worker if (connector->connection != DRM_MODE_CONNECTED) {
2070*d83cc019SAndroid Build Coastguard Worker igt_debug("Skipping auto-discovery for connector %s-%d: "
2071*d83cc019SAndroid Build Coastguard Worker "connector status is not connected\n",
2072*d83cc019SAndroid Build Coastguard Worker kmstest_connector_type_str(connector->connector_type),
2073*d83cc019SAndroid Build Coastguard Worker connector->connector_type_id);
2074*d83cc019SAndroid Build Coastguard Worker return -1;
2075*d83cc019SAndroid Build Coastguard Worker }
2076*d83cc019SAndroid Build Coastguard Worker
2077*d83cc019SAndroid Build Coastguard Worker ok = kmstest_get_property(drm_fd, connector->connector_id,
2078*d83cc019SAndroid Build Coastguard Worker DRM_MODE_OBJECT_CONNECTOR, "EDID",
2079*d83cc019SAndroid Build Coastguard Worker NULL, &edid_blob_id, NULL);
2080*d83cc019SAndroid Build Coastguard Worker if (!ok || !edid_blob_id) {
2081*d83cc019SAndroid Build Coastguard Worker igt_debug("Skipping auto-discovery for connector %s-%d: "
2082*d83cc019SAndroid Build Coastguard Worker "missing the EDID property\n",
2083*d83cc019SAndroid Build Coastguard Worker kmstest_connector_type_str(connector->connector_type),
2084*d83cc019SAndroid Build Coastguard Worker connector->connector_type_id);
2085*d83cc019SAndroid Build Coastguard Worker return -1;
2086*d83cc019SAndroid Build Coastguard Worker }
2087*d83cc019SAndroid Build Coastguard Worker
2088*d83cc019SAndroid Build Coastguard Worker edid_blob = drmModeGetPropertyBlob(drm_fd, edid_blob_id);
2089*d83cc019SAndroid Build Coastguard Worker igt_assert(edid_blob);
2090*d83cc019SAndroid Build Coastguard Worker
2091*d83cc019SAndroid Build Coastguard Worker edid = (const struct edid *) edid_blob->data;
2092*d83cc019SAndroid Build Coastguard Worker
2093*d83cc019SAndroid Build Coastguard Worker edid_get_mfg(edid, mfg);
2094*d83cc019SAndroid Build Coastguard Worker if (memcmp(mfg, "IGT", 3) != 0) {
2095*d83cc019SAndroid Build Coastguard Worker igt_debug("Skipping connector %s-%d for auto-discovery: "
2096*d83cc019SAndroid Build Coastguard Worker "manufacturer is %.3s, not IGT\n",
2097*d83cc019SAndroid Build Coastguard Worker kmstest_connector_type_str(connector->connector_type),
2098*d83cc019SAndroid Build Coastguard Worker connector->connector_type_id, mfg);
2099*d83cc019SAndroid Build Coastguard Worker goto out;
2100*d83cc019SAndroid Build Coastguard Worker }
2101*d83cc019SAndroid Build Coastguard Worker
2102*d83cc019SAndroid Build Coastguard Worker if (edid->prod_code[0] != 'C' || edid->prod_code[1] != 'H') {
2103*d83cc019SAndroid Build Coastguard Worker igt_warn("Invalid EDID for IGT connector %s-%d: "
2104*d83cc019SAndroid Build Coastguard Worker "invalid product code\n",
2105*d83cc019SAndroid Build Coastguard Worker kmstest_connector_type_str(connector->connector_type),
2106*d83cc019SAndroid Build Coastguard Worker connector->connector_type_id);
2107*d83cc019SAndroid Build Coastguard Worker goto out;
2108*d83cc019SAndroid Build Coastguard Worker }
2109*d83cc019SAndroid Build Coastguard Worker
2110*d83cc019SAndroid Build Coastguard Worker port_id = *(uint32_t *) &edid->serial;
2111*d83cc019SAndroid Build Coastguard Worker igt_debug("Auto-discovery mapped connector %s-%d to Chamelium "
2112*d83cc019SAndroid Build Coastguard Worker "port ID %d\n",
2113*d83cc019SAndroid Build Coastguard Worker kmstest_connector_type_str(connector->connector_type),
2114*d83cc019SAndroid Build Coastguard Worker connector->connector_type_id, port_id);
2115*d83cc019SAndroid Build Coastguard Worker
2116*d83cc019SAndroid Build Coastguard Worker out:
2117*d83cc019SAndroid Build Coastguard Worker drmModeFreePropertyBlob(edid_blob);
2118*d83cc019SAndroid Build Coastguard Worker return port_id;
2119*d83cc019SAndroid Build Coastguard Worker }
2120*d83cc019SAndroid Build Coastguard Worker
2121*d83cc019SAndroid Build Coastguard Worker /**
2122*d83cc019SAndroid Build Coastguard Worker * chamelium_autodiscover: automagically discover the Chamelium port mapping
2123*d83cc019SAndroid Build Coastguard Worker *
2124*d83cc019SAndroid Build Coastguard Worker * The Chamelium API uses port IDs wheras the Device Under Test uses DRM
2125*d83cc019SAndroid Build Coastguard Worker * connectors. We need to know which Chamelium port is plugged to a given DRM
2126*d83cc019SAndroid Build Coastguard Worker * connector. This has typically been done via a configuration file in the
2127*d83cc019SAndroid Build Coastguard Worker * past (see #chamelium_read_port_mappings), but this function provides an
2128*d83cc019SAndroid Build Coastguard Worker * automatic way to do it.
2129*d83cc019SAndroid Build Coastguard Worker *
2130*d83cc019SAndroid Build Coastguard Worker * We will plug all Chamelium ports with a different EDID on each. Then we'll
2131*d83cc019SAndroid Build Coastguard Worker * read the EDID on each DRM connector and infer the Chamelium port ID.
2132*d83cc019SAndroid Build Coastguard Worker */
chamelium_autodiscover(struct chamelium * chamelium,int drm_fd)2133*d83cc019SAndroid Build Coastguard Worker static bool chamelium_autodiscover(struct chamelium *chamelium, int drm_fd)
2134*d83cc019SAndroid Build Coastguard Worker {
2135*d83cc019SAndroid Build Coastguard Worker int candidate_ports[CHAMELIUM_MAX_PORTS];
2136*d83cc019SAndroid Build Coastguard Worker size_t candidate_ports_len;
2137*d83cc019SAndroid Build Coastguard Worker drmModeRes *res;
2138*d83cc019SAndroid Build Coastguard Worker drmModeConnector *connector;
2139*d83cc019SAndroid Build Coastguard Worker struct chamelium_port *port;
2140*d83cc019SAndroid Build Coastguard Worker size_t i, j, port_count;
2141*d83cc019SAndroid Build Coastguard Worker int port_id;
2142*d83cc019SAndroid Build Coastguard Worker uint32_t conn_id;
2143*d83cc019SAndroid Build Coastguard Worker struct chamelium_edid *edid;
2144*d83cc019SAndroid Build Coastguard Worker bool found;
2145*d83cc019SAndroid Build Coastguard Worker uint32_t discovered_conns[CHAMELIUM_MAX_PORTS] = {0};
2146*d83cc019SAndroid Build Coastguard Worker char conn_name[64];
2147*d83cc019SAndroid Build Coastguard Worker struct timespec start;
2148*d83cc019SAndroid Build Coastguard Worker uint64_t elapsed_ns;
2149*d83cc019SAndroid Build Coastguard Worker
2150*d83cc019SAndroid Build Coastguard Worker candidate_ports_len = chamelium_get_video_ports(chamelium,
2151*d83cc019SAndroid Build Coastguard Worker candidate_ports);
2152*d83cc019SAndroid Build Coastguard Worker
2153*d83cc019SAndroid Build Coastguard Worker igt_debug("Starting Chamelium port auto-discovery on %zu ports\n",
2154*d83cc019SAndroid Build Coastguard Worker candidate_ports_len);
2155*d83cc019SAndroid Build Coastguard Worker igt_gettime(&start);
2156*d83cc019SAndroid Build Coastguard Worker
2157*d83cc019SAndroid Build Coastguard Worker edid = chamelium_new_edid(chamelium, igt_kms_get_base_edid());
2158*d83cc019SAndroid Build Coastguard Worker
2159*d83cc019SAndroid Build Coastguard Worker /* Set EDID and plug ports we want to auto-discover */
2160*d83cc019SAndroid Build Coastguard Worker port_count = chamelium->port_count;
2161*d83cc019SAndroid Build Coastguard Worker for (i = 0; i < candidate_ports_len; i++) {
2162*d83cc019SAndroid Build Coastguard Worker port_id = candidate_ports[i];
2163*d83cc019SAndroid Build Coastguard Worker
2164*d83cc019SAndroid Build Coastguard Worker /* Get or add a chamelium_port slot */
2165*d83cc019SAndroid Build Coastguard Worker port = NULL;
2166*d83cc019SAndroid Build Coastguard Worker for (j = 0; j < chamelium->port_count; j++) {
2167*d83cc019SAndroid Build Coastguard Worker if (chamelium->ports[j].id == port_id) {
2168*d83cc019SAndroid Build Coastguard Worker port = &chamelium->ports[j];
2169*d83cc019SAndroid Build Coastguard Worker break;
2170*d83cc019SAndroid Build Coastguard Worker }
2171*d83cc019SAndroid Build Coastguard Worker }
2172*d83cc019SAndroid Build Coastguard Worker if (!port) {
2173*d83cc019SAndroid Build Coastguard Worker igt_assert(port_count < CHAMELIUM_MAX_PORTS);
2174*d83cc019SAndroid Build Coastguard Worker port = &chamelium->ports[port_count];
2175*d83cc019SAndroid Build Coastguard Worker port_count++;
2176*d83cc019SAndroid Build Coastguard Worker
2177*d83cc019SAndroid Build Coastguard Worker port->id = port_id;
2178*d83cc019SAndroid Build Coastguard Worker }
2179*d83cc019SAndroid Build Coastguard Worker
2180*d83cc019SAndroid Build Coastguard Worker chamelium_port_set_edid(chamelium, port, edid);
2181*d83cc019SAndroid Build Coastguard Worker chamelium_plug(chamelium, port);
2182*d83cc019SAndroid Build Coastguard Worker }
2183*d83cc019SAndroid Build Coastguard Worker
2184*d83cc019SAndroid Build Coastguard Worker /* Reprobe connectors and build the mapping */
2185*d83cc019SAndroid Build Coastguard Worker res = drmModeGetResources(drm_fd);
2186*d83cc019SAndroid Build Coastguard Worker if (!res)
2187*d83cc019SAndroid Build Coastguard Worker return false;
2188*d83cc019SAndroid Build Coastguard Worker
2189*d83cc019SAndroid Build Coastguard Worker for (i = 0; i < res->count_connectors; i++) {
2190*d83cc019SAndroid Build Coastguard Worker conn_id = res->connectors[i];
2191*d83cc019SAndroid Build Coastguard Worker
2192*d83cc019SAndroid Build Coastguard Worker /* Read the EDID and parse the Chamelium port ID we stored
2193*d83cc019SAndroid Build Coastguard Worker * there. */
2194*d83cc019SAndroid Build Coastguard Worker connector = drmModeGetConnector(drm_fd, res->connectors[i]);
2195*d83cc019SAndroid Build Coastguard Worker port_id = port_id_from_edid(drm_fd, connector);
2196*d83cc019SAndroid Build Coastguard Worker drmModeFreeConnector(connector);
2197*d83cc019SAndroid Build Coastguard Worker if (port_id < 0)
2198*d83cc019SAndroid Build Coastguard Worker continue;
2199*d83cc019SAndroid Build Coastguard Worker
2200*d83cc019SAndroid Build Coastguard Worker /* If we already have a mapping from the config file, check
2201*d83cc019SAndroid Build Coastguard Worker * that it's consistent. */
2202*d83cc019SAndroid Build Coastguard Worker found = false;
2203*d83cc019SAndroid Build Coastguard Worker for (j = 0; j < chamelium->port_count; j++) {
2204*d83cc019SAndroid Build Coastguard Worker port = &chamelium->ports[j];
2205*d83cc019SAndroid Build Coastguard Worker if (port->connector_id == conn_id) {
2206*d83cc019SAndroid Build Coastguard Worker found = true;
2207*d83cc019SAndroid Build Coastguard Worker igt_assert_f(port->id == port_id,
2208*d83cc019SAndroid Build Coastguard Worker "Inconsistency detected in .igtrc: "
2209*d83cc019SAndroid Build Coastguard Worker "connector %s is configured with "
2210*d83cc019SAndroid Build Coastguard Worker "Chamelium port %d, but is "
2211*d83cc019SAndroid Build Coastguard Worker "connected to port %d\n",
2212*d83cc019SAndroid Build Coastguard Worker port->name, port->id, port_id);
2213*d83cc019SAndroid Build Coastguard Worker break;
2214*d83cc019SAndroid Build Coastguard Worker }
2215*d83cc019SAndroid Build Coastguard Worker }
2216*d83cc019SAndroid Build Coastguard Worker if (found)
2217*d83cc019SAndroid Build Coastguard Worker continue;
2218*d83cc019SAndroid Build Coastguard Worker
2219*d83cc019SAndroid Build Coastguard Worker /* We got a new mapping */
2220*d83cc019SAndroid Build Coastguard Worker found = false;
2221*d83cc019SAndroid Build Coastguard Worker for (j = 0; j < candidate_ports_len; j++) {
2222*d83cc019SAndroid Build Coastguard Worker if (port_id == candidate_ports[j]) {
2223*d83cc019SAndroid Build Coastguard Worker found = true;
2224*d83cc019SAndroid Build Coastguard Worker discovered_conns[j] = conn_id;
2225*d83cc019SAndroid Build Coastguard Worker break;
2226*d83cc019SAndroid Build Coastguard Worker }
2227*d83cc019SAndroid Build Coastguard Worker }
2228*d83cc019SAndroid Build Coastguard Worker igt_assert_f(found, "Auto-discovered a port (%d) we haven't "
2229*d83cc019SAndroid Build Coastguard Worker "setup\n", port_id);
2230*d83cc019SAndroid Build Coastguard Worker }
2231*d83cc019SAndroid Build Coastguard Worker
2232*d83cc019SAndroid Build Coastguard Worker drmModeFreeResources(res);
2233*d83cc019SAndroid Build Coastguard Worker
2234*d83cc019SAndroid Build Coastguard Worker /* We now have a Chamelium port ID ↔ DRM connector ID mapping:
2235*d83cc019SAndroid Build Coastguard Worker * candidate_ports contains the Chamelium port IDs and
2236*d83cc019SAndroid Build Coastguard Worker * discovered_conns contains the DRM connector IDs. */
2237*d83cc019SAndroid Build Coastguard Worker for (i = 0; i < candidate_ports_len; i++) {
2238*d83cc019SAndroid Build Coastguard Worker port_id = candidate_ports[i];
2239*d83cc019SAndroid Build Coastguard Worker conn_id = discovered_conns[i];
2240*d83cc019SAndroid Build Coastguard Worker if (!conn_id) {
2241*d83cc019SAndroid Build Coastguard Worker continue;
2242*d83cc019SAndroid Build Coastguard Worker }
2243*d83cc019SAndroid Build Coastguard Worker
2244*d83cc019SAndroid Build Coastguard Worker port = &chamelium->ports[chamelium->port_count];
2245*d83cc019SAndroid Build Coastguard Worker chamelium->port_count++;
2246*d83cc019SAndroid Build Coastguard Worker
2247*d83cc019SAndroid Build Coastguard Worker port->id = port_id;
2248*d83cc019SAndroid Build Coastguard Worker port->type = chamelium_get_port_type(chamelium, port);
2249*d83cc019SAndroid Build Coastguard Worker port->connector_id = conn_id;
2250*d83cc019SAndroid Build Coastguard Worker
2251*d83cc019SAndroid Build Coastguard Worker connector = drmModeGetConnectorCurrent(drm_fd, conn_id);
2252*d83cc019SAndroid Build Coastguard Worker snprintf(conn_name, sizeof(conn_name), "%s-%u",
2253*d83cc019SAndroid Build Coastguard Worker kmstest_connector_type_str(connector->connector_type),
2254*d83cc019SAndroid Build Coastguard Worker connector->connector_type_id);
2255*d83cc019SAndroid Build Coastguard Worker drmModeFreeConnector(connector);
2256*d83cc019SAndroid Build Coastguard Worker port->name = strdup(conn_name);
2257*d83cc019SAndroid Build Coastguard Worker }
2258*d83cc019SAndroid Build Coastguard Worker
2259*d83cc019SAndroid Build Coastguard Worker elapsed_ns = igt_nsec_elapsed(&start);
2260*d83cc019SAndroid Build Coastguard Worker igt_debug("Auto-discovery took %fms\n",
2261*d83cc019SAndroid Build Coastguard Worker (float) elapsed_ns / (1000 * 1000));
2262*d83cc019SAndroid Build Coastguard Worker
2263*d83cc019SAndroid Build Coastguard Worker return true;
2264*d83cc019SAndroid Build Coastguard Worker }
2265*d83cc019SAndroid Build Coastguard Worker
chamelium_read_config(struct chamelium * chamelium,int drm_fd)2266*d83cc019SAndroid Build Coastguard Worker static bool chamelium_read_config(struct chamelium *chamelium, int drm_fd)
2267*d83cc019SAndroid Build Coastguard Worker {
2268*d83cc019SAndroid Build Coastguard Worker GError *error = NULL;
2269*d83cc019SAndroid Build Coastguard Worker
2270*d83cc019SAndroid Build Coastguard Worker if (!igt_key_file) {
2271*d83cc019SAndroid Build Coastguard Worker igt_warn("No configuration file available for chamelium\n");
2272*d83cc019SAndroid Build Coastguard Worker return false;
2273*d83cc019SAndroid Build Coastguard Worker }
2274*d83cc019SAndroid Build Coastguard Worker
2275*d83cc019SAndroid Build Coastguard Worker chamelium->url = g_key_file_get_string(igt_key_file, "Chamelium", "URL",
2276*d83cc019SAndroid Build Coastguard Worker &error);
2277*d83cc019SAndroid Build Coastguard Worker if (!chamelium->url) {
2278*d83cc019SAndroid Build Coastguard Worker igt_warn("Couldn't read chamelium URL from config file: %s\n",
2279*d83cc019SAndroid Build Coastguard Worker error->message);
2280*d83cc019SAndroid Build Coastguard Worker return false;
2281*d83cc019SAndroid Build Coastguard Worker }
2282*d83cc019SAndroid Build Coastguard Worker
2283*d83cc019SAndroid Build Coastguard Worker if (!chamelium_read_port_mappings(chamelium, drm_fd)) {
2284*d83cc019SAndroid Build Coastguard Worker return false;
2285*d83cc019SAndroid Build Coastguard Worker }
2286*d83cc019SAndroid Build Coastguard Worker return chamelium_autodiscover(chamelium, drm_fd);
2287*d83cc019SAndroid Build Coastguard Worker }
2288*d83cc019SAndroid Build Coastguard Worker
2289*d83cc019SAndroid Build Coastguard Worker /**
2290*d83cc019SAndroid Build Coastguard Worker * chamelium_reset:
2291*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
2292*d83cc019SAndroid Build Coastguard Worker *
2293*d83cc019SAndroid Build Coastguard Worker * Resets the chamelium's IO board. As well, this also has the effect of
2294*d83cc019SAndroid Build Coastguard Worker * causing all of the chamelium ports to get set to unplugged
2295*d83cc019SAndroid Build Coastguard Worker */
chamelium_reset(struct chamelium * chamelium)2296*d83cc019SAndroid Build Coastguard Worker void chamelium_reset(struct chamelium *chamelium)
2297*d83cc019SAndroid Build Coastguard Worker {
2298*d83cc019SAndroid Build Coastguard Worker igt_debug("Resetting the chamelium\n");
2299*d83cc019SAndroid Build Coastguard Worker xmlrpc_DECREF(chamelium_rpc(chamelium, NULL, "Reset", "()"));
2300*d83cc019SAndroid Build Coastguard Worker }
2301*d83cc019SAndroid Build Coastguard Worker
chamelium_exit_handler(int sig)2302*d83cc019SAndroid Build Coastguard Worker static void chamelium_exit_handler(int sig)
2303*d83cc019SAndroid Build Coastguard Worker {
2304*d83cc019SAndroid Build Coastguard Worker igt_debug("Deinitializing Chamelium\n");
2305*d83cc019SAndroid Build Coastguard Worker
2306*d83cc019SAndroid Build Coastguard Worker if (cleanup_instance)
2307*d83cc019SAndroid Build Coastguard Worker chamelium_deinit(cleanup_instance);
2308*d83cc019SAndroid Build Coastguard Worker }
2309*d83cc019SAndroid Build Coastguard Worker
2310*d83cc019SAndroid Build Coastguard Worker /**
2311*d83cc019SAndroid Build Coastguard Worker * chamelium_init:
2312*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
2313*d83cc019SAndroid Build Coastguard Worker * @drm_fd: a display initialized with #igt_display_require
2314*d83cc019SAndroid Build Coastguard Worker *
2315*d83cc019SAndroid Build Coastguard Worker * Sets up a connection with a chamelium, using the URL specified in the
2316*d83cc019SAndroid Build Coastguard Worker * Chamelium configuration. This must be called first before trying to use the
2317*d83cc019SAndroid Build Coastguard Worker * chamelium.
2318*d83cc019SAndroid Build Coastguard Worker *
2319*d83cc019SAndroid Build Coastguard Worker * If we fail to establish a connection with the chamelium, fail to find a
2320*d83cc019SAndroid Build Coastguard Worker * configured connector, etc. we fail the current test.
2321*d83cc019SAndroid Build Coastguard Worker *
2322*d83cc019SAndroid Build Coastguard Worker * Returns: A newly initialized chamelium struct, or NULL on error
2323*d83cc019SAndroid Build Coastguard Worker */
chamelium_init(int drm_fd)2324*d83cc019SAndroid Build Coastguard Worker struct chamelium *chamelium_init(int drm_fd)
2325*d83cc019SAndroid Build Coastguard Worker {
2326*d83cc019SAndroid Build Coastguard Worker struct chamelium *chamelium = malloc(sizeof(struct chamelium));
2327*d83cc019SAndroid Build Coastguard Worker
2328*d83cc019SAndroid Build Coastguard Worker if (!chamelium)
2329*d83cc019SAndroid Build Coastguard Worker return NULL;
2330*d83cc019SAndroid Build Coastguard Worker
2331*d83cc019SAndroid Build Coastguard Worker /* A chamelium instance was set up previously, so clean it up before
2332*d83cc019SAndroid Build Coastguard Worker * starting a new one
2333*d83cc019SAndroid Build Coastguard Worker */
2334*d83cc019SAndroid Build Coastguard Worker if (cleanup_instance)
2335*d83cc019SAndroid Build Coastguard Worker chamelium_deinit(cleanup_instance);
2336*d83cc019SAndroid Build Coastguard Worker
2337*d83cc019SAndroid Build Coastguard Worker memset(chamelium, 0, sizeof(*chamelium));
2338*d83cc019SAndroid Build Coastguard Worker chamelium->drm_fd = drm_fd;
2339*d83cc019SAndroid Build Coastguard Worker igt_list_init(&chamelium->edids);
2340*d83cc019SAndroid Build Coastguard Worker
2341*d83cc019SAndroid Build Coastguard Worker /* Setup the libxmlrpc context */
2342*d83cc019SAndroid Build Coastguard Worker xmlrpc_env_init(&chamelium->env);
2343*d83cc019SAndroid Build Coastguard Worker xmlrpc_client_setup_global_const(&chamelium->env);
2344*d83cc019SAndroid Build Coastguard Worker xmlrpc_client_create(&chamelium->env, XMLRPC_CLIENT_NO_FLAGS, PACKAGE,
2345*d83cc019SAndroid Build Coastguard Worker PACKAGE_VERSION, NULL, 0, &chamelium->client);
2346*d83cc019SAndroid Build Coastguard Worker if (chamelium->env.fault_occurred) {
2347*d83cc019SAndroid Build Coastguard Worker igt_debug("Failed to init xmlrpc: %s\n",
2348*d83cc019SAndroid Build Coastguard Worker chamelium->env.fault_string);
2349*d83cc019SAndroid Build Coastguard Worker goto error;
2350*d83cc019SAndroid Build Coastguard Worker }
2351*d83cc019SAndroid Build Coastguard Worker
2352*d83cc019SAndroid Build Coastguard Worker if (!chamelium_read_config(chamelium, drm_fd))
2353*d83cc019SAndroid Build Coastguard Worker goto error;
2354*d83cc019SAndroid Build Coastguard Worker
2355*d83cc019SAndroid Build Coastguard Worker cleanup_instance = chamelium;
2356*d83cc019SAndroid Build Coastguard Worker igt_install_exit_handler(chamelium_exit_handler);
2357*d83cc019SAndroid Build Coastguard Worker
2358*d83cc019SAndroid Build Coastguard Worker return chamelium;
2359*d83cc019SAndroid Build Coastguard Worker
2360*d83cc019SAndroid Build Coastguard Worker error:
2361*d83cc019SAndroid Build Coastguard Worker xmlrpc_env_clean(&chamelium->env);
2362*d83cc019SAndroid Build Coastguard Worker free(chamelium);
2363*d83cc019SAndroid Build Coastguard Worker
2364*d83cc019SAndroid Build Coastguard Worker return NULL;
2365*d83cc019SAndroid Build Coastguard Worker }
2366*d83cc019SAndroid Build Coastguard Worker
2367*d83cc019SAndroid Build Coastguard Worker /**
2368*d83cc019SAndroid Build Coastguard Worker * chamelium_deinit:
2369*d83cc019SAndroid Build Coastguard Worker * @chamelium: The Chamelium instance to use
2370*d83cc019SAndroid Build Coastguard Worker *
2371*d83cc019SAndroid Build Coastguard Worker * Frees the resources used by a connection to the chamelium that was set up
2372*d83cc019SAndroid Build Coastguard Worker * with #chamelium_init. As well, this function restores the state of the
2373*d83cc019SAndroid Build Coastguard Worker * chamelium like it was before calling #chamelium_init. This function is also
2374*d83cc019SAndroid Build Coastguard Worker * called as an exit handler, so users only need to call manually if they don't
2375*d83cc019SAndroid Build Coastguard Worker * want the chamelium interfering with other tests in the same file.
2376*d83cc019SAndroid Build Coastguard Worker */
chamelium_deinit(struct chamelium * chamelium)2377*d83cc019SAndroid Build Coastguard Worker void chamelium_deinit(struct chamelium *chamelium)
2378*d83cc019SAndroid Build Coastguard Worker {
2379*d83cc019SAndroid Build Coastguard Worker int i;
2380*d83cc019SAndroid Build Coastguard Worker struct chamelium_edid *pos, *tmp;
2381*d83cc019SAndroid Build Coastguard Worker
2382*d83cc019SAndroid Build Coastguard Worker /* We want to make sure we leave all of the ports plugged in, since
2383*d83cc019SAndroid Build Coastguard Worker * testing setups requiring multiple monitors are probably using the
2384*d83cc019SAndroid Build Coastguard Worker * chamelium to provide said monitors
2385*d83cc019SAndroid Build Coastguard Worker */
2386*d83cc019SAndroid Build Coastguard Worker chamelium_reset(chamelium);
2387*d83cc019SAndroid Build Coastguard Worker for (i = 0; i < chamelium->port_count; i++)
2388*d83cc019SAndroid Build Coastguard Worker chamelium_plug(chamelium, &chamelium->ports[i]);
2389*d83cc019SAndroid Build Coastguard Worker
2390*d83cc019SAndroid Build Coastguard Worker /* Destroy any EDIDs we created to make sure we don't leak them */
2391*d83cc019SAndroid Build Coastguard Worker igt_list_for_each_safe(pos, tmp, &chamelium->edids, link) {
2392*d83cc019SAndroid Build Coastguard Worker for (i = 0; i < CHAMELIUM_MAX_PORTS; i++) {
2393*d83cc019SAndroid Build Coastguard Worker if (pos->ids[i])
2394*d83cc019SAndroid Build Coastguard Worker chamelium_destroy_edid(chamelium, pos->ids[i]);
2395*d83cc019SAndroid Build Coastguard Worker free(pos->raw[i]);
2396*d83cc019SAndroid Build Coastguard Worker }
2397*d83cc019SAndroid Build Coastguard Worker free(pos->base);
2398*d83cc019SAndroid Build Coastguard Worker free(pos);
2399*d83cc019SAndroid Build Coastguard Worker }
2400*d83cc019SAndroid Build Coastguard Worker
2401*d83cc019SAndroid Build Coastguard Worker xmlrpc_client_destroy(chamelium->client);
2402*d83cc019SAndroid Build Coastguard Worker xmlrpc_env_clean(&chamelium->env);
2403*d83cc019SAndroid Build Coastguard Worker
2404*d83cc019SAndroid Build Coastguard Worker for (i = 0; i < chamelium->port_count; i++)
2405*d83cc019SAndroid Build Coastguard Worker free(chamelium->ports[i].name);
2406*d83cc019SAndroid Build Coastguard Worker
2407*d83cc019SAndroid Build Coastguard Worker free(chamelium);
2408*d83cc019SAndroid Build Coastguard Worker }
2409*d83cc019SAndroid Build Coastguard Worker
2410*d83cc019SAndroid Build Coastguard Worker igt_constructor {
2411*d83cc019SAndroid Build Coastguard Worker /* Frame dumps can be large, so we need to be able to handle very large
2412*d83cc019SAndroid Build Coastguard Worker * responses
2413*d83cc019SAndroid Build Coastguard Worker *
2414*d83cc019SAndroid Build Coastguard Worker * Limit here is 15MB
2415*d83cc019SAndroid Build Coastguard Worker */
2416*d83cc019SAndroid Build Coastguard Worker xmlrpc_limit_set(XMLRPC_XML_SIZE_LIMIT_ID, 15728640);
2417*d83cc019SAndroid Build Coastguard Worker }
2418