root/drivers/char/fbmem.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. PROC_CONSOLE
  2. fb_read
  3. fb_write
  4. fb_ioctl
  5. fb_mmap
  6. fb_open
  7. fb_release
  8. register_framebuffer
  9. unregister_framebuffer
  10. fbmem_init

   1 /*
   2  *  linux/drivers/char/fbmem.c
   3  *
   4  *  Copyright (C) 1994 Martin Schaller
   5  *
   6  * This file is subject to the terms and conditions of the GNU General Public
   7  * License.  See the file README.legal in the main directory of this archive
   8  * for more details.
   9  */
  10 
  11 #include <linux/types.h>
  12 #include <linux/errno.h>
  13 #include <linux/sched.h>
  14 #include <linux/kernel.h>
  15 #include <linux/major.h>
  16 #include <linux/malloc.h>
  17 #include <linux/mman.h>
  18 #include <linux/tty.h>
  19 
  20 #include <asm/segment.h>
  21 #include <asm/bootinfo.h>
  22 #include <asm/page.h>
  23 #include <asm/pgtable.h>
  24 
  25 #include <linux/fb.h>
  26 
  27 #define FB_MAJOR        29
  28 
  29 #define FB_MODES_SHIFT    5     /* 32 modes per framebuffer */
  30 #define FB_NUM_MINORS   256     /* 256 Minors               */
  31 #define FB_MAX          (FB_NUM_MINORS / (1 << FB_MODES_SHIFT))
  32 
  33 #define GET_INODE(i) MKDEV(FB_MAJOR, (i) << FB_MODES_SHIFT)
  34 #define GET_FB_IDX(node) (MINOR(node) >> FB_MODES_SHIFT)
  35 #define GET_FB_VAR_IDX(node) (MINOR(node) & ((1 << FB_MODES_SHIFT)-1)) 
  36 
  37 struct fb_ops *registered_fb[FB_MAX];
  38 struct fb_var_screeninfo *registered_fb_var[FB_MAX];
  39 int registered_fb_var_num[FB_MAX];
  40 int fb_curr_open[FB_MAX];
  41 int fb_open_count[FB_MAX];
  42 
  43 static inline int PROC_CONSOLE(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  44 {
  45         if (!current->tty)
  46                 return fg_console;
  47 
  48         if (current->tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
  49                 /* XXX Should report error here? */
  50                 return fg_console;
  51 
  52         if (MINOR(current->tty->device) < 1)
  53                 return fg_console;
  54 
  55         return MINOR(current->tty->device) - 1;
  56 }
  57 
  58 static int 
  59 fb_read(struct inode *inode, struct file *file, char *buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
  60 {
  61         unsigned long p = file->f_pos;
  62         struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)];
  63         struct fb_fix_screeninfo fix;
  64         char *base_addr;
  65         int copy_size;
  66 
  67         if (! fb)
  68                 return -ENODEV;
  69         if (count < 0)
  70                 return -EINVAL;
  71 
  72         fb->fb_get_fix(&fix,PROC_CONSOLE());
  73         base_addr=(char *) fix.smem_start;
  74         copy_size=(count + p <= fix.smem_len ? count : fix.smem_len - p);
  75         memcpy_tofs(buf, base_addr+p, copy_size);
  76         file->f_pos += copy_size;
  77         return copy_size;
  78 }
  79 
  80 static int 
  81 fb_write(struct inode *inode, struct file *file, const char *buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
  82 {
  83         unsigned long p = file->f_pos;
  84         struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)];
  85         struct fb_fix_screeninfo fix;
  86         char *base_addr;
  87         int copy_size;
  88 
  89         if (! fb)
  90                 return -ENODEV;
  91         if (count < 0)
  92                 return -EINVAL;
  93         fb->fb_get_fix(&fix, PROC_CONSOLE());
  94         base_addr=(char *) fix.smem_start;
  95         copy_size=(count + p <= fix.smem_len ? count : fix.smem_len - p);
  96         memcpy_fromfs(base_addr+p, buf, copy_size); 
  97         file->f_pos += copy_size;
  98         return copy_size;
  99 }
 100 
 101 
 102 static int 
 103 fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
     /* [previous][next][first][last][top][bottom][index][help] */
 104          unsigned long arg)
 105 {
 106         struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)];
 107         struct fb_cmap cmap;
 108         struct fb_var_screeninfo var;
 109         struct fb_fix_screeninfo fix;
 110 
 111         int i,fbidx,vidx;
 112         
 113         if (! fb)
 114                 return -ENODEV;
 115         switch (cmd) {
 116         case FBIOGET_VSCREENINFO:
 117                 i = verify_area(VERIFY_WRITE, (void *) arg, 
 118                                 sizeof(struct fb_var_screeninfo));
 119                 if (i) return i;
 120                 fbidx=GET_FB_IDX(inode->i_rdev);
 121                 vidx=GET_FB_VAR_IDX(inode->i_rdev);
 122                 if (! vidx) /* ask device driver for current */
 123                         i=fb->fb_get_var(&var, PROC_CONSOLE());
 124                 else
 125                         var=registered_fb_var[fbidx][vidx-1];
 126                 memcpy_tofs((void *) arg, &var, sizeof(var));
 127                 return i;
 128         case FBIOPUT_VSCREENINFO:
 129                 i = verify_area(VERIFY_WRITE, (void *) arg, 
 130                                 sizeof(struct fb_var_screeninfo));
 131                 if (i) return i;
 132                 memcpy_fromfs(&var, (void *) arg, sizeof(var));
 133                 i=fb->fb_set_var(&var, PROC_CONSOLE());
 134                 memcpy_tofs((void *) arg, &var, sizeof(var));
 135                 fbidx=GET_FB_IDX(inode->i_rdev);
 136                 vidx=GET_FB_VAR_IDX(inode->i_rdev);
 137                 if (! i && vidx)
 138                         registered_fb_var[fbidx][vidx-1]=var;
 139                 return i;
 140         case FBIOGET_FSCREENINFO:
 141                 i = verify_area(VERIFY_WRITE, (void *) arg, 
 142                                 sizeof(struct fb_fix_screeninfo));
 143                 if (i)  return i;
 144                 i=fb->fb_get_fix(&fix, PROC_CONSOLE());
 145                 memcpy_tofs((void *) arg, &fix, sizeof(fix));
 146                 return i;
 147         case FBIOPUTCMAP:
 148                 i = verify_area(VERIFY_READ, (void *) arg,
 149                                 sizeof(struct fb_cmap));
 150                 if (i) return i;
 151                 memcpy_fromfs(&cmap, (void *) arg, sizeof(cmap));
 152                 i = verify_area(VERIFY_READ, (void *) cmap.red, 
 153                                 cmap.len * sizeof(unsigned short));
 154                 if (i) return i;
 155                 i = verify_area(VERIFY_READ, (void *) cmap.green, 
 156                                 cmap.len * sizeof(unsigned short));
 157                 if (i) return i;
 158                 i = verify_area(VERIFY_READ, (void *) cmap.blue, 
 159                                 cmap.len * sizeof(unsigned short));
 160                 if (i) return i;
 161                 if (cmap.transp) {
 162                         i = verify_area(VERIFY_READ, (void *) cmap.transp, 
 163                                         cmap.len * sizeof(unsigned short));
 164                         if (i) return i;
 165                 }
 166                 return (fb->fb_set_cmap(&cmap, 0, PROC_CONSOLE()));
 167         case FBIOGETCMAP:
 168                 i = verify_area(VERIFY_READ, (void *) arg,
 169                                 sizeof(struct fb_cmap));
 170                 if (i)  return i;
 171                 memcpy_fromfs(&cmap, (void *) arg, sizeof(cmap));
 172                 i = verify_area(VERIFY_WRITE, (void *) cmap.red, 
 173                                 cmap.len * sizeof(unsigned short));
 174                 if (i) return i;
 175                 i = verify_area(VERIFY_WRITE, (void *) cmap.green, 
 176                                 cmap.len * sizeof(unsigned short));
 177                 if (i) return i;
 178                 i = verify_area(VERIFY_WRITE, (void *) cmap.blue, 
 179                                 cmap.len * sizeof(unsigned short));
 180                 if (i) return i;
 181                 if (cmap.transp) {
 182                         i = verify_area(VERIFY_WRITE, (void *) cmap.transp, 
 183                                         cmap.len * sizeof(unsigned short));
 184                         if (i) return i;
 185                 }
 186                 return (fb->fb_get_cmap(&cmap, 0, PROC_CONSOLE()));
 187         case FBIOPAN_DISPLAY:
 188                 i = verify_area(VERIFY_WRITE, (void *) arg, 
 189                                 sizeof(struct fb_var_screeninfo));
 190                 if (i) return i;
 191                 memcpy_fromfs(&var, (void *) arg, sizeof(var));
 192                 i=fb->fb_pan_display(&var, PROC_CONSOLE());
 193                 memcpy_tofs((void *) arg, &var, sizeof(var));
 194                 fbidx=GET_FB_IDX(inode->i_rdev);
 195                 vidx=GET_FB_VAR_IDX(inode->i_rdev);
 196                 if (! i && vidx)
 197                         registered_fb_var[fbidx][vidx-1]=var;
 198                 return i;
 199         default:
 200                 return (fb->fb_ioctl(inode, file, cmd, arg, PROC_CONSOLE()));
 201         }
 202 }
 203 
 204 static int 
 205 fb_mmap(struct inode *inode, struct file *file, struct vm_area_struct * vma)
     /* [previous][next][first][last][top][bottom][index][help] */
 206 {
 207         struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)];
 208         struct fb_fix_screeninfo fix;
 209 
 210         if (! fb)
 211                 return -ENODEV;
 212         fb->fb_get_fix(&fix, PROC_CONSOLE());
 213         if ((vma->vm_end - vma->vm_start + vma->vm_offset) > fix.smem_len)
 214                 return -EINVAL;
 215         vma->vm_offset += fix.smem_start;
 216         if (vma->vm_offset & ~PAGE_MASK)
 217                 return -ENXIO;
 218         if (m68k_is040or060) {
 219                 pgprot_val(vma->vm_page_prot) &= _CACHEMASK040;
 220                 /* Use write-through cache mode */
 221                 pgprot_val(vma->vm_page_prot) |= _PAGE_CACHE040W;
 222         }
 223         if (remap_page_range(vma->vm_start, vma->vm_offset,
 224                              vma->vm_end - vma->vm_start, vma->vm_page_prot))
 225                 return -EAGAIN;
 226         vma->vm_inode = inode;
 227         inode->i_count++;
 228         return 0;
 229 }
 230 
 231 static int
 232 fb_open(struct inode *inode, struct file *file)
     /* [previous][next][first][last][top][bottom][index][help] */
 233 {
 234         int fbidx=GET_FB_IDX(inode->i_rdev);
 235         int vidx=GET_FB_VAR_IDX(inode->i_rdev);
 236         struct fb_ops *fb = registered_fb[fbidx];
 237         int err;
 238         
 239         if (! vidx)             /* fb?current always succeeds */ 
 240                 return 0;
 241         if (vidx > registered_fb_var_num[fbidx])
 242                 return -EINVAL;
 243         if (fb_curr_open[fbidx] && fb_curr_open[fbidx] != vidx)
 244                 return -EBUSY;
 245         if (file->f_mode & 2) /* only set parameters if opened writeable */
 246                 if ((err=fb->fb_set_var(registered_fb_var[fbidx] + vidx-1, PROC_CONSOLE())))
 247                         return err;
 248         fb_curr_open[fbidx] = vidx;
 249         fb_open_count[fbidx]++;
 250         return 0;
 251 }
 252 
 253 static void 
 254 fb_release(struct inode *inode, struct file *file)
     /* [previous][next][first][last][top][bottom][index][help] */
 255 {
 256         int fbidx=GET_FB_IDX(inode->i_rdev);
 257         int vidx=GET_FB_VAR_IDX(inode->i_rdev);
 258         if (! vidx)
 259                 return;
 260         if (! (--fb_open_count[fbidx]))
 261                 fb_curr_open[fbidx]=0;
 262 }
 263 
 264 static struct file_operations fb_fops = {
 265         NULL,           /* lseek        */
 266         fb_read,        /* read         */
 267         fb_write,       /* write        */
 268         NULL,           /* readdir      */
 269         NULL,           /* select       */
 270         fb_ioctl,       /* ioctl        */
 271         fb_mmap,        /* mmap         */
 272         fb_open,        /* open         */
 273         fb_release,     /* release      */
 274         NULL            /* fsync        */
 275 };
 276 
 277 int
 278 register_framebuffer(char *id, int *node, struct fb_ops *fbops, int fbvar_num, 
     /* [previous][next][first][last][top][bottom][index][help] */
 279                      struct fb_var_screeninfo *fbvar)
 280 {
 281         int i;
 282         for (i = 0 ; i < FB_MAX; i++)
 283                 if (! registered_fb[i])
 284                         break;
 285         if (i == FB_MAX)
 286                 return -ENXIO;
 287         registered_fb[i]=fbops;
 288         registered_fb_var[i]=fbvar;
 289         registered_fb_var_num[i]=fbvar_num;
 290         *node=GET_INODE(i);
 291         return 0;
 292 }
 293 
 294 int
 295 unregister_framebuffer(int node)
     /* [previous][next][first][last][top][bottom][index][help] */
 296 {
 297         int i=GET_FB_IDX(node);
 298         if (! registered_fb[i])
 299                 return -EINVAL; 
 300         registered_fb[i]=NULL;
 301         registered_fb_var[i]=NULL;
 302         return 0;
 303 }
 304 
 305 void
 306 fbmem_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 307 {
 308         if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
 309                 printk("unable to get major %d for fb devs\n", FB_MAJOR);
 310 }
 311 

/* [previous][next][first][last][top][bottom][index][help] */