1 // SPDX-License-Identifier: GPL-2.0
2 /* sbuslib.c: Helper library for SBUS framebuffer drivers.
4 * Copyright (C) 2003 David S. Miller (davem@redhat.com)
7 #include <linux/compat.h>
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/string.h>
13 #include <linux/uaccess.h>
20 void sbusfb_fill_var(struct fb_var_screeninfo
*var
, struct device_node
*dp
,
23 memset(var
, 0, sizeof(*var
));
25 var
->xres
= of_getintprop_default(dp
, "width", 1152);
26 var
->yres
= of_getintprop_default(dp
, "height", 900);
27 var
->xres_virtual
= var
->xres
;
28 var
->yres_virtual
= var
->yres
;
29 var
->bits_per_pixel
= bpp
;
32 EXPORT_SYMBOL(sbusfb_fill_var
);
34 static unsigned long sbusfb_mmapsize(long size
, unsigned long fbsize
)
36 if (size
== SBUS_MMAP_EMPTY
) return 0;
37 if (size
>= 0) return size
;
38 return fbsize
* (-size
);
41 int sbusfb_mmap_helper(const struct sbus_mmap_map
*map
,
42 unsigned long physbase
,
44 unsigned long iospace
,
45 struct vm_area_struct
*vma
)
47 unsigned int size
, page
, r
, map_size
;
48 unsigned long map_offset
= 0;
52 if (!(vma
->vm_flags
& (VM_SHARED
| VM_MAYSHARE
)))
55 size
= vma
->vm_end
- vma
->vm_start
;
56 if (vma
->vm_pgoff
> (~0UL >> PAGE_SHIFT
))
59 off
= vma
->vm_pgoff
<< PAGE_SHIFT
;
61 /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */
63 vma
->vm_page_prot
= pgprot_decrypted(vma
->vm_page_prot
);
64 vma
->vm_page_prot
= pgprot_noncached(vma
->vm_page_prot
);
66 /* Each page, see which map applies */
67 for (page
= 0; page
< size
; ){
69 for (i
= 0; map
[i
].size
; i
++)
70 if (map
[i
].voff
== off
+page
) {
71 map_size
= sbusfb_mmapsize(map
[i
].size
, fbsize
);
73 #define POFF_MASK (PAGE_MASK|0x1UL)
75 #define POFF_MASK (PAGE_MASK)
77 map_offset
= (physbase
+ map
[i
].poff
) & POFF_MASK
;
84 if (page
+ map_size
> size
)
85 map_size
= size
- page
;
86 r
= io_remap_pfn_range(vma
,
88 MK_IOSPACE_PFN(iospace
,
89 map_offset
>> PAGE_SHIFT
),
99 EXPORT_SYMBOL(sbusfb_mmap_helper
);
101 int sbusfb_ioctl_helper(unsigned long cmd
, unsigned long arg
,
102 struct fb_info
*info
,
103 int type
, int fb_depth
, unsigned long fb_size
)
107 struct fbtype __user
*f
= (struct fbtype __user
*) arg
;
109 if (put_user(type
, &f
->fb_type
) ||
110 put_user(info
->var
.yres
, &f
->fb_height
) ||
111 put_user(info
->var
.xres
, &f
->fb_width
) ||
112 put_user(fb_depth
, &f
->fb_depth
) ||
113 put_user(0, &f
->fb_cmsize
) ||
114 put_user(fb_size
, &f
->fb_cmsize
))
118 case FBIOPUTCMAP_SPARC
: {
119 struct fbcmap __user
*c
= (struct fbcmap __user
*) arg
;
121 u16 red
, green
, blue
;
122 u8 red8
, green8
, blue8
;
123 unsigned char __user
*ured
;
124 unsigned char __user
*ugreen
;
125 unsigned char __user
*ublue
;
126 unsigned int index
, count
, i
;
128 if (get_user(index
, &c
->index
) ||
129 get_user(count
, &c
->count
) ||
130 get_user(ured
, &c
->red
) ||
131 get_user(ugreen
, &c
->green
) ||
132 get_user(ublue
, &c
->blue
))
140 for (i
= 0; i
< count
; i
++) {
143 if (get_user(red8
, &ured
[i
]) ||
144 get_user(green8
, &ugreen
[i
]) ||
145 get_user(blue8
, &ublue
[i
]))
152 cmap
.start
= index
+ i
;
153 err
= fb_set_cmap(&cmap
, info
);
159 case FBIOGETCMAP_SPARC
: {
160 struct fbcmap __user
*c
= (struct fbcmap __user
*) arg
;
161 unsigned char __user
*ured
;
162 unsigned char __user
*ugreen
;
163 unsigned char __user
*ublue
;
164 struct fb_cmap
*cmap
= &info
->cmap
;
165 unsigned int index
, count
, i
;
168 if (get_user(index
, &c
->index
) ||
169 get_user(count
, &c
->count
) ||
170 get_user(ured
, &c
->red
) ||
171 get_user(ugreen
, &c
->green
) ||
172 get_user(ublue
, &c
->blue
))
175 if (index
> cmap
->len
|| count
> cmap
->len
- index
)
178 for (i
= 0; i
< count
; i
++) {
179 red
= cmap
->red
[index
+ i
] >> 8;
180 green
= cmap
->green
[index
+ i
] >> 8;
181 blue
= cmap
->blue
[index
+ i
] >> 8;
182 if (put_user(red
, &ured
[i
]) ||
183 put_user(green
, &ugreen
[i
]) ||
184 put_user(blue
, &ublue
[i
]))
193 EXPORT_SYMBOL(sbusfb_ioctl_helper
);
196 int sbusfb_compat_ioctl(struct fb_info
*info
, unsigned int cmd
, unsigned long arg
)
205 case FBIOGCURSOR32
: /* This is not implemented yet.
206 Later it should be converted... */
210 return info
->fbops
->fb_ioctl(info
, cmd
, arg
);
212 case FBIOPUTCMAP_SPARC
: {
215 u16 red
, green
, blue
;
216 u8 red8
, green8
, blue8
;
217 unsigned char __user
*ured
;
218 unsigned char __user
*ugreen
;
219 unsigned char __user
*ublue
;
222 if (copy_from_user(&c
, compat_ptr(arg
), sizeof(c
)))
224 ured
= compat_ptr(c
.red
);
225 ugreen
= compat_ptr(c
.green
);
226 ublue
= compat_ptr(c
.blue
);
233 for (i
= 0; i
< c
.count
; i
++) {
236 if (get_user(red8
, &ured
[i
]) ||
237 get_user(green8
, &ugreen
[i
]) ||
238 get_user(blue8
, &ublue
[i
]))
245 cmap
.start
= c
.index
+ i
;
246 err
= fb_set_cmap(&cmap
, info
);
252 case FBIOGETCMAP32
: {
254 unsigned char __user
*ured
;
255 unsigned char __user
*ugreen
;
256 unsigned char __user
*ublue
;
257 struct fb_cmap
*cmap
= &info
->cmap
;
258 unsigned int index
, i
;
261 if (copy_from_user(&c
, compat_ptr(arg
), sizeof(c
)))
264 ured
= compat_ptr(c
.red
);
265 ugreen
= compat_ptr(c
.green
);
266 ublue
= compat_ptr(c
.blue
);
268 if (index
> cmap
->len
|| c
.count
> cmap
->len
- index
)
271 for (i
= 0; i
< c
.count
; i
++) {
272 red
= cmap
->red
[index
+ i
] >> 8;
273 green
= cmap
->green
[index
+ i
] >> 8;
274 blue
= cmap
->blue
[index
+ i
] >> 8;
275 if (put_user(red
, &ured
[i
]) ||
276 put_user(green
, &ugreen
[i
]) ||
277 put_user(blue
, &ublue
[i
]))
286 EXPORT_SYMBOL(sbusfb_compat_ioctl
);