linux/drivers/video/omap2/omapfb/omapfb-sysfs.c
<<
>>
Prefs
   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/omapdss.h>
  33#include <video/omapvrfb.h>
  34
  35#include "omapfb.h"
  36
  37static 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
  46static 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        if (!lock_fb_info(fbi))
  64                return -ENODEV;
  65
  66        r = 0;
  67        if (rot_type == ofbi->rotation_type)
  68                goto out;
  69
  70        rg = omapfb_get_mem_region(ofbi->region);
  71
  72        if (rg->size) {
  73                r = -EBUSY;
  74                goto put_region;
  75        }
  76
  77        ofbi->rotation_type = rot_type;
  78
  79        /*
  80         * Since the VRAM for this FB is not allocated at the moment we don't
  81         * need to do any further parameter checking at this point.
  82         */
  83put_region:
  84        omapfb_put_mem_region(rg);
  85out:
  86        unlock_fb_info(fbi);
  87
  88        return r ? r : count;
  89}
  90
  91
  92static ssize_t show_mirror(struct device *dev,
  93                struct device_attribute *attr, char *buf)
  94{
  95        struct fb_info *fbi = dev_get_drvdata(dev);
  96        struct omapfb_info *ofbi = FB2OFB(fbi);
  97
  98        return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->mirror);
  99}
 100
 101static ssize_t store_mirror(struct device *dev,
 102                struct device_attribute *attr,
 103                const char *buf, size_t count)
 104{
 105        struct fb_info *fbi = dev_get_drvdata(dev);
 106        struct omapfb_info *ofbi = FB2OFB(fbi);
 107        bool mirror;
 108        int r;
 109        struct fb_var_screeninfo new_var;
 110
 111        r = strtobool(buf, &mirror);
 112        if (r)
 113                return r;
 114
 115        if (!lock_fb_info(fbi))
 116                return -ENODEV;
 117
 118        ofbi->mirror = mirror;
 119
 120        omapfb_get_mem_region(ofbi->region);
 121
 122        memcpy(&new_var, &fbi->var, sizeof(new_var));
 123        r = check_fb_var(fbi, &new_var);
 124        if (r)
 125                goto out;
 126        memcpy(&fbi->var, &new_var, sizeof(fbi->var));
 127
 128        set_fb_fix(fbi);
 129
 130        r = omapfb_apply_changes(fbi, 0);
 131        if (r)
 132                goto out;
 133
 134        r = count;
 135out:
 136        omapfb_put_mem_region(ofbi->region);
 137
 138        unlock_fb_info(fbi);
 139
 140        return r;
 141}
 142
 143static ssize_t show_overlays(struct device *dev,
 144                struct device_attribute *attr, char *buf)
 145{
 146        struct fb_info *fbi = dev_get_drvdata(dev);
 147        struct omapfb_info *ofbi = FB2OFB(fbi);
 148        struct omapfb2_device *fbdev = ofbi->fbdev;
 149        ssize_t l = 0;
 150        int t;
 151
 152        if (!lock_fb_info(fbi))
 153                return -ENODEV;
 154        omapfb_lock(fbdev);
 155
 156        for (t = 0; t < ofbi->num_overlays; t++) {
 157                struct omap_overlay *ovl = ofbi->overlays[t];
 158                int ovlnum;
 159
 160                for (ovlnum = 0; ovlnum < fbdev->num_overlays; ++ovlnum)
 161                        if (ovl == fbdev->overlays[ovlnum])
 162                                break;
 163
 164                l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
 165                                t == 0 ? "" : ",", ovlnum);
 166        }
 167
 168        l += snprintf(buf + l, PAGE_SIZE - l, "\n");
 169
 170        omapfb_unlock(fbdev);
 171        unlock_fb_info(fbi);
 172
 173        return l;
 174}
 175
 176static struct omapfb_info *get_overlay_fb(struct omapfb2_device *fbdev,
 177                struct omap_overlay *ovl)
 178{
 179        int i, t;
 180
 181        for (i = 0; i < fbdev->num_fbs; i++) {
 182                struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
 183
 184                for (t = 0; t < ofbi->num_overlays; t++) {
 185                        if (ofbi->overlays[t] == ovl)
 186                                return ofbi;
 187                }
 188        }
 189
 190        return NULL;
 191}
 192
 193static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
 194                const char *buf, size_t count)
 195{
 196        struct fb_info *fbi = dev_get_drvdata(dev);
 197        struct omapfb_info *ofbi = FB2OFB(fbi);
 198        struct omapfb2_device *fbdev = ofbi->fbdev;
 199        struct omap_overlay *ovls[OMAPFB_MAX_OVL_PER_FB];
 200        struct omap_overlay *ovl;
 201        int num_ovls, r, i;
 202        int len;
 203        bool added = false;
 204
 205        num_ovls = 0;
 206
 207        len = strlen(buf);
 208        if (buf[len - 1] == '\n')
 209                len = len - 1;
 210
 211        if (!lock_fb_info(fbi))
 212                return -ENODEV;
 213        omapfb_lock(fbdev);
 214
 215        if (len > 0) {
 216                char *p = (char *)buf;
 217                int ovlnum;
 218
 219                while (p < buf + len) {
 220                        int found;
 221                        if (num_ovls == OMAPFB_MAX_OVL_PER_FB) {
 222                                r = -EINVAL;
 223                                goto out;
 224                        }
 225
 226                        ovlnum = simple_strtoul(p, &p, 0);
 227                        if (ovlnum > fbdev->num_overlays) {
 228                                r = -EINVAL;
 229                                goto out;
 230                        }
 231
 232                        found = 0;
 233                        for (i = 0; i < num_ovls; ++i) {
 234                                if (ovls[i] == fbdev->overlays[ovlnum]) {
 235                                        found = 1;
 236                                        break;
 237                                }
 238                        }
 239
 240                        if (!found)
 241                                ovls[num_ovls++] = fbdev->overlays[ovlnum];
 242
 243                        p++;
 244                }
 245        }
 246
 247        for (i = 0; i < num_ovls; ++i) {
 248                struct omapfb_info *ofbi2 = get_overlay_fb(fbdev, ovls[i]);
 249                if (ofbi2 && ofbi2 != ofbi) {
 250                        dev_err(fbdev->dev, "overlay already in use\n");
 251                        r = -EINVAL;
 252                        goto out;
 253                }
 254        }
 255
 256        /* detach unused overlays */
 257        for (i = 0; i < ofbi->num_overlays; ++i) {
 258                int t, found;
 259
 260                ovl = ofbi->overlays[i];
 261
 262                found = 0;
 263
 264                for (t = 0; t < num_ovls; ++t) {
 265                        if (ovl == ovls[t]) {
 266                                found = 1;
 267                                break;
 268                        }
 269                }
 270
 271                if (found)
 272                        continue;
 273
 274                DBG("detaching %d\n", ofbi->overlays[i]->id);
 275
 276                omapfb_get_mem_region(ofbi->region);
 277
 278                omapfb_overlay_enable(ovl, 0);
 279
 280                if (ovl->manager)
 281                        ovl->manager->apply(ovl->manager);
 282
 283                omapfb_put_mem_region(ofbi->region);
 284
 285                for (t = i + 1; t < ofbi->num_overlays; t++) {
 286                        ofbi->rotation[t-1] = ofbi->rotation[t];
 287                        ofbi->overlays[t-1] = ofbi->overlays[t];
 288                }
 289
 290                ofbi->num_overlays--;
 291                i--;
 292        }
 293
 294        for (i = 0; i < num_ovls; ++i) {
 295                int t, found;
 296
 297                ovl = ovls[i];
 298
 299                found = 0;
 300
 301                for (t = 0; t < ofbi->num_overlays; ++t) {
 302                        if (ovl == ofbi->overlays[t]) {
 303                                found = 1;
 304                                break;
 305                        }
 306                }
 307
 308                if (found)
 309                        continue;
 310                ofbi->rotation[ofbi->num_overlays] = 0;
 311                ofbi->overlays[ofbi->num_overlays++] = ovl;
 312
 313                added = true;
 314        }
 315
 316        if (added) {
 317                omapfb_get_mem_region(ofbi->region);
 318
 319                r = omapfb_apply_changes(fbi, 0);
 320
 321                omapfb_put_mem_region(ofbi->region);
 322
 323                if (r)
 324                        goto out;
 325        }
 326
 327        r = count;
 328out:
 329        omapfb_unlock(fbdev);
 330        unlock_fb_info(fbi);
 331
 332        return r;
 333}
 334
 335static ssize_t show_overlays_rotate(struct device *dev,
 336                struct device_attribute *attr, char *buf)
 337{
 338        struct fb_info *fbi = dev_get_drvdata(dev);
 339        struct omapfb_info *ofbi = FB2OFB(fbi);
 340        ssize_t l = 0;
 341        int t;
 342
 343        if (!lock_fb_info(fbi))
 344                return -ENODEV;
 345
 346        for (t = 0; t < ofbi->num_overlays; t++) {
 347                l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
 348                                t == 0 ? "" : ",", ofbi->rotation[t]);
 349        }
 350
 351        l += snprintf(buf + l, PAGE_SIZE - l, "\n");
 352
 353        unlock_fb_info(fbi);
 354
 355        return l;
 356}
 357
 358static ssize_t store_overlays_rotate(struct device *dev,
 359                struct device_attribute *attr, const char *buf, size_t count)
 360{
 361        struct fb_info *fbi = dev_get_drvdata(dev);
 362        struct omapfb_info *ofbi = FB2OFB(fbi);
 363        int num_ovls = 0, r, i;
 364        int len;
 365        bool changed = false;
 366        u8 rotation[OMAPFB_MAX_OVL_PER_FB];
 367
 368        len = strlen(buf);
 369        if (buf[len - 1] == '\n')
 370                len = len - 1;
 371
 372        if (!lock_fb_info(fbi))
 373                return -ENODEV;
 374
 375        if (len > 0) {
 376                char *p = (char *)buf;
 377
 378                while (p < buf + len) {
 379                        int rot;
 380
 381                        if (num_ovls == ofbi->num_overlays) {
 382                                r = -EINVAL;
 383                                goto out;
 384                        }
 385
 386                        rot = simple_strtoul(p, &p, 0);
 387                        if (rot < 0 || rot > 3) {
 388                                r = -EINVAL;
 389                                goto out;
 390                        }
 391
 392                        if (ofbi->rotation[num_ovls] != rot)
 393                                changed = true;
 394
 395                        rotation[num_ovls++] = rot;
 396
 397                        p++;
 398                }
 399        }
 400
 401        if (num_ovls != ofbi->num_overlays) {
 402                r = -EINVAL;
 403                goto out;
 404        }
 405
 406        if (changed) {
 407                for (i = 0; i < num_ovls; ++i)
 408                        ofbi->rotation[i] = rotation[i];
 409
 410                omapfb_get_mem_region(ofbi->region);
 411
 412                r = omapfb_apply_changes(fbi, 0);
 413
 414                omapfb_put_mem_region(ofbi->region);
 415
 416                if (r)
 417                        goto out;
 418
 419                /* FIXME error handling? */
 420        }
 421
 422        r = count;
 423out:
 424        unlock_fb_info(fbi);
 425
 426        return r;
 427}
 428
 429static ssize_t show_size(struct device *dev,
 430                struct device_attribute *attr, char *buf)
 431{
 432        struct fb_info *fbi = dev_get_drvdata(dev);
 433        struct omapfb_info *ofbi = FB2OFB(fbi);
 434
 435        return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region->size);
 436}
 437
 438static ssize_t store_size(struct device *dev, struct device_attribute *attr,
 439                const char *buf, size_t count)
 440{
 441        struct fb_info *fbi = dev_get_drvdata(dev);
 442        struct omapfb_info *ofbi = FB2OFB(fbi);
 443        struct omapfb2_device *fbdev = ofbi->fbdev;
 444        struct omap_dss_device *display = fb2display(fbi);
 445        struct omapfb2_mem_region *rg;
 446        unsigned long size;
 447        int r;
 448        int i;
 449
 450        r = kstrtoul(buf, 0, &size);
 451        if (r)
 452                return r;
 453
 454        size = PAGE_ALIGN(size);
 455
 456        if (!lock_fb_info(fbi))
 457                return -ENODEV;
 458
 459        if (display && display->driver->sync)
 460                display->driver->sync(display);
 461
 462        rg = ofbi->region;
 463
 464        down_write_nested(&rg->lock, rg->id);
 465        atomic_inc(&rg->lock_count);
 466
 467        if (atomic_read(&rg->map_count)) {
 468                r = -EBUSY;
 469                goto out;
 470        }
 471
 472        for (i = 0; i < fbdev->num_fbs; i++) {
 473                struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]);
 474                int j;
 475
 476                if (ofbi2->region != rg)
 477                        continue;
 478
 479                for (j = 0; j < ofbi2->num_overlays; j++) {
 480                        struct omap_overlay *ovl;
 481                        ovl = ofbi2->overlays[j];
 482                        if (ovl->is_enabled(ovl)) {
 483                                r = -EBUSY;
 484                                goto out;
 485                        }
 486                }
 487        }
 488
 489        if (size != ofbi->region->size) {
 490                r = omapfb_realloc_fbmem(fbi, size, ofbi->region->type);
 491                if (r) {
 492                        dev_err(dev, "realloc fbmem failed\n");
 493                        goto out;
 494                }
 495        }
 496
 497        r = count;
 498out:
 499        atomic_dec(&rg->lock_count);
 500        up_write(&rg->lock);
 501
 502        unlock_fb_info(fbi);
 503
 504        return r;
 505}
 506
 507static ssize_t show_phys(struct device *dev,
 508                struct device_attribute *attr, char *buf)
 509{
 510        struct fb_info *fbi = dev_get_drvdata(dev);
 511        struct omapfb_info *ofbi = FB2OFB(fbi);
 512
 513        return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region->paddr);
 514}
 515
 516static ssize_t show_virt(struct device *dev,
 517                struct device_attribute *attr, char *buf)
 518{
 519        struct fb_info *fbi = dev_get_drvdata(dev);
 520        struct omapfb_info *ofbi = FB2OFB(fbi);
 521
 522        return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr);
 523}
 524
 525static ssize_t show_upd_mode(struct device *dev,
 526                struct device_attribute *attr, char *buf)
 527{
 528        struct fb_info *fbi = dev_get_drvdata(dev);
 529        enum omapfb_update_mode mode;
 530        int r;
 531
 532        r = omapfb_get_update_mode(fbi, &mode);
 533
 534        if (r)
 535                return r;
 536
 537        return snprintf(buf, PAGE_SIZE, "%u\n", (unsigned)mode);
 538}
 539
 540static ssize_t store_upd_mode(struct device *dev, struct device_attribute *attr,
 541                const char *buf, size_t count)
 542{
 543        struct fb_info *fbi = dev_get_drvdata(dev);
 544        unsigned mode;
 545        int r;
 546
 547        r = kstrtouint(buf, 0, &mode);
 548        if (r)
 549                return r;
 550
 551        r = omapfb_set_update_mode(fbi, mode);
 552        if (r)
 553                return r;
 554
 555        return count;
 556}
 557
 558static struct device_attribute omapfb_attrs[] = {
 559        __ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type,
 560                        store_rotate_type),
 561        __ATTR(mirror, S_IRUGO | S_IWUSR, show_mirror, store_mirror),
 562        __ATTR(size, S_IRUGO | S_IWUSR, show_size, store_size),
 563        __ATTR(overlays, S_IRUGO | S_IWUSR, show_overlays, store_overlays),
 564        __ATTR(overlays_rotate, S_IRUGO | S_IWUSR, show_overlays_rotate,
 565                        store_overlays_rotate),
 566        __ATTR(phys_addr, S_IRUGO, show_phys, NULL),
 567        __ATTR(virt_addr, S_IRUGO, show_virt, NULL),
 568        __ATTR(update_mode, S_IRUGO | S_IWUSR, show_upd_mode, store_upd_mode),
 569};
 570
 571int omapfb_create_sysfs(struct omapfb2_device *fbdev)
 572{
 573        int i;
 574        int r;
 575
 576        DBG("create sysfs for fbs\n");
 577        for (i = 0; i < fbdev->num_fbs; i++) {
 578                int t;
 579                for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) {
 580                        r = device_create_file(fbdev->fbs[i]->dev,
 581                                        &omapfb_attrs[t]);
 582
 583                        if (r) {
 584                                dev_err(fbdev->dev, "failed to create sysfs "
 585                                                "file\n");
 586                                return r;
 587                        }
 588                }
 589        }
 590
 591        return 0;
 592}
 593
 594void omapfb_remove_sysfs(struct omapfb2_device *fbdev)
 595{
 596        int i, t;
 597
 598        DBG("remove sysfs for fbs\n");
 599        for (i = 0; i < fbdev->num_fbs; i++) {
 600                for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++)
 601                        device_remove_file(fbdev->fbs[i]->dev,
 602                                        &omapfb_attrs[t]);
 603        }
 604}
 605
 606