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