1b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen/*
2b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen * linux/drivers/video/omap2/omapfb-sysfs.c
3b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen *
4b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen * Copyright (C) 2008 Nokia Corporation
5b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen *
7b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen * Some code and ideas taken from drivers/video/omap/ driver
8b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen * by Imre Deak.
9b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen *
10b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen * This program is free software; you can redistribute it and/or modify it
11b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen * under the terms of the GNU General Public License version 2 as published by
12b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen * the Free Software Foundation.
13b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen *
14b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen * This program is distributed in the hope that it will be useful, but WITHOUT
15b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
17b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen * more details.
18b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen *
19b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen * You should have received a copy of the GNU General Public License along with
20b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen * this program.  If not, see <http://www.gnu.org/licenses/>.
21b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen */
22b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
23b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen#include <linux/fb.h>
24b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen#include <linux/sysfs.h>
25b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen#include <linux/device.h>
26b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen#include <linux/uaccess.h>
27b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen#include <linux/platform_device.h>
28b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen#include <linux/kernel.h>
29b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen#include <linux/mm.h>
30b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen#include <linux/omapfb.h>
31b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
32a0b38cc4d35e095f14ab0f486135f8a619ebfc14Tomi Valkeinen#include <video/omapdss.h>
33b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen#include <plat/vrfb.h>
34b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
35b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen#include "omapfb.h"
36b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
37b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinenstatic ssize_t show_rotate_type(struct device *dev,
38b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		struct device_attribute *attr, char *buf)
39b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen{
40b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct fb_info *fbi = dev_get_drvdata(dev);
41b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct omapfb_info *ofbi = FB2OFB(fbi);
42b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
43b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->rotation_type);
44b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen}
45b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
46b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinenstatic ssize_t store_rotate_type(struct device *dev,
47b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		struct device_attribute *attr,
48b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		const char *buf, size_t count)
49b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen{
50b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct fb_info *fbi = dev_get_drvdata(dev);
51b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct omapfb_info *ofbi = FB2OFB(fbi);
52430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä	struct omapfb2_mem_region *rg;
53e3502ce97f2d2d183735d9fae76b081a634ffd85Tomi Valkeinen	int rot_type;
54b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	int r;
55b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
56e3502ce97f2d2d183735d9fae76b081a634ffd85Tomi Valkeinen	r = kstrtoint(buf, 0, &rot_type);
57e3502ce97f2d2d183735d9fae76b081a634ffd85Tomi Valkeinen	if (r)
58e3502ce97f2d2d183735d9fae76b081a634ffd85Tomi Valkeinen		return r;
59b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
60b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)
61b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		return -EINVAL;
62b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
6327b67c92a30967e3a9e9ea082d4ca4bc6882f879Jani Nikula	if (!lock_fb_info(fbi))
6427b67c92a30967e3a9e9ea082d4ca4bc6882f879Jani Nikula		return -ENODEV;
65b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
66b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	r = 0;
67b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	if (rot_type == ofbi->rotation_type)
68b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		goto out;
69b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
70430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä	rg = omapfb_get_mem_region(ofbi->region);
71430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä
72430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä	if (rg->size) {
73b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		r = -EBUSY;
74430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä		goto put_region;
75b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	}
76b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
77b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	ofbi->rotation_type = rot_type;
78b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
79b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	/*
80b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	 * Since the VRAM for this FB is not allocated at the moment we don't
81b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	 * need to do any further parameter checking at this point.
82b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	 */
83430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjäläput_region:
84430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä	omapfb_put_mem_region(rg);
85b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinenout:
86b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	unlock_fb_info(fbi);
87b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
88b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	return r ? r : count;
89b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen}
90b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
91b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
92b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinenstatic ssize_t show_mirror(struct device *dev,
93b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		struct device_attribute *attr, char *buf)
94b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen{
95b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct fb_info *fbi = dev_get_drvdata(dev);
96b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct omapfb_info *ofbi = FB2OFB(fbi);
97b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
98b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->mirror);
99b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen}
100b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
101b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinenstatic ssize_t store_mirror(struct device *dev,
102b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		struct device_attribute *attr,
103b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		const char *buf, size_t count)
104b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen{
105b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct fb_info *fbi = dev_get_drvdata(dev);
106b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct omapfb_info *ofbi = FB2OFB(fbi);
1077fbf1bb02d1005203e39ca7bd7aa7afcd2909c4bTomi Valkeinen	bool mirror;
108b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	int r;
109b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct fb_var_screeninfo new_var;
110b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
1117fbf1bb02d1005203e39ca7bd7aa7afcd2909c4bTomi Valkeinen	r = strtobool(buf, &mirror);
112e3502ce97f2d2d183735d9fae76b081a634ffd85Tomi Valkeinen	if (r)
113e3502ce97f2d2d183735d9fae76b081a634ffd85Tomi Valkeinen		return r;
114b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
11527b67c92a30967e3a9e9ea082d4ca4bc6882f879Jani Nikula	if (!lock_fb_info(fbi))
11627b67c92a30967e3a9e9ea082d4ca4bc6882f879Jani Nikula		return -ENODEV;
117b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
118b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	ofbi->mirror = mirror;
119b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
120430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä	omapfb_get_mem_region(ofbi->region);
121430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä
122b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	memcpy(&new_var, &fbi->var, sizeof(new_var));
123b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	r = check_fb_var(fbi, &new_var);
124b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	if (r)
125b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		goto out;
126b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	memcpy(&fbi->var, &new_var, sizeof(fbi->var));
127b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
128b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	set_fb_fix(fbi);
129b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
130b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	r = omapfb_apply_changes(fbi, 0);
131b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	if (r)
132b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		goto out;
133b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
134b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	r = count;
135b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinenout:
136430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä	omapfb_put_mem_region(ofbi->region);
137430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä
138b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	unlock_fb_info(fbi);
139b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
140b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	return r;
141b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen}
142b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
143b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinenstatic ssize_t show_overlays(struct device *dev,
144b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		struct device_attribute *attr, char *buf)
145b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen{
146b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct fb_info *fbi = dev_get_drvdata(dev);
147b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct omapfb_info *ofbi = FB2OFB(fbi);
148b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct omapfb2_device *fbdev = ofbi->fbdev;
149b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	ssize_t l = 0;
150b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	int t;
151b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
15227b67c92a30967e3a9e9ea082d4ca4bc6882f879Jani Nikula	if (!lock_fb_info(fbi))
15327b67c92a30967e3a9e9ea082d4ca4bc6882f879Jani Nikula		return -ENODEV;
154238a41329ca208d1170962260babb428b6e222c2Jani Nikula	omapfb_lock(fbdev);
155b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
156b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	for (t = 0; t < ofbi->num_overlays; t++) {
157b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		struct omap_overlay *ovl = ofbi->overlays[t];
158b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		int ovlnum;
159b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
160b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		for (ovlnum = 0; ovlnum < fbdev->num_overlays; ++ovlnum)
161b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			if (ovl == fbdev->overlays[ovlnum])
162b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen				break;
163b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
164b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
165b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen				t == 0 ? "" : ",", ovlnum);
166b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	}
167b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
168b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	l += snprintf(buf + l, PAGE_SIZE - l, "\n");
169b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
170b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	omapfb_unlock(fbdev);
171238a41329ca208d1170962260babb428b6e222c2Jani Nikula	unlock_fb_info(fbi);
172b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
173b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	return l;
174b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen}
175b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
176b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinenstatic struct omapfb_info *get_overlay_fb(struct omapfb2_device *fbdev,
177b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		struct omap_overlay *ovl)
178b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen{
179b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	int i, t;
180b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
181b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	for (i = 0; i < fbdev->num_fbs; i++) {
182b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
183b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
184b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		for (t = 0; t < ofbi->num_overlays; t++) {
185b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			if (ofbi->overlays[t] == ovl)
186b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen				return ofbi;
187b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		}
188b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	}
189b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
190b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	return NULL;
191b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen}
192b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
193b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinenstatic ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
194b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		const char *buf, size_t count)
195b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen{
196b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct fb_info *fbi = dev_get_drvdata(dev);
197b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct omapfb_info *ofbi = FB2OFB(fbi);
198b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct omapfb2_device *fbdev = ofbi->fbdev;
199b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct omap_overlay *ovls[OMAPFB_MAX_OVL_PER_FB];
200b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct omap_overlay *ovl;
201b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	int num_ovls, r, i;
202b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	int len;
203b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	bool added = false;
204b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
205b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	num_ovls = 0;
206b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
207b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	len = strlen(buf);
208b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	if (buf[len - 1] == '\n')
209b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		len = len - 1;
210b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
21127b67c92a30967e3a9e9ea082d4ca4bc6882f879Jani Nikula	if (!lock_fb_info(fbi))
21227b67c92a30967e3a9e9ea082d4ca4bc6882f879Jani Nikula		return -ENODEV;
213238a41329ca208d1170962260babb428b6e222c2Jani Nikula	omapfb_lock(fbdev);
214b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
215b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	if (len > 0) {
216b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		char *p = (char *)buf;
217b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		int ovlnum;
218b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
219b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		while (p < buf + len) {
220b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			int found;
221b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			if (num_ovls == OMAPFB_MAX_OVL_PER_FB) {
222b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen				r = -EINVAL;
223b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen				goto out;
224b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			}
225b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
226b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			ovlnum = simple_strtoul(p, &p, 0);
227b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			if (ovlnum > fbdev->num_overlays) {
228b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen				r = -EINVAL;
229b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen				goto out;
230b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			}
231b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
232b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			found = 0;
233b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			for (i = 0; i < num_ovls; ++i) {
234b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen				if (ovls[i] == fbdev->overlays[ovlnum]) {
235b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen					found = 1;
236b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen					break;
237b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen				}
238b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			}
239b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
240b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			if (!found)
241b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen				ovls[num_ovls++] = fbdev->overlays[ovlnum];
242b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
243b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			p++;
244b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		}
245b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	}
246b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
247b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	for (i = 0; i < num_ovls; ++i) {
248b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		struct omapfb_info *ofbi2 = get_overlay_fb(fbdev, ovls[i]);
249b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		if (ofbi2 && ofbi2 != ofbi) {
250b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			dev_err(fbdev->dev, "overlay already in use\n");
251b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			r = -EINVAL;
252b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			goto out;
253b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		}
254b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	}
255b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
256b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	/* detach unused overlays */
257b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	for (i = 0; i < ofbi->num_overlays; ++i) {
258b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		int t, found;
259b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
260b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		ovl = ofbi->overlays[i];
261b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
262b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		found = 0;
263b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
264b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		for (t = 0; t < num_ovls; ++t) {
265b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			if (ovl == ovls[t]) {
266b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen				found = 1;
267b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen				break;
268b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			}
269b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		}
270b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
271b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		if (found)
272b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			continue;
273b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
274b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		DBG("detaching %d\n", ofbi->overlays[i]->id);
275b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
276430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä		omapfb_get_mem_region(ofbi->region);
277430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä
278b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		omapfb_overlay_enable(ovl, 0);
279b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
280b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		if (ovl->manager)
281b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			ovl->manager->apply(ovl->manager);
282b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
283430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä		omapfb_put_mem_region(ofbi->region);
284430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä
285b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		for (t = i + 1; t < ofbi->num_overlays; t++) {
286b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			ofbi->rotation[t-1] = ofbi->rotation[t];
287b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			ofbi->overlays[t-1] = ofbi->overlays[t];
288b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		}
289b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
290b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		ofbi->num_overlays--;
291b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		i--;
292b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	}
293b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
294b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	for (i = 0; i < num_ovls; ++i) {
295b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		int t, found;
296b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
297b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		ovl = ovls[i];
298b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
299b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		found = 0;
300b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
301b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		for (t = 0; t < ofbi->num_overlays; ++t) {
302b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			if (ovl == ofbi->overlays[t]) {
303b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen				found = 1;
304b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen				break;
305b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			}
306b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		}
307b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
308b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		if (found)
309b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			continue;
310b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		ofbi->rotation[ofbi->num_overlays] = 0;
311b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		ofbi->overlays[ofbi->num_overlays++] = ovl;
312b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
313b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		added = true;
314b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	}
315b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
316b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	if (added) {
317430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä		omapfb_get_mem_region(ofbi->region);
318430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä
319b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		r = omapfb_apply_changes(fbi, 0);
320430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä
321430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä		omapfb_put_mem_region(ofbi->region);
322430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä
323b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		if (r)
324b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			goto out;
325b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	}
326b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
327b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	r = count;
328b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinenout:
329b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	omapfb_unlock(fbdev);
330238a41329ca208d1170962260babb428b6e222c2Jani Nikula	unlock_fb_info(fbi);
331b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
332b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	return r;
333b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen}
334b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
335b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinenstatic ssize_t show_overlays_rotate(struct device *dev,
336b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		struct device_attribute *attr, char *buf)
337b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen{
338b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct fb_info *fbi = dev_get_drvdata(dev);
339b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct omapfb_info *ofbi = FB2OFB(fbi);
340b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	ssize_t l = 0;
341b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	int t;
342b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
34327b67c92a30967e3a9e9ea082d4ca4bc6882f879Jani Nikula	if (!lock_fb_info(fbi))
34427b67c92a30967e3a9e9ea082d4ca4bc6882f879Jani Nikula		return -ENODEV;
345b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
346b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	for (t = 0; t < ofbi->num_overlays; t++) {
347b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
348b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen				t == 0 ? "" : ",", ofbi->rotation[t]);
349b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	}
350b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
351b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	l += snprintf(buf + l, PAGE_SIZE - l, "\n");
352b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
353b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	unlock_fb_info(fbi);
354b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
355b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	return l;
356b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen}
357b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
358b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinenstatic ssize_t store_overlays_rotate(struct device *dev,
359b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		struct device_attribute *attr, const char *buf, size_t count)
360b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen{
361b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct fb_info *fbi = dev_get_drvdata(dev);
362b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct omapfb_info *ofbi = FB2OFB(fbi);
363b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	int num_ovls = 0, r, i;
364b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	int len;
365b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	bool changed = false;
366b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	u8 rotation[OMAPFB_MAX_OVL_PER_FB];
367b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
368b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	len = strlen(buf);
369b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	if (buf[len - 1] == '\n')
370b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		len = len - 1;
371b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
37227b67c92a30967e3a9e9ea082d4ca4bc6882f879Jani Nikula	if (!lock_fb_info(fbi))
37327b67c92a30967e3a9e9ea082d4ca4bc6882f879Jani Nikula		return -ENODEV;
374b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
375b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	if (len > 0) {
376b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		char *p = (char *)buf;
377b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
378b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		while (p < buf + len) {
379b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			int rot;
380b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
381b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			if (num_ovls == ofbi->num_overlays) {
382b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen				r = -EINVAL;
383b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen				goto out;
384b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			}
385b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
386b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			rot = simple_strtoul(p, &p, 0);
387b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			if (rot < 0 || rot > 3) {
388b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen				r = -EINVAL;
389b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen				goto out;
390b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			}
391b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
392b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			if (ofbi->rotation[num_ovls] != rot)
393b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen				changed = true;
394b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
395b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			rotation[num_ovls++] = rot;
396b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
397b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			p++;
398b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		}
399b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	}
400b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
401b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	if (num_ovls != ofbi->num_overlays) {
402b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		r = -EINVAL;
403b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		goto out;
404b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	}
405b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
406b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	if (changed) {
407b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		for (i = 0; i < num_ovls; ++i)
408b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			ofbi->rotation[i] = rotation[i];
409b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
410430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä		omapfb_get_mem_region(ofbi->region);
411430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä
412b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		r = omapfb_apply_changes(fbi, 0);
413430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä
414430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä		omapfb_put_mem_region(ofbi->region);
415430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä
416b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		if (r)
417b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			goto out;
418b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
419b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		/* FIXME error handling? */
420b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	}
421b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
422b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	r = count;
423b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinenout:
424b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	unlock_fb_info(fbi);
425b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
426b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	return r;
427b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen}
428b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
429b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinenstatic ssize_t show_size(struct device *dev,
430b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		struct device_attribute *attr, char *buf)
431b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen{
432b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct fb_info *fbi = dev_get_drvdata(dev);
433b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct omapfb_info *ofbi = FB2OFB(fbi);
434b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
435078ff546a806b2c2ab74c25c8edd4c6d4680656aVille Syrjälä	return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region->size);
436b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen}
437b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
438b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinenstatic ssize_t store_size(struct device *dev, struct device_attribute *attr,
439b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		const char *buf, size_t count)
440b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen{
441b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct fb_info *fbi = dev_get_drvdata(dev);
442b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct omapfb_info *ofbi = FB2OFB(fbi);
443078ff546a806b2c2ab74c25c8edd4c6d4680656aVille Syrjälä	struct omapfb2_device *fbdev = ofbi->fbdev;
444078ff546a806b2c2ab74c25c8edd4c6d4680656aVille Syrjälä	struct omapfb2_mem_region *rg;
445b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	unsigned long size;
446b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	int r;
447b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	int i;
448b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
449e3502ce97f2d2d183735d9fae76b081a634ffd85Tomi Valkeinen	r = kstrtoul(buf, 0, &size);
450e3502ce97f2d2d183735d9fae76b081a634ffd85Tomi Valkeinen	if (r)
451e3502ce97f2d2d183735d9fae76b081a634ffd85Tomi Valkeinen		return r;
452e3502ce97f2d2d183735d9fae76b081a634ffd85Tomi Valkeinen
453e3502ce97f2d2d183735d9fae76b081a634ffd85Tomi Valkeinen	size = PAGE_ALIGN(size);
454b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
45527b67c92a30967e3a9e9ea082d4ca4bc6882f879Jani Nikula	if (!lock_fb_info(fbi))
45627b67c92a30967e3a9e9ea082d4ca4bc6882f879Jani Nikula		return -ENODEV;
457b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
458078ff546a806b2c2ab74c25c8edd4c6d4680656aVille Syrjälä	rg = ofbi->region;
459078ff546a806b2c2ab74c25c8edd4c6d4680656aVille Syrjälä
4603d84b65aa63833a2ac07b1cc626984a1e1485fedVille Syrjälä	down_write_nested(&rg->lock, rg->id);
4611ceafc00910439c8e5450fae189b69427725992cVille Syrjälä	atomic_inc(&rg->lock_count);
462430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä
463078ff546a806b2c2ab74c25c8edd4c6d4680656aVille Syrjälä	if (atomic_read(&rg->map_count)) {
464078ff546a806b2c2ab74c25c8edd4c6d4680656aVille Syrjälä		r = -EBUSY;
465078ff546a806b2c2ab74c25c8edd4c6d4680656aVille Syrjälä		goto out;
466078ff546a806b2c2ab74c25c8edd4c6d4680656aVille Syrjälä	}
467078ff546a806b2c2ab74c25c8edd4c6d4680656aVille Syrjälä
468078ff546a806b2c2ab74c25c8edd4c6d4680656aVille Syrjälä	for (i = 0; i < fbdev->num_fbs; i++) {
469078ff546a806b2c2ab74c25c8edd4c6d4680656aVille Syrjälä		struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]);
470078ff546a806b2c2ab74c25c8edd4c6d4680656aVille Syrjälä		int j;
471078ff546a806b2c2ab74c25c8edd4c6d4680656aVille Syrjälä
472078ff546a806b2c2ab74c25c8edd4c6d4680656aVille Syrjälä		if (ofbi2->region != rg)
473078ff546a806b2c2ab74c25c8edd4c6d4680656aVille Syrjälä			continue;
474078ff546a806b2c2ab74c25c8edd4c6d4680656aVille Syrjälä
475078ff546a806b2c2ab74c25c8edd4c6d4680656aVille Syrjälä		for (j = 0; j < ofbi2->num_overlays; j++) {
476aaa874a985158383c4b394c687c716ef26288741Tomi Valkeinen			struct omap_overlay *ovl;
477aaa874a985158383c4b394c687c716ef26288741Tomi Valkeinen			ovl = ofbi2->overlays[j];
478aaa874a985158383c4b394c687c716ef26288741Tomi Valkeinen			if (ovl->is_enabled(ovl)) {
479078ff546a806b2c2ab74c25c8edd4c6d4680656aVille Syrjälä				r = -EBUSY;
480078ff546a806b2c2ab74c25c8edd4c6d4680656aVille Syrjälä				goto out;
481078ff546a806b2c2ab74c25c8edd4c6d4680656aVille Syrjälä			}
482b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		}
483b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	}
484b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
485078ff546a806b2c2ab74c25c8edd4c6d4680656aVille Syrjälä	if (size != ofbi->region->size) {
486078ff546a806b2c2ab74c25c8edd4c6d4680656aVille Syrjälä		r = omapfb_realloc_fbmem(fbi, size, ofbi->region->type);
487b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		if (r) {
488b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			dev_err(dev, "realloc fbmem failed\n");
489b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			goto out;
490b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		}
491b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	}
492b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
493b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	r = count;
494b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinenout:
4951ceafc00910439c8e5450fae189b69427725992cVille Syrjälä	atomic_dec(&rg->lock_count);
4962f642a17503838e256b8b7e9f1153512e2efc38bVille Syrjälä	up_write(&rg->lock);
497430571d59a0b51c6541c153ad8b08e72fef26098Ville Syrjälä
498b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	unlock_fb_info(fbi);
499b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
500b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	return r;
501b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen}
502b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
503b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinenstatic ssize_t show_phys(struct device *dev,
504b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		struct device_attribute *attr, char *buf)
505b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen{
506b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct fb_info *fbi = dev_get_drvdata(dev);
507b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct omapfb_info *ofbi = FB2OFB(fbi);
508b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
509078ff546a806b2c2ab74c25c8edd4c6d4680656aVille Syrjälä	return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region->paddr);
510b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen}
511b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
512b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinenstatic ssize_t show_virt(struct device *dev,
513b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		struct device_attribute *attr, char *buf)
514b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen{
515b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct fb_info *fbi = dev_get_drvdata(dev);
516b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	struct omapfb_info *ofbi = FB2OFB(fbi);
517b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
518078ff546a806b2c2ab74c25c8edd4c6d4680656aVille Syrjälä	return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr);
519b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen}
520b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
52127cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinenstatic ssize_t show_upd_mode(struct device *dev,
52227cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen		struct device_attribute *attr, char *buf)
52327cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen{
52427cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen	struct fb_info *fbi = dev_get_drvdata(dev);
52527cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen	enum omapfb_update_mode mode;
52627cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen	int r;
52727cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen
52827cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen	r = omapfb_get_update_mode(fbi, &mode);
52927cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen
53027cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen	if (r)
53127cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen		return r;
53227cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen
53327cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen	return snprintf(buf, PAGE_SIZE, "%u\n", (unsigned)mode);
53427cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen}
53527cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen
53627cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinenstatic ssize_t store_upd_mode(struct device *dev, struct device_attribute *attr,
53727cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen		const char *buf, size_t count)
53827cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen{
53927cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen	struct fb_info *fbi = dev_get_drvdata(dev);
54027cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen	unsigned mode;
54127cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen	int r;
54227cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen
54327cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen	r = kstrtouint(buf, 0, &mode);
54427cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen	if (r)
54527cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen		return r;
54627cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen
54727cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen	r = omapfb_set_update_mode(fbi, mode);
54827cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen	if (r)
54927cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen		return r;
55027cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen
55127cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen	return count;
55227cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen}
55327cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen
554b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinenstatic struct device_attribute omapfb_attrs[] = {
555b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	__ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type,
556b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			store_rotate_type),
557b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	__ATTR(mirror, S_IRUGO | S_IWUSR, show_mirror, store_mirror),
558b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	__ATTR(size, S_IRUGO | S_IWUSR, show_size, store_size),
559b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	__ATTR(overlays, S_IRUGO | S_IWUSR, show_overlays, store_overlays),
560b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	__ATTR(overlays_rotate, S_IRUGO | S_IWUSR, show_overlays_rotate,
561b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			store_overlays_rotate),
562b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	__ATTR(phys_addr, S_IRUGO, show_phys, NULL),
563b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	__ATTR(virt_addr, S_IRUGO, show_virt, NULL),
56427cc213ea7dde929692df46a64c8d8ef74663e48Tomi Valkeinen	__ATTR(update_mode, S_IRUGO | S_IWUSR, show_upd_mode, store_upd_mode),
565b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen};
566b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
567b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinenint omapfb_create_sysfs(struct omapfb2_device *fbdev)
568b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen{
569b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	int i;
570b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	int r;
571b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
572b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	DBG("create sysfs for fbs\n");
573b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	for (i = 0; i < fbdev->num_fbs; i++) {
574b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		int t;
575b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) {
576b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			r = device_create_file(fbdev->fbs[i]->dev,
577b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen					&omapfb_attrs[t]);
578b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
579b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			if (r) {
580b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen				dev_err(fbdev->dev, "failed to create sysfs "
581b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen						"file\n");
582b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen				return r;
583b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			}
584b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		}
585b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	}
586b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
587b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	return 0;
588b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen}
589b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
590b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinenvoid omapfb_remove_sysfs(struct omapfb2_device *fbdev)
591b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen{
592b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	int i, t;
593b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
594b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	DBG("remove sysfs for fbs\n");
595b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	for (i = 0; i < fbdev->num_fbs; i++) {
596b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen		for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++)
597b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen			device_remove_file(fbdev->fbs[i]->dev,
598b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen					&omapfb_attrs[t]);
599b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen	}
600b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen}
601b39a982ddecf1d95ed96f8457c39d3ea11df93f6Tomi Valkeinen
602