448 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2009 Nokia Corporation4 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>5 *6 * Some code and ideas taken from drivers/video/omap/ driver7 * by Imre Deak.8 */9 10#define DSS_SUBSYS_NAME "OVERLAY"11 12#include <linux/module.h>13#include <linux/err.h>14#include <linux/sysfs.h>15#include <linux/kobject.h>16#include <linux/kstrtox.h>17#include <linux/platform_device.h>18 19#include <video/omapfb_dss.h>20 21#include "dss.h"22#include "dss_features.h"23 24static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf)25{26 return sysfs_emit(buf, "%s\n", ovl->name);27}28 29static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf)30{31 return sysfs_emit(buf, "%s\n",32 ovl->manager ? ovl->manager->name : "<none>");33}34 35static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,36 size_t size)37{38 int i, r;39 struct omap_overlay_manager *mgr = NULL;40 struct omap_overlay_manager *old_mgr;41 int len = size;42 43 if (buf[size-1] == '\n')44 --len;45 46 if (len > 0) {47 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {48 mgr = omap_dss_get_overlay_manager(i);49 50 if (sysfs_streq(buf, mgr->name))51 break;52 53 mgr = NULL;54 }55 }56 57 if (len > 0 && mgr == NULL)58 return -EINVAL;59 60 if (mgr)61 DSSDBG("manager %s found\n", mgr->name);62 63 if (mgr == ovl->manager)64 return size;65 66 old_mgr = ovl->manager;67 68 r = dispc_runtime_get();69 if (r)70 return r;71 72 /* detach old manager */73 if (old_mgr) {74 r = ovl->unset_manager(ovl);75 if (r) {76 DSSERR("detach failed\n");77 goto err;78 }79 80 r = old_mgr->apply(old_mgr);81 if (r)82 goto err;83 }84 85 if (mgr) {86 r = ovl->set_manager(ovl, mgr);87 if (r) {88 DSSERR("Failed to attach overlay\n");89 goto err;90 }91 92 r = mgr->apply(mgr);93 if (r)94 goto err;95 }96 97 dispc_runtime_put();98 99 return size;100 101err:102 dispc_runtime_put();103 return r;104}105 106static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)107{108 struct omap_overlay_info info;109 110 ovl->get_overlay_info(ovl, &info);111 112 return sysfs_emit(buf, "%d,%d\n",113 info.width, info.height);114}115 116static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf)117{118 struct omap_overlay_info info;119 120 ovl->get_overlay_info(ovl, &info);121 122 return sysfs_emit(buf, "%d\n", info.screen_width);123}124 125static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf)126{127 struct omap_overlay_info info;128 129 ovl->get_overlay_info(ovl, &info);130 131 return sysfs_emit(buf, "%d,%d\n",132 info.pos_x, info.pos_y);133}134 135static ssize_t overlay_position_store(struct omap_overlay *ovl,136 const char *buf, size_t size)137{138 int r;139 char *last;140 struct omap_overlay_info info;141 142 ovl->get_overlay_info(ovl, &info);143 144 info.pos_x = simple_strtoul(buf, &last, 10);145 ++last;146 if (last - buf >= size)147 return -EINVAL;148 149 info.pos_y = simple_strtoul(last, &last, 10);150 151 r = ovl->set_overlay_info(ovl, &info);152 if (r)153 return r;154 155 if (ovl->manager) {156 r = ovl->manager->apply(ovl->manager);157 if (r)158 return r;159 }160 161 return size;162}163 164static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf)165{166 struct omap_overlay_info info;167 168 ovl->get_overlay_info(ovl, &info);169 170 return sysfs_emit(buf, "%d,%d\n",171 info.out_width, info.out_height);172}173 174static ssize_t overlay_output_size_store(struct omap_overlay *ovl,175 const char *buf, size_t size)176{177 int r;178 char *last;179 struct omap_overlay_info info;180 181 ovl->get_overlay_info(ovl, &info);182 183 info.out_width = simple_strtoul(buf, &last, 10);184 ++last;185 if (last - buf >= size)186 return -EINVAL;187 188 info.out_height = simple_strtoul(last, &last, 10);189 190 r = ovl->set_overlay_info(ovl, &info);191 if (r)192 return r;193 194 if (ovl->manager) {195 r = ovl->manager->apply(ovl->manager);196 if (r)197 return r;198 }199 200 return size;201}202 203static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)204{205 return sysfs_emit(buf, "%d\n", ovl->is_enabled(ovl));206}207 208static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,209 size_t size)210{211 int r;212 bool enable;213 214 r = kstrtobool(buf, &enable);215 if (r)216 return r;217 218 if (enable)219 r = ovl->enable(ovl);220 else221 r = ovl->disable(ovl);222 223 if (r)224 return r;225 226 return size;227}228 229static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf)230{231 struct omap_overlay_info info;232 233 ovl->get_overlay_info(ovl, &info);234 235 return sysfs_emit(buf, "%d\n",236 info.global_alpha);237}238 239static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,240 const char *buf, size_t size)241{242 int r;243 u8 alpha;244 struct omap_overlay_info info;245 246 if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)247 return -ENODEV;248 249 r = kstrtou8(buf, 0, &alpha);250 if (r)251 return r;252 253 ovl->get_overlay_info(ovl, &info);254 255 info.global_alpha = alpha;256 257 r = ovl->set_overlay_info(ovl, &info);258 if (r)259 return r;260 261 if (ovl->manager) {262 r = ovl->manager->apply(ovl->manager);263 if (r)264 return r;265 }266 267 return size;268}269 270static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl,271 char *buf)272{273 struct omap_overlay_info info;274 275 ovl->get_overlay_info(ovl, &info);276 277 return sysfs_emit(buf, "%d\n",278 info.pre_mult_alpha);279}280 281static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,282 const char *buf, size_t size)283{284 int r;285 u8 alpha;286 struct omap_overlay_info info;287 288 if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)289 return -ENODEV;290 291 r = kstrtou8(buf, 0, &alpha);292 if (r)293 return r;294 295 ovl->get_overlay_info(ovl, &info);296 297 info.pre_mult_alpha = alpha;298 299 r = ovl->set_overlay_info(ovl, &info);300 if (r)301 return r;302 303 if (ovl->manager) {304 r = ovl->manager->apply(ovl->manager);305 if (r)306 return r;307 }308 309 return size;310}311 312static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf)313{314 struct omap_overlay_info info;315 316 ovl->get_overlay_info(ovl, &info);317 318 return sysfs_emit(buf, "%d\n", info.zorder);319}320 321static ssize_t overlay_zorder_store(struct omap_overlay *ovl,322 const char *buf, size_t size)323{324 int r;325 u8 zorder;326 struct omap_overlay_info info;327 328 if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)329 return -ENODEV;330 331 r = kstrtou8(buf, 0, &zorder);332 if (r)333 return r;334 335 ovl->get_overlay_info(ovl, &info);336 337 info.zorder = zorder;338 339 r = ovl->set_overlay_info(ovl, &info);340 if (r)341 return r;342 343 if (ovl->manager) {344 r = ovl->manager->apply(ovl->manager);345 if (r)346 return r;347 }348 349 return size;350}351 352struct overlay_attribute {353 struct attribute attr;354 ssize_t (*show)(struct omap_overlay *, char *);355 ssize_t (*store)(struct omap_overlay *, const char *, size_t);356};357 358#define OVERLAY_ATTR(_name, _mode, _show, _store) \359 struct overlay_attribute overlay_attr_##_name = \360 __ATTR(_name, _mode, _show, _store)361 362static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL);363static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR,364 overlay_manager_show, overlay_manager_store);365static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL);366static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL);367static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR,368 overlay_position_show, overlay_position_store);369static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR,370 overlay_output_size_show, overlay_output_size_store);371static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR,372 overlay_enabled_show, overlay_enabled_store);373static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,374 overlay_global_alpha_show, overlay_global_alpha_store);375static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR,376 overlay_pre_mult_alpha_show,377 overlay_pre_mult_alpha_store);378static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR,379 overlay_zorder_show, overlay_zorder_store);380 381static struct attribute *overlay_sysfs_attrs[] = {382 &overlay_attr_name.attr,383 &overlay_attr_manager.attr,384 &overlay_attr_input_size.attr,385 &overlay_attr_screen_width.attr,386 &overlay_attr_position.attr,387 &overlay_attr_output_size.attr,388 &overlay_attr_enabled.attr,389 &overlay_attr_global_alpha.attr,390 &overlay_attr_pre_mult_alpha.attr,391 &overlay_attr_zorder.attr,392 NULL393};394ATTRIBUTE_GROUPS(overlay_sysfs);395 396static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr,397 char *buf)398{399 struct omap_overlay *overlay;400 struct overlay_attribute *overlay_attr;401 402 overlay = container_of(kobj, struct omap_overlay, kobj);403 overlay_attr = container_of(attr, struct overlay_attribute, attr);404 405 if (!overlay_attr->show)406 return -ENOENT;407 408 return overlay_attr->show(overlay, buf);409}410 411static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr,412 const char *buf, size_t size)413{414 struct omap_overlay *overlay;415 struct overlay_attribute *overlay_attr;416 417 overlay = container_of(kobj, struct omap_overlay, kobj);418 overlay_attr = container_of(attr, struct overlay_attribute, attr);419 420 if (!overlay_attr->store)421 return -ENOENT;422 423 return overlay_attr->store(overlay, buf, size);424}425 426static const struct sysfs_ops overlay_sysfs_ops = {427 .show = overlay_attr_show,428 .store = overlay_attr_store,429};430 431static struct kobj_type overlay_ktype = {432 .sysfs_ops = &overlay_sysfs_ops,433 .default_groups = overlay_sysfs_groups,434};435 436int dss_overlay_kobj_init(struct omap_overlay *ovl,437 struct platform_device *pdev)438{439 return kobject_init_and_add(&ovl->kobj, &overlay_ktype,440 &pdev->dev.kobj, "overlay%d", ovl->id);441}442 443void dss_overlay_kobj_uninit(struct omap_overlay *ovl)444{445 kobject_del(&ovl->kobj);446 kobject_put(&ovl->kobj);447}448