Coverage Report

Created: 2026-02-14 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gstreamer/subprojects/libdrm-2.4.124/xf86drmMode.c
Line
Count
Source
1
/*
2
 * \file xf86drmMode.c
3
 * Header for DRM modesetting interface.
4
 *
5
 * \author Jakob Bornecrantz <wallbraker@gmail.com>
6
 *
7
 * \par Acknowledgements:
8
 * Feb 2007, Dave Airlie <airlied@linux.ie>
9
 */
10
11
/*
12
 * Copyright (c) 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas.
13
 * Copyright (c) 2007-2008 Dave Airlie <airlied@linux.ie>
14
 * Copyright (c) 2007-2008 Jakob Bornecrantz <wallbraker@gmail.com>
15
 *
16
 * Permission is hereby granted, free of charge, to any person obtaining a
17
 * copy of this software and associated documentation files (the "Software"),
18
 * to deal in the Software without restriction, including without limitation
19
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
20
 * and/or sell copies of the Software, and to permit persons to whom the
21
 * Software is furnished to do so, subject to the following conditions:
22
 *
23
 * The above copyright notice and this permission notice shall be included in
24
 * all copies or substantial portions of the Software.
25
 *
26
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
31
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
32
 * IN THE SOFTWARE.
33
 *
34
 */
35
36
#include <assert.h>
37
#include <limits.h>
38
#include <stdint.h>
39
#include <stdlib.h>
40
#include <sys/ioctl.h>
41
#if HAVE_SYS_SYSCTL_H
42
#ifdef __FreeBSD__
43
#include <sys/types.h>
44
#endif
45
#include <sys/sysctl.h>
46
#endif
47
#include <stdio.h>
48
#include <stdbool.h>
49
50
#include "libdrm_macros.h"
51
#include "xf86drmMode.h"
52
#include "xf86drm.h"
53
#include <drm.h>
54
#include <drm_fourcc.h>
55
#include <string.h>
56
#include <dirent.h>
57
#include <unistd.h>
58
#include <errno.h>
59
60
0
#define memclear(s) memset(&s, 0, sizeof(s))
61
62
0
#define U642VOID(x) ((void *)(unsigned long)(x))
63
0
#define VOID2U64(x) ((uint64_t)(unsigned long)(x))
64
65
static inline int DRM_IOCTL(int fd, unsigned long cmd, void *arg)
66
0
{
67
0
  int ret = drmIoctl(fd, cmd, arg);
68
0
  return ret < 0 ? -errno : ret;
69
0
}
70
71
/*
72
 * Util functions
73
 */
74
75
static void* drmAllocCpy(char *array, int count, int entry_size)
76
0
{
77
0
  char *r;
78
0
  int i;
79
80
0
  if (!count || !array || !entry_size)
81
0
    return 0;
82
83
0
  if (!(r = drmMalloc(count*entry_size)))
84
0
    return 0;
85
86
0
  for (i = 0; i < count; i++)
87
0
    memcpy(r+(entry_size*i), array+(entry_size*i), entry_size);
88
89
0
  return r;
90
0
}
91
92
/*
93
 * A couple of free functions.
94
 */
95
96
drm_public void drmModeFreeModeInfo(drmModeModeInfoPtr ptr)
97
0
{
98
0
  if (!ptr)
99
0
    return;
100
101
0
  drmFree(ptr);
102
0
}
103
104
drm_public void drmModeFreeResources(drmModeResPtr ptr)
105
0
{
106
0
  if (!ptr)
107
0
    return;
108
109
0
  drmFree(ptr->fbs);
110
0
  drmFree(ptr->crtcs);
111
0
  drmFree(ptr->connectors);
112
0
  drmFree(ptr->encoders);
113
0
  drmFree(ptr);
114
0
}
115
116
drm_public void drmModeFreeFB(drmModeFBPtr ptr)
117
0
{
118
0
  if (!ptr)
119
0
    return;
120
121
  /* we might add more frees later. */
122
0
  drmFree(ptr);
123
0
}
124
125
drm_public void drmModeFreeCrtc(drmModeCrtcPtr ptr)
126
0
{
127
0
  if (!ptr)
128
0
    return;
129
130
0
  drmFree(ptr);
131
0
}
132
133
drm_public void drmModeFreeConnector(drmModeConnectorPtr ptr)
134
0
{
135
0
  if (!ptr)
136
0
    return;
137
138
0
  drmFree(ptr->encoders);
139
0
  drmFree(ptr->prop_values);
140
0
  drmFree(ptr->props);
141
0
  drmFree(ptr->modes);
142
0
  drmFree(ptr);
143
0
}
144
145
drm_public void drmModeFreeEncoder(drmModeEncoderPtr ptr)
146
0
{
147
0
  drmFree(ptr);
148
0
}
149
150
/*
151
 * ModeSetting functions.
152
 */
153
154
drm_public int drmIsKMS(int fd)
155
0
{
156
0
  struct drm_mode_card_res res = {0};
157
158
0
  if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res) != 0)
159
0
    return 0;
160
161
0
  return res.count_crtcs > 0 && res.count_connectors > 0 && res.count_encoders > 0;
162
0
}
163
164
drm_public drmModeResPtr drmModeGetResources(int fd)
165
0
{
166
0
  struct drm_mode_card_res res, counts;
167
0
  drmModeResPtr r = 0;
168
169
0
retry:
170
0
  memclear(res);
171
0
  if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
172
0
    return 0;
173
174
0
  counts = res;
175
176
0
  if (res.count_fbs) {
177
0
    res.fb_id_ptr = VOID2U64(drmMalloc(res.count_fbs*sizeof(uint32_t)));
178
0
    if (!res.fb_id_ptr)
179
0
      goto err_allocs;
180
0
  }
181
0
  if (res.count_crtcs) {
182
0
    res.crtc_id_ptr = VOID2U64(drmMalloc(res.count_crtcs*sizeof(uint32_t)));
183
0
    if (!res.crtc_id_ptr)
184
0
      goto err_allocs;
185
0
  }
186
0
  if (res.count_connectors) {
187
0
    res.connector_id_ptr = VOID2U64(drmMalloc(res.count_connectors*sizeof(uint32_t)));
188
0
    if (!res.connector_id_ptr)
189
0
      goto err_allocs;
190
0
  }
191
0
  if (res.count_encoders) {
192
0
    res.encoder_id_ptr = VOID2U64(drmMalloc(res.count_encoders*sizeof(uint32_t)));
193
0
    if (!res.encoder_id_ptr)
194
0
      goto err_allocs;
195
0
  }
196
197
0
  if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
198
0
    goto err_allocs;
199
200
  /* The number of available connectors and etc may have changed with a
201
   * hotplug event in between the ioctls, in which case the field is
202
   * silently ignored by the kernel.
203
   */
204
0
  if (counts.count_fbs < res.count_fbs ||
205
0
      counts.count_crtcs < res.count_crtcs ||
206
0
      counts.count_connectors < res.count_connectors ||
207
0
      counts.count_encoders < res.count_encoders)
208
0
  {
209
0
    drmFree(U642VOID(res.fb_id_ptr));
210
0
    drmFree(U642VOID(res.crtc_id_ptr));
211
0
    drmFree(U642VOID(res.connector_id_ptr));
212
0
    drmFree(U642VOID(res.encoder_id_ptr));
213
214
0
    goto retry;
215
0
  }
216
217
  /*
218
   * return
219
   */
220
0
  if (!(r = drmMalloc(sizeof(*r))))
221
0
    goto err_allocs;
222
223
0
  r->min_width     = res.min_width;
224
0
  r->max_width     = res.max_width;
225
0
  r->min_height    = res.min_height;
226
0
  r->max_height    = res.max_height;
227
0
  r->count_fbs     = res.count_fbs;
228
0
  r->count_crtcs   = res.count_crtcs;
229
0
  r->count_connectors = res.count_connectors;
230
0
  r->count_encoders = res.count_encoders;
231
232
0
  r->fbs        = drmAllocCpy(U642VOID(res.fb_id_ptr), res.count_fbs, sizeof(uint32_t));
233
0
  r->crtcs      = drmAllocCpy(U642VOID(res.crtc_id_ptr), res.count_crtcs, sizeof(uint32_t));
234
0
  r->connectors = drmAllocCpy(U642VOID(res.connector_id_ptr), res.count_connectors, sizeof(uint32_t));
235
0
  r->encoders   = drmAllocCpy(U642VOID(res.encoder_id_ptr), res.count_encoders, sizeof(uint32_t));
236
0
  if ((res.count_fbs && !r->fbs) ||
237
0
      (res.count_crtcs && !r->crtcs) ||
238
0
      (res.count_connectors && !r->connectors) ||
239
0
      (res.count_encoders && !r->encoders))
240
0
  {
241
0
    drmFree(r->fbs);
242
0
    drmFree(r->crtcs);
243
0
    drmFree(r->connectors);
244
0
    drmFree(r->encoders);
245
0
    drmFree(r);
246
0
    r = 0;
247
0
  }
248
249
0
err_allocs:
250
0
  drmFree(U642VOID(res.fb_id_ptr));
251
0
  drmFree(U642VOID(res.crtc_id_ptr));
252
0
  drmFree(U642VOID(res.connector_id_ptr));
253
0
  drmFree(U642VOID(res.encoder_id_ptr));
254
255
0
  return r;
256
0
}
257
258
259
drm_public int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth,
260
                            uint8_t bpp, uint32_t pitch, uint32_t bo_handle,
