1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2009 Nokia Corporation 4 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> 5 * 6 * Some code and ideas taken from drivers/video/omap/ driver 7 * 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 24 static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf) 25 { 26 return sysfs_emit(buf, "%s\n", ovl->name); 27 } 28 29 static 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 35 static 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 101 err: 102 dispc_runtime_put(); 103 return r; 104 } 105 106 static 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 116 static 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 125 static 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 135 static 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 164 static 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 174 static 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 203 static 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 208 static 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 else 221 r = ovl->disable(ovl); 222 223 if (r) 224 return r; 225 226 return size; 227 } 228 229 static 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 239 static 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 270 static 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 281 static 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 312 static 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 321 static 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 352 struct 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 362 static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL); 363 static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR, 364 overlay_manager_show, overlay_manager_store); 365 static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL); 366 static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL); 367 static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR, 368 overlay_position_show, overlay_position_store); 369 static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR, 370 overlay_output_size_show, overlay_output_size_store); 371 static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR, 372 overlay_enabled_show, overlay_enabled_store); 373 static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR, 374 overlay_global_alpha_show, overlay_global_alpha_store); 375 static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR, 376 overlay_pre_mult_alpha_show, 377 overlay_pre_mult_alpha_store); 378 static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR, 379 overlay_zorder_show, overlay_zorder_store); 380 381 static 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 NULL 393 }; 394 ATTRIBUTE_GROUPS(overlay_sysfs); 395 396 static 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 411 static 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 426 static const struct sysfs_ops overlay_sysfs_ops = { 427 .show = overlay_attr_show, 428 .store = overlay_attr_store, 429 }; 430 431 static struct kobj_type overlay_ktype = { 432 .sysfs_ops = &overlay_sysfs_ops, 433 .default_groups = overlay_sysfs_groups, 434 }; 435 436 int 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 443 void dss_overlay_kobj_uninit(struct omap_overlay *ovl) 444 { 445 kobject_del(&ovl->kobj); 446 kobject_put(&ovl->kobj); 447 } 448