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 "MANAGER" 22 23 #include <linux/kernel.h> 24 #include <linux/slab.h> 25 #include <linux/module.h> 26 #include <linux/platform_device.h> 27 #include <linux/jiffies.h> 28 29 #include <video/omapfb_dss.h> 30 31 #include "dss.h" 32 #include "dss_features.h" 33 34 static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf) 35 { 36 return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name); 37 } 38 39 static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf) 40 { 41 struct omap_dss_device *dssdev = mgr->get_device(mgr); 42 43 return snprintf(buf, PAGE_SIZE, "%s\n", dssdev ? 44 dssdev->name : "<none>"); 45 } 46 47 static int manager_display_match(struct omap_dss_device *dssdev, void *data) 48 { 49 const char *str = data; 50 51 return sysfs_streq(dssdev->name, str); 52 } 53 54 static ssize_t manager_display_store(struct omap_overlay_manager *mgr, 55 const char *buf, size_t size) 56 { 57 int r = 0; 58 size_t len = size; 59 struct omap_dss_device *dssdev = NULL; 60 struct omap_dss_device *old_dssdev; 61 62 if (buf[size-1] == '\n') 63 --len; 64 65 if (len > 0) 66 dssdev = omap_dss_find_device((void *)buf, 67 manager_display_match); 68 69 if (len > 0 && dssdev == NULL) 70 return -EINVAL; 71 72 if (dssdev) { 73 DSSDBG("display %s found\n", dssdev->name); 74 75 if (omapdss_device_is_connected(dssdev)) { 76 DSSERR("new display is already connected\n"); 77 r = -EINVAL; 78 goto put_device; 79 } 80 81 if (omapdss_device_is_enabled(dssdev)) { 82 DSSERR("new display is not disabled\n"); 83 r = -EINVAL; 84 goto put_device; 85 } 86 } 87 88 old_dssdev = mgr->get_device(mgr); 89 if (old_dssdev) { 90 if (omapdss_device_is_enabled(old_dssdev)) { 91 DSSERR("old display is not disabled\n"); 92 r = -EINVAL; 93 goto put_device; 94 } 95 96 old_dssdev->driver->disconnect(old_dssdev); 97 } 98 99 if (dssdev) { 100 r = dssdev->driver->connect(dssdev); 101 if (r) { 102 DSSERR("failed to connect new device\n"); 103 goto put_device; 104 } 105 106 old_dssdev = mgr->get_device(mgr); 107 if (old_dssdev != dssdev) { 108 DSSERR("failed to connect device to this manager\n"); 109 dssdev->driver->disconnect(dssdev); 110 goto put_device; 111 } 112 113 r = mgr->apply(mgr); 114 if (r) { 115 DSSERR("failed to apply dispc config\n"); 116 goto put_device; 117 } 118 } 119 120 put_device: 121 if (dssdev) 122 omap_dss_put_device(dssdev); 123 124 return r ? r : size; 125 } 126 127 static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr, 128 char *buf) 129 { 130 struct omap_overlay_manager_info info; 131 132 mgr->get_manager_info(mgr, &info); 133 134 return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color); 135 } 136 137 static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr, 138 const char *buf, size_t size) 139 { 140 struct omap_overlay_manager_info info; 141 u32 color; 142 int r; 143 144 r = kstrtouint(buf, 0, &color); 145 if (r) 146 return r; 147 148 mgr->get_manager_info(mgr, &info); 149 150 info.default_color = color; 151 152 r = mgr->set_manager_info(mgr, &info); 153 if (r) 154 return r; 155 156 r = mgr->apply(mgr); 157 if (r) 158 return r; 159 160 return size; 161 } 162 163 static const char *trans_key_type_str[] = { 164 "gfx-destination", 165 "video-source", 166 }; 167 168 static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr, 169 char *buf) 170 { 171 enum omap_dss_trans_key_type key_type; 172 struct omap_overlay_manager_info info; 173 174 mgr->get_manager_info(mgr, &info); 175 176 key_type = info.trans_key_type; 177 BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str)); 178 179 return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]); 180 } 181 182 static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr, 183 const char *buf, size_t size) 184 { 185 struct omap_overlay_manager_info info; 186 int r; 187 188 r = sysfs_match_string(trans_key_type_str, buf); 189 if (r < 0) 190 return r; 191 192 mgr->get_manager_info(mgr, &info); 193 194 info.trans_key_type = r; 195 196 r = mgr->set_manager_info(mgr, &info); 197 if (r) 198 return r; 199 200 r = mgr->apply(mgr); 201 if (r) 202 return r; 203 204 return size; 205 } 206 207 static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr, 208 char *buf) 209 { 210 struct omap_overlay_manager_info info; 211 212 mgr->get_manager_info(mgr, &info); 213 214 return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key); 215 } 216 217 static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr, 218 const char *buf, size_t size) 219 { 220 struct omap_overlay_manager_info info; 221 u32 key_value; 222 int r; 223 224 r = kstrtouint(buf, 0, &key_value); 225 if (r) 226 return r; 227 228 mgr->get_manager_info(mgr, &info); 229 230 info.trans_key = key_value; 231 232 r = mgr->set_manager_info(mgr, &info); 233 if (r) 234 return r; 235 236 r = mgr->apply(mgr); 237 if (r) 238 return r; 239 240 return size; 241 } 242 243 static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr, 244 char *buf) 245 { 246 struct omap_overlay_manager_info info; 247 248 mgr->get_manager_info(mgr, &info); 249 250 return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled); 251 } 252 253 static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, 254 const char *buf, size_t size) 255 { 256 struct omap_overlay_manager_info info; 257 bool enable; 258 int r; 259 260 r = strtobool(buf, &enable); 261 if (r) 262 return r; 263 264 mgr->get_manager_info(mgr, &info); 265 266 info.trans_enabled = enable; 267 268 r = mgr->set_manager_info(mgr, &info); 269 if (r) 270 return r; 271 272 r = mgr->apply(mgr); 273 if (r) 274 return r; 275 276 return size; 277 } 278 279 static ssize_t manager_alpha_blending_enabled_show( 280 struct omap_overlay_manager *mgr, char *buf) 281 { 282 struct omap_overlay_manager_info info; 283 284 if(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) 285 return -ENODEV; 286 287 mgr->get_manager_info(mgr, &info); 288 289 return snprintf(buf, PAGE_SIZE, "%d\n", 290 info.partial_alpha_enabled); 291 } 292 293 static ssize_t manager_alpha_blending_enabled_store( 294 struct omap_overlay_manager *mgr, 295 const char *buf, size_t size) 296 { 297 struct omap_overlay_manager_info info; 298 bool enable; 299 int r; 300 301 if(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) 302 return -ENODEV; 303 304 r = strtobool(buf, &enable); 305 if (r) 306 return r; 307 308 mgr->get_manager_info(mgr, &info); 309 310 info.partial_alpha_enabled = enable; 311 312 r = mgr->set_manager_info(mgr, &info); 313 if (r) 314 return r; 315 316 r = mgr->apply(mgr); 317 if (r) 318 return r; 319 320 return size; 321 } 322 323 static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr, 324 char *buf) 325 { 326 struct omap_overlay_manager_info info; 327 328 mgr->get_manager_info(mgr, &info); 329 330 return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable); 331 } 332 333 static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr, 334 const char *buf, size_t size) 335 { 336 struct omap_overlay_manager_info info; 337 int r; 338 bool enable; 339 340 if (!dss_has_feature(FEAT_CPR)) 341 return -ENODEV; 342 343 r = strtobool(buf, &enable); 344 if (r) 345 return r; 346 347 mgr->get_manager_info(mgr, &info); 348 349 if (info.cpr_enable == enable) 350 return size; 351 352 info.cpr_enable = enable; 353 354 r = mgr->set_manager_info(mgr, &info); 355 if (r) 356 return r; 357 358 r = mgr->apply(mgr); 359 if (r) 360 return r; 361 362 return size; 363 } 364 365 static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr, 366 char *buf) 367 { 368 struct omap_overlay_manager_info info; 369 370 mgr->get_manager_info(mgr, &info); 371 372 return snprintf(buf, PAGE_SIZE, 373 "%d %d %d %d %d %d %d %d %d\n", 374 info.cpr_coefs.rr, 375 info.cpr_coefs.rg, 376 info.cpr_coefs.rb, 377 info.cpr_coefs.gr, 378 info.cpr_coefs.gg, 379 info.cpr_coefs.gb, 380 info.cpr_coefs.br, 381 info.cpr_coefs.bg, 382 info.cpr_coefs.bb); 383 } 384 385 static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr, 386 const char *buf, size_t size) 387 { 388 struct omap_overlay_manager_info info; 389 struct omap_dss_cpr_coefs coefs; 390 int r, i; 391 s16 *arr; 392 393 if (!dss_has_feature(FEAT_CPR)) 394 return -ENODEV; 395 396 if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd", 397 &coefs.rr, &coefs.rg, &coefs.rb, 398 &coefs.gr, &coefs.gg, &coefs.gb, 399 &coefs.br, &coefs.bg, &coefs.bb) != 9) 400 return -EINVAL; 401 402 arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb, 403 coefs.gr, coefs.gg, coefs.gb, 404 coefs.br, coefs.bg, coefs.bb }; 405 406 for (i = 0; i < 9; ++i) { 407 if (arr[i] < -512 || arr[i] > 511) 408 return -EINVAL; 409 } 410 411 mgr->get_manager_info(mgr, &info); 412 413 info.cpr_coefs = coefs; 414 415 r = mgr->set_manager_info(mgr, &info); 416 if (r) 417 return r; 418 419 r = mgr->apply(mgr); 420 if (r) 421 return r; 422 423 return size; 424 } 425 426 struct manager_attribute { 427 struct attribute attr; 428 ssize_t (*show)(struct omap_overlay_manager *, char *); 429 ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t); 430 }; 431 432 #define MANAGER_ATTR(_name, _mode, _show, _store) \ 433 struct manager_attribute manager_attr_##_name = \ 434 __ATTR(_name, _mode, _show, _store) 435 436 static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL); 437 static MANAGER_ATTR(display, S_IRUGO|S_IWUSR, 438 manager_display_show, manager_display_store); 439 static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR, 440 manager_default_color_show, manager_default_color_store); 441 static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR, 442 manager_trans_key_type_show, manager_trans_key_type_store); 443 static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR, 444 manager_trans_key_value_show, manager_trans_key_value_store); 445 static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR, 446 manager_trans_key_enabled_show, 447 manager_trans_key_enabled_store); 448 static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR, 449 manager_alpha_blending_enabled_show, 450 manager_alpha_blending_enabled_store); 451 static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR, 452 manager_cpr_enable_show, 453 manager_cpr_enable_store); 454 static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR, 455 manager_cpr_coef_show, 456 manager_cpr_coef_store); 457 458 459 static struct attribute *manager_sysfs_attrs[] = { 460 &manager_attr_name.attr, 461 &manager_attr_display.attr, 462 &manager_attr_default_color.attr, 463 &manager_attr_trans_key_type.attr, 464 &manager_attr_trans_key_value.attr, 465 &manager_attr_trans_key_enabled.attr, 466 &manager_attr_alpha_blending_enabled.attr, 467 &manager_attr_cpr_enable.attr, 468 &manager_attr_cpr_coef.attr, 469 NULL 470 }; 471 472 static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr, 473 char *buf) 474 { 475 struct omap_overlay_manager *manager; 476 struct manager_attribute *manager_attr; 477 478 manager = container_of(kobj, struct omap_overlay_manager, kobj); 479 manager_attr = container_of(attr, struct manager_attribute, attr); 480 481 if (!manager_attr->show) 482 return -ENOENT; 483 484 return manager_attr->show(manager, buf); 485 } 486 487 static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr, 488 const char *buf, size_t size) 489 { 490 struct omap_overlay_manager *manager; 491 struct manager_attribute *manager_attr; 492 493 manager = container_of(kobj, struct omap_overlay_manager, kobj); 494 manager_attr = container_of(attr, struct manager_attribute, attr); 495 496 if (!manager_attr->store) 497 return -ENOENT; 498 499 return manager_attr->store(manager, buf, size); 500 } 501 502 static const struct sysfs_ops manager_sysfs_ops = { 503 .show = manager_attr_show, 504 .store = manager_attr_store, 505 }; 506 507 static struct kobj_type manager_ktype = { 508 .sysfs_ops = &manager_sysfs_ops, 509 .default_attrs = manager_sysfs_attrs, 510 }; 511 512 int dss_manager_kobj_init(struct omap_overlay_manager *mgr, 513 struct platform_device *pdev) 514 { 515 return kobject_init_and_add(&mgr->kobj, &manager_ktype, 516 &pdev->dev.kobj, "manager%d", mgr->id); 517 } 518 519 void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr) 520 { 521 kobject_del(&mgr->kobj); 522 kobject_put(&mgr->kobj); 523 524 memset(&mgr->kobj, 0, sizeof(mgr->kobj)); 525 } 526