linux/drivers/video/fbdev/sbuslib.c
<<
>>
Prefs
   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/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_device.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(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_noncached(vma->vm_page_prot);
  64
  65        /* Each page, see which map applies */
  66        for (page = 0; page < size; ){
  67                map_size = 0;
  68                for (i = 0; map[i].size; i++)
  69                        if (map[i].voff == off+page) {
  70                                map_size = sbusfb_mmapsize(map[i].size, fbsize);
  71#ifdef __sparc_v9__
  72#define POFF_MASK       (PAGE_MASK|0x1UL)
  73#else
  74#define POFF_MASK       (PAGE_MASK)
  75#endif                          
  76                                map_offset = (physbase + map[i].poff) & POFF_MASK;
  77                                break;
  78                        }
  79                if (!map_size) {
  80                        page += PAGE_SIZE;
  81                        continue;
  82                }
  83                if (page + map_size > size)
  84                        map_size = size - page;
  85                r = io_remap_pfn_range(vma,
  86                                        vma->vm_start + page,
  87                                        MK_IOSPACE_PFN(iospace,
  88                                                map_offset >> PAGE_SHIFT),
  89                                        map_size,
  90                                        vma->vm_page_prot);
  91                if (r)
  92                        return -EAGAIN;
  93                page += map_size;
  94        }
  95
  96        return 0;
  97}
  98EXPORT_SYMBOL(sbusfb_mmap_helper);
  99
 100int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg,
 101                        struct fb_info *info,
 102                        int type, int fb_depth, unsigned long fb_size)
 103{
 104        switch(cmd) {
 105        case FBIOGTYPE: {
 106                struct fbtype __user *f = (struct fbtype __user *) arg;
 107
 108                if (put_user(type, &f->fb_type) ||
 109                    put_user(info->var.yres, &f->fb_height) ||
 110                    put_user(info->var.xres, &f->fb_width) ||
 111                    put_user(fb_depth, &f->fb_depth) ||
 112                    put_user(0, &f->fb_cmsize) ||
 113                    put_user(fb_size, &f->fb_cmsize))
 114                        return -EFAULT;
 115                return 0;
 116        }
 117        case FBIOPUTCMAP_SPARC: {
 118                struct fbcmap __user *c = (struct fbcmap __user *) arg;
 119                struct fb_cmap cmap;
 120                u16 red, green, blue;
 121                u8 red8, green8, blue8;
 122                unsigned char __user *ured;
 123                unsigned char __user *ugreen;
 124                unsigned char __user *ublue;
 125                unsigned int index, count, i;
 126
 127                if (get_user(index, &c->index) ||
 128                    get_user(count, &c->count) ||
 129                    get_user(ured, &c->red) ||
 130                    get_user(ugreen, &c->green) ||
 131                    get_user(ublue, &c->blue))
 132                        return -EFAULT;
 133
 134                cmap.len = 1;
 135                cmap.red = &red;
 136                cmap.green = &green;
 137                cmap.blue = &blue;
 138                cmap.transp = NULL;
 139                for (i = 0; i < count; i++) {
 140                        int err;
 141
 142                        if (get_user(red8, &ured[i]) ||
 143                            get_user(green8, &ugreen[i]) ||
 144                            get_user(blue8, &ublue[i]))
 145                                return -EFAULT;
 146
 147                        red = red8 << 8;
 148                        green = green8 << 8;
 149                        blue = blue8 << 8;
 150
 151                        cmap.start = index + i;
 152                        err = fb_set_cmap(&cmap, info);
 153                        if (err)
 154                                return err;
 155                }
 156                return 0;
 157        }
 158        case FBIOGETCMAP_SPARC: {
 159                struct fbcmap __user *c = (struct fbcmap __user *) arg;
 160                unsigned char __user *ured;
 161                unsigned char __user *ugreen;
 162                unsigned char __user *ublue;
 163                struct fb_cmap *cmap = &info->cmap;
 164                unsigned int index, count, i;
 165                u8 red, green, blue;
 166
 167                if (get_user(index, &c->index) ||
 168                    get_user(count, &c->count) ||
 169                    get_user(ured, &c->red) ||
 170                    get_user(ugreen, &c->green) ||
 171                    get_user(ublue, &c->blue))
 172                        return -EFAULT;
 173
 174                if (index > cmap->len || count > cmap->len - index)
 175                        return -EINVAL;
 176
 177                for (i = 0; i < count; i++) {
 178                        red = cmap->red[index + i] >> 8;
 179                        green = cmap->green[index + i] >> 8;
 180                        blue = cmap->blue[index + i] >> 8;
 181                        if (put_user(red, &ured[i]) ||
 182                            put_user(green, &ugreen[i]) ||
 183                            put_user(blue, &ublue[i]))
 184                                return -EFAULT;
 185                }
 186                return 0;
 187        }
 188        default:
 189                return -EINVAL;
 190        }
 191}
 192EXPORT_SYMBOL(sbusfb_ioctl_helper);
 193
 194#ifdef CONFIG_COMPAT
 195int sbusfb_compat_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 196{
 197        switch (cmd) {
 198        case FBIOGTYPE:
 199        case FBIOSATTR:
 200        case FBIOGATTR:
 201        case FBIOSVIDEO:
 202        case FBIOGVIDEO:
 203        case FBIOSCURSOR32:
 204        case FBIOGCURSOR32:     /* This is not implemented yet.
 205                                   Later it should be converted... */
 206        case FBIOSCURPOS:
 207        case FBIOGCURPOS:
 208        case FBIOGCURMAX:
 209                return info->fbops->fb_ioctl(info, cmd, arg);
 210        case FBIOPUTCMAP32:
 211        case FBIOPUTCMAP_SPARC: {
 212                struct fbcmap32 c;
 213                struct fb_cmap cmap;
 214                u16 red, green, blue;
 215                u8 red8, green8, blue8;
 216                unsigned char __user *ured;
 217                unsigned char __user *ugreen;
 218                unsigned char __user *ublue;
 219                unsigned int i;
 220
 221                if (copy_from_user(&c, compat_ptr(arg), sizeof(c)))
 222                        return -EFAULT;
 223                ured = compat_ptr(c.red);
 224                ugreen = compat_ptr(c.green);
 225                ublue = compat_ptr(c.blue);
 226
 227                cmap.len = 1;
 228                cmap.red = &red;
 229                cmap.green = &green;
 230                cmap.blue = &blue;
 231                cmap.transp = NULL;
 232                for (i = 0; i < c.count; i++) {
 233                        int err;
 234
 235                        if (get_user(red8, &ured[i]) ||
 236                            get_user(green8, &ugreen[i]) ||
 237                            get_user(blue8, &ublue[i]))
 238                                return -EFAULT;
 239
 240                        red = red8 << 8;
 241                        green = green8 << 8;
 242                        blue = blue8 << 8;
 243
 244                        cmap.start = c.index + i;
 245                        err = fb_set_cmap(&cmap, info);
 246                        if (err)
 247                                return err;
 248                }
 249                return 0;
 250        }
 251        case FBIOGETCMAP32: {
 252                struct fbcmap32 c;
 253                unsigned char __user *ured;
 254                unsigned char __user *ugreen;
 255                unsigned char __user *ublue;
 256                struct fb_cmap *cmap = &info->cmap;
 257                unsigned int index, i;
 258                u8 red, green, blue;
 259
 260                if (copy_from_user(&c, compat_ptr(arg), sizeof(c)))
 261                        return -EFAULT;
 262                index = c.index;
 263                ured = compat_ptr(c.red);
 264                ugreen = compat_ptr(c.green);
 265                ublue = compat_ptr(c.blue);
 266
 267                if (index > cmap->len || c.count > cmap->len - index)
 268                        return -EINVAL;
 269
 270                for (i = 0; i < c.count; i++) {
 271                        red = cmap->red[index + i] >> 8;
 272                        green = cmap->green[index + i] >> 8;
 273                        blue = cmap->blue[index + i] >> 8;
 274                        if (put_user(red, &ured[i]) ||
 275                            put_user(green, &ugreen[i]) ||
 276                            put_user(blue, &ublue[i]))
 277                                return -EFAULT;
 278                }
 279                return 0;
 280        }
 281        default:
 282                return -ENOIOCTLCMD;
 283        }
 284}
 285EXPORT_SYMBOL(sbusfb_compat_ioctl);
 286#endif
 287