672a5e2ac609f10850e351bd2985c8fbadc09af6
[platform/upstream/libdrm.git] / libdrm / xf86drmMode.c
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) <year> <copyright holders>
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a
15  * copy of this software and associated documentation files (the "Software"),
16  * to deal in the Software without restriction, including without limitation
17  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18  * and/or sell copies of the Software, and to permit persons to whom the
19  * Software is furnished to do so, subject to the following conditions:
20  *
21  * The above copyright notice and this permission notice shall be included in
22  * all copies or substantial portions of the Software.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30  * IN THE SOFTWARE.
31  *
32  */
33
34 /*
35  * TODO the types we are after are defined in diffrent headers on diffrent
36  * platforms find which headers to include to get uint32_t
37  */
38 #include <stdint.h>
39 #include <sys/ioctl.h>
40 #include <stdio.h>
41
42 #include "xf86drmMode.h"
43 #include "xf86drm.h"
44 #include <drm.h>
45 #include <string.h>
46 #include <dirent.h>
47 #include <errno.h>
48
49 #define U642VOID(x) ((void *)(unsigned long)(x))
50 #define VOID2U64(x) ((uint64_t)(unsigned long)(x))
51
52 /*
53  * Util functions
54  */
55
56 void* drmAllocCpy(void *array, int count, int entry_size)
57 {
58         char *r;
59         int i;
60
61         if (!count || !array || !entry_size)
62                 return 0;
63
64         if (!(r = drmMalloc(count*entry_size)))
65                 return 0;
66
67         for (i = 0; i < count; i++)
68                 memcpy(r+(entry_size*i), array+(entry_size*i), entry_size);
69
70         return r;
71 }
72
73 /*
74  * A couple of free functions.
75  */
76
77 void drmModeFreeModeInfo(struct drm_mode_modeinfo *ptr)
78 {
79         if (!ptr)
80                 return;
81
82         drmFree(ptr);
83 }
84
85 void drmModeFreeResources(drmModeResPtr ptr)
86 {
87         if (!ptr)
88                 return;
89
90         drmFree(ptr);
91
92 }
93
94 void drmModeFreeFB(drmModeFBPtr ptr)
95 {
96         if (!ptr)
97                 return;
98
99         /* we might add more frees later. */
100         drmFree(ptr);
101 }
102
103 void drmModeFreeCrtc(drmModeCrtcPtr ptr)
104 {
105         if (!ptr)
106                 return;
107
108         drmFree(ptr);
109
110 }
111
112 void drmModeFreeOutput(drmModeOutputPtr ptr)
113 {
114         if (!ptr)
115                 return;
116
117         drmFree(ptr->modes);
118         drmFree(ptr);
119
120 }
121
122 /*
123  * ModeSetting functions.
124  */
125
126 drmModeResPtr drmModeGetResources(int fd)
127 {
128         struct drm_mode_card_res res;
129         drmModeResPtr r = 0;
130
131         memset(&res, 0, sizeof(struct drm_mode_card_res));
132
133         if (ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
134                 return 0;
135
136         if (res.count_fbs)
137                 res.fb_id_ptr = VOID2U64(drmMalloc(res.count_fbs*sizeof(uint32_t)));
138         if (res.count_crtcs)
139                 res.crtc_id_ptr = VOID2U64(drmMalloc(res.count_crtcs*sizeof(uint32_t)));
140         if (res.count_outputs)
141                 res.output_id_ptr = VOID2U64(drmMalloc(res.count_outputs*sizeof(uint32_t)));
142         if (res.count_encoders)
143                 res.encoder_id_ptr = VOID2U64(drmMalloc(res.count_encoders*sizeof(uint32_t)));
144
145         if (ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) {
146                 r = NULL;
147                 goto err_allocs;
148         }
149
150         /*
151          * return
152          */
153
154
155         if (!(r = drmMalloc(sizeof(*r))))
156                 return 0;
157
158         r->min_width     = res.min_width;
159         r->max_width     = res.max_width;
160         r->min_height    = res.min_height;
161         r->max_height    = res.max_height;
162         r->count_fbs     = res.count_fbs;
163         r->count_crtcs   = res.count_crtcs;
164         r->count_outputs = res.count_outputs;
165         /* TODO we realy should test if these allocs fails. */
166         r->fbs           = drmAllocCpy(U642VOID(res.fb_id_ptr), res.count_fbs, sizeof(uint32_t));
167         r->crtcs         = drmAllocCpy(U642VOID(res.crtc_id_ptr), res.count_crtcs, sizeof(uint32_t));
168         r->outputs       = drmAllocCpy(U642VOID(res.output_id_ptr), res.count_outputs, sizeof(uint32_t));
169         r->encoders      = drmAllocCpy(U642VOID(res.encoder_id_ptr), res.count_encoders, sizeof(uint32_t));
170
171 err_allocs:
172         drmFree(U642VOID(res.fb_id_ptr));
173         drmFree(U642VOID(res.crtc_id_ptr));
174         drmFree(U642VOID(res.output_id_ptr));
175         drmFree(U642VOID(res.encoder_id_ptr));
176
177         return r;
178 }
179
180 uint32_t drmModeGetHotplug(int fd)
181 {
182         struct drm_mode_hotplug arg;
183         arg.counter = 0;
184
185         ioctl(fd, DRM_IOCTL_MODE_HOTPLUG, &arg);
186         return arg.counter;
187 }
188
189 int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth,
190                  uint8_t bpp, uint32_t pitch, uint32_t bo_handle,
191                  uint32_t *buf_id)
192 {
193         struct drm_mode_fb_cmd f;
194         int ret;
195
196         f.width  = width;
197         f.height = height;
198         f.pitch  = pitch;
199         f.bpp    = bpp;
200         f.depth  = depth;
201         f.handle = bo_handle;
202
203         if ((ret = ioctl(fd, DRM_IOCTL_MODE_ADDFB, &f)))
204                 return ret;
205
206         *buf_id = f.buffer_id;
207         return 0;
208 }
209
210 int drmModeRmFB(int fd, uint32_t bufferId)
211 {
212         return ioctl(fd, DRM_IOCTL_MODE_RMFB, &bufferId);
213
214
215 }
216
217 drmModeFBPtr drmModeGetFB(int fd, uint32_t buf)
218 {
219         struct drm_mode_fb_cmd info;
220         drmModeFBPtr r;
221
222         info.buffer_id = buf;
223
224         if (ioctl(fd, DRM_IOCTL_MODE_GETFB, &info))
225                 return NULL;
226
227         if (!(r = drmMalloc(sizeof(*r))))
228                 return NULL;
229
230         r->buffer_id = info.buffer_id;
231         r->width = info.width;
232         r->height = info.height;
233         r->pitch = info.pitch;
234         r->bpp = info.bpp;
235         r->handle = info.handle;
236         r->depth = info.depth;
237
238         return r;
239 }
240
241
242 /*
243  * Crtc functions
244  */
245
246 drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId)
247 {
248         struct drm_mode_crtc crtc;
249         drmModeCrtcPtr r;
250
251         crtc.count_outputs   = 0;
252         crtc.outputs         = 0;
253         crtc.count_possibles = 0;
254         crtc.possibles       = 0;
255         crtc.crtc_id = crtcId;
256
257         if (ioctl(fd, DRM_IOCTL_MODE_GETCRTC, &crtc))
258                 return 0;
259
260         /*
261          * return
262          */
263
264         if (!(r = drmMalloc(sizeof(*r))))
265                 return 0;
266         
267         r->crtc_id         = crtc.crtc_id;
268         r->x               = crtc.x;
269         r->y               = crtc.y;
270         r->mode_valid      = crtc.mode_valid;
271         if (r->mode_valid)
272                 memcpy(&r->mode, &crtc.mode, sizeof(struct drm_mode_modeinfo));
273         r->buffer_id       = crtc.fb_id;
274         r->gamma_size      = crtc.gamma_size;
275         r->count_outputs   = crtc.count_outputs;
276         r->count_possibles = crtc.count_possibles;
277         /* TODO we realy should test if these alloc & cpy fails. */
278         r->outputs         = crtc.outputs;
279         r->possibles       = crtc.possibles;
280
281         return r;
282 }
283
284
285 int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,
286                    uint32_t x, uint32_t y, uint32_t *outputs, int count,
287                    struct drm_mode_modeinfo *mode)
288 {
289         struct drm_mode_crtc crtc;
290
291         crtc.count_outputs   = 0;
292         crtc.outputs         = 0;
293         crtc.count_possibles = 0;
294         crtc.possibles       = 0;
295
296         crtc.x             = x;
297         crtc.y             = y;
298         crtc.crtc_id       = crtcId;
299         crtc.fb_id         = bufferId;
300         crtc.set_outputs_ptr = VOID2U64(outputs);
301         crtc.count_outputs = count;
302         if (mode) {
303           memcpy(&crtc.mode, mode, sizeof(struct drm_mode_modeinfo));
304           crtc.mode_valid = 1;
305         } else
306           crtc.mode_valid = 0;
307
308         return ioctl(fd, DRM_IOCTL_MODE_SETCRTC, &crtc);
309 }
310
311 /*
312  * Cursor manipulation
313  */
314
315 int drmModeSetCursor(int fd, uint32_t crtcId, uint32_t bo_handle, uint32_t width, uint32_t height)
316 {
317         struct drm_mode_cursor arg;
318
319         arg.flags = DRM_MODE_CURSOR_BO;
320         arg.crtc = crtcId;
321         arg.width = width;
322         arg.height = height;
323         arg.handle = bo_handle;
324
325         return ioctl(fd, DRM_IOCTL_MODE_CURSOR, &arg);
326 }
327
328 int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y)
329 {
330         struct drm_mode_cursor arg;
331
332         arg.flags = DRM_MODE_CURSOR_MOVE;
333         arg.crtc = crtcId;
334         arg.x = x;
335         arg.y = y;
336
337         return ioctl(fd, DRM_IOCTL_MODE_CURSOR, &arg);
338 }
339
340 /*
341  * Encoder get 
342  */
343 drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id)
344 {
345         struct drm_mode_get_encoder enc;
346         drmModeEncoderPtr r = NULL;
347
348         enc.encoder_id = encoder_id;
349         enc.encoder_type = 0;
350         enc.crtcs = 0;
351         enc.clones = 0;
352
353         if (ioctl(fd, DRM_IOCTL_MODE_GETENCODER, &enc))
354                 return 0;
355
356         r->encoder_type = enc.encoder_type;
357         r->crtcs = enc.crtcs;
358         r->clones = enc.clones;
359
360         return r;
361 }
362
363 /*
364  * Output manipulation
365  */
366
367 drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id)
368 {
369         struct drm_mode_get_output out;
370         drmModeOutputPtr r = NULL;
371
372         out.output = output_id;
373         out.output_type_id = 0;
374         out.output_type  = 0;
375         out.count_crtcs  = 0;
376         out.crtcs        = 0;
377         out.count_clones = 0;
378         out.clones       = 0;
379         out.count_modes  = 0;
380         out.modes_ptr    = 0;
381         out.count_props  = 0;
382         out.props_ptr    = 0;
383         out.prop_values_ptr = 0;
384         out.count_encoders  = 0;
385         out.encoders_ptr = 0;
386
387         if (ioctl(fd, DRM_IOCTL_MODE_GETOUTPUT, &out))
388                 return 0;
389
390         if (out.count_props) {
391                 out.props_ptr = VOID2U64(drmMalloc(out.count_props*sizeof(uint32_t)));
392                 out.prop_values_ptr = VOID2U64(drmMalloc(out.count_props*sizeof(uint64_t)));
393         }
394
395         if (out.count_modes)
396                 out.modes_ptr = VOID2U64(drmMalloc(out.count_modes*sizeof(struct drm_mode_modeinfo)));
397
398         if (out.count_encoders)
399                 out.encoders_ptr = VOID2U64(drmMalloc(out.count_encoders*sizeof(uint32_t)));
400
401         if (ioctl(fd, DRM_IOCTL_MODE_GETOUTPUT, &out))
402                 goto err_allocs;
403
404         if(!(r = drmMalloc(sizeof(*r)))) {
405                 goto err_allocs;
406         }
407
408         r->output_id = out.output;
409         r->crtc = out.crtc;
410         r->connection   = out.connection;
411         r->mmWidth      = out.mm_width;
412         r->mmHeight     = out.mm_height;
413         r->subpixel     = out.subpixel;
414         r->count_crtcs  = out.count_crtcs;
415         r->count_clones = out.count_clones;
416         r->count_modes  = out.count_modes;
417         /* TODO we should test if these alloc & cpy fails. */
418         r->crtcs        = out.crtcs;
419         r->clones       = out.clones;
420         r->count_props  = out.count_props;
421         r->props        = drmAllocCpy(U642VOID(out.props_ptr), out.count_props, sizeof(uint32_t));
422         r->prop_values  = drmAllocCpy(U642VOID(out.prop_values_ptr), out.count_props, sizeof(uint64_t));
423         r->modes        = drmAllocCpy(U642VOID(out.modes_ptr), out.count_modes, sizeof(struct drm_mode_modeinfo));
424         r->count_encoders = out.count_encoders;
425         r->encoders     = drmAllocCpy(U642VOID(out.encoders_ptr), out.count_encoders, sizeof(uint32_t));
426         r->output_type  = out.output_type;
427         r->output_type_id = out.output_type_id;
428
429 err_allocs:
430         drmFree(U642VOID(out.prop_values_ptr));
431         drmFree(U642VOID(out.props_ptr));
432         drmFree(U642VOID(out.modes_ptr));
433         drmFree(U642VOID(out.encoders_ptr));
434
435         return r;
436 }
437
438 int drmModeAttachMode(int fd, uint32_t output_id, struct drm_mode_modeinfo *mode_info)
439 {
440         struct drm_mode_mode_cmd res;
441
442         memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo));
443         res.output_id = output_id;
444
445         return ioctl(fd, DRM_IOCTL_MODE_ATTACHMODE, &res);
446 }
447
448 int drmModeDetachMode(int fd, uint32_t output_id, struct drm_mode_modeinfo *mode_info)
449 {
450         struct drm_mode_mode_cmd res;
451
452         memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo));
453         res.output_id = output_id;
454
455         return ioctl(fd, DRM_IOCTL_MODE_DETACHMODE, &res);
456 }
457
458
459 drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id)
460 {
461         struct drm_mode_get_property prop;
462         drmModePropertyPtr r;
463
464         prop.prop_id = property_id;
465         prop.count_enum_blobs = 0;
466         prop.count_values = 0;
467         prop.flags = 0;
468         prop.enum_blob_ptr = 0;
469         prop.values_ptr = 0;
470
471         if (ioctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop))
472                 return 0;
473
474         if (prop.count_values)
475                 prop.values_ptr = VOID2U64(drmMalloc(prop.count_values * sizeof(uint64_t)));
476
477         if (prop.count_enum_blobs && (prop.flags & DRM_MODE_PROP_ENUM))
478                 prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(struct drm_mode_property_enum)));
479
480         if (prop.count_enum_blobs && (prop.flags & DRM_MODE_PROP_BLOB)) {
481                 prop.values_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t)));
482                 prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t)));
483         }
484
485         if (ioctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop)) {
486                 r = NULL;
487                 goto err_allocs;
488         }
489
490         if (!(r = drmMalloc(sizeof(*r))))
491                 return NULL;
492         
493         r->prop_id = prop.prop_id;
494         r->count_values = prop.count_values;
495         
496         r->flags = prop.flags;
497         if (prop.count_values)
498                 r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_values, sizeof(uint64_t));
499         if (prop.flags & DRM_MODE_PROP_ENUM) {
500                 r->count_enums = prop.count_enum_blobs;
501                 r->enums = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(struct drm_mode_property_enum));
502         } else  if (prop.flags & DRM_MODE_PROP_ENUM) {
503                 r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_enum_blobs, sizeof(uint32_t));
504                 r->blob_ids = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(uint32_t));
505                 r->count_blobs = prop.count_enum_blobs;
506         }
507         strncpy(r->name, prop.name, DRM_PROP_NAME_LEN);
508         r->name[DRM_PROP_NAME_LEN-1] = 0;
509
510 err_allocs:
511         drmFree(U642VOID(prop.values_ptr));
512         drmFree(U642VOID(prop.enum_blob_ptr));
513
514         return r;
515 }
516
517 void drmModeFreeProperty(drmModePropertyPtr ptr)
518 {
519         if (!ptr)
520                 return;
521
522         drmFree(ptr->values);
523         drmFree(ptr->enums);
524         drmFree(ptr);
525 }
526
527 drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id)
528 {
529         struct drm_mode_get_blob blob;
530         drmModePropertyBlobPtr r;
531
532         blob.length = 0;
533         blob.data = 0;
534         blob.blob_id = blob_id;
535
536         if (ioctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
537                 return NULL;
538
539         if (blob.length)
540                 blob.data = VOID2U64(drmMalloc(blob.length));
541
542         if (ioctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) {
543                 r = NULL;
544                 goto err_allocs;
545         }
546
547         if (!(r = drmMalloc(sizeof(*r))))
548                 return NULL;
549
550         r->id = blob.blob_id;
551         r->length = blob.length;
552         r->data = drmAllocCpy(U642VOID(blob.data), 1, blob.length);
553
554 err_allocs:
555         drmFree(U642VOID(blob.data));
556         return r;
557 }
558
559 void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr)
560 {
561         if (!ptr)
562                 return;
563
564         drmFree(ptr->data);
565         drmFree(ptr);
566 }
567
568 int drmModeOutputSetProperty(int fd, uint32_t output_id, uint32_t property_id,
569                              uint64_t value)
570 {
571         struct drm_mode_output_set_property osp;
572         int ret;
573
574         osp.output_id = output_id;
575         osp.prop_id = property_id;
576         osp.value = value;
577
578         if ((ret = ioctl(fd, DRM_IOCTL_MODE_SETPROPERTY, &osp)))
579                 return ret;
580
581         return 0;
582 }
583
584 /*
585  * checks if a modesetting capable driver has attached to the pci id
586  * returns 0 if modesetting supported.
587  *  -EINVAL or invalid bus id
588  *  -ENOSYS if no modesetting support
589 */
590 int drmCheckModesettingSupported(const char *busid)
591 {
592 #ifdef __linux__
593         char pci_dev_dir[1024];
594         int domain, bus, dev, func;
595         DIR *sysdir;
596         struct dirent *dent;
597         int found = 0, ret;
598
599         ret = sscanf(busid, "pci:%04x:%02x:%02x.%d", &domain, &bus, &dev, &func);
600         if (ret != 4)
601                 return -EINVAL;
602
603         sprintf(pci_dev_dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/drm",
604                 domain, bus, dev, func);
605
606         sysdir = opendir(pci_dev_dir);
607         if (sysdir) {
608                 dent = readdir(sysdir);
609                 while (dent) {
610                         if (!strncmp(dent->d_name, "controlD", 8)) {
611                                 found = 1;
612                                 break;
613                         }
614                 
615                         dent = readdir(sysdir);
616                 }
617                 closedir(sysdir);
618                 if (found)
619                         return 0;
620         }
621
622         sprintf(pci_dev_dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/",
623                 domain, bus, dev, func);
624
625         sysdir = opendir(pci_dev_dir);
626         if (!sysdir)
627                 return -EINVAL;
628
629         dent = readdir(sysdir);
630         while (dent) {
631                 if (!strncmp(dent->d_name, "drm:controlD", 12)) {
632                         found = 1;
633                         break;
634                 }
635                 
636                 dent = readdir(sysdir);
637         }
638                         
639         closedir(sysdir);
640         if (found)
641                 return 0;
642 #endif
643         return -ENOSYS;
644
645 }
646
647 int drmModeReplaceFB(int fd, uint32_t buffer_id,
648                      uint32_t width, uint32_t height, uint8_t depth,
649                      uint8_t bpp, uint32_t pitch, uint32_t bo_handle)
650 {
651         struct drm_mode_fb_cmd f;
652         int ret;
653
654         f.width = width;
655         f.height = height;
656         f.pitch = pitch;
657         f.bpp = bpp;
658         f.depth = depth;
659         f.handle = bo_handle;
660         f.buffer_id = buffer_id;
661
662         if ((ret = ioctl(fd, DRM_IOCTL_MODE_REPLACEFB, &f)))
663                 return ret;
664
665         return 0;
666 }