2 * gfx.c: support for SGI's /dev/graphics, /dev/opengl
4 * Author: Miguel de Icaza (miguel@nuclecu.unam.mx)
6 * On IRIX, /dev/graphics is [10, 146]
7 * /dev/opengl is [10, 147]
9 * From a mail with Mark J. Kilgard, /dev/opengl and /dev/graphics are
10 * the same thing, the use of /dev/graphics seems deprecated though.
12 * The reason that the original SGI programmer had to use only one
13 * device for all the graphic cards on the system will remain a
14 * mistery for the rest of our lives. Why some ioctls take a board
15 * number and some others not? Mistery. Why do they map the hardware
16 * registers into the user address space with an ioctl instead of
17 * mmap? Mistery too. Why they did not use the standard way of
18 * making ioctl constants and instead sticked a random constant?
21 * We implement those misterious things, and tried not to think about
22 * the reasons behind them.
25 #include <linux/miscdevice.h>
26 #include <linux/sched.h>
28 #include <linux/mman.h>
29 #include <asm/uaccess.h>
35 #include <asm/pgtable.h>
40 #ifdef PRODUCTION_DRIVER
41 #define enable_gconsole()
42 #define disable_gconsole()
45 static struct graphics_ops cards
[MAXCARDS
];
48 #define GRAPHICS_CARD(inode) 0
51 sgi_graphics_open (struct inode
*inode
, struct file
*file
)
57 sgi_graphics_ioctl (struct inode
*inode
, struct file
*file
, unsigned int cmd
, unsigned long arg
)
60 unsigned int devnum
= GRAPHICS_CARD (inode
->i_rdev
);
63 if ((cmd
>= RRM_BASE
) && (cmd
<= RRM_CMD_LIMIT
))
64 return rrm_command (cmd
-RRM_BASE
, (void *) arg
);
67 case GFX_GETNUM_BOARDS
:
70 case GFX_GETBOARD_INFO
: {
71 struct gfx_getboardinfo_args
*bia
= (void *) arg
;
75 i
= verify_area (VERIFY_READ
, (void *) arg
, sizeof (struct gfx_getboardinfo_args
));
78 __get_user_ret (board
, &bia
->board
, -EFAULT
);
79 __get_user_ret (dest_buf
, &bia
->buf
, -EFAULT
);
80 __get_user_ret (max_len
, &bia
->len
, -EFAULT
);
84 if (max_len
< sizeof (struct gfx_getboardinfo_args
))
86 if (max_len
> cards
[board
].g_board_info_len
)
87 max_len
= cards
[boards
].g_board_info_len
;
88 i
= verify_area (VERIFY_WRITE
, dest_buf
, max_len
);
90 if (copy_to_user (dest_buf
, cards
[board
].g_board_info
, max_len
))
95 case GFX_ATTACH_BOARD
: {
96 struct gfx_attach_board_args
*att
= (void *) arg
;
100 i
= verify_area (VERIFY_READ
, (void *)arg
, sizeof (struct gfx_attach_board_args
));
103 __get_user_ret (board
, &att
->board
, -EFAULT
);
104 __get_user_ret (vaddr
, &att
->vaddr
, -EFAULT
);
106 /* Ok for now we are assuming /dev/graphicsN -> head N even
107 * if the ioctl api suggests that this is not quite the case.
109 * Otherwise we fail, we use this assumption in the mmap code
110 * below to find our board information.
112 if (board
!= devnum
){
113 printk ("Parameter board does not match the current board\n");
120 /* If it is the first opening it, then make it the board owner */
121 if (!cards
[board
].g_owner
)
122 cards
[board
].g_owner
= current
;
125 * Ok, we now call mmap on this file, which will end up calling
129 r
= do_mmap (file
, (unsigned long)vaddr
, cards
[board
].g_regs_size
,
130 PROT_READ
|PROT_WRITE
, MAP_FIXED
|MAP_PRIVATE
, 0);
136 /* Strange, the real mapping seems to be done at GFX_ATTACH_BOARD,
137 * GFX_MAPALL is not even used by IRIX X server
146 * for my IRIX 6.2 X server, this is what the kernel returns
151 /* Xsgi does not use this one, I assume minor is the board being queried */
155 return (cards
[devnum
].g_owner
!= 0);
158 if (cards
[devnum
].g_ioctl
)
159 return (*cards
[devnum
].g_ioctl
)(devnum
, cmd
, arg
);
166 sgi_graphics_close (struct inode
*inode
, struct file
*file
)
168 int board
= GRAPHICS_CARD (inode
->i_rdev
);
170 /* Tell the rendering manager that one client is going away */
171 rrm_close (inode
, file
);
173 /* Was this file handle from the board owner?, clear it */
174 if (current
== cards
[board
].g_owner
){
175 cards
[board
].g_owner
= 0;
176 (*cards
[board
].g_reset_console
)();
183 * This is the core of the direct rendering engine.
187 sgi_graphics_nopage (struct vm_area_struct
*vma
, unsigned long address
, int write_access
)
190 int board
= GRAPHICS_CARD (vma
->vm_dentry
->d_inode
->i_rdev
);
192 #ifdef DEBUG_GRAPHICS
193 printk ("Got a page fault for board %d address=%lx guser=%lx\n", board
, address
,
194 cards
[board
].g_user
);
197 /* 1. figure out if another process has this mapped,
198 * and revoke the mapping in that case.
200 if (cards
[board
].g_user
&& cards
[board
].g_user
!= current
){
201 /* FIXME: save graphics context here, dump it to rendering node? */
202 remove_mapping (cards
[board
].g_user
, vma
->vm_start
, vma
->vm_end
);
204 cards
[board
].g_user
= current
;
206 printk ("Registers: 0x%lx\n", cards
[board
].g_regs
);
207 printk ("vm_start: 0x%lx\n", vma
->vm_start
);
208 printk ("address: 0x%lx\n", address
);
209 printk ("diff: 0x%lx\n", (address
- vma
->vm_start
));
211 printk ("page/pfn: 0x%lx\n", page
);
212 printk ("TLB entry: %lx\n", pte_val (mk_pte (page
+ PAGE_OFFSET
, PAGE_USERIO
)));
215 /* 2. Map this into the current process address space */
216 page
= ((cards
[board
].g_regs
) + (address
- vma
->vm_start
));
217 return page
+ PAGE_OFFSET
;
221 * We convert a GFX ioctl for mapping hardware registers, in a nice sys_mmap
222 * call, which takes care of everything that must be taken care of.
226 static struct vm_operations_struct graphics_mmap
= {
227 NULL
, /* no special mmap-open */
228 NULL
, /* no special mmap-close */
229 NULL
, /* no special mmap-unmap */
230 NULL
, /* no special mmap-protect */
231 NULL
, /* no special mmap-sync */
232 NULL
, /* no special mmap-advise */
233 sgi_graphics_nopage
, /* our magic no-page fault handler */
234 NULL
, /* no special mmap-wppage */
235 NULL
, /* no special mmap-swapout */
236 NULL
/* no special mmap-swapin */
240 sgi_graphics_mmap (struct inode
*inode
, struct file
*file
, struct vm_area_struct
*vma
)
244 size
= vma
->vm_end
- vma
->vm_start
;
245 if (vma
->vm_offset
& ~PAGE_MASK
)
248 /* 1. Set our special graphic virtualizer */
249 vma
->vm_ops
= &graphics_mmap
;
251 /* 2. Set the special tlb permission bits */
252 vma
->vm_page_prot
= PAGE_USERIO
;
255 vma
->vm_dentry
= dget (file
->f_dentry
);
259 /* Do any post card-detection setup on graphics_ops */
261 graphics_ops_post_init (int slot
)
263 /* There is no owner for the card initially */
264 cards
[slot
].g_owner
= (struct task_struct
*) 0;
265 cards
[slot
].g_user
= (struct task_struct
*) 0;
268 struct file_operations sgi_graphics_fops
= {
274 sgi_graphics_ioctl
, /* ioctl */
275 sgi_graphics_mmap
, /* mmap */
276 sgi_graphics_open
, /* open */
278 sgi_graphics_close
, /* release */
280 NULL
, /* check_media_change */
281 NULL
, /* revalidate */
286 static struct miscdevice dev_graphics
= {
287 SGI_GRAPHICS_MINOR
, "sgi-graphics", &sgi_graphics_fops
291 static struct miscdevice dev_opengl
= {
292 SGI_OPENGL_MINOR
, "sgi-opengl", &sgi_graphics_fops
295 /* This is called later from the misc-init routine */
299 misc_register (&dev_graphics
);
300 misc_register (&dev_opengl
);
304 gfx_init (const char **name
)
306 struct console_ops
*console
;
307 struct graphics_ops
*g
;
309 printk ("GFX INIT: ");
313 if ((g
= newport_probe (boards
, name
)) != 0){
315 graphics_ops_post_init (boards
);
319 /* Add more graphic drivers here */
320 /* Keep passing console around */
322 if (boards
> MAXCARDS
){
323 printk ("Too many cards found on the system\n");