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