1 // SPDX-License-Identifier: GPL-2.0
2
3 #include <linux/fb.h>
4 #include <linux/module.h>
5 #include <linux/uaccess.h>
6
fb_io_read(struct fb_info * info,char __user * buf,size_t count,loff_t * ppos)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
fb_io_write(struct fb_info * info,const char __user * buf,size_t count,loff_t * ppos)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