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