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