File Index
Files and directories
Sign in
FILE

sbuslib.c

File preview with syntax highlighting.

linux-6.19.14/drivers/video/fbdev/sbuslib.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/* sbuslib.c: Helper library for SBUS framebuffer drivers.
  3 *
  4 * Copyright (C) 2003 David S. Miller (davem@redhat.com)
  5 */
  6
  7#include <linux/compat.h>
  8#include <linux/export.h>
  9#include <linux/kernel.h>
 10#include <linux/module.h>
 11#include <linux/string.h>
 12#include <linux/fb.h>
 13#include <linux/mm.h>
 14#include <linux/uaccess.h>
 15#include <linux/of.h>
 16
 17#include <asm/fbio.h>
 18
 19#include "sbuslib.h"
 20
 21void sbusfb_fill_var(struct fb_var_screeninfo *var, struct device_node *dp,
 22		     int bpp)
 23{
 24	memset(var, 0, sizeof(*var));
 25
 26	var->xres = of_getintprop_default(dp, "width", 1152);
 27	var->yres = of_getintprop_default(dp, "height", 900);
 28	var->xres_virtual = var->xres;
 29	var->yres_virtual = var->yres;
 30	var->bits_per_pixel = bpp;
 31}
 32
 33EXPORT_SYMBOL(sbusfb_fill_var);
 34
 35static unsigned long sbusfb_mmapsize(long size, unsigned long fbsize)
 36{
 37	if (size == SBUS_MMAP_EMPTY) return 0;
 38	if (size >= 0) return size;
 39	return fbsize * (-size);
 40}
 41
 42int sbusfb_mmap_helper(const struct sbus_mmap_map *map,
 43		       unsigned long physbase,
 44		       unsigned long fbsize,
 45		       unsigned long iospace,
 46		       struct vm_area_struct *vma)
 47{
 48	unsigned int size, page, r, map_size;
 49	unsigned long map_offset = 0;
 50	unsigned long off;
 51	int i;
 52
 53	if (!(vma->vm_flags & (VM_SHARED | VM_MAYSHARE)))
 54		return -EINVAL;
 55
 56	size = vma->vm_end - vma->vm_start;
 57	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
 58		return -EINVAL;
 59
 60	off = vma->vm_pgoff << PAGE_SHIFT;
 61
 62	/* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */
 63
 64	vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
 65	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 66
 67	/* Each page, see which map applies */
 68	for (page = 0; page < size; ){
 69		map_size = 0;
 70		for (i = 0; map[i].size; i++)
 71			if (map[i].voff == off+page) {
 72				map_size = sbusfb_mmapsize(map[i].size, fbsize);
 73#ifdef __sparc_v9__
 74#define POFF_MASK	(PAGE_MASK|0x1UL)
 75#else
 76#define POFF_MASK	(PAGE_MASK)
 77#endif
 78				map_offset = (physbase + map[i].poff) & POFF_MASK;
 79				break;
 80			}
 81		if (!map_size) {
 82			page += PAGE_SIZE;
 83			continue;
 84		}
 85		if (page + map_size > size)
 86			map_size = size - page;
 87		r = io_remap_pfn_range(vma,
 88					vma->vm_start + page,
 89					MK_IOSPACE_PFN(iospace,
 90						map_offset >> PAGE_SHIFT),
 91					map_size,
 92					vma->vm_page_prot);
 93		if (r)
 94			return -EAGAIN;
 95		page += map_size;
 96	}
 97
 98	return 0;
 99}
