/* * Copyright (c) 2013, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of The Linux Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #ifdef MSM_BSP #include #include #endif #include #include "minui.h" #define MDP_V4_0 400 #ifdef MSM_BSP #define ALIGN(x, align) (((x) + ((align)-1)) & ~((align)-1)) typedef struct { unsigned char *mem_buf; int size; int ion_fd; int mem_fd; struct ion_handle_data handle_data; } memInfo; //Left and right overlay id static int overlayL_id = MSMFB_NEW_REQUEST; static int overlayR_id = MSMFB_NEW_REQUEST; static memInfo mem_info; static int map_mdp_pixel_format() { int format = MDP_RGB_565; #if defined(RECOVERY_BGRA) format = MDP_BGRA_8888; #elif defined(RECOVERY_RGBX) format = MDP_RGBA_8888; #endif return format; } static bool overlay_supported = false; static bool isMDP5 = false; bool target_has_overlay(char *version) { int ret; int mdp_version; if (strlen(version) >= 8) { if(!strncmp(version, "msmfb", strlen("msmfb"))) { char str_ver[4]; memcpy(str_ver, version + strlen("msmfb"), 3); str_ver[3] = '\0'; mdp_version = atoi(str_ver); if (mdp_version >= MDP_V4_0) { overlay_supported = true; } } else if (!strncmp(version, "mdssfb", strlen("mdssfb"))) { overlay_supported = true; isMDP5 = true; } } if (overlay_supported) printf("Using qcomm overlay\n"); return overlay_supported; } bool isTargetMdp5() { if (isMDP5) return true; return false; } int free_ion_mem(void) { if (!overlay_supported) return -EINVAL; int ret = 0; if (mem_info.mem_buf) munmap(mem_info.mem_buf, mem_info.size); if (mem_info.ion_fd >= 0) { ret = ioctl(mem_info.ion_fd, ION_IOC_FREE, &mem_info.handle_data); if (ret < 0) perror("free_mem failed "); } if (mem_info.mem_fd >= 0) close(mem_info.mem_fd); if (mem_info.ion_fd >= 0) close(mem_info.ion_fd); memset(&mem_info, 0, sizeof(mem_info)); mem_info.mem_fd = -1; mem_info.ion_fd = -1; return 0; } int alloc_ion_mem(unsigned int size) { if (!overlay_supported) return -EINVAL; int result; struct ion_fd_data fd_data; struct ion_allocation_data ionAllocData; mem_info.ion_fd = open("/dev/ion", O_RDWR|O_DSYNC); if (mem_info.ion_fd < 0) { perror("ERROR: Can't open ion "); return -errno; } ionAllocData.flags = 0; ionAllocData.len = size; ionAllocData.align = sysconf(_SC_PAGESIZE); ionAllocData.heap_mask = ION_HEAP(ION_IOMMU_HEAP_ID) | ION_HEAP(ION_SYSTEM_CONTIG_HEAP_ID); result = ioctl(mem_info.ion_fd, ION_IOC_ALLOC, &ionAllocData); if(result){ perror("ION_IOC_ALLOC Failed "); close(mem_info.ion_fd); return result; } fd_data.handle = ionAllocData.handle; mem_info.handle_data.handle = ionAllocData.handle; result = ioctl(mem_info.ion_fd, ION_IOC_MAP, &fd_data); if (result) { perror("ION_IOC_MAP Failed "); free_ion_mem(); return result; } mem_info.mem_buf = (unsigned char *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_data.fd, 0); mem_info.mem_fd = fd_data.fd; if (!mem_info.mem_buf) { perror("ERROR: mem_buf MAP_FAILED "); free_ion_mem(); return -ENOMEM; } return 0; } int allocate_overlay(int fd, GGLSurface gr_fb[]) { int ret = 0; if (!overlay_supported) return -EINVAL; if (!isDisplaySplit()) { // Check if overlay is already allocated if (MSMFB_NEW_REQUEST == overlayL_id) { struct mdp_overlay overlayL; memset(&overlayL, 0 , sizeof (struct mdp_overlay)); /* Fill Overlay Data */ overlayL.src.width = ALIGN(gr_fb[0].width, 32); overlayL.src.height = gr_fb[0].height; overlayL.src.format = map_mdp_pixel_format(); overlayL.src_rect.w = gr_fb[0].width; overlayL.src_rect.h = gr_fb[0].height; overlayL.dst_rect.w = gr_fb[0].width; overlayL.dst_rect.h = gr_fb[0].height; overlayL.alpha = 0xFF; overlayL.transp_mask = MDP_TRANSP_NOP; overlayL.id = MSMFB_NEW_REQUEST; ret = ioctl(fd, MSMFB_OVERLAY_SET, &overlayL); if (ret < 0) { perror("Overlay Set Failed"); return ret; } overlayL_id = overlayL.id; } } else { float xres = getFbXres(); int lSplit = getLeftSplit(); float lSplitRatio = lSplit / xres; float lCropWidth = gr_fb[0].width * lSplitRatio; int lWidth = lSplit; int rWidth = gr_fb[0].width - lSplit; int height = gr_fb[0].height; if (MSMFB_NEW_REQUEST == overlayL_id) { struct mdp_overlay overlayL; memset(&overlayL, 0 , sizeof (struct mdp_overlay)); /* Fill OverlayL Data */ overlayL.src.width = ALIGN(gr_fb[0].width, 32); overlayL.src.height = gr_fb[0].height; overlayL.src.format = map_mdp_pixel_format(); overlayL.src_rect.x = 0; overlayL.src_rect.y = 0; overlayL.src_rect.w = lCropWidth; overlayL.src_rect.h = gr_fb[0].height; overlayL.dst_rect.x = 0; overlayL.dst_rect.y = 0; overlayL.dst_rect.w = lWidth; overlayL.dst_rect.h = height; overlayL.alpha = 0xFF; overlayL.transp_mask = MDP_TRANSP_NOP; overlayL.id = MSMFB_NEW_REQUEST; ret = ioctl(fd, MSMFB_OVERLAY_SET, &overlayL); if (ret < 0) { perror("OverlayL Set Failed"); return ret; } overlayL_id = overlayL.id; } if (MSMFB_NEW_REQUEST == overlayR_id) { struct mdp_overlay overlayR; memset(&overlayR, 0 , sizeof (struct mdp_overlay)); /* Fill OverlayR Data */ overlayR.src.width = ALIGN(gr_fb[0].width, 32); overlayR.src.height = gr_fb[0].height; overlayR.src.format = map_mdp_pixel_format(); overlayR.src_rect.x = lCropWidth; overlayR.src_rect.y = 0; overlayR.src_rect.w = gr_fb[0].width - lCropWidth; overlayR.src_rect.h = gr_fb[0].height; overlayR.dst_rect.x = 0; overlayR.dst_rect.y = 0; overlayR.dst_rect.w = rWidth; overlayR.dst_rect.h = height; overlayR.alpha = 0xFF; overlayR.flags = MDSS_MDP_RIGHT_MIXER; overlayR.transp_mask = MDP_TRANSP_NOP; overlayR.id = MSMFB_NEW_REQUEST; ret = ioctl(fd, MSMFB_OVERLAY_SET, &overlayR); if (ret < 0) { perror("OverlayR Set Failed"); return ret; } overlayR_id = overlayR.id; } } return 0; } int free_overlay(int fd) { if (!overlay_supported) return -EINVAL; int ret = 0; struct mdp_display_commit ext_commit; if (!isDisplaySplit()) { if (overlayL_id != MSMFB_NEW_REQUEST) { ret = ioctl(fd, MSMFB_OVERLAY_UNSET, &overlayL_id); if (ret) { perror("Overlay Unset Failed"); overlayL_id = MSMFB_NEW_REQUEST; return ret; } } } else { if (overlayL_id != MSMFB_NEW_REQUEST) { ret = ioctl(fd, MSMFB_OVERLAY_UNSET, &overlayL_id); if (ret) { perror("OverlayL Unset Failed"); overlayL_id = MSMFB_NEW_REQUEST; return ret; } } if (overlayR_id != MSMFB_NEW_REQUEST) { ret = ioctl(fd, MSMFB_OVERLAY_UNSET, &overlayR_id); if (ret) { perror("OverlayR Unset Failed"); overlayR_id = MSMFB_NEW_REQUEST; return ret; } } } memset(&ext_commit, 0, sizeof(struct mdp_display_commit)); ext_commit.flags = MDP_DISPLAY_COMMIT_OVERLAY; ext_commit.wait_for_finish = 1; ret = ioctl(fd, MSMFB_DISPLAY_COMMIT, &ext_commit); if (ret < 0) { perror("ERROR: Clear MSMFB_DISPLAY_COMMIT failed!"); overlayL_id = MSMFB_NEW_REQUEST; overlayR_id = MSMFB_NEW_REQUEST; return ret; } overlayL_id = MSMFB_NEW_REQUEST; overlayR_id = MSMFB_NEW_REQUEST; return 0; } int overlay_display_frame(int fd, GGLubyte* data, size_t size) { if (!overlay_supported) return -EINVAL; int ret = 0; struct msmfb_overlay_data ovdataL, ovdataR; struct mdp_display_commit ext_commit; if (!isDisplaySplit()) { if (overlayL_id == MSMFB_NEW_REQUEST) { perror("display_frame failed, no overlay\n"); return -EINVAL; } memcpy(mem_info.mem_buf, data, size); memset(&ovdataL, 0, sizeof(struct msmfb_overlay_data)); ovdataL.id = overlayL_id; ovdataL.data.flags = 0; ovdataL.data.offset = 0; ovdataL.data.memory_id = mem_info.mem_fd; ret = ioctl(fd, MSMFB_OVERLAY_PLAY, &ovdataL); if (ret < 0) { perror("overlay_display_frame failed, overlay play Failed\n"); return ret; } } else { if (overlayL_id == MSMFB_NEW_REQUEST) { perror("display_frame failed, no overlayL \n"); return -EINVAL; } memcpy(mem_info.mem_buf, data, size); memset(&ovdataL, 0, sizeof(struct msmfb_overlay_data)); ovdataL.id = overlayL_id; ovdataL.data.flags = 0; ovdataL.data.offset = 0; ovdataL.data.memory_id = mem_info.mem_fd; ret = ioctl(fd, MSMFB_OVERLAY_PLAY, &ovdataL); if (ret < 0) { perror("overlay_display_frame failed, overlayL play Failed\n"); return ret; } if (overlayR_id == MSMFB_NEW_REQUEST) { perror("display_frame failed, no overlayR \n"); return -EINVAL; } memset(&ovdataR, 0, sizeof(struct msmfb_overlay_data)); ovdataR.id = overlayR_id; ovdataR.data.flags = 0; ovdataR.data.offset = 0; ovdataR.data.memory_id = mem_info.mem_fd; ret = ioctl(fd, MSMFB_OVERLAY_PLAY, &ovdataR); if (ret < 0) { perror("overlay_display_frame failed, overlayR play Failed\n"); return ret; } } memset(&ext_commit, 0, sizeof(struct mdp_display_commit)); ext_commit.flags = MDP_DISPLAY_COMMIT_OVERLAY; ext_commit.wait_for_finish = 1; ret = ioctl(fd, MSMFB_DISPLAY_COMMIT, &ext_commit); if (ret < 0) { perror("overlay_display_frame failed, overlay commit Failed\n!"); } return ret; } #else bool target_has_overlay(char *version) { return false; } bool isTargetMdp5() { return false; } int free_ion_mem(void) { return -EINVAL; } int alloc_ion_mem(unsigned int size) { return -EINVAL; } int allocate_overlay(int fd, GGLSurface gr_fb[]) { return -EINVAL; } int free_overlay(int fd) { return -EINVAL; } int overlay_display_frame(int fd, GGLubyte* data, size_t size) { return -EINVAL; } #endif //#ifdef MSM_BSP