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