blob: 350192d8173548aec8dd0293eaae4f8943af5c5a [file] [log] [blame]
Naseer Ahmed78c952e2013-11-25 18:12:23 -05001/*
Arun Kumar K.Rf15adc02014-01-21 21:26:25 -08002* Copyright (c) 2013-2014 The Linux Foundation. All rights reserved.
Naseer Ahmed78c952e2013-11-25 18:12:23 -05003*
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
Saurabh Shah90c55cf2015-02-10 15:37:39 -080030#include <fcntl.h>
31#include <stdio.h>
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <unistd.h>
Naseer Ahmed78c952e2013-11-25 18:12:23 -050035#include <display_config.h>
36#include <QServiceUtils.h>
Saurabh Shah90c55cf2015-02-10 15:37:39 -080037#include <qd_utils.h>
Naseer Ahmed78c952e2013-11-25 18:12:23 -050038
39using namespace android;
40using namespace qService;
41
42namespace qdutils {
43
Saurabh Shah90c55cf2015-02-10 15:37:39 -080044//=============================================================================
45// The functions below run in the client process and wherever necessary
46// do a binder call to HWC to get/set data.
47
Naseer Ahmed78c952e2013-11-25 18:12:23 -050048int isExternalConnected(void) {
49 int ret;
Arun Kumar K.Rf15adc02014-01-21 21:26:25 -080050 status_t err = (status_t) FAILED_TRANSACTION;
Naseer Ahmed78c952e2013-11-25 18:12:23 -050051 sp<IQService> binder = getBinder();
52 Parcel inParcel, outParcel;
53 if(binder != NULL) {
54 err = binder->dispatch(IQService::CHECK_EXTERNAL_STATUS,
55 &inParcel , &outParcel);
56 }
57 if(err) {
58 ALOGE("%s: Failed to get external status err=%d", __FUNCTION__, err);
59 ret = err;
60 } else {
61 ret = outParcel.readInt32();
62 }
63 return ret;
64}
65
66int getDisplayAttributes(int dpy, DisplayAttributes_t& dpyattr) {
Arun Kumar K.Rf15adc02014-01-21 21:26:25 -080067 status_t err = (status_t) FAILED_TRANSACTION;
Naseer Ahmed78c952e2013-11-25 18:12:23 -050068 sp<IQService> binder = getBinder();
69 Parcel inParcel, outParcel;
70 inParcel.writeInt32(dpy);
71 if(binder != NULL) {
72 err = binder->dispatch(IQService::GET_DISPLAY_ATTRIBUTES,
73 &inParcel, &outParcel);
74 }
75 if(!err) {
76 dpyattr.vsync_period = outParcel.readInt32();
77 dpyattr.xres = outParcel.readInt32();
78 dpyattr.yres = outParcel.readInt32();
79 dpyattr.xdpi = outParcel.readFloat();
80 dpyattr.ydpi = outParcel.readFloat();
81 dpyattr.panel_type = (char) outParcel.readInt32();
82 } else {
Saurabh Shah90c55cf2015-02-10 15:37:39 -080083 ALOGE("%s() failed with err %d", __FUNCTION__, err);
Naseer Ahmed78c952e2013-11-25 18:12:23 -050084 }
85 return err;
86}
87
88int setHSIC(int dpy, const HSICData_t& hsic_data) {
Arun Kumar K.Rf15adc02014-01-21 21:26:25 -080089 status_t err = (status_t) FAILED_TRANSACTION;
Naseer Ahmed78c952e2013-11-25 18:12:23 -050090 sp<IQService> binder = getBinder();
91 Parcel inParcel, outParcel;
92 inParcel.writeInt32(dpy);
93 inParcel.writeInt32(hsic_data.hue);
94 inParcel.writeFloat(hsic_data.saturation);
95 inParcel.writeInt32(hsic_data.intensity);
96 inParcel.writeFloat(hsic_data.contrast);
97 if(binder != NULL) {
98 err = binder->dispatch(IQService::SET_HSIC_DATA, &inParcel, &outParcel);
99 }
100 if(err)
101 ALOGE("%s: Failed to get external status err=%d", __FUNCTION__, err);
102 return err;
103}
Arun Kumar K.R8e7a62f2013-12-06 18:55:41 -0800104
105int getDisplayVisibleRegion(int dpy, hwc_rect_t &rect) {
Arun Kumar K.Rf15adc02014-01-21 21:26:25 -0800106 status_t err = (status_t) FAILED_TRANSACTION;
Arun Kumar K.R8e7a62f2013-12-06 18:55:41 -0800107 sp<IQService> binder = getBinder();
108 Parcel inParcel, outParcel;
109 inParcel.writeInt32(dpy);
110 if(binder != NULL) {
111 err = binder->dispatch(IQService::GET_DISPLAY_VISIBLE_REGION,
112 &inParcel, &outParcel);
113 }
114 if(!err) {
115 rect.left = outParcel.readInt32();
116 rect.top = outParcel.readInt32();
117 rect.right = outParcel.readInt32();
118 rect.bottom = outParcel.readInt32();
119 } else {
120 ALOGE("%s: Failed to getVisibleRegion for dpy =%d: err = %d",
121 __FUNCTION__, dpy, err);
122 }
123 return err;
124}
125
Ramkumar Radhakrishnan0a021a82014-05-19 19:53:56 -0700126int setViewFrame(int dpy, int l, int t, int r, int b) {
127 status_t err = (status_t) FAILED_TRANSACTION;
128 sp<IQService> binder = getBinder();
129 Parcel inParcel, outParcel;
130 inParcel.writeInt32(dpy);
131 inParcel.writeInt32(l);
132 inParcel.writeInt32(t);
133 inParcel.writeInt32(r);
134 inParcel.writeInt32(b);
135
136 if(binder != NULL) {
137 err = binder->dispatch(IQService::SET_VIEW_FRAME,
138 &inParcel, &outParcel);
139 }
140 if(err)
141 ALOGE("%s: Failed to set view frame for dpy %d err=%d",
142 __FUNCTION__, dpy, err);
143
144 return err;
145}
146
Arun Kumar K.R33888f52014-10-09 15:56:33 -0700147int setSecondaryDisplayStatus(int dpy, uint32_t status) {
148 status_t err = (status_t) FAILED_TRANSACTION;
149 sp<IQService> binder = getBinder();
150 Parcel inParcel, outParcel;
151 inParcel.writeInt32(dpy);
152 inParcel.writeInt32(status);
153
154 if(binder != NULL) {
155 err = binder->dispatch(IQService::SET_SECONDARY_DISPLAY_STATUS,
156 &inParcel, &outParcel);
157 }
158 if(err)
159 ALOGE("%s: Failed for dpy %d status = %d err=%d", __FUNCTION__, dpy,
160 status, err);
161
162 return err;
163}
164
Raj Kamal0d53fc62014-11-25 17:36:36 +0530165int configureDynRefreshRate(uint32_t op, uint32_t refreshRate) {
166 status_t err = (status_t) FAILED_TRANSACTION;
167 sp<IQService> binder = getBinder();
168 Parcel inParcel, outParcel;
169 inParcel.writeInt32(op);
170 inParcel.writeInt32(refreshRate);
171
172 if(binder != NULL) {
173 err = binder->dispatch(IQService::CONFIGURE_DYN_REFRESH_RATE,
174 &inParcel, &outParcel);
175 }
176
177 if(err)
178 ALOGE("%s: Failed setting op %d err=%d", __FUNCTION__, op, err);
179
180 return err;
181}
182
Saurabh Shah90c55cf2015-02-10 15:37:39 -0800183int getConfigCount(int /*dpy*/) {
184 int numConfigs = -1;
185 sp<IQService> binder = getBinder();
186 if(binder != NULL) {
187 Parcel inParcel, outParcel;
188 inParcel.writeInt32(DISPLAY_PRIMARY);
189 status_t err = binder->dispatch(IQService::GET_CONFIG_COUNT,
190 &inParcel, &outParcel);
191 if(!err) {
192 numConfigs = outParcel.readInt32();
193 ALOGI("%s() Received num configs %d", __FUNCTION__, numConfigs);
194 } else {
195 ALOGE("%s() failed with err %d", __FUNCTION__, err);
196 }
197 }
198 return numConfigs;
199}
200
201int getActiveConfig(int /*dpy*/) {
202 int configIndex = -1;
203 sp<IQService> binder = getBinder();
204 if(binder != NULL) {
205 Parcel inParcel, outParcel;
206 inParcel.writeInt32(DISPLAY_PRIMARY);
207 status_t err = binder->dispatch(IQService::GET_ACTIVE_CONFIG,
208 &inParcel, &outParcel);
209 if(!err) {
210 configIndex = outParcel.readInt32();
211 ALOGI("%s() Received active config index %d", __FUNCTION__,
212 configIndex);
213 } else {
214 ALOGE("%s() failed with err %d", __FUNCTION__, err);
215 }
216 }
217 return configIndex;
218}
219
220int setActiveConfig(int configIndex, int /*dpy*/) {
221 status_t err = (status_t) FAILED_TRANSACTION;
222 sp<IQService> binder = getBinder();
223 if(binder != NULL) {
224 Parcel inParcel, outParcel;
225 inParcel.writeInt32(configIndex);
226 inParcel.writeInt32(DISPLAY_PRIMARY);
227 err = binder->dispatch(IQService::SET_ACTIVE_CONFIG,
228 &inParcel, &outParcel);
229 if(!err) {
230 ALOGI("%s() Successfully set active config index %d", __FUNCTION__,
231 configIndex);
232 } else {
233 ALOGE("%s() failed with err %d", __FUNCTION__, err);
234 }
235 }
236 return err;
237}
238
239DisplayAttributes getDisplayAttributes(int configIndex, int /*dpy*/) {
240 DisplayAttributes dpyattr;
241 sp<IQService> binder = getBinder();
242 if(binder != NULL) {
243 Parcel inParcel, outParcel;
244 inParcel.writeInt32(configIndex);
245 inParcel.writeInt32(DISPLAY_PRIMARY);
246 status_t err = binder->dispatch(
247 IQService::GET_DISPLAY_ATTRIBUTES_FOR_CONFIG, &inParcel,
248 &outParcel);
249 if(!err) {
250 dpyattr.vsync_period = outParcel.readInt32();
251 dpyattr.xres = outParcel.readInt32();
252 dpyattr.yres = outParcel.readInt32();
253 dpyattr.xdpi = outParcel.readFloat();
254 dpyattr.ydpi = outParcel.readFloat();
255 dpyattr.panel_type = (char) outParcel.readInt32();
256 ALOGI("%s() Received attrs for index %d: xres %d, yres %d",
257 __FUNCTION__, configIndex, dpyattr.xres, dpyattr.yres);
258 } else {
259 ALOGE("%s() failed with err %d", __FUNCTION__, err);
260 }
261 }
262 return dpyattr;
263}
264
Tatenda Chipeperekwa42072882015-03-24 11:50:27 -0700265int setPanelMode(int mode) {
266 status_t err = (status_t) FAILED_TRANSACTION;
267 sp<IQService> binder = getBinder();
268 if(binder != NULL) {
269 Parcel inParcel, outParcel;
270 inParcel.writeInt32(mode);
271 err = binder->dispatch(IQService::SET_DISPLAY_MODE,
272 &inParcel, &outParcel);
273 if(!err) {
274 ALOGI("%s() Successfully set the display mode to %d", __FUNCTION__,
275 mode);
276 } else {
277 ALOGE("%s() failed with err %d", __FUNCTION__, err);
278 }
279 }
280 return err;
281}
282
Saurabh Shah90c55cf2015-02-10 15:37:39 -0800283//=============================================================================
284// The functions/methods below run in the context of HWC and
285// are called in response to binder calls from clients
286
287Configs* Configs::getInstance() {
288 if(sConfigs == NULL) {
289 sConfigs = new Configs();
290 if(sConfigs->init() == false) {
291 ALOGE("%s(): Configs initialization failed", __FUNCTION__);
292 delete sConfigs;
293 sConfigs = NULL;
294 }
295 }
296 return sConfigs;
297}
298
299Configs::Configs() : mActiveConfig(0), mConfigsSupported(0) {}
300
301bool Configs::init() {
302 DisplayAttributes dpyAttr;
303 if(not getCurrentMode(dpyAttr)) {
304 ALOGE("%s(): Mode switch is disabled", __FUNCTION__);
305 return false;
306 }
307
308 FILE *fHnd;
309 size_t len = PAGE_SIZE;
310 ssize_t read = 0;
311 uint32_t configCount = 0;
312 char sysfsPath[MAX_SYSFS_FILE_PATH];
313
314 memset(sysfsPath, '\0', sizeof(sysfsPath));
315 snprintf(sysfsPath , sizeof(sysfsPath),
316 "/sys/class/graphics/fb0/modes");
317
318 fHnd = fopen(sysfsPath, "r");
319 if (fHnd == NULL) {
320 ALOGE("%s(): Opening file %s failed with error %s", __FUNCTION__,
321 sysfsPath, strerror(errno));
322 return false;
323 }
324
325 memset(mModeStr, 0, sizeof(mModeStr));
326 while((configCount < CONFIGS_MAX) and
327 ((read = getline(&mModeStr[configCount], &len, fHnd)) > 0)) {
328 //String is of form "U:1600x2560p-0". Documentation/fb/modedb.txt in the
329 //kernel has more info on the format.
330 char *xptr = strcasestr(mModeStr[configCount], ":");
331 char *yptr = strcasestr(mModeStr[configCount], "x");
332 if(xptr && yptr) {
333 mConfigs[configCount].xres = atoi(xptr + 1);
334 mConfigs[configCount].yres = atoi(yptr + 1);
335 ALOGI("%s(): Parsed Config %s", __FUNCTION__,
336 mModeStr[configCount]);
337 ALOGI("%s(): Config %u: %u x %u", __FUNCTION__, configCount,
338 mConfigs[configCount].xres, mConfigs[configCount].yres);
339 if(mConfigs[configCount].xres == dpyAttr.xres and
340 mConfigs[configCount].yres == dpyAttr.yres) {
341 mActiveConfig = configCount;
342 }
343 } else {
344 ALOGE("%s(): Tokenizing str %s failed", __FUNCTION__,
345 mModeStr[configCount]);
346 //Free memory allocated internally by getline()
347 for(uint32_t i = 0; i <= configCount; i++) {
348 free(mModeStr[i]);
349 }
350 fclose(fHnd);
351 return false;
352 }
353 configCount++;
354 }
355
356 fclose(fHnd);
357
358 if(configCount == 0) {
359 ALOGE("%s No configs found", __FUNCTION__);
360 return false;
361 }
362 mConfigsSupported = configCount;
363 return true;
364}
365
366bool Configs::getCurrentMode(DisplayAttributes& dpyAttr) {
367 bool ret = false;
368 FILE *fHnd = fopen("/sys/class/graphics/fb0/mode", "r");
369 if(fHnd) {
370 char *buffer = NULL; //getline will allocate
371 size_t len = PAGE_SIZE;
372 if(getline(&buffer, &len, fHnd) > 0) {
373 //String is of form "U:1600x2560p-0". Documentation/fb/modedb.txt in
374 //kernel has more info on the format.
375 char *xptr = strcasestr(buffer, ":");
376 char *yptr = strcasestr(buffer, "x");
377 if(xptr && yptr) {
378 dpyAttr.xres = atoi(xptr + 1);
379 dpyAttr.yres = atoi(yptr + 1);
380 ALOGI("%s(): Parsed Current Config Str %s", __FUNCTION__,
381 buffer);
382 ALOGI("%s(): Current Config: %u x %u", __FUNCTION__,
383 dpyAttr.xres, dpyAttr.yres);
384 ret = true;
385 }
386 }
387
388 if(buffer)
389 free(buffer);
390
391 fclose(fHnd);
392 }
393 return ret;
394}
395
396bool Configs::setActiveConfig(const uint32_t& index) {
397 if(index >= mConfigsSupported) {
398 ALOGE("%s(): Invalid Index %u", __FUNCTION__, index);
399 return false;
400 }
401
402 bool ret = true;
403 int fd = -1;
404 size_t len = PAGE_SIZE;
405 char sysfsPath[MAX_SYSFS_FILE_PATH];
406 memset(sysfsPath, '\0', sizeof(sysfsPath));
407 snprintf(sysfsPath , sizeof(sysfsPath),
408 "/sys/class/graphics/fb0/mode");
409
410 fd = open(sysfsPath, O_WRONLY);
411 if (fd < 0) {
412 ALOGE("%s(): Opening file %s failed", __FUNCTION__, sysfsPath);
413 return false;
414 }
415
416 ssize_t written = pwrite(fd, mModeStr[index], strlen(mModeStr[index]), 0);
417 if(written <= 0) {
418 ALOGE("%s(): Writing config %s to %s failed with error: %s",
419 __FUNCTION__, mModeStr[index], sysfsPath, strerror(errno));
420 close(fd);
421 return false;
422 }
423
424 ALOGI("%s(): Successfully set config %u", __FUNCTION__, index);
425 mActiveConfig = index;
426 MDPVersion::getInstance().updateSplitInfo();
427 close(fd);
428 return true;
429}
430
431Configs* Configs::sConfigs = NULL;
432
Naseer Ahmed78c952e2013-11-25 18:12:23 -0500433}; //namespace
Krishna Chaitanya Parimi155ef4a2014-10-13 17:06:25 +0530434
435// ----------------------------------------------------------------------------
436// Screen refresh for native daemons linking dynamically to libqdutils
437// ----------------------------------------------------------------------------
438extern "C" int refreshScreen() {
439 int ret = 0;
440 ret = screenRefresh();
441 return ret;
442}