patch-1.3.94 linux/drivers/char/fbmem.c

Next file: linux/drivers/char/ftape/Makefile
Previous file: linux/drivers/char/atarimouse.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.93/linux/drivers/char/fbmem.c linux/drivers/char/fbmem.c
@@ -0,0 +1,292 @@
+/*
+ *  linux/drivers/char/fbmem.c
+ *
+ *  Copyright (C) 1994 Martin Schaller
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/malloc.h>
+#include <linux/mman.h>
+#include <linux/tty.h>
+
+#include <asm/segment.h>
+#include <asm/bootinfo.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#include <linux/fb.h>
+
+#define FB_MAJOR	29
+
+#define FB_MODES_SHIFT    5	/* 32 modes per framebuffer */
+#define FB_NUM_MINORS 	256	/* 256 Minors		    */
+#define FB_MAX		(FB_NUM_MINORS / (1 << FB_MODES_SHIFT))
+
+#define GET_INODE(i) MKDEV(FB_MAJOR, (i) << FB_MODES_SHIFT)
+#define GET_FB_IDX(node) (MINOR(node) >> FB_MODES_SHIFT)
+#define GET_FB_VAR_IDX(node) (MINOR(node) & ((1 << FB_MODES_SHIFT)-1)) 
+
+struct fb_ops *registered_fb[FB_MAX];
+struct fb_var_screeninfo *registered_fb_var[FB_MAX];
+int registered_fb_var_num[FB_MAX];
+int fb_curr_open[FB_MAX];
+int fb_open_count[FB_MAX];
+
+static inline int PROC_CONSOLE(void)
+{
+	if (!current->tty)
+		return fg_console;
+
+	if (MINOR(current->tty->device) < 1)
+		return fg_console;
+
+	return MINOR(current->tty->device) - 1;
+}
+
+static int 
+fb_read(struct inode *inode, struct file *file, char *buf, int count)
+{
+	unsigned long p = file->f_pos;
+	struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)];
+	struct fb_fix_screeninfo fix;
+	char *base_addr;
+	int copy_size;
+
+	if (! fb)
+		return -ENODEV;
+	if (count < 0)
+		return -EINVAL;
+
+	fb->fb_get_fix(&fix,PROC_CONSOLE());
+	base_addr=(char *) fix.smem_start;
+	copy_size=(count + p <= fix.smem_len ? count : fix.smem_len - p);
+	memcpy_tofs(buf, base_addr+p, copy_size);
+	file->f_pos += copy_size;
+	return copy_size;
+}
+
+static int 
+fb_write(struct inode *inode, struct file *file, const char *buf, int count)
+{
+	unsigned long p = file->f_pos;
+	struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)];
+	struct fb_fix_screeninfo fix;
+	char *base_addr;
+	int copy_size;
+
+	if (! fb)
+		return -ENODEV;
+	if (count < 0)
+		return -EINVAL;
+	fb->fb_get_fix(&fix, PROC_CONSOLE());
+	base_addr=(char *) fix.smem_start;
+	copy_size=(count + p <= fix.smem_len ? count : fix.smem_len - p);
+	memcpy_fromfs(base_addr+p, buf, copy_size); 
+	file->f_pos += copy_size;
+	return copy_size;
+}
+
+
+static int 
+fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	 unsigned long arg)
+{
+	struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)];
+	struct fb_cmap cmap;
+	struct fb_var_screeninfo var;
+	struct fb_fix_screeninfo fix;
+
+	int i,fbidx,vidx;
+	
+	if (! fb)
+		return -ENODEV;
+	switch (cmd) {
+	case FBIOGET_VSCREENINFO:
+		i = verify_area(VERIFY_WRITE, (void *) arg, 
+				sizeof(struct fb_var_screeninfo));
+		if (i) return i;
+		fbidx=GET_FB_IDX(inode->i_rdev);
+		vidx=GET_FB_VAR_IDX(inode->i_rdev);
+		if (! vidx) /* ask device driver for current */
+			i=fb->fb_get_var(&var, PROC_CONSOLE());
+		else
+			var=registered_fb_var[fbidx][vidx-1];
+		memcpy_tofs((void *) arg, &var, sizeof(var));
+		return i;
+	case FBIOPUT_VSCREENINFO:
+		i = verify_area(VERIFY_WRITE, (void *) arg, 
+				sizeof(struct fb_var_screeninfo));
+		if (i) return i;
+		memcpy_fromfs(&var, (void *) arg, sizeof(var));
+		i=fb->fb_set_var(&var, PROC_CONSOLE());
+		memcpy_tofs((void *) arg, &var, sizeof(var));
+		fbidx=GET_FB_IDX(inode->i_rdev);
+		vidx=GET_FB_VAR_IDX(inode->i_rdev);
+		if (! i && vidx)
+			registered_fb_var[fbidx][vidx-1]=var;
+		return i;
+	case FBIOGET_FSCREENINFO:
+		i = verify_area(VERIFY_WRITE, (void *) arg, 
+				sizeof(struct fb_fix_screeninfo));
+		if (i)	return i;
+		i=fb->fb_get_fix(&fix, PROC_CONSOLE());
+		memcpy_tofs((void *) arg, &fix, sizeof(fix));
+		return i;
+	case FBIOPUTCMAP:
+		i = verify_area(VERIFY_READ, (void *) arg,
+				sizeof(struct fb_cmap));
+		if (i) return i;
+		memcpy_fromfs(&cmap, (void *) arg, sizeof(cmap));
+		i = verify_area(VERIFY_READ, (void *) cmap.red, 
+				cmap.len * sizeof(unsigned short));
+		if (i) return i;
+		i = verify_area(VERIFY_READ, (void *) cmap.green, 
+				cmap.len * sizeof(unsigned short));
+		if (i) return i;
+		i = verify_area(VERIFY_READ, (void *) cmap.blue, 
+				cmap.len * sizeof(unsigned short));
+		if (i) return i;
+		if (cmap.transp) {
+			i = verify_area(VERIFY_READ, (void *) cmap.transp, 
+					cmap.len * sizeof(unsigned short));
+			if (i) return i;
+		}
+		return (fb->fb_set_cmap(&cmap, 0, PROC_CONSOLE()));
+	case FBIOGETCMAP:
+		i = verify_area(VERIFY_READ, (void *) arg,
+				sizeof(struct fb_cmap));
+		if (i)	return i;
+		memcpy_fromfs(&cmap, (void *) arg, sizeof(cmap));
+		i = verify_area(VERIFY_WRITE, (void *) cmap.red, 
+				cmap.len * sizeof(unsigned short));
+		if (i) return i;
+		i = verify_area(VERIFY_WRITE, (void *) cmap.green, 
+				cmap.len * sizeof(unsigned short));
+		if (i) return i;
+		i = verify_area(VERIFY_WRITE, (void *) cmap.blue, 
+				cmap.len * sizeof(unsigned short));
+		if (i) return i;
+		if (cmap.transp) {
+			i = verify_area(VERIFY_WRITE, (void *) cmap.transp, 
+					cmap.len * sizeof(unsigned short));
+			if (i) return i;
+		}
+		return (fb->fb_get_cmap(&cmap, 0, PROC_CONSOLE()));
+	default:
+		return (fb->fb_ioctl(inode, file, cmd, arg, PROC_CONSOLE()));
+	}
+}
+
+static int 
+fb_mmap(struct inode *inode, struct file *file, struct vm_area_struct * vma)
+{
+	struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)];
+	struct fb_fix_screeninfo fix;
+
+	if (! fb)
+		return -ENODEV;
+	fb->fb_get_fix(&fix, PROC_CONSOLE());
+	if ((vma->vm_end - vma->vm_start + vma->vm_offset) > fix.smem_len)
+		return -EINVAL;
+	vma->vm_offset += fix.smem_start;
+	if (vma->vm_offset & ~PAGE_MASK)
+		return -ENXIO;
+	if (boot_info.cputype & CPU_68040)
+		pgprot_val(vma->vm_page_prot) &= _CACHEMASK040;
+	if (remap_page_range(vma->vm_start, vma->vm_offset,
+			     vma->vm_end - vma->vm_start, vma->vm_page_prot))
+		return -EAGAIN;
+	vma->vm_inode = inode;
+	inode->i_count++;
+	return 0;
+}
+
+static int
+fb_open(struct inode *inode, struct file *file)
+{
+	int fbidx=GET_FB_IDX(inode->i_rdev);
+	int vidx=GET_FB_VAR_IDX(inode->i_rdev);
+	struct fb_ops *fb = registered_fb[fbidx];
+	int err;
+	
+	if (! vidx)		/* fb?current always succeeds */ 
+		return 0;
+	if (vidx > registered_fb_var_num[fbidx])
+		return -EINVAL;
+	if (fb_curr_open[fbidx] && fb_curr_open[fbidx] != vidx)
+		return -EBUSY;
+ 	if (file->f_mode & 2) /* only set parameters if opened writeable */
+		if ((err=fb->fb_set_var(registered_fb_var[fbidx] + vidx-1, PROC_CONSOLE())))
+			return err;
+	fb_curr_open[fbidx] = vidx;
+	fb_open_count[fbidx]++;
+	return 0;
+}
+
+static void 
+fb_release(struct inode *inode, struct file *file)
+{
+	int fbidx=GET_FB_IDX(inode->i_rdev);
+	int vidx=GET_FB_VAR_IDX(inode->i_rdev);
+	if (! vidx)
+		return;
+	if (! (--fb_open_count[fbidx]))
+		fb_curr_open[fbidx]=0;
+}
+
+static struct file_operations fb_fops = {
+	NULL,		/* lseek	*/
+	fb_read,	/* read		*/
+	fb_write,	/* write	*/
+	NULL,		/* readdir 	*/
+	NULL,		/* select 	*/
+	fb_ioctl,	/* ioctl 	*/
+	fb_mmap,	/* mmap		*/
+	fb_open,	/* open 	*/
+	fb_release,	/* release 	*/
+	NULL		/* fsync 	*/
+};
+
+int
+register_framebuffer(char *id, int *node, struct fb_ops *fbops, int fbvar_num, 
+		     struct fb_var_screeninfo *fbvar)
+{
+	int i;
+	for (i = 0 ; i < FB_MAX; i++)
+		if (! registered_fb[i])
+			break;
+	if (i == FB_MAX)
+		return -ENXIO;
+	registered_fb[i]=fbops;
+	registered_fb_var[i]=fbvar;
+	registered_fb_var_num[i]=fbvar_num;
+	*node=GET_INODE(i);
+	return 0;
+}
+
+int
+unregister_framebuffer(int node)
+{
+	int i=GET_FB_IDX(node);
+	if (! registered_fb[i])
+		return -EINVAL; 
+	registered_fb[i]=NULL;
+	registered_fb_var[i]=NULL;
+	return 0;
+}
+
+void
+fbmem_init(void)
+{
+	if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
+		printk("unable to get major %d for fb devs\n", FB_MAJOR);
+}
+

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this