- pre2
[davej-history.git] / drivers / sgi / char / graphics.c
blob46f9402439c2bffc70d9ae53b78e0bd8bd50897e
1 /* $Id: graphics.c,v 1.22 2000/02/18 00:24:43 ralf Exp $
3 * gfx.c: support for SGI's /dev/graphics, /dev/opengl
5 * Author: Miguel de Icaza (miguel@nuclecu.unam.mx)
6 * Ralf Baechle (ralf@gnu.org)
7 * Ulf Carlsson (ulfc@bun.falkenberg.se)
9 * On IRIX, /dev/graphics is [10, 146]
10 * /dev/opengl is [10, 147]
12 * From a mail with Mark J. Kilgard, /dev/opengl and /dev/graphics are
13 * the same thing, the use of /dev/graphics seems deprecated though.
15 * The reason that the original SGI programmer had to use only one
16 * device for all the graphic cards on the system will remain a
17 * mistery for the rest of our lives. Why some ioctls take a board
18 * number and some others not? Mistery. Why do they map the hardware
19 * registers into the user address space with an ioctl instead of
20 * mmap? Mistery too. Why they did not use the standard way of
21 * making ioctl constants and instead sticked a random constant?
22 * Mistery too.
24 * We implement those misterious things, and tried not to think about
25 * the reasons behind them.
27 #include <linux/kernel.h>
28 #include <linux/fs.h>
29 #include <linux/init.h>
30 #include <linux/miscdevice.h>
31 #include <linux/sched.h>
32 #include <linux/mm.h>
33 #include <linux/mman.h>
34 #include <linux/malloc.h>
35 #include <linux/module.h>
36 #include <linux/smp_lock.h>
37 #include <asm/uaccess.h>
38 #include "gconsole.h"
39 #include "graphics.h"
40 #include "usema.h"
41 #include <asm/gfx.h>
42 #include <asm/rrm.h>
43 #include <asm/page.h>
44 #include <asm/pgtable.h>
45 #include <video/newport.h>
47 #define DEBUG
49 /* The boards */
50 extern struct graphics_ops *newport_probe (int, const char **);
52 static struct graphics_ops cards [MAXCARDS];
53 static int boards;
55 #define GRAPHICS_CARD(inode) 0
58 void enable_gconsole(void) {};
59 void disable_gconsole(void) {};
63 int
64 sgi_graphics_open (struct inode *inode, struct file *file)
66 struct newport_regs *nregs =
67 (struct newport_regs *) KSEG1ADDR(cards[0].g_regs);
69 newport_wait();
70 nregs->set.wrmask = 0xffffffff;
71 nregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
72 NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX |
73 NPORT_DMODE0_STOPY);
74 nregs->set.colori = 1;
75 nregs->set.xystarti = (0 << 16) | 0;
76 nregs->go.xyendi = (1280 << 16) | 1024;
78 return 0;
81 int
82 sgi_graphics_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
84 unsigned int board;
85 unsigned int devnum = GRAPHICS_CARD (inode->i_rdev);
86 int i;
88 if ((cmd >= RRM_BASE) && (cmd <= RRM_CMD_LIMIT))
89 return rrm_command (cmd-RRM_BASE, (void *) arg);
91 switch (cmd){
92 case GFX_GETNUM_BOARDS:
93 return boards;
95 case GFX_GETBOARD_INFO: {
96 struct gfx_getboardinfo_args *bia = (void *) arg;
97 void *dest_buf;
98 int max_len;
100 i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct gfx_getboardinfo_args));
101 if (i) return i;
103 if (__get_user (board, &bia->board) ||
104 __get_user (dest_buf, &bia->buf) ||
105 __get_user (max_len, &bia->len))
106 return -EFAULT;
108 if (board >= boards)
109 return -EINVAL;
110 if (max_len < sizeof (struct gfx_getboardinfo_args))
111 return -EINVAL;
112 if (max_len > cards [board].g_board_info_len)
113 max_len = cards [boards].g_board_info_len;
114 i = verify_area (VERIFY_WRITE, dest_buf, max_len);
115 if (i) return i;
116 if (copy_to_user (dest_buf, cards [board].g_board_info, max_len))
117 return -EFAULT;
118 return max_len;
121 case GFX_ATTACH_BOARD: {
122 struct gfx_attach_board_args *att = (void *) arg;
123 void *vaddr;
124 int r;
126 i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct gfx_attach_board_args));
127 if (i) return i;
129 if (__get_user (board, &att->board) ||
130 __get_user (vaddr, &att->vaddr))
131 return -EFAULT;
133 /* Ok for now we are assuming /dev/graphicsN -> head N even
134 * if the ioctl api suggests that this is not quite the case.
136 * Otherwise we fail, we use this assumption in the mmap code
137 * below to find our board information.
139 if (board != devnum){
140 printk ("Parameter board does not match the current board\n");
141 return -EINVAL;
144 if (board >= boards)
145 return -EINVAL;
147 /* If it is the first opening it, then make it the board owner */
148 if (!cards [board].g_owner)
149 cards [board].g_owner = current;
152 * Ok, we now call mmap on this file, which will end up calling
153 * sgi_graphics_mmap
155 disable_gconsole ();
156 down(&current->mm->mmap_sem);
157 r = do_mmap (file, (unsigned long)vaddr,
158 cards[board].g_regs_size, PROT_READ|PROT_WRITE,
159 MAP_FIXED|MAP_PRIVATE, 0);
160 up(&current->mm->mmap_sem);
161 if (r)
162 return r;
165 /* Strange, the real mapping seems to be done at GFX_ATTACH_BOARD,
166 * GFX_MAPALL is not even used by IRIX X server
168 case GFX_MAPALL:
169 return 0;
171 case GFX_LABEL:
172 return 0;
174 /* Version check
175 * for my IRIX 6.2 X server, this is what the kernel returns
177 case 1:
178 return 3;
180 /* Xsgi does not use this one, I assume minor is the board being queried */
181 case GFX_IS_MANAGED:
182 if (devnum > boards)
183 return -EINVAL;
184 return (cards [devnum].g_owner != 0);
186 default:
187 if (cards [devnum].g_ioctl)
188 return (*cards [devnum].g_ioctl)(devnum, cmd, arg);
191 return -EINVAL;
195 sgi_graphics_close (struct inode *inode, struct file *file)
197 int board = GRAPHICS_CARD (inode->i_rdev);
199 /* Tell the rendering manager that one client is going away */
200 lock_kernel();
201 rrm_close (inode, file);
203 /* Was this file handle from the board owner?, clear it */
204 if (current == cards [board].g_owner){
205 cards [board].g_owner = 0;
206 if (cards [board].g_reset_console)
207 (*cards [board].g_reset_console)();
208 enable_gconsole ();
210 unlock_kernel();
211 return 0;
215 * This is the core of the direct rendering engine.
218 unsigned long
219 sgi_graphics_nopage (struct vm_area_struct *vma, unsigned long address, int
220 no_share)
222 pgd_t *pgd; pmd_t *pmd; pte_t *pte;
223 int board = GRAPHICS_CARD (vma->vm_dentry->d_inode->i_rdev);
225 unsigned long virt_add, phys_add;
227 #ifdef DEBUG
228 printk ("Got a page fault for board %d address=%lx guser=%lx\n", board,
229 address, (unsigned long) cards[board].g_user);
230 #endif
232 /* Figure out if another process has this mapped, and revoke the mapping
233 * in that case. */
234 if (cards[board].g_user && cards[board].g_user != current) {
235 /* FIXME: save graphics context here, dump it to rendering
236 * node? */
238 remove_mapping(cards[board].g_user, vma->vm_start, vma->vm_end);
241 cards [board].g_user = current;
243 /* Map the physical address of the newport registers into the address
244 * space of this process */
246 virt_add = address & PAGE_MASK;
247 phys_add = cards[board].g_regs + virt_add - vma->vm_start;
248 remap_page_range(virt_add, phys_add, PAGE_SIZE, vma->vm_page_prot);
250 pgd = pgd_offset(current->mm, address);
251 pmd = pmd_offset(pgd, address);
252 pte = pte_offset(pmd, address);
253 printk("page: %08lx\n", pte_page(*pte));
254 return pte_page(*pte);
258 * We convert a GFX ioctl for mapping hardware registers, in a nice sys_mmap
259 * call, which takes care of everything that must be taken care of.
263 static struct vm_operations_struct graphics_mmap = {
264 nopage: sgi_graphics_nopage, /* our magic no-page fault handler */
268 sgi_graphics_mmap (struct file *file, struct vm_area_struct *vma)
270 uint size;
272 size = vma->vm_end - vma->vm_start;
274 /* 1. Set our special graphic virtualizer */
275 vma->vm_ops = &graphics_mmap;
277 /* 2. Set the special tlb permission bits */
278 vma->vm_page_prot = PAGE_USERIO;
280 /* final setup */
281 vma->vm_file = file;
282 return 0;
285 #if 0
286 /* Do any post card-detection setup on graphics_ops */
287 static void
288 graphics_ops_post_init (int slot)
290 /* There is no owner for the card initially */
291 cards [slot].g_owner = (struct task_struct *) 0;
292 cards [slot].g_user = (struct task_struct *) 0;
294 #endif
296 struct file_operations sgi_graphics_fops = {
297 ioctl: sgi_graphics_ioctl,
298 mmap: sgi_graphics_mmap,
299 open: sgi_graphics_open,
300 release: sgi_graphics_close,
303 /* /dev/graphics */
304 static struct miscdevice dev_graphics = {
305 SGI_GRAPHICS_MINOR, "sgi-graphics", &sgi_graphics_fops
308 /* /dev/opengl */
309 static struct miscdevice dev_opengl = {
310 SGI_OPENGL_MINOR, "sgi-opengl", &sgi_graphics_fops
313 /* This is called later from the misc-init routine */
314 void __init gfx_register (void)
316 misc_register (&dev_graphics);
317 misc_register (&dev_opengl);
320 void __init gfx_init (const char **name)
322 #if 0
323 struct console_ops *console;
324 struct graphics_ops *g;
325 #endif
327 printk ("GFX INIT: ");
328 shmiq_init ();
329 usema_init ();
331 boards++;
333 #if 0
334 if ((g = newport_probe (boards, name)) != 0) {
335 cards [boards] = *g;
336 graphics_ops_post_init (boards);
337 boards++;
338 console = 0;
340 /* Add more graphic drivers here */
341 /* Keep passing console around */
342 #endif
344 if (boards > MAXCARDS)
345 printk (KERN_WARNING "Too many cards found on the system\n");
348 #ifdef MODULE
349 int init_module(void) {
350 static int initiated = 0;
352 printk("SGI Newport Graphics version %i.%i.%i\n",42,54,69);
354 if (!initiated++) {
355 shmiq_init();
356 usema_init();
357 printk("Adding first board\n");
358 boards++;
359 cards[0].g_regs = 0x1f0f0000;
360 cards[0].g_regs_size = sizeof (struct newport_regs);
363 printk("Boards: %d\n", boards);
365 misc_register (&dev_graphics);
366 misc_register (&dev_opengl);
368 return 0;
371 void cleanup_module(void) {
372 printk("Shutting down SGI Newport Graphics\n");
374 misc_deregister (&dev_graphics);
375 misc_deregister (&dev_opengl);
377 #endif