261
                            uint32_t *buf_id)
262
0
{
263
0
  struct drm_mode_fb_cmd f;
264
0
  int ret;
265
266
0
  memclear(f);
267
0
  f.width  = width;
268
0
  f.height = height;
269
0
  f.pitch  = pitch;
270
0
  f.bpp    = bpp;
271
0
  f.depth  = depth;
272
0
  f.handle = bo_handle;
273
274
0
  if ((ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_ADDFB, &f)))
275
0
    return ret;
276
277
0
  *buf_id = f.fb_id;
278
0
  return 0;
279
0
}
280
281
drm_public int drmModeAddFB2WithModifiers(int fd, uint32_t width,
282
    uint32_t height, uint32_t pixel_format, const uint32_t bo_handles[4],
283
    const uint32_t pitches[4], const uint32_t offsets[4],
284
    const uint64_t modifier[4], uint32_t *buf_id, uint32_t flags)
285
0
{
286
0
  struct drm_mode_fb_cmd2 f;
287
0
  int ret;
288
289
0
  memclear(f);
290
0
  f.width  = width;
291
0
  f.height = height;
292
0
  f.pixel_format = pixel_format;
293
0
  f.flags = flags;
294
0
  memcpy(f.handles, bo_handles, 4 * sizeof(bo_handles[0]));
295
0
  memcpy(f.pitches, pitches, 4 * sizeof(pitches[0]));
296
0
  memcpy(f.offsets, offsets, 4 * sizeof(offsets[0]));
297
0
  if (modifier)
298
0
    memcpy(f.modifier, modifier, 4 * sizeof(modifier[0]));
299
300
0
  if ((ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_ADDFB2, &f)))
301
0
    return ret;
302
303
0
  *buf_id = f.fb_id;
304
0
  return 0;
305
0
}
306
307
drm_public int drmModeAddFB2(int fd, uint32_t width, uint32_t height,
308
    uint32_t pixel_format, const uint32_t bo_handles[4],
309
    const uint32_t pitches[4], const uint32_t offsets[4],
310
    uint32_t *buf_id, uint32_t flags)
311
0
{
312
0
  return drmModeAddFB2WithModifiers(fd, width, height,
313
0
            pixel_format, bo_handles,
314
0
            pitches, offsets, NULL,
315
0
            buf_id, flags);
316
0
}
317
318
drm_public int drmModeRmFB(int fd, uint32_t bufferId)
319
0
{
320
0
  return DRM_IOCTL(fd, DRM_IOCTL_MODE_RMFB, &bufferId);
321
0
}
322
323
drm_public int drmModeCloseFB(int fd, uint32_t buffer_id)
324
0
{
325
0
  struct drm_mode_closefb closefb;
326
327
0
  memclear(closefb);
328
0
  closefb.fb_id = buffer_id;
329
330
0
  return DRM_IOCTL(fd, DRM_IOCTL_MODE_CLOSEFB, &closefb);
331
0
}
332
333
drm_public drmModeFBPtr drmModeGetFB(int fd, uint32_t buf)
334
0
{
335
0
  struct drm_mode_fb_cmd info;
336
0
  drmModeFBPtr r;
337
338
0
  memclear(info);
339
0
  info.fb_id = buf;
340
341
0
  if (drmIoctl(fd, DRM_IOCTL_MODE_GETFB, &info))
342
0
    return NULL;
343
344
0
  if (!(r = drmMalloc(sizeof(*r))))
345
0
    return NULL;
346
347
0
  r->fb_id = info.fb_id;
348
0
  r->width = info.width;
349
0
  r->height = info.height;
350
0
  r->pitch = info.pitch;
351
0
  r->bpp = info.bpp;
352
0
  r->handle = info.handle;
353
0
  r->depth = info.depth;
354
355
0
  return r;
356
0
}
357
358
drm_public int drmModeDirtyFB(int fd, uint32_t bufferId,
359
       drmModeClipPtr clips, uint32_t num_clips)
360
0
{
361
0
  struct drm_mode_fb_dirty_cmd dirty;
362
363
0
  memclear(dirty);
364
0
  dirty.fb_id = bufferId;
365
0
  dirty.clips_ptr = VOID2U64(clips);
366
0
  dirty.num_clips = num_clips;
367
368
0
  return DRM_IOCTL(fd, DRM_IOCTL_MODE_DIRTYFB, &dirty);
369
0
}
370
371
/*
372
 * Crtc functions
373
 */
374
375
drm_public drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId)
376
0
{
377
0
  struct drm_mode_crtc crtc;
378
0
  drmModeCrtcPtr r;
379
380
0
  memclear(crtc);
381
0
  crtc.crtc_id = crtcId;
382
383
0
  if (drmIoctl(fd, DRM_IOCTL_MODE_GETCRTC, &crtc))
384
0
    return 0;
385
386
  /*
387
   * return
388
   */
389
390
0
  if (!(r = drmMalloc(sizeof(*r))))
391
0
    return 0;
392
393
0
  r->crtc_id         = crtc.crtc_id;
394
0
  r->x               = crtc.x;
395
0
  r->y               = crtc.y;
396
0
  r->mode_valid      = crtc.mode_valid;
397
0
  if (r->mode_valid) {
398
0
    memcpy(&r->mode, &crtc.mode, sizeof(struct drm_mode_modeinfo));
399
0
    r->width = crtc.mode.hdisplay;
400
0
    r->height = crtc.mode.vdisplay;
401
0
  }
402
0
  r->buffer_id       = crtc.fb_id;
403
0
  r->gamma_size      = crtc.gamma_size;
404
0
  return r;
405
0
}
406
407
drm_public int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,
408
       uint32_t x, uint32_t y, uint32_t *connectors, int count,
409
       drmModeModeInfoPtr mode)
410
0
{
411
0
  struct drm_mode_crtc crtc;
412
413
0
  memclear(crtc);
414
0
  crtc.x             = x;
415
0
  crtc.y             = y;
416
0
  crtc.crtc_id       = crtcId;
417
0
  crtc.fb_id         = bufferId;
418
0
  crtc.set_connectors_ptr = VOID2U64(connectors);
419
0
  crtc.count_connectors = count;
420
0
  if (mode) {
421
0
    memcpy(&crtc.mode, mode, sizeof(struct drm_mode_modeinfo));
422
0
    crtc.mode_valid = 1;
423
0
  }
424
425
0
  return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETCRTC, &crtc);
426
0
}
427
428
/*
429
 * Cursor manipulation
430
 */
431
432
drm_public int drmModeSetCursor(int fd, uint32_t crtcId, uint32_t bo_handle,
433
                uint32_t width, uint32_t height)
434
0
{
435
0
  struct drm_mode_cursor arg;
436
437
0
  memclear(arg);
438
0
  arg.flags = DRM_MODE_CURSOR_BO;
439
0
  arg.crtc_id = crtcId;
440
0
  arg.width = width;
441
0
  arg.height = height;
442
0
  arg.handle = bo_handle;
443
444
0
  return DRM_IOCTL(fd, DRM_IOCTL_MODE_CURSOR, &arg);
445
0
}
446
447
drm_public int drmModeSetCursor2(int fd, uint32_t crtcId, uint32_t bo_handle,
448
                 uint32_t width, uint32_t height, int32_t hot_x,
449
                 int32_t hot_y)
450
0
{
451
0
  struct drm_mode_cursor2 arg;
452
453
0
  memclear(arg);
454
0
  arg.flags = DRM_MODE_CURSOR_BO;
455
0
  arg.crtc_id = crtcId;
456
0
  arg.width = width;
457
0
  arg.height = height;
458
0
  arg.handle = bo_handle;
459
0
  arg.hot_x = hot_x;
460
0
  arg.hot_y = hot_y;
461
462
0
  return DRM_IOCTL(fd, DRM_IOCTL_MODE_CURSOR2, &arg);
463
0
}
464
465
drm_public int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y)
466
0
{
467
0
  struct drm_mode_cursor arg;
468
469
0
  memclear(arg);
470
0
  arg.flags = DRM_MODE_CURSOR_MOVE;
471
0
  arg.crtc_id = crtcId;
472
0
  arg.x = x;
473
0
  arg.y = y;
474
475
0
  return DRM_IOCTL(fd, DRM_IOCTL_MODE_CURSOR, &arg);
476
0
}
477
478
/*
479
 * Encoder get
480
 */
481
drm_public drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id)
482
0
{
483
0
  struct drm_mode_get_encoder enc;
484
0
  drmModeEncoderPtr r = NULL;
485
486
0
  memclear(enc);
487
0
  enc.encoder_id = encoder_id;
488
489
0
  if (drmIoctl(fd, DRM_IOCTL_MODE_GETENCODER, &enc))
490
0
    return 0;
491
492
0
  if (!(r = drmMalloc(sizeof(*r))))
493
0
    return 0;
494
495
0
  r->encoder_id = enc.encoder_id;
496
0
  r->crtc_id = enc.crtc_id;
497
0
  r->encoder_type = enc.encoder_type;
498
0
  r->possible_crtcs = enc.possible_crtcs;
499
0
  r->possible_clones = enc.possible_clones;
500
501
0
  return r;
502
0
}
503
504
/*
505
 * Connector manipulation
506
 */
