linux/drivers/video/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        /* To stop the swapper from even considering these pages */
  61        vma->vm_flags |= (VM_IO | VM_RESERVED);
  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                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                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 + count > cmap->len)
 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
 195static int fbiogetputcmap(struct fb_info *info, unsigned int cmd, unsigned long arg)
 196{
 197        struct fbcmap32 __user *argp = (void __user *)arg;
 198        struct fbcmap __user *p = compat_alloc_user_space(sizeof(*p));
 199        u32 addr;
 200        int ret;
 201
 202        ret = copy_in_user(p, argp, 2 * sizeof(int));
 203        ret |= get_user(addr, &argp->red);
 204        ret |= put_user(compat_ptr(addr), &p->red);
 205        ret |= get_user(addr, &argp->green);
 206        ret |= put_user(compat_ptr(addr), &p->green);
 207        ret |= get_user(addr, &argp->blue);
 208        ret |= put_user(compat_ptr(addr), &p->blue);
 209        if (ret)
 210                return -EFAULT;
 211        return info->fbops->fb_ioctl(info,
 212                        (cmd == FBIOPUTCMAP32) ?
 213                        FBIOPUTCMAP_SPARC : FBIOGETCMAP_SPARC,
 214                        (unsigned long)p);
 215}
 216
 217static int fbiogscursor(struct fb_info *info, unsigned long arg)
 218{
 219        struct fbcursor __user *p = compat_alloc_user_space(sizeof(*p));
 220        struct fbcursor32 __user *argp =  (void __user *)arg;
 221        compat_uptr_t addr;
 222        int ret;
 223
 224        ret = copy_in_user(p, argp,
 225                              2 * sizeof (short) + 2 * sizeof(struct fbcurpos));
 226        ret |= copy_in_user(&p->size, &argp->size, sizeof(struct fbcurpos));
 227        ret |= copy_in_user(&p->cmap, &argp->cmap, 2 * sizeof(int));
 228        ret |= get_user(addr, &argp->cmap.red);
 229        ret |= put_user(compat_ptr(addr), &p->cmap.red);
 230        ret |= get_user(addr, &argp->cmap.green);
 231        ret |= put_user(compat_ptr(addr), &p->cmap.green);
 232        ret |= get_user(addr, &argp->cmap.blue);
 233        ret |= put_user(compat_ptr(addr), &p->cmap.blue);
 234        ret |= get_user(addr, &argp->mask);
 235        ret |= put_user(compat_ptr(addr), &p->mask);
 236        ret |= get_user(addr, &argp->image);
 237        ret |= put_user(compat_ptr(addr), &p->image);
 238        if (ret)
 239                return -EFAULT;
 240        return info->fbops->fb_ioctl(info, FBIOSCURSOR, (unsigned long)p);
 241}
 242
 243int sbusfb_compat_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 244{
 245        switch (cmd) {
 246        case FBIOGTYPE:
 247        case FBIOSATTR:
 248        case FBIOGATTR:
 249        case FBIOSVIDEO:
 250        case FBIOGVIDEO:
 251        case FBIOGCURSOR32:     /* This is not implemented yet.
 252                                   Later it should be converted... */
 253        case FBIOSCURPOS:
 254        case FBIOGCURPOS:
 255        case FBIOGCURMAX:
 256                return info->fbops->fb_ioctl(info, cmd, arg);
 257        case FBIOPUTCMAP32:
 258                return fbiogetputcmap(info, cmd, arg);
 259        case FBIOGETCMAP32:
 260                return fbiogetputcmap(info, cmd, arg);
 261        case FBIOSCURSOR32:
 262                return fbiogscursor(info, arg);
 263        default:
 264                return -ENOIOCTLCMD;
 265        }
 266}
 267EXPORT_SYMBOL(sbusfb_compat_ioctl);
 268#endif
 269
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.