Import 2.3.10pre1
[davej-history.git] / drivers / sgi / char / graphics.c
blobde0ecf1f2beeb225036cecd16b8a4542d16caeb8
1 /* $Id: graphics.c,v 1.16 1999/04/01 23:45:00 ulfc 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 <asm/uaccess.h>
37 #include "gconsole.h"
38 #include "graphics.h"
39 #include "usema.h"
40 #include <asm/gfx.h>
41 #include <asm/rrm.h>
42 #include <asm/page.h>
43 #include <asm/pgtable.h>
44 #include <asm/newport.h>
46 #define DEBUG
48 /* The boards */
49 extern struct graphics_ops *newport_probe (int, const char **);
51 static struct graphics_ops cards [MAXCARDS];
52 static int boards;
54 #define GRAPHICS_CARD(inode) 0
57 void enable_gconsole(void) {};
58 void disable_gconsole(void) {};
62 int
63 sgi_graphics_open (struct inode *inode, struct file *file)
65 struct newport_regs *nregs =
66 (struct newport_regs *) KSEG1ADDR(cards[0].g_regs);
68 newport_wait();
69 nregs->set.wrmask = 0xffffffff;
70 nregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
71 NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX |
72 NPORT_DMODE0_STOPY);
73 nregs->set.colori = 1;
74 nregs->set.xystarti = (0 << 16) | 0;
75 nregs->go.xyendi = (1280 << 16) | 1024;
77 return 0;
80 int
81 sgi_graphics_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
83 unsigned int board;
84 unsigned int devnum = GRAPHICS_CARD (inode->i_rdev);
85 int i;
87 if ((cmd >= RRM_BASE) && (cmd <= RRM_CMD_LIMIT))
88 return rrm_command (cmd-RRM_BASE, (void *) arg);
90 switch (cmd){
91 case GFX_GETNUM_BOARDS:
92 return boards;
94 case GFX_GETBOARD_INFO: {
95 struct gfx_getboardinfo_args *bia = (void *) arg;
96 void *dest_buf;
97 int max_len;
99 i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct gfx_getboardinfo_args));
100 if (i) return i;
102 __get_user_ret (board, &bia->board, -EFAULT);
103 __get_user_ret (dest_buf, &bia->buf, -EFAULT);
104 __get_user_ret (max_len, &bia->len, -EFAULT);
106 if (board >= boards)
107 return -EINVAL;
108 if (max_len < sizeof (struct gfx_getboardinfo_args))
109 return -EINVAL;
110 if (max_len > cards [board].g_board_info_len)
111 max_len = cards [boards].g_board_info_len;
112 i = verify_area (VERIFY_WRITE, dest_buf, max_len);
113 if (i) return i;
114 if (copy_to_user (dest_buf, cards [board].g_board_info, max_len))
115 return -EFAULT;
116 return max_len;
119 case GFX_ATTACH_BOARD: {
120 struct gfx_attach_board_args *att = (void *) arg;
121 void *vaddr;
122 int r;
124 i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct gfx_attach_board_args));
125 if (i) return i;
127 __get_user_ret (board, &att->board, -EFAULT);
128 __get_user_ret (vaddr, &att->vaddr, -EFAULT);
130 /* Ok for now we are assuming /dev/graphicsN -> head N even
131 * if the ioctl api suggests that this is not quite the case.
133 * Otherwise we fail, we use this assumption in the mmap code
134 * below to find our board information.
136 if (board != devnum){
137 printk ("Parameter board does not match the current board\n");
138 return -EINVAL;
141 if (board >= boards)
142 return -EINVAL;
144 /* If it is the first opening it, then make it the board owner */
145 if (!cards [board].g_owner)
146 cards [board].g_owner = current;
149 * Ok, we now call mmap on this file, which will end up calling
150 * sgi_graphics_mmap
152 disable_gconsole ();
153 r = do_mmap (file, (unsigned long)vaddr,
154 cards[board].g_regs_size, PROT_READ|PROT_WRITE,
155 MAP_FIXED|MAP_PRIVATE, 0);
156 if (r)
157 return r;
160 /* Strange, the real mapping seems to be done at GFX_ATTACH_BOARD,
161 * GFX_MAPALL is not even used by IRIX X server
163 case GFX_MAPALL:
164 return 0;
166 case GFX_LABEL:
167 return 0;
169 /* Version check
170 * for my IRIX 6.2 X server, this is what the kernel returns
172 case 1:
173 return 3;
175 /* Xsgi does not use this one, I assume minor is the board being queried */
176 case GFX_IS_MANAGED:
177 if (devnum > boards)
178 return -EINVAL;
179 return (cards [devnum].g_owner != 0);
181 default:
182 if (cards [devnum].g_ioctl)
183 return (*cards [devnum].g_ioctl)(devnum, cmd, arg);
186 return -EINVAL;
190 sgi_graphics_close (struct inode *inode, struct file *file)
192 int board = GRAPHICS_CARD (inode->i_rdev);
194 /* Tell the rendering manager that one client is going away */
195 rrm_close (inode, file);
197 /* Was this file handle from the board owner?, clear it */
198 if (current == cards [board].g_owner){
199 cards [board].g_owner = 0;
200 if (cards [board].g_reset_console)
201 (*cards [board].g_reset_console)();
202 enable_gconsole ();
204 return 0;
208 * This is the core of the direct rendering engine.
211 unsigned long
212 sgi_graphics_nopage (struct vm_area_struct *vma, unsigned long address, int
213 no_share)
215 pgd_t *pgd; pmd_t *pmd; pte_t *pte;
216 int board = GRAPHICS_CARD (vma->vm_dentry->d_inode->i_rdev);
218 unsigned long virt_add, phys_add;
220 #ifdef DEBUG
221 printk ("Got a page fault for board %d address=%lx guser=%lx\n", board,
222 address, (unsigned long) cards[board].g_user);
223 #endif
225 /* Figure out if another process has this mapped, and revoke the mapping
226 * in that case. */
227 if (cards[board].g_user && cards[board].g_user != current) {
228 /* FIXME: save graphics context here, dump it to rendering
229 * node? */
231 remove_mapping(cards[board].g_user, vma->vm_start, vma->vm_end);
234 cards [board].g_user = current;
236 /* Map the physical address of the newport registers into the address
237 * space of this process */
239 virt_add = address & PAGE_MASK;
240 phys_add = cards[board].g_regs + virt_add - vma->vm_start;
241 remap_page_range(virt_add, phys_add, PAGE_SIZE, vma->vm_page_prot);
243 pgd = pgd_offset(current->mm, address);
244 pmd = pmd_offset(pgd, address);
245 pte = pte_offset(pmd, address);
246 printk("page: %08lx\n", pte_page(*pte));
247 return pte_page(*pte);
251 * We convert a GFX ioctl for mapping hardware registers, in a nice sys_mmap
252 * call, which takes care of everything that must be taken care of.
256 static struct vm_operations_struct graphics_mmap = {
257 NULL, /* no special mmap-open */
258 NULL, /* no special mmap-close */
259 NULL, /* no special mmap-unmap */
260 NULL, /* no special mmap-protect */
261 NULL, /* no special mmap-sync */
262 NULL, /* no special mmap-advise */
263 sgi_graphics_nopage, /* our magic no-page fault handler */
264 NULL, /* no special mmap-wppage */
265 NULL /* no special mmap-swapout */
269 sgi_graphics_mmap (struct file *file, struct vm_area_struct *vma)
271 uint size;
273 size = vma->vm_end - vma->vm_start;
274 if (vma->vm_offset & ~PAGE_MASK)
275 return -ENXIO;
277 /* 1. Set our special graphic virtualizer */
278 vma->vm_ops = &graphics_mmap;
280 /* 2. Set the special tlb permission bits */
281 vma->vm_page_prot = PAGE_USERIO;
283 /* final setup */
284 vma->vm_file = file;
285 return 0;
288 #if 0
289 /* Do any post card-detection setup on graphics_ops */
290 static void
291 graphics_ops_post_init (int slot)
293 /* There is no owner for the card initially */
294 cards [slot].g_owner = (struct task_struct *) 0;
295 cards [slot].g_user = (struct task_struct *) 0;
297 #endif
299 struct file_operations sgi_graphics_fops = {
300 NULL, /* llseek */
301 NULL, /* read */
302 NULL, /* write */
303 NULL, /* readdir */
304 NULL, /* poll */
305 sgi_graphics_ioctl, /* ioctl */
306 sgi_graphics_mmap, /* mmap */
307 sgi_graphics_open, /* open */
308 NULL, /* flush */
309 sgi_graphics_close, /* release */
310 NULL, /* fsync */
311 NULL, /* check_media_change */
312 NULL, /* revalidate */
313 NULL /* lock */
316 /* /dev/graphics */
317 static struct miscdevice dev_graphics = {
318 SGI_GRAPHICS_MINOR, "sgi-graphics", &sgi_graphics_fops
321 /* /dev/opengl */
322 static struct miscdevice dev_opengl = {
323 SGI_OPENGL_MINOR, "sgi-opengl", &sgi_graphics_fops
326 /* This is called later from the misc-init routine */
327 __initfunc(void gfx_register (void))
329 misc_register (&dev_graphics);
330 misc_register (&dev_opengl);
333 __initfunc(void gfx_init (const char **name))
335 #if 0
336 struct console_ops *console;
337 struct graphics_ops *g;
338 #endif
340 printk ("GFX INIT: ");
341 shmiq_init ();
342 usema_init ();
344 boards++;
346 #if 0
347 if ((g = newport_probe (boards, name)) != 0) {
348 cards [boards] = *g;
349 graphics_ops_post_init (boards);
350 boards++;
351 console = 0;
353 /* Add more graphic drivers here */
354 /* Keep passing console around */
355 #endif
357 if (boards > MAXCARDS)
358 printk (KERN_WARNING "Too many cards found on the system\n");
361 #ifdef MODULE
362 int init_module(void) {
363 static int initiated = 0;
365 printk("SGI Newport Graphics version %i.%i.%i\n",42,54,69);
367 if (!initiated++) {
368 shmiq_init();
369 usema_init();
370 printk("Adding first board\n");
371 boards++;
372 cards[0].g_regs = 0x1f0f0000;
373 cards[0].g_regs_size = sizeof (struct newport_regs);
376 printk("Boards: %d\n", boards);
378 misc_register (&dev_graphics);
379 misc_register (&dev_opengl);
381 return 0;
384 void cleanup_module(void) {
385 printk("Shutting down SGI Newport Graphics\n");
387 misc_deregister (&dev_graphics);
388 misc_deregister (&dev_opengl);
390 #endif