blob: 0629f84b8049338f17dbcf9862740ffe455fc32b [file] [log] [blame]
Sean Paule0c4c3d2015-01-20 16:56:04 -05001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "hwcomposer-drm"
18
19#include <fcntl.h>
20#include <errno.h>
21#include <sys/param.h>
22
23#include <cutils/log.h>
24
25#include <xf86drm.h>
26#include <xf86drmMode.h>
27#include <drm/drm_fourcc.h>
28
29#include <hardware/hardware.h>
30#include <hardware/hwcomposer.h>
31
32#include <gralloc_drm.h>
33#include <gralloc_drm_priv.h>
34#include <gralloc_drm_handle.h>
35
36#define ARRAY_SIZE(arr) (int)(sizeof(arr) / sizeof((arr)[0]))
37
38#define HWCOMPOSER_DRM_DEVICE "/dev/dri/card0"
39#define MAX_NUM_DISPLAYS 3
40#define UM_PER_INCH 25400
41
42static const uint32_t panel_types[] = {
43 DRM_MODE_CONNECTOR_LVDS,
44 DRM_MODE_CONNECTOR_eDP,
45 DRM_MODE_CONNECTOR_DSI,
46};
47
48struct hwc_drm_display {
49 uint32_t connector_id;
50
51 drmModeModeInfoPtr configs;
52 uint32_t num_configs;
53
54 int active_config;
55 uint32_t active_crtc;
56};
57
58struct hwc_context_t {
59 hwc_composer_device_1_t device;
60
61 int fd;
62 struct drm_module_t *gralloc_module; /* TODO: NUKE THIS */
63
64 hwc_procs_t const *procs;
65
66 struct hwc_drm_display displays[MAX_NUM_DISPLAYS];
67 int num_displays;
68};
69
70static int hwc_get_drm_display(struct hwc_context_t *ctx, int display,
71 struct hwc_drm_display **hd)
72{
73 if (display >= MAX_NUM_DISPLAYS) {
74 ALOGE("Requested display is out-of-bounds %d %d", display,
75 MAX_NUM_DISPLAYS);
76 return -EINVAL;
77 }
78 *hd = &ctx->displays[display];
79 return 0;
80}
81
82static int hwc_prepare_layer(hwc_layer_1_t *layer)
83{
84 /* TODO: We can't handle background right now, defer to sufaceFlinger */
85 if (layer->compositionType == HWC_BACKGROUND) {
86 layer->compositionType = HWC_FRAMEBUFFER;
87 ALOGV("Can't handle background layers yet");
88
89 /* TODO: Support sideband compositions */
90 } else if (layer->compositionType == HWC_SIDEBAND) {
91 layer->compositionType = HWC_FRAMEBUFFER;
92 ALOGV("Can't handle sideband content yet");
93 }
94
95 layer->hints = 0;
96
97 /* TODO: Handle cursor by setting compositionType=HWC_CURSOR_OVERLAY */
98 if (layer->flags & HWC_IS_CURSOR_LAYER) {
99 ALOGV("Can't handle async cursors yet");
100 }
101
102 /* TODO: Handle transformations */
103 if (layer->transform) {
104 ALOGV("Can't handle transformations yet");
105 }
106
107 /* TODO: Handle blending & plane alpha*/
108 if (layer->blending == HWC_BLENDING_PREMULT ||
109 layer->blending == HWC_BLENDING_COVERAGE) {
110 ALOGV("Can't handle blending yet");
111 }
112
113 /* TODO: Handle cropping & scaling */
114
115 return 0;
116}
117
118static int hwc_prepare(hwc_composer_device_1_t */* dev */, size_t num_displays,
119 hwc_display_contents_1_t** display_contents)
120{
121 int ret = 0, i, j;
122
123 /* TODO: Check flags for HWC_GEOMETRY_CHANGED */
124
125 for (i = 0; i < (int)num_displays && i < MAX_NUM_DISPLAYS; i++) {
126 for (j = 0; j < (int)display_contents[i]->numHwLayers; j++) {
127 ret = hwc_prepare_layer(
128 &display_contents[i]->hwLayers[j]);
129 if (ret) {
130 ALOGE("Failed to prepare layer %d:%d", j, i);
131 return ret;
132 }
133 }
134 }
135
136 return ret;
137}
138
139static int hwc_bo_add_fb(hwc_context_t */* ctx */, struct gralloc_drm_bo_t *bo)
140{
141 uint32_t pitches[4] = { 0, 0, 0, 0 };
142 uint32_t handles[4] = { 0, 0, 0, 0 };
143 uint32_t offsets[4] = { 0, 0, 0, 0 };
144 int drm_format;
145
146 pitches[0] = bo->handle->stride;
147 handles[0] = bo->fb_handle;
148
149 switch(bo->handle->format) {
150 case HAL_PIXEL_FORMAT_RGB_888:
151 drm_format = DRM_FORMAT_BGR888;
152 break;
153 case HAL_PIXEL_FORMAT_BGRA_8888:
154 drm_format = DRM_FORMAT_ARGB8888;
155 break;
156 case HAL_PIXEL_FORMAT_RGBX_8888:
157 drm_format = DRM_FORMAT_XBGR8888;
158 break;
159 case HAL_PIXEL_FORMAT_RGBA_8888:
160 drm_format = DRM_FORMAT_ABGR8888;
161 break;
162 case HAL_PIXEL_FORMAT_RGB_565:
163 drm_format = DRM_FORMAT_BGR565;
164 break;
165 case HAL_PIXEL_FORMAT_YV12:
166 drm_format = DRM_FORMAT_YVU420;
167 break;
168 default:
169 ALOGE("error resolving drm format");
170 return -EINVAL;
171 }
172
173 return drmModeAddFB2(bo->drm->fd, bo->handle->width, bo->handle->height,
174 drm_format, handles, pitches, offsets, (uint32_t *) &bo->fb_id,
175 0);
176}
177
178static bool hwc_mode_is_equal(drmModeModeInfoPtr a, drmModeModeInfoPtr b)
179{
180 return a->clock == b->clock &&
181 a->hdisplay == b->hdisplay &&
182 a->hsync_start == b->hsync_start &&
183 a->hsync_end == b->hsync_end &&
184 a->htotal == b->htotal &&
185 a->hskew == b->hskew &&
186 a->vdisplay == b->vdisplay &&
187 a->vsync_start == b->vsync_start &&
188 a->vsync_end == b->vsync_end &&
189 a->vtotal == b->vtotal &&
190 a->vscan == b->vscan &&
191 a->vrefresh == b->vrefresh &&
192 a->flags == b->flags &&
193 a->type == b->type &&
194 !strcmp(a->name, b->name);
195}
196
197static int hwc_set_display(hwc_context_t *ctx, int display,
198 hwc_display_contents_1_t* display_contents)
199{
200 struct hwc_drm_display *hd = NULL;
201 drmModeCrtcPtr crtc;
202 drmModeModeInfoPtr m;
203 hwc_layer_1_t *layer = NULL;
204 int ret, i;
205
206 /* TODO: NUKE THIS */
207 gralloc_drm_t *drm = ctx->gralloc_module->drm;
208 gralloc_drm_handle_t *gr_handle;
209 struct gralloc_drm_bo_t *bo;
210
211 ret = hwc_get_drm_display(ctx, display, &hd);
212 if (ret)
213 return ret;
214
215 if (!hd->active_crtc) {
216 ALOGE("There is no active crtc for display %d", display);
217 return -ENOENT;
218 }
219
220 /*
221 * TODO: We can only support one hw layer atm, so choose either the
222 * first one or the framebuffer target.
223 */
224 if (!display_contents->numHwLayers) {
225 return 0;
226 } else if (display_contents->numHwLayers == 1) {
227 layer = &display_contents->hwLayers[0];
228 } else {
229 for (i = 0; i < (int)display_contents->numHwLayers; i++) {
230 layer = &display_contents->hwLayers[i];
231 if (layer->compositionType == HWC_FRAMEBUFFER_TARGET)
232 break;
233 }
234 if (i == (int)display_contents->numHwLayers) {
235 ALOGE("Could not find a suitable layer for display %d",
236 display);
237 }
238 }
239
240 gr_handle = (gralloc_drm_handle_t *)layer->handle;
241
242 bo = gr_handle->data;
243 if (!bo) {
244 ALOGE("Could not get drm bo from handle");
245 return -EINVAL;
246 }
247
248 if (!bo->fb_id) {
249 ret = hwc_bo_add_fb(ctx, bo);
250 if (ret) {
251 ALOGE("could not create drm fb %d", ret);
252 return ret;
253 }
254 }
255
256 crtc = drmModeGetCrtc(ctx->fd, hd->active_crtc);
257 if (!crtc) {
258 ALOGE("Failed to get crtc for display %d", display);
259 return -ENODEV;
260 }
261
262 m = &hd->configs[hd->active_config];
263
264 /* Do a modeset if we haven't done one, or the mode has changed */
265 if (!crtc->mode_valid || !hwc_mode_is_equal(m, &crtc->mode)) {
266 ret = drmModeSetCrtc(ctx->fd, crtc->crtc_id, bo->fb_id, 0, 0,
267 &hd->connector_id, 1, m);
268 if (ret) {
269 ALOGE("Modeset failed for crtc %d", crtc->crtc_id);
270 goto out;
271 }
272 goto out;
273 }
274
275 ret = drmModePageFlip(ctx->fd, crtc->crtc_id, bo->fb_id, 0, 0);
276 if (ret) {
277 ALOGE("Failed to flip buffer for crtc %d", crtc->crtc_id);
278 goto out;
279 }
280
281out:
282 drmModeFreeCrtc(crtc);
283 return ret;
284}
285
286static int hwc_set(hwc_composer_device_1_t *dev, size_t num_displays,
287 hwc_display_contents_1_t** display_contents)
288{
289 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
290 int ret = 0, i;
291
292 /* TODO: Handle acquire & release fences */
293
294 for (i = 0; i < (int)num_displays && i < MAX_NUM_DISPLAYS; i++) {
295 display_contents[i]->retireFenceFd = -1; /* TODO: sync */
296
297 ret = hwc_set_display(ctx, i, display_contents[i]);
298 }
299
300 return ret;
301}
302
303static int hwc_event_control(struct hwc_composer_device_1 */* dev */,
304 int /* display */, int /* event */, int /* enabled */)
305{
306 int ret;
307
308 /* TODO */
309 return 0;
310}
311
312static int hwc_set_power_mode(struct hwc_composer_device_1* dev, int display,
313 int mode)
314{
315 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
316 struct hwc_drm_display *hd = NULL;
317 drmModeConnectorPtr c;
318 int ret, i;
319 uint32_t dpms_prop = 0;
320 uint64_t dpms_value = 0;
321
322 ret = hwc_get_drm_display(ctx, display, &hd);
323 if (ret)
324 return ret;
325
326 c = drmModeGetConnector(ctx->fd, hd->connector_id);
327 if (!c) {
328 ALOGE("Failed to get connector %d", display);
329 return -ENODEV;
330 }
331
332 for (i = 0; !dpms_prop && i < c->count_props; i++) {
333 drmModePropertyPtr p;
334
335 p = drmModeGetProperty(ctx->fd, c->props[i]);
336 if (!p)
337 continue;
338
339 if (!strcmp(p->name, "DPMS"))
340 dpms_prop = c->props[i];
341
342 drmModeFreeProperty(p);
343 }
344 if (!dpms_prop) {
345 ALOGE("Failed to get DPMS property from display %d", display);
346 ret = -ENOENT;
347 goto out;
348 }
349
350 switch(mode) {
351 case HWC_POWER_MODE_OFF:
352 dpms_value = DRM_MODE_DPMS_OFF;
353 break;
354
355 /* We can't support dozing right now, so go full on */
356 case HWC_POWER_MODE_DOZE:
357 case HWC_POWER_MODE_DOZE_SUSPEND:
358 case HWC_POWER_MODE_NORMAL:
359 dpms_value = DRM_MODE_DPMS_ON;
360 break;
361 };
362
363 ret = drmModeConnectorSetProperty(ctx->fd, c->connector_id,
364 dpms_prop, dpms_value);
365 if (ret) {
366 ALOGE("Failed to set DPMS property for display %d", display);
367 goto out;
368 }
369
370out:
371 drmModeFreeConnector(c);
372 return ret;
373}
374
375static int hwc_query(struct hwc_composer_device_1 */* dev */, int what,
376 int *value)
377{
378 switch(what) {
379 case HWC_BACKGROUND_LAYER_SUPPORTED:
380 *value = 0; /* TODO: We should do this */
381 break;
382 case HWC_VSYNC_PERIOD:
383 ALOGW("Query for deprecated vsync value, returning 60Hz");
384 *value = 1000 * 1000 * 1000 / 60;
385 break;
386 case HWC_DISPLAY_TYPES_SUPPORTED:
387 *value = HWC_DISPLAY_PRIMARY | HWC_DISPLAY_EXTERNAL;
388 break;
389 }
390 return 0;
391}
392
393static void hwc_register_procs(struct hwc_composer_device_1* dev,
394 hwc_procs_t const* procs)
395{
396 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
397
398 ctx->procs = procs;
399}
400
401static int hwc_get_display_configs(struct hwc_composer_device_1* dev,
402 int display, uint32_t* configs, size_t* numConfigs)
403{
404 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
405 struct hwc_drm_display *hd = NULL;
406 drmModeConnectorPtr c;
407 int ret = 0, i;
408
409 if (!*numConfigs)
410 return 0;
411
412 ret = hwc_get_drm_display(ctx, display, &hd);
413 if (ret)
414 return ret;
415
416 c = drmModeGetConnector(ctx->fd, hd->connector_id);
417 if (!c) {
418 ALOGE("Failed to get connector %d", display);
419 return -ENODEV;
420 }
421
422 if (hd->configs)
423 free(hd->configs);
424
425 hd->active_config = -1;
426 hd->configs = (drmModeModeInfoPtr)calloc(c->count_modes,
427 sizeof(*hd->configs));
428 if (!hd->configs) {
429 ALOGE("Failed to allocate config list for display %d", display);
430 ret = -ENOMEM;
431 hd->num_configs = 0;
432 goto out;
433 }
434
435 for (i = 0; i < c->count_modes; i++) {
436 drmModeModeInfoPtr m = &hd->configs[i];
437
438 memcpy(m, &c->modes[i], sizeof(*m));
439
440 if (i < (int)*numConfigs)
441 configs[i] = i;
442 }
443
444 hd->num_configs = c->count_modes;
445 *numConfigs = MIN(c->count_modes, *numConfigs);
446
447out:
448 drmModeFreeConnector(c);
449 return ret;
450}
451
452static int hwc_check_config_valid(struct hwc_context_t *ctx,
453 drmModeConnectorPtr connector, int display,
454 int config_idx)
455{
456 struct hwc_drm_display *hd = NULL;
457 drmModeModeInfoPtr m = NULL;
458 int ret = 0, i;
459
460 ret = hwc_get_drm_display(ctx, display, &hd);
461 if (ret)
462 return ret;
463
464 /* Make sure the requested config is still valid for the display */
465 for (i = 0; i < connector->count_modes; i++) {
466 if (hwc_mode_is_equal(&connector->modes[i],
467 &hd->configs[config_idx])) {
468 m = &hd->configs[config_idx];
469 break;
470 }
471 }
472 if (!m)
473 return -ENOENT;
474
475 return 0;
476}
477
478static int hwc_get_display_attributes(struct hwc_composer_device_1* dev,
479 int display, uint32_t config, const uint32_t* attributes,
480 int32_t* values)
481{
482 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
483 struct hwc_drm_display *hd = NULL;
484 drmModeConnectorPtr c;
485 drmModeModeInfoPtr m;
486 int ret, i;
487
488 ret = hwc_get_drm_display(ctx, display, &hd);
489 if (ret)
490 return ret;
491
492 if (config >= hd->num_configs) {
493 ALOGE("Requested config is out-of-bounds %d %d", config,
494 hd->num_configs);
495 return -EINVAL;
496 }
497
498 c = drmModeGetConnector(ctx->fd, hd->connector_id);
499 if (!c) {
500 ALOGE("Failed to get connector %d", display);
501 return -ENODEV;
502 }
503
504 ret = hwc_check_config_valid(ctx, c, display, (int)config);
505 if (ret) {
506 ALOGE("Provided config is no longer valid %u", config);
507 goto out;
508 }
509
510 m = &hd->configs[config];
511 for (i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) {
512 switch(attributes[i]) {
513 case HWC_DISPLAY_VSYNC_PERIOD:
514 values[i] = 1000 * 1000 * 1000 / m->vrefresh;
515 break;
516 case HWC_DISPLAY_WIDTH:
517 values[i] = m->hdisplay;
518 break;
519 case HWC_DISPLAY_HEIGHT:
520 values[i] = m->vdisplay;
521 break;
522 case HWC_DISPLAY_DPI_X:
523 /* Dots per 1000 inches */
524 values[i] = c->mmWidth ?
525 (m->hdisplay * UM_PER_INCH) / c->mmWidth : 0;
526 break;
527 case HWC_DISPLAY_DPI_Y:
528 /* Dots per 1000 inches */
529 values[i] = c->mmHeight ?
530 (m->vdisplay * UM_PER_INCH) / c->mmHeight : 0;
531 break;
532 }
533 }
534
535out:
536 drmModeFreeConnector(c);
537 return ret;
538}
539
540static int hwc_get_active_config(struct hwc_composer_device_1* dev, int display)
541{
542 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
543 struct hwc_drm_display *hd = NULL;
544 drmModeConnectorPtr c;
545 int ret;
546
547 ret = hwc_get_drm_display(ctx, display, &hd);
548 if (ret)
549 return ret;
550
551 if (hd->active_config < 0)
552 return -1;
553
554 c = drmModeGetConnector(ctx->fd, hd->connector_id);
555 if (!c) {
556 ALOGE("Failed to get connector %d", display);
557 return -ENODEV;
558 }
559
560 ret = hwc_check_config_valid(ctx, c, display, hd->active_config);
561 if (ret) {
562 ALOGE("Config is no longer valid %d", hd->active_config);
563 ret = -1;
564 goto out;
565 }
566
567 ret = hd->active_config;
568
569out:
570 drmModeFreeConnector(c);
571 return ret;
572}
573
574static bool hwc_crtc_is_bound(struct hwc_context_t *ctx, uint32_t crtc_id)
575{
576 int i;
577
578 for (i = 0; i < MAX_NUM_DISPLAYS; i++) {
579 if (ctx->displays[i].active_crtc == crtc_id)
580 return true;
581 }
582 return false;
583}
584
585static int hwc_try_encoder(struct hwc_context_t *ctx, drmModeResPtr r,
586 uint32_t encoder_id, uint32_t *crtc_id)
587{
588 drmModeEncoderPtr e;
589 int ret, i;
590
591 e = drmModeGetEncoder(ctx->fd, encoder_id);
592 if (!e) {
593 ALOGE("Failed to get encoder for connector %d", encoder_id);
594 return -ENODEV;
595 }
596
597 /* First try to use the currently-bound crtc */
598 if (e->crtc_id) {
599 if (!hwc_crtc_is_bound(ctx, e->crtc_id)) {
600 *crtc_id = e->crtc_id;
601 ret = 0;
602 goto out;
603 }
604 }
605
606 /* Try to find a possible crtc which will work */
607 for (i = 0; i < r->count_crtcs; i++) {
608 if (!(e->possible_crtcs & (1 << i)))
609 continue;
610
611 /* We've already tried this earlier */
612 if (e->crtc_id == r->crtcs[i])
613 continue;
614
615 if (!hwc_crtc_is_bound(ctx, r->crtcs[i])) {
616 *crtc_id = r->crtcs[i];
617 ret = 0;
618 goto out;
619 }
620 }
621
622 /* We can't use the encoder, but nothing went wrong, try another one */
623 ret = -EAGAIN;
624
625out:
626 drmModeFreeEncoder(e);
627 return ret;
628}
629
630static int hwc_set_active_config(struct hwc_composer_device_1* dev, int display,
631 int index)
632{
633 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
634 struct hwc_drm_display *hd = NULL;
635 drmModeResPtr r = NULL;
636 drmModeConnectorPtr c;
637 uint32_t crtc_id = 0;
638 int ret, i;
639 bool new_crtc, new_encoder;
640
641 ret = hwc_get_drm_display(ctx, display, &hd);
642 if (ret)
643 return ret;
644
645 c = drmModeGetConnector(ctx->fd, hd->connector_id);
646 if (!c) {
647 ALOGE("Failed to get connector %d", display);
648 return -ENODEV;
649 }
650
651 if (c->connection == DRM_MODE_DISCONNECTED) {
652 ALOGE("Tried to configure a disconnected display %d", display);
653 ret = -ENODEV;
654 goto out;
655 }
656
657 ret = hwc_check_config_valid(ctx, c, display, index);
658 if (ret) {
659 ALOGE("Provided config is no longer valid %u", index);
660 ret = -ENOENT;
661 goto out;
662 }
663
664 r = drmModeGetResources(ctx->fd);
665 if (!r) {
666 ALOGE("Failed to get drm resources");
667 goto out;
668 }
669
670 /* We no longer have an active_crtc */
671 hd->active_crtc = 0;
672
673 /* First, try to use the currently-connected encoder */
674 if (c->encoder_id) {
675 ret = hwc_try_encoder(ctx, r, c->encoder_id, &crtc_id);
676 if (ret && ret != -EAGAIN) {
677 ALOGE("Encoder try failed %d", ret);
678 goto out;
679 }
680 }
681
682 /* We couldn't find a crtc with the attached encoder, try the others */
683 if (!crtc_id) {
684 for (i = 0; i < c->count_encoders; i++) {
685 ret = hwc_try_encoder(ctx, r, c->encoders[i], &crtc_id);
686 if (!ret) {
687 break;
688 } else if (ret != -EAGAIN) {
689 ALOGE("Encoder try failed %d", ret);
690 goto out;
691 }
692 }
693 if (!crtc_id) {
694 ALOGE("Couldn't find valid crtc to modeset");
695 ret = -EINVAL;
696 goto out;
697 }
698 }
699
700 hd->active_crtc = crtc_id;
701 hd->active_config = index;
702
703 /* TODO: Once we have atomic, set the crtc timing info here */
704
705out:
706 if (r)
707 drmModeFreeResources(r);
708
709 drmModeFreeConnector(c);
710 return ret;
711}
712
713static int hwc_device_close(struct hw_device_t *dev)
714{
715 struct hwc_context_t *ctx = (struct hwc_context_t *)dev;
716
717 free(ctx);
718
719 return 0;
720}
721
722static int hwc_initialize_display(struct hwc_context_t *ctx, int display,
723 uint32_t connector_id)
724{
725 struct hwc_drm_display *hd = NULL;
726 int ret;
727
728 ret = hwc_get_drm_display(ctx, display, &hd);
729 if (ret)
730 return ret;
731
732 hd->active_config = -1;
733 hd->connector_id = connector_id;
734
735 return 0;
736}
737
738static int hwc_enumerate_displays(struct hwc_context_t *ctx)
739{
740 struct hwc_drm_display *panel_hd;
741 drmModeResPtr res;
742 drmModeConnectorPtr *conn_list;
743 int ret = 0, i, j;
744
745 res = drmModeGetResources(ctx->fd);
746 if (!res) {
747 ALOGE("Failed to get drm resources");
748 return -ENODEV;
749 }
750
751 conn_list = (drmModeConnector **)calloc(res->count_connectors,
752 sizeof(*conn_list));
753 if (!conn_list) {
754 ALOGE("Failed to allocate connector list");
755 ret = -ENOMEM;
756 goto out;
757 }
758
759 for (i = 0; i < res->count_connectors; i++) {
760 conn_list[i] = drmModeGetConnector(ctx->fd, res->connectors[i]);
761 if (!conn_list[i]) {
762 ALOGE("Failed to get connector %d", res->connectors[i]);
763 ret = -ENODEV;
764 goto out;
765 }
766 }
767
768 ctx->num_displays = 0;
769
770 /* Find a connected, panel type connector for display 0 */
771 for (i = 0; i < res->count_connectors; i++) {
772 drmModeConnectorPtr c = conn_list[i];
773
774 for (j = 0; j < ARRAY_SIZE(panel_types); j++) {
775 if (c->connector_type == panel_types[j] &&
776 c->connection == DRM_MODE_CONNECTED)
777 break;
778 }
779 if (j == ARRAY_SIZE(panel_types))
780 continue;
781
782 hwc_initialize_display(ctx, ctx->num_displays, c->connector_id);
783 ctx->num_displays++;
784 break;
785 }
786
787 ret = hwc_get_drm_display(ctx, 0, &panel_hd);
788 if (ret)
789 goto out;
790
791 /* Fill in the other displays */
792 for (i = 0; i < res->count_connectors; i++) {
793 drmModeConnectorPtr c = conn_list[i];
794
795 if (panel_hd->connector_id == c->connector_id)
796 continue;
797
798 hwc_initialize_display(ctx, ctx->num_displays, c->connector_id);
799 ctx->num_displays++;
800 }
801
802out:
803 for (i = 0; i < res->count_connectors; i++) {
804 if (conn_list[i])
805 drmModeFreeConnector(conn_list[i]);
806 }
807 free(conn_list);
808
809 if (res)
810 drmModeFreeResources(res);
811
812 return ret;
813}
814
815static int hwc_device_open(const struct hw_module_t* module, const char* name,
816 struct hw_device_t** dev)
817{
818 int ret = 0;
819 struct hwc_context_t *ctx;
820
821 if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
822 ALOGE("Invalid module name- %s", name);
823 return -EINVAL;
824 }
825
826 ctx = (hwc_context_t *)calloc(1, sizeof(*ctx));
827 if (!ctx) {
828 ALOGE("Failed to allocate hwc context");
829 return -ENOMEM;
830 }
831
832 /* TODO: NUKE THIS */
833 ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
834 (const hw_module_t **)&ctx->gralloc_module);
835 if (ret) {
836 ALOGE("Failed to open gralloc module");
837 goto out;
838 }
839
840 /* TODO: Use drmOpenControl here instead */
841 ctx->fd = open(HWCOMPOSER_DRM_DEVICE, O_RDWR);
842 if (ctx->fd < 0) {
843 ALOGE("Failed to open dri- %s", strerror(-errno));
844 goto out;
845 }
846
847 ret = drmSetMaster(ctx->fd);
848 if (ret) {
849 ALOGE("Failed to set hwcomposer as drm master %d", ret);
850 goto out;
851 }
852
853 ret = hwc_enumerate_displays(ctx);
854 if (ret) {
855 ALOGE("Failed to enumerate displays: %s", strerror(ret));
856 goto out;
857 }
858
859 ctx->device.common.tag = HARDWARE_DEVICE_TAG;
860 ctx->device.common.version = HWC_DEVICE_API_VERSION_1_4;
861 ctx->device.common.module = const_cast<hw_module_t*>(module);
862 ctx->device.common.close = hwc_device_close;
863
864 ctx->device.prepare = hwc_prepare;
865 ctx->device.set = hwc_set;
866 ctx->device.eventControl = hwc_event_control;
867 ctx->device.setPowerMode = hwc_set_power_mode;
868 ctx->device.query = hwc_query;
869 ctx->device.registerProcs = hwc_register_procs;
870 ctx->device.getDisplayConfigs = hwc_get_display_configs;
871 ctx->device.getDisplayAttributes = hwc_get_display_attributes;
872 ctx->device.getActiveConfig = hwc_get_active_config;
873 ctx->device.setActiveConfig = hwc_set_active_config;
874 ctx->device.setCursorPositionAsync = NULL; /* TODO: Add cursor */
875
876 *dev = &ctx->device.common;
877
878 return 0;
879out:
880 if (ctx->fd >= 0)
881 close(ctx->fd);
882
883 free(ctx);
884 return ret;
885}
886
887static struct hw_module_methods_t hwc_module_methods = {
888 open: hwc_device_open
889};
890
891hwc_module_t HAL_MODULE_INFO_SYM = {
892 common: {
893 tag: HARDWARE_MODULE_TAG,
894 version_major: 1,
895 version_minor: 0,
896 id: HWC_HARDWARE_MODULE_ID,
897 name: "DRM hwcomposer module",
898 author: "The Android Open Source Project",
899 methods: &hwc_module_methods,
900 dso: NULL,
901 reserved: { 0 },
902 }
903};