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