507
static drmModeConnectorPtr
508
_drmModeGetConnector(int fd, uint32_t connector_id, int probe)
509
0
{
510
0
  struct drm_mode_get_connector conn, counts;
511
0
  drmModeConnectorPtr r = NULL;
512
0
  struct drm_mode_modeinfo stack_mode;
513
514
0
  memclear(conn);
515
0
  conn.connector_id = connector_id;
516
0
  if (!probe) {
517
0
    conn.count_modes = 1;
518
0
    conn.modes_ptr = VOID2U64(&stack_mode);
519
0
  }
520
521
0
  if (drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
522
0
    return 0;
523
524
0
retry:
525
0
  counts = conn;
526
527
0
  if (conn.count_props) {
528
0
    conn.props_ptr = VOID2U64(drmMalloc(conn.count_props*sizeof(uint32_t)));
529
0
    if (!conn.props_ptr)
530
0
      goto err_allocs;
531
0
    conn.prop_values_ptr = VOID2U64(drmMalloc(conn.count_props*sizeof(uint64_t)));
532
0
    if (!conn.prop_values_ptr)
533
0
      goto err_allocs;
534
0
  }
535
536
0
  if (conn.count_modes) {
537
0
    conn.modes_ptr = VOID2U64(drmMalloc(conn.count_modes*sizeof(struct drm_mode_modeinfo)));
538
0
    if (!conn.modes_ptr)
539
0
      goto err_allocs;
540
0
  } else {
541
0
    conn.count_modes = 1;
542
0
    conn.modes_ptr = VOID2U64(&stack_mode);
543
0
  }
544
545
0
  if (conn.count_encoders) {
546
0
    conn.encoders_ptr = VOID2U64(drmMalloc(conn.count_encoders*sizeof(uint32_t)));
547
0
    if (!conn.encoders_ptr)
548
0
      goto err_allocs;
549
0
  }
550
551
0
  if (drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
552
0
    goto err_allocs;
553
554
  /* The number of available connectors and etc may have changed with a
555
   * hotplug event in between the ioctls, in which case the field is
556
   * silently ignored by the kernel.
557
   */
558
0
  if (counts.count_props < conn.count_props ||
559
0
      counts.count_modes < conn.count_modes ||
560
0
      counts.count_encoders < conn.count_encoders) {
561
0
    drmFree(U642VOID(conn.props_ptr));
562
0
    drmFree(U642VOID(conn.prop_values_ptr));
563
0
    if (U642VOID(conn.modes_ptr) != &stack_mode)
564
0
      drmFree(U642VOID(conn.modes_ptr));
565
0
    drmFree(U642VOID(conn.encoders_ptr));
566
567
0
    goto retry;
568
0
  }
569
570
0
  if(!(r = drmMalloc(sizeof(*r)))) {
571
0
    goto err_allocs;
572
0
  }
573
574
0
  r->connector_id = conn.connector_id;
575
0
  r->encoder_id = conn.encoder_id;
576
0
  r->connection   = conn.connection;
577
0
  r->mmWidth      = conn.mm_width;
578
0
  r->mmHeight     = conn.mm_height;
579
  /* convert subpixel from kernel to userspace */
580
0
  r->subpixel     = conn.subpixel + 1;
581
0
  r->count_modes  = conn.count_modes;
582
0
  r->count_props  = conn.count_props;
583
0
  r->props        = drmAllocCpy(U642VOID(conn.props_ptr), conn.count_props, sizeof(uint32_t));
584
0
  r->prop_values  = drmAllocCpy(U642VOID(conn.prop_values_ptr), conn.count_props, sizeof(uint64_t));
585
0
  r->modes        = drmAllocCpy(U642VOID(conn.modes_ptr), conn.count_modes, sizeof(struct drm_mode_modeinfo));
586
0
  r->count_encoders = conn.count_encoders;
587
0
  r->encoders     = drmAllocCpy(U642VOID(conn.encoders_ptr), conn.count_encoders, sizeof(uint32_t));
588
0
  r->connector_type  = conn.connector_type;
589
0
  r->connector_type_id = conn.connector_type_id;
590
591
0
  if ((r->count_props && !r->props) ||
592
0
      (r->count_props && !r->prop_values) ||
593
0
      (r->count_modes && !r->modes) ||
594
0
      (r->count_encoders && !r->encoders)) {
595
0
    drmFree(r->props);
596
0
    drmFree(r->prop_values);
597
0
    drmFree(r->modes);
598
0
    drmFree(r->encoders);
599
0
    drmFree(r);
600
0
    r = 0;
601
0
  }
602
603
0
err_allocs:
604
0
  drmFree(U642VOID(conn.prop_values_ptr));
605
0
  drmFree(U642VOID(conn.props_ptr));
606
0
  if (U642VOID(conn.modes_ptr) != &stack_mode)
607
0
    drmFree(U642VOID(conn.modes_ptr));
608
0
  drmFree(U642VOID(conn.encoders_ptr));
609
610
0
  return r;
611
0
}
612
613
drm_public drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id)
614
0
{
615
0
  return _drmModeGetConnector(fd, connector_id, 1);
616
0
}
617
618
drm_public drmModeConnectorPtr drmModeGetConnectorCurrent(int fd, uint32_t connector_id)
619
0
{
620
0
  return _drmModeGetConnector(fd, connector_id, 0);
621
0
}
622
623
drm_public uint32_t drmModeConnectorGetPossibleCrtcs(int fd,
624
                                                     const drmModeConnector *connector)
625
0
{
626
0
  drmModeEncoder *encoder;
627
0
  int i;
628
0
  uint32_t possible_crtcs;
629
630
0
  possible_crtcs = 0;
631
0
  for (i = 0; i < connector->count_encoders; i++) {
632
0
    encoder = drmModeGetEncoder(fd, connector->encoders[i]);
633
0
    if (!encoder) {
634
0
      return 0;
635
0
    }
636
637
0
    possible_crtcs |= encoder->possible_crtcs;
638
0
    drmModeFreeEncoder(encoder);
639
0
  }
640
641
0
  if (possible_crtcs == 0)
642
0
    errno = ENOENT;
643
0
  return possible_crtcs;
644
0
}
645
646
drm_public int drmModeAttachMode(int fd, uint32_t connector_id, drmModeModeInfoPtr mode_info)
647
0
{
648
0
  struct drm_mode_mode_cmd res;
649
650
0
  memclear(res);
651
0
  memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo));
652
0
  res.connector_id = connector_id;
653
654
0
  return DRM_IOCTL(fd, DRM_IOCTL_MODE_ATTACHMODE, &res);
655
0
}
656
657
drm_public int drmModeDetachMode(int fd, uint32_t connector_id, drmModeModeInfoPtr mode_info)
658
0
{
659
0
  struct drm_mode_mode_cmd res;
660
661
0
  memclear(res);
662
0
  memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo));
663
0
  res.connector_id = connector_id;
664
665
0
  return DRM_IOCTL(fd, DRM_IOCTL_MODE_DETACHMODE, &res);
666
0
}
667
668
drm_public drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id)
669
0
{
670
0
  struct drm_mode_get_property prop;
671
0
  drmModePropertyPtr r;
672
673
0
  memclear(prop);
674
0
  prop.prop_id = property_id;
675
676
0
  if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop))
677
0
    return 0;
678
679
0
  if (prop.count_values)
680
0
    prop.values_ptr = VOID2U64(drmMalloc(prop.count_values * sizeof(uint64_t)));
681
682
0
  if (prop.count_enum_blobs && (prop.flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)))
683
0
    prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(struct drm_mode_property_enum)));
684
685
0
  if (prop.count_enum_blobs && (prop.flags & DRM_MODE_PROP_BLOB)) {
686
0
    prop.values_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t)));
687
0
    prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t)));
688
0
  }
689
690
0
  if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop)) {
691
0
    r = NULL;
692
0
    goto err_allocs;
693
0
  }
694
695
0
  if (!(r = drmMalloc(sizeof(*r))))
696
0
    goto err_allocs;
697
698
0
  r->prop_id = prop.prop_id;
699
0
  r->count_values = prop.count_values;
700
701
0
  r->flags = prop.flags;
702
0
  if (prop.count_values)
703
0
    r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_values, sizeof(uint64_t));
704
0
  if (prop.flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) {
705
0
    r->count_enums = prop.count_enum_blobs;
706
0
    r->enums = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(struct drm_mode_property_enum));
707
0
  } else if (prop.flags & DRM_MODE_PROP_BLOB) {
708
0
    r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_enum_blobs, sizeof(uint32_t));
709
0
    r->blob_ids = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(uint32_t));
710
0
    r->count_blobs = prop.count_enum_blobs;
711
0
  }
712
0
  strncpy(r->name, prop.name, DRM_PROP_NAME_LEN);
