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