Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 481 lines 12 kB view raw
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 15static 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 32static 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 54static 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 83static 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 94static 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 123static 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 139static 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 154static 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 161static 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 180static 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 188static 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 209static 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 217static 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 224static 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 243static 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 250static 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 258static 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 265static 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 273static 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 280static 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 305static 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 313static 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 321static 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 342static 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) 350static 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 391static 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 */ 417static DEVICE_ATTR(bits_per_pixel, 0644, show_bpp, store_bpp); 418static DEVICE_ATTR(blank, 0644, show_blank, store_blank); 419static DEVICE_ATTR(console, 0644, show_console, store_console); 420static DEVICE_ATTR(cursor, 0644, show_cursor, store_cursor); 421static DEVICE_ATTR(mode, 0644, show_mode, store_mode); 422static DEVICE_ATTR(modes, 0644, show_modes, store_modes); 423static DEVICE_ATTR(pan, 0644, show_pan, store_pan); 424static DEVICE_ATTR(virtual_size, 0644, show_virtual, store_virtual); 425static DEVICE_ATTR(name, 0444, show_name, NULL); 426static DEVICE_ATTR(stride, 0444, show_stride, NULL); 427static DEVICE_ATTR(rotate, 0644, show_rotate, store_rotate); 428static DEVICE_ATTR(state, 0644, show_fbstate, store_fbstate); 429#if IS_ENABLED(CONFIG_FB_BACKLIGHT) 430static DEVICE_ATTR(bl_curve, 0644, show_bl_curve, store_bl_curve); 431#endif 432 433static 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 452ATTRIBUTE_GROUPS(fb_device); 453 454int 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 472void 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}