713
0
  r->name[DRM_PROP_NAME_LEN-1] = 0;
714
715
0
err_allocs:
716
0
  drmFree(U642VOID(prop.values_ptr));
717
0
  drmFree(U642VOID(prop.enum_blob_ptr));
718
719
0
  return r;
720
0
}
721
722
drm_public void drmModeFreeProperty(drmModePropertyPtr ptr)
723
0
{
724
0
  if (!ptr)
725
0
    return;
726
727
0
  drmFree(ptr->values);
728
0
  drmFree(ptr->enums);
729
0
  drmFree(ptr->blob_ids);
730
0
  drmFree(ptr);
731
0
}
732
733
drm_public drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd,
734
                             uint32_t blob_id)
735
0
{
736
0
  struct drm_mode_get_blob blob;
737
0
  drmModePropertyBlobPtr r;
738
739
0
  memclear(blob);
740
0
  blob.blob_id = blob_id;
741
742
0
  if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
743
0
    return NULL;
744
745
0
  if (blob.length)
746
0
    blob.data = VOID2U64(drmMalloc(blob.length));
747
748
0
  if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) {
749
0
    r = NULL;
750
0
    goto err_allocs;
751
0
  }
752
753
0
  if (!(r = drmMalloc(sizeof(*r))))
754
0
    goto err_allocs;
755
756
0
  r->id = blob.blob_id;
757
0
  r->length = blob.length;
758
0
  r->data = drmAllocCpy(U642VOID(blob.data), 1, blob.length);
759
760
0
err_allocs:
761
0
  drmFree(U642VOID(blob.data));
762
0
  return r;
763
0
}
764
765
static inline const uint32_t *
766
get_formats_ptr(const struct drm_format_modifier_blob *blob)
767
0
{
768
0
  return (const uint32_t *)(((uint8_t *)blob) + blob->formats_offset);
769
0
}
770
771
static inline const struct drm_format_modifier *
772
get_modifiers_ptr(const struct drm_format_modifier_blob *blob)
773
0
{
774
0
  return (const struct drm_format_modifier *)(((uint8_t *)blob) +
775
0
                blob->modifiers_offset);
776
0
}
777
778
static bool _drmModeFormatModifierGetNext(const drmModePropertyBlobRes *blob,
779
            drmModeFormatModifierIterator *iter)
780
0
{
781
0
  const struct drm_format_modifier *blob_modifiers, *mod;
782
0
  const struct drm_format_modifier_blob *fmt_mod_blob;
783
0
  const uint32_t *blob_formats;
784
785
0
  assert(blob && iter);
786
787
0
  fmt_mod_blob = blob->data;
788
0
  blob_modifiers = get_modifiers_ptr(fmt_mod_blob);
789
0
  blob_formats = get_formats_ptr(fmt_mod_blob);
790
791
  /* fmt_idx and mod_idx designate the number of processed formats
792
   * and modifiers.
793
   */
794
0
  if (iter->fmt_idx >= fmt_mod_blob->count_formats ||
795
0
      iter->mod_idx >= fmt_mod_blob->count_modifiers)
796
0
    return false;
797
798
0
  iter->fmt = blob_formats[iter->fmt_idx];
799
0
  iter->mod = DRM_FORMAT_MOD_INVALID;
800
801
  /* From the latest valid found, get the next valid modifier */
802
0
  while (iter->mod_idx < fmt_mod_blob->count_modifiers) {
803
0
    mod = &blob_modifiers[iter->mod_idx++];
804
805
    /* Check if the format that fmt_idx designates, belongs to
806
     * this modifier 64-bit window selected via mod->offset.
807
     */
808
0
    if (iter->fmt_idx < mod->offset ||
809
0
        iter->fmt_idx >= mod->offset + 64)
810
0
      continue;
811
0
    if (!(mod->formats & (1 << (iter->fmt_idx - mod->offset))))
812
0
      continue;
813
814
0
    iter->mod = mod->modifier;
815
0
    break;
816
0
  }
817
818
0
  if (iter->mod_idx == fmt_mod_blob->count_modifiers) {
819
0
    iter->mod_idx = 0;
820
0
    iter->fmt_idx++;
821
0
  }
822
823
  /* Since mod_idx reset, in order for the caller to iterate over
824
   * the last modifier of the last format, always return true here
825
   * and early return from the next call.
826
   */
827
0
  return true;
828
0
}
829
830
/**
831
 * Iterate over formats first and then over modifiers. On each call, iter->fmt
832
 * is retained until all associated modifiers are returned. Then, either update
833
 * iter->fmt with the next format, or exit if there aren't any left.
834
 *
835
 * NOTE: clients should not make any assumption on mod_idx and fmt_idx values
836
 *
837
 * @blob: valid kernel blob holding formats and modifiers
838
 * @iter: input and output iterator data. Iter data must be initialised to zero
839
 * @return: false, on error or there aren't any further formats or modifiers left.
840
 *          true, on success and there are more formats or modifiers.
841
 */
842
drm_public bool drmModeFormatModifierBlobIterNext(const drmModePropertyBlobRes *blob,
843
              drmModeFormatModifierIterator *iter)
844
0
{
845
0
  drmModeFormatModifierIterator tmp;
846
0
  bool has_fmt;
847
848
0
  if (!blob || !iter)
849
0
    return false;
850
851
0
  tmp.fmt_idx = iter->fmt_idx;
852
0
  tmp.mod_idx = iter->mod_idx;
853
854
  /* With the current state of things, DRM/KMS drivers are allowed to
855
   * construct blobs having formats and no modifiers. Userspace can't
856
   * legitimately abort in such cases.
857
   *
858
   * While waiting for the kernel to perhaps disallow formats with no
859
   * modifiers in IN_FORMATS blobs, skip the format altogether.
860
   */
861
0
  do {
862
0
    has_fmt = _drmModeFormatModifierGetNext(blob, &tmp);
863
0
    if (has_fmt && tmp.mod != DRM_FORMAT_MOD_INVALID)
864
0
      *iter = tmp;
865
866
0
  } while (has_fmt && tmp.mod == DRM_FORMAT_MOD_INVALID);
867
868
0
  return has_fmt;
869
0
}
870
871
drm_public void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr)
872
0
{
873
0
  if (!ptr)
874
0
    return;
875
876
0
  drmFree(ptr->data);
877
0
  drmFree(ptr);
878
0
}
879
880
drm_public int drmModeConnectorSetProperty(int fd, uint32_t connector_id,
881
                       uint32_t property_id,
882
                       uint64_t value)
883
0
{
884
0
  struct drm_mode_connector_set_property osp;
885
886
0
  memclear(osp);
887
0
  osp.connector_id = connector_id;
888
0
  osp.prop_id = property_id;
889
0
  osp.value = value;
890
891
0
  return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETPROPERTY, &osp);
892
0
}
893
894
/*
895
 * checks if a modesetting capable driver has attached to the pci id
896
 * returns 0 if modesetting supported.
897
 *  -EINVAL or invalid bus id
898
 *  -ENOSYS if no modesetting support
899
*/
900
drm_public int drmCheckModesettingSupported(const char *busid)
901
0
{
902
0
#if defined (__linux__)
903
0
  char pci_dev_dir[1024];
904
0
  int domain, bus, dev, func;
905
0
  DIR *sysdir;
906
0
  struct dirent *dent;
907
0
  int found = 0, ret;
908
909
0
  ret = sscanf(busid, "pci:%04x:%02x:%02x.%d", &domain, &bus, &dev, &func);
910
0
  if (ret != 4)
911
0
    return -EINVAL;
912
913
0
  sprintf(pci_dev_dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/drm",
914
0
    domain, bus, dev, func);
915
916
0
  sysdir = opendir(pci_dev_dir);
917
0
  if (sysdir) {
918
0
    dent = readdir(sysdir);
919
0
    while (dent) {
920
0
      if (!strncmp(dent->d_name, "controlD", 8)) {
921
0
        found = 1;
922
0
        break;
923
0
      }
924
925
0
      dent = readdir(sysdir);
926
0
    }
927
0
    closedir(sysdir);
928
0
    if (found)
929
0
      return 0;
930
0
  }
931
932
0
  sprintf(pci_dev_dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/",
933
0
    domain, bus, dev, func);
934
935
0
  sysdir = opendir(pci_dev_dir);
936
0
  if (!sysdir)
937
0
    return -EINVAL;
938
939
0
  dent = readdir(sysdir);
940
0
  while (dent) {
941
0
    if (!strncmp(dent->d_name, "drm:controlD", 12)) {
942
0
      found = 1;
943
0
      break;
944
0
    }
945
946
0
    dent = readdir(sysdir);
947
0
  }
948
949
0
  closedir(sysdir);
950
0
  if (found)
951
0
    return 0;
952
#elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
953
  char sbusid[1024];
954
  char oid[128];
955
  int i, modesetting, ret;
956
  size_t len;
957
958
  /* How many GPUs do we expect in the machine ? */
959
  for (i = 0; i < 10; i++) {
960
    snprintf(oid, sizeof(oid), "hw.dri.%d.busid", i);
961
    len = sizeof(sbusid);
962
    ret = sysctlbyname(oid, sbusid, &len, NULL, 0);
963
    if (ret == -1) {
964
      if (errno == ENOENT)
965
        continue;
966
      return -EINVAL;
967
    }
968
    if (strcmp(sbusid, busid) != 0)
969
      continue;
970
    snprintf(oid, sizeof(oid), "hw.dri.%d.modesetting", i);
971
    len = sizeof(modesetting);
972
    ret = sysctlbyname(oid, &modesetting, &len, NULL, 0);
973
    if (ret == -1 || len != sizeof(modesetting))
974
      return -EINVAL;
975
    return (modesetting ? 0 : -ENOSYS);
976
  }
977
#elif defined(__DragonFly__)
978
  return 0;
979
#elif defined(__OpenBSD__)
980
  int fd;
981
  struct drm_mode_card_res res;
982
  drmModeResPtr r = 0;
983
984
  if ((fd = drmOpen(NULL, busid)) < 0)
985
    return -EINVAL;
986
987
  memset(&res, 0, sizeof(struct drm_mode_card_res));
988
989
  if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) {
990
    drmClose(fd);
991
    return -errno;
992
  }
