hwc.cpp revision 56d570f1d7eb34ab0db968298efb8e75b849c893
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 * Copyright (C) 2012-2013, The Linux Foundation. All rights reserved.
4 *
5 * Not a Contribution, Apache license notifications and license are retained
6 * for attribution purposes only.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 *      http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20#define ATRACE_TAG ATRACE_TAG_GRAPHICS
21#include <fcntl.h>
22#include <errno.h>
23
24#include <cutils/log.h>
25#include <cutils/atomic.h>
26#include <EGL/egl.h>
27#include <utils/Trace.h>
28#include <sys/ioctl.h>
29#include <overlay.h>
30#include <overlayRotator.h>
31#include <mdp_version.h>
32#include "hwc_utils.h"
33#include "hwc_fbupdate.h"
34#include "hwc_mdpcomp.h"
35#include "hwc_dump_layers.h"
36#include "external.h"
37#include "hwc_copybit.h"
38#include "profiler.h"
39
40using namespace qhwc;
41using namespace overlay;
42
43#define VSYNC_DEBUG 0
44#define BLANK_DEBUG 1
45
46static int hwc_device_open(const struct hw_module_t* module,
47                           const char* name,
48                           struct hw_device_t** device);
49
50static struct hw_module_methods_t hwc_module_methods = {
51    open: hwc_device_open
52};
53
54hwc_module_t HAL_MODULE_INFO_SYM = {
55    common: {
56        tag: HARDWARE_MODULE_TAG,
57        version_major: 2,
58        version_minor: 0,
59        id: HWC_HARDWARE_MODULE_ID,
60        name: "Qualcomm Hardware Composer Module",
61        author: "CodeAurora Forum",
62        methods: &hwc_module_methods,
63        dso: 0,
64        reserved: {0},
65    }
66};
67
68/*
69 * Save callback functions registered to HWC
70 */
71static void hwc_registerProcs(struct hwc_composer_device_1* dev,
72                              hwc_procs_t const* procs)
73{
74    ALOGI("%s", __FUNCTION__);
75    hwc_context_t* ctx = (hwc_context_t*)(dev);
76    if(!ctx) {
77        ALOGE("%s: Invalid context", __FUNCTION__);
78        return;
79    }
80    ctx->proc = procs;
81
82    // Now that we have the functions needed, kick off
83    // the uevent & vsync threads
84    init_uevent_thread(ctx);
85    init_vsync_thread(ctx);
86}
87
88//Helper
89static void reset(hwc_context_t *ctx, int numDisplays,
90                  hwc_display_contents_1_t** displays) {
91    for(int i = 0; i < MAX_DISPLAYS; i++) {
92        hwc_display_contents_1_t *list = displays[i];
93        // XXX:SurfaceFlinger no longer guarantees that this
94        // value is reset on every prepare. However, for the layer
95        // cache we need to reset it.
96        // We can probably rethink that later on
97        if (LIKELY(list && list->numHwLayers > 1)) {
98            for(uint32_t j = 0; j < list->numHwLayers; j++) {
99                if(list->hwLayers[j].compositionType != HWC_FRAMEBUFFER_TARGET)
100                    list->hwLayers[j].compositionType = HWC_FRAMEBUFFER;
101            }
102        }
103
104        if(ctx->mFBUpdate[i])
105            ctx->mFBUpdate[i]->reset();
106        if(ctx->mCopyBit[i])
107            ctx->mCopyBit[i]->reset();
108    }
109}
110
111//clear prev layer prop flags and realloc for current frame
112static void reset_layer_prop(hwc_context_t* ctx, int dpy, int numAppLayers) {
113    if(ctx->layerProp[dpy]) {
114       delete[] ctx->layerProp[dpy];
115       ctx->layerProp[dpy] = NULL;
116    }
117    ctx->layerProp[dpy] = new LayerProp[numAppLayers];
118}
119
120static int display_commit(hwc_context_t *ctx, int dpy) {
121    struct mdp_display_commit commit_info;
122    memset(&commit_info, 0, sizeof(struct mdp_display_commit));
123    commit_info.flags = MDP_DISPLAY_COMMIT_OVERLAY;
124    if(ioctl(ctx->dpyAttr[dpy].fd, MSMFB_DISPLAY_COMMIT, &commit_info) == -1) {
125       ALOGE("%s: MSMFB_DISPLAY_COMMIT for primary failed", __FUNCTION__);
126       return -errno;
127    }
128    return 0;
129}
130
131static int hwc_prepare_primary(hwc_composer_device_1 *dev,
132        hwc_display_contents_1_t *list) {
133    hwc_context_t* ctx = (hwc_context_t*)(dev);
134    const int dpy = HWC_DISPLAY_PRIMARY;
135    if (LIKELY(list && list->numHwLayers > 1) &&
136            ctx->dpyAttr[dpy].isActive) {
137        reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
138        uint32_t last = list->numHwLayers - 1;
139        hwc_layer_1_t *fbLayer = &list->hwLayers[last];
140        if(fbLayer->handle) {
141            setListStats(ctx, list, dpy);
142            int fbZOrder = ctx->mMDPComp[dpy]->prepare(ctx, list);
143            if(fbZOrder >= 0)
144                ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZOrder);
145
146            if (ctx->mMDP.version < qdutils::MDP_V4_0) {
147                if((fbZOrder >= 0) && ctx->mCopyBit[dpy])
148                    ctx->mCopyBit[dpy]->prepare(ctx, list, dpy);
149            }
150        }
151    }
152    return 0;
153}
154
155static int hwc_prepare_external(hwc_composer_device_1 *dev,
156        hwc_display_contents_1_t *list, int dpy) {
157
158    hwc_context_t* ctx = (hwc_context_t*)(dev);
159    Locker::Autolock _l(ctx->mExtLock);
160
161    if (LIKELY(list && list->numHwLayers > 1) &&
162            ctx->dpyAttr[dpy].isActive &&
163            ctx->dpyAttr[dpy].connected) {
164        reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
165        uint32_t last = list->numHwLayers - 1;
166        hwc_layer_1_t *fbLayer = &list->hwLayers[last];
167        if(!ctx->dpyAttr[dpy].isPause) {
168            if(fbLayer->handle) {
169                ctx->mExtDispConfiguring = false;
170                setListStats(ctx, list, dpy);
171                int fbZOrder = ctx->mMDPComp[dpy]->prepare(ctx, list);
172                if(ctx->deviceOrientation &&
173                    ctx->listStats[dpy].isDisplayAnimating) {
174                    fbZOrder = 0;
175                }
176                if(fbZOrder >= 0)
177                    ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZOrder);
178
179                /* Temporarily commenting out C2D until we support partial
180                   copybit composition for mixed mode MDP
181
182                if((fbZOrder >= 0) && ctx->mCopyBit[dpy])
183                    ctx->mCopyBit[dpy]->prepare(ctx, list, dpy);
184                */
185                if(ctx->listStats[dpy].isDisplayAnimating) {
186                    // Mark all app layers as HWC_OVERLAY for external during
187                    // animation, so that SF doesnt draw it on FB
188                    for(int i = 0 ;i < ctx->listStats[dpy].numAppLayers; i++) {
189                        hwc_layer_1_t *layer = &list->hwLayers[i];
190                        layer->compositionType = HWC_OVERLAY;
191                    }
192                }
193            }
194        } else {
195            // External Display is in Pause state.
196            // ToDo:
197            // Mark all application layers as OVERLAY so that
198            // GPU will not compose. This is done for power
199            // optimization
200        }
201    }
202    return 0;
203}
204
205static int hwc_prepare(hwc_composer_device_1 *dev, size_t numDisplays,
206                       hwc_display_contents_1_t** displays)
207{
208    int ret = 0;
209    hwc_context_t* ctx = (hwc_context_t*)(dev);
210    Locker::Autolock _l(ctx->mBlankLock);
211    reset(ctx, numDisplays, displays);
212
213    ctx->mOverlay->configBegin();
214    ctx->mRotMgr->configBegin();
215    Overlay::setDMAMode(Overlay::DMA_LINE_MODE);
216
217    for (int32_t i = numDisplays; i >= 0; i--) {
218        hwc_display_contents_1_t *list = displays[i];
219        switch(i) {
220            case HWC_DISPLAY_PRIMARY:
221                ret = hwc_prepare_primary(dev, list);
222                break;
223            case HWC_DISPLAY_EXTERNAL:
224            case HWC_DISPLAY_VIRTUAL:
225                ret = hwc_prepare_external(dev, list, i);
226                break;
227            default:
228                ret = -EINVAL;
229        }
230    }
231
232    ctx->mOverlay->configDone();
233    ctx->mRotMgr->configDone();
234
235    return ret;
236}
237
238static int hwc_eventControl(struct hwc_composer_device_1* dev, int dpy,
239                             int event, int enable)
240{
241    int ret = 0;
242    hwc_context_t* ctx = (hwc_context_t*)(dev);
243    Locker::Autolock _l(ctx->mBlankLock);
244    switch(event) {
245        case HWC_EVENT_VSYNC:
246            if (ctx->vstate.enable == enable)
247                break;
248            ret = hwc_vsync_control(ctx, dpy, enable);
249            if(ret == 0)
250                ctx->vstate.enable = !!enable;
251            ALOGD_IF (VSYNC_DEBUG, "VSYNC state changed to %s",
252                      (enable)?"ENABLED":"DISABLED");
253            break;
254#ifdef QCOM_BSP
255        case  HWC_EVENT_ORIENTATION:
256            if(dpy == HWC_DISPLAY_PRIMARY) {
257                // store the primary display orientation
258                // will be used in hwc_video::configure to disable
259                // rotation animation on external display
260                ctx->deviceOrientation = enable;
261            }
262            break;
263#endif
264        default:
265            ret = -EINVAL;
266    }
267    return ret;
268}
269
270static int hwc_blank(struct hwc_composer_device_1* dev, int dpy, int blank)
271{
272    ATRACE_CALL();
273    hwc_context_t* ctx = (hwc_context_t*)(dev);
274
275    Locker::Autolock _l(ctx->mBlankLock);
276    int ret = 0;
277    ALOGD_IF(BLANK_DEBUG, "%s: %s display: %d", __FUNCTION__,
278          blank==1 ? "Blanking":"Unblanking", dpy);
279    if(blank) {
280        // free up all the overlay pipes in use
281        // when we get a blank for either display
282        // makes sure that all pipes are freed
283        ctx->mOverlay->configBegin();
284        ctx->mOverlay->configDone();
285        ctx->mRotMgr->clear();
286    }
287    switch(dpy) {
288        case HWC_DISPLAY_PRIMARY:
289            if(blank) {
290                ret = ioctl(ctx->dpyAttr[dpy].fd, FBIOBLANK,FB_BLANK_POWERDOWN);
291
292                if(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected == true) {
293                    // Surfaceflinger does not send Blank/unblank event to hwc
294                    // for virtual display, handle it explicitly when blank for
295                    // primary is invoked, so that any pipes unset get committed
296                    if (display_commit(ctx, HWC_DISPLAY_VIRTUAL) < 0) {
297                        ret = -1;
298                        ALOGE("%s:post failed for virtual display !!",
299                                                            __FUNCTION__);
300                    } else {
301                        ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = !blank;
302                    }
303                }
304            } else {
305                ret = ioctl(ctx->dpyAttr[dpy].fd, FBIOBLANK, FB_BLANK_UNBLANK);
306                if(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected == true) {
307                    ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = !blank;
308                }
309            }
310            break;
311        case HWC_DISPLAY_EXTERNAL:
312            if(blank) {
313                // call external framebuffer commit on blank,
314                // so that any pipe unsets gets committed
315                if (display_commit(ctx, dpy) < 0) {
316                    ret = -1;
317                    ALOGE("%s:post failed for external display !! ",
318                          __FUNCTION__);
319                }
320            } else {
321            }
322            break;
323        default:
324            return -EINVAL;
325    }
326    // Enable HPD here, as during bootup unblank is called
327    // when SF is completely initialized
328    ctx->mExtDisplay->setHPD(1);
329    if(ret == 0){
330        ctx->dpyAttr[dpy].isActive = !blank;
331    } else {
332        ALOGE("%s: Failed in %s display: %d error:%s", __FUNCTION__,
333              blank==1 ? "blanking":"unblanking", dpy, strerror(errno));
334        return ret;
335    }
336
337    ALOGD_IF(BLANK_DEBUG, "%s: Done %s display: %d", __FUNCTION__,
338          blank==1 ? "blanking":"unblanking", dpy);
339    return 0;
340}
341
342static int hwc_query(struct hwc_composer_device_1* dev,
343                     int param, int* value)
344{
345    hwc_context_t* ctx = (hwc_context_t*)(dev);
346    int supported = HWC_DISPLAY_PRIMARY_BIT;
347
348    switch (param) {
349    case HWC_BACKGROUND_LAYER_SUPPORTED:
350        // Not supported for now
351        value[0] = 0;
352        break;
353    case HWC_DISPLAY_TYPES_SUPPORTED:
354        if(ctx->mMDP.hasOverlay)
355            supported |= HWC_DISPLAY_EXTERNAL_BIT;
356        value[0] = supported;
357        break;
358    default:
359        return -EINVAL;
360    }
361    return 0;
362
363}
364
365
366static int hwc_set_primary(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
367    ATRACE_CALL();
368    int ret = 0;
369    const int dpy = HWC_DISPLAY_PRIMARY;
370    if (LIKELY(list) && ctx->dpyAttr[dpy].isActive) {
371        uint32_t last = list->numHwLayers - 1;
372        hwc_layer_1_t *fbLayer = &list->hwLayers[last];
373        int fd = -1; //FenceFD from the Copybit(valid in async mode)
374        bool copybitDone = false;
375        if(ctx->mCopyBit[dpy])
376            copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
377        if(list->numHwLayers > 1)
378            hwc_sync(ctx, list, dpy, fd);
379
380        // Dump the layers for primary
381        if(ctx->mHwcDebug[dpy])
382            ctx->mHwcDebug[dpy]->dumpLayers(list);
383
384        if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
385            ALOGE("%s: MDPComp draw failed", __FUNCTION__);
386            ret = -1;
387        }
388
389        //TODO We dont check for SKIP flag on this layer because we need PAN
390        //always. Last layer is always FB
391        private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
392        if(copybitDone) {
393            hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer();
394        }
395
396        if(hnd) {
397            if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) {
398                ALOGE("%s: FBUpdate draw failed", __FUNCTION__);
399                ret = -1;
400            }
401        }
402
403        if (display_commit(ctx, dpy) < 0) {
404            ALOGE("%s: display commit fail!", __FUNCTION__);
405            ret = -1;
406        }
407    }
408
409    closeAcquireFds(list);
410    return ret;
411}
412
413static int hwc_set_external(hwc_context_t *ctx,
414                            hwc_display_contents_1_t* list, int dpy)
415{
416    ATRACE_CALL();
417    int ret = 0;
418    Locker::Autolock _l(ctx->mExtLock);
419
420    if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
421        !ctx->dpyAttr[dpy].isPause &&
422        ctx->dpyAttr[dpy].connected) {
423        uint32_t last = list->numHwLayers - 1;
424        hwc_layer_1_t *fbLayer = &list->hwLayers[last];
425        int fd = -1; //FenceFD from the Copybit(valid in async mode)
426        bool copybitDone = false;
427        if(ctx->mCopyBit[dpy])
428            copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
429
430        if(list->numHwLayers > 1)
431            hwc_sync(ctx, list, dpy, fd);
432
433        // Dump the layers for external
434        if(ctx->mHwcDebug[dpy])
435            ctx->mHwcDebug[dpy]->dumpLayers(list);
436
437        if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
438            ALOGE("%s: MDPComp draw failed", __FUNCTION__);
439            ret = -1;
440        }
441
442        int extOnlyLayerIndex =
443            ctx->listStats[dpy].extOnlyLayerIndex;
444
445        private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
446        if(extOnlyLayerIndex!= -1) {
447            hwc_layer_1_t *extLayer = &list->hwLayers[extOnlyLayerIndex];
448            hnd = (private_handle_t *)extLayer->handle;
449        } else if(copybitDone) {
450            hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer();
451        }
452
453        if(hnd && !isYuvBuffer(hnd)) {
454            if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) {
455                ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
456                ret = -1;
457            }
458        }
459
460        if (display_commit(ctx, dpy) < 0) {
461            ALOGE("%s: display commit fail!", __FUNCTION__);
462            ret = -1;
463        }
464    }
465
466    closeAcquireFds(list);
467    return ret;
468}
469
470static int hwc_set(hwc_composer_device_1 *dev,
471                   size_t numDisplays,
472                   hwc_display_contents_1_t** displays)
473{
474    int ret = 0;
475    hwc_context_t* ctx = (hwc_context_t*)(dev);
476    Locker::Autolock _l(ctx->mBlankLock);
477    for (uint32_t i = 0; i <= numDisplays; i++) {
478        hwc_display_contents_1_t* list = displays[i];
479        switch(i) {
480            case HWC_DISPLAY_PRIMARY:
481                ret = hwc_set_primary(ctx, list);
482                break;
483            case HWC_DISPLAY_EXTERNAL:
484            case HWC_DISPLAY_VIRTUAL:
485            /* ToDo: We are using hwc_set_external path for both External and
486                     Virtual displays on HWC1.1. Eventually, we will have
487                     separate functions when we move to HWC1.2
488            */
489                ret = hwc_set_external(ctx, list, i);
490                break;
491            default:
492                ret = -EINVAL;
493        }
494    }
495    // This is only indicative of how many times SurfaceFlinger posts
496    // frames to the display.
497    CALC_FPS();
498    MDPComp::resetIdleFallBack();
499    ctx->mVideoTransFlag = false;
500    return ret;
501}
502
503int hwc_getDisplayConfigs(struct hwc_composer_device_1* dev, int disp,
504        uint32_t* configs, size_t* numConfigs) {
505    int ret = 0;
506    hwc_context_t* ctx = (hwc_context_t*)(dev);
507    //in 1.1 there is no way to choose a config, report as config id # 0
508    //This config is passed to getDisplayAttributes. Ignore for now.
509    switch(disp) {
510        case HWC_DISPLAY_PRIMARY:
511            if(*numConfigs > 0) {
512                configs[0] = 0;
513                *numConfigs = 1;
514            }
515            ret = 0; //NO_ERROR
516            break;
517        case HWC_DISPLAY_EXTERNAL:
518            ret = -1; //Not connected
519            if(ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected) {
520                ret = 0; //NO_ERROR
521                if(*numConfigs > 0) {
522                    configs[0] = 0;
523                    *numConfigs = 1;
524                }
525            }
526            break;
527    }
528    return ret;
529}
530
531int hwc_getDisplayAttributes(struct hwc_composer_device_1* dev, int disp,
532        uint32_t config, const uint32_t* attributes, int32_t* values) {
533
534    hwc_context_t* ctx = (hwc_context_t*)(dev);
535    //If hotpluggable displays are inactive return error
536    if(disp == HWC_DISPLAY_EXTERNAL && !ctx->dpyAttr[disp].connected) {
537        return -1;
538    }
539
540    //From HWComposer
541    static const uint32_t DISPLAY_ATTRIBUTES[] = {
542        HWC_DISPLAY_VSYNC_PERIOD,
543        HWC_DISPLAY_WIDTH,
544        HWC_DISPLAY_HEIGHT,
545        HWC_DISPLAY_DPI_X,
546        HWC_DISPLAY_DPI_Y,
547        HWC_DISPLAY_NO_ATTRIBUTE,
548    };
549
550    const int NUM_DISPLAY_ATTRIBUTES = (sizeof(DISPLAY_ATTRIBUTES) /
551            sizeof(DISPLAY_ATTRIBUTES)[0]);
552
553    for (size_t i = 0; i < NUM_DISPLAY_ATTRIBUTES - 1; i++) {
554        switch (attributes[i]) {
555        case HWC_DISPLAY_VSYNC_PERIOD:
556            values[i] = ctx->dpyAttr[disp].vsync_period;
557            break;
558        case HWC_DISPLAY_WIDTH:
559            values[i] = ctx->dpyAttr[disp].xres;
560            ALOGD("%s disp = %d, width = %d",__FUNCTION__, disp,
561                    ctx->dpyAttr[disp].xres);
562            break;
563        case HWC_DISPLAY_HEIGHT:
564            values[i] = ctx->dpyAttr[disp].yres;
565            ALOGD("%s disp = %d, height = %d",__FUNCTION__, disp,
566                    ctx->dpyAttr[disp].yres);
567            break;
568        case HWC_DISPLAY_DPI_X:
569            values[i] = (int32_t) (ctx->dpyAttr[disp].xdpi*1000.0);
570            break;
571        case HWC_DISPLAY_DPI_Y:
572            values[i] = (int32_t) (ctx->dpyAttr[disp].ydpi*1000.0);
573            break;
574        default:
575            ALOGE("Unknown display attribute %d",
576                    attributes[i]);
577            return -EINVAL;
578        }
579    }
580    return 0;
581}
582
583void hwc_dump(struct hwc_composer_device_1* dev, char *buff, int buff_len)
584{
585    hwc_context_t* ctx = (hwc_context_t*)(dev);
586    android::String8 aBuf("");
587    dumpsys_log(aBuf, "Qualcomm HWC state:\n");
588    dumpsys_log(aBuf, "  MDPVersion=%d\n", ctx->mMDP.version);
589    dumpsys_log(aBuf, "  DisplayPanel=%c\n", ctx->mMDP.panel);
590    for(int dpy = 0; dpy < MAX_DISPLAYS; dpy++) {
591        if(ctx->mMDPComp[dpy])
592            ctx->mMDPComp[dpy]->dump(aBuf);
593    }
594    char ovDump[2048] = {'\0'};
595    ctx->mOverlay->getDump(ovDump, 2048);
596    dumpsys_log(aBuf, ovDump);
597    ovDump[0] = '\0';
598    ctx->mRotMgr->getDump(ovDump, 1024);
599    dumpsys_log(aBuf, ovDump);
600    strlcpy(buff, aBuf.string(), buff_len);
601}
602
603static int hwc_device_close(struct hw_device_t *dev)
604{
605    if(!dev) {
606        ALOGE("%s: NULL device pointer", __FUNCTION__);
607        return -1;
608    }
609    closeContext((hwc_context_t*)dev);
610    free(dev);
611
612    return 0;
613}
614
615static int hwc_device_open(const struct hw_module_t* module, const char* name,
616                           struct hw_device_t** device)
617{
618    int status = -EINVAL;
619
620    if (!strcmp(name, HWC_HARDWARE_COMPOSER)) {
621        struct hwc_context_t *dev;
622        dev = (hwc_context_t*)malloc(sizeof(*dev));
623        memset(dev, 0, sizeof(*dev));
624
625        //Initialize hwc context
626        initContext(dev);
627
628        //Setup HWC methods
629        dev->device.common.tag          = HARDWARE_DEVICE_TAG;
630        dev->device.common.version      = HWC_DEVICE_API_VERSION_1_1;
631        dev->device.common.module       = const_cast<hw_module_t*>(module);
632        dev->device.common.close        = hwc_device_close;
633        dev->device.prepare             = hwc_prepare;
634        dev->device.set                 = hwc_set;
635        dev->device.eventControl        = hwc_eventControl;
636        dev->device.blank               = hwc_blank;
637        dev->device.query               = hwc_query;
638        dev->device.registerProcs       = hwc_registerProcs;
639        dev->device.dump                = hwc_dump;
640        dev->device.getDisplayConfigs   = hwc_getDisplayConfigs;
641        dev->device.getDisplayAttributes = hwc_getDisplayAttributes;
642        *device = &dev->device.common;
643        status = 0;
644    }
645    return status;
646}
647