1 /*
2 * Copyright (C) 2019 Red Hat
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 * 02111-1307, USA.
18 */
19
20 #include "config.h"
21
22 #include "backends/native/meta-kms-connector.h"
23 #include "backends/native/meta-kms-connector-private.h"
24
25 #include <errno.h>
26
27 #include "backends/native/meta-kms-crtc.h"
28 #include "backends/native/meta-kms-device-private.h"
29 #include "backends/native/meta-kms-impl-device.h"
30 #include "backends/native/meta-kms-mode-private.h"
31 #include "backends/native/meta-kms-update-private.h"
32
33 typedef struct _MetaKmsConnectorPropTable
34 {
35 MetaKmsProp props[META_KMS_CONNECTOR_N_PROPS];
36 } MetaKmsConnectorPropTable;
37
38 struct _MetaKmsConnector
39 {
40 GObject parent;
41
42 MetaKmsDevice *device;
43
44 uint32_t id;
45 uint32_t type;
46 uint32_t type_id;
47 char *name;
48
49 drmModeConnection connection;
50 MetaKmsConnectorState *current_state;
51
52 MetaKmsConnectorPropTable prop_table;
53
54 uint32_t edid_blob_id;
55 uint32_t tile_blob_id;
56
57 gboolean fd_held;
58 };
59
G_DEFINE_TYPE(MetaKmsConnector,meta_kms_connector,G_TYPE_OBJECT)60 G_DEFINE_TYPE (MetaKmsConnector, meta_kms_connector, G_TYPE_OBJECT)
61
62 MetaKmsDevice *
63 meta_kms_connector_get_device (MetaKmsConnector *connector)
64 {
65 return connector->device;
66 }
67
68 uint32_t
meta_kms_connector_get_prop_id(MetaKmsConnector * connector,MetaKmsConnectorProp prop)69 meta_kms_connector_get_prop_id (MetaKmsConnector *connector,
70 MetaKmsConnectorProp prop)
71 {
72 return connector->prop_table.props[prop].prop_id;
73 }
74
75 const char *
meta_kms_connector_get_prop_name(MetaKmsConnector * connector,MetaKmsConnectorProp prop)76 meta_kms_connector_get_prop_name (MetaKmsConnector *connector,
77 MetaKmsConnectorProp prop)
78 {
79 return connector->prop_table.props[prop].name;
80 }
81
82 uint32_t
meta_kms_connector_get_connector_type(MetaKmsConnector * connector)83 meta_kms_connector_get_connector_type (MetaKmsConnector *connector)
84 {
85 return connector->type;
86 }
87
88 uint32_t
meta_kms_connector_get_id(MetaKmsConnector * connector)89 meta_kms_connector_get_id (MetaKmsConnector *connector)
90 {
91 return connector->id;
92 }
93
94 const char *
meta_kms_connector_get_name(MetaKmsConnector * connector)95 meta_kms_connector_get_name (MetaKmsConnector *connector)
96 {
97 return connector->name;
98 }
99
100 gboolean
meta_kms_connector_can_clone(MetaKmsConnector * connector,MetaKmsConnector * other_connector)101 meta_kms_connector_can_clone (MetaKmsConnector *connector,
102 MetaKmsConnector *other_connector)
103 {
104 MetaKmsConnectorState *state = connector->current_state;
105 MetaKmsConnectorState *other_state = other_connector->current_state;
106
107 if (state->common_possible_clones == 0 ||
108 other_state->common_possible_clones == 0)
109 return FALSE;
110
111 if (state->encoder_device_idxs != other_state->encoder_device_idxs)
112 return FALSE;
113
114 return TRUE;
115 }
116
117 const MetaKmsConnectorState *
meta_kms_connector_get_current_state(MetaKmsConnector * connector)118 meta_kms_connector_get_current_state (MetaKmsConnector *connector)
119 {
120 return connector->current_state;
121 }
122
123 gboolean
meta_kms_connector_is_underscanning_supported(MetaKmsConnector * connector)124 meta_kms_connector_is_underscanning_supported (MetaKmsConnector *connector)
125 {
126 uint32_t underscan_prop_id;
127
128 underscan_prop_id =
129 meta_kms_connector_get_prop_id (connector,
130 META_KMS_CONNECTOR_PROP_UNDERSCAN);
131
132 return underscan_prop_id != 0;
133 }
134
135 static void
sync_fd_held(MetaKmsConnector * connector,MetaKmsImplDevice * impl_device)136 sync_fd_held (MetaKmsConnector *connector,
137 MetaKmsImplDevice *impl_device)
138 {
139 gboolean should_hold_fd;
140
141 should_hold_fd = connector->current_state->current_crtc_id != 0;
142
143 if (connector->fd_held == should_hold_fd)
144 return;
145
146 if (should_hold_fd)
147 meta_kms_impl_device_hold_fd (impl_device);
148 else
149 meta_kms_impl_device_unhold_fd (impl_device);
150
151 connector->fd_held = should_hold_fd;
152 }
153
154 static void
set_panel_orientation(MetaKmsConnectorState * state,drmModePropertyPtr prop,uint64_t orientation)155 set_panel_orientation (MetaKmsConnectorState *state,
156 drmModePropertyPtr prop,
157 uint64_t orientation)
158 {
159 const char *name;
160
161 name = prop->enums[orientation].name;
162 if (strcmp (name, "Upside Down") == 0)
163 {
164 state->panel_orientation_transform = META_MONITOR_TRANSFORM_180;
165 }
166 else if (strcmp (name, "Left Side Up") == 0)
167 {
168 /* Left side up, rotate 90 degrees counter clockwise to correct */
169 state->panel_orientation_transform = META_MONITOR_TRANSFORM_90;
170 }
171 else if (strcmp (name, "Right Side Up") == 0)
172 {
173 /* Right side up, rotate 270 degrees counter clockwise to correct */
174 state->panel_orientation_transform = META_MONITOR_TRANSFORM_270;
175 }
176 else
177 {
178 state->panel_orientation_transform = META_MONITOR_TRANSFORM_NORMAL;
179 }
180 }
181
182 static void
state_set_properties(MetaKmsConnectorState * state,MetaKmsImplDevice * impl_device,drmModeConnector * drm_connector)183 state_set_properties (MetaKmsConnectorState *state,
184 MetaKmsImplDevice *impl_device,
185 drmModeConnector *drm_connector)
186 {
187 int fd;
188 int i;
189
190 fd = meta_kms_impl_device_get_fd (impl_device);
191
192 for (i = 0; i < drm_connector->count_props; i++)
193 {
194 drmModePropertyPtr prop;
195
196 prop = drmModeGetProperty (fd, drm_connector->props[i]);
197 if (!prop)
198 continue;
199
200 if ((prop->flags & DRM_MODE_PROP_RANGE) &&
201 strcmp (prop->name, "suggested X") == 0)
202 state->suggested_x = drm_connector->prop_values[i];
203 else if ((prop->flags & DRM_MODE_PROP_RANGE) &&
204 strcmp (prop->name, "suggested Y") == 0)
205 state->suggested_y = drm_connector->prop_values[i];
206 else if ((prop->flags & DRM_MODE_PROP_RANGE) &&
207 strcmp (prop->name, "hotplug_mode_update") == 0)
208 state->hotplug_mode_update = drm_connector->prop_values[i];
209 else if (strcmp (prop->name, "scaling mode") == 0)
210 state->has_scaling = TRUE;
211 else if ((prop->flags & DRM_MODE_PROP_ENUM) &&
212 strcmp (prop->name, "panel orientation") == 0)
213 set_panel_orientation (state, prop, drm_connector->prop_values[i]);
214 else if ((prop->flags & DRM_MODE_PROP_RANGE) &&
215 strcmp (prop->name, "non-desktop") == 0)
216 state->non_desktop = drm_connector->prop_values[i];
217
218 drmModeFreeProperty (prop);
219 }
220 }
221
222 static CoglSubpixelOrder
drm_subpixel_order_to_cogl_subpixel_order(drmModeSubPixel subpixel)223 drm_subpixel_order_to_cogl_subpixel_order (drmModeSubPixel subpixel)
224 {
225 switch (subpixel)
226 {
227 case DRM_MODE_SUBPIXEL_NONE:
228 return COGL_SUBPIXEL_ORDER_NONE;
229 break;
230 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
231 return COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB;
232 break;
233 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
234 return COGL_SUBPIXEL_ORDER_HORIZONTAL_BGR;
235 break;
236 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
237 return COGL_SUBPIXEL_ORDER_VERTICAL_RGB;
238 break;
239 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
240 return COGL_SUBPIXEL_ORDER_VERTICAL_BGR;
241 break;
242 case DRM_MODE_SUBPIXEL_UNKNOWN:
243 return COGL_SUBPIXEL_ORDER_UNKNOWN;
244 }
245 return COGL_SUBPIXEL_ORDER_UNKNOWN;
246 }
247
248 static void
state_set_edid(MetaKmsConnectorState * state,MetaKmsConnector * connector,MetaKmsImplDevice * impl_device,uint32_t blob_id)249 state_set_edid (MetaKmsConnectorState *state,
250 MetaKmsConnector *connector,
251 MetaKmsImplDevice *impl_device,
252 uint32_t blob_id)
253 {
254 int fd;
255 drmModePropertyBlobPtr edid_blob;
256 GBytes *edid_data;
257
258 fd = meta_kms_impl_device_get_fd (impl_device);
259 edid_blob = drmModeGetPropertyBlob (fd, blob_id);
260 if (!edid_blob)
261 {
262 g_warning ("Failed to read EDID of connector %s: %s",
263 connector->name, g_strerror (errno));
264 return;
265 }
266
267 edid_data = g_bytes_new (edid_blob->data, edid_blob->length);
268 drmModeFreePropertyBlob (edid_blob);
269
270 state->edid_data = edid_data;
271 }
272
273 static void
state_set_tile_info(MetaKmsConnectorState * state,MetaKmsConnector * connector,MetaKmsImplDevice * impl_device,uint32_t blob_id)274 state_set_tile_info (MetaKmsConnectorState *state,
275 MetaKmsConnector *connector,
276 MetaKmsImplDevice *impl_device,
277 uint32_t blob_id)
278 {
279 int fd;
280 drmModePropertyBlobPtr tile_blob;
281
282 state->tile_info = (MetaTileInfo) { 0 };
283
284 fd = meta_kms_impl_device_get_fd (impl_device);
285 tile_blob = drmModeGetPropertyBlob (fd, blob_id);
286 if (!tile_blob)
287 {
288 g_warning ("Failed to read TILE of connector %s: %s",
289 connector->name, strerror (errno));
290 return;
291 }
292
293 if (tile_blob->length > 0)
294 {
295 if (sscanf ((char *) tile_blob->data, "%d:%d:%d:%d:%d:%d:%d:%d",
296 &state->tile_info.group_id,
297 &state->tile_info.flags,
298 &state->tile_info.max_h_tiles,
299 &state->tile_info.max_v_tiles,
300 &state->tile_info.loc_h_tile,
301 &state->tile_info.loc_v_tile,
302 &state->tile_info.tile_w,
303 &state->tile_info.tile_h) != 8)
304 {
305 g_warning ("Couldn't understand TILE property blob of connector %s",
306 connector->name);
307 state->tile_info = (MetaTileInfo) { 0 };
308 }
309 }
310
311 drmModeFreePropertyBlob (tile_blob);
312 }
313
314 static void
state_set_blobs(MetaKmsConnectorState * state,MetaKmsConnector * connector,MetaKmsImplDevice * impl_device,drmModeConnector * drm_connector)315 state_set_blobs (MetaKmsConnectorState *state,
316 MetaKmsConnector *connector,
317 MetaKmsImplDevice *impl_device,
318 drmModeConnector *drm_connector)
319 {
320 int fd;
321 int i;
322
323 fd = meta_kms_impl_device_get_fd (impl_device);
324
325 for (i = 0; i < drm_connector->count_props; i++)
326 {
327 drmModePropertyPtr prop;
328
329 prop = drmModeGetProperty (fd, drm_connector->props[i]);
330 if (!prop)
331 continue;
332
333 if (prop->flags & DRM_MODE_PROP_BLOB)
334 {
335 uint32_t blob_id;
336
337 blob_id = drm_connector->prop_values[i];
338
339 if (blob_id)
340 {
341 if (strcmp (prop->name, "EDID") == 0)
342 state_set_edid (state, connector, impl_device, blob_id);
343 else if (strcmp (prop->name, "TILE") == 0)
344 state_set_tile_info (state, connector, impl_device, blob_id);
345 }
346 }
347
348 drmModeFreeProperty (prop);
349 }
350 }
351
352 static void
state_set_physical_dimensions(MetaKmsConnectorState * state,drmModeConnector * drm_connector)353 state_set_physical_dimensions (MetaKmsConnectorState *state,
354 drmModeConnector *drm_connector)
355 {
356 state->width_mm = drm_connector->mmWidth;
357 state->height_mm = drm_connector->mmHeight;
358 }
359
360 static void
state_set_modes(MetaKmsConnectorState * state,MetaKmsImplDevice * impl_device,drmModeConnector * drm_connector)361 state_set_modes (MetaKmsConnectorState *state,
362 MetaKmsImplDevice *impl_device,
363 drmModeConnector *drm_connector)
364 {
365 int i;
366
367 for (i = 0; i < drm_connector->count_modes; i++)
368 {
369 MetaKmsMode *mode;
370
371 mode = meta_kms_mode_new (impl_device, &drm_connector->modes[i],
372 META_KMS_MODE_FLAG_NONE);
373 state->modes = g_list_prepend (state->modes, mode);
374 }
375 state->modes = g_list_reverse (state->modes);
376 }
377
378 static void
set_encoder_device_idx_bit(uint32_t * encoder_device_idxs,uint32_t encoder_id,MetaKmsImplDevice * impl_device,drmModeRes * drm_resources)379 set_encoder_device_idx_bit (uint32_t *encoder_device_idxs,
380 uint32_t encoder_id,
381 MetaKmsImplDevice *impl_device,
382 drmModeRes *drm_resources)
383 {
384 int fd;
385 int i;
386
387 fd = meta_kms_impl_device_get_fd (impl_device);
388
389 for (i = 0; i < drm_resources->count_encoders; i++)
390 {
391 drmModeEncoder *drm_encoder;
392
393 drm_encoder = drmModeGetEncoder (fd, drm_resources->encoders[i]);
394 if (!drm_encoder)
395 continue;
396
397 if (drm_encoder->encoder_id == encoder_id)
398 {
399 *encoder_device_idxs |= (1 << i);
400 drmModeFreeEncoder (drm_encoder);
401 break;
402 }
403
404 drmModeFreeEncoder (drm_encoder);
405 }
406 }
407
408 static void
state_set_crtc_state(MetaKmsConnectorState * state,drmModeConnector * drm_connector,MetaKmsImplDevice * impl_device,drmModeRes * drm_resources)409 state_set_crtc_state (MetaKmsConnectorState *state,
410 drmModeConnector *drm_connector,
411 MetaKmsImplDevice *impl_device,
412 drmModeRes *drm_resources)
413 {
414 int fd;
415 int i;
416 uint32_t common_possible_crtcs;
417 uint32_t common_possible_clones;
418 uint32_t encoder_device_idxs;
419
420 fd = meta_kms_impl_device_get_fd (impl_device);
421
422 common_possible_crtcs = UINT32_MAX;
423 common_possible_clones = UINT32_MAX;
424 encoder_device_idxs = 0;
425 for (i = 0; i < drm_connector->count_encoders; i++)
426 {
427 drmModeEncoder *drm_encoder;
428
429 drm_encoder = drmModeGetEncoder (fd, drm_connector->encoders[i]);
430 if (!drm_encoder)
431 continue;
432
433 common_possible_crtcs &= drm_encoder->possible_crtcs;
434 common_possible_clones &= drm_encoder->possible_clones;
435
436 set_encoder_device_idx_bit (&encoder_device_idxs,
437 drm_encoder->encoder_id,
438 impl_device,
439 drm_resources);
440
441 if (drm_connector->encoder_id == drm_encoder->encoder_id)
442 state->current_crtc_id = drm_encoder->crtc_id;
443
444 drmModeFreeEncoder (drm_encoder);
445 }
446
447 state->common_possible_crtcs = common_possible_crtcs;
448 state->common_possible_clones = common_possible_clones;
449 state->encoder_device_idxs = encoder_device_idxs;
450 }
451
452 static MetaKmsConnectorState *
meta_kms_connector_state_new(void)453 meta_kms_connector_state_new (void)
454 {
455 MetaKmsConnectorState *state;
456
457 state = g_new0 (MetaKmsConnectorState, 1);
458 state->suggested_x = -1;
459 state->suggested_y = -1;
460
461 return state;
462 }
463
464 static void
meta_kms_connector_state_free(MetaKmsConnectorState * state)465 meta_kms_connector_state_free (MetaKmsConnectorState *state)
466 {
467 g_clear_pointer (&state->edid_data, g_bytes_unref);
468 g_list_free_full (state->modes, (GDestroyNotify) meta_kms_mode_free);
469 g_free (state);
470 }
471
472 G_DEFINE_AUTOPTR_CLEANUP_FUNC (MetaKmsConnectorState,
473 meta_kms_connector_state_free);
474
475 static gboolean
kms_modes_equal(GList * modes,GList * other_modes)476 kms_modes_equal (GList *modes,
477 GList *other_modes)
478 {
479 GList *l;
480
481 if (g_list_length (modes) != g_list_length (other_modes))
482 return FALSE;
483
484 for (l = modes; l; l = l->next)
485 {
486 GList *k;
487 MetaKmsMode *mode = l->data;
488
489 for (k = other_modes; k; k = k->next)
490 {
491 MetaKmsMode *other_mode = k->data;
492
493 if (!meta_kms_mode_equal (mode, other_mode))
494 return FALSE;
495 }
496 }
497
498 return TRUE;
499 }
500
501 static MetaKmsUpdateChanges
meta_kms_connector_state_changes(MetaKmsConnectorState * state,MetaKmsConnectorState * new_state)502 meta_kms_connector_state_changes (MetaKmsConnectorState *state,
503 MetaKmsConnectorState *new_state)
504 {
505 if (state->current_crtc_id != new_state->current_crtc_id)
506 return META_KMS_UPDATE_CHANGE_FULL;
507
508 if (state->common_possible_crtcs != new_state->common_possible_crtcs)
509 return META_KMS_UPDATE_CHANGE_FULL;
510
511 if (state->common_possible_clones != new_state->common_possible_clones)
512 return META_KMS_UPDATE_CHANGE_FULL;
513
514 if (state->encoder_device_idxs != new_state->encoder_device_idxs)
515 return META_KMS_UPDATE_CHANGE_FULL;
516
517 if (state->width_mm != new_state->width_mm)
518 return META_KMS_UPDATE_CHANGE_FULL;
519
520 if (state->height_mm != new_state->height_mm)
521 return META_KMS_UPDATE_CHANGE_FULL;
522
523 if (state->has_scaling != new_state->has_scaling)
524 return META_KMS_UPDATE_CHANGE_FULL;
525
526 if (state->non_desktop != new_state->non_desktop)
527 return META_KMS_UPDATE_CHANGE_FULL;
528
529 if (state->subpixel_order != new_state->subpixel_order)
530 return META_KMS_UPDATE_CHANGE_FULL;
531
532 if (state->suggested_x != new_state->suggested_x)
533 return META_KMS_UPDATE_CHANGE_FULL;
534
535 if (state->suggested_y != new_state->suggested_y)
536 return META_KMS_UPDATE_CHANGE_FULL;
537
538 if (state->hotplug_mode_update != new_state->hotplug_mode_update)
539 return META_KMS_UPDATE_CHANGE_FULL;
540
541 if (state->panel_orientation_transform !=
542 new_state->panel_orientation_transform)
543 return META_KMS_UPDATE_CHANGE_FULL;
544
545 if (!meta_tile_info_equal (&state->tile_info, &new_state->tile_info))
546 return META_KMS_UPDATE_CHANGE_FULL;
547
548 if ((state->edid_data && !new_state->edid_data) || !state->edid_data ||
549 !g_bytes_equal (state->edid_data, new_state->edid_data))
550 return META_KMS_UPDATE_CHANGE_FULL;
551
552 if (!kms_modes_equal (state->modes, new_state->modes))
553 return META_KMS_UPDATE_CHANGE_FULL;
554
555 return META_KMS_UPDATE_CHANGE_NONE;
556 }
557
558 static MetaKmsUpdateChanges
meta_kms_connector_read_state(MetaKmsConnector * connector,MetaKmsImplDevice * impl_device,drmModeConnector * drm_connector,drmModeRes * drm_resources)559 meta_kms_connector_read_state (MetaKmsConnector *connector,
560 MetaKmsImplDevice *impl_device,
561 drmModeConnector *drm_connector,
562 drmModeRes *drm_resources)
563 {
564 g_autoptr (MetaKmsConnectorState) state = NULL;
565 g_autoptr (MetaKmsConnectorState) current_state = NULL;
566 MetaKmsUpdateChanges connector_changes;
567 MetaKmsUpdateChanges changes;
568
569 current_state = g_steal_pointer (&connector->current_state);
570 changes = META_KMS_UPDATE_CHANGE_NONE;
571
572 if (drm_connector->connection != DRM_MODE_CONNECTED)
573 {
574 if (drm_connector->connection != connector->connection)
575 {
576 connector->connection = drm_connector->connection;
577 changes |= META_KMS_UPDATE_CHANGE_FULL;
578 }
579
580 return changes;
581 }
582
583 state = meta_kms_connector_state_new ();
584
585 state_set_blobs (state, connector, impl_device, drm_connector);
586
587 state_set_properties (state, impl_device, drm_connector);
588
589 state->subpixel_order =
590 drm_subpixel_order_to_cogl_subpixel_order (drm_connector->subpixel);
591
592 state_set_physical_dimensions (state, drm_connector);
593
594 state_set_modes (state, impl_device, drm_connector);
595
596 state_set_crtc_state (state, drm_connector, impl_device, drm_resources);
597
598 if (drm_connector->connection != connector->connection)
599 {
600 connector->connection = drm_connector->connection;
601 changes |= META_KMS_UPDATE_CHANGE_FULL;
602 }
603
604 if (!current_state)
605 connector_changes = META_KMS_UPDATE_CHANGE_FULL;
606 else
607 connector_changes = meta_kms_connector_state_changes (current_state, state);
608
609 if (connector_changes == META_KMS_UPDATE_CHANGE_NONE)
610 {
611 connector->current_state = g_steal_pointer (¤t_state);
612 }
613 else
614 {
615 connector->current_state = g_steal_pointer (&state);
616 changes |= connector_changes;
617 }
618
619 if (changes != META_KMS_UPDATE_CHANGE_NONE)
620 sync_fd_held (connector, impl_device);
621
622 return changes;
623 }
624
625 MetaKmsUpdateChanges
meta_kms_connector_update_state(MetaKmsConnector * connector,drmModeRes * drm_resources)626 meta_kms_connector_update_state (MetaKmsConnector *connector,
627 drmModeRes *drm_resources)
628 {
629 MetaKmsImplDevice *impl_device;
630 drmModeConnector *drm_connector;
631 MetaKmsUpdateChanges changes;
632
633 impl_device = meta_kms_device_get_impl_device (connector->device);
634 drm_connector = drmModeGetConnector (meta_kms_impl_device_get_fd (impl_device),
635 connector->id);
636
637 if (!drm_connector)
638 return META_KMS_UPDATE_CHANGE_FULL;
639
640 changes = meta_kms_connector_read_state (connector, impl_device,
641 drm_connector,
642 drm_resources);
643 drmModeFreeConnector (drm_connector);
644
645 return changes;
646 }
647
648 void
meta_kms_connector_predict_state(MetaKmsConnector * connector,MetaKmsUpdate * update)649 meta_kms_connector_predict_state (MetaKmsConnector *connector,
650 MetaKmsUpdate *update)
651 {
652 MetaKmsImplDevice *impl_device;
653 MetaKmsConnectorState *current_state;
654 GList *mode_sets;
655 GList *l;
656 current_state = connector->current_state;
657 if (!current_state)
658 return;
659
660 mode_sets = meta_kms_update_get_mode_sets (update);
661 for (l = mode_sets; l; l = l->next)
662 {
663 MetaKmsModeSet *mode_set = l->data;
664 MetaKmsCrtc *crtc = mode_set->crtc;
665
666 if (current_state->current_crtc_id == meta_kms_crtc_get_id (crtc))
667 {
668 if (g_list_find (mode_set->connectors, connector))
669 break;
670 else
671 current_state->current_crtc_id = 0;
672 }
673 else
674 {
675 if (g_list_find (mode_set->connectors, connector))
676 {
677 current_state->current_crtc_id = meta_kms_crtc_get_id (crtc);
678 break;
679 }
680 }
681 }
682
683 impl_device = meta_kms_device_get_impl_device (connector->device);
684 sync_fd_held (connector, impl_device);
685 }
686
687 static void
init_properties(MetaKmsConnector * connector,MetaKmsImplDevice * impl_device,drmModeConnector * drm_connector)688 init_properties (MetaKmsConnector *connector,
689 MetaKmsImplDevice *impl_device,
690 drmModeConnector *drm_connector)
691 {
692 MetaKmsConnectorPropTable *prop_table = &connector->prop_table;
693
694 *prop_table = (MetaKmsConnectorPropTable) {
695 .props = {
696 [META_KMS_CONNECTOR_PROP_CRTC_ID] =
697 {
698 .name = "CRTC_ID",
699 .type = DRM_MODE_PROP_OBJECT,
700 },
701 [META_KMS_CONNECTOR_PROP_DPMS] =
702 {
703 .name = "DPMS",
704 .type = DRM_MODE_PROP_ENUM,
705 },
706 [META_KMS_CONNECTOR_PROP_UNDERSCAN] =
707 {
708 .name = "underscan",
709 .type = DRM_MODE_PROP_ENUM,
710 },
711 [META_KMS_CONNECTOR_PROP_UNDERSCAN_HBORDER] =
712 {
713 .name = "underscan hborder",
714 .type = DRM_MODE_PROP_RANGE,
715 },
716 [META_KMS_CONNECTOR_PROP_UNDERSCAN_VBORDER] =
717 {
718 .name = "underscan vborder",
719 .type = DRM_MODE_PROP_RANGE,
720 },
721 }
722 };
723
724 meta_kms_impl_device_init_prop_table (impl_device,
725 drm_connector->props,
726 drm_connector->prop_values,
727 drm_connector->count_props,
728 connector->prop_table.props,
729 META_KMS_CONNECTOR_N_PROPS,
730 NULL);
731 }
732
733 static char *
make_connector_name(drmModeConnector * drm_connector)734 make_connector_name (drmModeConnector *drm_connector)
735 {
736 static const char * const connector_type_names[] = {
737 "None",
738 "VGA",
739 "DVI-I",
740 "DVI-D",
741 "DVI-A",
742 "Composite",
743 "SVIDEO",
744 "LVDS",
745 "Component",
746 "DIN",
747 "DP",
748 "HDMI",
749 "HDMI-B",
750 "TV",
751 "eDP",
752 "Virtual",
753 "DSI",
754 };
755
756 if (drm_connector->connector_type < G_N_ELEMENTS (connector_type_names))
757 return g_strdup_printf ("%s-%d",
758 connector_type_names[drm_connector->connector_type],
759 drm_connector->connector_type_id);
760 else
761 return g_strdup_printf ("Unknown%d-%d",
762 drm_connector->connector_type,
763 drm_connector->connector_type_id);
764 }
765
766 gboolean
meta_kms_connector_is_same_as(MetaKmsConnector * connector,drmModeConnector * drm_connector)767 meta_kms_connector_is_same_as (MetaKmsConnector *connector,
768 drmModeConnector *drm_connector)
769 {
770 return (connector->id == drm_connector->connector_id &&
771 connector->type == drm_connector->connector_type &&
772 connector->type_id == drm_connector->connector_type_id);
773 }
774
775 MetaKmsConnector *
meta_kms_connector_new(MetaKmsImplDevice * impl_device,drmModeConnector * drm_connector,drmModeRes * drm_resources)776 meta_kms_connector_new (MetaKmsImplDevice *impl_device,
777 drmModeConnector *drm_connector,
778 drmModeRes *drm_resources)
779 {
780 MetaKmsConnector *connector;
781
782 g_assert (drm_connector);
783 connector = g_object_new (META_TYPE_KMS_CONNECTOR, NULL);
784 connector->device = meta_kms_impl_device_get_device (impl_device);
785 connector->id = drm_connector->connector_id;
786 connector->type = drm_connector->connector_type;
787 connector->type_id = drm_connector->connector_type_id;
788 connector->name = make_connector_name (drm_connector);
789
790 init_properties (connector, impl_device, drm_connector);
791
792 meta_kms_connector_read_state (connector, impl_device,
793 drm_connector,
794 drm_resources);
795
796 return connector;
797 }
798
799 static void
meta_kms_connector_finalize(GObject * object)800 meta_kms_connector_finalize (GObject *object)
801 {
802 MetaKmsConnector *connector = META_KMS_CONNECTOR (object);
803
804 if (connector->fd_held)
805 {
806 MetaKmsImplDevice *impl_device;
807
808 impl_device = meta_kms_device_get_impl_device (connector->device);
809 meta_kms_impl_device_unhold_fd (impl_device);
810 }
811
812 g_clear_pointer (&connector->current_state, meta_kms_connector_state_free);
813 g_free (connector->name);
814
815 G_OBJECT_CLASS (meta_kms_connector_parent_class)->finalize (object);
816 }
817
818 static void
meta_kms_connector_init(MetaKmsConnector * connector)819 meta_kms_connector_init (MetaKmsConnector *connector)
820 {
821 }
822
823 static void
meta_kms_connector_class_init(MetaKmsConnectorClass * klass)824 meta_kms_connector_class_init (MetaKmsConnectorClass *klass)
825 {
826 GObjectClass *object_class = G_OBJECT_CLASS (klass);
827
828 object_class->finalize = meta_kms_connector_finalize;
829 }
830