993
994
  drmClose(fd);
995
  return 0;
996
#endif
997
0
  return -ENOSYS;
998
0
}
999
1000
drm_public int drmModeCrtcGetGamma(int fd, uint32_t crtc_id, uint32_t size,
1001
                   uint16_t *red, uint16_t *green,
1002
                   uint16_t *blue)
1003
0
{
1004
0
  struct drm_mode_crtc_lut l;
1005
1006
0
  memclear(l);
1007
0
  l.crtc_id = crtc_id;
1008
0
  l.gamma_size = size;
1009
0
  l.red = VOID2U64(red);
1010
0
  l.green = VOID2U64(green);
1011
0
  l.blue = VOID2U64(blue);
1012
1013
0
  return DRM_IOCTL(fd, DRM_IOCTL_MODE_GETGAMMA, &l);
1014
0
}
1015
1016
drm_public int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size,
1017
                   const uint16_t *red, const uint16_t *green,
1018
                   const uint16_t *blue)
1019
0
{
1020
0
  struct drm_mode_crtc_lut l;
1021
1022
0
  memclear(l);
1023
0
  l.crtc_id = crtc_id;
1024
0
  l.gamma_size = size;
1025
0
  l.red = VOID2U64(red);
1026
0
  l.green = VOID2U64(green);
1027
0
  l.blue = VOID2U64(blue);
1028
1029
0
  return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETGAMMA, &l);
1030
0
}
1031
1032
drm_public int drmHandleEvent(int fd, drmEventContextPtr evctx)
1033
0
{
1034
0
  char buffer[1024];
1035
0
  int len, i;
1036
0
  struct drm_event *e;
1037
0
  struct drm_event_vblank *vblank;
1038
0
  struct drm_event_crtc_sequence *seq;
1039
0
  void *user_data;
1040
1041
  /* The DRM read semantics guarantees that we always get only
1042
   * complete events. */
1043
1044
0
  len = read(fd, buffer, sizeof buffer);
1045
0
  if (len == 0)
1046
0
    return 0;
1047
0
  if (len < (int)sizeof *e)
1048
0
    return -1;
1049
1050
0
  i = 0;
1051
0
  while (i < len) {
1052
0
    e = (struct drm_event *)(buffer + i);
1053
0
    switch (e->type) {
1054
0
    case DRM_EVENT_VBLANK:
1055
0
      if (evctx->version < 1 ||
1056
0
          evctx->vblank_handler == NULL)
1057
0
        break;
1058
0
      vblank = (struct drm_event_vblank *) e;
1059
0
      evctx->vblank_handler(fd,
1060
0
                vblank->sequence,
1061
0
                vblank->tv_sec,
1062
0
                vblank->tv_usec,
1063
0
                U642VOID (vblank->user_data));
1064
0
      break;
1065
0
    case DRM_EVENT_FLIP_COMPLETE:
1066
0
      vblank = (struct drm_event_vblank *) e;
1067
0
      user_data = U642VOID (vblank->user_data);
1068
1069
0
      if (evctx->version >= 3 && evctx->page_flip_handler2)
1070
0
        evctx->page_flip_handler2(fd,
1071
0
               vblank->sequence,
1072
0
               vblank->tv_sec,
1073
0
               vblank->tv_usec,
1074
0
               vblank->crtc_id,
1075
0
               user_data);
1076
0
      else if (evctx->version >= 2 && evctx->page_flip_handler)
1077
0
        evctx->page_flip_handler(fd,
1078
0
               vblank->sequence,
1079
0
               vblank->tv_sec,
1080
0
               vblank->tv_usec,
1081
0
               user_data);
1082
0
      break;
1083
0
    case DRM_EVENT_CRTC_SEQUENCE:
1084
0
      seq = (struct drm_event_crtc_sequence *) e;
1085
0
      if (evctx->version >= 4 && evctx->sequence_handler)
1086
0
        evctx->sequence_handler(fd,
1087
0
              seq->sequence,
1088
0
              seq->time_ns,
1089
0
              seq->user_data);
1090
0
      break;
1091
0
    default:
1092
0
      break;
1093
0
    }
1094
0
    i += e->length;
1095
0
  }
1096
1097
0
  return 0;
1098
0
}
1099
1100
drm_public int drmModePageFlip(int fd, uint32_t crtc_id, uint32_t fb_id,
1101
        uint32_t flags, void *user_data)
1102
0
{
1103
0
  struct drm_mode_crtc_page_flip flip;
1104
1105
0
  memclear(flip);
1106
0
  flip.fb_id = fb_id;
1107
0
  flip.crtc_id = crtc_id;
1108
0
  flip.user_data = VOID2U64(user_data);
1109
0
  flip.flags = flags;
1110
1111
0
  return DRM_IOCTL(fd, DRM_IOCTL_MODE_PAGE_FLIP, &flip);
1112
0
}
1113
1114
drm_public int drmModePageFlipTarget(int fd, uint32_t crtc_id, uint32_t fb_id,
1115
        uint32_t flags, void *user_data,
1116
        uint32_t target_vblank)
1117
0
{
1118
0
  struct drm_mode_crtc_page_flip_target flip_target;
1119
1120
0
  memclear(flip_target);
1121
0
  flip_target.fb_id = fb_id;
1122
0
  flip_target.crtc_id = crtc_id;
1123
0
  flip_target.user_data = VOID2U64(user_data);
1124
0
  flip_target.flags = flags;
1125
0
  flip_target.sequence = target_vblank;
1126
1127
0
  return DRM_IOCTL(fd, DRM_IOCTL_MODE_PAGE_FLIP, &flip_target);
1128
0
}
1129
1130
drm_public int drmModeSetPlane(int fd, uint32_t plane_id, uint32_t crtc_id,
1131
        uint32_t fb_id, uint32_t flags,
1132
        int32_t crtc_x, int32_t crtc_y,
1133
        uint32_t crtc_w, uint32_t crtc_h,
1134
        uint32_t src_x, uint32_t src_y,
1135
        uint32_t src_w, uint32_t src_h)
1136
0
{
1137
0
  struct drm_mode_set_plane s;
1138
1139
0
  memclear(s);
1140
0
  s.plane_id = plane_id;
1141
0
  s.crtc_id = crtc_id;
1142
0
  s.fb_id = fb_id;
1143
0
  s.flags = flags;
1144
0
  s.crtc_x = crtc_x;
1145
0
  s.crtc_y = crtc_y;
1146
0
  s.crtc_w = crtc_w;
1147
0
  s.crtc_h = crtc_h;
1148
0
  s.src_x = src_x;
1149
0
  s.src_y = src_y;
1150
0
  s.src_w = src_w;
1151
0
  s.src_h = src_h;
1152
1153
0
  return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETPLANE, &s);
