brintos

brintos / linux-shallow public Read only

0
0
Text · 3.4 KiB · 3408ff1 Raw
173 lines · c
1// SPDX-License-Identifier: GPL-2.02 3#include <linux/fb.h>4#include <linux/module.h>5#include <linux/uaccess.h>6 7ssize_t fb_io_read(struct fb_info *info, char __user *buf, size_t count, loff_t *ppos)8{9	unsigned long p = *ppos;10	u8 *buffer, *dst;11	u8 __iomem *src;12	int c, cnt = 0, err = 0;13	unsigned long total_size, trailing;14 15	if (info->flags & FBINFO_VIRTFB)16		fb_warn_once(info, "Framebuffer is not in I/O address space.");17 18	if (!info->screen_base)19		return -ENODEV;20 21	total_size = info->screen_size;22 23	if (total_size == 0)24		total_size = info->fix.smem_len;25 26	if (p >= total_size)27		return 0;28 29	if (count >= total_size)30		count = total_size;31 32	if (count + p > total_size)33		count = total_size - p;34 35	buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,36			 GFP_KERNEL);37	if (!buffer)38		return -ENOMEM;39 40	src = (u8 __iomem *) (info->screen_base + p);41 42	if (info->fbops->fb_sync)43		info->fbops->fb_sync(info);44 45	while (count) {46		c  = (count > PAGE_SIZE) ? PAGE_SIZE : count;47		dst = buffer;48		fb_memcpy_fromio(dst, src, c);49		dst += c;50		src += c;51 52		trailing = copy_to_user(buf, buffer, c);53		if (trailing == c) {54			err = -EFAULT;55			break;56		}57		c -= trailing;58 59		*ppos += c;60		buf += c;61		cnt += c;62		count -= c;63	}64 65	kfree(buffer);66 67	return cnt ? cnt : err;68}69EXPORT_SYMBOL(fb_io_read);70 71ssize_t fb_io_write(struct fb_info *info, const char __user *buf, size_t count, loff_t *ppos)72{73	unsigned long p = *ppos;74	u8 *buffer, *src;75	u8 __iomem *dst;76	int c, cnt = 0, err = 0;77	unsigned long total_size, trailing;78 79	if (info->flags & FBINFO_VIRTFB)80		fb_warn_once(info, "Framebuffer is not in I/O address space.");81 82	if (!info->screen_base)83		return -ENODEV;84 85	total_size = info->screen_size;86 87	if (total_size == 0)88		total_size = info->fix.smem_len;89 90	if (p > total_size)91		return -EFBIG;92 93	if (count > total_size) {94		err = -EFBIG;95		count = total_size;96	}97 98	if (count + p > total_size) {99		if (!err)100			err = -ENOSPC;101 102		count = total_size - p;103	}104 105	buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,106			 GFP_KERNEL);107	if (!buffer)108		return -ENOMEM;109 110	dst = (u8 __iomem *) (info->screen_base + p);111 112	if (info->fbops->fb_sync)113		info->fbops->fb_sync(info);114 115	while (count) {116		c = (count > PAGE_SIZE) ? PAGE_SIZE : count;117		src = buffer;118 119		trailing = copy_from_user(src, buf, c);120		if (trailing == c) {121			err = -EFAULT;122			break;123		}124		c -= trailing;125 126		fb_memcpy_toio(dst, src, c);127		dst += c;128		src += c;129		*ppos += c;130		buf += c;131		cnt += c;132		count -= c;133	}134 135	kfree(buffer);136 137	return (cnt) ? cnt : err;138}139EXPORT_SYMBOL(fb_io_write);140 141int fb_io_mmap(struct fb_info *info, struct vm_area_struct *vma)142{143	unsigned long start = info->fix.smem_start;144	u32 len = info->fix.smem_len;145	unsigned long mmio_pgoff = PAGE_ALIGN((start & ~PAGE_MASK) + len) >> PAGE_SHIFT;146 147	if (info->flags & FBINFO_VIRTFB)148		fb_warn_once(info, "Framebuffer is not in I/O address space.");149 150	/*151	 * This can be either the framebuffer mapping, or if pgoff points152	 * past it, the mmio mapping.153	 */154	if (vma->vm_pgoff >= mmio_pgoff) {155		if (info->var.accel_flags)156			return -EINVAL;157 158		vma->vm_pgoff -= mmio_pgoff;159		start = info->fix.mmio_start;160		len = info->fix.mmio_len;161	}162 163	vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);164	vma->vm_page_prot = pgprot_framebuffer(vma->vm_page_prot, vma->vm_start,165					       vma->vm_end, start);166 167	return vm_iomap_memory(vma, start, len);168}169EXPORT_SYMBOL(fb_io_mmap);170 171MODULE_DESCRIPTION("Fbdev helpers for framebuffers in I/O memory");172MODULE_LICENSE("GPL");173