brintos

brintos / linux-shallow public Read only

0
0
Text · 11.3 KiB · 831b2c2 Raw
589 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * linux/drivers/video/omap2/omapfb-sysfs.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/sysfs.h>14#include <linux/device.h>15#include <linux/uaccess.h>16#include <linux/platform_device.h>17#include <linux/kernel.h>18#include <linux/kstrtox.h>19#include <linux/mm.h>20#include <linux/omapfb.h>21 22#include <video/omapfb_dss.h>23#include <video/omapvrfb.h>24 25#include "omapfb.h"26 27static ssize_t show_rotate_type(struct device *dev,28		struct device_attribute *attr, char *buf)29{30	struct fb_info *fbi = dev_get_drvdata(dev);31	struct omapfb_info *ofbi = FB2OFB(fbi);32 33	return sysfs_emit(buf, "%d\n", ofbi->rotation_type);34}35 36static ssize_t store_rotate_type(struct device *dev,37		struct device_attribute *attr,38		const char *buf, size_t count)39{40	struct fb_info *fbi = dev_get_drvdata(dev);41	struct omapfb_info *ofbi = FB2OFB(fbi);42	struct omapfb2_mem_region *rg;43	int rot_type;44	int r;45 46	r = kstrtoint(buf, 0, &rot_type);47	if (r)48		return r;49 50	if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)51		return -EINVAL;52 53	lock_fb_info(fbi);54 55	r = 0;56	if (rot_type == ofbi->rotation_type)57		goto out;58 59	rg = omapfb_get_mem_region(ofbi->region);60 61	if (rg->size) {62		r = -EBUSY;63		goto put_region;64	}65 66	ofbi->rotation_type = rot_type;67 68	/*69	 * Since the VRAM for this FB is not allocated at the moment we don't70	 * need to do any further parameter checking at this point.71	 */72put_region:73	omapfb_put_mem_region(rg);74out:75	unlock_fb_info(fbi);76 77	return r ? r : count;78}79 80 81static ssize_t show_mirror(struct device *dev,82		struct device_attribute *attr, char *buf)83{84	struct fb_info *fbi = dev_get_drvdata(dev);85	struct omapfb_info *ofbi = FB2OFB(fbi);86 87	return sysfs_emit(buf, "%d\n", ofbi->mirror);88}89 90static ssize_t store_mirror(struct device *dev,91		struct device_attribute *attr,92		const char *buf, size_t count)93{94	struct fb_info *fbi = dev_get_drvdata(dev);95	struct omapfb_info *ofbi = FB2OFB(fbi);96	bool mirror;97	int r;98	struct fb_var_screeninfo new_var;99 100	r = kstrtobool(buf, &mirror);101	if (r)102		return r;103 104	lock_fb_info(fbi);105 106	ofbi->mirror = mirror;107 108	omapfb_get_mem_region(ofbi->region);109 110	memcpy(&new_var, &fbi->var, sizeof(new_var));111	r = check_fb_var(fbi, &new_var);112	if (r)113		goto out;114	memcpy(&fbi->var, &new_var, sizeof(fbi->var));115 116	set_fb_fix(fbi);117 118	r = omapfb_apply_changes(fbi, 0);119	if (r)120		goto out;121 122	r = count;123out:124	omapfb_put_mem_region(ofbi->region);125 126	unlock_fb_info(fbi);127 128	return r;129}130 131static ssize_t show_overlays(struct device *dev,132		struct device_attribute *attr, char *buf)133{134	struct fb_info *fbi = dev_get_drvdata(dev);135	struct omapfb_info *ofbi = FB2OFB(fbi);136	struct omapfb2_device *fbdev = ofbi->fbdev;137	ssize_t l = 0;138	int t;139 140	lock_fb_info(fbi);141	omapfb_lock(fbdev);142 143	for (t = 0; t < ofbi->num_overlays; t++) {144		struct omap_overlay *ovl = ofbi->overlays[t];145		int ovlnum;146 147		for (ovlnum = 0; ovlnum < fbdev->num_overlays; ++ovlnum)148			if (ovl == fbdev->overlays[ovlnum])149				break;150 151		l += scnprintf(buf + l, PAGE_SIZE - l, "%s%d",152				t == 0 ? "" : ",", ovlnum);153	}154 155	l += scnprintf(buf + l, PAGE_SIZE - l, "\n");156 157	omapfb_unlock(fbdev);158	unlock_fb_info(fbi);159 160	return l;161}162 163static struct omapfb_info *get_overlay_fb(struct omapfb2_device *fbdev,164		struct omap_overlay *ovl)165{166	int i, t;167 168	for (i = 0; i < fbdev->num_fbs; i++) {169		struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);170 171		for (t = 0; t < ofbi->num_overlays; t++) {172			if (ofbi->overlays[t] == ovl)173				return ofbi;174		}175	}176 177	return NULL;178}179 180static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,181		const char *buf, size_t count)182{183	struct fb_info *fbi = dev_get_drvdata(dev);184	struct omapfb_info *ofbi = FB2OFB(fbi);185	struct omapfb2_device *fbdev = ofbi->fbdev;186	struct omap_overlay *ovls[OMAPFB_MAX_OVL_PER_FB];187	struct omap_overlay *ovl;188	int num_ovls, r, i;189	int len;190	bool added = false;191 192	num_ovls = 0;193 194	len = strlen(buf);195	if (buf[len - 1] == '\n')196		len = len - 1;197 198	lock_fb_info(fbi);199	omapfb_lock(fbdev);200 201	if (len > 0) {202		char *p = (char *)buf;203		int ovlnum;204 205		while (p < buf + len) {206			int found;207			if (num_ovls == OMAPFB_MAX_OVL_PER_FB) {208				r = -EINVAL;209				goto out;210			}211 212			ovlnum = simple_strtoul(p, &p, 0);213			if (ovlnum > fbdev->num_overlays) {214				r = -EINVAL;215				goto out;216			}217 218			found = 0;219			for (i = 0; i < num_ovls; ++i) {220				if (ovls[i] == fbdev->overlays[ovlnum]) {221					found = 1;222					break;223				}224			}225 226			if (!found)227				ovls[num_ovls++] = fbdev->overlays[ovlnum];228 229			p++;230		}231	}232 233	for (i = 0; i < num_ovls; ++i) {234		struct omapfb_info *ofbi2 = get_overlay_fb(fbdev, ovls[i]);235		if (ofbi2 && ofbi2 != ofbi) {236			dev_err(fbdev->dev, "overlay already in use\n");237			r = -EINVAL;238			goto out;239		}240	}241 242	/* detach unused overlays */243	for (i = 0; i < ofbi->num_overlays; ++i) {244		int t, found;245 246		ovl = ofbi->overlays[i];247 248		found = 0;249 250		for (t = 0; t < num_ovls; ++t) {251			if (ovl == ovls[t]) {252				found = 1;253				break;254			}255		}256 257		if (found)258			continue;259 260		DBG("detaching %d\n", ofbi->overlays[i]->id);261 262		omapfb_get_mem_region(ofbi->region);263 264		omapfb_overlay_enable(ovl, 0);265 266		if (ovl->manager)267			ovl->manager->apply(ovl->manager);268 269		omapfb_put_mem_region(ofbi->region);270 271		for (t = i + 1; t < ofbi->num_overlays; t++) {272			ofbi->rotation[t-1] = ofbi->rotation[t];273			ofbi->overlays[t-1] = ofbi->overlays[t];274		}275 276		ofbi->num_overlays--;277		i--;278	}279 280	for (i = 0; i < num_ovls; ++i) {281		int t, found;282 283		ovl = ovls[i];284 285		found = 0;286 287		for (t = 0; t < ofbi->num_overlays; ++t) {288			if (ovl == ofbi->overlays[t]) {289				found = 1;290				break;291			}292		}293 294		if (found)295			continue;296		ofbi->rotation[ofbi->num_overlays] = 0;297		ofbi->overlays[ofbi->num_overlays++] = ovl;298 299		added = true;300	}301 302	if (added) {303		omapfb_get_mem_region(ofbi->region);304 305		r = omapfb_apply_changes(fbi, 0);306 307		omapfb_put_mem_region(ofbi->region);308 309		if (r)310			goto out;311	}312 313	r = count;314out:315	omapfb_unlock(fbdev);316	unlock_fb_info(fbi);317 318	return r;319}320 321static ssize_t show_overlays_rotate(struct device *dev,322		struct device_attribute *attr, char *buf)323{324	struct fb_info *fbi = dev_get_drvdata(dev);325	struct omapfb_info *ofbi = FB2OFB(fbi);326	ssize_t l = 0;327	int t;328 329	lock_fb_info(fbi);330 331	for (t = 0; t < ofbi->num_overlays; t++) {332		l += scnprintf(buf + l, PAGE_SIZE - l, "%s%d",333				t == 0 ? "" : ",", ofbi->rotation[t]);334	}335 336	l += scnprintf(buf + l, PAGE_SIZE - l, "\n");337 338	unlock_fb_info(fbi);339 340	return l;341}342 343static ssize_t store_overlays_rotate(struct device *dev,344		struct device_attribute *attr, const char *buf, size_t count)345{346	struct fb_info *fbi = dev_get_drvdata(dev);347	struct omapfb_info *ofbi = FB2OFB(fbi);348	int num_ovls = 0, r, i;349	int len;350	bool changed = false;351	u8 rotation[OMAPFB_MAX_OVL_PER_FB];352 353	len = strlen(buf);354	if (buf[len - 1] == '\n')355		len = len - 1;356 357	lock_fb_info(fbi);358 359	if (len > 0) {360		char *p = (char *)buf;361 362		while (p < buf + len) {363			int rot;364 365			if (num_ovls == ofbi->num_overlays) {366				r = -EINVAL;367				goto out;368			}369 370			rot = simple_strtoul(p, &p, 0);371			if (rot < 0 || rot > 3) {372				r = -EINVAL;373				goto out;374			}375 376			if (ofbi->rotation[num_ovls] != rot)377				changed = true;378 379			rotation[num_ovls++] = rot;380 381			p++;382		}383	}384 385	if (num_ovls != ofbi->num_overlays) {386		r = -EINVAL;387		goto out;388	}389 390	if (changed) {391		for (i = 0; i < num_ovls; ++i)392			ofbi->rotation[i] = rotation[i];393 394		omapfb_get_mem_region(ofbi->region);395 396		r = omapfb_apply_changes(fbi, 0);397 398		omapfb_put_mem_region(ofbi->region);399 400		if (r)401			goto out;402 403		/* FIXME error handling? */404	}405 406	r = count;407out:408	unlock_fb_info(fbi);409 410	return r;411}412 413static ssize_t show_size(struct device *dev,414		struct device_attribute *attr, char *buf)415{416	struct fb_info *fbi = dev_get_drvdata(dev);417	struct omapfb_info *ofbi = FB2OFB(fbi);418 419	return sysfs_emit(buf, "%lu\n", ofbi->region->size);420}421 422static ssize_t store_size(struct device *dev, struct device_attribute *attr,423		const char *buf, size_t count)424{425	struct fb_info *fbi = dev_get_drvdata(dev);426	struct omapfb_info *ofbi = FB2OFB(fbi);427	struct omapfb2_device *fbdev = ofbi->fbdev;428	struct omap_dss_device *display = fb2display(fbi);429	struct omapfb2_mem_region *rg;430	unsigned long size;431	int r;432	int i;433 434	r = kstrtoul(buf, 0, &size);435	if (r)436		return r;437 438	size = PAGE_ALIGN(size);439 440	lock_fb_info(fbi);441 442	if (display && display->driver->sync)443		display->driver->sync(display);444 445	rg = ofbi->region;446 447	down_write_nested(&rg->lock, rg->id);448	atomic_inc(&rg->lock_count);449 450	if (atomic_read(&rg->map_count)) {451		r = -EBUSY;452		goto out;453	}454 455	for (i = 0; i < fbdev->num_fbs; i++) {456		struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]);457		int j;458 459		if (ofbi2->region != rg)460			continue;461 462		for (j = 0; j < ofbi2->num_overlays; j++) {463			struct omap_overlay *ovl;464			ovl = ofbi2->overlays[j];465			if (ovl->is_enabled(ovl)) {466				r = -EBUSY;467				goto out;468			}469		}470	}471 472	if (size != ofbi->region->size) {473		r = omapfb_realloc_fbmem(fbi, size, ofbi->region->type);474		if (r) {475			dev_err(dev, "realloc fbmem failed\n");476			goto out;477		}478	}479 480	r = count;481out:482	atomic_dec(&rg->lock_count);483	up_write(&rg->lock);484 485	unlock_fb_info(fbi);486 487	return r;488}489 490static ssize_t show_phys(struct device *dev,491		struct device_attribute *attr, char *buf)492{493	struct fb_info *fbi = dev_get_drvdata(dev);494	struct omapfb_info *ofbi = FB2OFB(fbi);495 496	return sysfs_emit(buf, "%0x\n", ofbi->region->paddr);497}498 499static ssize_t show_virt(struct device *dev,500		struct device_attribute *attr, char *buf)501{502	struct fb_info *fbi = dev_get_drvdata(dev);503	struct omapfb_info *ofbi = FB2OFB(fbi);504 505	return sysfs_emit(buf, "%p\n", ofbi->region->vaddr);506}507 508static ssize_t show_upd_mode(struct device *dev,509		struct device_attribute *attr, char *buf)510{511	struct fb_info *fbi = dev_get_drvdata(dev);512	enum omapfb_update_mode mode;513	int r;514 515	r = omapfb_get_update_mode(fbi, &mode);516 517	if (r)518		return r;519 520	return sysfs_emit(buf, "%u\n", (unsigned int)mode);521}522 523static ssize_t store_upd_mode(struct device *dev, struct device_attribute *attr,524		const char *buf, size_t count)525{526	struct fb_info *fbi = dev_get_drvdata(dev);527	unsigned mode;528	int r;529 530	r = kstrtouint(buf, 0, &mode);531	if (r)532		return r;533 534	r = omapfb_set_update_mode(fbi, mode);535	if (r)536		return r;537 538	return count;539}540 541static struct device_attribute omapfb_attrs[] = {542	__ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type,543			store_rotate_type),544	__ATTR(mirror, S_IRUGO | S_IWUSR, show_mirror, store_mirror),545	__ATTR(size, S_IRUGO | S_IWUSR, show_size, store_size),546	__ATTR(overlays, S_IRUGO | S_IWUSR, show_overlays, store_overlays),547	__ATTR(overlays_rotate, S_IRUGO | S_IWUSR, show_overlays_rotate,548			store_overlays_rotate),549	__ATTR(phys_addr, S_IRUGO, show_phys, NULL),550	__ATTR(virt_addr, S_IRUGO, show_virt, NULL),551	__ATTR(update_mode, S_IRUGO | S_IWUSR, show_upd_mode, store_upd_mode),552};553 554int omapfb_create_sysfs(struct omapfb2_device *fbdev)555{556	int i;557	int r;558 559	DBG("create sysfs for fbs\n");560	for (i = 0; i < fbdev->num_fbs; i++) {561		int t;562		for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) {563			r = device_create_file(fbdev->fbs[i]->dev,564					&omapfb_attrs[t]);565 566			if (r) {567				dev_err(fbdev->dev, "failed to create sysfs "568						"file\n");569				return r;570			}571		}572	}573 574	return 0;575}576 577void omapfb_remove_sysfs(struct omapfb2_device *fbdev)578{579	int i, t;580 581	DBG("remove sysfs for fbs\n");582	for (i = 0; i < fbdev->num_fbs; i++) {583		for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++)584			device_remove_file(fbdev->fbs[i]->dev,585					&omapfb_attrs[t]);586	}587}588 589