]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/video/omap2/omapfb/omapfb-sysfs.c
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux...
[mv-sheeva.git] / drivers / video / omap2 / omapfb / omapfb-sysfs.c
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
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         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          */
81 put_region:
82         omapfb_put_mem_region(rg);
83 out:
84         unlock_fb_info(fbi);
85
86         return r ? r : count;
87 }
88
89
90 static 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
99 static 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;
134 out:
135         omapfb_put_mem_region(ofbi->region);
136
137         unlock_fb_info(fbi);
138
139         return r;
140 }
141
142 static 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
175 static 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
192 static 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;
327 out:
328         omapfb_unlock(fbdev);
329         unlock_fb_info(fbi);
330
331         return r;
332 }
333
334 static 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
357 static 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                 /* FIXME error handling? */
419         }
420
421         r = count;
422 out:
423         unlock_fb_info(fbi);
424
425         return r;
426 }
427
428 static ssize_t show_size(struct device *dev,
429                 struct device_attribute *attr, char *buf)
430 {
431         struct fb_info *fbi = dev_get_drvdata(dev);
432         struct omapfb_info *ofbi = FB2OFB(fbi);
433
434         return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region->size);
435 }
436
437 static ssize_t store_size(struct device *dev, struct device_attribute *attr,
438                 const char *buf, size_t count)
439 {
440         struct fb_info *fbi = dev_get_drvdata(dev);
441         struct omapfb_info *ofbi = FB2OFB(fbi);
442         struct omapfb2_device *fbdev = ofbi->fbdev;
443         struct omapfb2_mem_region *rg;
444         unsigned long size;
445         int r;
446         int i;
447
448         size = PAGE_ALIGN(simple_strtoul(buf, NULL, 0));
449
450         if (!lock_fb_info(fbi))
451                 return -ENODEV;
452
453         rg = ofbi->region;
454
455         down_write_nested(&rg->lock, rg->id);
456         atomic_inc(&rg->lock_count);
457
458         if (atomic_read(&rg->map_count)) {
459                 r = -EBUSY;
460                 goto out;
461         }
462
463         for (i = 0; i < fbdev->num_fbs; i++) {
464                 struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]);
465                 int j;
466
467                 if (ofbi2->region != rg)
468                         continue;
469
470                 for (j = 0; j < ofbi2->num_overlays; j++) {
471                         if (ofbi2->overlays[j]->info.enabled) {
472                                 r = -EBUSY;
473                                 goto out;
474                         }
475                 }
476         }
477
478         if (size != ofbi->region->size) {
479                 r = omapfb_realloc_fbmem(fbi, size, ofbi->region->type);
480                 if (r) {
481                         dev_err(dev, "realloc fbmem failed\n");
482                         goto out;
483                 }
484         }
485
486         r = count;
487 out:
488         atomic_dec(&rg->lock_count);
489         up_write(&rg->lock);
490
491         unlock_fb_info(fbi);
492
493         return r;
494 }
495
496 static ssize_t show_phys(struct device *dev,
497                 struct device_attribute *attr, char *buf)
498 {
499         struct fb_info *fbi = dev_get_drvdata(dev);
500         struct omapfb_info *ofbi = FB2OFB(fbi);
501
502         return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region->paddr);
503 }
504
505 static ssize_t show_virt(struct device *dev,
506                 struct device_attribute *attr, char *buf)
507 {
508         struct fb_info *fbi = dev_get_drvdata(dev);
509         struct omapfb_info *ofbi = FB2OFB(fbi);
510
511         return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr);
512 }
513
514 static struct device_attribute omapfb_attrs[] = {
515         __ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type,
516                         store_rotate_type),
517         __ATTR(mirror, S_IRUGO | S_IWUSR, show_mirror, store_mirror),
518         __ATTR(size, S_IRUGO | S_IWUSR, show_size, store_size),
519         __ATTR(overlays, S_IRUGO | S_IWUSR, show_overlays, store_overlays),
520         __ATTR(overlays_rotate, S_IRUGO | S_IWUSR, show_overlays_rotate,
521                         store_overlays_rotate),
522         __ATTR(phys_addr, S_IRUGO, show_phys, NULL),
523         __ATTR(virt_addr, S_IRUGO, show_virt, NULL),
524 };
525
526 int omapfb_create_sysfs(struct omapfb2_device *fbdev)
527 {
528         int i;
529         int r;
530
531         DBG("create sysfs for fbs\n");
532         for (i = 0; i < fbdev->num_fbs; i++) {
533                 int t;
534                 for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) {
535                         r = device_create_file(fbdev->fbs[i]->dev,
536                                         &omapfb_attrs[t]);
537
538                         if (r) {
539                                 dev_err(fbdev->dev, "failed to create sysfs "
540                                                 "file\n");
541                                 return r;
542                         }
543                 }
544         }
545
546         return 0;
547 }
548
549 void omapfb_remove_sysfs(struct omapfb2_device *fbdev)
550 {
551         int i, t;
552
553         DBG("remove sysfs for fbs\n");
554         for (i = 0; i < fbdev->num_fbs; i++) {
555                 for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++)
556                         device_remove_file(fbdev->fbs[i]->dev,
557                                         &omapfb_attrs[t]);
558         }
559 }
560