1154
0
}
1155
1156
drm_public drmModePlanePtr drmModeGetPlane(int fd, uint32_t plane_id)
1157
0
{
1158
0
  struct drm_mode_get_plane ovr, counts;
1159
0
  drmModePlanePtr r = 0;
1160
1161
0
retry:
1162
0
  memclear(ovr);
1163
0
  ovr.plane_id = plane_id;
1164
0
  if (drmIoctl(fd, DRM_IOCTL_MODE_GETPLANE, &ovr))
1165
0
    return 0;
1166
1167
0
  counts = ovr;
1168
1169
0
  if (ovr.count_format_types) {
1170
0
    ovr.format_type_ptr = VOID2U64(drmMalloc(ovr.count_format_types *
1171
0
               sizeof(uint32_t)));
1172
0
    if (!ovr.format_type_ptr)
1173
0
      goto err_allocs;
1174
0
  }
1175
1176
0
  if (drmIoctl(fd, DRM_IOCTL_MODE_GETPLANE, &ovr))
1177
0
    goto err_allocs;
1178
1179
0
  if (counts.count_format_types < ovr.count_format_types) {
1180
0
    drmFree(U642VOID(ovr.format_type_ptr));
1181
0
    goto retry;
1182
0
  }
1183
1184
0
  if (!(r = drmMalloc(sizeof(*r))))
1185
0
    goto err_allocs;
1186
1187
0
  r->count_formats = ovr.count_format_types;
1188
0
  r->plane_id = ovr.plane_id;
1189
0
  r->crtc_id = ovr.crtc_id;
1190
0
  r->fb_id = ovr.fb_id;
1191
0
  r->possible_crtcs = ovr.possible_crtcs;
1192
0
  r->gamma_size = ovr.gamma_size;
1193
0
  r->formats = drmAllocCpy(U642VOID(ovr.format_type_ptr),
1194
0
         ovr.count_format_types, sizeof(uint32_t));
1195
0
  if (ovr.count_format_types && !r->formats) {
1196
0
    drmFree(r->formats);
1197
0
    drmFree(r);
1198
0
    r = 0;
1199
0
  }
1200
1201
0
err_allocs:
1202
0
  drmFree(U642VOID(ovr.format_type_ptr));
1203
1204
0
  return r;
1205
0
}
1206
1207
drm_public void drmModeFreePlane(drmModePlanePtr ptr)
1208
0
{
1209
0
  if (!ptr)
1210
0
    return;
1211
1212
0
  drmFree(ptr->formats);
1213
0
  drmFree(ptr);
1214
0
}
1215
1216
drm_public drmModePlaneResPtr drmModeGetPlaneResources(int fd)
1217
0
{
1218
0
  struct drm_mode_get_plane_res res, counts;
1219
0
  drmModePlaneResPtr r = 0;
1220
1221
0
retry:
1222
0
  memclear(res);
1223
0
  if (drmIoctl(fd, DRM_IOCTL_MODE_GETPLANERESOURCES, &res))
1224
0
    return 0;
1225
1226
0
  counts = res;
1227
1228
0
  if (res.count_planes) {
1229
0
    res.plane_id_ptr = VOID2U64(drmMalloc(res.count_planes *
1230
0
              sizeof(uint32_t)));
1231
0
    if (!res.plane_id_ptr)
1232
0
      goto err_allocs;
1233
0
  }
1234
1235
0
  if (drmIoctl(fd, DRM_IOCTL_MODE_GETPLANERESOURCES, &res))
1236
0
    goto err_allocs;
1237
1238
0
  if (counts.count_planes < res.count_planes) {
1239
0
    drmFree(U642VOID(res.plane_id_ptr));
1240
0
    goto retry;
1241
0
  }
1242
1243
0
  if (!(r = drmMalloc(sizeof(*r))))
1244
0
    goto err_allocs;
1245
1246
0
  r->count_planes = res.count_planes;
1247
0
  r->planes = drmAllocCpy(U642VOID(res.plane_id_ptr),
1248
0
          res.count_planes, sizeof(uint32_t));
1249
0
  if (res.count_planes && !r->planes) {
1250
0
    drmFree(r->planes);
1251
0
    drmFree(r);
1252
0
    r = 0;
1253
0
  }
1254
1255
0
err_allocs:
1256
0
  drmFree(U642VOID(res.plane_id_ptr));
1257
1258
0
  return r;
1259
0
}
1260
1261
drm_public void drmModeFreePlaneResources(drmModePlaneResPtr ptr)
1262
0
{
1263
0
  if (!ptr)
1264
0
    return;
1265
1266
0
  drmFree(ptr->planes);
1267
0
  drmFree(ptr);
1268
0
}
1269
1270
drm_public drmModeObjectPropertiesPtr drmModeObjectGetProperties(int fd,
1271
                  uint32_t object_id,
1272
                  uint32_t object_type)
1273
0
{
1274
0
  struct drm_mode_obj_get_properties properties;
1275
0
  drmModeObjectPropertiesPtr ret = NULL;
1276
0
  uint32_t count;
1277
1278
0
retry:
1279
0
  memclear(properties);
1280
0
  properties.obj_id = object_id;
1281
0
  properties.obj_type = object_type;
1282
1283
0
  if (drmIoctl(fd, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &properties))
1284
0
    return 0;
1285
1286
0
  count = properties.count_props;
1287
1288
0
  if (count) {
1289
0
    properties.props_ptr = VOID2U64(drmMalloc(count *
1290
0
                sizeof(uint32_t)));
1291
0
    if (!properties.props_ptr)
1292
0
      goto err_allocs;
1293
0
    properties.prop_values_ptr = VOID2U64(drmMalloc(count *
1294
0
                  sizeof(uint64_t)));
1295
0
    if (!properties.prop_values_ptr)
1296
0
      goto err_allocs;
1297
0
  }
1298
1299
0
  if (drmIoctl(fd, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &properties))
1300
0
    goto err_allocs;
1301
1302
0
  if (count < properties.count_props) {
1303
0
    drmFree(U642VOID(properties.props_ptr));
1304
0
    drmFree(U642VOID(properties.prop_values_ptr));
1305
0
    goto retry;
1306
0
  }
1307
0
  count = properties.count_props;
1308
1309
0
  ret = drmMalloc(sizeof(*ret));
1310
0
  if (!ret)
1311
0
    goto err_allocs;
1312
1313
0
  ret->count_props = count;
1314
0
  ret->props = drmAllocCpy(U642VOID(properties.props_ptr),
1315
0
         count, sizeof(uint32_t));
1316
0
  ret->prop_values = drmAllocCpy(U642VOID(properties.prop_values_ptr),
1317
0
               count, sizeof(uint64_t));
1318
0
  if (ret->count_props && (!ret->props || !ret->prop_values)) {
1319
0
    drmFree(ret->props);
1320
0
    drmFree(ret->prop_values);
1321
0
    drmFree(ret);
1322
0
    ret = NULL;
1323
0
  }
1324
1325
0
err_allocs:
1326
0
  drmFree(U642VOID(properties.props_ptr));
1327
0
  drmFree(U642VOID(properties.prop_values_ptr));
1328
0
  return ret;
1329
0
}
1330
1331
drm_public void drmModeFreeObjectProperties(drmModeObjectPropertiesPtr ptr)
1332
0
{
1333
0
  if (!ptr)
1334
0
    return;
1335
0
  drmFree(ptr->props);
1336
0
  drmFree(ptr->prop_values);
1337
0
  drmFree(ptr);
1338
0
}
1339
1340
drm_public int drmModeObjectSetProperty(int fd, uint32_t object_id, uint32_t object_type,
1341
           uint32_t property_id, uint64_t value)
1342
0
{
1343
0
  struct drm_mode_obj_set_property prop;
1344
1345
0
  memclear(prop);
1346
0
  prop.value = value;
1347
0
  prop.prop_id = property_id;
1348
0
  prop.obj_id = object_id;
1349
0
  prop.obj_type = object_type;
1350
1351
0
  return DRM_IOCTL(fd, DRM_IOCTL_MODE_OBJ_SETPROPERTY, &prop);
1352
0
}
1353
1354
typedef struct _drmModeAtomicReqItem drmModeAtomicReqItem, *drmModeAtomicReqItemPtr;
1355
1356
struct _drmModeAtomicReqItem {
1357
  uint32_t object_id;
1358
  uint32_t property_id;
1359
  uint64_t value;
1360
  uint32_t cursor;
1361
};
1362
1363
struct _drmModeAtomicReq {
1364
  uint32_t cursor;
1365
  uint32_t size_items;
1366
  drmModeAtomicReqItemPtr items;
1367
};
1368
1369
drm_public drmModeAtomicReqPtr drmModeAtomicAlloc(void)
1370
0
{
1371
0
  drmModeAtomicReqPtr req;
1372
1373
0
  req = drmMalloc(sizeof *req);
1374
0
  if (!req)
1375
0
    return NULL;
1376
1377
0
  req->items = NULL;
1378
0
  req->cursor = 0;
1379
0
  req->size_items = 0;
1380
1381
0
  return req;
1382
0
}
1383
1384
drm_public drmModeAtomicReqPtr drmModeAtomicDuplicate(const drmModeAtomicReqPtr old)
1385
0
{
1386
0
  drmModeAtomicReqPtr new;
1387
1388
0
  if (!old)
1389
0
    return NULL;
1390
1391
0
  new = drmMalloc(sizeof *new);
1392
0
  if (!new)
1393
0
    return NULL;
1394
1395
0
  new->cursor = old->cursor;
1396
0
  new->size_items = old->size_items;
1397
1398
0
  if (old->size_items) {
1399
0
    new->items = drmMalloc(old->size_items * sizeof(*new->items));
1400
0
    if (!new->items) {
1401
0
      free(new);
1402
0
      return NULL;
1403
0
    }
1404
0
    memcpy(new->items, old->items,
1405
0
           old->cursor * sizeof(*new->items));
1406
0
  } else {
1407
0
    new->items = NULL;
1408
0
  }
1409
1410
0
  return new;
1411
0
}
1412
1413
drm_public int drmModeAtomicMerge(drmModeAtomicReqPtr base,
1414
                                  const drmModeAtomicReqPtr augment)
