summaryrefslogtreecommitdiffstats
path: root/drivers/sgi/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/sgi/char')
-rw-r--r--drivers/sgi/char/Makefile3
-rw-r--r--drivers/sgi/char/cons_newport.c14
-rw-r--r--drivers/sgi/char/gconsole.h6
-rw-r--r--drivers/sgi/char/graphics.c180
-rw-r--r--drivers/sgi/char/graphics.h23
-rw-r--r--drivers/sgi/char/newport.h4
-rw-r--r--drivers/sgi/char/rrm.c69
-rw-r--r--drivers/sgi/char/sgicons.c39
8 files changed, 298 insertions, 40 deletions
diff --git a/drivers/sgi/char/Makefile b/drivers/sgi/char/Makefile
index 8877d3996..d5a0110df 100644
--- a/drivers/sgi/char/Makefile
+++ b/drivers/sgi/char/Makefile
@@ -8,7 +8,8 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
O_TARGET := sgichar.o
-O_OBJS := graphics.o streamable.o newport.o cons_newport.o sgicons.o vga_font.o
+O_OBJS := graphics.o streamable.o newport.o cons_newport.o sgicons.o \
+ vga_font.o rrm.o
ifeq ($(CONFIG_SGI_SERIAL),y)
O_OBJS += sgiserial.o
diff --git a/drivers/sgi/char/cons_newport.c b/drivers/sgi/char/cons_newport.c
index 94c61ec91..154ffdb57 100644
--- a/drivers/sgi/char/cons_newport.c
+++ b/drivers/sgi/char/cons_newport.c
@@ -1,4 +1,4 @@
-/* $Id: newport.c,v 1.2 1997/06/17 11:15:12 ralf Exp $
+/* $Id: cons_newport.c,v 1.1 1997/07/02 06:20:17 miguel Exp $
* cons_newport.c: Newport graphics console code for the SGI.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -541,14 +541,15 @@ struct ng1_info newport_board_info = {
/* right now the newport does not do anything at all */
struct graphics_ops newport_graphic_ops = {
0, /* owner */
-
+ 0, /* current user */
(void *) &newport_board_info, /* board info */
sizeof (struct ng1_info), /* size of our data structure */
+ 0, 0, /* g_regs, g_regs_size */
0, 0 /* save_context, restore_context */
};
struct graphics_ops *
-newport_probe (int slot, struct console_ops *cops, char **name)
+newport_probe (int slot, const char **name)
{
struct newport_regs *p;
@@ -567,9 +568,8 @@ newport_probe (int slot, struct console_ops *cops, char **name)
return 0;
}
- /* It may be null if we are not the first graphics card on the system */
- if (cops != NULL){
- *cops = newport_console;
+ if (slot == 0){
+ register_gconsole (&newport_console);
video_type = VIDEO_TYPE_SGI;
can_do_color = 1;
*name = "NEWPORT";
@@ -594,5 +594,7 @@ newport_probe (int slot, struct console_ops *cops, char **name)
#if 0
newport_render_logo();
#endif
+ newport_graphic_ops.g_regs = 0x1f0f0000;
+ newport_graphic_ops.g_regs_size = sizeof (struct newport_regs);
return &newport_graphic_ops;
}
diff --git a/drivers/sgi/char/gconsole.h b/drivers/sgi/char/gconsole.h
index bfdfbffa3..e629fe9fc 100644
--- a/drivers/sgi/char/gconsole.h
+++ b/drivers/sgi/char/gconsole.h
@@ -18,10 +18,12 @@ struct console_ops {
void (*memcpyw)(unsigned short *to, unsigned short *from, unsigned int count);
};
+void register_gconsole (struct console_ops *);
+
/* This points to the system console */
-extern struct console_ops gconsole;
+extern struct console_ops *gconsole;
-extern void gfx_init (char **name);
+extern void gfx_init (const char **name);
extern void __set_origin (unsigned short offset);
extern void hide_cursor (void);
diff --git a/drivers/sgi/char/graphics.c b/drivers/sgi/char/graphics.c
index 4d2e70993..a454eda6f 100644
--- a/drivers/sgi/char/graphics.c
+++ b/drivers/sgi/char/graphics.c
@@ -1,26 +1,44 @@
/*
* gfx.c: support for SGI's /dev/graphics, /dev/opengl
- * (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * Author: Miguel de Icaza (miguel@nuclecu.unam.mx)
*
* On IRIX, /dev/graphics is [57, 0]
* /dev/opengl is [57, 1]
*
- * From a mail with Mark Kilgard, /dev/opengl and /dev/graphics are
+ * From a mail with Mark J. Kilgard, /dev/opengl and /dev/graphics are
* the same thing, the use of /dev/graphics seems deprecated though.
+ *
+ * The reason that the original SGI programmer had to use only one
+ * device for all the graphic cards on the system will remain a
+ * mistery for the rest of our lives. Why some ioctls take a board
+ * number and some others not? Mistery. Why do they map the hardware
+ * registers into the user address space with an ioctl instead of
+ * mmap? Mistery too. Why they did not use the standard way of
+ * making ioctl constants and instead sticked a random constant?
+ * Mistery too.
+ *
+ * We implement those misterious things, and tried not to think about
+ * the reasons behind them.
*/
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
#include <asm/uaccess.h>
#include "gconsole.h"
#include "graphics.h"
#include <asm/gfx.h>
+#include <asm/rrm.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
/* The boards */
#include "newport.h"
-static int boards;
static struct graphics_ops cards [MAXCARDS];
+static int boards;
int
sgi_graphics_open (struct inode *inode, struct file *file)
@@ -31,15 +49,19 @@ sgi_graphics_open (struct inode *inode, struct file *file)
int
sgi_graphics_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
+ unsigned int board;
+ unsigned int minor = MINOR (inode->i_rdev);
int i;
+ if ((cmd >= RRM_BASE) && (cmd <= RRM_CMD_LIMIT))
+ return rrm_command (cmd-RRM_BASE, (void *) arg);
+
switch (cmd){
case GFX_GETNUM_BOARDS:
return boards;
case GFX_GETBOARD_INFO: {
struct gfx_getboardinfo_args *bia = (void *) arg;
- int board;
void *dest_buf;
int max_len;
@@ -54,14 +76,67 @@ sgi_graphics_ioctl (struct inode *inode, struct file *file, unsigned int cmd, un
return -EINVAL;
if (max_len < sizeof (struct gfx_getboardinfo_args))
return -EINVAL;
- if (max_len > cards [board].board_info_len)
- max_len = cards [boards].board_info_len;
+ if (max_len > cards [board].g_board_info_len)
+ max_len = cards [boards].g_board_info_len;
i = verify_area (VERIFY_WRITE, dest_buf, max_len);
if (i) return i;
- if (copy_to_user (dest_buf, cards [board].board_info, max_len))
+ if (copy_to_user (dest_buf, cards [board].g_board_info, max_len))
return -EFAULT;
return max_len;
}
+
+ case GFX_ATTACH_BOARD: {
+ struct gfx_attach_board_args *att = (void *) arg;
+ void *vaddr;
+ int r;
+
+ i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct gfx_attach_board_args));
+ if (i) return i;
+
+ __get_user_ret (board, &att->board, -EFAULT);
+ __get_user_ret (vaddr, &att->vaddr, -EFAULT);
+
+ /* Ok for now we are assuming /dev/graphicsN -> head N even
+ * if the ioctl api suggests that this is not quite the case.
+ *
+ * Otherwise we fail, we use this assumption in the mmap code
+ * below to find our board information.
+ */
+ if (board != minor){
+ printk ("Parameter board does not match minor\n");
+ return -EINVAL;
+ }
+
+ if (board >= boards)
+ return -EINVAL;
+
+ /* If it is the first opening it, then make it the board owner */
+ if (!cards [board].g_owner)
+ cards [board].g_owner = current;
+
+ /*
+ * Ok, we now call mmap on this file, which will end up calling
+ * sgi_graphics_mmap
+ */
+ r = do_mmap (file, (unsigned long)vaddr, cards [board].g_regs_size,
+ PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE, 0);
+ if (r)
+ return r;
+ }
+
+ /* Strange, the real mapping seems to be done at GFX_ATTACH_BOARD,
+ * GFX_MAPALL is not even used by IRIX X server
+ */
+ case GFX_MAPALL:
+ return 0;
+
+ /* Xsgi does not use this one, I assume minor is the board being queried */
+ case GFX_IS_MANAGED:
+ if (minor > boards)
+ return -EINVAL;
+ return (cards [minor].g_owner != 0);
+
+
} /* ioctl switch (cmd) */
return -EINVAL;
@@ -70,15 +145,95 @@ sgi_graphics_ioctl (struct inode *inode, struct file *file, unsigned int cmd, un
int
sgi_graphics_close (struct inode *inode, struct file *file)
{
+ int minor = MINOR (inode->i_rdev);
+
+ /* Tell the rendering manager that one client is going away */
+ rrm_close (inode, file);
+
+ /* Was this file handle from the board owner?, clear it */
+ if (current == cards [minor].g_owner)
+ cards [minor].g_owner = 0;
+
return 0;
}
+/*
+ * This is the core of the direct rendering engine.
+ */
+
+unsigned long
+sgi_graphics_nopage (struct vm_area_struct *vma, unsigned long address, int write_access)
+{
+ unsigned long page;
+ int board = MINOR (vma->vm_inode->i_rdev);
+
+ printk ("Got a page fault for board %d\n", board);
+
+ if (current == cards [board].g_user){
+ printk ("Mhm, strange, graphics registers should be already mapped\n");
+
+ /* force a segfault */
+ return 0;
+ }
+
+ /* 1. figure out if another process has this mapped,
+ * and revoke the mapping in that case.
+ */
+ if (cards [board].g_user)
+ remove_mapping (cards [board].g_user, vma->vm_start, vma->vm_end);
+
+ /* 2. Map this into the current process address space */
+ page = ((cards [board].g_regs) + (vma->vm_start - address));
+ return page >> PAGE_SHIFT;
+}
+
+/*
+ * We convert a GFX ioctl for mapping hardware registers, in a nice sys_mmap
+ * call, which takes care of everything that must be taken care of.
+ *
+ */
+
+static struct vm_operations_struct graphics_mmap = {
+ NULL, /* no special mmap-open */
+ NULL, /* no special mmap-close */
+ NULL, /* no special mmap-unmap */
+ NULL, /* no special mmap-protect */
+ NULL, /* no special mmap-sync */
+ NULL, /* no special mmap-advise */
+ sgi_graphics_nopage, /* our magic no-page fault handler */
+ NULL, /* no special mmap-wppage */
+ NULL, /* no special mmap-swapout */
+ NULL /* no special mmap-swapin */
+};
+
+int
+sgi_graphics_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma)
+{
+ uint size;
+
+ size = vma->vm_end - vma->vm_start;
+ if (vma->vm_offset & ~PAGE_MASK)
+ return -ENXIO;
+
+ /* 1. Set our special graphic virtualizer */
+ vma->vm_ops = &graphics_mmap;
+
+ /* 2. Set the special tlb permission bits */
+ vma->vm_page_prot = PAGE_USERIO;
+
+ /* final setup */
+ vma->vm_inode = inode;
+ atomic_inc (&inode->i_count);
+ return 0;
+}
+
/* Do any post card-detection setup on graphics_ops */
static void
graphics_ops_post_init (int slot)
{
/* There is no owner for the card initially */
- cards [slot].owner = (struct task_struct *) 0;
+ cards [slot].g_owner = (struct task_struct *) 0;
+ cards [slot].g_user = (struct task_struct *) 0;
}
struct file_operations sgi_graphics_fops = {
@@ -88,7 +243,7 @@ struct file_operations sgi_graphics_fops = {
NULL, /* readdir */
NULL, /* poll */
sgi_graphics_ioctl, /* ioctl */
- NULL, /* mmap */
+ sgi_graphics_mmap, /* mmap */
sgi_graphics_open, /* open */
sgi_graphics_close, /* release */
NULL, /* fsync */
@@ -108,14 +263,12 @@ static struct miscdevice dev_opengl = {
};
void
-gfx_init (char **name)
+gfx_init (const char **name)
{
struct console_ops *console;
struct graphics_ops *g;
- console = &gconsole;
-
- if ((g = newport_probe (boards, console, name)) != 0){
+ if ((g = newport_probe (boards, name)) != 0){
cards [boards] = *g;
graphics_ops_post_init (boards);
boards++;
@@ -136,3 +289,4 @@ gfx_register (void)
misc_register (&dev_graphics);
misc_register (&dev_opengl);
}
+
diff --git a/drivers/sgi/char/graphics.h b/drivers/sgi/char/graphics.h
index 6a26e785d..a0477df1e 100644
--- a/drivers/sgi/char/graphics.h
+++ b/drivers/sgi/char/graphics.h
@@ -1,12 +1,23 @@
#define MAXCARDS 4
struct graphics_ops {
- struct task_struct *owner;
+ /* SGIism: Board owner, gets the shmiq requests from the kernel */
+ struct task_struct *g_owner;
- /* Board info */
- void *board_info;
- int board_info_len;
+ /* Last process that got the graphics registers mapped */
+ struct task_struct *g_user;
- void (*save_context)(void);
- void (*restore_context)(void);
+ /* Board info */
+ void *g_board_info;
+ int g_board_info_len;
+
+ /* These point to hardware registers that should be mapped with
+ * GFX_ATTACH_BOARD and the size of the information pointed to
+ */
+ unsigned long g_regs;
+ int g_regs_size;
+
+ void (*g_save_context)(void);
+ void (*g_restore_context)(void);
};
+
diff --git a/drivers/sgi/char/newport.h b/drivers/sgi/char/newport.h
index 440e9b452..582305bd8 100644
--- a/drivers/sgi/char/newport.h
+++ b/drivers/sgi/char/newport.h
@@ -1,4 +1,4 @@
-/* $Id: newport.h,v 1.1.1.1 1997/06/01 03:17:26 ralf Exp $
+/* $Id: newport.h,v 1.2 1997/07/02 06:20:19 miguel Exp $
* newport.h: Defines and register layout for NEWPORT graphics
* hardware.
*
@@ -406,6 +406,6 @@ static inline int newport_bfwait(void)
return 0;
}
-extern struct graphics_ops *newport_probe (int, struct console_ops *, char **);
+extern struct graphics_ops *newport_probe (int, const char **);
#endif /* !(_SGI_NEWPORT_H) */
diff --git a/drivers/sgi/char/rrm.c b/drivers/sgi/char/rrm.c
new file mode 100644
index 000000000..b13c79588
--- /dev/null
+++ b/drivers/sgi/char/rrm.c
@@ -0,0 +1,69 @@
+/*
+ * Linux Rendering Resource Manager
+ *
+ * Implements the SGI-compatible rendering resource manager.
+ * This takes care of implementing the virtualized video hardware
+ * access required for OpenGL direct rendering.
+ *
+ * Author: Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * Fixes:
+ */
+#include <asm/uaccess.h>
+#include <asm/rrm.h>
+
+int
+rrm_open_rn (int rnid, void *arg)
+{
+ return 0;
+}
+
+int
+rrm_close_rn (int rnid, void *arg)
+{
+ return 0;
+}
+
+int
+rrm_bind_proc_to_rn (int rnid, void *arg)
+{
+ return 0;
+}
+
+typedef int (*rrm_function )(void *arg);
+
+struct {
+ int (*r_fn)(int rnid, void *arg);
+ int arg_size;
+} rrm_functions [] = {
+ { rrm_open_rn, sizeof (struct RRM_OpenRN) },
+ { rrm_close_rn, sizeof (struct RRM_CloseRN) },
+ { rrm_bind_proc_to_rn, sizeof (struct RRM_BindProcToRN) }
+};
+
+#define RRM_FUNCTIONS (sizeof (rrm_functions)/sizeof (rrm_functions [0]))
+
+/* cmd is a number in the range [0..RRM_CMD_LIMIT-RRM_BASE] */
+int
+rrm_command (unsigned int cmd, void *arg)
+{
+ int i, rnid;
+
+ if (cmd > RRM_FUNCTIONS){
+ printk ("Called unimplemented rrm ioctl: %d\n", cmd + RRM_BASE);
+ return -EINVAL;
+ }
+ i = verify_area (VERIFY_READ, arg, rrm_functions [cmd].arg_size);
+ if (i) return i;
+
+ __get_user_ret (rnid, (int *) arg, -EFAULT);
+ return (*(rrm_functions [cmd].r_fn))(rnid, arg);
+}
+
+int
+rrm_close (struct inode *inode, struct file *file)
+{
+ /* This routine is invoked when the device is closed */
+ return 0;
+}
+
diff --git a/drivers/sgi/char/sgicons.c b/drivers/sgi/char/sgicons.c
index 7f8882cda..daf1b8fce 100644
--- a/drivers/sgi/char/sgicons.c
+++ b/drivers/sgi/char/sgicons.c
@@ -17,60 +17,79 @@
#include "gconsole.h"
/* This is the system graphics console (the first adapter found) */
-struct console_ops gconsole;
+struct console_ops *gconsole = 0;
+
+void
+register_gconsole (struct console_ops *gc)
+{
+ if (gconsole)
+ return;
+ gconsole = gc;
+}
void
__set_origin (unsigned short offset)
{
- (*gconsole.set_origin)(offset);
+ if (gconsole)
+ (*gconsole->set_origin)(offset);
}
void
hide_cursor (void)
{
- (*gconsole.hide_cursor)();
+
+ if (gconsole)
+ (*gconsole->hide_cursor)();
}
void
set_cursor (int currcons)
{
- (*gconsole.set_cursor)(currcons);
+ if (gconsole)
+ (*gconsole->set_cursor)(currcons);
}
void
get_scrmem (int currcons)
{
- (*gconsole.get_scrmem)(currcons);
+ if (gconsole)
+ (*gconsole->get_scrmem)(currcons);
}
void
set_scrmem (int currcons, long offset)
{
- (*gconsole.set_scrmem)(currcons, offset);
+ if (gconsole)
+ (*gconsole->set_scrmem)(currcons, offset);
}
int
set_get_cmap (unsigned char *arg, int set)
{
- return (*gconsole.set_get_cmap)(arg, set);
+ if (gconsole)
+ return (*gconsole->set_get_cmap)(arg, set);
+ return 0;
}
void
blitc (unsigned short charattr, unsigned long addr)
{
- (*gconsole.blitc)(charattr, addr);
+ if (gconsole)
+ (*gconsole->blitc)(charattr, addr);
}
void
memsetw (void *s, unsigned short c, unsigned int count)
{
- (*gconsole.memsetw)(s, c, count);
+ if (gconsole)
+ (*gconsole->memsetw)(s, c, count);
}
void
memcpyw (unsigned short *to, unsigned short *from, unsigned int count)
{
- (*gconsole.memcpyw)(to, from, count);
+ if (gconsole)
+ (*gconsole->memcpyw)(to, from, count);
}
int