/* * Present frame and synchronize with the display to prevent tearing * On DSI panels the sync function is used to handle FRAMEDONE IRQ * On DPI panels the wait_for_vsync is used to handle VSYNC IRQ * in: psDevInfo */ void OMAPLFBPresentSync(OMAPLFB_DEVINFO *psDevInfo, OMAPLFB_FLIP_ITEM *psFlipItem) { struct fb_info *framebuffer = psDevInfo->psLINFBInfo; struct omapfb_info *ofbi = FB2OFB(framebuffer); struct omap_dss_device *display; struct omapfb2_device *fbdev = ofbi->fbdev; struct omap_dss_driver *driver; struct omap_overlay_manager *manager; int err = 1; omapfb_lock(fbdev); // [email protected] Backup the Display device for using later [START] #if defined(CONFIG_MACH_LGE_OMAP3) Prev_disp = display = fb2display(framebuffer); #else display = fb2display(framebuffer); #endif // [email protected] Backup the Display device for using later [END] /* The framebuffer doesn't have a display attached, just bail out */ if (!display) { omapfb_unlock(fbdev); return; } driver = display->driver; manager = display->manager; if (driver && driver->sync && driver->get_update_mode(display) == OMAP_DSS_UPDATE_MANUAL) { /* Wait first for the DSI bus to be released then update */ err = driver->sync(display); OMAPLFBFlipNoLock(psDevInfo->psSwapChain, (unsigned long)psFlipItem->sSysAddr->uiAddr); } else if (manager && manager->wait_for_vsync) { /* * Update the video pipelines registers then wait until the * frame is shown with a VSYNC */ OMAPLFBFlipNoLock(psDevInfo->psSwapChain, (unsigned long)psFlipItem->sSysAddr->uiAddr); err = manager->wait_for_vsync(manager); } if (err) WARNING_PRINTK("Unable to sync with display %u!", psDevInfo->uDeviceID); omapfb_unlock(fbdev); }
static int omapfb_get_update_mode(struct fb_info *fbi, enum omapfb_update_mode *mode) { struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; struct omap_display *display = fb2display(fbi); enum omap_dss_update_mode m; if (!display || !display->get_update_mode) return -EINVAL; omapfb_lock(fbdev); m = display->get_update_mode(display); omapfb_unlock(fbdev); switch (m) { case OMAP_DSS_UPDATE_DISABLED: *mode = OMAPFB_UPDATE_DISABLED; break; case OMAP_DSS_UPDATE_AUTO: *mode = OMAPFB_AUTO_UPDATE; break; case OMAP_DSS_UPDATE_MANUAL: *mode = OMAPFB_MANUAL_UPDATE; break; default: BUG(); } return 0; }
static ssize_t show_managers(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct omapfb2_device *fbdev = platform_get_drvdata(pdev); ssize_t l = 0, size = PAGE_SIZE; int i; omapfb_lock(fbdev); for (i = 0; i < fbdev->num_managers; i++) { struct omap_display *display; struct omap_overlay_manager *mgr; mgr = fbdev->managers[i]; display = mgr->display; l += snprintf(buf + l, size - l, "%s t:%s trans:%d type:%d key:%08x alpha:%d\n", mgr->name, display ? display->name : "none", mgr->info.trans_enabled, mgr->info.trans_key_type, mgr->info.trans_key, mgr->info.alpha_enabled); } omapfb_unlock(fbdev); return l; }
static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) { struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; omapfb_lock(fbdev); if (ofbi->num_overlays != 1) { memset(pi, 0, sizeof(*pi)); } else { struct omap_overlay_info *ovli; struct omap_overlay *ovl; ovl = ofbi->overlays[0]; ovli = &ovl->info; pi->pos_x = ovli->pos_x; pi->pos_y = ovli->pos_y; pi->enabled = ovli->enabled; pi->channel_out = 0; /* xxx */ pi->mirror = 0; pi->out_width = ovli->out_width; pi->out_height = ovli->out_height; } omapfb_unlock(fbdev); return 0; }
static int omapfb_update_window(struct fb_info *fbi, u32 x, u32 y, u32 w, u32 h) { struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; struct omap_display *display = fb2display(fbi); int dw, dh; if (!display) return 0; if (w == 0 || h == 0) return 0; display->get_resolution(display, &dw, &dh); if (x + w > dw || y + h > dh) return -EINVAL; omapfb_lock(fbdev); display->update(display, x, y, w, h); omapfb_unlock(fbdev); return 0; }
static ssize_t show_overlays(struct device *dev, struct device_attribute *attr, char *buf) { struct fb_info *fbi = dev_get_drvdata(dev); struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; ssize_t l = 0; int t; if (!lock_fb_info(fbi)) return -ENODEV; omapfb_lock(fbdev); for (t = 0; t < ofbi->num_overlays; t++) { struct omap_overlay *ovl = ofbi->overlays[t]; int ovlnum; for (ovlnum = 0; ovlnum < fbdev->num_overlays; ++ovlnum) if (ovl == fbdev->overlays[ovlnum]) break; l += snprintf(buf + l, PAGE_SIZE - l, "%s%d", t == 0 ? "" : ",", ovlnum); } l += snprintf(buf + l, PAGE_SIZE - l, "\n"); omapfb_unlock(fbdev); unlock_fb_info(fbi); return l; }
static int omapfb_set_update_mode(struct fb_info *fbi, enum omapfb_update_mode mode) { struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; struct omap_display *display = fb2display(fbi); enum omap_dss_update_mode um; int r; if (!display || !display->set_update_mode) return -EINVAL; switch (mode) { case OMAPFB_UPDATE_DISABLED: um = OMAP_DSS_UPDATE_DISABLED; break; case OMAPFB_AUTO_UPDATE: um = OMAP_DSS_UPDATE_AUTO; break; case OMAPFB_MANUAL_UPDATE: um = OMAP_DSS_UPDATE_MANUAL; break; default: return -EINVAL; } omapfb_lock(fbdev); r = display->set_update_mode(display, um); omapfb_unlock(fbdev); return r; }
static int omapfb_get_color_key(struct fb_info *fbi, struct omapfb_color_key *ck) { struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; struct omap_overlay_manager *mgr = NULL; int r = 0; int i; omapfb_lock(fbdev); for (i = 0; i < ofbi->num_overlays; i++) { if (ofbi->overlays[i]->manager) { mgr = ofbi->overlays[i]->manager; break; } } if (!mgr) { r = -EINVAL; goto err; } *ck = omapfb_color_keys[mgr->id]; err: omapfb_unlock(fbdev); return r; }
static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) { struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; struct omap_display *display = fb2display(fbi); struct omap_overlay *ovl; int r = 0; DBG("omapfb_setup_plane\n"); omapfb_lock(fbdev); if (ofbi->num_overlays != 1) { r = -EINVAL; goto out; } /* XXX uses only the first overlay */ ovl = ofbi->overlays[0]; if (pi->enabled && !ofbi->region.size) { /* * This plane's memory was freed, can't enable it * until it's reallocated. */ r = -EINVAL; goto out; } if (pi->enabled) { r = omapfb_setup_overlay(fbi, ovl, pi->pos_x, pi->pos_y, pi->out_width, pi->out_height); if (r) goto out; } ovl->enable(ovl, pi->enabled); if (ovl->manager) ovl->manager->apply(ovl->manager); if (display) { int w, h; if (display->sync) display->sync(display); display->get_resolution(display, &w, &h); if (display->update) display->update(display, 0, 0, w, h); } out: omapfb_unlock(fbdev); if (r) dev_err(fbdev->dev, "setup_plane failed\n"); return r; }
int omapfb_set_update_mode(struct fb_info *fbi, enum omapfb_update_mode mode) { struct omap_dss_device *display = fb2display(fbi); struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; struct omapfb_display_data *d; int r; if (!display) return -EINVAL; if (mode != OMAPFB_AUTO_UPDATE && mode != OMAPFB_MANUAL_UPDATE) return -EINVAL; omapfb_lock(fbdev); d = get_display_data(fbdev, display); if (d->update_mode == mode) { omapfb_unlock(fbdev); return 0; } r = 0; if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { if (mode == OMAPFB_AUTO_UPDATE) omapfb_start_auto_update(fbdev, display); else /* MANUAL_UPDATE */ omapfb_stop_auto_update(fbdev, display); d->update_mode = mode; } else { /* AUTO_UPDATE */ if (mode == OMAPFB_MANUAL_UPDATE) r = -EINVAL; } omapfb_unlock(fbdev); return r; }
static ssize_t show_displays(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct omapfb2_device *fbdev = platform_get_drvdata(pdev); ssize_t l = 0, size = PAGE_SIZE; int i; struct omap_video_timings timings; omapfb_lock(fbdev); for (i = 0; i < fbdev->num_displays; i++) { struct omap_display *display; enum omap_dss_update_mode mode = -1; int te = 0; int rot = 0, mir = 0; display = fbdev->displays[i]; if (display->get_update_mode) mode = display->get_update_mode(display); if (display->get_te) te = display->get_te(display); if (display->get_timings) display->get_timings(display, &timings); else memset(&timings, 0, sizeof(timings)); if (display->get_rotate) rot = display->get_rotate(display); if (display->get_mirror) mir = display->get_mirror(display); l += snprintf(buf + l, size - l, "%s e:%d u:%d t:%d h:%u/%u/%u/%u " "v:%u/%u/%u/%u p:%u r:%d i:%d\n", display->name, display->state != OMAP_DSS_DISPLAY_DISABLED, mode, te, timings.x_res, timings.hfp, timings.hbp, timings.hsw, timings.y_res, timings.vfp, timings.vbp, timings.vsw, timings.pixel_clock, rot, mir); } omapfb_unlock(fbdev); return l; }
void OMAPLFBFlip(OMAPLFB_SWAPCHAIN *psSwapChain, unsigned long aPhyAddr) { OMAPLFB_DEVINFO *psDevInfo = (OMAPLFB_DEVINFO *)psSwapChain->pvDevInfo; struct fb_info *framebuffer = psDevInfo->psLINFBInfo; struct omapfb_info *ofbi = FB2OFB(framebuffer); struct omapfb2_device *fbdev = ofbi->fbdev; omapfb_lock(fbdev); OMAPLFBFlipNoLock(psSwapChain, aPhyAddr); omapfb_unlock(fbdev); }
/* * Synchronize with the display to prevent tearing * On DSI panels the display->sync function is used to handle FRAMEDONE IRQ * On DPI panels the display->wait_vsync is used to handle VSYNC IRQ * in: psDevInfo */ void OMAPLFBPresentSync(OMAPLFB_DEVINFO *psDevInfo, OMAPLFB_FLIP_ITEM *psFlipItem) { struct fb_info * framebuffer = psDevInfo->psLINFBInfo; struct omapfb_info *ofbi = FB2OFB(framebuffer); struct omapfb2_device *fbdev = ofbi->fbdev; struct omap_dss_device *display; int err = 1; omapfb_lock(fbdev); display = fb2display(framebuffer); /* The framebuffer doesn't have a display attached, just bail out */ if (!display) { omapfb_unlock(fbdev); return; } if (display->sync && display->get_update_mode(display) == OMAP_DSS_UPDATE_MANUAL) { /* Wait first for the DSI bus to be released then update */ err = display->sync(display); OMAPLFBFlipNoLock(psDevInfo->psSwapChain, (unsigned long)psFlipItem->sSysAddr->uiAddr); } else if (display->wait_vsync) { /* * Update the video pipelines registers then wait until the * frame is shown with a VSYNC */ OMAPLFBFlipNoLock(psDevInfo->psSwapChain, (unsigned long)psFlipItem->sSysAddr->uiAddr); err = display->wait_vsync(display); } if (err) WARNING_PRINTK("Unable to sync with display %u!", psDevInfo->uDeviceID); omapfb_unlock(fbdev); }
static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) { struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; struct omapfb2_mem_region *rg; rg = &ofbi->region; memset(mi, 0, sizeof(*mi)); omapfb_lock(fbdev); mi->size = rg->size; mi->type = rg->type; omapfb_unlock(fbdev); return 0; }
/* This function is exported for SGX driver use */ int omapfb_update_window(struct fb_info *fbi, u32 x, u32 y, u32 w, u32 h) { struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; int r; if (!lock_fb_info(fbi)) return -ENODEV; omapfb_lock(fbdev); r = omapfb_update_window_nolock(fbi, x, y, w, h); omapfb_unlock(fbdev); unlock_fb_info(fbi); return r; }
static ssize_t show_overlays(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct omapfb2_device *fbdev = platform_get_drvdata(pdev); ssize_t l = 0, size = PAGE_SIZE; int i, mgr_num, alpha; omapfb_lock(fbdev); for (i = 0; i < fbdev->num_overlays; i++) { struct omap_overlay *ovl; struct omap_overlay_manager *mgr; ovl = fbdev->overlays[i]; mgr = ovl->manager; if (strcmp(ovl->name, "vid1") != 0) alpha = ovl->info.global_alpha; else alpha = -1; for (mgr_num = 0; mgr_num < fbdev->num_managers; mgr_num++) if (fbdev->managers[mgr_num] == mgr) break; l += snprintf(buf + l, size - l, "%s t:%s x:%d y:%d iw:%d ih:%d w:%d h:%d a:%d e:%d\n", ovl->name, mgr ? mgr->name : "none", ovl->info.pos_x, ovl->info.pos_y, ovl->info.width, ovl->info.height, ovl->info.out_width, ovl->info.out_height, alpha, ovl->info.enabled); } omapfb_unlock(fbdev); return l; }
void OMAPLFBFlip(OMAPLFB_SWAPCHAIN *psSwapChain, unsigned long aPhyAddr) { struct omap_overlay* overlay; struct omap_overlay_info overlay_info; struct fb_info * framebuffer; OMAPLFB_DEVINFO *psDevInfo; struct omapfb_info *ofbi; struct omapfb2_device *fbdev; int i; unsigned long fb_offset; psDevInfo = (OMAPLFB_DEVINFO *) psSwapChain->pvDevInfo; framebuffer = psDevInfo->psLINFBInfo; ofbi = FB2OFB(framebuffer); fb_offset = aPhyAddr - psDevInfo->sSystemBuffer.sSysAddr.uiAddr; fbdev = ofbi->fbdev; omapfb_lock(fbdev); for(i = 0; i < ofbi->num_overlays ; i++) { overlay = ofbi->overlays[i]; overlay->get_overlay_info( overlay, &overlay_info ); /* If the overlay is not enabled don't update it */ if(!overlay_info.enabled) continue; overlay_info.paddr = framebuffer->fix.smem_start + fb_offset; overlay_info.vaddr = framebuffer->screen_base + fb_offset; overlay->set_overlay_info(overlay, &overlay_info); overlay->manager->apply(overlay->manager); if(overlay->manager->device->update) { overlay->manager->device->update( overlay->manager->device, 0, 0, overlay_info.width, overlay_info.height); } } omapfb_unlock(fbdev); }
int omapfb_get_update_mode(struct fb_info *fbi, enum omapfb_update_mode *mode) { struct omap_dss_device *display = fb2display(fbi); struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; struct omapfb_display_data *d; if (!display) return -EINVAL; omapfb_lock(fbdev); d = get_display_data(fbdev, display); *mode = d->update_mode; omapfb_unlock(fbdev); return 0; }
static ssize_t show_framebuffers(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct omapfb2_device *fbdev = platform_get_drvdata(pdev); ssize_t l = 0, size = PAGE_SIZE; int i, t; omapfb_lock(fbdev); for (i = 0; i < fbdev->num_fbs; i++) { struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]); struct omapfb2_mem_region *rg; rg = &ofbi->region; l += snprintf(buf + l, size - l, "%d p:%08x v:%p size:%lu t:", ofbi->id, rg->_paddr, rg->_vaddr, rg->size); if (ofbi->num_overlays == 0) l += snprintf(buf + l, size - l, "none"); for (t = 0; t < ofbi->num_overlays; t++) { struct omap_overlay *ovl; ovl = ofbi->overlays[t]; l += snprintf(buf + l, size - l, "%s%s", t == 0 ? "" : ",", ovl->name); } l += snprintf(buf + l, size - l, "\n"); } omapfb_unlock(fbdev); return l; }
static ssize_t store_managers(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); struct omapfb2_device *fbdev = platform_get_drvdata(pdev); int idx; struct omap_overlay_manager *mgr; struct omap_display *display; char mgrname[10]; char displayname[10]; int r; idx = 0; while (idx < count && buf[idx] != ' ') ++idx; if (idx == count) return -EINVAL; if (idx >= sizeof(mgrname)) return -EINVAL; strncpy(mgrname, buf, idx); mgrname[idx] = 0; idx++; omapfb_lock(fbdev); mgr = find_manager_by_name(fbdev, mgrname); if (!mgr) { dev_err(dev, "manager not found\n"); r = -EINVAL; goto err; } r = sscanf(buf + idx, "t:%9s", displayname); if (r != 1) { r = -EINVAL; goto err; } if (strcmp(displayname, "none") == 0) { display = NULL; } else { display = find_display_by_name(fbdev, displayname); if (!display) { dev_err(dev, "display not found\n"); r = -EINVAL; goto err; } } if (mgr->display) { r = mgr->unset_display(mgr); if (r) { dev_err(dev, "failed to unset display\n"); goto err; } } if (display) { r = mgr->set_display(mgr, display); if (r) { dev_err(dev, "failed to set manager\n"); goto err; } r = mgr->apply(mgr); if (r) { dev_err(dev, "failed to apply dispc config\n"); goto err; } } omapfb_unlock(fbdev); return count; err: omapfb_unlock(fbdev); return r; }
static ssize_t store_overlays(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); struct omapfb2_device *fbdev = platform_get_drvdata(pdev); int idx; struct omap_overlay *ovl = NULL; struct omap_overlay_manager *mgr; int r; char ovlname[10]; int posx, posy, outw, outh; int enabled; int alpha; idx = 0; while (idx < count && buf[idx] != ' ') ++idx; if (idx == count) return -EINVAL; if (idx >= sizeof(ovlname)) return -EINVAL; strncpy(ovlname, buf, idx); ovlname[idx] = 0; idx++; omapfb_lock(fbdev); ovl = find_overlay_by_name(fbdev, ovlname); if (!ovl) { dev_err(dev, "ovl not found\n"); r = -EINVAL; goto err; } DBG("ovl %s found\n", ovl->name); mgr = ovl->manager; posx = ovl->info.pos_x; posy = ovl->info.pos_y; outw = ovl->info.out_width; outh = ovl->info.out_height; if (strcmp(ovl->name, "vid1") != 0) alpha = ovl->info.global_alpha; else alpha = -1; enabled = ovl->info.enabled; while (idx < count) { char c; int val; int len; char sval[10]; r = sscanf(buf + idx, "%c:%d%n", &c, &val, &len); if (r != 2) { val = 0; r = sscanf(buf + idx, "%c:%9s%n", &c, sval, &len); if (r != 2) { dev_err(dev, "sscanf failed, aborting\n"); r = -EINVAL; goto err; } } else { sval[0] = 0; } switch (c) { case 't': if (strcmp(sval, "none") == 0) { mgr = NULL; } else { mgr = find_manager_by_name(fbdev, sval); if (mgr == NULL) { dev_err(dev, "no such manager\n"); r = -EINVAL; goto err; } DBG("manager %s found\n", mgr->name); } break; case 'x': posx = val; break; case 'y': posy = val; break; case 'w': if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) outw = val; break; case 'h': if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) outh = val; break; case 'a': alpha = val & 0xff; break; case 'e': enabled = val; break; default: dev_err(dev, "unknown option %c\n", c); r = -EINVAL; goto err; } idx += len + 1; } if (strcmp(ovl->name, "vid1") != 0) ovl->info.global_alpha = alpha; r = ovl->setup_output(ovl, posx, posy, outw, outh); if (r) { dev_err(dev, "setup overlay failed\n"); goto err; } if (mgr != ovl->manager) { /* detach old manager */ if (ovl->manager) { r = ovl->unset_manager(ovl); if (r) { dev_err(dev, "detach failed\n"); goto err; } } if (mgr) { r = ovl->set_manager(ovl, mgr); if (r) { dev_err(dev, "Failed to attach overlay\n"); goto err; } } } r = ovl->enable(ovl, enabled); if (r) { dev_err(dev, "enable overlay failed\n"); goto err; } if (mgr) { r = mgr->apply(mgr); if (r) { dev_err(dev, "failed to apply dispc config\n"); goto err; } } else { ovl->enable(ovl, 0); } if (mgr && mgr->display && mgr->display->update) { int w, h; mgr->display->get_resolution(mgr->display, &w, &h); mgr->display->update(mgr->display, 0, 0, w, h); } omapfb_unlock(fbdev); return count; err: omapfb_unlock(fbdev); return r; }
static ssize_t store_framebuffers(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); struct omapfb2_device *fbdev = platform_get_drvdata(pdev); int idx; char fbname[3]; unsigned long fbnum; char ovlnames[40]; int num_ovls = 0; struct omap_overlay *ovls[OMAPFB_MAX_OVL_PER_FB]; struct fb_info *fbi; struct omapfb_info *ofbi; int r, i; idx = 0; while (idx < count && buf[idx] != ' ') ++idx; if (idx == count) return -EINVAL; if (idx >= sizeof(fbname)) return -EINVAL; strncpy(fbname, buf, idx); fbname[idx] = 0; idx++; if (strict_strtoul(fbname, 10, &fbnum)) return -EINVAL; r = sscanf(buf + idx, "t:%39s", ovlnames); if (r != 1) { r = -EINVAL; goto err; } omapfb_lock(fbdev); if (fbnum >= fbdev->num_fbs) { dev_err(dev, "fb not found\n"); r = -EINVAL; goto err; } fbi = fbdev->fbs[fbnum]; ofbi = FB2OFB(fbi); if (strcmp(ovlnames, "none") == 0) { num_ovls = 0; } else { num_ovls = parse_overlays(fbdev, ovlnames, ovls); if (num_ovls == 0) { dev_err(dev, "overlays not found\n"); r = -EINVAL; goto err; } } for (i = 0; i < ofbi->num_overlays; i++) { r = omapfb_detach_framebuffer(fbi, ofbi->overlays[i]); if (r) { dev_err(dev, "detach failed\n"); goto err; } } if (num_ovls > 0) { for (i = 0; i < num_ovls; i++) { r = omapfb_attach_framebuffer(fbi, ovls[i]); if (r) { dev_err(dev, "attach failed\n"); goto err; } } } omapfb_unlock(fbdev); return count; err: omapfb_unlock(fbdev); return r; }
static ssize_t store_overlays(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct fb_info *fbi = dev_get_drvdata(dev); struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; struct omap_overlay *ovls[OMAPFB_MAX_OVL_PER_FB]; struct omap_overlay *ovl; int num_ovls, r, i; int len; bool added = false; num_ovls = 0; len = strlen(buf); if (buf[len - 1] == '\n') len = len - 1; if (!lock_fb_info(fbi)) return -ENODEV; omapfb_lock(fbdev); if (len > 0) { char *p = (char *)buf; int ovlnum; while (p < buf + len) { int found; if (num_ovls == OMAPFB_MAX_OVL_PER_FB) { r = -EINVAL; goto out; } ovlnum = simple_strtoul(p, &p, 0); if (ovlnum > fbdev->num_overlays) { r = -EINVAL; goto out; } found = 0; for (i = 0; i < num_ovls; ++i) { if (ovls[i] == fbdev->overlays[ovlnum]) { found = 1; break; } } if (!found) ovls[num_ovls++] = fbdev->overlays[ovlnum]; p++; } } for (i = 0; i < num_ovls; ++i) { struct omapfb_info *ofbi2 = get_overlay_fb(fbdev, ovls[i]); if (ofbi2 && ofbi2 != ofbi) { dev_err(fbdev->dev, "overlay already in use\n"); r = -EINVAL; goto out; } } /* detach unused overlays */ for (i = 0; i < ofbi->num_overlays; ++i) { int t, found; ovl = ofbi->overlays[i]; found = 0; for (t = 0; t < num_ovls; ++t) { if (ovl == ovls[t]) { found = 1; break; } } if (found) continue; DBG("detaching %d\n", ofbi->overlays[i]->id); omapfb_get_mem_region(ofbi->region); omapfb_overlay_enable(ovl, 0); if (ovl->manager) ovl->manager->apply(ovl->manager); omapfb_put_mem_region(ofbi->region); for (t = i + 1; t < ofbi->num_overlays; t++) { ofbi->rotation[t-1] = ofbi->rotation[t]; ofbi->overlays[t-1] = ofbi->overlays[t]; } ofbi->num_overlays--; i--; } for (i = 0; i < num_ovls; ++i) { int t, found; ovl = ovls[i]; found = 0; for (t = 0; t < ofbi->num_overlays; ++t) { if (ovl == ofbi->overlays[t]) { found = 1; break; } } if (found) continue; ofbi->rotation[ofbi->num_overlays] = 0; ofbi->overlays[ofbi->num_overlays++] = ovl; added = true; } if (added) { omapfb_get_mem_region(ofbi->region); r = omapfb_apply_changes(fbi, 0); omapfb_put_mem_region(ofbi->region); if (r) goto out; } r = count; out: omapfb_unlock(fbdev); unlock_fb_info(fbi); return r; }
static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) { struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; struct omapfb2_mem_region *rg; struct omap_display *display = fb2display(fbi); int r, i; size_t size; if (mi->type > OMAPFB_MEMTYPE_MAX) return -EINVAL; size = PAGE_ALIGN(mi->size); rg = &ofbi->region; omapfb_lock(fbdev); for (i = 0; i < ofbi->num_overlays; i++) { if (ofbi->overlays[i]->info.enabled) { r = -EBUSY; goto out; } } if (rg->size != size || rg->type != mi->type) { struct fb_var_screeninfo new_var; unsigned long old_size = rg->size; if (display->sync) display->sync(display); r = omapfb_realloc_fbmem(fbdev, ofbi->id, size); if (r) goto out; if (old_size != size) { if (size) { memcpy(&new_var, &fbi->var, sizeof(new_var)); r = check_fb_var(fbi, &new_var); if (r < 0) goto out; memcpy(&fbi->var, &new_var, sizeof(fbi->var)); set_fb_fix(fbi); } else { /* * Set these explicitly to indicate that the * plane memory is dealloce'd, the other * screen parameters in var / fix are invalid. */ fbi->fix.smem_start = 0; fbi->fix.smem_len = 0; } } } r = 0; out: omapfb_unlock(fbdev); return r; }
static ssize_t store_managers(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); struct omapfb2_device *fbdev = platform_get_drvdata(pdev); struct omap_overlay_manager *mgr; struct omap_display *display = NULL; char displayname[10]; int r; char *s, *tok; char str[128]; struct omap_overlay_manager_info newinfo; int apply = 0; displayname[0] = '\0'; if (strlen(buf) > sizeof(str) - 1) return -EINVAL; strcpy(str, buf); /* remove trailing linefeeds */ s = str + strlen(str) - 1; while (s >= str && *s == '\n') { *s = 0; s--; } s = str; if ((tok = strsep(&s, " ")) == 0) return -EINVAL; omapfb_lock(fbdev); mgr = find_manager_by_name(fbdev, tok); if (!mgr) { dev_err(dev, "manager not found\n"); r = -EINVAL; goto err; } newinfo = mgr->info; while ((tok = strsep(&s, " "))) { if (strncmp(tok, "t:", 2) == 0) { r = sscanf(tok, "t:%9s", displayname); if (r != 1) { r = -EINVAL; goto err; } } else if(strncmp(tok, "trans:", 6) == 0) { newinfo.trans_enabled = simple_strtoul(tok+6, NULL, 0); } else if(strncmp(tok, "type:", 5) == 0) { newinfo.trans_key_type = simple_strtoul(tok+5, NULL, 0); } else if(strncmp(tok, "key:", 4) == 0) { newinfo.trans_key = simple_strtoul(tok+4, NULL, 0); } else if(strncmp(tok, "alpha:", 6) == 0) { newinfo.alpha_enabled = simple_strtoul(tok+6, NULL, 0); } else { dev_err(dev, "unknown option\n"); r = -EINVAL; goto err; } } if (memcmp(&newinfo, &mgr->info, sizeof(struct omap_overlay_manager_info)) != 0) { mgr->info = newinfo; mgr->info_dirty = 1; apply = 1; } if (displayname[0] != '\0') { if (strcmp(displayname, "none") == 0) { display = NULL; } else { display = find_display_by_name(fbdev, displayname); if (!display) { dev_err(dev, "display not found: [%s]\n", displayname); r = -EINVAL; goto err; } } if (mgr->display) { r = mgr->unset_display(mgr); if (r) { dev_err(dev, "failed to unset display\n"); goto err; } } if (display) { r = mgr->set_display(mgr, display); if (r) { dev_err(dev, "failed to set manager\n"); goto err; } } apply = 1; } if (apply) { r = mgr->apply(mgr); if (r) { dev_err(dev, "failed to apply dispc config\n"); goto err; } } omapfb_unlock(fbdev); return count; err: omapfb_unlock(fbdev); return r; }
static ssize_t store_displays(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); struct omapfb2_device *fbdev = platform_get_drvdata(pdev); int enable; struct omap_video_timings old_timings; struct omap_video_timings new_timings; enum omap_dss_update_mode mode; enum omap_dss_venc_norm new_norm; enum omap_dss_venc_type new_type = OMAP_DSS_VENC_TYPE_COMPOSITE; struct omap_display *display = NULL; int r; int te, rot, mir; char str[128]; char *s, *tok; if (strlen(buf) > sizeof(str) - 1) return -EINVAL; strcpy(str, buf); /* remove trailing linefeeds */ s = str + strlen(str) - 1; while (s >= str && *s == '\n') { *s = 0; s--; } s = str; if ((tok = strsep(&s, " ")) == 0) return -EINVAL; omapfb_lock(fbdev); display = find_display_by_name(fbdev, tok); if (!display) { dev_err(dev, "display not found: [%s]\n", tok); r = -EINVAL; goto err; } enable = display->state != OMAP_DSS_DISPLAY_DISABLED; if (display->get_update_mode) mode = display->get_update_mode(display); else mode = 0; if (display->get_te) te = display->get_te(display); else te = 0; if (display->get_rotate) rot = display->get_rotate(display); else rot = 0; if (display->get_mirror) mir = display->get_mirror(display); else mir = 0; if (display->get_timings) display->get_timings(display, &old_timings); else memset(&old_timings, 0, sizeof(old_timings)); memcpy(&new_timings, &old_timings, sizeof(new_timings)); /* TV norm switching */ if (display->get_tv_norm) new_norm = display->get_tv_norm(display); else new_norm = -1; /* TV type switching */ if (display->get_tv_type) new_type = display->get_tv_type(display); while ((tok = strsep(&s, " "))) { char c, *o; if (strlen(tok) < 3 || tok[1] != ':') { dev_err(dev, "illegal option\n"); r = -EINVAL; goto err; } c = tok[0]; o = tok + 2; switch (c) { case 'e': enable = simple_strtoul(o, NULL, 0); break; case 'u': mode = simple_strtoul(o, NULL, 0); break; case 't': te = simple_strtoul(o, NULL, 0); break; case 'r': rot = simple_strtoul(o, NULL, 0); break; case 'i': mir = simple_strtoul(o, NULL, 0); break; case 'm': { unsigned bpp; if (omapfb_mode_to_timings(o, &new_timings, &bpp) != 0) memset(&new_timings, 0, sizeof(new_timings)); break; } case 'h': { unsigned xres, hfp, hbp, hsw; if (sscanf(o, "%u/%u/%u/%u", &xres, &hfp, &hbp, &hsw) != 4) { dev_err(dev, "illegal horizontal timings\n"); r = -EINVAL; goto err; } new_timings.x_res = xres; new_timings.hfp = hfp; new_timings.hbp = hbp; new_timings.hsw = hsw; break; } case 'v': { unsigned yres, vfp, vbp, vsw; if (sscanf(o, "%u/%u/%u/%u", &yres, &vfp, &vbp, &vsw) != 4) { dev_err(dev, "illegal vertical timings\n"); r = -EINVAL; goto err; } new_timings.y_res = yres; new_timings.vfp = vfp; new_timings.vbp = vbp; new_timings.vsw = vsw; break; } case 'p': new_timings.pixel_clock = simple_strtoul(o, NULL, 0); break; case 'l': new_timings.interlaced = simple_strtoul(o, NULL, 0); break; case 'n': new_norm = simple_strtoul(o, NULL, 0); break; case 's': new_type = simple_strtoul(o, NULL, 0); break; default: dev_err(dev, "unknown option %c\n", c); r = -EINVAL; goto err; } } if (memcmp(&new_timings, &old_timings, sizeof(new_timings)) != 0) { if (display->set_timings) display->set_timings(display, &new_timings); /* sigh, bpp is not a setting of the display, but * the overlay. */ //def_display->panel->bpp = bpp; } if (display->set_update_mode && display->get_update_mode) { if (mode != display->get_update_mode(display)) display->set_update_mode(display, mode); } if (display->enable_te && display->get_te) { if (te != display->get_te(display)) display->enable_te(display, te); } if (display->set_rotate && display->get_rotate) { if (rot != display->get_rotate(display)) display->set_rotate(display, rot); } if (display->set_mirror && display->get_mirror) { if (mir != display->get_mirror(display)) display->set_mirror(display, mir); } if (display->set_tv_norm) display->set_tv_norm(display, new_norm); if (display->set_tv_type) display->set_tv_type(display, new_type); /* enable display after all settings */ if (enable != (display->state != OMAP_DSS_DISPLAY_DISABLED)) { if (enable) { r = display->enable(display); if (r) dev_err(dev, "failed to enable display\n"); } else { display->disable(display); } } r = count; err: omapfb_unlock(fbdev); return r; }
int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) { struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; struct omap_display *display = fb2display(fbi); union { struct omapfb_update_window_old uwnd_o; struct omapfb_update_window uwnd; struct omapfb_plane_info plane_info; struct omapfb_caps caps; struct omapfb_mem_info mem_info; enum omapfb_update_mode update_mode; int test_num; } p; int r = 0; DBG("ioctl %x (%d)\n", cmd, cmd & 0xff); switch (cmd) { case OMAPFB_SYNC_GFX: if (!display || !display->sync) { /* DSS1 never returns an error here, so we neither */ /*r = -EINVAL;*/ break; } omapfb_lock(fbdev); r = display->sync(display); omapfb_unlock(fbdev); break; case OMAPFB_UPDATE_WINDOW_OLD: if (!display || !display->update) { r = -EINVAL; break; } if (copy_from_user(&p.uwnd_o, (void __user *)arg, sizeof(p.uwnd_o))) { r = -EFAULT; break; } r = omapfb_update_window(fbi, p.uwnd_o.x, p.uwnd_o.y, p.uwnd_o.width, p.uwnd_o.height); break; case OMAPFB_UPDATE_WINDOW: if (!display || !display->update) { r = -EINVAL; break; } if (copy_from_user(&p.uwnd, (void __user *)arg, sizeof(p.uwnd))) { r = -EFAULT; break; } r = omapfb_update_window(fbi, p.uwnd.x, p.uwnd.y, p.uwnd.width, p.uwnd.height); break; case OMAPFB_SETUP_PLANE: if (copy_from_user(&p.plane_info, (void __user *)arg, sizeof(p.plane_info))) r = -EFAULT; else r = omapfb_setup_plane(fbi, &p.plane_info); break; case OMAPFB_CROP_PLANE: if (copy_from_user(&p.plane_info, (void __user *)arg, sizeof(p.plane_info))) r = -EFAULT; else r = omapfb_crop_plane(fbi, &p.plane_info); break; case OMAPFB_QUERY_PLANE: r = omapfb_query_plane(fbi, &p.plane_info); if (r < 0) break; if (copy_to_user((void __user *)arg, &p.plane_info, sizeof(p.plane_info))) r = -EFAULT; break; case OMAPFB_SETUP_MEM: if (copy_from_user(&p.mem_info, (void __user *)arg, sizeof(p.mem_info))) r = -EFAULT; else r = omapfb_setup_mem(fbi, &p.mem_info); break; case OMAPFB_QUERY_MEM: r = omapfb_query_mem(fbi, &p.mem_info); if (r < 0) break; if (copy_to_user((void __user *)arg, &p.mem_info, sizeof(p.mem_info))) r = -EFAULT; break; case OMAPFB_GET_CAPS: if (!display) { r = -EINVAL; break; } p.caps.ctrl = display->caps; if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps))) r = -EFAULT; break; case OMAPFB_SET_UPDATE_MODE: if (get_user(p.update_mode, (int __user *)arg)) r = -EFAULT; else r = omapfb_set_update_mode(fbi, p.update_mode); break; case OMAPFB_GET_UPDATE_MODE: r = omapfb_get_update_mode(fbi, &p.update_mode); if (r) break; if (put_user(p.update_mode, (enum omapfb_update_mode __user *)arg)) r = -EFAULT; break; /* LCD and CTRL tests do the same thing for backward * compatibility */ case OMAPFB_LCD_TEST: if (get_user(p.test_num, (int __user *)arg)) { r = -EFAULT; break; } if (!display || !display->run_test) { r = -EINVAL; break; } r = display->run_test(display, p.test_num); break; case OMAPFB_CTRL_TEST: if (get_user(p.test_num, (int __user *)arg)) { r = -EFAULT; break; } if (!display || !display->run_test) { r = -EINVAL; break; } r = display->run_test(display, p.test_num); break; case OMAPFB_WAIT_FOR_VSYNC: return omapfb_wait_for_vsync(fbi); break; case OMAPFB_VRFB_ROTATE_CCW: ofbi->rotation_type = OMAPFB_ROT_VRFB; ofbi->rotation = FB_ROTATE_CCW; set_fb_fix(fbi); omapfb_apply_changes(fbi, 0); break; default: DBG("ioctl unhandled\n"); r = -EINVAL; } return r; }
static int present_buffer(struct omap_display_buffer *buffer) { struct omap_display_device *display = buffer->display; struct fb_info *framebuffer; struct omapfb_info *ofbi; struct omapfb2_device *fbdev; int i; int fb_idx; switch (display->id) { case OMAP_DISPID_PRIMARY: fb_idx = 0; break; case OMAP_DISPID_SECONDARY: fb_idx = 1; break; case OMAP_DISPID_TERTIARY: fb_idx = 2; break; case OMAP_DISPID_VIRTUAL: case OMAP_DISPID_BADSTATE: default: ERR_PRINT("Unable to handle display %i", display->id); BUG(); } if (fb_idx < 0 || fb_idx >= num_registered_fb) { ERR_PRINT("Framebuffer %i doesn't exist for display '%s'", fb_idx, display->name); return 1; } framebuffer = registered_fb[fb_idx]; ofbi = FB2OFB(framebuffer); fbdev = ofbi->fbdev; omapfb_lock(fbdev); /* Get the overlays attached to the framebuffer */ for (i = 0; i < ofbi->num_overlays ; i++) { struct omap_dss_device *display = NULL; struct omap_dss_driver *driver = NULL; struct omap_overlay_manager *manager; struct omap_overlay *overlay; struct omap_overlay_info overlay_info; overlay = ofbi->overlays[i]; manager = overlay->manager; overlay->get_overlay_info(overlay, &overlay_info); overlay_info.paddr = buffer->physical_addr; overlay_info.vaddr = (void *) buffer->virtual_addr; overlay->set_overlay_info(overlay, &overlay_info); if (manager) { manager->apply(manager); display = manager->device; driver = display ? display->driver : NULL; } if (dss_ovl_manually_updated(overlay)) { if (driver->sched_update) driver->sched_update(display, 0, 0, overlay_info.width, overlay_info.height); else if (driver->update) driver->update(display, 0, 0, overlay_info.width, overlay_info.height); } } omapfb_unlock(fbdev); return 0; }
int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) { struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; struct omap_dss_device *display = fb2display(fbi); union { struct omapfb_update_window_old uwnd_o; struct omapfb_update_window uwnd; struct omapfb_plane_info plane_info; struct omapfb_caps caps; struct omapfb_mem_info mem_info; struct omapfb_color_key color_key; struct omapfb_ovl_colormode ovl_colormode; enum omapfb_update_mode update_mode; int test_num; struct omapfb_memory_read memory_read; struct omapfb_vram_info vram_info; struct omapfb_tearsync_info tearsync_info; struct omapfb_display_info display_info; u32 crt; } p; int r = 0; switch (cmd) { case OMAPFB_SYNC_GFX: DBG("ioctl SYNC_GFX\n"); if (!display || !display->driver->sync) { /* DSS1 never returns an error here, so we neither */ /*r = -EINVAL;*/ break; } r = display->driver->sync(display); break; case OMAPFB_UPDATE_WINDOW_OLD: DBG("ioctl UPDATE_WINDOW_OLD\n"); if (!display || !display->driver->update) { r = -EINVAL; break; } if (copy_from_user(&p.uwnd_o, (void __user *)arg, sizeof(p.uwnd_o))) { r = -EFAULT; break; } r = omapfb_update_window_nolock(fbi, p.uwnd_o.x, p.uwnd_o.y, p.uwnd_o.width, p.uwnd_o.height); break; case OMAPFB_UPDATE_WINDOW: DBG("ioctl UPDATE_WINDOW\n"); if (!display || !display->driver->update) { r = -EINVAL; break; } if (copy_from_user(&p.uwnd, (void __user *)arg, sizeof(p.uwnd))) { r = -EFAULT; break; } r = omapfb_update_window_nolock(fbi, p.uwnd.x, p.uwnd.y, p.uwnd.width, p.uwnd.height); break; case OMAPFB_SETUP_PLANE: DBG("ioctl SETUP_PLANE\n"); if (copy_from_user(&p.plane_info, (void __user *)arg, sizeof(p.plane_info))) r = -EFAULT; else r = omapfb_setup_plane(fbi, &p.plane_info); break; case OMAPFB_QUERY_PLANE: DBG("ioctl QUERY_PLANE\n"); r = omapfb_query_plane(fbi, &p.plane_info); if (r < 0) break; if (copy_to_user((void __user *)arg, &p.plane_info, sizeof(p.plane_info))) r = -EFAULT; break; case OMAPFB_SETUP_MEM: DBG("ioctl SETUP_MEM\n"); if (copy_from_user(&p.mem_info, (void __user *)arg, sizeof(p.mem_info))) r = -EFAULT; else r = omapfb_setup_mem(fbi, &p.mem_info); break; case OMAPFB_QUERY_MEM: DBG("ioctl QUERY_MEM\n"); r = omapfb_query_mem(fbi, &p.mem_info); if (r < 0) break; if (copy_to_user((void __user *)arg, &p.mem_info, sizeof(p.mem_info))) r = -EFAULT; break; case OMAPFB_GET_CAPS: DBG("ioctl GET_CAPS\n"); if (!display) { r = -EINVAL; break; } memset(&p.caps, 0, sizeof(p.caps)); if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) p.caps.ctrl |= OMAPFB_CAPS_MANUAL_UPDATE; if (display->caps & OMAP_DSS_DISPLAY_CAP_TEAR_ELIM) p.caps.ctrl |= OMAPFB_CAPS_TEARSYNC; if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps))) r = -EFAULT; break; case OMAPFB_GET_OVERLAY_COLORMODE: DBG("ioctl GET_OVERLAY_COLORMODE\n"); if (copy_from_user(&p.ovl_colormode, (void __user *)arg, sizeof(p.ovl_colormode))) { r = -EFAULT; break; } r = omapfb_get_ovl_colormode(fbdev, &p.ovl_colormode); if (r < 0) break; if (copy_to_user((void __user *)arg, &p.ovl_colormode, sizeof(p.ovl_colormode))) r = -EFAULT; break; case OMAPFB_SET_UPDATE_MODE: DBG("ioctl SET_UPDATE_MODE\n"); if (get_user(p.update_mode, (int __user *)arg)) r = -EFAULT; else r = omapfb_set_update_mode(fbi, p.update_mode); break; case OMAPFB_GET_UPDATE_MODE: DBG("ioctl GET_UPDATE_MODE\n"); r = omapfb_get_update_mode(fbi, &p.update_mode); if (r) break; if (put_user(p.update_mode, (enum omapfb_update_mode __user *)arg)) r = -EFAULT; break; case OMAPFB_SET_COLOR_KEY: DBG("ioctl SET_COLOR_KEY\n"); if (copy_from_user(&p.color_key, (void __user *)arg, sizeof(p.color_key))) r = -EFAULT; else r = omapfb_set_color_key(fbi, &p.color_key); break; case OMAPFB_GET_COLOR_KEY: DBG("ioctl GET_COLOR_KEY\n"); r = omapfb_get_color_key(fbi, &p.color_key); if (r) break; if (copy_to_user((void __user *)arg, &p.color_key, sizeof(p.color_key))) r = -EFAULT; break; case FBIO_WAITFORVSYNC: if (get_user(p.crt, (__u32 __user *)arg)) { r = -EFAULT; break; } if (p.crt != 0) { r = -ENODEV; break; } /* FALLTHROUGH */ case OMAPFB_WAITFORVSYNC: DBG("ioctl WAITFORVSYNC\n"); if (!display) { r = -EINVAL; break; } r = display->manager->wait_for_vsync(display->manager); break; case OMAPFB_WAITFORGO: DBG("ioctl WAITFORGO\n"); if (!display) { r = -EINVAL; break; } r = omapfb_wait_for_go(fbi); break; /* LCD and CTRL tests do the same thing for backward * compatibility */ case OMAPFB_LCD_TEST: DBG("ioctl LCD_TEST\n"); if (get_user(p.test_num, (int __user *)arg)) { r = -EFAULT; break; } if (!display || !display->driver->run_test) { r = -EINVAL; break; } r = display->driver->run_test(display, p.test_num); break; case OMAPFB_CTRL_TEST: DBG("ioctl CTRL_TEST\n"); if (get_user(p.test_num, (int __user *)arg)) { r = -EFAULT; break; } if (!display || !display->driver->run_test) { r = -EINVAL; break; } r = display->driver->run_test(display, p.test_num); break; case OMAPFB_MEMORY_READ: DBG("ioctl MEMORY_READ\n"); if (copy_from_user(&p.memory_read, (void __user *)arg, sizeof(p.memory_read))) { r = -EFAULT; break; } r = omapfb_memory_read(fbi, &p.memory_read); break; case OMAPFB_GET_VRAM_INFO: { unsigned long vram, free, largest; DBG("ioctl GET_VRAM_INFO\n"); omap_vram_get_info(&vram, &free, &largest); p.vram_info.total = vram; p.vram_info.free = free; p.vram_info.largest_free_block = largest; if (copy_to_user((void __user *)arg, &p.vram_info, sizeof(p.vram_info))) r = -EFAULT; break; } case OMAPFB_SET_TEARSYNC: { DBG("ioctl SET_TEARSYNC\n"); if (copy_from_user(&p.tearsync_info, (void __user *)arg, sizeof(p.tearsync_info))) { r = -EFAULT; break; } if (!display || !display->driver->enable_te) { r = -ENODEV; break; } r = display->driver->enable_te(display, !!p.tearsync_info.enabled); break; } case OMAPFB_GET_DISPLAY_INFO: { u16 xres, yres; u32 w, h; DBG("ioctl GET_DISPLAY_INFO\n"); if (display == NULL) { r = -ENODEV; break; } get_fb_resolution(display, &xres, &yres); p.display_info.xres = xres; p.display_info.yres = yres; omapdss_display_get_dimensions(display, &w, &h); p.display_info.width = w; p.display_info.height = h; if (copy_to_user((void __user *)arg, &p.display_info, sizeof(p.display_info))) r = -EFAULT; break; } case OMAPFB_ENABLEVSYNC: if (get_user(p.crt, (__u32 __user *)arg)) { r = -EFAULT; break; } omapfb_lock(fbdev); fbdev->vsync_active = !!p.crt; if (display->state == OMAP_DSS_DISPLAY_ACTIVE) { if (p.crt) omapfb_enable_vsync(fbdev, display->channel, true); else omapfb_enable_vsync(fbdev, display->channel, false); } omapfb_unlock(fbdev); break; default: dev_err(fbdev->dev, "Unknown ioctl 0x%x\n", cmd); r = -EINVAL; } if (r < 0) DBG("ioctl failed: %d\n", r); return r; }