cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fbsysfs.c (14238B)


      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/*
      9 * Note:  currently there's only stubs for framebuffer_alloc and
     10 * framebuffer_release here.  The reson for that is that until all drivers
     11 * are converted to use it a sysfsification will open OOPSable races.
     12 */
     13
     14#include <linux/kernel.h>
     15#include <linux/slab.h>
     16#include <linux/fb.h>
     17#include <linux/fbcon.h>
     18#include <linux/console.h>
     19#include <linux/module.h>
     20
     21#define FB_SYSFS_FLAG_ATTR 1
     22
     23/**
     24 * framebuffer_alloc - creates a new frame buffer info structure
     25 *
     26 * @size: size of driver private data, can be zero
     27 * @dev: pointer to the device for this fb, this can be NULL
     28 *
     29 * Creates a new frame buffer info structure. Also reserves @size bytes
     30 * for driver private data (info->par). info->par (if any) will be
     31 * aligned to sizeof(long).
     32 *
     33 * Returns the new structure, or NULL if an error occurred.
     34 *
     35 */
     36struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
     37{
     38#define BYTES_PER_LONG (BITS_PER_LONG/8)
     39#define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG))
     40	int fb_info_size = sizeof(struct fb_info);
     41	struct fb_info *info;
     42	char *p;
     43
     44	if (size)
     45		fb_info_size += PADDING;
     46
     47	p = kzalloc(fb_info_size + size, GFP_KERNEL);
     48
     49	if (!p)
     50		return NULL;
     51
     52	info = (struct fb_info *) p;
     53
     54	if (size)
     55		info->par = p + fb_info_size;
     56
     57	info->device = dev;
     58	info->fbcon_rotate_hint = -1;
     59
     60#if IS_ENABLED(CONFIG_FB_BACKLIGHT)
     61	mutex_init(&info->bl_curve_mutex);
     62#endif
     63
     64	return info;
     65#undef PADDING
     66#undef BYTES_PER_LONG
     67}
     68EXPORT_SYMBOL(framebuffer_alloc);
     69
     70/**
     71 * framebuffer_release - marks the structure available for freeing
     72 *
     73 * @info: frame buffer info structure
     74 *
     75 * Drop the reference count of the device embedded in the
     76 * framebuffer info structure.
     77 *
     78 */
     79void framebuffer_release(struct fb_info *info)
     80{
     81	if (!info)
     82		return;
     83
     84	if (WARN_ON(refcount_read(&info->count)))
     85		return;
     86
     87	kfree(info->apertures);
     88	kfree(info);
     89}
     90EXPORT_SYMBOL(framebuffer_release);
     91
     92static int activate(struct fb_info *fb_info, struct fb_var_screeninfo *var)
     93{
     94	int err;
     95
     96	var->activate |= FB_ACTIVATE_FORCE;
     97	console_lock();
     98	lock_fb_info(fb_info);
     99	err = fb_set_var(fb_info, var);
    100	if (!err)
    101		fbcon_update_vcs(fb_info, var->activate & FB_ACTIVATE_ALL);
    102	unlock_fb_info(fb_info);
    103	console_unlock();
    104	if (err)
    105		return err;
    106	return 0;
    107}
    108
    109static int mode_string(char *buf, unsigned int offset,
    110		       const struct fb_videomode *mode)
    111{
    112	char m = 'U';
    113	char v = 'p';
    114
    115	if (mode->flag & FB_MODE_IS_DETAILED)
    116		m = 'D';
    117	if (mode->flag & FB_MODE_IS_VESA)
    118		m = 'V';
    119	if (mode->flag & FB_MODE_IS_STANDARD)
    120		m = 'S';
    121
    122	if (mode->vmode & FB_VMODE_INTERLACED)
    123		v = 'i';
    124	if (mode->vmode & FB_VMODE_DOUBLE)
    125		v = 'd';
    126
    127	return snprintf(&buf[offset], PAGE_SIZE - offset, "%c:%dx%d%c-%d\n",
    128	                m, mode->xres, mode->yres, v, mode->refresh);
    129}
    130
    131static ssize_t store_mode(struct device *device, struct device_attribute *attr,
    132			  const char *buf, size_t count)
    133{
    134	struct fb_info *fb_info = dev_get_drvdata(device);
    135	char mstr[100];
    136	struct fb_var_screeninfo var;
    137	struct fb_modelist *modelist;
    138	struct fb_videomode *mode;
    139	struct list_head *pos;
    140	size_t i;
    141	int err;
    142
    143	memset(&var, 0, sizeof(var));
    144
    145	list_for_each(pos, &fb_info->modelist) {
    146		modelist = list_entry(pos, struct fb_modelist, list);
    147		mode = &modelist->mode;
    148		i = mode_string(mstr, 0, mode);
    149		if (strncmp(mstr, buf, max(count, i)) == 0) {
    150
    151			var = fb_info->var;
    152			fb_videomode_to_var(&var, mode);
    153			if ((err = activate(fb_info, &var)))
    154				return err;
    155			fb_info->mode = mode;
    156			return count;
    157		}
    158	}
    159	return -EINVAL;
    160}
    161
    162static ssize_t show_mode(struct device *device, struct device_attribute *attr,
    163			 char *buf)
    164{
    165	struct fb_info *fb_info = dev_get_drvdata(device);
    166
    167	if (!fb_info->mode)
    168		return 0;
    169
    170	return mode_string(buf, 0, fb_info->mode);
    171}
    172
    173static ssize_t store_modes(struct device *device,
    174			   struct device_attribute *attr,
    175			   const char *buf, size_t count)
    176{
    177	struct fb_info *fb_info = dev_get_drvdata(device);
    178	LIST_HEAD(old_list);
    179	int i = count / sizeof(struct fb_videomode);
    180
    181	if (i * sizeof(struct fb_videomode) != count)
    182		return -EINVAL;
    183
    184	console_lock();
    185	lock_fb_info(fb_info);
    186
    187	list_splice(&fb_info->modelist, &old_list);
    188	fb_videomode_to_modelist((const struct fb_videomode *)buf, i,
    189				 &fb_info->modelist);
    190	if (fb_new_modelist(fb_info)) {
    191		fb_destroy_modelist(&fb_info->modelist);
    192		list_splice(&old_list, &fb_info->modelist);
    193	} else
    194		fb_destroy_modelist(&old_list);
    195
    196	unlock_fb_info(fb_info);
    197	console_unlock();
    198
    199	return 0;
    200}
    201
    202static ssize_t show_modes(struct device *device, struct device_attribute *attr,
    203			  char *buf)
    204{
    205	struct fb_info *fb_info = dev_get_drvdata(device);
    206	unsigned int i;
    207	struct list_head *pos;
    208	struct fb_modelist *modelist;
    209	const struct fb_videomode *mode;
    210
    211	i = 0;
    212	list_for_each(pos, &fb_info->modelist) {
    213		modelist = list_entry(pos, struct fb_modelist, list);
    214		mode = &modelist->mode;
    215		i += mode_string(buf, i, mode);
    216	}
    217	return i;
    218}
    219
    220static ssize_t store_bpp(struct device *device, struct device_attribute *attr,
    221			 const char *buf, size_t count)
    222{
    223	struct fb_info *fb_info = dev_get_drvdata(device);
    224	struct fb_var_screeninfo var;
    225	char ** last = NULL;
    226	int err;
    227
    228	var = fb_info->var;
    229	var.bits_per_pixel = simple_strtoul(buf, last, 0);
    230	if ((err = activate(fb_info, &var)))
    231		return err;
    232	return count;
    233}
    234
    235static ssize_t show_bpp(struct device *device, struct device_attribute *attr,
    236			char *buf)
    237{
    238	struct fb_info *fb_info = dev_get_drvdata(device);
    239	return sysfs_emit(buf, "%d\n", fb_info->var.bits_per_pixel);
    240}
    241
    242static ssize_t store_rotate(struct device *device,
    243			    struct device_attribute *attr,
    244			    const char *buf, size_t count)
    245{
    246	struct fb_info *fb_info = dev_get_drvdata(device);
    247	struct fb_var_screeninfo var;
    248	char **last = NULL;
    249	int err;
    250
    251	var = fb_info->var;
    252	var.rotate = simple_strtoul(buf, last, 0);
    253
    254	if ((err = activate(fb_info, &var)))
    255		return err;
    256
    257	return count;
    258}
    259
    260
    261static ssize_t show_rotate(struct device *device,
    262			   struct device_attribute *attr, char *buf)
    263{
    264	struct fb_info *fb_info = dev_get_drvdata(device);
    265
    266	return sysfs_emit(buf, "%d\n", fb_info->var.rotate);
    267}
    268
    269static ssize_t store_virtual(struct device *device,
    270			     struct device_attribute *attr,
    271			     const char *buf, size_t count)
    272{
    273	struct fb_info *fb_info = dev_get_drvdata(device);
    274	struct fb_var_screeninfo var;
    275	char *last = NULL;
    276	int err;
    277
    278	var = fb_info->var;
    279	var.xres_virtual = simple_strtoul(buf, &last, 0);
    280	last++;
    281	if (last - buf >= count)
    282		return -EINVAL;
    283	var.yres_virtual = simple_strtoul(last, &last, 0);
    284
    285	if ((err = activate(fb_info, &var)))
    286		return err;
    287	return count;
    288}
    289
    290static ssize_t show_virtual(struct device *device,
    291			    struct device_attribute *attr, char *buf)
    292{
    293	struct fb_info *fb_info = dev_get_drvdata(device);
    294	return sysfs_emit(buf, "%d,%d\n", fb_info->var.xres_virtual,
    295			fb_info->var.yres_virtual);
    296}
    297
    298static ssize_t show_stride(struct device *device,
    299			   struct device_attribute *attr, char *buf)
    300{
    301	struct fb_info *fb_info = dev_get_drvdata(device);
    302	return sysfs_emit(buf, "%d\n", fb_info->fix.line_length);
    303}
    304
    305static ssize_t store_blank(struct device *device,
    306			   struct device_attribute *attr,
    307			   const char *buf, size_t count)
    308{
    309	struct fb_info *fb_info = dev_get_drvdata(device);
    310	char *last = NULL;
    311	int err, arg;
    312
    313	arg = simple_strtoul(buf, &last, 0);
    314	console_lock();
    315	err = fb_blank(fb_info, arg);
    316	/* might again call into fb_blank */
    317	fbcon_fb_blanked(fb_info, arg);
    318	console_unlock();
    319	if (err < 0)
    320		return err;
    321	return count;
    322}
    323
    324static ssize_t show_blank(struct device *device,
    325			  struct device_attribute *attr, char *buf)
    326{
    327//	struct fb_info *fb_info = dev_get_drvdata(device);
    328	return 0;
    329}
    330
    331static ssize_t store_console(struct device *device,
    332			     struct device_attribute *attr,
    333			     const char *buf, size_t count)
    334{
    335//	struct fb_info *fb_info = dev_get_drvdata(device);
    336	return 0;
    337}
    338
    339static ssize_t show_console(struct device *device,
    340			    struct device_attribute *attr, char *buf)
    341{
    342//	struct fb_info *fb_info = dev_get_drvdata(device);
    343	return 0;
    344}
    345
    346static ssize_t store_cursor(struct device *device,
    347			    struct device_attribute *attr,
    348			    const char *buf, size_t count)
    349{
    350//	struct fb_info *fb_info = dev_get_drvdata(device);
    351	return 0;
    352}
    353
    354static ssize_t show_cursor(struct device *device,
    355			   struct device_attribute *attr, char *buf)
    356{
    357//	struct fb_info *fb_info = dev_get_drvdata(device);
    358	return 0;
    359}
    360
    361static ssize_t store_pan(struct device *device,
    362			 struct device_attribute *attr,
    363			 const char *buf, size_t count)
    364{
    365	struct fb_info *fb_info = dev_get_drvdata(device);
    366	struct fb_var_screeninfo var;
    367	char *last = NULL;
    368	int err;
    369
    370	var = fb_info->var;
    371	var.xoffset = simple_strtoul(buf, &last, 0);
    372	last++;
    373	if (last - buf >= count)
    374		return -EINVAL;
    375	var.yoffset = simple_strtoul(last, &last, 0);
    376
    377	console_lock();
    378	err = fb_pan_display(fb_info, &var);
    379	console_unlock();
    380
    381	if (err < 0)
    382		return err;
    383	return count;
    384}
    385
    386static ssize_t show_pan(struct device *device,
    387			struct device_attribute *attr, char *buf)
    388{
    389	struct fb_info *fb_info = dev_get_drvdata(device);
    390	return sysfs_emit(buf, "%d,%d\n", fb_info->var.xoffset,
    391			fb_info->var.yoffset);
    392}
    393
    394static ssize_t show_name(struct device *device,
    395			 struct device_attribute *attr, char *buf)
    396{
    397	struct fb_info *fb_info = dev_get_drvdata(device);
    398
    399	return sysfs_emit(buf, "%s\n", fb_info->fix.id);
    400}
    401
    402static ssize_t store_fbstate(struct device *device,
    403			     struct device_attribute *attr,
    404			     const char *buf, size_t count)
    405{
    406	struct fb_info *fb_info = dev_get_drvdata(device);
    407	u32 state;
    408	char *last = NULL;
    409
    410	state = simple_strtoul(buf, &last, 0);
    411
    412	console_lock();
    413	lock_fb_info(fb_info);
    414
    415	fb_set_suspend(fb_info, (int)state);
    416
    417	unlock_fb_info(fb_info);
    418	console_unlock();
    419
    420	return count;
    421}
    422
    423static ssize_t show_fbstate(struct device *device,
    424			    struct device_attribute *attr, char *buf)
    425{
    426	struct fb_info *fb_info = dev_get_drvdata(device);
    427	return sysfs_emit(buf, "%d\n", fb_info->state);
    428}
    429
    430#if IS_ENABLED(CONFIG_FB_BACKLIGHT)
    431static ssize_t store_bl_curve(struct device *device,
    432			      struct device_attribute *attr,
    433			      const char *buf, size_t count)
    434{
    435	struct fb_info *fb_info = dev_get_drvdata(device);
    436	u8 tmp_curve[FB_BACKLIGHT_LEVELS];
    437	unsigned int i;
    438
    439	/* Some drivers don't use framebuffer_alloc(), but those also
    440	 * don't have backlights.
    441	 */
    442	if (!fb_info || !fb_info->bl_dev)
    443		return -ENODEV;
    444
    445	if (count != (FB_BACKLIGHT_LEVELS / 8 * 24))
    446		return -EINVAL;
    447
    448	for (i = 0; i < (FB_BACKLIGHT_LEVELS / 8); ++i)
    449		if (sscanf(&buf[i * 24],
    450			"%2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx\n",
    451			&tmp_curve[i * 8 + 0],
    452			&tmp_curve[i * 8 + 1],
    453			&tmp_curve[i * 8 + 2],
    454			&tmp_curve[i * 8 + 3],
    455			&tmp_curve[i * 8 + 4],
    456			&tmp_curve[i * 8 + 5],
    457			&tmp_curve[i * 8 + 6],
    458			&tmp_curve[i * 8 + 7]) != 8)
    459			return -EINVAL;
    460
    461	/* If there has been an error in the input data, we won't
    462	 * reach this loop.
    463	 */
    464	mutex_lock(&fb_info->bl_curve_mutex);
    465	for (i = 0; i < FB_BACKLIGHT_LEVELS; ++i)
    466		fb_info->bl_curve[i] = tmp_curve[i];
    467	mutex_unlock(&fb_info->bl_curve_mutex);
    468
    469	return count;
    470}
    471
    472static ssize_t show_bl_curve(struct device *device,
    473			     struct device_attribute *attr, char *buf)
    474{
    475	struct fb_info *fb_info = dev_get_drvdata(device);
    476	ssize_t len = 0;
    477	unsigned int i;
    478
    479	/* Some drivers don't use framebuffer_alloc(), but those also
    480	 * don't have backlights.
    481	 */
    482	if (!fb_info || !fb_info->bl_dev)
    483		return -ENODEV;
    484
    485	mutex_lock(&fb_info->bl_curve_mutex);
    486	for (i = 0; i < FB_BACKLIGHT_LEVELS; i += 8)
    487		len += scnprintf(&buf[len], PAGE_SIZE - len, "%8ph\n",
    488				fb_info->bl_curve + i);
    489	mutex_unlock(&fb_info->bl_curve_mutex);
    490
    491	return len;
    492}
    493#endif
    494
    495/* When cmap is added back in it should be a binary attribute
    496 * not a text one. Consideration should also be given to converting
    497 * fbdev to use configfs instead of sysfs */
    498static struct device_attribute device_attrs[] = {
    499	__ATTR(bits_per_pixel, S_IRUGO|S_IWUSR, show_bpp, store_bpp),
    500	__ATTR(blank, S_IRUGO|S_IWUSR, show_blank, store_blank),
    501	__ATTR(console, S_IRUGO|S_IWUSR, show_console, store_console),
    502	__ATTR(cursor, S_IRUGO|S_IWUSR, show_cursor, store_cursor),
    503	__ATTR(mode, S_IRUGO|S_IWUSR, show_mode, store_mode),
    504	__ATTR(modes, S_IRUGO|S_IWUSR, show_modes, store_modes),
    505	__ATTR(pan, S_IRUGO|S_IWUSR, show_pan, store_pan),
    506	__ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual),
    507	__ATTR(name, S_IRUGO, show_name, NULL),
    508	__ATTR(stride, S_IRUGO, show_stride, NULL),
    509	__ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate),
    510	__ATTR(state, S_IRUGO|S_IWUSR, show_fbstate, store_fbstate),
    511#if IS_ENABLED(CONFIG_FB_BACKLIGHT)
    512	__ATTR(bl_curve, S_IRUGO|S_IWUSR, show_bl_curve, store_bl_curve),
    513#endif
    514};
    515
    516int fb_init_device(struct fb_info *fb_info)
    517{
    518	int i, error = 0;
    519
    520	dev_set_drvdata(fb_info->dev, fb_info);
    521
    522	fb_info->class_flag |= FB_SYSFS_FLAG_ATTR;
    523
    524	for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
    525		error = device_create_file(fb_info->dev, &device_attrs[i]);
    526
    527		if (error)
    528			break;
    529	}
    530
    531	if (error) {
    532		while (--i >= 0)
    533			device_remove_file(fb_info->dev, &device_attrs[i]);
    534		fb_info->class_flag &= ~FB_SYSFS_FLAG_ATTR;
    535	}
    536
    537	return 0;
    538}
    539
    540void fb_cleanup_device(struct fb_info *fb_info)
    541{
    542	unsigned int i;
    543
    544	if (fb_info->class_flag & FB_SYSFS_FLAG_ATTR) {
    545		for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
    546			device_remove_file(fb_info->dev, &device_attrs[i]);
    547
    548		fb_info->class_flag &= ~FB_SYSFS_FLAG_ATTR;
    549	}
    550}
    551
    552#if IS_ENABLED(CONFIG_FB_BACKLIGHT)
    553/* This function generates a linear backlight curve
    554 *
    555 *     0: off
    556 *   1-7: min
    557 * 8-127: linear from min to max
    558 */
    559void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max)
    560{
    561	unsigned int i, flat, count, range = (max - min);
    562
    563	mutex_lock(&fb_info->bl_curve_mutex);
    564
    565	fb_info->bl_curve[0] = off;
    566
    567	for (flat = 1; flat < (FB_BACKLIGHT_LEVELS / 16); ++flat)
    568		fb_info->bl_curve[flat] = min;
    569
    570	count = FB_BACKLIGHT_LEVELS * 15 / 16;
    571	for (i = 0; i < count; ++i)
    572		fb_info->bl_curve[flat + i] = min + (range * (i + 1) / count);
    573
    574	mutex_unlock(&fb_info->bl_curve_mutex);
    575}
    576EXPORT_SYMBOL_GPL(fb_bl_default_curve);
    577#endif