diff options
Diffstat (limited to 'drivers/sgi/char')
-rw-r--r-- | drivers/sgi/char/Makefile | 3 | ||||
-rw-r--r-- | drivers/sgi/char/cons_newport.c | 14 | ||||
-rw-r--r-- | drivers/sgi/char/gconsole.h | 6 | ||||
-rw-r--r-- | drivers/sgi/char/graphics.c | 180 | ||||
-rw-r--r-- | drivers/sgi/char/graphics.h | 23 | ||||
-rw-r--r-- | drivers/sgi/char/newport.h | 4 | ||||
-rw-r--r-- | drivers/sgi/char/rrm.c | 69 | ||||
-rw-r--r-- | drivers/sgi/char/sgicons.c | 39 |
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 |