Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit df43938b authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'fbmem'

* fbmem:
  fbmem: make read/write/ioctl use the frame buffer at open time
  fbcon: add lifetime refcount to opened frame buffers
parents 49f019c1 c47747fd
Loading
Loading
Loading
Loading
+80 −26
Original line number Original line Diff line number Diff line
@@ -42,9 +42,34 @@


#define FBPIXMAPSIZE	(1024 * 8)
#define FBPIXMAPSIZE	(1024 * 8)


static DEFINE_MUTEX(registration_lock);
struct fb_info *registered_fb[FB_MAX] __read_mostly;
struct fb_info *registered_fb[FB_MAX] __read_mostly;
int num_registered_fb __read_mostly;
int num_registered_fb __read_mostly;


static struct fb_info *get_fb_info(unsigned int idx)
{
	struct fb_info *fb_info;

	if (idx >= FB_MAX)
		return ERR_PTR(-ENODEV);

	mutex_lock(&registration_lock);
	fb_info = registered_fb[idx];
	if (fb_info)
		atomic_inc(&fb_info->count);
	mutex_unlock(&registration_lock);

	return fb_info;
}

static void put_fb_info(struct fb_info *fb_info)
{
	if (!atomic_dec_and_test(&fb_info->count))
		return;
	if (fb_info->fbops->fb_destroy)
		fb_info->fbops->fb_destroy(fb_info);
}

