1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * fbsysfs.c - framebuffer device class and attributes 4 * 5 * Copyright (c) 2004 James Simmons <jsimmons@infradead.org> 6 */ 7 8 #include <linux/console.h> 9 #include <linux/fb.h> 10 #include <linux/major.h> 11 12 #include "fb_internal.h" 13 #include "fbcon.h" 14 15 static int activate_locked(struct fb_info *fb_info, 16 struct fb_var_screeninfo *var) 17 { 18 var->activate |= FB_ACTIVATE_FORCE; 19 return fb_set_var_from_user(fb_info, var); 20 } 21 22 static int activate(struct fb_info *fb_info, struct fb_var_screeninfo *var) 23 { 24 int err; 25 26 console_lock(); 27 lock_fb_info(fb_info); 28 err = activate_locked(fb_info, var); 29 unlock_fb_info(fb_info); 30 console_unlock(); 31 32 return err; 33 } 34 35 static int mode_string(char *buf, size_t size, unsigned int offset, 36 const struct fb_videomode *mode) 37 { 38 char m = 'U'; 39 char v = 'p'; 40 41 if (offset >= size) 42 return 0; 43 44 if (mode->flag & FB_MODE_IS_DETAILED) 45 m = 'D'; 46 if (mode->flag & FB_MODE_IS_VESA) 47 m = 'V'; 48 if (mode->flag & FB_MODE_IS_STANDARD) 49 m = 'S'; 50 51 if (mode->vmode & FB_VMODE_INTERLACED) 52 v = 'i'; 53 if (mode->vmode & FB_VMODE_DOUBLE) 54 v = 'd'; 55 56 return scnprintf(&buf[offset], size - offset, "%c:%dx%d%c-%d\n", 57 m, mode->xres, mode->yres, v, mode->refresh); 58 } 59 60 static ssize_t store_mode(struct device *device, struct device_attribute *attr, 61 const char *buf, size_t count) 62 { 63 struct fb_info *fb_info = dev_get_drvdata(device); 64 char mstr[100]; 65 struct fb_var_screeninfo var; 66 struct fb_modelist *modelist; 67 struct fb_videomode *mode; 68 size_t i; 69 int err; 70 71 memset(&var, 0, sizeof(var)); 72 73 console_lock(); 74 lock_fb_info(fb_info); 75 76 list_for_each_entry(modelist, &fb_info->modelist, list) { 77 mode = &modelist->mode; 78 i = mode_string(mstr, sizeof(mstr), 0, mode); 79 if (strncmp(mstr, buf, max(count, i)) == 0) { 80 81 var = fb_info->var; 82 fb_videomode_to_var(&var, mode); 83 err = activate_locked(fb_info, &var); 84 if (err) { 85 unlock_fb_info(fb_info); 86 console_unlock(); 87 return err; 88 } 89 fb_info->mode = mode; 90 unlock_fb_info(fb_info); 91 console_unlock(); 92 return count; 93 } 94 } 95 96 unlock_fb_info(fb_info); 97 console_unlock(); 98 99 return -EINVAL; 100 } 101 102 static ssize_t show_mode(struct device *device, struct device_attribute *attr, 103 char *buf) 104 { 105 struct fb_info *fb_info = dev_get_drvdata(device); 106 struct fb_videomode mode; 107 bool have_mode = false; 108 109 lock_fb_info(fb_info); 110 if (fb_info->mode) { 111 mode = *fb_info->mode; 112 have_mode = true; 113 } 114 unlock_fb_info(fb_info); 115 116 if (!have_mode) 117 return 0; 118 119 return mode_string(buf, PAGE_SIZE, 0, &mode); 120 } 121 122 static ssize_t store_modes(struct device *device, 123 struct device_attribute *attr, 124 const char *buf, size_t count) 125 { 126 struct fb_info *fb_info = dev_get_drvdata(device); 127 LIST_HEAD(old_list); 128 int i = count / sizeof(struct fb_videomode); 129 130 if (i * sizeof(struct fb_videomode) != count) 131 return -EINVAL; 132 133 console_lock(); 134 lock_fb_info(fb_info); 135 136 list_splice(&fb_info->modelist, &old_list); 137 fb_videomode_to_modelist((const struct fb_videomode *)buf, i, 138 &fb_info->modelist); 139 if (fb_new_modelist(fb_info)) { 140 fb_destroy_modelist(&fb_info->modelist); 141 list_splice(&old_list, &fb_info->modelist); 142 } else { 143 /* 144 * fb_display[i].mode and fb_info->mode both point into the old 145 * list. Clear them before it is freed. 146 */ 147 fbcon_delete_modelist(&old_list); 148 fb_info->mode = NULL; 149 fb_destroy_modelist(&old_list); 150 } 151 152 unlock_fb_info(fb_info); 153 console_unlock(); 154 155 return 0; 156 } 157 158 static ssize_t show_modes(struct device *device, struct device_attribute *attr, 159 char *buf) 160 { 161 struct fb_info *fb_info = dev_get_drvdata(device); 162 unsigned int i; 163 struct fb_modelist *modelist; 164 const struct fb_videomode *mode; 165 166 i = 0; 167 lock_fb_info(fb_info); 168 list_for_each_entry(modelist, &fb_info->modelist, list) { 169 mode = &modelist->mode; 170 i += mode_string(buf, PAGE_SIZE, i, mode); 171 if (i >= PAGE_SIZE - 1) 172 break; 173 } 174 unlock_fb_info(fb_info); 175 176 return i; 177 } 178 179 static ssize_t store_bpp(struct device *device, struct device_attribute *attr, 180 const char *buf, size_t count) 181 { 182 struct fb_info *fb_info = dev_get_drvdata(device); 183 struct fb_var_screeninfo var; 184 char ** last = NULL; 185 int err; 186 187 var = fb_info->var; 188 var.bits_per_pixel = simple_strtoul(buf, last, 0); 189 if ((err = activate(fb_info, &var))) 190 return err; 191 return count; 192 } 193 194 static ssize_t show_bpp(struct device *device, struct device_attribute *attr, 195 char *buf) 196 { 197 struct fb_info *fb_info = dev_get_drvdata(device); 198 return sysfs_emit(buf, "%d\n", fb_info->var.bits_per_pixel); 199 } 200 201 static ssize_t store_rotate(struct device *device, 202 struct device_attribute *attr, 203 const char *buf, size_t count) 204 { 205 struct fb_info *fb_info = dev_get_drvdata(device); 206 struct fb_var_screeninfo var; 207 char **last = NULL; 208 int err; 209 210 var = fb_info->var; 211 var.rotate = simple_strtoul(buf, last, 0); 212 213 if ((err = activate(fb_info, &var))) 214 return err; 215 216 return count; 217 } 218 219 220 static ssize_t show_rotate(struct device *device, 221 struct device_attribute *attr, char *buf) 222 { 223 struct fb_info *fb_info = dev_get_drvdata(device); 224 225 return sysfs_emit(buf, "%d\n", fb_info->var.rotate); 226 } 227 228 static ssize_t store_virtual(struct device *device, 229 struct device_attribute *attr, 230 const char *buf, size_t count) 231 { 232 struct fb_info *fb_info = dev_get_drvdata(device); 233 struct fb_var_screeninfo var; 234 char *last = NULL; 235 int err; 236 237 var = fb_info->var; 238 var.xres_virtual = simple_strtoul(buf, &last, 0); 239 last++; 240 if (last - buf >= count) 241 return -EINVAL; 242 var.yres_virtual = simple_strtoul(last, &last, 0); 243 244 if ((err = activate(fb_info, &var))) 245 return err; 246 return count; 247 } 248 249 static ssize_t show_virtual(struct device *device, 250 struct device_attribute *attr, char *buf) 251 { 252 struct fb_info *fb_info = dev_get_drvdata(device); 253 return sysfs_emit(buf, "%d,%d\n", fb_info->var.xres_virtual, 254 fb_info->var.yres_virtual); 255 } 256 257 static ssize_t show_stride(struct device *device, 258 struct device_attribute *attr, char *buf) 259 { 260 struct fb_info *fb_info = dev_get_drvdata(device); 261 return sysfs_emit(buf, "%d\n", fb_info->fix.line_length); 262 } 263 264 static ssize_t store_blank(struct device *device, 265 struct device_attribute *attr, 266 const char *buf, size_t count) 267 { 268 struct fb_info *fb_info = dev_get_drvdata(device); 269 char *last = NULL; 270 int err, arg; 271 272 arg = simple_strtoul(buf, &last, 0); 273 console_lock(); 274 err = fb_blank_from_user(fb_info, arg); 275 console_unlock(); 276 if (err < 0) 277 return err; 278 return count; 279 } 280 281 static ssize_t show_blank(struct device *device, struct device_attribute *attr, char *buf) 282 { 283 struct fb_info *fb_info = dev_get_drvdata(device); 284 285 return sysfs_emit(buf, "%d\n", fb_info->blank); 286 } 287 288 static ssize_t store_console(struct device *device, 289 struct device_attribute *attr, 290 const char *buf, size_t count) 291 { 292 // struct fb_info *fb_info = dev_get_drvdata(device); 293 return 0; 294 } 295 296 static ssize_t show_console(struct device *device, 297 struct device_attribute *attr, char *buf) 298 { 299 // struct fb_info *fb_info = dev_get_drvdata(device); 300 return 0; 301 } 302 303 static ssize_t store_cursor(struct device *device, 304 struct device_attribute *attr, 305 const char *buf, size_t count) 306 { 307 // struct fb_info *fb_info = dev_get_drvdata(device); 308 return 0; 309 } 310 311 static ssize_t show_cursor(struct device *device, 312 struct device_attribute *attr, char *buf) 313 { 314 // struct fb_info *fb_info = dev_get_drvdata(device); 315 return 0; 316 } 317 318 static ssize_t store_pan(struct device *device, 319 struct device_attribute *attr, 320 const char *buf, size_t count) 321 { 322 struct fb_info *fb_info = dev_get_drvdata(device); 323 struct fb_var_screeninfo var; 324 char *last = NULL; 325 int err; 326 327 var = fb_info->var; 328 var.xoffset = simple_strtoul(buf, &last, 0); 329 last++; 330 if (last - buf >= count) 331 return -EINVAL; 332 var.yoffset = simple_strtoul(last, &last, 0); 333 334 console_lock(); 335 err = fb_pan_display(fb_info, &var); 336 console_unlock(); 337 338 if (err < 0) 339 return err; 340 return count; 341 } 342 343 static ssize_t show_pan(struct device *device, 344 struct device_attribute *attr, char *buf) 345 { 346 struct fb_info *fb_info = dev_get_drvdata(device); 347 return sysfs_emit(buf, "%d,%d\n", fb_info->var.xoffset, 348 fb_info->var.yoffset); 349 } 350 351 static ssize_t show_name(struct device *device, 352 struct device_attribute *attr, char *buf) 353 { 354 struct fb_info *fb_info = dev_get_drvdata(device); 355 356 return sysfs_emit(buf, "%s\n", fb_info->fix.id); 357 } 358 359 static ssize_t store_fbstate(struct device *device, 360 struct device_attribute *attr, 361 const char *buf, size_t count) 362 { 363 struct fb_info *fb_info = dev_get_drvdata(device); 364 u32 state; 365 char *last = NULL; 366 367 state = simple_strtoul(buf, &last, 0); 368 369 console_lock(); 370 lock_fb_info(fb_info); 371 372 fb_set_suspend(fb_info, (int)state); 373 374 unlock_fb_info(fb_info); 375 console_unlock(); 376 377 return count; 378 } 379 380 static ssize_t show_fbstate(struct device *device, 381 struct device_attribute *attr, char *buf) 382 { 383 struct fb_info *fb_info = dev_get_drvdata(device); 384 return sysfs_emit(buf, "%d\n", fb_info->state); 385 } 386 387 #if IS_ENABLED(CONFIG_FB_BACKLIGHT) 388 static ssize_t store_bl_curve(struct device *device, 389 struct device_attribute *attr, 390 const char *buf, size_t count) 391 { 392 struct fb_info *fb_info = dev_get_drvdata(device); 393 u8 tmp_curve[FB_BACKLIGHT_LEVELS]; 394 unsigned int i; 395 396 /* Some drivers don't use framebuffer_alloc(), but those also 397 * don't have backlights. 398 */ 399 if (!fb_info || !fb_info->bl_dev) 400 return -ENODEV; 401 402 if (count != (FB_BACKLIGHT_LEVELS / 8 * 24)) 403 return -EINVAL; 404 405 for (i = 0; i < (FB_BACKLIGHT_LEVELS / 8); ++i) 406 if (sscanf(&buf[i * 24], 407 "%2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx\n", 408 &tmp_curve[i * 8 + 0], 409 &tmp_curve[i * 8 + 1], 410 &tmp_curve[i * 8 + 2], 411 &tmp_curve[i * 8 + 3], 412 &tmp_curve[i * 8 + 4], 413 &tmp_curve[i * 8 + 5], 414 &tmp_curve[i * 8 + 6], 415 &tmp_curve[i * 8 + 7]) != 8) 416 return -EINVAL; 417 418 /* If there has been an error in the input data, we won't 419 * reach this loop. 420 */ 421 mutex_lock(&fb_info->bl_curve_mutex); 422 for (i = 0; i < FB_BACKLIGHT_LEVELS; ++i) 423 fb_info->bl_curve[i] = tmp_curve[i]; 424 mutex_unlock(&fb_info->bl_curve_mutex); 425 426 return count; 427 } 428 429 static ssize_t show_bl_curve(struct device *device, 430 struct device_attribute *attr, char *buf) 431 { 432 struct fb_info *fb_info = dev_get_drvdata(device); 433 ssize_t len = 0; 434 unsigned int i; 435 436 /* Some drivers don't use framebuffer_alloc(), but those also 437 * don't have backlights. 438 */ 439 if (!fb_info || !fb_info->bl_dev) 440 return -ENODEV; 441 442 mutex_lock(&fb_info->bl_curve_mutex); 443 for (i = 0; i < FB_BACKLIGHT_LEVELS; i += 8) 444 len += scnprintf(&buf[len], PAGE_SIZE - len, "%8ph\n", 445 fb_info->bl_curve + i); 446 mutex_unlock(&fb_info->bl_curve_mutex); 447 448 return len; 449 } 450 #endif 451 452 /* When cmap is added back in it should be a binary attribute 453 * not a text one. Consideration should also be given to converting 454 * fbdev to use configfs instead of sysfs */ 455 static DEVICE_ATTR(bits_per_pixel, 0644, show_bpp, store_bpp); 456 static DEVICE_ATTR(blank, 0644, show_blank, store_blank); 457 static DEVICE_ATTR(console, 0644, show_console, store_console); 458 static DEVICE_ATTR(cursor, 0644, show_cursor, store_cursor); 459 static DEVICE_ATTR(mode, 0644, show_mode, store_mode); 460 static DEVICE_ATTR(modes, 0644, show_modes, store_modes); 461 static DEVICE_ATTR(pan, 0644, show_pan, store_pan); 462 static DEVICE_ATTR(virtual_size, 0644, show_virtual, store_virtual); 463 static DEVICE_ATTR(name, 0444, show_name, NULL); 464 static DEVICE_ATTR(stride, 0444, show_stride, NULL); 465 static DEVICE_ATTR(rotate, 0644, show_rotate, store_rotate); 466 static DEVICE_ATTR(state, 0644, show_fbstate, store_fbstate); 467 #if IS_ENABLED(CONFIG_FB_BACKLIGHT) 468 static DEVICE_ATTR(bl_curve, 0644, show_bl_curve, store_bl_curve); 469 #endif 470 471 static struct attribute *fb_device_attrs[] = { 472 &dev_attr_bits_per_pixel.attr, 473 &dev_attr_blank.attr, 474 &dev_attr_console.attr, 475 &dev_attr_cursor.attr, 476 &dev_attr_mode.attr, 477 &dev_attr_modes.attr, 478 &dev_attr_pan.attr, 479 &dev_attr_virtual_size.attr, 480 &dev_attr_name.attr, 481 &dev_attr_stride.attr, 482 &dev_attr_rotate.attr, 483 &dev_attr_state.attr, 484 #if IS_ENABLED(CONFIG_FB_BACKLIGHT) 485 &dev_attr_bl_curve.attr, 486 #endif 487 NULL, 488 }; 489 490 ATTRIBUTE_GROUPS(fb_device); 491 492 int fb_device_create(struct fb_info *fb_info) 493 { 494 int node = fb_info->node; 495 dev_t devt = MKDEV(FB_MAJOR, node); 496 int ret; 497 498 fb_info->dev = device_create_with_groups(fb_class, fb_info->device, devt, fb_info, 499 fb_device_groups, "fb%d", node); 500 if (IS_ERR(fb_info->dev)) { 501 /* Not fatal */ 502 ret = PTR_ERR(fb_info->dev); 503 pr_warn("Unable to create device for framebuffer %d; error %d\n", node, ret); 504 fb_info->dev = NULL; 505 } 506 507 return 0; 508 } 509 510 void fb_device_destroy(struct fb_info *fb_info) 511 { 512 dev_t devt = MKDEV(FB_MAJOR, fb_info->node); 513 514 if (!fb_info->dev) 515 return; 516 517 device_destroy(fb_class, devt); 518 fb_info->dev = NULL; 519 } 520