1/*
2* Copyright (c) 2013 The Linux Foundation. All rights reserved.
3*
4* Redistribution and use in source and binary forms, with or without
5* modification, are permitted provided that the following conditions are
6* met:
7*    * Redistributions of source code must retain the above copyright
8*      notice, this list of conditions and the following disclaimer.
9*    * Redistributions in binary form must reproduce the above
10*      copyright notice, this list of conditions and the following
11*      disclaimer in the documentation and/or other materials provided
12*      with the distribution.
13*    * Neither the name of The Linux Foundation. nor the names of its
14*      contributors may be used to endorse or promote products derived
15*      from this software without specific prior written permission.
16*
17* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*/
29
30#include "overlay.h"
31#include "overlayWriteback.h"
32#include "mdpWrapper.h"
33
34namespace overlay {
35
36//=========== class WritebackMem ==============================================
37bool WritebackMem::manageMem(uint32_t size, bool isSecure) {
38    if(mBuf.bufSz() == size) {
39        return true;
40    }
41    if(mBuf.valid()) {
42        if(!mBuf.close()) {
43            ALOGE("%s error closing mem", __func__);
44            return false;
45        }
46    }
47    return alloc(size, isSecure);
48}
49
50bool WritebackMem::alloc(uint32_t size, bool isSecure) {
51    if(!mBuf.open(NUM_BUFS, size, isSecure)){
52        ALOGE("%s: Failed to open", __func__);
53        mBuf.close();
54        return false;
55    }
56
57    OVASSERT(MAP_FAILED != mBuf.addr(), "MAP failed");
58    OVASSERT(mBuf.getFD() != -1, "getFd is -1");
59
60    mCurrOffsetIndex = 0;
61    for (uint32_t i = 0; i < NUM_BUFS; i++) {
62        mOffsets[i] = i * size;
63    }
64    return true;
65}
66
67bool WritebackMem::dealloc() {
68    bool ret = true;
69    if(mBuf.valid()) {
70        ret = mBuf.close();
71    }
72    return ret;
73}
74
75//=========== class Writeback =================================================
76Writeback::Writeback() : mXres(0), mYres(0), mOpFmt(-1) {
77    int fbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK);
78    if(!utils::openDev(mFd, fbNum, Res::fbPath, O_RDWR)) {
79        ALOGE("%s failed to init %s", __func__, Res::fbPath);
80        return;
81    }
82    startSession();
83}
84
85Writeback::~Writeback() {
86    stopSession();
87    if (!mFd.close()) {
88        ALOGE("%s error closing fd", __func__);
89    }
90}
91
92bool Writeback::startSession() {
93    if(!mdp_wrapper::wbInitStart(mFd.getFD())) {
94        ALOGE("%s failed", __func__);
95        return false;
96    }
97    return true;
98}
99
100bool Writeback::stopSession() {
101    if(mFd.valid()) {
102        if(!mdp_wrapper::wbStopTerminate(mFd.getFD())) {
103            ALOGE("%s failed", __func__);
104            return false;
105        }
106    } else {
107        ALOGE("%s Invalid fd", __func__);
108        return false;
109    }
110    return true;
111}
112
113bool Writeback::configureDpyInfo(int xres, int yres) {
114    if(mXres != xres || mYres != yres) {
115        fb_var_screeninfo vinfo;
116        memset(&vinfo, 0, sizeof(fb_var_screeninfo));
117        if(!mdp_wrapper::getVScreenInfo(mFd.getFD(), vinfo)) {
118            ALOGE("%s failed", __func__);
119            return false;
120        }
121        vinfo.xres = xres;
122        vinfo.yres = yres;
123        vinfo.xres_virtual = xres;
124        vinfo.yres_virtual = yres;
125        vinfo.xoffset = 0;
126        vinfo.yoffset = 0;
127        if(!mdp_wrapper::setVScreenInfo(mFd.getFD(), vinfo)) {
128            ALOGE("%s failed", __func__);
129            return false;
130        }
131        mXres = xres;
132        mYres = yres;
133    }
134    return true;
135}
136
137bool Writeback::configureMemory(uint32_t size, bool isSecure) {
138    if(!mWbMem.manageMem(size, isSecure)) {
139        ALOGE("%s failed, memory failure", __func__);
140        return false;
141    }
142    return true;
143}
144
145bool Writeback::queueBuffer(int opFd, uint32_t opOffset) {
146    memset(&mFbData, 0, sizeof(struct msmfb_data));
147    //Queue
148    mFbData.offset = opOffset;
149    mFbData.memory_id = opFd;
150    mFbData.id = 0;
151    mFbData.flags = 0;
152    if(!mdp_wrapper::wbQueueBuffer(mFd.getFD(), mFbData)) {
153        ALOGE("%s: queuebuffer failed", __func__);
154        return false;
155    }
156    return true;
157}
158
159bool Writeback::dequeueBuffer() {
160    //Dequeue
161    mFbData.flags = MSMFB_WRITEBACK_DEQUEUE_BLOCKING;
162    if(!mdp_wrapper::wbDequeueBuffer(mFd.getFD(), mFbData)) {
163        ALOGE("%s: dequeuebuffer failed", __func__);
164        return false;
165    }
166    return true;
167}
168
169bool Writeback::writeSync(int opFd, uint32_t opOffset) {
170    if(!queueBuffer(opFd, opOffset)) {
171        return false;
172    }
173    if(!Overlay::displayCommit(mFd.getFD())) {
174        return false;
175    }
176    if(!dequeueBuffer()) {
177        return false;
178    }
179    return true;
180}
181
182bool Writeback::writeSync() {
183    mWbMem.useNextBuffer();
184    return writeSync(mWbMem.getDstFd(), mWbMem.getOffset());
185}
186
187bool Writeback::setOutputFormat(int mdpFormat) {
188    if(mdpFormat != mOpFmt) {
189        struct msmfb_metadata metadata;
190        memset(&metadata, 0 , sizeof(metadata));
191        metadata.op = metadata_op_wb_format;
192        metadata.data.mixer_cfg.writeback_format = mdpFormat;
193        if (ioctl(mFd.getFD(), MSMFB_METADATA_SET, &metadata) < 0) {
194            ALOGE("Error setting MDP Writeback format");
195            return false;
196        }
197        mOpFmt = mdpFormat;
198    }
199    return true;
200}
201
202int Writeback::getOutputFormat() {
203    if(mOpFmt < 0) {
204        struct msmfb_metadata metadata;
205        memset(&metadata, 0 , sizeof(metadata));
206        metadata.op = metadata_op_wb_format;
207        if (ioctl(mFd.getFD(), MSMFB_METADATA_GET, &metadata) < 0) {
208            ALOGE("Error retrieving MDP Writeback format");
209            return -1;
210        }
211        mOpFmt =  metadata.data.mixer_cfg.writeback_format;
212    }
213    return mOpFmt;
214}
215
216//static
217
218Writeback *Writeback::getInstance() {
219    if(sWb == NULL) {
220        sWb = new Writeback();
221    }
222    sUsed = true;
223    return sWb;
224}
225
226void Writeback::configDone() {
227    if(sUsed == false && sWb) {
228        delete sWb;
229        sWb = NULL;
230    }
231}
232
233void Writeback::clear() {
234    sUsed = false;
235    if(sWb) {
236        delete sWb;
237        sWb = NULL;
238    }
239}
240
241bool Writeback::getDump(char *buf, size_t len) {
242    if(sWb) {
243        utils::getDump(buf, len, "WBData", sWb->mFbData);
244        char str[4] = {'\0'};
245        snprintf(str, 4, "\n");
246        strncat(buf, str, strlen(str));
247        return true;
248    }
249    return false;
250}
251
252Writeback *Writeback::sWb = 0;
253bool Writeback::sUsed = false;
254
255} //namespace overlay
256