100EXPORT_SYMBOL(sbusfb_mmap_helper);
101
102int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg,
103			struct fb_info *info,
104			int type, int fb_depth, unsigned long fb_size)
105{
106	switch(cmd) {
107	case FBIOGTYPE: {
108		struct fbtype __user *f = (struct fbtype __user *) arg;
109
110		if (put_user(type, &f->fb_type) ||
111		    put_user(info->var.yres, &f->fb_height) ||
112		    put_user(info->var.xres, &f->fb_width) ||
113		    put_user(fb_depth, &f->fb_depth) ||
114		    put_user(0, &f->fb_cmsize) ||
115		    put_user(fb_size, &f->fb_cmsize))
116			return -EFAULT;
117		return 0;
118	}
119	case FBIOPUTCMAP_SPARC: {
120		struct fbcmap __user *c = (struct fbcmap __user *) arg;
121		struct fb_cmap cmap;
122		u16 red, green, blue;
123		u8 red8, green8, blue8;
124		unsigned char __user *ured;
125		unsigned char __user *ugreen;
126		unsigned char __user *ublue;
127		unsigned int index, count, i;
128
129		if (get_user(index, &c->index) ||
130		    get_user(count, &c->count) ||
131		    get_user(ured, &c->red) ||
132		    get_user(ugreen, &c->green) ||
133		    get_user(ublue, &c->blue))
134			return -EFAULT;
135
136		cmap.len = 1;
137		cmap.red = &red;
138		cmap.green = &green;
139		cmap.blue = &blue;
140		cmap.transp = NULL;
141		for (i = 0; i < count; i++) {
142			int err;
143
144			if (get_user(red8, &ured[i]) ||
145			    get_user(green8, &ugreen[i]) ||
146			    get_user(blue8, &ublue[i]))
147				return -EFAULT;
148
149			red = red8 << 8;
150			green = green8 << 8;
151			blue = blue8 << 8;
152
153			cmap.start = index + i;
154			err = fb_set_cmap(&cmap, info);
155			if (err)
156				return err;
157		}
158		return 0;
159	}
160	case FBIOGETCMAP_SPARC: {
161		struct fbcmap __user *c = (struct fbcmap __user *) arg;
162		unsigned char __user *ured;
163		unsigned char __user *ugreen;
164		unsigned char __user *ublue;
165		struct fb_cmap *cmap = &info->cmap;
166		unsigned int index, count, i;
167		u8 red, green, blue;
168
169		if (get_user(index, &c->index) ||
170		    get_user(count, &c->count) ||
171		    get_user(ured, &c->red) ||
172		    get_user(ugreen, &c->green) ||
173		    get_user(ublue, &c->blue))
174			return -EFAULT;
175
176		if (index > cmap->len || count > cmap->len - index)
177			return -EINVAL;
178
179		for (i = 0; i < count; i++) {
180			red = cmap->red[index + i] >> 8;
181			green = cmap->green[index + i] >> 8;
182			blue = cmap->blue[index + i] >> 8;
183			if (put_user(red, &ured[i]) ||
184			    put_user(green, &ugreen[i]) ||
185			    put_user(blue, &ublue[i]))
186				return -EFAULT;
187		}
188		return 0;
189	}
190	default:
191		return -EINVAL;
192	}
193}
194EXPORT_SYMBOL(sbusfb_ioctl_helper);
195
196#ifdef CONFIG_COMPAT
197int sbusfb_compat_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
198{
199	switch (cmd) {
200	case FBIOGTYPE:
201	case FBIOSATTR:
202	case FBIOGATTR:
203	case FBIOSVIDEO:
204	case FBIOGVIDEO:
205	case FBIOSCURSOR32:
206	case FBIOGCURSOR32:	/* This is not implemented yet.
207				   Later it should be converted... */
208	case FBIOSCURPOS:
209	case FBIOGCURPOS:
210	case FBIOGCURMAX:
211		return info->fbops->fb_ioctl(info, cmd, arg);
212	case FBIOPUTCMAP32:
213	case FBIOPUTCMAP_SPARC: {
214		struct fbcmap32 c;
215		struct fb_cmap cmap;
216		u16 red, green, blue;
217		u8 red8, green8, blue8;
218		unsigned char __user *ured;
219		unsigned char __user *ugreen;
220		unsigned char __user *ublue;
221		unsigned int i;
222
223		if (copy_from_user(&c, compat_ptr(arg), sizeof(c)))
224			return -EFAULT;
225		ured = compat_ptr(c.red);
226		ugreen = compat_ptr(c.green);
227		ublue = compat_ptr(c.blue);
228
229		cmap.len = 1;
230		cmap.red = &red;
231		cmap.green = &green;
232		cmap.blue = &blue;
233		cmap.transp = NULL;
234		for (i = 0; i < c.count; i++) {
235			int err;
236
237			if (get_user(red8, &ured[i]) ||
238			    get_user(green8, &ugreen[i]) ||
239			    get_user(blue8, &ublue[i]))
240				return -EFAULT;
241
242			red = red8 << 8;
243			green = green8 << 8;
244			blue = blue8 << 8;
245
246			cmap.start = c.index + i;
247			err = fb_set_cmap(&cmap, info);
248			if (err)
249				return err;
250		}
251		return 0;
252	}
253	case FBIOGETCMAP32: {
254		struct fbcmap32 c;
255		unsigned char __user *ured;
256		unsigned char __user *ugreen;
257		unsigned char __user *ublue;
258		struct fb_cmap *cmap = &info->cmap;
259		unsigned int index, i;
260		u8 red, green, blue;
261
262		if (copy_from_user(&c, compat_ptr(arg), sizeof(c)))
263			return -EFAULT;
264		index = c.index;
265		ured = compat_ptr(c.red);
266		ugreen = compat_ptr(c.green);
267		ublue = compat_ptr(c.blue);
268
269		if (index > cmap->len || c.count > cmap->len - index)
270			return -EINVAL;
271
272		for (i = 0; i < c.count; i++) {
273			red = cmap->red[index + i] >> 8;
274			green = cmap->green[index + i] >> 8;
275			blue = cmap->blue[index + i] >> 8;
276			if (put_user(red, &ured[i]) ||
277			    put_user(green, &ugreen[i]) ||
278			    put_user(blue, &ublue[i]))
279				return -EFAULT;
280		}
281		return 0;
282	}
283	default:
284		return -ENOIOCTLCMD;
285	}
286}
287EXPORT_SYMBOL(sbusfb_compat_ioctl);
288#endif
~/ Read-only file preview.