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?
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 <linux/smp_lock.h>
37 #include <asm/uaccess.h>
44 #include <asm/pgtable.h>
45 #include <video/newport.h>
50 extern struct graphics_ops
*newport_probe (int, const char **);
52 static struct graphics_ops cards
[MAXCARDS
];
55 #define GRAPHICS_CARD(inode) 0
58 void enable_gconsole(void) {};
59 void disable_gconsole(void) {};
64 sgi_graphics_open (struct inode
*inode
, struct file
*file
)
66 struct newport_regs
*nregs
=
67 (struct newport_regs
*) KSEG1ADDR(cards
[0].g_regs
);
70 nregs
->set
.wrmask
= 0xffffffff;
71 nregs
->set
.drawmode0
= (NPORT_DMODE0_DRAW
| NPORT_DMODE0_BLOCK
|
72 NPORT_DMODE0_DOSETUP
| NPORT_DMODE0_STOPX
|
74 nregs
->set
.colori
= 1;
75 nregs
->set
.xystarti
= (0 << 16) | 0;
76 nregs
->go
.xyendi
= (1280 << 16) | 1024;
82 sgi_graphics_ioctl (struct inode
*inode
, struct file
*file
, unsigned int cmd
, unsigned long arg
)
85 unsigned int devnum
= GRAPHICS_CARD (inode
->i_rdev
);
88 if ((cmd
>= RRM_BASE
) && (cmd
<= RRM_CMD_LIMIT
))
89 return rrm_command (cmd
-RRM_BASE
, (void *) arg
);
92 case GFX_GETNUM_BOARDS
:
95 case GFX_GETBOARD_INFO
: {
96 struct gfx_getboardinfo_args
*bia
= (void *) arg
;
100 i
= verify_area (VERIFY_READ
, (void *) arg
, sizeof (struct gfx_getboardinfo_args
));
103 if (__get_user (board
, &bia
->board
) ||
104 __get_user (dest_buf
, &bia
->buf
) ||
105 __get_user (max_len
, &bia
->len
))
110 if (max_len
< sizeof (struct gfx_getboardinfo_args
))
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
);
116 if (copy_to_user (dest_buf
, cards
[board
].g_board_info
, max_len
))
121 case GFX_ATTACH_BOARD
: {
122 struct gfx_attach_board_args
*att
= (void *) arg
;
126 i
= verify_area (VERIFY_READ
, (void *)arg
, sizeof (struct gfx_attach_board_args
));
129 if (__get_user (board
, &att
->board
) ||
130 __get_user (vaddr
, &att
->vaddr
))
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");
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
156 down(¤t
->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(¤t
->mm
->mmap_sem
);
165 /* Strange, the real mapping seems to be done at GFX_ATTACH_BOARD,
166 * GFX_MAPALL is not even used by IRIX X server
175 * for my IRIX 6.2 X server, this is what the kernel returns
180 /* Xsgi does not use this one, I assume minor is the board being queried */
184 return (cards
[devnum
].g_owner
!= 0);
187 if (cards
[devnum
].g_ioctl
)
188 return (*cards
[devnum
].g_ioctl
)(devnum
, cmd
, arg
);
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 */
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
)();
215 * This is the core of the direct rendering engine.
219 sgi_graphics_nopage (struct vm_area_struct
*vma
, unsigned long address
, int
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
;
228 printk ("Got a page fault for board %d address=%lx guser=%lx\n", board
,
229 address
, (unsigned long) cards
[board
].g_user
);
232 /* Figure out if another process has this mapped, and revoke the mapping
234 if (cards
[board
].g_user
&& cards
[board
].g_user
!= current
) {
235 /* FIXME: save graphics context here, dump it to rendering
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
)
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
;
286 /* Do any post card-detection setup on graphics_ops */
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;
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
,
304 static struct miscdevice dev_graphics
= {
305 SGI_GRAPHICS_MINOR
, "sgi-graphics", &sgi_graphics_fops
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
)
323 struct console_ops
*console
;
324 struct graphics_ops
*g
;
327 printk ("GFX INIT: ");
334 if ((g
= newport_probe (boards
, name
)) != 0) {
336 graphics_ops_post_init (boards
);
340 /* Add more graphic drivers here */
341 /* Keep passing console around */
344 if (boards
> MAXCARDS
)
345 printk (KERN_WARNING
"Too many cards found on the system\n");
349 int init_module(void) {
350 static int initiated
= 0;
352 printk("SGI Newport Graphics version %i.%i.%i\n",42,54,69);
357 printk("Adding first board\n");
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
);
371 void cleanup_module(void) {
372 printk("Shutting down SGI Newport Graphics\n");
374 misc_deregister (&dev_graphics
);
375 misc_deregister (&dev_opengl
);