int lock_fb_info(struct fb_info *info)
int lock_fb_info(struct fb_info *info)
{
{
	mutex_lock(&info->lock);
	mutex_lock(&info->lock);
@@ -647,6 +672,7 @@ int fb_show_logo(struct fb_info *info, int rotate) { return 0; }


static void *fb_seq_start(struct seq_file *m, loff_t *pos)
static void *fb_seq_start(struct seq_file *m, loff_t *pos)
{
{
	mutex_lock(&registration_lock);
	return (*pos < FB_MAX) ? pos : NULL;
	return (*pos < FB_MAX) ? pos : NULL;
}
}


@@ -658,6 +684,7 @@ static void *fb_seq_next(struct seq_file *m, void *v, loff_t *pos)


static void fb_seq_stop(struct seq_file *m, void *v)
static void fb_seq_stop(struct seq_file *m, void *v)
{
{
	mutex_unlock(&registration_lock);
}
}


static int fb_seq_show(struct seq_file *m, void *v)
static int fb_seq_show(struct seq_file *m, void *v)
@@ -690,13 +717,30 @@ static const struct file_operations fb_proc_fops = {
	.release	= seq_release,
	.release	= seq_release,
};
};


static ssize_t
/*
fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
 * We hold a reference to the fb_info in file->private_data,
 * but if the current registered fb has changed, we don't
 * actually want to use it.
 *
 * So look up the fb_info using the inode minor number,
 * and just verify it against the reference we have.
 */
static struct fb_info *file_fb_info(struct file *file)
{
{
	unsigned long p = *ppos;
	struct inode *inode = file->f_path.dentry->d_inode;
	struct inode *inode = file->f_path.dentry->d_inode;
	int fbidx = iminor(inode);
	int fbidx = iminor(inode);
	struct fb_info *info = registered_fb[fbidx];
	struct fb_info *info = registered_fb[fbidx];

	if (info != file->private_data)
		info = NULL;
	return info;
}

static ssize_t
fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
	unsigned long p = *ppos;
	struct fb_info *info = file_fb_info(file);
	u8 *buffer, *dst;
	u8 *buffer, *dst;
	u8 __iomem *src;
	u8 __iomem *src;
	int c, cnt = 0, err = 0;
	int c, cnt = 0, err = 0;
@@ -761,9 +805,7 @@ static ssize_t
fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
{
	unsigned long p = *ppos;
	unsigned long p = *ppos;
	struct inode *inode = file->f_path.dentry->d_inode;
	struct fb_info *info = file_fb_info(file);
	int fbidx = iminor(inode);
	struct fb_info *info = registered_fb[fbidx];
	u8 *buffer, *src;
	u8 *buffer, *src;
	u8 __iomem *dst;
	u8 __iomem *dst;
	int c, cnt = 0, err = 0;
	int c, cnt = 0, err = 0;
@@ -1141,10 +1183,10 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,


static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
{
	struct inode *inode = file->f_path.dentry->d_inode;
	struct fb_info *info = file_fb_info(file);
	int fbidx = iminor(inode);
	struct fb_info *info = registered_fb[fbidx];


	if (!info)
		return -ENODEV;
	return do_fb_ioctl(info, cmd, arg);
	return do_fb_ioctl(info, cmd, arg);
}
}


@@ -1265,12 +1307,13 @@ static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd,
static long fb_compat_ioctl(struct file *file, unsigned int cmd,
static long fb_compat_ioctl(struct file *file, unsigned int cmd,
			    unsigned long arg)
			    unsigned long arg)
{
{
	struct inode *inode = file->f_path.dentry->d_inode;
	struct fb_info *info = file_fb_info(file);
	int fbidx = iminor(inode);
	struct fb_ops *fb;
	struct fb_info *info = registered_fb[fbidx];
	struct fb_ops *fb = info->fbops;
	long ret = -ENOIOCTLCMD;
	long ret = -ENOIOCTLCMD;


	if (!info)
		return -ENODEV;
	fb = info->fbops;
	switch(cmd) {
	switch(cmd) {
	case FBIOGET_VSCREENINFO:
	case FBIOGET_VSCREENINFO:
	case FBIOPUT_VSCREENINFO:
	case FBIOPUT_VSCREENINFO:
@@ -1303,16 +1346,18 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd,
static int
static int
fb_mmap(struct file *file, struct vm_area_struct * vma)
fb_mmap(struct file *file, struct vm_area_struct * vma)
{
{
	int fbidx = iminor(file->f_path.dentry->d_inode);
	struct fb_info *info = file_fb_info(file);
	struct fb_info *info = registered_fb[fbidx];
	struct fb_ops *fb;
	struct fb_ops *fb = info->fbops;
	unsigned long off;
	unsigned long off;
	unsigned long start;
	unsigned long start;
	u32 len;
	u32 len;


	if (!info)
		return -ENODEV;
	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
		return -EINVAL;
		return -EINVAL;
	off = vma->vm_pgoff << PAGE_SHIFT;
	off = vma->vm_pgoff << PAGE_SHIFT;
	fb = info->fbops;
	if (!fb)
	if (!fb)
		return -ENODEV;
		return -ENODEV;
	mutex_lock(&info->mm_lock);
	mutex_lock(&info->mm_lock);
@@ -1361,14 +1406,16 @@ __releases(&info->lock)
	struct fb_info *info;
	struct fb_info *info;
	int res = 0;
	int res = 0;


	if (fbidx >= FB_MAX)
	info = get_fb_info(fbidx);
		return -ENODEV;
	if (!info) {
	info = registered_fb[fbidx];
	if (!info)
		request_module("fb%d", fbidx);
		request_module("fb%d", fbidx);
	info = registered_fb[fbidx];
		info = get_fb_info(fbidx);
		if (!info)
		if (!info)
			return -ENODEV;
			return -ENODEV;
	}
	if (IS_ERR(info))
		return PTR_ERR(info);

	mutex_lock(&info->lock);
	mutex_lock(&info->lock);
	if (!try_module_get(info->fbops->owner)) {
	if (!try_module_get(info->fbops->owner)) {
		res = -ENODEV;
		res = -ENODEV;
@@ -1386,6 +1433,8 @@ __releases(&info->lock)
#endif
#endif
out:
out:
	mutex_unlock(&info->lock);
	mutex_unlock(&info->lock);
	if (res)
		put_fb_info(info);
	return res;
	return res;
}
}


@@ -1401,6 +1450,7 @@ __releases(&info->lock)
		info->fbops->fb_release(info,1);
		info->fbops->fb_release(info,1);
	module_put(info->fbops->owner);
	module_put(info->fbops->owner);
	mutex_unlock(&info->lock);
	mutex_unlock(&info->lock);
	put_fb_info(info);
	return 0;
	return 0;
}
}


@@ -1542,11 +1592,13 @@ register_framebuffer(struct fb_info *fb_info)
	remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,
	remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,
					 fb_is_primary_device(fb_info));
					 fb_is_primary_device(fb_info));


	mutex_lock(&registration_lock);
	num_registered_fb++;
	num_registered_fb++;
	for (i = 0 ; i < FB_MAX; i++)
	for (i = 0 ; i < FB_MAX; i++)
		if (!registered_fb[i])
		if (!registered_fb[i])
			break;
			break;
	fb_info->node = i;
	fb_info->node = i;
	atomic_set(&fb_info->count, 1);
	mutex_init(&fb_info->lock);
	mutex_init(&fb_info->lock);
	mutex_init(&fb_info->mm_lock);
	mutex_init(&fb_info->mm_lock);


@@ -1583,6 +1635,7 @@ register_framebuffer(struct fb_info *fb_info)
	fb_var_to_videomode(&mode, &fb_info->var);
	fb_var_to_videomode(&mode, &fb_info->var);
	fb_add_videomode(&mode, &fb_info->modelist);
	fb_add_videomode(&mode, &fb_info->modelist);
	registered_fb[i] = fb_info;
	registered_fb[i] = fb_info;
	mutex_unlock(&registration_lock);


	event.info = fb_info;
	event.info = fb_info;
	if (!lock_fb_info(fb_info))
	if (!lock_fb_info(fb_info))
@@ -1616,6 +1669,7 @@ unregister_framebuffer(struct fb_info *fb_info)
	struct fb_event event;
	struct fb_event event;
	int i, ret = 0;
	int i, ret = 0;


	mutex_lock(&registration_lock);
	i = fb_info->node;
	i = fb_info->node;
	if (!registered_fb[i]) {
	if (!registered_fb[i]) {
		ret = -EINVAL;
		ret = -EINVAL;
@@ -1646,9 +1700,9 @@ unregister_framebuffer(struct fb_info *fb_info)
	fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
	fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);


	/* this may free fb info */
	/* this may free fb info */
	if (fb_info->fbops->fb_destroy)
	put_fb_info(fb_info);
		fb_info->fbops->fb_destroy(fb_info);
done:
done:
	mutex_unlock(&registration_lock);
	return ret;
	return ret;
}
}


+1 −0
Original line number Original line Diff line number Diff line
@@ -832,6 +832,7 @@ struct fb_tile_ops {
#define FBINFO_CAN_FORCE_OUTPUT     0x200000
#define FBINFO_CAN_FORCE_OUTPUT     0x200000


struct fb_info {
struct fb_info {
	atomic_t count;
	int node;
	int node;
	int flags;
	int flags;
	struct mutex lock;		/* Lock for open/release/ioctl funcs */
	struct mutex lock;		/* Lock for open/release/ioctl funcs */