Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0 2 : 3 : #include <linux/fb.h> 4 : #include <linux/module.h> 5 : #include <linux/uaccess.h> 6 : 7 0 : ssize_t fb_io_read(struct fb_info *info, char __user *buf, size_t count, loff_t *ppos) 8 : { 9 0 : unsigned long p = *ppos; 10 : u8 *buffer, *dst; 11 : u8 __iomem *src; 12 0 : int c, cnt = 0, err = 0; 13 : unsigned long total_size, trailing; 14 : 15 0 : if (!info->screen_base) 16 : return -ENODEV; 17 : 18 0 : total_size = info->screen_size; 19 : 20 0 : if (total_size == 0) 21 0 : total_size = info->fix.smem_len; 22 : 23 0 : if (p >= total_size) 24 : return 0; 25 : 26 0 : if (count >= total_size) 27 0 : count = total_size; 28 : 29 0 : if (count + p > total_size) 30 0 : count = total_size - p; 31 : 32 0 : buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, 33 : GFP_KERNEL); 34 0 : if (!buffer) 35 : return -ENOMEM; 36 : 37 0 : src = (u8 __iomem *) (info->screen_base + p); 38 : 39 0 : if (info->fbops->fb_sync) 40 0 : info->fbops->fb_sync(info); 41 : 42 0 : while (count) { 43 0 : c = (count > PAGE_SIZE) ? PAGE_SIZE : count; 44 0 : dst = buffer; 45 0 : fb_memcpy_fromio(dst, src, c); 46 0 : dst += c; 47 0 : src += c; 48 : 49 0 : trailing = copy_to_user(buf, buffer, c); 50 0 : if (trailing == c) { 51 : err = -EFAULT; 52 : break; 53 : } 54 0 : c -= trailing; 55 : 56 0 : *ppos += c; 57 0 : buf += c; 58 0 : cnt += c; 59 0 : count -= c; 60 : } 61 : 62 0 : kfree(buffer); 63 : 64 0 : return cnt ? cnt : err; 65 : } 66 : EXPORT_SYMBOL(fb_io_read); 67 : 68 0 : ssize_t fb_io_write(struct fb_info *info, const char __user *buf, size_t count, loff_t *ppos) 69 : { 70 0 : unsigned long p = *ppos; 71 : u8 *buffer, *src; 72 : u8 __iomem *dst; 73 0 : int c, cnt = 0, err = 0; 74 : unsigned long total_size, trailing; 75 : 76 0 : if (!info->screen_base) 77 : return -ENODEV; 78 : 79 0 : total_size = info->screen_size; 80 : 81 0 : if (total_size == 0) 82 0 : total_size = info->fix.smem_len; 83 : 84 0 : if (p > total_size) 85 : return -EFBIG; 86 : 87 0 : if (count > total_size) { 88 0 : err = -EFBIG; 89 0 : count = total_size; 90 : } 91 : 92 0 : if (count + p > total_size) { 93 0 : if (!err) 94 0 : err = -ENOSPC; 95 : 96 0 : count = total_size - p; 97 : } 98 : 99 0 : buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, 100 : GFP_KERNEL); 101 0 : if (!buffer) 102 : return -ENOMEM; 103 : 104 0 : dst = (u8 __iomem *) (info->screen_base + p); 105 : 106 0 : if (info->fbops->fb_sync) 107 0 : info->fbops->fb_sync(info); 108 : 109 0 : while (count) { 110 0 : c = (count > PAGE_SIZE) ? PAGE_SIZE : count; 111 0 : src = buffer; 112 : 113 0 : trailing = copy_from_user(src, buf, c); 114 0 : if (trailing == c) { 115 : err = -EFAULT; 116 : break; 117 : } 118 0 : c -= trailing; 119 : 120 0 : fb_memcpy_toio(dst, src, c); 121 0 : dst += c; 122 0 : src += c; 123 0 : *ppos += c; 124 0 : buf += c; 125 0 : cnt += c; 126 0 : count -= c; 127 : } 128 : 129 0 : kfree(buffer); 130 : 131 0 : return (cnt) ? cnt : err; 132 : } 133 : EXPORT_SYMBOL(fb_io_write);