| /* |
| ** |
| ** Copyright 2008, The Android Open Source Project |
| ** Copyright 2010, Samsung Electronics Co. LTD |
| ** |
| ** Licensed under the Apache License, Version 2.0 (the "License"); |
| ** you may not use this file except in compliance with the License. |
| ** You may obtain a copy of the License at |
| ** |
| ** http://www.apache.org/licenses/LICENSE-2.0 |
| ** |
| ** Unless required by applicable law or agreed to in writing, software |
| ** distributed under the License is distributed on an "AS IS" BASIS, |
| ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| ** See the License for the specific language governing permissions and |
| ** limitations under the License. |
| */ |
| |
| /* |
| ** |
| ** @author Taikyung, Yu(taikyung.yu@samsung.com) |
| ** @date 2011-07-06 |
| */ |
| |
| #define LOG_TAG "SecTVOutService" |
| |
| #include <binder/IServiceManager.h> |
| #include <utils/RefBase.h> |
| #include <binder/IInterface.h> |
| #include <binder/Parcel.h> |
| #include <utils/Log.h> |
| #include "SecTVOutService.h" |
| #include <linux/fb.h> |
| |
| namespace android { |
| #define DEFAULT_LCD_WIDTH 800 |
| #define DEFAULT_LCD_HEIGHT 480 |
| |
| #define DIRECT_VIDEO_RENDERING (1) |
| #define DIRECT_UI_RENDERING (0) |
| |
| enum { |
| SET_HDMI_STATUS = IBinder::FIRST_CALL_TRANSACTION, |
| SET_HDMI_MODE, |
| SET_HDMI_RESOLUTION, |
| SET_HDMI_HDCP, |
| SET_HDMI_ROTATE, |
| SET_HDMI_HWCLAYER, |
| BLIT_2_HDMI |
| }; |
| |
| int SecTVOutService::HdmiFlushThread() |
| { |
| while (!mExitHdmiFlushThread) { |
| nsecs_t timeout = -1; |
| sp<MessageBase> msg = mHdmiEventQueue.waitMessage(timeout); |
| } |
| |
| return 0; |
| } |
| |
| int SecTVOutService::instantiate() |
| { |
| ALOGD("SecTVOutService instantiate"); |
| int r = defaultServiceManager()->addService(String16( "SecTVOutService"), new SecTVOutService ()); |
| ALOGD("SecTVOutService r=%d", r); |
| |
| return r; |
| } |
| |
| SecTVOutService::SecTVOutService () { |
| ALOGV("SecTVOutService created"); |
| mHdmiCableInserted = false; |
| #ifdef SUPPORT_G2D_UI_MODE |
| mUILayerMode = SecHdmi::HDMI_LAYER_GRAPHIC_1; |
| #else |
| mUILayerMode = SecHdmi::HDMI_LAYER_VIDEO; |
| #endif |
| mHwcLayer = 0; |
| mExitHdmiFlushThread = false; |
| |
| setLCDsize(); |
| if (mSecHdmi.create(mLCD_width, mLCD_height) == false) |
| ALOGE("%s::mSecHdmi.create() fail", __func__); |
| else |
| setHdmiStatus(1); |
| |
| mHdmiFlushThread = new HDMIFlushThread(this); |
| } |
| |
| void SecTVOutService::setLCDsize(void) { |
| char const * const device_template[] = { |
| "/dev/graphics/fb%u", |
| "/dev/fb%u", |
| 0 }; |
| |
| int fd = -1; |
| int i = 0; |
| char name[64]; |
| |
| while ((fd==-1) && device_template[i]) { |
| snprintf(name, 64, device_template[i], 0); |
| fd = open(name, O_RDWR, 0); |
| i++; |
| } |
| if (fd > 0) { |
| struct fb_var_screeninfo info; |
| if (ioctl(fd, FBIOGET_VSCREENINFO, &info) != -1) { |
| mLCD_width = info.xres; |
| mLCD_height = info.yres; |
| } else { |
| mLCD_width = DEFAULT_LCD_WIDTH; |
| mLCD_height = DEFAULT_LCD_HEIGHT; |
| } |
| close(fd); |
| } |
| return; |
| } |
| |
| SecTVOutService::~SecTVOutService () { |
| ALOGV ("SecTVOutService destroyed"); |
| |
| if (mHdmiFlushThread != NULL) { |
| mHdmiFlushThread->requestExit(); |
| mExitHdmiFlushThread = true; |
| mHdmiFlushThread->requestExitAndWait(); |
| mHdmiFlushThread.clear(); |
| } |
| } |
| |
| status_t SecTVOutService::onTransact(uint32_t code, const Parcel & data, Parcel * reply, uint32_t flags) |
| { |
| switch (code) { |
| case SET_HDMI_STATUS: { |
| int status = data.readInt32(); |
| setHdmiStatus(status); |
| } break; |
| |
| case SET_HDMI_MODE: { |
| int mode = data.readInt32(); |
| setHdmiMode(mode); |
| } break; |
| |
| case SET_HDMI_RESOLUTION: { |
| int resolution = data.readInt32(); |
| setHdmiResolution(resolution); |
| } break; |
| |
| case SET_HDMI_HDCP: { |
| int enHdcp = data.readInt32(); |
| setHdmiHdcp(enHdcp); |
| } break; |
| |
| case SET_HDMI_ROTATE: { |
| int rotVal = data.readInt32(); |
| int hwcLayer = data.readInt32(); |
| setHdmiRotate(rotVal, hwcLayer); |
| } break; |
| |
| case SET_HDMI_HWCLAYER: { |
| int hwcLayer = data.readInt32(); |
| setHdmiHwcLayer((uint32_t)hwcLayer); |
| } break; |
| |
| case BLIT_2_HDMI: { |
| uint32_t w = data.readInt32(); |
| uint32_t h = data.readInt32(); |
| uint32_t colorFormat = data.readInt32(); |
| uint32_t physYAddr = data.readInt32(); |
| uint32_t physCbAddr = data.readInt32(); |
| uint32_t physCrAddr = data.readInt32(); |
| uint32_t dstX = data.readInt32(); |
| uint32_t dstY = data.readInt32(); |
| uint32_t hdmiLayer = data.readInt32(); |
| uint32_t num_of_hwc_layer = data.readInt32(); |
| |
| blit2Hdmi(w, h, colorFormat, physYAddr, physCbAddr, physCrAddr, dstX, dstY, hdmiLayer, num_of_hwc_layer); |
| } break; |
| |
| default : |
| ALOGE ( "onTransact::default"); |
| return BBinder::onTransact (code, data, reply, flags); |
| } |
| |
| return NO_ERROR; |
| } |
| |
| void SecTVOutService::setHdmiStatus(uint32_t status) |
| { |
| |
| ALOGD("%s HDMI cable status = %d", __func__, status); |
| { |
| Mutex::Autolock _l(mLock); |
| |
| bool hdmiCableInserted = (bool)status; |
| |
| if (mHdmiCableInserted == hdmiCableInserted) |
| return; |
| |
| if (hdmiCableInserted == true) { |
| if (mSecHdmi.connect() == false) { |
| ALOGE("%s::mSecHdmi.connect() fail", __func__); |
| hdmiCableInserted = false; |
| } |
| } else { |
| if (mSecHdmi.disconnect() == false) |
| ALOGE("%s::mSecHdmi.disconnect() fail", __func__); |
| } |
| |
| mHdmiCableInserted = hdmiCableInserted; |
| } |
| |
| if (hdmiCableInserted() == true) |
| this->blit2Hdmi(mLCD_width, mLCD_height, HAL_PIXEL_FORMAT_BGRA_8888, 0, 0, 0, 0, 0, HDMI_MODE_UI, 0); |
| } |
| |
| void SecTVOutService::setHdmiMode(uint32_t mode) |
| { |
| ALOGD("%s TV mode = %d", __func__, mode); |
| Mutex::Autolock _l(mLock); |
| |
| if ((hdmiCableInserted() == true) && (mSecHdmi.setHdmiOutputMode(mode)) == false) { |
| ALOGE("%s::mSecHdmi.setHdmiOutputMode() fail", __func__); |
| return; |
| } |
| } |
| |
| void SecTVOutService::setHdmiResolution(uint32_t resolution) |
| { |
| //ALOGD("%s TV resolution = %d", __func__, resolution); |
| Mutex::Autolock _l(mLock); |
| |
| if ((hdmiCableInserted() == true) && (mSecHdmi.setHdmiResolution(resolution)) == false) { |
| ALOGE("%s::mSecHdmi.setHdmiResolution() fail", __func__); |
| return; |
| } |
| } |
| |
| void SecTVOutService::setHdmiHdcp(uint32_t hdcp_en) |
| { |
| ALOGD("%s TV HDCP = %d", __func__, hdcp_en); |
| Mutex::Autolock _l(mLock); |
| |
| if ((hdmiCableInserted() == true) && (mSecHdmi.setHdcpMode(hdcp_en)) == false) { |
| ALOGE("%s::mSecHdmi.setHdcpMode() fail", __func__); |
| return; |
| } |
| } |
| |
| void SecTVOutService::setHdmiRotate(uint32_t rotVal, uint32_t hwcLayer) |
| { |
| //ALOGD("%s TV ROTATE = %d", __func__, rotVal); |
| Mutex::Autolock _l(mLock); |
| |
| if ((hdmiCableInserted() == true) && (mSecHdmi.setUIRotation(rotVal, hwcLayer)) == false) { |
| ALOGE("%s::mSecHdmi.setUIRotation() fail", __func__); |
| return; |
| } |
| } |
| |
| void SecTVOutService::setHdmiHwcLayer(uint32_t hwcLayer) |
| { |
| //ALOGD("%s TV HWCLAYER = %d", __func__, hwcLayer); |
| Mutex::Autolock _l(mLock); |
| |
| mHwcLayer = hwcLayer; |
| return; |
| } |
| |
| void SecTVOutService::blit2Hdmi(uint32_t w, uint32_t h, uint32_t colorFormat, |
| uint32_t pPhyYAddr, uint32_t pPhyCbAddr, uint32_t pPhyCrAddr, |
| uint32_t dstX, uint32_t dstY, |
| uint32_t hdmiMode, |
| uint32_t num_of_hwc_layer) |
| { |
| Mutex::Autolock _l(mLock); |
| |
| if (hdmiCableInserted() == false) |
| return; |
| |
| int hdmiLayer = SecHdmi::HDMI_LAYER_VIDEO; |
| #if defined(CHECK_UI_TIME) || defined(CHECK_VIDEO_TIME) |
| nsecs_t start, end; |
| #endif |
| |
| sp<MessageBase> msg; |
| |
| switch (hdmiMode) { |
| case HDMI_MODE_UI : |
| if (mHwcLayer >= 2) |
| hdmiLayer = SecHdmi::HDMI_LAYER_GRAPHIC_0; |
| else if (mHwcLayer == 1) |
| hdmiLayer = SecHdmi::HDMI_LAYER_GRAPHIC_1; |
| else |
| #ifdef SUPPORT_G2D_UI_MODE |
| hdmiLayer = SecHdmi::HDMI_LAYER_GRAPHIC_1; |
| #else |
| hdmiLayer = SecHdmi::HDMI_LAYER_VIDEO; |
| #endif |
| |
| #ifdef SUPPORT_G2D_UI_MODE |
| if (mHwcLayer == 0) { |
| if (mSecHdmi.clear(SecHdmi::HDMI_LAYER_VIDEO) == false) |
| ALOGE("%s::mSecHdmi.clear(%d) fail", __func__, SecHdmi::HDMI_LAYER_VIDEO); |
| if (mSecHdmi.clear(SecHdmi::HDMI_LAYER_GRAPHIC_0) == false) |
| ALOGE("%s::mSecHdmi.clear(%d) fail", __func__, SecHdmi::HDMI_LAYER_GRAPHIC_0); |
| } |
| #endif |
| |
| if (mUILayerMode != hdmiLayer) { |
| if (mSecHdmi.clear(mUILayerMode) == false) |
| ALOGE("%s::mSecHdmi.clear(%d) fail", __func__, mUILayerMode); |
| } |
| |
| mUILayerMode = hdmiLayer; |
| |
| #if !defined(BOARD_USES_HDMI_SUBTITLES) |
| if (mHwcLayer == 0) |
| #endif |
| #if (DIRECT_UI_RENDERING == 1) |
| { |
| #ifdef CHECK_UI_TIME |
| start = systemTime(); |
| #endif |
| if (mSecHdmi.flush(w, h, colorFormat, pPhyYAddr, pPhyCbAddr, pPhyCrAddr, dstX, dstY, |
| mUILayerMode, mHwcLayer) == false) |
| ALOGE("%s::mSecHdmi.flush() on HDMI_MODE_UI fail", __func__); |
| #ifdef CHECK_UI_TIME |
| end = systemTime(); |
| ALOGD("[UI] mSecHdmi.flush[end-start] = %ld ms", long(ns2ms(end)) - long(ns2ms(start))); |
| #endif |
| } |
| #else |
| { |
| msg = new SecHdmiEventMsg(&mSecHdmi, w, h, colorFormat, pPhyYAddr, pPhyCbAddr, pPhyCrAddr, |
| dstX, dstY, mUILayerMode, mHwcLayer, HDMI_MODE_UI); |
| |
| /* post to HdmiEventQueue */ |
| mHdmiEventQueue.postMessage(msg, 0, 0); |
| } |
| #endif |
| break; |
| |
| case HDMI_MODE_VIDEO : |
| #if !defined(BOARD_USES_HDMI_SUBTITLES) |
| #ifdef SUPPORT_G2D_UI_MODE |
| if (mSecHdmi.clear(SecHdmi::HDMI_LAYER_GRAPHIC_0) == false) |
| ALOGE("%s::mSecHdmi.clear(%d) fail", __func__, SecHdmi::HDMI_LAYER_GRAPHIC_0); |
| if (mSecHdmi.clear(SecHdmi::HDMI_LAYER_GRAPHIC_1) == false) |
| ALOGE("%s::mSecHdmi.clear(%d) fail", __func__, SecHdmi::HDMI_LAYER_GRAPHIC_1); |
| #endif |
| #endif |
| |
| #if (DIRECT_VIDEO_RENDERING == 1) |
| #ifdef CHECK_VIDEO_TIME |
| start = systemTime(); |
| #endif |
| if (mSecHdmi.flush(w, h, colorFormat, pPhyYAddr, pPhyCbAddr, pPhyCrAddr, dstX, dstY, |
| SecHdmi::HDMI_LAYER_VIDEO, mHwcLayer) == false) |
| ALOGE("%s::mSecHdmi.flush() on HDMI_MODE_VIDEO fail", __func__); |
| #ifdef CHECK_VIDEO_TIME |
| end = systemTime(); |
| ALOGD("[Video] mSecHdmi.flush[end-start] = %ld ms", long(ns2ms(end)) - long(ns2ms(start))); |
| #endif |
| #else |
| msg = new SecHdmiEventMsg(&mSecHdmi, w, h, colorFormat, pPhyYAddr, pPhyCbAddr, pPhyCrAddr, |
| dstX, dstY, SecHdmi::HDMI_LAYER_VIDEO, mHwcLayer, HDMI_MODE_VIDEO); |
| |
| /* post to HdmiEventQueue */ |
| mHdmiEventQueue.postMessage(msg, 0, 0); |
| #endif |
| break; |
| |
| default: |
| ALOGE("unmatched HDMI_MODE : %d", hdmiMode); |
| break; |
| } |
| |
| return; |
| } |
| |
| bool SecTVOutService::hdmiCableInserted(void) |
| { |
| return mHdmiCableInserted; |
| } |
| |
| } |