DSS2: fix return value for rotate_type sysfs function
[pandora-kernel.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 <mach/display.h>
33 #include <mach/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_device *fbdev = ofbi->fbdev;
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         omapfb_lock(fbdev);
62
63         r = 0;
64         if (rot_type == ofbi->rotation_type)
65                 goto out;
66
67         if (ofbi->region.size) {
68                 r = -EBUSY;
69                 goto out;
70         }
71
72         ofbi->rotation_type = rot_type;
73
74         /*
75          * Since the VRAM for this FB is not allocated at the moment we don't need to
76          * do any further parameter checking at this point.
77          */
78 out:
79         omapfb_unlock(fbdev);
80
81         return r ? r : count;
82 }
83
84
85 static ssize_t show_mirror(struct device *dev,
86                 struct device_attribute *attr, char *buf)
87 {
88         struct fb_info *fbi = dev_get_drvdata(dev);
89         struct omapfb_info *ofbi = FB2OFB(fbi);
90
91         return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->mirror);
92 }
93
94 static ssize_t store_mirror(struct device *dev,
95                 struct device_attribute *attr,
96                 const char *buf, size_t count)
97 {
98         struct fb_info *fbi = dev_get_drvdata(dev);
99         struct omapfb_info *ofbi = FB2OFB(fbi);
100         struct omapfb2_device *fbdev = ofbi->fbdev;
101         bool mirror;
102         int r;
103         struct fb_var_screeninfo new_var;
104
105         mirror = simple_strtoul(buf, NULL, 0);
106
107         if (mirror != 0 && mirror != 1)
108                 return -EINVAL;
109
110         omapfb_lock(fbdev);
111
112         ofbi->mirror = mirror;
113
114         memcpy(&new_var, &fbi->var, sizeof(new_var));
115         r = check_fb_var(fbi, &new_var);
116         if (r)
117                 goto out;
118         memcpy(&fbi->var, &new_var, sizeof(fbi->var));
119
120         set_fb_fix(fbi);
121
122         r = omapfb_apply_changes(fbi, 0);
123         if (r)
124                 goto out;
125
126         r = count;
127 out:
128         omapfb_unlock(fbdev);
129
130         return r;
131 }
132
133 static ssize_t show_overlays(struct device *dev,
134                 struct device_attribute *attr, char *buf)
135 {
136         struct fb_info *fbi = dev_get_drvdata(dev);
137         struct omapfb_info *ofbi = FB2OFB(fbi);
138         struct omapfb2_device *fbdev = ofbi->fbdev;
139         ssize_t l = 0;
140         int t;
141
142         for (t = 0; t < ofbi->num_overlays; t++) {
143                 struct omap_overlay *ovl = ofbi->overlays[t];
144                 int ovlnum;
145
146                 for (ovlnum = 0; ovlnum < fbdev->num_overlays; ++ovlnum)
147                         if (ovl == fbdev->overlays[ovlnum])
148                                 break;
149
150                 l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
151                                 t == 0 ? "" : ",", ovlnum);
152         }
153
154         l += snprintf(buf + l, PAGE_SIZE - l, "\n");
155
156         return l;
157 }
158
159 static struct omapfb_info *get_overlay_fb(struct omapfb2_device *fbdev,
160                 struct omap_overlay *ovl)
161 {
162         int i, t;
163
164         for (i = 0; i < fbdev->num_fbs; i++) {
165                 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
166
167                 for (t = 0; t < ofbi->num_overlays; t++) {
168                         if (ofbi->overlays[t] == ovl)
169                                 return ofbi;
170                 }
171         }
172
173         return NULL;
174 }
175
176 static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
177                 const char *buf, size_t count)
178 {
179         struct fb_info *fbi = dev_get_drvdata(dev);
180         struct omapfb_info *ofbi = FB2OFB(fbi);
181         struct omapfb2_device *fbdev = ofbi->fbdev;
182         struct omap_overlay *ovls[OMAPFB_MAX_OVL_PER_FB];
183         struct omap_overlay *ovl;
184         int num_ovls, r, i;
185         int len;
186
187         num_ovls = 0;
188
189         len = strlen(buf);
190         if (buf[len - 1] == '\n')
191                 len = len - 1;
192
193         omapfb_lock(fbdev);
194
195         if (len > 0) {
196                 char *p = (char *)buf;
197                 int ovlnum;
198
199                 while (p < buf + len) {
200                         int found;
201                         if (num_ovls == OMAPFB_MAX_OVL_PER_FB) {
202                                 r = -EINVAL;
203                                 goto out;
204                         }
205
206                         ovlnum = simple_strtoul(p, &p, 0);
207                         if (ovlnum > fbdev->num_overlays) {
208                                 r = -EINVAL;
209                                 goto out;
210                         }
211
212                         found = 0;
213                         for (i = 0; i < num_ovls; ++i) {
214                                 if (ovls[i] == fbdev->overlays[ovlnum]) {
215                                         found = 1;
216                                         break;
217                                 }
218                         }
219
220                         if (!found)
221                                 ovls[num_ovls++] = fbdev->overlays[ovlnum];
222
223                         p++;
224                 }
225         }
226
227         for (i = 0; i < num_ovls; ++i) {
228                 struct omapfb_info *ofbi2 = get_overlay_fb(fbdev, ovls[i]);
229                 if (ofbi2 && ofbi2 != ofbi) {
230                         dev_err(fbdev->dev, "overlay already in use\n");
231                         r = -EINVAL;
232                         goto out;
233                 }
234         }
235
236         /* detach unused overlays */
237         for (i = 0; i < ofbi->num_overlays; ++i) {
238                 int t, found;
239
240                 ovl = ofbi->overlays[i];
241
242                 found = 0;
243
244                 for (t = 0; t < num_ovls; ++t) {
245                         if (ovl == ovls[t]) {
246                                 found = 1;
247                                 break;
248                         }
249                 }
250
251                 if (found)
252                         continue;
253
254                 DBG("detaching %d\n", ofbi->overlays[i]->id);
255
256                 omapfb_overlay_enable(ovl, 0);
257
258                 if (ovl->manager)
259                         ovl->manager->apply(ovl->manager);
260
261                 for (t = i + 1; t < ofbi->num_overlays; t++)
262                         ofbi->overlays[t-1] = ofbi->overlays[t];
263
264                 ofbi->num_overlays--;
265                 i--;
266         }
267
268         for (i = 0; i < num_ovls; ++i) {
269                 int t, found;
270
271                 ovl = ovls[i];
272
273                 found = 0;
274
275                 for (t = 0; t < ofbi->num_overlays; ++t) {
276                         if (ovl == ofbi->overlays[t]) {
277                                 found = 1;
278                                 break;
279                         }
280                 }
281
282                 if (found)
283                         continue;
284
285                 ofbi->overlays[ofbi->num_overlays++] = ovl;
286
287                 r = omapfb_apply_changes(fbi, 1);
288                 if (r)
289                         goto out;
290
291                 if (ovl->manager) {
292                         r = ovl->manager->apply(ovl->manager);
293                         if (r)
294                                 goto out;
295                 }
296         }
297
298         r = count;
299 out:
300         omapfb_unlock(fbdev);
301
302         return r;
303 }
304
305 static ssize_t show_size(struct device *dev,
306                 struct device_attribute *attr, char *buf)
307 {
308         struct fb_info *fbi = dev_get_drvdata(dev);
309         struct omapfb_info *ofbi = FB2OFB(fbi);
310
311         return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region.size);
312 }
313
314 static ssize_t store_size(struct device *dev, struct device_attribute *attr,
315                 const char *buf, size_t count)
316 {
317         struct fb_info *fbi = dev_get_drvdata(dev);
318         struct omapfb_info *ofbi = FB2OFB(fbi);
319         struct omapfb2_device *fbdev = ofbi->fbdev;
320         unsigned long size;
321         int r;
322         int i;
323
324         size = PAGE_ALIGN(simple_strtoul(buf, NULL, 0));
325
326         omapfb_lock(fbdev);
327
328         for (i = 0; i < ofbi->num_overlays; i++) {
329                 if (ofbi->overlays[i]->info.enabled) {
330                         r = -EBUSY;
331                         goto out;
332                 }
333         }
334
335         if (size != ofbi->region.size) {
336                 r = omapfb_realloc_fbmem(fbi, size, ofbi->region.type);
337                 if (r) {
338                         dev_err(dev, "realloc fbmem failed\n");
339                         goto out;
340                 }
341         }
342
343         r = count;
344 out:
345         omapfb_unlock(fbdev);
346
347         return r;
348 }
349
350 static ssize_t show_phys(struct device *dev,
351                 struct device_attribute *attr, char *buf)
352 {
353         struct fb_info *fbi = dev_get_drvdata(dev);
354         struct omapfb_info *ofbi = FB2OFB(fbi);
355
356         return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region.paddr);
357 }
358
359 static ssize_t show_virt(struct device *dev,
360                 struct device_attribute *attr, char *buf)
361 {
362         struct fb_info *fbi = dev_get_drvdata(dev);
363         struct omapfb_info *ofbi = FB2OFB(fbi);
364
365         return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region.vaddr);
366 }
367
368 static struct device_attribute omapfb_attrs[] = {
369         __ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type, store_rotate_type),
370         __ATTR(mirror, S_IRUGO | S_IWUSR, show_mirror, store_mirror),
371         __ATTR(size, S_IRUGO | S_IWUSR, show_size, store_size),
372         __ATTR(overlays, S_IRUGO | S_IWUSR, show_overlays, store_overlays),
373         __ATTR(phys_addr, S_IRUGO, show_phys, NULL),
374         __ATTR(virt_addr, S_IRUGO, show_virt, NULL),
375 };
376
377 int omapfb_create_sysfs(struct omapfb2_device *fbdev)
378 {
379         int i;
380         int r;
381
382         DBG("create sysfs for fbs\n");
383         for (i = 0; i < fbdev->num_fbs; i++) {
384                 int t;
385                 for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) {
386                         r = device_create_file(fbdev->fbs[i]->dev,
387                                         &omapfb_attrs[t]);
388
389                         if (r) {
390                                 dev_err(fbdev->dev, "failed to create sysfs file\n");
391                                 return r;
392                         }
393                 }
394         }
395
396         return 0;
397 }
398
399 void omapfb_remove_sysfs(struct omapfb2_device *fbdev)
400 {
401         int i, t;
402
403         DBG("remove sysfs for fbs\n");
404         for (i = 0; i < fbdev->num_fbs; i++) {
405                 for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++)
406                         device_remove_file(fbdev->fbs[i]->dev,
407                                         &omapfb_attrs[t]);
408         }
409 }
410