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 
38 using namespace android;
39 using namespace qService;
40 using namespace qhwc;
41 
42 namespace qClient {
43 
44 // ----------------------------------------------------------------------------
QClient(hwc_context_t * ctx)45 QClient::QClient(hwc_context_t *ctx) : mHwcContext(ctx),
46         mMPDeathNotifier(new MPDeathNotifier(ctx))
47 {
48     ALOGD_IF(QCLIENT_DEBUG, "QClient Constructor invoked");
49 }
50 
~QClient()51 QClient::~QClient()
52 {
53     ALOGD_IF(QCLIENT_DEBUG,"QClient Destructor invoked");
54 }
55 
securing(hwc_context_t * ctx,uint32_t startEnd)56 static 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 
unsecuring(hwc_context_t * ctx,uint32_t startEnd)70 static 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 
died()80 void 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 
screenRefresh(hwc_context_t * ctx)89 static 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 
setExtOrientation(hwc_context_t * ctx,uint32_t orientation)98 static void setExtOrientation(hwc_context_t *ctx, uint32_t orientation) {
99     ctx->mExtOrientation = orientation;
100 }
101 
isExternalConnected(hwc_context_t * ctx,Parcel * outParcel)102 static 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 
getDisplayAttributes(hwc_context_t * ctx,const Parcel * inParcel,Parcel * outParcel)108 static 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 }
setHSIC(const Parcel * inParcel)124 static 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 
setBufferMirrorMode(hwc_context_t * ctx,uint32_t enable)136 static void setBufferMirrorMode(hwc_context_t *ctx, uint32_t enable) {
137     ctx->mBufferMirrorMode = enable;
138 }
139 
getDisplayVisibleRegion(hwc_context_t * ctx,int dpy,Parcel * outParcel)140 static 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 
pauseWFD(hwc_context_t * ctx,uint32_t pause)165 static 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 
setWfdStatus(hwc_context_t * ctx,uint32_t wfdStatus)179 static 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 
setViewFrame(hwc_context_t * ctx,const Parcel * inParcel)198 static 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 
toggleDynamicDebug(hwc_context_t * ctx,const Parcel * inParcel)217 static 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 
notifyCallback(uint32_t command,const Parcel * inParcel,Parcel * outParcel)237 status_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