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