288 lines · c
1// SPDX-License-Identifier: GPL-2.02/* 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/kernel.h>9#include <linux/module.h>10#include <linux/string.h>11#include <linux/fb.h>12#include <linux/mm.h>13#include <linux/uaccess.h>14#include <linux/of.h>15 16#include <asm/fbio.h>17 18#include "sbuslib.h"19 20void sbusfb_fill_var(struct fb_var_screeninfo *var, struct device_node *dp,21 int bpp)22{23 memset(var, 0, sizeof(*var));24 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;30}31 32EXPORT_SYMBOL(sbusfb_fill_var);33 34static unsigned long sbusfb_mmapsize(long size, unsigned long fbsize)35{36 if (size == SBUS_MMAP_EMPTY) return 0;37 if (size >= 0) return size;38 return fbsize * (-size);39}40 41int sbusfb_mmap_helper(const struct sbus_mmap_map *map,42 unsigned long physbase,43 unsigned long fbsize,44 unsigned long iospace,45 struct vm_area_struct *vma)46{47 unsigned int size, page, r, map_size;48 unsigned long map_offset = 0;49 unsigned long off;50 int i;51 52 if (!(vma->vm_flags & (VM_SHARED | VM_MAYSHARE)))53 return -EINVAL;54 55 size = vma->vm_end - vma->vm_start;56 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))57 return -EINVAL;58 59 off = vma->vm_pgoff << PAGE_SHIFT;60 61 /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */62 63 vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);64 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);65 66 /* Each page, see which map applies */67 for (page = 0; page < size; ){68 map_size = 0;69 for (i = 0; map[i].size; i++)70 if (map[i].voff == off+page) {71 map_size = sbusfb_mmapsize(map[i].size, fbsize);72#ifdef __sparc_v9__73#define POFF_MASK (PAGE_MASK|0x1UL)74#else75#define POFF_MASK (PAGE_MASK)76#endif77 map_offset = (physbase + map[i].poff) & POFF_MASK;78 break;79 }80 if (!map_size) {81 page += PAGE_SIZE;82 continue;83 }84 if (page + map_size > size)85 map_size = size - page;86 r = io_remap_pfn_range(vma,87 vma->vm_start + page,88 MK_IOSPACE_PFN(iospace,89 map_offset >> PAGE_SHIFT),90 map_size,91 vma->vm_page_prot);92 if (r)93 return -EAGAIN;94 page += map_size;95 }96 97 return 0;98}99EXPORT_SYMBOL(sbusfb_mmap_helper);100 101int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg,102 struct fb_info *info,103 int type, int fb_depth, unsigned long fb_size)104{105 switch(cmd) {106 case FBIOGTYPE: {107 struct fbtype __user *f = (struct fbtype __user *) arg;108 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))115 return -EFAULT;116 return 0;117 }118 case FBIOPUTCMAP_SPARC: {119 struct fbcmap __user *c = (struct fbcmap __user *) arg;120 struct fb_cmap cmap;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;127 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))133 return -EFAULT;134 135 cmap.len = 1;136 cmap.red = &red;137 cmap.green = &green;138 cmap.blue = &blue;139 cmap.transp = NULL;140 for (i = 0; i < count; i++) {141 int err;142 143 if (get_user(red8, &ured[i]) ||144 get_user(green8, &ugreen[i]) ||145 get_user(blue8, &ublue[i]))146 return -EFAULT;147 148 red = red8 << 8;149 green = green8 << 8;150 blue = blue8 << 8;151 152 cmap.start = index + i;153 err = fb_set_cmap(&cmap, info);154 if (err)155 return err;156 }157 return 0;158 }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;166 u8 red, green, blue;167 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))173 return -EFAULT;174 175 if (index > cmap->len || count > cmap->len - index)176 return -EINVAL;177 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]))185 return -EFAULT;186 }187 return 0;188 }189 default:190 return -EINVAL;191 }192}193EXPORT_SYMBOL(sbusfb_ioctl_helper);194 195#ifdef CONFIG_COMPAT196int sbusfb_compat_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)197{198 switch (cmd) {199 case FBIOGTYPE:200 case FBIOSATTR:201 case FBIOGATTR:202 case FBIOSVIDEO:203 case FBIOGVIDEO:204 case FBIOSCURSOR32:205 case FBIOGCURSOR32: /* This is not implemented yet.206 Later it should be converted... */207 case FBIOSCURPOS:208 case FBIOGCURPOS:209 case FBIOGCURMAX:210 return info->fbops->fb_ioctl(info, cmd, arg);211 case FBIOPUTCMAP32:212 case FBIOPUTCMAP_SPARC: {213 struct fbcmap32 c;214 struct fb_cmap cmap;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;220 unsigned int i;221 222 if (copy_from_user(&c, compat_ptr(arg), sizeof(c)))223 return -EFAULT;224 ured = compat_ptr(c.red);225 ugreen = compat_ptr(c.green);226 ublue = compat_ptr(c.blue);227 228 cmap.len = 1;229 cmap.red = &red;230 cmap.green = &green;231 cmap.blue = &blue;232 cmap.transp = NULL;233 for (i = 0; i < c.count; i++) {234 int err;235 236 if (get_user(red8, &ured[i]) ||237 get_user(green8, &ugreen[i]) ||238 get_user(blue8, &ublue[i]))239 return -EFAULT;240 241 red = red8 << 8;242 green = green8 << 8;243 blue = blue8 << 8;244 245 cmap.start = c.index + i;246 err = fb_set_cmap(&cmap, info);247 if (err)248 return err;249 }250 return 0;251 }252 case FBIOGETCMAP32: {253 struct fbcmap32 c;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;259 u8 red, green, blue;260 261 if (copy_from_user(&c, compat_ptr(arg), sizeof(c)))262 return -EFAULT;263 index = c.index;264 ured = compat_ptr(c.red);265 ugreen = compat_ptr(c.green);266 ublue = compat_ptr(c.blue);267 268 if (index > cmap->len || c.count > cmap->len - index)269 return -EINVAL;270 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]))278 return -EFAULT;279 }280 return 0;281 }282 default:283 return -ENOIOCTLCMD;284 }285}286EXPORT_SYMBOL(sbusfb_compat_ioctl);287#endif288