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