fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / video / sbuslib.c
index a09be52..34ef859 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright (C) 2003 David S. Miller (davem@redhat.com)
  */
 
+#include <linux/compat.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/string.h>
@@ -45,6 +46,9 @@ int sbusfb_mmap_helper(struct sbus_mmap_map *map,
        unsigned long off;
        int i;
                                         
+       if (!(vma->vm_flags & (VM_SHARED | VM_MAYSHARE)))
+               return -EINVAL;
+
        size = vma->vm_end - vma->vm_start;
        if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
                return -EINVAL;
@@ -52,8 +56,10 @@ int sbusfb_mmap_helper(struct sbus_mmap_map *map,
        off = vma->vm_pgoff << PAGE_SHIFT;
 
        /* To stop the swapper from even considering these pages */
-       vma->vm_flags |= (VM_SHM | VM_IO | VM_LOCKED);
+       vma->vm_flags |= (VM_IO | VM_RESERVED);
        
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
        /* Each page, see which map applies */
        for (page = 0; page < size; ){
                map_size = 0;
@@ -74,10 +80,12 @@ int sbusfb_mmap_helper(struct sbus_mmap_map *map,
                }
                if (page + map_size > size)
                        map_size = size - page;
-               r = io_remap_page_range(vma,
+               r = io_remap_pfn_range(vma,
                                        vma->vm_start + page,
-                                       map_offset, map_size,
-                                       vma->vm_page_prot, iospace);
+                                       MK_IOSPACE_PFN(iospace,
+                                               map_offset >> PAGE_SHIFT),
+                                       map_size,
+                                       vma->vm_page_prot);
                if (r)
                        return -EAGAIN;
                page += map_size;
@@ -93,7 +101,7 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg,
 {
        switch(cmd) {
        case FBIOGTYPE: {
-               struct fbtype *f = (struct fbtype *) arg;
+               struct fbtype __user *f = (struct fbtype __user *) arg;
 
                if (put_user(type, &f->fb_type) ||
                    __put_user(info->var.yres, &f->fb_height) ||
@@ -105,10 +113,13 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg,
                return 0;
        }
        case FBIOPUTCMAP_SPARC: {
-               struct fbcmap *c = (struct fbcmap *) arg;
+               struct fbcmap __user *c = (struct fbcmap __user *) arg;
                struct fb_cmap cmap;
                u16 red, green, blue;
-               unsigned char *ured, *ugreen, *ublue;
+               u8 red8, green8, blue8;
+               unsigned char __user *ured;
+               unsigned char __user *ugreen;
+               unsigned char __user *ublue;
                int index, count, i;
 
                if (get_user(index, &c->index) ||
@@ -122,26 +133,34 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg,
                cmap.red = &red;
                cmap.green = &green;
                cmap.blue = &blue;
+               cmap.transp = NULL;
                for (i = 0; i < count; i++) {
                        int err;
 
-                       if (get_user(red, &ured[i]) ||
-                           get_user(green, &ugreen[i]) ||
-                           get_user(blue, &ublue[i]))
+                       if (get_user(red8, &ured[i]) ||
+                           get_user(green8, &ugreen[i]) ||
+                           get_user(blue8, &ublue[i]))
                                return -EFAULT;
 
+                       red = red8 << 8;
+                       green = green8 << 8;
+                       blue = blue8 << 8;
+
                        cmap.start = index + i;
-                       err = fb_set_cmap(&cmap, 0, info);
+                       err = fb_set_cmap(&cmap, info);
                        if (err)
                                return err;
                }
                return 0;
        }
        case FBIOGETCMAP_SPARC: {
-               struct fbcmap *c = (struct fbcmap *) arg;
-               unsigned char *ured, *ugreen, *ublue;
+               struct fbcmap __user *c = (struct fbcmap __user *) arg;
+               unsigned char __user *ured;
+               unsigned char __user *ugreen;
+               unsigned char __user *ublue;
                struct fb_cmap *cmap = &info->cmap;
                int index, count, i;
+               u8 red, green, blue;
 
                if (get_user(index, &c->index) ||
                    __get_user(count, &c->count) ||
@@ -154,9 +173,12 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg,
                        return -EINVAL;
 
                for (i = 0; i < count; i++) {
-                       if (put_user(cmap->red[index + i], &ured[i]) ||
-                           put_user(cmap->green[index + i], &ugreen[i]) ||
-                           put_user(cmap->blue[index + i], &ublue[i]))
+                       red = cmap->red[index + i] >> 8;
+                       green = cmap->green[index + i] >> 8;
+                       blue = cmap->blue[index + i] >> 8;
+                       if (put_user(red, &ured[i]) ||
+                           put_user(green, &ugreen[i]) ||
+                           put_user(blue, &ublue[i]))
                                return -EFAULT;
                }
                return 0;
@@ -166,3 +188,104 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg,
        };
 }
 EXPORT_SYMBOL(sbusfb_ioctl_helper);
+
+#ifdef CONFIG_COMPAT
+struct  fbcmap32 {
+       int             index;          /* first element (0 origin) */
+       int             count;
+       u32             red;
+       u32             green;
+       u32             blue;
+};
+
+#define FBIOPUTCMAP32  _IOW('F', 3, struct fbcmap32)
+#define FBIOGETCMAP32  _IOW('F', 4, struct fbcmap32)
+
+static int fbiogetputcmap(struct fb_info *info, unsigned int cmd, unsigned long arg)
+{
+       struct fbcmap32 __user *argp = (void __user *)arg;
+       struct fbcmap __user *p = compat_alloc_user_space(sizeof(*p));
+       u32 addr;
+       int ret;
+
+       ret = copy_in_user(p, argp, 2 * sizeof(int));
+       ret |= get_user(addr, &argp->red);
+       ret |= put_user(compat_ptr(addr), &p->red);
+       ret |= get_user(addr, &argp->green);
+       ret |= put_user(compat_ptr(addr), &p->green);
+       ret |= get_user(addr, &argp->blue);
+       ret |= put_user(compat_ptr(addr), &p->blue);
+       if (ret)
+               return -EFAULT;
+       return info->fbops->fb_ioctl(info,
+                       (cmd == FBIOPUTCMAP32) ?
+                       FBIOPUTCMAP_SPARC : FBIOGETCMAP_SPARC,
+                       (unsigned long)p);
+}
+
+struct fbcursor32 {
+       short set;              /* what to set, choose from the list above */
+       short enable;           /* cursor on/off */
+       struct fbcurpos pos;    /* cursor position */
+       struct fbcurpos hot;    /* cursor hot spot */
+       struct fbcmap32 cmap;   /* color map info */
+       struct fbcurpos size;   /* cursor bit map size */
+       u32     image;          /* cursor image bits */
+       u32     mask;           /* cursor mask bits */
+};
+
+#define FBIOSCURSOR32  _IOW('F', 24, struct fbcursor32)
+#define FBIOGCURSOR32  _IOW('F', 25, struct fbcursor32)
+
+static int fbiogscursor(struct fb_info *info, unsigned long arg)
+{
+       struct fbcursor __user *p = compat_alloc_user_space(sizeof(*p));
+       struct fbcursor32 __user *argp =  (void __user *)arg;
+       compat_uptr_t addr;
+       int ret;
+
+       ret = copy_in_user(p, argp,
+                             2 * sizeof (short) + 2 * sizeof(struct fbcurpos));
+       ret |= copy_in_user(&p->size, &argp->size, sizeof(struct fbcurpos));
+       ret |= copy_in_user(&p->cmap, &argp->cmap, 2 * sizeof(int));
+       ret |= get_user(addr, &argp->cmap.red);
+       ret |= put_user(compat_ptr(addr), &p->cmap.red);
+       ret |= get_user(addr, &argp->cmap.green);
+       ret |= put_user(compat_ptr(addr), &p->cmap.green);
+       ret |= get_user(addr, &argp->cmap.blue);
+       ret |= put_user(compat_ptr(addr), &p->cmap.blue);
+       ret |= get_user(addr, &argp->mask);
+       ret |= put_user(compat_ptr(addr), &p->mask);
+       ret |= get_user(addr, &argp->image);
+       ret |= put_user(compat_ptr(addr), &p->image);
+       if (ret)
+               return -EFAULT;
+       return info->fbops->fb_ioctl(info, FBIOSCURSOR, (unsigned long)p);
+}
+
+int sbusfb_compat_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case FBIOGTYPE:
+       case FBIOSATTR:
+       case FBIOGATTR:
+       case FBIOSVIDEO:
+       case FBIOGVIDEO:
+       case FBIOGCURSOR32:     /* This is not implemented yet.
+                                  Later it should be converted... */
+       case FBIOSCURPOS:
+       case FBIOGCURPOS:
+       case FBIOGCURMAX:
+               return info->fbops->fb_ioctl(info, cmd, arg);
+       case FBIOPUTCMAP32:
+               return fbiogetputcmap(info, cmd, arg);
+       case FBIOGETCMAP32:
+               return fbiogetputcmap(info, cmd, arg);
+       case FBIOSCURSOR32:
+               return fbiogscursor(info, arg);
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+EXPORT_SYMBOL(sbusfb_compat_ioctl);
+#endif