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