0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/fb.h>
0013 #include <linux/sysfs.h>
0014 #include <linux/device.h>
0015 #include <linux/uaccess.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/kernel.h>
0018 #include <linux/mm.h>
0019 #include <linux/omapfb.h>
0020
0021 #include <video/omapfb_dss.h>
0022 #include <video/omapvrfb.h>
0023
0024 #include "omapfb.h"
0025
0026 static ssize_t show_rotate_type(struct device *dev,
0027 struct device_attribute *attr, char *buf)
0028 {
0029 struct fb_info *fbi = dev_get_drvdata(dev);
0030 struct omapfb_info *ofbi = FB2OFB(fbi);
0031
0032 return sysfs_emit(buf, "%d\n", ofbi->rotation_type);
0033 }
0034
0035 static ssize_t store_rotate_type(struct device *dev,
0036 struct device_attribute *attr,
0037 const char *buf, size_t count)
0038 {
0039 struct fb_info *fbi = dev_get_drvdata(dev);
0040 struct omapfb_info *ofbi = FB2OFB(fbi);
0041 struct omapfb2_mem_region *rg;
0042 int rot_type;
0043 int r;
0044
0045 r = kstrtoint(buf, 0, &rot_type);
0046 if (r)
0047 return r;
0048
0049 if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)
0050 return -EINVAL;
0051
0052 lock_fb_info(fbi);
0053
0054 r = 0;
0055 if (rot_type == ofbi->rotation_type)
0056 goto out;
0057
0058 rg = omapfb_get_mem_region(ofbi->region);
0059
0060 if (rg->size) {
0061 r = -EBUSY;
0062 goto put_region;
0063 }
0064
0065 ofbi->rotation_type = rot_type;
0066
0067
0068
0069
0070
0071 put_region:
0072 omapfb_put_mem_region(rg);
0073 out:
0074 unlock_fb_info(fbi);
0075
0076 return r ? r : count;
0077 }
0078
0079
0080 static ssize_t show_mirror(struct device *dev,
0081 struct device_attribute *attr, char *buf)
0082 {
0083 struct fb_info *fbi = dev_get_drvdata(dev);
0084 struct omapfb_info *ofbi = FB2OFB(fbi);
0085
0086 return sysfs_emit(buf, "%d\n", ofbi->mirror);
0087 }
0088
0089 static ssize_t store_mirror(struct device *dev,
0090 struct device_attribute *attr,
0091 const char *buf, size_t count)
0092 {
0093 struct fb_info *fbi = dev_get_drvdata(dev);
0094 struct omapfb_info *ofbi = FB2OFB(fbi);
0095 bool mirror;
0096 int r;
0097 struct fb_var_screeninfo new_var;
0098
0099 r = strtobool(buf, &mirror);
0100 if (r)
0101 return r;
0102
0103 lock_fb_info(fbi);
0104
0105 ofbi->mirror = mirror;
0106
0107 omapfb_get_mem_region(ofbi->region);
0108
0109 memcpy(&new_var, &fbi->var, sizeof(new_var));
0110 r = check_fb_var(fbi, &new_var);
0111 if (r)
0112 goto out;
0113 memcpy(&fbi->var, &new_var, sizeof(fbi->var));
0114
0115 set_fb_fix(fbi);
0116
0117 r = omapfb_apply_changes(fbi, 0);
0118 if (r)
0119 goto out;
0120
0121 r = count;
0122 out:
0123 omapfb_put_mem_region(ofbi->region);
0124
0125 unlock_fb_info(fbi);
0126
0127 return r;
0128 }
0129
0130 static ssize_t show_overlays(struct device *dev,
0131 struct device_attribute *attr, char *buf)
0132 {
0133 struct fb_info *fbi = dev_get_drvdata(dev);
0134 struct omapfb_info *ofbi = FB2OFB(fbi);
0135 struct omapfb2_device *fbdev = ofbi->fbdev;
0136 ssize_t l = 0;
0137 int t;
0138
0139 lock_fb_info(fbi);
0140 omapfb_lock(fbdev);
0141
0142 for (t = 0; t < ofbi->num_overlays; t++) {
0143 struct omap_overlay *ovl = ofbi->overlays[t];
0144 int ovlnum;
0145
0146 for (ovlnum = 0; ovlnum < fbdev->num_overlays; ++ovlnum)
0147 if (ovl == fbdev->overlays[ovlnum])
0148 break;
0149
0150 l += scnprintf(buf + l, PAGE_SIZE - l, "%s%d",
0151 t == 0 ? "" : ",", ovlnum);
0152 }
0153
0154 l += scnprintf(buf + l, PAGE_SIZE - l, "\n");
0155
0156 omapfb_unlock(fbdev);
0157 unlock_fb_info(fbi);
0158
0159 return l;
0160 }
0161
0162 static struct omapfb_info *get_overlay_fb(struct omapfb2_device *fbdev,
0163 struct omap_overlay *ovl)
0164 {
0165 int i, t;
0166
0167 for (i = 0; i < fbdev->num_fbs; i++) {
0168 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
0169
0170 for (t = 0; t < ofbi->num_overlays; t++) {
0171 if (ofbi->overlays[t] == ovl)
0172 return ofbi;
0173 }
0174 }
0175
0176 return NULL;
0177 }
0178
0179 static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
0180 const char *buf, size_t count)
0181 {
0182 struct fb_info *fbi = dev_get_drvdata(dev);
0183 struct omapfb_info *ofbi = FB2OFB(fbi);
0184 struct omapfb2_device *fbdev = ofbi->fbdev;
0185 struct omap_overlay *ovls[OMAPFB_MAX_OVL_PER_FB];
0186 struct omap_overlay *ovl;
0187 int num_ovls, r, i;
0188 int len;
0189 bool added = false;
0190
0191 num_ovls = 0;
0192
0193 len = strlen(buf);
0194 if (buf[len - 1] == '\n')
0195 len = len - 1;
0196
0197 lock_fb_info(fbi);
0198 omapfb_lock(fbdev);
0199
0200 if (len > 0) {
0201 char *p = (char *)buf;
0202 int ovlnum;
0203
0204 while (p < buf + len) {
0205 int found;
0206 if (num_ovls == OMAPFB_MAX_OVL_PER_FB) {
0207 r = -EINVAL;
0208 goto out;
0209 }
0210
0211 ovlnum = simple_strtoul(p, &p, 0);
0212 if (ovlnum > fbdev->num_overlays) {
0213 r = -EINVAL;
0214 goto out;
0215 }
0216
0217 found = 0;
0218 for (i = 0; i < num_ovls; ++i) {
0219 if (ovls[i] == fbdev->overlays[ovlnum]) {
0220 found = 1;
0221 break;
0222 }
0223 }
0224
0225 if (!found)
0226 ovls[num_ovls++] = fbdev->overlays[ovlnum];
0227
0228 p++;
0229 }
0230 }
0231
0232 for (i = 0; i < num_ovls; ++i) {
0233 struct omapfb_info *ofbi2 = get_overlay_fb(fbdev, ovls[i]);
0234 if (ofbi2 && ofbi2 != ofbi) {
0235 dev_err(fbdev->dev, "overlay already in use\n");
0236 r = -EINVAL;
0237 goto out;
0238 }
0239 }
0240
0241
0242 for (i = 0; i < ofbi->num_overlays; ++i) {
0243 int t, found;
0244
0245 ovl = ofbi->overlays[i];
0246
0247 found = 0;
0248
0249 for (t = 0; t < num_ovls; ++t) {
0250 if (ovl == ovls[t]) {
0251 found = 1;
0252 break;
0253 }
0254 }
0255
0256 if (found)
0257 continue;
0258
0259 DBG("detaching %d\n", ofbi->overlays[i]->id);
0260
0261 omapfb_get_mem_region(ofbi->region);
0262
0263 omapfb_overlay_enable(ovl, 0);
0264
0265 if (ovl->manager)
0266 ovl->manager->apply(ovl->manager);
0267
0268 omapfb_put_mem_region(ofbi->region);
0269
0270 for (t = i + 1; t < ofbi->num_overlays; t++) {
0271 ofbi->rotation[t-1] = ofbi->rotation[t];
0272 ofbi->overlays[t-1] = ofbi->overlays[t];
0273 }
0274
0275 ofbi->num_overlays--;
0276 i--;
0277 }
0278
0279 for (i = 0; i < num_ovls; ++i) {
0280 int t, found;
0281
0282 ovl = ovls[i];
0283
0284 found = 0;
0285
0286 for (t = 0; t < ofbi->num_overlays; ++t) {
0287 if (ovl == ofbi->overlays[t]) {
0288 found = 1;
0289 break;
0290 }
0291 }
0292
0293 if (found)
0294 continue;
0295 ofbi->rotation[ofbi->num_overlays] = 0;
0296 ofbi->overlays[ofbi->num_overlays++] = ovl;
0297
0298 added = true;
0299 }
0300
0301 if (added) {
0302 omapfb_get_mem_region(ofbi->region);
0303
0304 r = omapfb_apply_changes(fbi, 0);
0305
0306 omapfb_put_mem_region(ofbi->region);
0307
0308 if (r)
0309 goto out;
0310 }
0311
0312 r = count;
0313 out:
0314 omapfb_unlock(fbdev);
0315 unlock_fb_info(fbi);
0316
0317 return r;
0318 }
0319
0320 static ssize_t show_overlays_rotate(struct device *dev,
0321 struct device_attribute *attr, char *buf)
0322 {
0323 struct fb_info *fbi = dev_get_drvdata(dev);
0324 struct omapfb_info *ofbi = FB2OFB(fbi);
0325 ssize_t l = 0;
0326 int t;
0327
0328 lock_fb_info(fbi);
0329
0330 for (t = 0; t < ofbi->num_overlays; t++) {
0331 l += scnprintf(buf + l, PAGE_SIZE - l, "%s%d",
0332 t == 0 ? "" : ",", ofbi->rotation[t]);
0333 }
0334
0335 l += scnprintf(buf + l, PAGE_SIZE - l, "\n");
0336
0337 unlock_fb_info(fbi);
0338
0339 return l;
0340 }
0341
0342 static ssize_t store_overlays_rotate(struct device *dev,
0343 struct device_attribute *attr, const char *buf, size_t count)
0344 {
0345 struct fb_info *fbi = dev_get_drvdata(dev);
0346 struct omapfb_info *ofbi = FB2OFB(fbi);
0347 int num_ovls = 0, r, i;
0348 int len;
0349 bool changed = false;
0350 u8 rotation[OMAPFB_MAX_OVL_PER_FB];
0351
0352 len = strlen(buf);
0353 if (buf[len - 1] == '\n')
0354 len = len - 1;
0355
0356 lock_fb_info(fbi);
0357
0358 if (len > 0) {
0359 char *p = (char *)buf;
0360
0361 while (p < buf + len) {
0362 int rot;
0363
0364 if (num_ovls == ofbi->num_overlays) {
0365 r = -EINVAL;
0366 goto out;
0367 }
0368
0369 rot = simple_strtoul(p, &p, 0);
0370 if (rot < 0 || rot > 3) {
0371 r = -EINVAL;
0372 goto out;
0373 }
0374
0375 if (ofbi->rotation[num_ovls] != rot)
0376 changed = true;
0377
0378 rotation[num_ovls++] = rot;
0379
0380 p++;
0381 }
0382 }
0383
0384 if (num_ovls != ofbi->num_overlays) {
0385 r = -EINVAL;
0386 goto out;
0387 }
0388
0389 if (changed) {
0390 for (i = 0; i < num_ovls; ++i)
0391 ofbi->rotation[i] = rotation[i];
0392
0393 omapfb_get_mem_region(ofbi->region);
0394
0395 r = omapfb_apply_changes(fbi, 0);
0396
0397 omapfb_put_mem_region(ofbi->region);
0398
0399 if (r)
0400 goto out;
0401
0402
0403 }
0404
0405 r = count;
0406 out:
0407 unlock_fb_info(fbi);
0408
0409 return r;
0410 }
0411
0412 static ssize_t show_size(struct device *dev,
0413 struct device_attribute *attr, char *buf)
0414 {
0415 struct fb_info *fbi = dev_get_drvdata(dev);
0416 struct omapfb_info *ofbi = FB2OFB(fbi);
0417
0418 return sysfs_emit(buf, "%lu\n", ofbi->region->size);
0419 }
0420
0421 static ssize_t store_size(struct device *dev, struct device_attribute *attr,
0422 const char *buf, size_t count)
0423 {
0424 struct fb_info *fbi = dev_get_drvdata(dev);
0425 struct omapfb_info *ofbi = FB2OFB(fbi);
0426 struct omapfb2_device *fbdev = ofbi->fbdev;
0427 struct omap_dss_device *display = fb2display(fbi);
0428 struct omapfb2_mem_region *rg;
0429 unsigned long size;
0430 int r;
0431 int i;
0432
0433 r = kstrtoul(buf, 0, &size);
0434 if (r)
0435 return r;
0436
0437 size = PAGE_ALIGN(size);
0438
0439 lock_fb_info(fbi);
0440
0441 if (display && display->driver->sync)
0442 display->driver->sync(display);
0443
0444 rg = ofbi->region;
0445
0446 down_write_nested(&rg->lock, rg->id);
0447 atomic_inc(&rg->lock_count);
0448
0449 if (atomic_read(&rg->map_count)) {
0450 r = -EBUSY;
0451 goto out;
0452 }
0453
0454 for (i = 0; i < fbdev->num_fbs; i++) {
0455 struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]);
0456 int j;
0457
0458 if (ofbi2->region != rg)
0459 continue;
0460
0461 for (j = 0; j < ofbi2->num_overlays; j++) {
0462 struct omap_overlay *ovl;
0463 ovl = ofbi2->overlays[j];
0464 if (ovl->is_enabled(ovl)) {
0465 r = -EBUSY;
0466 goto out;
0467 }
0468 }
0469 }
0470
0471 if (size != ofbi->region->size) {
0472 r = omapfb_realloc_fbmem(fbi, size, ofbi->region->type);
0473 if (r) {
0474 dev_err(dev, "realloc fbmem failed\n");
0475 goto out;
0476 }
0477 }
0478
0479 r = count;
0480 out:
0481 atomic_dec(&rg->lock_count);
0482 up_write(&rg->lock);
0483
0484 unlock_fb_info(fbi);
0485
0486 return r;
0487 }
0488
0489 static ssize_t show_phys(struct device *dev,
0490 struct device_attribute *attr, char *buf)
0491 {
0492 struct fb_info *fbi = dev_get_drvdata(dev);
0493 struct omapfb_info *ofbi = FB2OFB(fbi);
0494
0495 return sysfs_emit(buf, "%0x\n", ofbi->region->paddr);
0496 }
0497
0498 static ssize_t show_virt(struct device *dev,
0499 struct device_attribute *attr, char *buf)
0500 {
0501 struct fb_info *fbi = dev_get_drvdata(dev);
0502 struct omapfb_info *ofbi = FB2OFB(fbi);
0503
0504 return sysfs_emit(buf, "%p\n", ofbi->region->vaddr);
0505 }
0506
0507 static ssize_t show_upd_mode(struct device *dev,
0508 struct device_attribute *attr, char *buf)
0509 {
0510 struct fb_info *fbi = dev_get_drvdata(dev);
0511 enum omapfb_update_mode mode;
0512 int r;
0513
0514 r = omapfb_get_update_mode(fbi, &mode);
0515
0516 if (r)
0517 return r;
0518
0519 return sysfs_emit(buf, "%u\n", (unsigned int)mode);
0520 }
0521
0522 static ssize_t store_upd_mode(struct device *dev, struct device_attribute *attr,
0523 const char *buf, size_t count)
0524 {
0525 struct fb_info *fbi = dev_get_drvdata(dev);
0526 unsigned mode;
0527 int r;
0528
0529 r = kstrtouint(buf, 0, &mode);
0530 if (r)
0531 return r;
0532
0533 r = omapfb_set_update_mode(fbi, mode);
0534 if (r)
0535 return r;
0536
0537 return count;
0538 }
0539
0540 static struct device_attribute omapfb_attrs[] = {
0541 __ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type,
0542 store_rotate_type),
0543 __ATTR(mirror, S_IRUGO | S_IWUSR, show_mirror, store_mirror),
0544 __ATTR(size, S_IRUGO | S_IWUSR, show_size, store_size),
0545 __ATTR(overlays, S_IRUGO | S_IWUSR, show_overlays, store_overlays),
0546 __ATTR(overlays_rotate, S_IRUGO | S_IWUSR, show_overlays_rotate,
0547 store_overlays_rotate),
0548 __ATTR(phys_addr, S_IRUGO, show_phys, NULL),
0549 __ATTR(virt_addr, S_IRUGO, show_virt, NULL),
0550 __ATTR(update_mode, S_IRUGO | S_IWUSR, show_upd_mode, store_upd_mode),
0551 };
0552
0553 int omapfb_create_sysfs(struct omapfb2_device *fbdev)
0554 {
0555 int i;
0556 int r;
0557
0558 DBG("create sysfs for fbs\n");
0559 for (i = 0; i < fbdev->num_fbs; i++) {
0560 int t;
0561 for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) {
0562 r = device_create_file(fbdev->fbs[i]->dev,
0563 &omapfb_attrs[t]);
0564
0565 if (r) {
0566 dev_err(fbdev->dev, "failed to create sysfs "
0567 "file\n");
0568 return r;
0569 }
0570 }
0571 }
0572
0573 return 0;
0574 }
0575
0576 void omapfb_remove_sysfs(struct omapfb2_device *fbdev)
0577 {
0578 int i, t;
0579
0580 DBG("remove sysfs for fbs\n");
0581 for (i = 0; i < fbdev->num_fbs; i++) {
0582 for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++)
0583 device_remove_file(fbdev->fbs[i]->dev,
0584 &omapfb_attrs[t]);
0585 }
0586 }
0587