xref: /OK3568_Linux_fs/external/recovery/minui/graphics_drm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (C) 2015 The Android Open Source Project
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Licensed under the Apache License, Version 2.0 (the "License");
5*4882a593Smuzhiyun  * you may not use this file except in compliance with the License.
6*4882a593Smuzhiyun  * You may obtain a copy of the License at
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  *      http://www.apache.org/licenses/LICENSE-2.0
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * Unless required by applicable law or agreed to in writing, software
11*4882a593Smuzhiyun  * distributed under the License is distributed on an "AS IS" BASIS,
12*4882a593Smuzhiyun  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4882a593Smuzhiyun  * See the License for the specific language governing permissions and
14*4882a593Smuzhiyun  * limitations under the License.
15*4882a593Smuzhiyun  */
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #define _GNU_SOURCE  //enable GUN extension for asprintf
18*4882a593Smuzhiyun #include <drm_fourcc.h>
19*4882a593Smuzhiyun #include <fcntl.h>
20*4882a593Smuzhiyun #include <stdbool.h>
21*4882a593Smuzhiyun #include <stdio.h>
22*4882a593Smuzhiyun #include <stdlib.h>
23*4882a593Smuzhiyun #include <string.h>
24*4882a593Smuzhiyun #include <sys/cdefs.h>
25*4882a593Smuzhiyun #include <sys/ioctl.h>
26*4882a593Smuzhiyun #include <sys/mman.h>
27*4882a593Smuzhiyun #include <sys/types.h>
28*4882a593Smuzhiyun #include <unistd.h>
29*4882a593Smuzhiyun #include <xf86drm.h>
30*4882a593Smuzhiyun #include <xf86drmMode.h>
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun #include "minui.h"
33*4882a593Smuzhiyun #include "graphics.h"
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun #define ARRAY_SIZE(A) (sizeof(A)/sizeof(*(A)))
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun struct drm_surface {
38*4882a593Smuzhiyun     GRSurface base;
39*4882a593Smuzhiyun     uint32_t fb_id;
40*4882a593Smuzhiyun     uint32_t handle;
41*4882a593Smuzhiyun };
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun static struct drm_surface *drm_surfaces[2];
44*4882a593Smuzhiyun static int current_buffer;
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun static drmModeCrtc *main_monitor_crtc;
47*4882a593Smuzhiyun static drmModeConnector *main_monitor_connector;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun static int drm_fd = -1;
50*4882a593Smuzhiyun 
drm_disable_crtc(int drm_fd,drmModeCrtc * crtc)51*4882a593Smuzhiyun static void drm_disable_crtc(int drm_fd, drmModeCrtc *crtc)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun     if (crtc) {
54*4882a593Smuzhiyun         drmModeSetCrtc(drm_fd, crtc->crtc_id,
55*4882a593Smuzhiyun                        0, // fb_id
56*4882a593Smuzhiyun                        0, 0,  // x,y
57*4882a593Smuzhiyun                        NULL,  // connectors
58*4882a593Smuzhiyun                        0,     // connector_count
59*4882a593Smuzhiyun                        NULL); // mode
60*4882a593Smuzhiyun     }
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun 
drm_enable_crtc(int drm_fd,drmModeCrtc * crtc,struct drm_surface * surface)63*4882a593Smuzhiyun static void drm_enable_crtc(int drm_fd, drmModeCrtc *crtc,
64*4882a593Smuzhiyun                             struct drm_surface *surface)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun     int32_t ret;
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun     ret = drmModeSetCrtc(drm_fd, crtc->crtc_id,
69*4882a593Smuzhiyun                          surface->fb_id,
70*4882a593Smuzhiyun                          0, 0,  // x,y
71*4882a593Smuzhiyun                          &main_monitor_connector->connector_id,
72*4882a593Smuzhiyun                          1,  // connector_count
73*4882a593Smuzhiyun                          &main_monitor_crtc->mode);
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun     if (ret)
76*4882a593Smuzhiyun         printf("drmModeSetCrtc failed ret=%d\n", ret);
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun 
drm_blank(minui_backend * backend,bool blank)79*4882a593Smuzhiyun static void drm_blank(minui_backend* backend, bool blank)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun     if (blank)
82*4882a593Smuzhiyun         drm_disable_crtc(drm_fd, main_monitor_crtc);
83*4882a593Smuzhiyun     else
84*4882a593Smuzhiyun         drm_enable_crtc(drm_fd, main_monitor_crtc,
85*4882a593Smuzhiyun                         drm_surfaces[current_buffer]);
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun 
drm_destroy_surface(struct drm_surface * surface)88*4882a593Smuzhiyun static void drm_destroy_surface(struct drm_surface *surface)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun     struct drm_gem_close gem_close;
91*4882a593Smuzhiyun     int ret;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun     if (!surface)
94*4882a593Smuzhiyun         return;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun     if (surface->base.data)
97*4882a593Smuzhiyun         munmap(surface->base.data,
98*4882a593Smuzhiyun                surface->base.row_bytes * surface->base.height);
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun     if (surface->fb_id) {
101*4882a593Smuzhiyun         ret = drmModeRmFB(drm_fd, surface->fb_id);
102*4882a593Smuzhiyun         if (ret)
103*4882a593Smuzhiyun             printf("drmModeRmFB failed ret=%d\n", ret);
104*4882a593Smuzhiyun     }
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun     if (surface->handle) {
107*4882a593Smuzhiyun         memset(&gem_close, 0, sizeof(gem_close));
108*4882a593Smuzhiyun         gem_close.handle = surface->handle;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun         ret = drmIoctl(drm_fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
111*4882a593Smuzhiyun         if (ret)
112*4882a593Smuzhiyun             printf("DRM_IOCTL_GEM_CLOSE failed ret=%d\n", ret);
113*4882a593Smuzhiyun     }
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun     free(surface);
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun 
drm_format_to_bpp(uint32_t format)118*4882a593Smuzhiyun static int drm_format_to_bpp(uint32_t format)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun     switch (format) {
121*4882a593Smuzhiyun     case DRM_FORMAT_ABGR8888:
122*4882a593Smuzhiyun     case DRM_FORMAT_BGRA8888:
123*4882a593Smuzhiyun     case DRM_FORMAT_RGBX8888:
124*4882a593Smuzhiyun     case DRM_FORMAT_BGRX8888:
125*4882a593Smuzhiyun     case DRM_FORMAT_XBGR8888:
126*4882a593Smuzhiyun     case DRM_FORMAT_XRGB8888:
127*4882a593Smuzhiyun         return 32;
128*4882a593Smuzhiyun     case DRM_FORMAT_RGB565:
129*4882a593Smuzhiyun         return 16;
130*4882a593Smuzhiyun     default:
131*4882a593Smuzhiyun         printf("Unknown format %d\n", format);
132*4882a593Smuzhiyun         return 32;
133*4882a593Smuzhiyun     }
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun 
drm_create_surface(int width,int height)136*4882a593Smuzhiyun static struct drm_surface *drm_create_surface(int width, int height)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun     struct drm_surface *surface;
139*4882a593Smuzhiyun     struct drm_mode_create_dumb create_dumb;
140*4882a593Smuzhiyun     uint32_t format;
141*4882a593Smuzhiyun     int ret;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun     surface = (struct drm_surface*)calloc(1, sizeof(*surface));
144*4882a593Smuzhiyun     if (!surface) {
145*4882a593Smuzhiyun         printf("Can't allocate memory\n");
146*4882a593Smuzhiyun         return NULL;
147*4882a593Smuzhiyun     }
148*4882a593Smuzhiyun #define RECOVERY_RGBX
149*4882a593Smuzhiyun #if defined(RECOVERY_ABGR)
150*4882a593Smuzhiyun     format = DRM_FORMAT_RGBA8888;
151*4882a593Smuzhiyun #elif defined(RECOVERY_BGRA)
152*4882a593Smuzhiyun     format = DRM_FORMAT_ARGB8888;
153*4882a593Smuzhiyun #elif defined(RECOVERY_RGBX)
154*4882a593Smuzhiyun     format = DRM_FORMAT_XBGR8888;
155*4882a593Smuzhiyun #else
156*4882a593Smuzhiyun     format = DRM_FORMAT_RGB565;
157*4882a593Smuzhiyun #endif
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun     memset(&create_dumb, 0, sizeof(create_dumb));
160*4882a593Smuzhiyun     create_dumb.height = height;
161*4882a593Smuzhiyun     create_dumb.width = width;
162*4882a593Smuzhiyun     create_dumb.bpp = drm_format_to_bpp(format);
163*4882a593Smuzhiyun     create_dumb.flags = 0;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun     ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb);
166*4882a593Smuzhiyun     if (ret) {
167*4882a593Smuzhiyun         printf("DRM_IOCTL_MODE_CREATE_DUMB failed ret=%d\n", ret);
168*4882a593Smuzhiyun         drm_destroy_surface(surface);
169*4882a593Smuzhiyun         return NULL;
170*4882a593Smuzhiyun     }
171*4882a593Smuzhiyun     surface->handle = create_dumb.handle;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun     uint32_t handles[4], pitches[4], offsets[4];
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun     handles[0] = surface->handle;
176*4882a593Smuzhiyun     pitches[0] = create_dumb.pitch;
177*4882a593Smuzhiyun     offsets[0] = 0;
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun     ret = drmModeAddFB2(drm_fd, width, height,
180*4882a593Smuzhiyun                         format, handles, pitches, offsets,
181*4882a593Smuzhiyun                         &(surface->fb_id), 0);
182*4882a593Smuzhiyun     if (ret) {
183*4882a593Smuzhiyun         printf("drmModeAddFB2 failed ret=%d\n", ret);
184*4882a593Smuzhiyun         drm_destroy_surface(surface);
185*4882a593Smuzhiyun         return NULL;
186*4882a593Smuzhiyun     }
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun     struct drm_mode_map_dumb map_dumb;
189*4882a593Smuzhiyun     memset(&map_dumb, 0, sizeof(map_dumb));
190*4882a593Smuzhiyun     map_dumb.handle = create_dumb.handle;
191*4882a593Smuzhiyun     ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb);
192*4882a593Smuzhiyun     if (ret) {
193*4882a593Smuzhiyun         printf("DRM_IOCTL_MODE_MAP_DUMB failed ret=%d\n", ret);
194*4882a593Smuzhiyun         drm_destroy_surface(surface);
195*4882a593Smuzhiyun         return NULL;;
196*4882a593Smuzhiyun     }
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun     surface->base.height = height;
199*4882a593Smuzhiyun     surface->base.width = width;
200*4882a593Smuzhiyun     surface->base.row_bytes = create_dumb.pitch;
201*4882a593Smuzhiyun     surface->base.pixel_bytes = create_dumb.bpp / 8;
202*4882a593Smuzhiyun     surface->base.data = (unsigned char*)
203*4882a593Smuzhiyun                          mmap(NULL,
204*4882a593Smuzhiyun                               surface->base.height * surface->base.row_bytes,
205*4882a593Smuzhiyun                               PROT_READ | PROT_WRITE, MAP_SHARED,
206*4882a593Smuzhiyun                               drm_fd, map_dumb.offset);
207*4882a593Smuzhiyun     if (surface->base.data == MAP_FAILED) {
208*4882a593Smuzhiyun         perror("mmap() failed");
209*4882a593Smuzhiyun         drm_destroy_surface(surface);
210*4882a593Smuzhiyun         return NULL;
211*4882a593Smuzhiyun     }
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun     return surface;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun 
find_crtc_for_connector(int fd,drmModeRes * resources,drmModeConnector * connector)216*4882a593Smuzhiyun static drmModeCrtc *find_crtc_for_connector(int fd,
217*4882a593Smuzhiyun                                             drmModeRes *resources,
218*4882a593Smuzhiyun                                             drmModeConnector *connector)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun     int i, j;
221*4882a593Smuzhiyun     drmModeEncoder *encoder;
222*4882a593Smuzhiyun     int32_t crtc;
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun     /*
225*4882a593Smuzhiyun      * Find the encoder. If we already have one, just use it.
226*4882a593Smuzhiyun      */
227*4882a593Smuzhiyun     if (connector->encoder_id)
228*4882a593Smuzhiyun         encoder = drmModeGetEncoder(fd, connector->encoder_id);
229*4882a593Smuzhiyun     else
230*4882a593Smuzhiyun         encoder = NULL;
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun     if (encoder && encoder->crtc_id) {
233*4882a593Smuzhiyun         crtc = encoder->crtc_id;
234*4882a593Smuzhiyun         drmModeFreeEncoder(encoder);
235*4882a593Smuzhiyun         return drmModeGetCrtc(fd, crtc);
236*4882a593Smuzhiyun     }
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun     /*
239*4882a593Smuzhiyun      * Didn't find anything, try to find a crtc and encoder combo.
240*4882a593Smuzhiyun      */
241*4882a593Smuzhiyun     crtc = -1;
242*4882a593Smuzhiyun     for (i = 0; i < connector->count_encoders; i++) {
243*4882a593Smuzhiyun         encoder = drmModeGetEncoder(fd, connector->encoders[i]);
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun         if (encoder) {
246*4882a593Smuzhiyun             for (j = 0; j < resources->count_crtcs; j++) {
247*4882a593Smuzhiyun                 if (!(encoder->possible_crtcs & (1 << j)))
248*4882a593Smuzhiyun                     continue;
249*4882a593Smuzhiyun                 crtc = resources->crtcs[j];
250*4882a593Smuzhiyun                 break;
251*4882a593Smuzhiyun             }
252*4882a593Smuzhiyun             if (crtc >= 0) {
253*4882a593Smuzhiyun                 drmModeFreeEncoder(encoder);
254*4882a593Smuzhiyun                 return drmModeGetCrtc(fd, crtc);
255*4882a593Smuzhiyun             }
256*4882a593Smuzhiyun         }
257*4882a593Smuzhiyun     }
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun     return NULL;
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun 
find_used_connector_by_type(int fd,drmModeRes * resources,unsigned type)262*4882a593Smuzhiyun static drmModeConnector *find_used_connector_by_type(int fd,
263*4882a593Smuzhiyun                                                      drmModeRes *resources,
264*4882a593Smuzhiyun                                                      unsigned type)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun     int i;
267*4882a593Smuzhiyun     for (i = 0; i < resources->count_connectors; i++) {
268*4882a593Smuzhiyun         drmModeConnector *connector;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun         connector = drmModeGetConnector(fd, resources->connectors[i]);
271*4882a593Smuzhiyun         if (connector) {
272*4882a593Smuzhiyun             if ((connector->connector_type == type) &&
273*4882a593Smuzhiyun                 (connector->connection == DRM_MODE_CONNECTED) &&
274*4882a593Smuzhiyun                 (connector->count_modes > 0))
275*4882a593Smuzhiyun                 return connector;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun             drmModeFreeConnector(connector);
278*4882a593Smuzhiyun         }
279*4882a593Smuzhiyun     }
280*4882a593Smuzhiyun     return NULL;
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun 
find_first_connected_connector(int fd,drmModeRes * resources)283*4882a593Smuzhiyun static drmModeConnector *find_first_connected_connector(int fd,
284*4882a593Smuzhiyun                                                         drmModeRes *resources)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun     int i;
287*4882a593Smuzhiyun     for (i = 0; i < resources->count_connectors; i++) {
288*4882a593Smuzhiyun         drmModeConnector *connector;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun         connector = drmModeGetConnector(fd, resources->connectors[i]);
291*4882a593Smuzhiyun         if (connector) {
292*4882a593Smuzhiyun             if ((connector->count_modes > 0) &&
293*4882a593Smuzhiyun                 (connector->connection == DRM_MODE_CONNECTED))
294*4882a593Smuzhiyun                 return connector;
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun             drmModeFreeConnector(connector);
297*4882a593Smuzhiyun         }
298*4882a593Smuzhiyun     }
299*4882a593Smuzhiyun     return NULL;
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun 
find_main_monitor(int fd,drmModeRes * resources,uint32_t * mode_index)302*4882a593Smuzhiyun static drmModeConnector *find_main_monitor(int fd, drmModeRes *resources,
303*4882a593Smuzhiyun                                            uint32_t *mode_index)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun     unsigned i = 0;
306*4882a593Smuzhiyun     int modes;
307*4882a593Smuzhiyun     /* Look for LVDS/eDP/DSI connectors. Those are the main screens. */
308*4882a593Smuzhiyun     unsigned kConnectorPriority[] = {
309*4882a593Smuzhiyun         DRM_MODE_CONNECTOR_LVDS,
310*4882a593Smuzhiyun         DRM_MODE_CONNECTOR_eDP,
311*4882a593Smuzhiyun         DRM_MODE_CONNECTOR_DSI,
312*4882a593Smuzhiyun     };
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun     drmModeConnector *main_monitor_connector = NULL;
315*4882a593Smuzhiyun     do {
316*4882a593Smuzhiyun         main_monitor_connector = find_used_connector_by_type(fd,
317*4882a593Smuzhiyun                                                              resources,
318*4882a593Smuzhiyun                                                              kConnectorPriority[i]);
319*4882a593Smuzhiyun         i++;
320*4882a593Smuzhiyun     } while (!main_monitor_connector && i < ARRAY_SIZE(kConnectorPriority));
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun     /* If we didn't find a connector, grab the first one that is connected. */
323*4882a593Smuzhiyun     if (!main_monitor_connector)
324*4882a593Smuzhiyun         main_monitor_connector =
325*4882a593Smuzhiyun             find_first_connected_connector(fd, resources);
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun     /* If we still didn't find a connector, give up and return. */
328*4882a593Smuzhiyun     if (!main_monitor_connector)
329*4882a593Smuzhiyun         return NULL;
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun     *mode_index = 0;
332*4882a593Smuzhiyun     for (modes = 0; modes < main_monitor_connector->count_modes; modes++) {
333*4882a593Smuzhiyun         if (main_monitor_connector->modes[modes].type &
334*4882a593Smuzhiyun             DRM_MODE_TYPE_PREFERRED) {
335*4882a593Smuzhiyun             *mode_index = modes;
336*4882a593Smuzhiyun             break;
337*4882a593Smuzhiyun         }
338*4882a593Smuzhiyun     }
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun     return main_monitor_connector;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun 
disable_non_main_crtcs(int fd,drmModeRes * resources,drmModeCrtc * main_crtc)343*4882a593Smuzhiyun static void disable_non_main_crtcs(int fd,
344*4882a593Smuzhiyun                                    drmModeRes *resources,
345*4882a593Smuzhiyun                                    drmModeCrtc* main_crtc)
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun     int i;
348*4882a593Smuzhiyun     drmModeCrtc* crtc;
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun     for (i = 0; i < resources->count_connectors; i++) {
351*4882a593Smuzhiyun         drmModeConnector *connector;
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun         connector = drmModeGetConnector(fd, resources->connectors[i]);
354*4882a593Smuzhiyun         crtc = find_crtc_for_connector(fd, resources, connector);
355*4882a593Smuzhiyun         if (crtc->crtc_id != main_crtc->crtc_id)
356*4882a593Smuzhiyun             drm_disable_crtc(fd, crtc);
357*4882a593Smuzhiyun         drmModeFreeCrtc(crtc);
358*4882a593Smuzhiyun     }
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun 
drm_init(minui_backend * backend)361*4882a593Smuzhiyun static GRSurface* drm_init(minui_backend* backend)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun     drmModeRes *res = NULL;
364*4882a593Smuzhiyun     uint32_t selected_mode;
365*4882a593Smuzhiyun     char *dev_name;
366*4882a593Smuzhiyun     int width, height;
367*4882a593Smuzhiyun     int ret, i;
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun     /* Consider DRM devices in order. */
370*4882a593Smuzhiyun     for (i = 0; i < DRM_MAX_MINOR; i++) {
371*4882a593Smuzhiyun         uint64_t cap = 0;
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun         ret = asprintf(&dev_name, DRM_DEV_NAME, DRM_DIR_NAME, i);
374*4882a593Smuzhiyun         if (ret < 0)
375*4882a593Smuzhiyun             continue;
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun         drm_fd = open(dev_name, O_RDWR, 0);
378*4882a593Smuzhiyun         free(dev_name);
379*4882a593Smuzhiyun         if (drm_fd < 0)
380*4882a593Smuzhiyun             continue;
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun         /* We need dumb buffers. */
383*4882a593Smuzhiyun         ret = drmGetCap(drm_fd, DRM_CAP_DUMB_BUFFER, &cap);
384*4882a593Smuzhiyun         if (ret || cap == 0) {
385*4882a593Smuzhiyun             close(drm_fd);
386*4882a593Smuzhiyun             continue;
387*4882a593Smuzhiyun         }
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun         res = drmModeGetResources(drm_fd);
390*4882a593Smuzhiyun         if (!res) {
391*4882a593Smuzhiyun             close(drm_fd);
392*4882a593Smuzhiyun             continue;
393*4882a593Smuzhiyun         }
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun         /* Use this device if it has at least one connected monitor. */
396*4882a593Smuzhiyun         if (res->count_crtcs > 0 && res->count_connectors > 0)
397*4882a593Smuzhiyun             if (find_first_connected_connector(drm_fd, res))
398*4882a593Smuzhiyun                 break;
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun         drmModeFreeResources(res);
401*4882a593Smuzhiyun         close(drm_fd);
402*4882a593Smuzhiyun         res = NULL;
403*4882a593Smuzhiyun     }
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun     if (drm_fd < 0 || res == NULL) {
406*4882a593Smuzhiyun         perror("cannot find/open a drm device");
407*4882a593Smuzhiyun         return NULL;
408*4882a593Smuzhiyun     }
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun     main_monitor_connector = find_main_monitor(drm_fd,
411*4882a593Smuzhiyun                                                res, &selected_mode);
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun     if (!main_monitor_connector) {
414*4882a593Smuzhiyun         printf("main_monitor_connector not found\n");
415*4882a593Smuzhiyun         drmModeFreeResources(res);
416*4882a593Smuzhiyun         close(drm_fd);
417*4882a593Smuzhiyun         return NULL;
418*4882a593Smuzhiyun     }
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun     main_monitor_crtc = find_crtc_for_connector(drm_fd, res,
421*4882a593Smuzhiyun                                                 main_monitor_connector);
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun     if (!main_monitor_crtc) {
424*4882a593Smuzhiyun         printf("main_monitor_crtc not found\n");
425*4882a593Smuzhiyun         drmModeFreeResources(res);
426*4882a593Smuzhiyun         close(drm_fd);
427*4882a593Smuzhiyun         return NULL;
428*4882a593Smuzhiyun     }
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun     disable_non_main_crtcs(drm_fd,
431*4882a593Smuzhiyun                            res, main_monitor_crtc);
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun     main_monitor_crtc->mode = main_monitor_connector->modes[selected_mode];
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun     width = main_monitor_crtc->mode.hdisplay;
436*4882a593Smuzhiyun     height = main_monitor_crtc->mode.vdisplay;
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun     drmModeFreeResources(res);
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun     drm_surfaces[0] = drm_create_surface(width, height);
441*4882a593Smuzhiyun     drm_surfaces[1] = drm_create_surface(width, height);
442*4882a593Smuzhiyun     if (!drm_surfaces[0] || !drm_surfaces[1]) {
443*4882a593Smuzhiyun         drm_destroy_surface(drm_surfaces[0]);
444*4882a593Smuzhiyun         drm_destroy_surface(drm_surfaces[1]);
445*4882a593Smuzhiyun         drmModeFreeResources(res);
446*4882a593Smuzhiyun         close(drm_fd);
447*4882a593Smuzhiyun         return NULL;
448*4882a593Smuzhiyun     }
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun     current_buffer = 0;
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun     drm_enable_crtc(drm_fd, main_monitor_crtc, drm_surfaces[1]);
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun     return &(drm_surfaces[0]->base);
455*4882a593Smuzhiyun }
456*4882a593Smuzhiyun 
drm_flip(minui_backend * backend)457*4882a593Smuzhiyun static GRSurface* drm_flip(minui_backend* backend)
458*4882a593Smuzhiyun {
459*4882a593Smuzhiyun     int ret;
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun     ret = drmModePageFlip(drm_fd, main_monitor_crtc->crtc_id,
462*4882a593Smuzhiyun                           drm_surfaces[current_buffer]->fb_id, 0, NULL);
463*4882a593Smuzhiyun     if (ret < 0) {
464*4882a593Smuzhiyun         printf("drmModePageFlip failed ret=%d\n", ret);
465*4882a593Smuzhiyun         return NULL;
466*4882a593Smuzhiyun     }
467*4882a593Smuzhiyun     current_buffer = 1 - current_buffer;
468*4882a593Smuzhiyun     return &(drm_surfaces[current_buffer]->base);
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun 
drm_exit(minui_backend * backend)471*4882a593Smuzhiyun static void drm_exit(minui_backend* backend)
472*4882a593Smuzhiyun {
473*4882a593Smuzhiyun     drm_disable_crtc(drm_fd, main_monitor_crtc);
474*4882a593Smuzhiyun     drm_destroy_surface(drm_surfaces[0]);
475*4882a593Smuzhiyun     drm_destroy_surface(drm_surfaces[1]);
476*4882a593Smuzhiyun     drmModeFreeCrtc(main_monitor_crtc);
477*4882a593Smuzhiyun     drmModeFreeConnector(main_monitor_connector);
478*4882a593Smuzhiyun     close(drm_fd);
479*4882a593Smuzhiyun     drm_fd = -1;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun static minui_backend drm_backend = {
483*4882a593Smuzhiyun     .init = drm_init,
484*4882a593Smuzhiyun     .flip = drm_flip,
485*4882a593Smuzhiyun     .blank = drm_blank,
486*4882a593Smuzhiyun     .exit = drm_exit,
487*4882a593Smuzhiyun };
488*4882a593Smuzhiyun 
open_drm()489*4882a593Smuzhiyun minui_backend* open_drm()
490*4882a593Smuzhiyun {
491*4882a593Smuzhiyun     return &drm_backend;
492*4882a593Smuzhiyun }
493