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