static int dovefb_switch_buff(struct fb_info *fi) { struct dovefb_layer_info *dfli = fi->par; int i = 0; struct _sOvlySurface *pOvlySurface = 0; unsigned long startaddr; int fbid; /* First check if we have a faster path */ if (dfli->vid_ovly_phys_addr_y) { /* Found a frame that should be presented now */ writel(dfli->vid_ovly_phys_addr_y, dfli->reg_base + LCD_SPU_DMA_START_ADDR_Y0); writel(dfli->vid_ovly_phys_addr_u, dfli->reg_base + LCD_SPU_DMA_START_ADDR_U0); writel(dfli->vid_ovly_phys_addr_v, dfli->reg_base + LCD_SPU_DMA_START_ADDR_V0); dfli->vid_ovly_phys_addr_y = 0; return 0; } /* * Find the latest frame. */ for (i = (MAX_QUEUE_NUM-1); i >= 0; i--) { if (freeBufList[i]) { pOvlySurface = (struct _sOvlySurface *)freeBufList[i]; break; } } if (!pOvlySurface) { /*pr_debug("********Oops: pOvlySurface" " is NULL!!!!\n\n");*/ return -1; } startaddr = (unsigned long)pOvlySurface->videoBufferAddr.startAddr; fbid = (int)pOvlySurface->videoBufferAddr.frameID; /* * Got new frame? */ if (dfli->new_addr != startaddr) { /* * Collect expired frame to list. */ collectFreeBuf(filterBufList, freeBufList, (i)); } /* * Update new surface. */ if (check_surface(fi, pOvlySurface->videoMode, &pOvlySurface->viewPortInfo, &pOvlySurface->viewPortOffset, &pOvlySurface->videoBufferAddr)) { dovefb_ovly_set_par(fi); dfli->cur_fbid = fbid; } return 0; }
static int dovefb_ovly_open(struct fb_info *fi, int user) { struct dovefb_mach_info *dmi; struct dovefb_layer_info *dfli = fi->par; struct fb_var_screeninfo *var = &fi->var; dmi = dfli->dev->platform_data; dfli->new_addr = 0; dfli->cur_fbid = 0; fi->fix.smem_start = dfli->fb_start_dma; fi->fix.smem_len = dfli->fb_size; fi->screen_base = dfli->fb_start; fi->screen_size = dfli->fb_size; memset(dfli->fb_start, 0, dfli->fb_size); dfli->pix_fmt = dmi->pix_fmt; dfli->surface.videoMode = -1; dfli->surface.viewPortInfo.srcWidth = var->xres; dfli->surface.viewPortInfo.srcHeight = var->yres; dfli->surface.viewPortInfo.zoomXSize = var->xres; dfli->surface.viewPortInfo.zoomYSize = var->yres; dfli->surface.videoBufferAddr.startAddr = (unsigned char *)fi->fix.smem_start; dovefb_set_pix_fmt(var, dfli->pix_fmt); dovefb_ovly_set_par(fi); if (mutex_is_locked(&dfli->access_ok)) mutex_unlock(&dfli->access_ok); /* clear buffer list. */ mutex_lock(&dfli->access_ok); clearFreeBuf(filterBufList, RESET_BUF); clearFreeBuf(freeBufList, RESET_BUF|FREE_ENTRY); mutex_unlock(&dfli->access_ok); dfli->vid_ovly_phys_addr_y = 0; return 0; }
static int dovefb_ovly_ioctl(struct fb_info *fi, unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *)arg; struct dovefb_layer_info *dfli = fi->par; u32 x; int vmode = 0; int gfx_on = 1; int vid_on = 1; int interpolation = 0; switch (cmd) { case DOVEFB_IOCTL_WAIT_VSYNC: wait_for_vsync(dfli); break; case DOVEFB_IOCTL_GET_VIEWPORT_INFO: return copy_to_user(argp, &dfli->surface.viewPortInfo, sizeof(struct _sViewPortInfo)) ? -EFAULT : 0; case DOVEFB_IOCTL_SET_VIEWPORT_INFO: mutex_lock(&dfli->access_ok); if (copy_from_user(&gViewPortInfo, argp, sizeof(gViewPortInfo))) { mutex_unlock(&dfli->access_ok); return -EFAULT; } if (check_surface(fi, -1, &gViewPortInfo, 0, 0)) dovefb_ovly_set_par(fi); mutex_unlock(&dfli->access_ok); break; case DOVEFB_IOCTL_SET_VIDEO_MODE: /* * Get data from user space. */ if (copy_from_user(&vmode, argp, sizeof(vmode))) return -EFAULT; if (check_surface(fi, vmode, 0, 0, 0)) dovefb_ovly_set_par(fi); break; case DOVEFB_IOCTL_GET_VIDEO_MODE: return copy_to_user(argp, &dfli->surface.videoMode, sizeof(u32)) ? -EFAULT : 0; case DOVEFB_IOCTL_CREATE_VID_BUFFER: { struct _sOvlySurface OvlySurface; mutex_lock(&dfli->access_ok); if (copy_from_user(&OvlySurface, argp, sizeof(struct _sOvlySurface))) { mutex_unlock(&dfli->access_ok); return -EFAULT; } /* Request a video buffer. */ dovefb_ovly_create_surface(&OvlySurface); if (copy_to_user(argp, &OvlySurface, sizeof(struct _sOvlySurface))) { mutex_unlock(&dfli->access_ok); return -EFAULT; } mutex_unlock(&dfli->access_ok); break; } case DOVEFB_IOCTL_FLIP_VID_BUFFER: { struct _sOvlySurface *surface = 0; u8 *start_addr, *input_data, *dst_addr; u32 length; surface = kmalloc(sizeof(struct _sOvlySurface), GFP_KERNEL); /* Get user-mode data. */ if (copy_from_user(surface, argp, sizeof(struct _sOvlySurface))) { kfree(surface); return -EFAULT; } mutex_lock(&dfli->access_ok); length = surface->videoBufferAddr.length; dst_addr = dfli->surface.videoBufferAddr.startAddr; start_addr = surface->videoBufferAddr.startAddr; input_data = surface->videoBufferAddr.inputData; /* * Has DMA addr? */ if (start_addr && (!input_data)) { if (0 != addFreeBuf(freeBufList, (u8 *)surface)) { pr_debug("Error: addFreeBuf()\n"); mutex_unlock(&dfli->access_ok); kfree(surface); return -EFAULT; } else { /* pr_debug("addFreeBuf(0x%08x) ok.\n", start_addr); */ } } else { if (check_surface(fi, surface->videoMode, &surface->viewPortInfo, &surface->viewPortOffset, &surface->videoBufferAddr)) dovefb_ovly_set_par(fi); /* copy buffer */ if (input_data) { wait_for_vsync(dfli); /* if support hw DMA, replace this. */ if (copy_from_user(dfli->fb_start, input_data, length)) { mutex_unlock(&dfli->access_ok); kfree(surface); return -EFAULT; } mutex_unlock(&dfli->access_ok); kfree(surface); return 0; } kfree(surface); #if 0 /* * Fix me: Currently not implemented yet. * Application allocate a physical contiguous * buffer and pass it into driver. Here is to * update fb's info to new buffer and free * old buffer. */ if (start_addr) { if (dfli->mem_status) free_pages( (unsigned long)dfli->fb_start, get_order(dfli->fb_size)); else dma_free_writecombine(dfli->dev, dfli->fb_size, dfli->fb_start, dfli->fb_start_dma); dfli->fb_start = __va(start_addr); dfli->fb_size = length; dfli->fb_start_dma = (dma_addr_t)__pa(dfli->fb_start); dfli->mem_status = 1; fi->fix.smem_start = dfli->fb_start_dma; fi->fix.smem_len = dfli->fb_size; fi->screen_base = dfli->fb_start; fi->screen_size = dfli->fb_size; } #endif } mutex_unlock(&dfli->access_ok); return 0; } case DOVEFB_IOCTL_GET_FREELIST: { mutex_lock(&dfli->access_ok); if (copy_to_user(argp, filterBufList, MAX_QUEUE_NUM*sizeof(u8 *))) { mutex_unlock(&dfli->access_ok); return -EFAULT; } clearFreeBuf(filterBufList, RESET_BUF); mutex_unlock(&dfli->access_ok); return 0; } case DOVEFB_IOCTL_GET_BUFF_ADDR: { return copy_to_user(argp, &dfli->surface.videoBufferAddr, sizeof(struct _sVideoBufferAddr)) ? -EFAULT : 0; } case DOVEFB_IOCTL_SET_VID_OFFSET: mutex_lock(&dfli->access_ok); if (copy_from_user(&gViewPortOffset, argp, sizeof(gViewPortOffset))) { mutex_unlock(&dfli->access_ok); return -EFAULT; } if (check_surface(fi, -1, 0, &gViewPortOffset, 0)) dovefb_ovly_set_par(fi); mutex_unlock(&dfli->access_ok); break; case DOVEFB_IOCTL_GET_VID_OFFSET: return copy_to_user(argp, &dfli->surface.viewPortOffset, sizeof(struct _sViewPortOffset)) ? -EFAULT : 0; case DOVEFB_IOCTL_SET_MEMORY_TOGGLE: break; case DOVEFB_IOCTL_SET_COLORKEYnALPHA: if (copy_from_user(&dfli->ckey_alpha, argp, sizeof(struct _sColorKeyNAlpha))) return -EFAULT; dovefb_ovly_set_colorkeyalpha(dfli); break; case DOVEFB_IOCTL_GET_COLORKEYnALPHA: if (copy_to_user(argp, &dfli->ckey_alpha, sizeof(struct _sColorKeyNAlpha))) return -EFAULT; break; case DOVEFB_IOCTL_SWITCH_VID_OVLY: if (copy_from_user(&vid_on, argp, sizeof(int))) return -EFAULT; if (0 == vid_on) { x = readl(dfli->reg_base + LCD_SPU_DMA_CTRL0) & ~CFG_DMA_ENA_MASK; writel(x, dfli->reg_base + LCD_SPU_DMA_CTRL0); } else { x = readl(dfli->reg_base + LCD_SPU_DMA_CTRL0) | CFG_DMA_ENA(0x1); writel(x, dfli->reg_base + LCD_SPU_DMA_CTRL0); /* Enable VID & VSync. */ x = readl(dfli->reg_base + SPU_IRQ_ENA) | DOVEFB_VID_INT_MASK | DOVEFB_VSYNC_INT_MASK; writel(x, dfli->reg_base + SPU_IRQ_ENA); } break; case DOVEFB_IOCTL_SWITCH_GRA_OVLY: if (copy_from_user(&gfx_on, argp, sizeof(int))) return -EFAULT; if (0 == gfx_on) { x = readl(dfli->reg_base + LCD_SPU_DMA_CTRL0) & ~CFG_GRA_ENA_MASK; writel(x, dfli->reg_base + LCD_SPU_DMA_CTRL0); } else { x = readl(dfli->reg_base + LCD_SPU_DMA_CTRL0) | CFG_GRA_ENA(0x1); writel(x, dfli->reg_base + LCD_SPU_DMA_CTRL0); } break; case DOVEFB_IOCTL_GET_FBID: mutex_lock(&dfli->access_ok); if (copy_to_user(argp, &dfli->cur_fbid, sizeof(unsigned int))) { mutex_unlock(&dfli->access_ok); return -EFAULT; } mutex_unlock(&dfli->access_ok); break; case DOVEFB_IOCTL_GET_SRC_MODE: mutex_lock(&dfli->access_ok); if (copy_to_user(argp, &dfli->src_mode, sizeof(int))) { mutex_unlock(&dfli->access_ok); return -EFAULT; } mutex_unlock(&dfli->access_ok); break; case DOVEFB_IOCTL_SET_SRC_MODE: mutex_lock(&dfli->access_ok); if (copy_from_user(&dfli->src_mode, argp, sizeof(int))) { mutex_unlock(&dfli->access_ok); return -EFAULT; } if (SHM_NORMAL == dfli->src_mode) { int i; /* * Recycle all video buffer. */ /* 1. collect freelist buffer */ for (i = (MAX_QUEUE_NUM-1); i >= 0; i--) { if (freeBufList[i]) break; } collectFreeBuf(filterBufList, freeBufList, (i)); /* 2. Recycle current frame to filter list. */ for (i = 0; i < MAX_QUEUE_NUM; i++) { if (!filterBufList[i]) filterBufList[i] = (u8 *)dfli->new_addr; } /* clear and reset related resource. */ clearFreeBuf(freeBufList, RESET_BUF|FREE_ENTRY); dfli->new_addr = 0; dfli->cur_fbid = 0; memset(dfli->fb_start, 0, dfli->fb_size); } mutex_unlock(&dfli->access_ok); break; case DOVEFB_IOCTL_GET_FBPA: { struct shm_private_info info; int index; if (copy_from_user(&info, argp, sizeof(struct shm_private_info))) return -EFAULT; /* which frame want to find. */ index = info.fbid; /* calc physical address. */ info.fb_pa = (unsigned long)(dfli->fb_start_dma+ (index*info.width*info.height*MAX_YUV_PIXEL)); if (copy_to_user(argp, &info, sizeof(struct shm_private_info))) return -EFAULT; break; } case DOVEFB_IOCTL_NEXT_FRAME_PRESENT: { unsigned int phy_addr[3]; mutex_lock(&dfli->access_ok); if (copy_from_user(&phy_addr, argp, 3*sizeof(unsigned int))) { mutex_unlock(&dfli->access_ok); return -EFAULT; } mutex_unlock(&dfli->access_ok); dfli->vid_ovly_phys_addr_y = phy_addr[0]; dfli->vid_ovly_phys_addr_u = phy_addr[1]; dfli->vid_ovly_phys_addr_v = phy_addr[2]; break; } case DOVEFB_IOCTL_SET_INTERPOLATION_MODE: /* * Get data from user space. */ if (copy_from_user(&interpolation, argp, sizeof(interpolation))) return -EFAULT; if ((interpolation == 0) || (interpolation == 3)) writel(CFG_VSC_LINEAR(interpolation) | (readl(dfli->reg_base + SPU_IOPAD_CONTROL) & !CFG_VSC_LINEAR_MASK), dfli->reg_base + SPU_IOPAD_CONTROL); break; default: pr_debug("ioctl_ovly(0x%x) No match.\n", cmd); break; } return 0; }