1/*
2 *  Copyright (c) 2013-14, 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 CLIENTS; 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 <hwc_qclient.h>
31#include <IQService.h>
32#include <hwc_utils.h>
33#include <mdp_version.h>
34#include <hwc_mdpcomp.h>
35
36#define QCLIENT_DEBUG 0
37
38using namespace android;
39using namespace qService;
40using namespace qhwc;
41
42namespace qClient {
43
44// ----------------------------------------------------------------------------
45QClient::QClient(hwc_context_t *ctx) : mHwcContext(ctx),
46        mMPDeathNotifier(new MPDeathNotifier(ctx))
47{
48    ALOGD_IF(QCLIENT_DEBUG, "QClient Constructor invoked");
49}
50
51QClient::~QClient()
52{
53    ALOGD_IF(QCLIENT_DEBUG,"QClient Destructor invoked");
54}
55
56static void securing(hwc_context_t *ctx, uint32_t startEnd) {
57    Locker::Autolock _sl(ctx->mDrawLock);
58    //The only way to make this class in this process subscribe to media
59    //player's death.
60    IMediaDeathNotifier::getMediaPlayerService();
61
62    ctx->mSecuring = startEnd;
63    //We're done securing
64    if(startEnd == IQService::END)
65        ctx->mSecureMode = true;
66    if(ctx->proc)
67        ctx->proc->invalidate(ctx->proc);
68}
69
70static void unsecuring(hwc_context_t *ctx, uint32_t startEnd) {
71    Locker::Autolock _sl(ctx->mDrawLock);
72    ctx->mSecuring = startEnd;
73    //We're done unsecuring
74    if(startEnd == IQService::END)
75        ctx->mSecureMode = false;
76    if(ctx->proc)
77        ctx->proc->invalidate(ctx->proc);
78}
79
80void QClient::MPDeathNotifier::died() {
81    Locker::Autolock _sl(mHwcContext->mDrawLock);
82    ALOGD_IF(QCLIENT_DEBUG, "Media Player died");
83    mHwcContext->mSecuring = false;
84    mHwcContext->mSecureMode = false;
85    if(mHwcContext->proc)
86        mHwcContext->proc->invalidate(mHwcContext->proc);
87}
88
89static android::status_t screenRefresh(hwc_context_t *ctx) {
90    status_t result = NO_INIT;
91    if(ctx->proc) {
92        ctx->proc->invalidate(ctx->proc);
93        result = NO_ERROR;
94    }
95    return result;
96}
97
98static void setExtOrientation(hwc_context_t *ctx, uint32_t orientation) {
99    ctx->mExtOrientation = orientation;
100}
101
102static void isExternalConnected(hwc_context_t* ctx, Parcel* outParcel) {
103    int connected;
104    connected = ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected ? 1 : 0;
105    outParcel->writeInt32(connected);
106}
107
108static void getDisplayAttributes(hwc_context_t* ctx, const Parcel* inParcel,
109        Parcel* outParcel) {
110    int dpy = inParcel->readInt32();
111    outParcel->writeInt32(ctx->dpyAttr[dpy].vsync_period);
112    if (ctx->dpyAttr[dpy].customFBSize) {
113        outParcel->writeInt32(ctx->dpyAttr[dpy].xres_new);
114        outParcel->writeInt32(ctx->dpyAttr[dpy].yres_new);
115    } else {
116        outParcel->writeInt32(ctx->dpyAttr[dpy].xres);
117        outParcel->writeInt32(ctx->dpyAttr[dpy].yres);
118    }
119    outParcel->writeFloat(ctx->dpyAttr[dpy].xdpi);
120    outParcel->writeFloat(ctx->dpyAttr[dpy].ydpi);
121    //XXX: Need to check what to return for HDMI
122    outParcel->writeInt32(ctx->mMDP.panel);
123}
124static void setHSIC(const Parcel* inParcel) {
125    int dpy = inParcel->readInt32();
126    ALOGD_IF(0, "In %s: dpy = %d", __FUNCTION__, dpy);
127    HSICData_t hsic_data;
128    hsic_data.hue = inParcel->readInt32();
129    hsic_data.saturation = inParcel->readFloat();
130    hsic_data.intensity = inParcel->readInt32();
131    hsic_data.contrast = inParcel->readFloat();
132    //XXX: Actually set the HSIC data through ABL lib
133}
134
135
136static void setBufferMirrorMode(hwc_context_t *ctx, uint32_t enable) {
137    ctx->mBufferMirrorMode = enable;
138}
139
140static status_t getDisplayVisibleRegion(hwc_context_t* ctx, int dpy,
141                                Parcel* outParcel) {
142    // Get the info only if the dpy is valid
143    if(dpy >= HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) {
144        Locker::Autolock _sl(ctx->mDrawLock);
145        if(dpy && (ctx->mExtOrientation || ctx->mBufferMirrorMode)) {
146            // Return the destRect on external, if external orienation
147            // is enabled
148            outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.left);
149            outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.top);
150            outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.right);
151            outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.bottom);
152        } else {
153            outParcel->writeInt32(ctx->mViewFrame[dpy].left);
154            outParcel->writeInt32(ctx->mViewFrame[dpy].top);
155            outParcel->writeInt32(ctx->mViewFrame[dpy].right);
156            outParcel->writeInt32(ctx->mViewFrame[dpy].bottom);
157        }
158        return NO_ERROR;
159    } else {
160        ALOGE("In %s: invalid dpy index %d", __FUNCTION__, dpy);
161        return BAD_VALUE;
162    }
163}
164
165static void pauseWFD(hwc_context_t *ctx, uint32_t pause) {
166    /* TODO: Will remove pauseWFD once all the clients start using
167     * setWfdStatus to indicate the status of WFD display
168     */
169    int dpy = HWC_DISPLAY_VIRTUAL;
170    if(pause) {
171        //WFD Pause
172        handle_pause(ctx, dpy);
173    } else {
174        //WFD Resume
175        handle_resume(ctx, dpy);
176    }
177}
178
179static void setWfdStatus(hwc_context_t *ctx, uint32_t wfdStatus) {
180
181    ALOGD_IF(HWC_WFDDISPSYNC_LOG,
182             "%s: Received a binder call that WFD state is %s",
183             __FUNCTION__,getExternalDisplayState(wfdStatus));
184    int dpy = HWC_DISPLAY_VIRTUAL;
185
186    if(wfdStatus == EXTERNAL_OFFLINE) {
187        ctx->mWfdSyncLock.lock();
188        ctx->mWfdSyncLock.signal();
189        ctx->mWfdSyncLock.unlock();
190    } else if(wfdStatus == EXTERNAL_PAUSE) {
191        handle_pause(ctx, dpy);
192    } else if(wfdStatus == EXTERNAL_RESUME) {
193        handle_resume(ctx, dpy);
194    }
195}
196
197
198static status_t setViewFrame(hwc_context_t* ctx, const Parcel* inParcel) {
199    int dpy = inParcel->readInt32();
200    if(dpy >= HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) {
201        Locker::Autolock _sl(ctx->mDrawLock);
202        ctx->mViewFrame[dpy].left   = inParcel->readInt32();
203        ctx->mViewFrame[dpy].top    = inParcel->readInt32();
204        ctx->mViewFrame[dpy].right  = inParcel->readInt32();
205        ctx->mViewFrame[dpy].bottom = inParcel->readInt32();
206        ALOGD_IF(QCLIENT_DEBUG, "%s: mViewFrame[%d] = [%d %d %d %d]",
207            __FUNCTION__, dpy,
208            ctx->mViewFrame[dpy].left, ctx->mViewFrame[dpy].top,
209            ctx->mViewFrame[dpy].right, ctx->mViewFrame[dpy].bottom);
210        return NO_ERROR;
211    } else {
212        ALOGE("In %s: invalid dpy index %d", __FUNCTION__, dpy);
213        return BAD_VALUE;
214    }
215}
216
217static void toggleDynamicDebug(hwc_context_t* ctx, const Parcel* inParcel) {
218    int debug_type = inParcel->readInt32();
219    bool enable = !!inParcel->readInt32();
220    ALOGD("%s: debug_type: %d enable:%d",
221            __FUNCTION__, debug_type, enable);
222    Locker::Autolock _sl(ctx->mDrawLock);
223    switch (debug_type) {
224        //break is ignored for DEBUG_ALL to toggle all of them at once
225        case IQService::DEBUG_ALL:
226        case IQService::DEBUG_MDPCOMP:
227            qhwc::MDPComp::dynamicDebug(enable);
228            if (debug_type != IQService::DEBUG_ALL)
229                break;
230        case IQService::DEBUG_VSYNC:
231            ctx->vstate.debug = enable;
232            if (debug_type != IQService::DEBUG_ALL)
233                break;
234    }
235}
236
237status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel,
238        Parcel* outParcel) {
239    status_t ret = NO_ERROR;
240
241    switch(command) {
242        case IQService::SECURING:
243            securing(mHwcContext, inParcel->readInt32());
244            break;
245        case IQService::UNSECURING:
246            unsecuring(mHwcContext, inParcel->readInt32());
247            break;
248        case IQService::SCREEN_REFRESH:
249            return screenRefresh(mHwcContext);
250            break;
251        case IQService::EXTERNAL_ORIENTATION:
252            setExtOrientation(mHwcContext, inParcel->readInt32());
253            break;
254        case IQService::BUFFER_MIRRORMODE:
255            setBufferMirrorMode(mHwcContext, inParcel->readInt32());
256            break;
257        case IQService::GET_DISPLAY_VISIBLE_REGION:
258            ret = getDisplayVisibleRegion(mHwcContext, inParcel->readInt32(),
259                                    outParcel);
260            break;
261        case IQService::CHECK_EXTERNAL_STATUS:
262            isExternalConnected(mHwcContext, outParcel);
263            break;
264        case IQService::GET_DISPLAY_ATTRIBUTES:
265            getDisplayAttributes(mHwcContext, inParcel, outParcel);
266            break;
267        case IQService::SET_HSIC_DATA:
268            setHSIC(inParcel);
269            break;
270        case IQService::PAUSE_WFD:
271            pauseWFD(mHwcContext, inParcel->readInt32());
272            break;
273        case IQService::SET_WFD_STATUS:
274            setWfdStatus(mHwcContext,inParcel->readInt32());
275            break;
276        case IQService::SET_VIEW_FRAME:
277            setViewFrame(mHwcContext, inParcel);
278            break;
279        case IQService::DYNAMIC_DEBUG:
280            toggleDynamicDebug(mHwcContext, inParcel);
281            break;
282        default:
283            ret = NO_ERROR;
284    }
285    return ret;
286}
287
288}
289