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?
24 * We implement those misterious things, and tried not to think about
25 * the reasons behind them.
27 #include <linux/kernel.h>
29 #include <linux/init.h>
30 #include <linux/miscdevice.h>
31 #include <linux/sched.h>
33 #include <linux/mman.h>
34 #include <linux/malloc.h>
35 #include <linux/module.h>
36 #include <asm/uaccess.h>
43 #include <asm/pgtable.h>
44 #include <asm/newport.h>
49 extern struct graphics_ops
*newport_probe (int, const char **);
51 static struct graphics_ops cards
[MAXCARDS
];
54 #define GRAPHICS_CARD(inode) 0
57 void enable_gconsole(void) {};
58 void disable_gconsole(void) {};
63 sgi_graphics_open (struct inode
*inode
, struct file
*file
)
65 struct newport_regs
*nregs
=
66 (struct newport_regs
*) KSEG1ADDR(cards
[0].g_regs
);
69 nregs
->set
.wrmask
= 0xffffffff;
70 nregs
->set
.drawmode0
= (NPORT_DMODE0_DRAW
| NPORT_DMODE0_BLOCK
|
71 NPORT_DMODE0_DOSETUP
| NPORT_DMODE0_STOPX
|
73 nregs
->set
.colori
= 1;
74 nregs
->set
.xystarti
= (0 << 16) | 0;
75 nregs
->go
.xyendi
= (1280 << 16) | 1024;
81 sgi_graphics_ioctl (struct inode
*inode
, struct file
*file
, unsigned int cmd
, unsigned long arg
)
84 unsigned int devnum
= GRAPHICS_CARD (inode
->i_rdev
);
87 if ((cmd
>= RRM_BASE
) && (cmd
<= RRM_CMD_LIMIT
))
88 return rrm_command (cmd
-RRM_BASE
, (void *) arg
);
91 case GFX_GETNUM_BOARDS
:
94 case GFX_GETBOARD_INFO
: {
95 struct gfx_getboardinfo_args
*bia
= (void *) arg
;
99 i
= verify_area (VERIFY_READ
, (void *) arg
, sizeof (struct gfx_getboardinfo_args
));
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
);
108 if (max_len
< sizeof (struct gfx_getboardinfo_args
))
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
);
114 if (copy_to_user (dest_buf
, cards
[board
].g_board_info
, max_len
))
119 case GFX_ATTACH_BOARD
: {
120 struct gfx_attach_board_args
*att
= (void *) arg
;
124 i
= verify_area (VERIFY_READ
, (void *)arg
, sizeof (struct gfx_attach_board_args
));
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");
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
153 r
= do_mmap (file
, (unsigned long)vaddr
,
154 cards
[board
].g_regs_size
, PROT_READ
|PROT_WRITE
,
155 MAP_FIXED
|MAP_PRIVATE
, 0);
160 /* Strange, the real mapping seems to be done at GFX_ATTACH_BOARD,
161 * GFX_MAPALL is not even used by IRIX X server
170 * for my IRIX 6.2 X server, this is what the kernel returns
175 /* Xsgi does not use this one, I assume minor is the board being queried */
179 return (cards
[devnum
].g_owner
!= 0);
182 if (cards
[devnum
].g_ioctl
)
183 return (*cards
[devnum
].g_ioctl
)(devnum
, cmd
, arg
);
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
)();
208 * This is the core of the direct rendering engine.
212 sgi_graphics_nopage (struct vm_area_struct
*vma
, unsigned long address
, int
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
;
221 printk ("Got a page fault for board %d address=%lx guser=%lx\n", board
,
222 address
, (unsigned long) cards
[board
].g_user
);
225 /* Figure out if another process has this mapped, and revoke the mapping
227 if (cards
[board
].g_user
&& cards
[board
].g_user
!= current
) {
228 /* FIXME: save graphics context here, dump it to rendering
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
)
273 size
= vma
->vm_end
- vma
->vm_start
;
274 if (vma
->vm_offset
& ~PAGE_MASK
)
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
;
289 /* Do any post card-detection setup on graphics_ops */
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;
299 struct file_operations sgi_graphics_fops
= {
305 sgi_graphics_ioctl
, /* ioctl */
306 sgi_graphics_mmap
, /* mmap */
307 sgi_graphics_open
, /* open */
309 sgi_graphics_close
, /* release */
311 NULL
, /* check_media_change */
312 NULL
, /* revalidate */
317 static struct miscdevice dev_graphics
= {
318 SGI_GRAPHICS_MINOR
, "sgi-graphics", &sgi_graphics_fops
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
))
336 struct console_ops
*console
;
337 struct graphics_ops
*g
;
340 printk ("GFX INIT: ");
347 if ((g
= newport_probe (boards
, name
)) != 0) {
349 graphics_ops_post_init (boards
);
353 /* Add more graphic drivers here */
354 /* Keep passing console around */
357 if (boards
> MAXCARDS
)
358 printk (KERN_WARNING
"Too many cards found on the system\n");
362 int init_module(void) {
363 static int initiated
= 0;
365 printk("SGI Newport Graphics version %i.%i.%i\n",42,54,69);
370 printk("Adding first board\n");
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
);
384 void cleanup_module(void) {
385 printk("Shutting down SGI Newport Graphics\n");
387 misc_deregister (&dev_graphics
);
388 misc_deregister (&dev_opengl
);