1// SPDX-License-Identifier: GPL-2.0-or-later
2
3#include <linux/export.h>
4#include <linux/fb.h>
5#include <linux/mutex.h>
6#include <linux/slab.h>
7
8/**
9 * framebuffer_alloc - creates a new frame buffer info structure
10 *
11 * @size: size of driver private data, can be zero
12 * @dev: pointer to the device for this fb, this can be NULL
13 *
14 * Creates a new frame buffer info structure. Also reserves @size bytes
15 * for driver private data (info->par). info->par (if any) will be
16 * aligned to sizeof(long). The new instances of struct fb_info and
17 * the driver private data are both cleared to zero.
18 *
19 * Returns the new structure, or NULL if an error occurred.
20 *
21 */
22struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
23{
24#define BYTES_PER_LONG (BITS_PER_LONG/8)
25#define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG))
26	int fb_info_size = sizeof(struct fb_info);
27	struct fb_info *info;
28	char *p;
29
30	if (size)
31		fb_info_size += PADDING;
32
33	p = kzalloc(fb_info_size + size, GFP_KERNEL);
34
35	if (!p)
36		return NULL;
37
38	info = (struct fb_info *) p;
39
40	if (size)
41		info->par = p + fb_info_size;
42
43	info->device = dev;
44	info->fbcon_rotate_hint = -1;
45
46#if IS_ENABLED(CONFIG_FB_BACKLIGHT)
47	mutex_init(&info->bl_curve_mutex);
48#endif
49
50	return info;
51#undef PADDING
52#undef BYTES_PER_LONG
53}
54EXPORT_SYMBOL(framebuffer_alloc);
55
56/**
57 * framebuffer_release - marks the structure available for freeing
58 *
59 * @info: frame buffer info structure
60 *
61 * Drop the reference count of the device embedded in the
62 * framebuffer info structure.
63 *
64 */
65void framebuffer_release(struct fb_info *info)
66{
67	if (!info)
68		return;
69
70	if (WARN_ON(refcount_read(&info->count)))
71		return;
72
73#if IS_ENABLED(CONFIG_FB_BACKLIGHT)
74	mutex_destroy(&info->bl_curve_mutex);
75#endif
76
77	kfree(info);
78}
79EXPORT_SYMBOL(framebuffer_release);
80