brintos

brintos / linux-shallow public Read only

0
0
Text · 18.3 KiB · ea8c88a Raw
917 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * linux/drivers/video/omap2/omapfb-ioctl.c4 *5 * Copyright (C) 2008 Nokia Corporation6 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>7 *8 * Some code and ideas taken from drivers/video/omap/ driver9 * by Imre Deak.10 */11 12#include <linux/fb.h>13#include <linux/device.h>14#include <linux/uaccess.h>15#include <linux/platform_device.h>16#include <linux/mm.h>17#include <linux/omapfb.h>18#include <linux/vmalloc.h>19#include <linux/export.h>20#include <linux/sizes.h>21 22#include <video/omapfb_dss.h>23#include <video/omapvrfb.h>24 25#include "omapfb.h"26 27static u8 get_mem_idx(struct omapfb_info *ofbi)28{29	if (ofbi->id == ofbi->region->id)30		return 0;31 32	return OMAPFB_MEM_IDX_ENABLED | ofbi->region->id;33}34 35static struct omapfb2_mem_region *get_mem_region(struct omapfb_info *ofbi,36						 u8 mem_idx)37{38	struct omapfb2_device *fbdev = ofbi->fbdev;39 40	if (mem_idx & OMAPFB_MEM_IDX_ENABLED)41		mem_idx &= OMAPFB_MEM_IDX_MASK;42	else43		mem_idx = ofbi->id;44 45	if (mem_idx >= fbdev->num_fbs)46		return NULL;47 48	return &fbdev->regions[mem_idx];49}50 51static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)52{53	struct omapfb_info *ofbi = FB2OFB(fbi);54	struct omapfb2_device *fbdev = ofbi->fbdev;55	struct omap_overlay *ovl;56	struct omap_overlay_info old_info;57	struct omapfb2_mem_region *old_rg, *new_rg;58	int r = 0;59 60	DBG("omapfb_setup_plane\n");61 62	if (ofbi->num_overlays == 0) {63		r = -EINVAL;64		goto out;65	}66 67	/* XXX uses only the first overlay */68	ovl = ofbi->overlays[0];69 70	old_rg = ofbi->region;71	new_rg = get_mem_region(ofbi, pi->mem_idx);72	if (!new_rg) {73		r = -EINVAL;74		goto out;75	}76 77	/* Take the locks in a specific order to keep lockdep happy */78	if (old_rg->id < new_rg->id) {79		omapfb_get_mem_region(old_rg);80		omapfb_get_mem_region(new_rg);81	} else if (new_rg->id < old_rg->id) {82		omapfb_get_mem_region(new_rg);83		omapfb_get_mem_region(old_rg);84	} else85		omapfb_get_mem_region(old_rg);86 87	if (pi->enabled && !new_rg->size) {88		/*89		 * This plane's memory was freed, can't enable it90		 * until it's reallocated.91		 */92		r = -EINVAL;93		goto put_mem;94	}95 96	ovl->get_overlay_info(ovl, &old_info);97 98	if (old_rg != new_rg) {99		ofbi->region = new_rg;100		set_fb_fix(fbi);101	}102 103	if (!pi->enabled) {104		r = ovl->disable(ovl);105		if (r)106			goto undo;107	}108 109	if (pi->enabled) {110		r = omapfb_setup_overlay(fbi, ovl, pi->pos_x, pi->pos_y,111			pi->out_width, pi->out_height);112		if (r)113			goto undo;114	} else {115		struct omap_overlay_info info;116 117		ovl->get_overlay_info(ovl, &info);118 119		info.pos_x = pi->pos_x;120		info.pos_y = pi->pos_y;121		info.out_width = pi->out_width;122		info.out_height = pi->out_height;123 124		r = ovl->set_overlay_info(ovl, &info);125		if (r)126			goto undo;127	}128 129	if (ovl->manager) {130		r = ovl->manager->apply(ovl->manager);131		if (r)132			goto undo;133	}134 135	if (pi->enabled) {136		r = ovl->enable(ovl);137		if (r)138			goto undo;139	}140 141	/* Release the locks in a specific order to keep lockdep happy */142	if (old_rg->id > new_rg->id) {143		omapfb_put_mem_region(old_rg);144		omapfb_put_mem_region(new_rg);145	} else if (new_rg->id > old_rg->id) {146		omapfb_put_mem_region(new_rg);147		omapfb_put_mem_region(old_rg);148	} else149		omapfb_put_mem_region(old_rg);150 151	return 0;152 153 undo:154	if (old_rg != new_rg) {155		ofbi->region = old_rg;156		set_fb_fix(fbi);157	}158 159	ovl->set_overlay_info(ovl, &old_info);160 put_mem:161	/* Release the locks in a specific order to keep lockdep happy */162	if (old_rg->id > new_rg->id) {163		omapfb_put_mem_region(old_rg);164		omapfb_put_mem_region(new_rg);165	} else if (new_rg->id > old_rg->id) {166		omapfb_put_mem_region(new_rg);167		omapfb_put_mem_region(old_rg);168	} else169		omapfb_put_mem_region(old_rg);170 out:171	dev_err(fbdev->dev, "setup_plane failed\n");172 173	return r;174}175 176static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)177{178	struct omapfb_info *ofbi = FB2OFB(fbi);179 180	if (ofbi->num_overlays == 0) {181		memset(pi, 0, sizeof(*pi));182	} else {183		struct omap_overlay *ovl;184		struct omap_overlay_info ovli;185 186		ovl = ofbi->overlays[0];187		ovl->get_overlay_info(ovl, &ovli);188 189		pi->pos_x = ovli.pos_x;190		pi->pos_y = ovli.pos_y;191		pi->enabled = ovl->is_enabled(ovl);192		pi->channel_out = 0; /* xxx */193		pi->mirror = 0;194		pi->mem_idx = get_mem_idx(ofbi);195		pi->out_width = ovli.out_width;196		pi->out_height = ovli.out_height;197	}198 199	return 0;200}201 202static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)203{204	struct omapfb_info *ofbi = FB2OFB(fbi);205	struct omapfb2_device *fbdev = ofbi->fbdev;206	struct omap_dss_device *display = fb2display(fbi);207	struct omapfb2_mem_region *rg;208	int r = 0, i;209	size_t size;210 211	if (mi->type != OMAPFB_MEMTYPE_SDRAM)212		return -EINVAL;213 214	size = PAGE_ALIGN(mi->size);215 216	if (display && display->driver->sync)217		display->driver->sync(display);218 219	rg = ofbi->region;220 221	down_write_nested(&rg->lock, rg->id);222	atomic_inc(&rg->lock_count);223 224	if (rg->size == size && rg->type == mi->type)225		goto out;226 227	if (atomic_read(&rg->map_count)) {228		r = -EBUSY;229		goto out;230	}231 232	for (i = 0; i < fbdev->num_fbs; i++) {233		struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]);234		int j;235 236		if (ofbi2->region != rg)237			continue;238 239		for (j = 0; j < ofbi2->num_overlays; j++) {240			struct omap_overlay *ovl;241			ovl = ofbi2->overlays[j];242			if (ovl->is_enabled(ovl)) {243				r = -EBUSY;244				goto out;245			}246		}247	}248 249	r = omapfb_realloc_fbmem(fbi, size, mi->type);250	if (r) {251		dev_err(fbdev->dev, "realloc fbmem failed\n");252		goto out;253	}254 255 out:256	atomic_dec(&rg->lock_count);257	up_write(&rg->lock);258 259	return r;260}261 262static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)263{264	struct omapfb_info *ofbi = FB2OFB(fbi);265	struct omapfb2_mem_region *rg;266 267	rg = omapfb_get_mem_region(ofbi->region);268	memset(mi, 0, sizeof(*mi));269 270	mi->size = rg->size;271	mi->type = rg->type;272 273	omapfb_put_mem_region(rg);274 275	return 0;276}277 278static int omapfb_update_window(struct fb_info *fbi,279		u32 x, u32 y, u32 w, u32 h)280{281	struct omap_dss_device *display = fb2display(fbi);282	u16 dw, dh;283 284	if (!display)285		return 0;286 287	if (w == 0 || h == 0)288		return 0;289 290	display->driver->get_resolution(display, &dw, &dh);291 292	if (x + w > dw || y + h > dh)293		return -EINVAL;294 295	return display->driver->update(display, x, y, w, h);296}297 298int omapfb_set_update_mode(struct fb_info *fbi,299				   enum omapfb_update_mode mode)300{301	struct omap_dss_device *display = fb2display(fbi);302	struct omapfb_info *ofbi = FB2OFB(fbi);303	struct omapfb2_device *fbdev = ofbi->fbdev;304	struct omapfb_display_data *d;305	int r;306 307	if (!display)308		return -EINVAL;309 310	if (mode != OMAPFB_AUTO_UPDATE && mode != OMAPFB_MANUAL_UPDATE)311		return -EINVAL;312 313	omapfb_lock(fbdev);314 315	d = get_display_data(fbdev, display);316 317	if (d->update_mode == mode) {318		omapfb_unlock(fbdev);319		return 0;320	}321 322	r = 0;323 324	if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {325		if (mode == OMAPFB_AUTO_UPDATE)326			omapfb_start_auto_update(fbdev, display);327		else /* MANUAL_UPDATE */328			omapfb_stop_auto_update(fbdev, display);329 330		d->update_mode = mode;331	} else { /* AUTO_UPDATE */332		if (mode == OMAPFB_MANUAL_UPDATE)333			r = -EINVAL;334	}335 336	omapfb_unlock(fbdev);337 338	return r;339}340 341int omapfb_get_update_mode(struct fb_info *fbi,342		enum omapfb_update_mode *mode)343{344	struct omap_dss_device *display = fb2display(fbi);345	struct omapfb_info *ofbi = FB2OFB(fbi);346	struct omapfb2_device *fbdev = ofbi->fbdev;347	struct omapfb_display_data *d;348 349	if (!display)350		return -EINVAL;351 352	omapfb_lock(fbdev);353 354	d = get_display_data(fbdev, display);355 356	*mode = d->update_mode;357 358	omapfb_unlock(fbdev);359 360	return 0;361}362 363/* XXX this color key handling is a hack... */364static struct omapfb_color_key omapfb_color_keys[2];365 366static int _omapfb_set_color_key(struct omap_overlay_manager *mgr,367		struct omapfb_color_key *ck)368{369	struct omap_overlay_manager_info info;370	enum omap_dss_trans_key_type kt;371	int r;372 373	mgr->get_manager_info(mgr, &info);374 375	if (ck->key_type == OMAPFB_COLOR_KEY_DISABLED) {376		info.trans_enabled = false;377		omapfb_color_keys[mgr->id] = *ck;378 379		r = mgr->set_manager_info(mgr, &info);380		if (r)381			return r;382 383		r = mgr->apply(mgr);384 385		return r;386	}387 388	switch (ck->key_type) {389	case OMAPFB_COLOR_KEY_GFX_DST:390		kt = OMAP_DSS_COLOR_KEY_GFX_DST;391		break;392	case OMAPFB_COLOR_KEY_VID_SRC:393		kt = OMAP_DSS_COLOR_KEY_VID_SRC;394		break;395	default:396		return -EINVAL;397	}398 399	info.default_color = ck->background;400	info.trans_key = ck->trans_key;401	info.trans_key_type = kt;402	info.trans_enabled = true;403 404	omapfb_color_keys[mgr->id] = *ck;405 406	r = mgr->set_manager_info(mgr, &info);407	if (r)408		return r;409 410	r = mgr->apply(mgr);411 412	return r;413}414 415static int omapfb_set_color_key(struct fb_info *fbi,416		struct omapfb_color_key *ck)417{418	struct omapfb_info *ofbi = FB2OFB(fbi);419	struct omapfb2_device *fbdev = ofbi->fbdev;420	int r;421	int i;422	struct omap_overlay_manager *mgr = NULL;423 424	omapfb_lock(fbdev);425 426	for (i = 0; i < ofbi->num_overlays; i++) {427		if (ofbi->overlays[i]->manager) {428			mgr = ofbi->overlays[i]->manager;429			break;430		}431	}432 433	if (!mgr) {434		r = -EINVAL;435		goto err;436	}437 438	r = _omapfb_set_color_key(mgr, ck);439err:440	omapfb_unlock(fbdev);441 442	return r;443}444 445static int omapfb_get_color_key(struct fb_info *fbi,446		struct omapfb_color_key *ck)447{448	struct omapfb_info *ofbi = FB2OFB(fbi);449	struct omapfb2_device *fbdev = ofbi->fbdev;450	struct omap_overlay_manager *mgr = NULL;451	int r = 0;452	int i;453 454	omapfb_lock(fbdev);455 456	for (i = 0; i < ofbi->num_overlays; i++) {457		if (ofbi->overlays[i]->manager) {458			mgr = ofbi->overlays[i]->manager;459			break;460		}461	}462 463	if (!mgr) {464		r = -EINVAL;465		goto err;466	}467 468	*ck = omapfb_color_keys[mgr->id];469err:470	omapfb_unlock(fbdev);471 472	return r;473}474 475static int omapfb_memory_read(struct fb_info *fbi,476		struct omapfb_memory_read *mr)477{478	struct omap_dss_device *display = fb2display(fbi);479	void *buf;480	int r;481 482	if (!display || !display->driver->memory_read)483		return -ENOENT;484 485	if (mr->w > 4096 || mr->h > 4096)486		return -EINVAL;487 488	if (mr->w * mr->h * 3 > mr->buffer_size)489		return -EINVAL;490 491	buf = vmalloc(mr->buffer_size);492	if (!buf) {493		DBG("vmalloc failed\n");494		return -ENOMEM;495	}496 497	r = display->driver->memory_read(display, buf, mr->buffer_size,498			mr->x, mr->y, mr->w, mr->h);499 500	if (r > 0) {501		if (copy_to_user(mr->buffer, buf, r))502			r = -EFAULT;503	}504 505	vfree(buf);506 507	return r;508}509 510static int omapfb_get_ovl_colormode(struct omapfb2_device *fbdev,511			     struct omapfb_ovl_colormode *mode)512{513	int ovl_idx = mode->overlay_idx;514	int mode_idx = mode->mode_idx;515	struct omap_overlay *ovl;516	enum omap_color_mode supported_modes;517	struct fb_var_screeninfo var;518	int i;519 520	if (ovl_idx >= fbdev->num_overlays)521		return -ENODEV;522	ovl = fbdev->overlays[ovl_idx];523	supported_modes = ovl->supported_modes;524 525	mode_idx = mode->mode_idx;526 527	for (i = 0; i < sizeof(supported_modes) * 8; i++) {528		if (!(supported_modes & (1 << i)))529			continue;530		/*531		 * It's possible that the FB doesn't support a mode532		 * that is supported by the overlay, so call the533		 * following here.534		 */535		if (dss_mode_to_fb_mode(1 << i, &var) < 0)536			continue;537 538		mode_idx--;539		if (mode_idx < 0)540			break;541	}542 543	if (i == sizeof(supported_modes) * 8)544		return -ENOENT;545 546	mode->bits_per_pixel = var.bits_per_pixel;547	mode->nonstd = var.nonstd;548	mode->red = var.red;549	mode->green = var.green;550	mode->blue = var.blue;551	mode->transp = var.transp;552 553	return 0;554}555 556static int omapfb_wait_for_go(struct fb_info *fbi)557{558	struct omapfb_info *ofbi = FB2OFB(fbi);559	int r = 0;560	int i;561 562	for (i = 0; i < ofbi->num_overlays; ++i) {563		struct omap_overlay *ovl = ofbi->overlays[i];564		r = ovl->wait_for_go(ovl);565		if (r)566			break;567	}568 569	return r;570}571 572int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)573{574	struct omapfb_info *ofbi = FB2OFB(fbi);575	struct omapfb2_device *fbdev = ofbi->fbdev;576	struct omap_dss_device *display = fb2display(fbi);577	struct omap_overlay_manager *mgr;578 579	union {580		struct omapfb_update_window_old	uwnd_o;581		struct omapfb_update_window	uwnd;582		struct omapfb_plane_info	plane_info;583		struct omapfb_caps		caps;584		struct omapfb_mem_info          mem_info;585		struct omapfb_color_key		color_key;586		struct omapfb_ovl_colormode	ovl_colormode;587		enum omapfb_update_mode		update_mode;588		int test_num;589		struct omapfb_memory_read	memory_read;590		struct omapfb_vram_info		vram_info;591		struct omapfb_tearsync_info	tearsync_info;592		struct omapfb_display_info	display_info;593		u32				crt;594	} p;595 596	int r = 0;597 598	memset(&p, 0, sizeof(p));599 600	switch (cmd) {601	case OMAPFB_SYNC_GFX:602		DBG("ioctl SYNC_GFX\n");603		if (!display || !display->driver->sync) {604			/* DSS1 never returns an error here, so we neither */605			/*r = -EINVAL;*/606			break;607		}608 609		r = display->driver->sync(display);610		break;611 612	case OMAPFB_UPDATE_WINDOW_OLD:613		DBG("ioctl UPDATE_WINDOW_OLD\n");614		if (!display || !display->driver->update) {615			r = -EINVAL;616			break;617		}618 619		if (copy_from_user(&p.uwnd_o,620					(void __user *)arg,621					sizeof(p.uwnd_o))) {622			r = -EFAULT;623			break;624		}625 626		r = omapfb_update_window(fbi, p.uwnd_o.x, p.uwnd_o.y,627				p.uwnd_o.width, p.uwnd_o.height);628		break;629 630	case OMAPFB_UPDATE_WINDOW:631		DBG("ioctl UPDATE_WINDOW\n");632		if (!display || !display->driver->update) {633			r = -EINVAL;634			break;635		}636 637		if (copy_from_user(&p.uwnd, (void __user *)arg,638					sizeof(p.uwnd))) {639			r = -EFAULT;640			break;641		}642 643		r = omapfb_update_window(fbi, p.uwnd.x, p.uwnd.y,644				p.uwnd.width, p.uwnd.height);645		break;646 647	case OMAPFB_SETUP_PLANE:648		DBG("ioctl SETUP_PLANE\n");649		if (copy_from_user(&p.plane_info, (void __user *)arg,650					sizeof(p.plane_info)))651			r = -EFAULT;652		else653			r = omapfb_setup_plane(fbi, &p.plane_info);654		break;655 656	case OMAPFB_QUERY_PLANE:657		DBG("ioctl QUERY_PLANE\n");658		r = omapfb_query_plane(fbi, &p.plane_info);659		if (r < 0)660			break;661		if (copy_to_user((void __user *)arg, &p.plane_info,662					sizeof(p.plane_info)))663			r = -EFAULT;664		break;665 666	case OMAPFB_SETUP_MEM:667		DBG("ioctl SETUP_MEM\n");668		if (copy_from_user(&p.mem_info, (void __user *)arg,669					sizeof(p.mem_info)))670			r = -EFAULT;671		else672			r = omapfb_setup_mem(fbi, &p.mem_info);673		break;674 675	case OMAPFB_QUERY_MEM:676		DBG("ioctl QUERY_MEM\n");677		r = omapfb_query_mem(fbi, &p.mem_info);678		if (r < 0)679			break;680		if (copy_to_user((void __user *)arg, &p.mem_info,681					sizeof(p.mem_info)))682			r = -EFAULT;683		break;684 685	case OMAPFB_GET_CAPS:686		DBG("ioctl GET_CAPS\n");687		if (!display) {688			r = -EINVAL;689			break;690		}691 692		memset(&p.caps, 0, sizeof(p.caps));693		if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)694			p.caps.ctrl |= OMAPFB_CAPS_MANUAL_UPDATE;695		if (display->caps & OMAP_DSS_DISPLAY_CAP_TEAR_ELIM)696			p.caps.ctrl |= OMAPFB_CAPS_TEARSYNC;697 698		if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps)))699			r = -EFAULT;700		break;701 702	case OMAPFB_GET_OVERLAY_COLORMODE:703		DBG("ioctl GET_OVERLAY_COLORMODE\n");704		if (copy_from_user(&p.ovl_colormode, (void __user *)arg,705				   sizeof(p.ovl_colormode))) {706			r = -EFAULT;707			break;708		}709		r = omapfb_get_ovl_colormode(fbdev, &p.ovl_colormode);710		if (r < 0)711			break;712		if (copy_to_user((void __user *)arg, &p.ovl_colormode,713				 sizeof(p.ovl_colormode)))714			r = -EFAULT;715		break;716 717	case OMAPFB_SET_UPDATE_MODE:718		DBG("ioctl SET_UPDATE_MODE\n");719		if (get_user(p.update_mode, (int __user *)arg))720			r = -EFAULT;721		else722			r = omapfb_set_update_mode(fbi, p.update_mode);723		break;724 725	case OMAPFB_GET_UPDATE_MODE:726		DBG("ioctl GET_UPDATE_MODE\n");727		r = omapfb_get_update_mode(fbi, &p.update_mode);728		if (r)729			break;730		if (put_user(p.update_mode,731					(enum omapfb_update_mode __user *)arg))732			r = -EFAULT;733		break;734 735	case OMAPFB_SET_COLOR_KEY:736		DBG("ioctl SET_COLOR_KEY\n");737		if (copy_from_user(&p.color_key, (void __user *)arg,738				   sizeof(p.color_key)))739			r = -EFAULT;740		else741			r = omapfb_set_color_key(fbi, &p.color_key);742		break;743 744	case OMAPFB_GET_COLOR_KEY:745		DBG("ioctl GET_COLOR_KEY\n");746		r = omapfb_get_color_key(fbi, &p.color_key);747		if (r)748			break;749		if (copy_to_user((void __user *)arg, &p.color_key,750				 sizeof(p.color_key)))751			r = -EFAULT;752		break;753 754	case FBIO_WAITFORVSYNC:755		if (get_user(p.crt, (__u32 __user *)arg)) {756			r = -EFAULT;757			break;758		}759		if (p.crt != 0) {760			r = -ENODEV;761			break;762		}763		fallthrough;764 765	case OMAPFB_WAITFORVSYNC:766		DBG("ioctl WAITFORVSYNC\n");767 768		if (!display) {769			r = -EINVAL;770			break;771		}772 773		mgr = omapdss_find_mgr_from_display(display);774		if (!mgr) {775			r = -EINVAL;776			break;777		}778 779		r = mgr->wait_for_vsync(mgr);780		break;781 782	case OMAPFB_WAITFORGO:783		DBG("ioctl WAITFORGO\n");784		if (!display) {785			r = -EINVAL;786			break;787		}788 789		r = omapfb_wait_for_go(fbi);790		break;791 792	/* LCD and CTRL tests do the same thing for backward793	 * compatibility */794	case OMAPFB_LCD_TEST:795		DBG("ioctl LCD_TEST\n");796		if (get_user(p.test_num, (int __user *)arg)) {797			r = -EFAULT;798			break;799		}800		if (!display || !display->driver->run_test) {801			r = -EINVAL;802			break;803		}804 805		r = display->driver->run_test(display, p.test_num);806 807		break;808 809	case OMAPFB_CTRL_TEST:810		DBG("ioctl CTRL_TEST\n");811		if (get_user(p.test_num, (int __user *)arg)) {812			r = -EFAULT;813			break;814		}815		if (!display || !display->driver->run_test) {816			r = -EINVAL;817			break;818		}819 820		r = display->driver->run_test(display, p.test_num);821 822		break;823 824	case OMAPFB_MEMORY_READ:825		DBG("ioctl MEMORY_READ\n");826 827		if (copy_from_user(&p.memory_read, (void __user *)arg,828					sizeof(p.memory_read))) {829			r = -EFAULT;830			break;831		}832 833		r = omapfb_memory_read(fbi, &p.memory_read);834 835		break;836 837	case OMAPFB_GET_VRAM_INFO: {838		DBG("ioctl GET_VRAM_INFO\n");839 840		/*841		 * We don't have the ability to get this vram info anymore.842		 * Fill in something that should keep the applications working.843		 */844		p.vram_info.total = SZ_1M * 64;845		p.vram_info.free = SZ_1M * 64;846		p.vram_info.largest_free_block = SZ_1M * 64;847 848		if (copy_to_user((void __user *)arg, &p.vram_info,849					sizeof(p.vram_info)))850			r = -EFAULT;851		break;852	}853 854	case OMAPFB_SET_TEARSYNC: {855		DBG("ioctl SET_TEARSYNC\n");856 857		if (copy_from_user(&p.tearsync_info, (void __user *)arg,858					sizeof(p.tearsync_info))) {859			r = -EFAULT;860			break;861		}862 863		if (!display || !display->driver->enable_te) {864			r = -ENODEV;865			break;866		}867 868		r = display->driver->enable_te(display,869				!!p.tearsync_info.enabled);870 871		break;872	}873 874	case OMAPFB_GET_DISPLAY_INFO: {875		u16 xres, yres;876 877		DBG("ioctl GET_DISPLAY_INFO\n");878 879		if (display == NULL) {880			r = -ENODEV;881			break;882		}883 884		display->driver->get_resolution(display, &xres, &yres);885 886		p.display_info.xres = xres;887		p.display_info.yres = yres;888 889		if (display->driver->get_dimensions) {890			u32 w, h;891			display->driver->get_dimensions(display, &w, &h);892			p.display_info.width = w;893			p.display_info.height = h;894		} else {895			p.display_info.width = 0;896			p.display_info.height = 0;897		}898 899		if (copy_to_user((void __user *)arg, &p.display_info,900					sizeof(p.display_info)))901			r = -EFAULT;902		break;903	}904 905	default:906		dev_err(fbdev->dev, "Unknown ioctl 0x%x\n", cmd);907		r = -EINVAL;908	}909 910	if (r < 0)911		DBG("ioctl failed: %d\n", r);912 913	return r;914}915 916 917