From fee03799b95240471d9007e4ccd2d6aad73c6450 Mon Sep 17 00:00:00 2001 From: Miguel de Icaza Date: Wed, 16 Jul 1997 02:50:37 +0000 Subject: o Implement /dev/graphics virtualizable access to registers. The actual context switch code is not yet there. But the rest of the magic (mapping/unmapping the registers on demand is already in). o Interface for allowing binary-only console modules added. o My RRM bits, nothing really interesting now. For now, I am assuming in the code that there will be a minor per real graphics device, and that the X server will go and open /dev/graphicsN instead of opening /dev/graphics and using the gfx_attach_board->board variable. The interface the X server uses is not clear. I believe it will be pretty easy to provide the stripped down shmiq interface. Not only that, but we can even provide the same ABI (yes, ABI) for SGI shmiq input modules (yep, looks pretty easy once you have an strace that shows this information). Now, the only thing missing is figuring what is wrong my current conception of the use of shmiq. I just can't get it. --- drivers/sgi/char/Makefile | 3 +- drivers/sgi/char/cons_newport.c | 14 ++-- drivers/sgi/char/gconsole.h | 6 +- drivers/sgi/char/graphics.c | 180 +++++++++++++++++++++++++++++++++++++--- drivers/sgi/char/graphics.h | 23 +++-- drivers/sgi/char/newport.h | 4 +- drivers/sgi/char/rrm.c | 69 +++++++++++++++ drivers/sgi/char/sgicons.c | 39 ++++++--- 8 files changed, 298 insertions(+), 40 deletions(-) create mode 100644 drivers/sgi/char/rrm.c (limited to 'drivers') 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 #include #include +#include +#include #include #include "gconsole.h" #include "graphics.h" #include +#include +#include +#include /* 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 +#include + +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 -- cgit v1.2.3