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