1415
0
{
1416
0
  uint32_t i;
1417
1418
0
  if (!base)
1419
0
    return -EINVAL;
1420
1421
0
  if (!augment || augment->cursor == 0)
1422
0
    return 0;
1423
1424
0
  if (base->cursor + augment->cursor >= base->size_items) {
1425
0
    drmModeAtomicReqItemPtr new;
1426
0
    int saved_size = base->size_items;
1427
1428
0
    base->size_items = base->cursor + augment->cursor;
1429
0
    new = realloc(base->items,
1430
0
            base->size_items * sizeof(*base->items));
1431
0
    if (!new) {
1432
0
      base->size_items = saved_size;
1433
0
      return -ENOMEM;
1434
0
    }
1435
0
    base->items = new;
1436
0
  }
1437
1438
0
  memcpy(&base->items[base->cursor], augment->items,
1439
0
         augment->cursor * sizeof(*augment->items));
1440
0
  for (i = base->cursor; i < base->cursor + augment->cursor; i++)
1441
0
    base->items[i].cursor = i;
1442
0
  base->cursor += augment->cursor;
1443
1444
0
  return 0;
1445
0
}
1446
1447
drm_public int drmModeAtomicGetCursor(const drmModeAtomicReqPtr req)
1448
0
{
1449
0
  if (!req)
1450
0
    return -EINVAL;
1451
0
  return req->cursor;
1452
0
}
1453
1454
drm_public void drmModeAtomicSetCursor(drmModeAtomicReqPtr req, int cursor)
1455
0
{
1456
0
  if (req)
1457
0
    req->cursor = cursor;
1458
0
}
1459
1460
drm_public int drmModeAtomicAddProperty(drmModeAtomicReqPtr req,
1461
                                        uint32_t object_id,
1462
                                        uint32_t property_id,
1463
                                        uint64_t value)
1464
0
{
1465
0
  if (!req)
1466
0
    return -EINVAL;
1467
1468
0
  if (object_id == 0 || property_id == 0)
1469
0
    return -EINVAL;
1470
1471
0
  if (req->cursor >= req->size_items) {
1472
0
    const uint32_t item_size_inc = getpagesize() / sizeof(*req->items);
1473
0
    drmModeAtomicReqItemPtr new;
1474
1475
0
    req->size_items += item_size_inc;
1476
0
    new = realloc(req->items, req->size_items * sizeof(*req->items));
1477
0
    if (!new) {
1478
0
      req->size_items -= item_size_inc;
1479
0
      return -ENOMEM;
1480
0
    }
1481
0
    req->items = new;
1482
0
  }
1483
1484
0
  req->items[req->cursor].object_id = object_id;
1485
0
  req->items[req->cursor].property_id = property_id;
1486
0
  req->items[req->cursor].value = value;
1487
0
  req->items[req->cursor].cursor = req->cursor;
1488
0
  req->cursor++;
1489
1490
0
  return req->cursor;
1491
0
}
1492
1493
drm_public void drmModeAtomicFree(drmModeAtomicReqPtr req)
1494
0
{
1495
0
  if (!req)
1496
0
    return;
1497
1498
0
  if (req->items)
1499
0
    drmFree(req->items);
1500
0
  drmFree(req);
1501
0
}
1502
1503
static int sort_req_list(const void *misc, const void *other)
1504
0
{
1505
0
  const drmModeAtomicReqItem *first = misc;
1506
0
  const drmModeAtomicReqItem *second = other;
1507
1508
0
  if (first->object_id != second->object_id)
1509
0
    return first->object_id - second->object_id;
1510
0
  else if (first->property_id != second->property_id)
1511
0
    return first->property_id - second->property_id;
1512
0
  else
1513
0
    return first->cursor - second->cursor;
1514
0
}
1515
1516
drm_public int drmModeAtomicCommit(int fd, const drmModeAtomicReqPtr req,
1517
                                   uint32_t flags, void *user_data)
1518
0
{
1519
0
  drmModeAtomicReqPtr sorted;
1520
0
  struct drm_mode_atomic atomic;
1521
0
  uint32_t *objs_ptr = NULL;
1522
0
  uint32_t *count_props_ptr = NULL;
1523
0
  uint32_t *props_ptr = NULL;
1524
0
  uint64_t *prop_values_ptr = NULL;
1525
0
  uint32_t last_obj_id = 0;
1526
0
  uint32_t i;
1527
0
  int obj_idx = -1;
1528
0
  int ret = -1;
1529
1530
0
  if (!req)
1531
0
    return -EINVAL;
1532
1533
0
  if (req->cursor == 0)
1534
0
    return 0;
1535
1536
0
  sorted = drmModeAtomicDuplicate(req);
1537
0
  if (sorted == NULL)
1538
0
    return -ENOMEM;
1539
1540
0
  memclear(atomic);
1541
1542
  /* Sort the list by object ID, then by property ID. */
1543
0
  qsort(sorted->items, sorted->cursor, sizeof(*sorted->items),
1544
0
        sort_req_list);
1545
1546
  /* Now the list is sorted, eliminate duplicate property sets. */
1547
0
  for (i = 0; i < sorted->cursor; i++) {
1548
0
    if (sorted->items[i].object_id != last_obj_id) {
1549
0
      atomic.count_objs++;
1550
0
      last_obj_id = sorted->items[i].object_id;
1551
0
    }
1552
1553
0
    if (i == sorted->cursor - 1)
1554
0
      continue;
1555
1556
0
    if (sorted->items[i].object_id != sorted->items[i + 1].object_id ||
1557
0
        sorted->items[i].property_id != sorted->items[i + 1].property_id)
1558
0
      continue;
1559
1560
0
    memmove(&sorted->items[i], &sorted->items[i + 1],
1561
0
      (sorted->cursor - i - 1) * sizeof(*sorted->items));
1562
0
    sorted->cursor--;
1563
0
  }
1564
1565
0
  for (i = 0; i < sorted->cursor; i++)
1566
0
    sorted->items[i].cursor = i;
1567
1568
0
  objs_ptr = drmMalloc(atomic.count_objs * sizeof objs_ptr[0]);
1569
0
  if (!objs_ptr) {
1570
0
    errno = ENOMEM;
1571
0
    goto out;
1572
0
  }
1573
1574
0
  count_props_ptr = drmMalloc(atomic.count_objs * sizeof count_props_ptr[0]);
1575
0
  if (!count_props_ptr) {
1576
0
    errno = ENOMEM;
1577
0
    goto out;
1578
0
  }
1579
1580
0
  props_ptr = drmMalloc(sorted->cursor * sizeof props_ptr[0]);
1581
0
  if (!props_ptr) {
1582
0
    errno = ENOMEM;
1583
0
    goto out;
1584
0
  }
1585
1586
0
  prop_values_ptr = drmMalloc(sorted->cursor * sizeof prop_values_ptr[0]);
1587
0
  if (!prop_values_ptr) {
1588
0
    errno = ENOMEM;
1589
0
    goto out;
1590
0
  }
1591
1592
0
  for (i = 0, last_obj_id = 0; i < sorted->cursor; i++) {
1593
0
    if (sorted->items[i].object_id != last_obj_id) {
1594
0
      obj_idx++;
1595
0
      objs_ptr[obj_idx] = sorted->items[i].object_id;
1596
0
      last_obj_id = objs_ptr[obj_idx];
1597
0
    }
1598
1599
0
    count_props_ptr[obj_idx]++;
1600
0
    props_ptr[i] = sorted->items[i].property_id;
1601
0
    prop_values_ptr[i] = sorted->items[i].value;
1602
1603
0
  }
1604
1605
0
  atomic.flags = flags;
1606
0
  atomic.objs_ptr = VOID2U64(objs_ptr);
1607
0
  atomic.count_props_ptr = VOID2U64(count_props_ptr);
1608
0
  atomic.props_ptr = VOID2U64(props_ptr);
1609
0
  atomic.prop_values_ptr = VOID2U64(prop_values_ptr);
1610
0
  atomic.user_data = VOID2U64(user_data);
1611
1612
0
  ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_ATOMIC, &atomic);
1613
1614
0
out:
1615
0
  drmFree(objs_ptr);
1616
0
  drmFree(count_props_ptr);
1617
0
  drmFree(props_ptr);
1618
0
  drmFree(prop_values_ptr);
1619
0
  drmModeAtomicFree(sorted);
1620
1621
0
  return ret;
1622
0
}
1623
1624
drm_public int
1625
drmModeCreatePropertyBlob(int fd, const void *data, size_t length,
1626
                                     uint32_t *id)
1627
0
{
1628
0
  struct drm_mode_create_blob create;
1629
0
  int ret;
1630
1631
0
  if (length >= 0xffffffff)
1632
0
    return -ERANGE;
1633
1634
0
  memclear(create);
1635
1636
0
  create.length = length;
1637
0
  create.data = (uintptr_t) data;
1638
0
  create.blob_id = 0;
1639
0
  *id = 0;
1640
1641
0
  ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_CREATEPROPBLOB, &create);
1642
0
  if (ret != 0)
1643
0
    return ret;
1644
1645
0
  *id = create.blob_id;
1646
0
  return 0;
1647
0
}
1648
1649
drm_public int
1650
drmModeDestroyPropertyBlob(int fd, uint32_t id)
1651
0
{
1652
0
  struct drm_mode_destroy_blob destroy;
1653
1654
0
  memclear(destroy);
1655
0
  destroy.blob_id = id;
1656
0
  return DRM_IOCTL(fd, DRM_IOCTL_MODE_DESTROYPROPBLOB, &destroy);
1657
0
}
1658
1659
drm_public int
1660
drmModeCreateLease(int fd, const uint32_t *objects, int num_objects, int flags,
1661
                   uint32_t *lessee_id)
1662
0
{
1663
0
  struct drm_mode_create_lease create;
1664
0
  int ret;
1665
1666
0
  memclear(create);
1667
0
  create.object_ids = (uintptr_t) objects;
1668
0
  create.object_count = num_objects;
1669
0
  create.flags = flags;
1670
1671
0
  ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_CREATE_LEASE, &create);
1672
0
  if (ret == 0) {
1673
0
    *lessee_id = create.lessee_id;
1674
0
    return create.fd;
1675
0
  }
1676
0
  return -errno;
1677
0
}
1678
1679
drm_public drmModeLesseeListPtr
1680
drmModeListLessees(int fd)
1681
0
{
1682
0
  struct drm_mode_list_lessees list;
1683
0
  uint32_t count;
1684
0
  drmModeLesseeListPtr ret;
1685
1686
0
  memclear(list);
1687
1688
0
  if (DRM_IOCTL(fd, DRM_IOCTL_MODE_LIST_LESSEES, &list))
1689
0
    return NULL;
1690
1691
0
  count = list.count_lessees;
1692
0
  ret = drmMalloc(sizeof (drmModeLesseeListRes) + count * sizeof (ret->lessees[0]));
1693
0
  if (!ret)
1694
0
    return NULL;
1695
1696
0
  list.lessees_ptr = VOID2U64(&ret->lessees[0]);
1697
0
  if (DRM_IOCTL(fd, DRM_IOCTL_MODE_LIST_LESSEES, &list)) {
1698
0
    drmFree(ret);
1699
0
    return NULL;
1700
0
  }
1701
1702
0
  ret->count = count;
1703
0
  return ret;
1704
0
}
1705
1706
drm_public drmModeObjectListPtr
1707
drmModeGetLease(int fd)
1708
0
{
1709
0
  struct drm_mode_get_lease get;
1710
0
  uint32_t count;
1711
0
  drmModeObjectListPtr ret;
1712
1713
0
  memclear(get);
1714
1715
0
  if (DRM_IOCTL(fd, DRM_IOCTL_MODE_GET_LEASE, &get))
1716
0
    return NULL;
1717
1718
0
  count = get.count_objects;
1719
0
  ret = drmMalloc(sizeof (drmModeObjectListRes) + count * sizeof (ret->objects[0]));
1720
0
  if (!ret)
1721
0
    return NULL;
1722
1723
0
  get.objects_ptr = VOID2U64(&ret->objects[0]);
1724
0
  if (DRM_IOCTL(fd, DRM_IOCTL_MODE_GET_LEASE, &get)) {
1725
0
    drmFree(ret);
1726
0
    return NULL;
1727
0
  }
1728
1729
0
  ret->count = count;
1730
0
  return ret;
1731
0
}
1732
1733
drm_public int
1734
drmModeRevokeLease(int fd, uint32_t lessee_id)
1735
0
{
1736
0
  struct drm_mode_revoke_lease revoke;
1737
0
  int ret;
1738
1739
0
  memclear(revoke);
1740
1741
0
  revoke.lessee_id = lessee_id;
1742
1743
0
  ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_REVOKE_LEASE, &revoke);
1744
0
  if (ret == 0)
1745
0
    return 0;
1746
0
  return -errno;
1747
0
}
1748
1749
drm_public drmModeFB2Ptr
1750
drmModeGetFB2(int fd, uint32_t fb_id)
1751
0
{
1752
0
  struct drm_mode_fb_cmd2 get = {
1753
0
    .fb_id = fb_id,
1754
0
  };
1755
0
  drmModeFB2Ptr ret;
1756
0
  int err;
1757
1758
0
  err = DRM_IOCTL(fd, DRM_IOCTL_MODE_GETFB2, &get);
1759
0
  if (err != 0)
1760
0
    return NULL;
1761
1762
0
  ret = drmMalloc(sizeof(drmModeFB2));
1763
0
  if (!ret)
1764
0
    return NULL;
1765
1766
0
  ret->fb_id = fb_id;
1767
0
  ret->width = get.width;
1768
0
  ret->height = get.height;
1769
0
  ret->pixel_format = get.pixel_format;
1770
0
  ret->flags = get.flags;
1771
0
  ret->modifier = get.modifier[0];
1772
0
  memcpy(ret->handles, get.handles, sizeof(uint32_t) * 4);
1773
0
  memcpy(ret->pitches, get.pitches, sizeof(uint32_t) * 4);
1774
0
  memcpy(ret->offsets, get.offsets, sizeof(uint32_t) * 4);
1775
1776
0
  return ret;
1777
0
}
1778
1779
drm_public void drmModeFreeFB2(drmModeFB2Ptr ptr)
1780
0
{
1781
0
  drmFree(ptr);
1782
0
}
1783
1784
drm_public const char *
1785
drmModeGetConnectorTypeName(uint32_t connector_type)
1786
0
{
1787
  /* Keep the strings in sync with the kernel's drm_connector_enum_list in
1788
   * drm_connector.c. */
1789
0
  switch (connector_type) {
1790
0
  case DRM_MODE_CONNECTOR_Unknown:
1791
0
    return "Unknown";
1792
0
  case DRM_MODE_CONNECTOR_VGA:
1793
0
    return "VGA";
1794
0
  case DRM_MODE_CONNECTOR_DVII:
1795
0
    return "DVI-I";
1796
0
  case DRM_MODE_CONNECTOR_DVID:
1797
0
    return "DVI-D";
1798
0
  case DRM_MODE_CONNECTOR_DVIA:
1799
0
    return "DVI-A";
1800
0
  case DRM_MODE_CONNECTOR_Composite:
1801
0
    return "Composite";
1802
0
  case DRM_MODE_CONNECTOR_SVIDEO:
1803
0
    return "SVIDEO";
1804
0
  case DRM_MODE_CONNECTOR_LVDS:
1805
0
    return "LVDS";
1806
0
  case DRM_MODE_CONNECTOR_Component:
1807
0
    return "Component";
1808
0
  case DRM_MODE_CONNECTOR_9PinDIN:
1809
0
    return "DIN";
1810
0
  case DRM_MODE_CONNECTOR_DisplayPort:
1811
0
    return "DP";
1812
0
  case DRM_MODE_CONNECTOR_HDMIA:
1813
0
    return "HDMI-A";
1814
0
  case DRM_MODE_CONNECTOR_HDMIB:
1815
0
    return "HDMI-B";
1816
0
  case DRM_MODE_CONNECTOR_TV:
1817
0
    return "TV";
1818
0
  case DRM_MODE_CONNECTOR_eDP:
1819
0
    return "eDP";
1820
0
  case DRM_MODE_CONNECTOR_VIRTUAL:
1821
0
    return "Virtual";
1822
0
  case DRM_MODE_CONNECTOR_DSI:
1823
0
    return "DSI";
1824
0
  case DRM_MODE_CONNECTOR_DPI:
1825
0
    return "DPI";
1826
0
  case DRM_MODE_CONNECTOR_WRITEBACK:
1827
0
    return "Writeback";
1828
0
  case DRM_MODE_CONNECTOR_SPI:
1829
0
    return "SPI";
1830
0
  case DRM_MODE_CONNECTOR_USB:
1831
0
    return "USB";
1832
0
  default:
1833
0
    return NULL;
1834
0
  }
1835
0
}
1836
1837
drm_public int
1838
drmModeCreateDumbBuffer(int fd, uint32_t width, uint32_t height, uint32_t bpp,
1839
                        uint32_t flags, uint32_t *handle, uint32_t *pitch,
1840
                        uint64_t *size)
1841
0
{
1842
0
  int ret;
1843
0
  struct drm_mode_create_dumb create = {
1844
0
    .width = width,
1845
0
    .height = height,
1846
0
    .bpp = bpp,
1847
0
    .flags = flags,
1848
0
  };
1849
1850
0
  ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create);
1851
0
  if (ret != 0)
1852
0
    return ret;
1853
1854
0
  *handle = create.handle;
1855
0
  *pitch = create.pitch;
1856
0
  *size = create.size;
1857
0
  return 0;
1858
0
}
1859
1860
drm_public int
1861
drmModeDestroyDumbBuffer(int fd, uint32_t handle)
1862
0
{
1863
0
  struct drm_mode_destroy_dumb destroy = {
1864
0
    .handle = handle,
1865
0
  };
1866
1867
0
  return DRM_IOCTL(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy);
1868
0
}
1869
1870
drm_public int
1871
drmModeMapDumbBuffer(int fd, uint32_t handle, uint64_t *offset)
1872
0
{
1873
0
  int ret;
1874
0
  struct drm_mode_map_dumb map = {
1875
0
    .handle = handle,
1876
0
  };
1877
1878
0
  ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_MAP_DUMB, &map);
1879
0
  if (ret != 0)
1880
0
    return ret;
1881
1882
0
  *offset = map.offset;
1883
0
  return 0;
1884
0
}