Import 2.1.118
[davej-history.git] / drivers / sgi / char / graphics.c
blob80803da81c88e34284326ef6015ee86221493f5f
1 /*
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?
19 * Mistery too.
21 * We implement those misterious things, and tried not to think about
22 * the reasons behind them.
24 #include <linux/fs.h>
25 #include <linux/miscdevice.h>
26 #include <linux/sched.h>
27 #include <linux/mm.h>
28 #include <linux/mman.h>
29 #include <asm/uaccess.h>
30 #include "gconsole.h"
31 #include "graphics.h"
32 #include <asm/gfx.h>
33 #include <asm/rrm.h>
34 #include <asm/page.h>
35 #include <asm/pgtable.h>
37 /* The boards */
38 #include "newport.h"
40 #ifdef PRODUCTION_DRIVER
41 #define enable_gconsole()
42 #define disable_gconsole()
43 #endif
45 static struct graphics_ops cards [MAXCARDS];
46 static int boards;
48 #define GRAPHICS_CARD(inode) 0
50 int
51 sgi_graphics_open (struct inode *inode, struct file *file)
53 return 0;
56 int
57 sgi_graphics_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
59 unsigned int board;
60 unsigned int devnum = GRAPHICS_CARD (inode->i_rdev);
61 int i;
63 if ((cmd >= RRM_BASE) && (cmd <= RRM_CMD_LIMIT))
64 return rrm_command (cmd-RRM_BASE, (void *) arg);
66 switch (cmd){
67 case GFX_GETNUM_BOARDS:
68 return boards;
70 case GFX_GETBOARD_INFO: {
71 struct gfx_getboardinfo_args *bia = (void *) arg;
72 void *dest_buf;
73 int max_len;
75 i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct gfx_getboardinfo_args));
76 if (i) return i;
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);
82 if (board >= boards)
83 return -EINVAL;
84 if (max_len < sizeof (struct gfx_getboardinfo_args))
85 return -EINVAL;
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);
89 if (i) return i;
90 if (copy_to_user (dest_buf, cards [board].g_board_info, max_len))
91 return -EFAULT;
92 return max_len;
95 case GFX_ATTACH_BOARD: {
96 struct gfx_attach_board_args *att = (void *) arg;
97 void *vaddr;
98 int r;
100 i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct gfx_attach_board_args));
101 if (i) return i;
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");
114 return -EINVAL;
117 if (board >= boards)
118 return -EINVAL;
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
126 * sgi_graphics_mmap
128 disable_gconsole ();
129 r = do_mmap (file, (unsigned long)vaddr, cards [board].g_regs_size,
130 PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE, 0);
131 if (r)
132 return r;
136 /* Strange, the real mapping seems to be done at GFX_ATTACH_BOARD,
137 * GFX_MAPALL is not even used by IRIX X server
139 case GFX_MAPALL:
140 return 0;
142 case GFX_LABEL:
143 return 0;
145 /* Version check
146 * for my IRIX 6.2 X server, this is what the kernel returns
148 case 1:
149 return 3;
151 /* Xsgi does not use this one, I assume minor is the board being queried */
152 case GFX_IS_MANAGED:
153 if (devnum > boards)
154 return -EINVAL;
155 return (cards [devnum].g_owner != 0);
157 default:
158 if (cards [devnum].g_ioctl)
159 return (*cards [devnum].g_ioctl)(devnum, cmd, arg);
162 return -EINVAL;
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)();
177 enable_gconsole ();
179 return 0;
183 * This is the core of the direct rendering engine.
186 unsigned long
187 sgi_graphics_nopage (struct vm_area_struct *vma, unsigned long address, int write_access)
189 unsigned long page;
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);
195 #endif
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;
205 #if DEBUG_GRAPHICS
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)));
213 #endif
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)
242 uint size;
244 size = vma->vm_end - vma->vm_start;
245 if (vma->vm_offset & ~PAGE_MASK)
246 return -ENXIO;
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;
254 /* final setup */
255 vma->vm_dentry = dget (file->f_dentry);
256 return 0;
259 /* Do any post card-detection setup on graphics_ops */
260 static void
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 = {
269 NULL, /* llseek */
270 NULL, /* read */
271 NULL, /* write */
272 NULL, /* readdir */
273 NULL, /* poll */
274 sgi_graphics_ioctl, /* ioctl */
275 sgi_graphics_mmap, /* mmap */
276 sgi_graphics_open, /* open */
277 NULL, /* flush */
278 sgi_graphics_close, /* release */
279 NULL, /* fsync */
280 NULL, /* check_media_change */
281 NULL, /* revalidate */
282 NULL /* lock */
285 /* /dev/graphics */
286 static struct miscdevice dev_graphics = {
287 SGI_GRAPHICS_MINOR, "sgi-graphics", &sgi_graphics_fops
290 /* /dev/opengl */
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 */
296 void
297 gfx_register (void)
299 misc_register (&dev_graphics);
300 misc_register (&dev_opengl);
303 void
304 gfx_init (const char **name)
306 struct console_ops *console;
307 struct graphics_ops *g;
309 printk ("GFX INIT: ");
310 shmiq_init ();
311 usema_init ();
313 if ((g = newport_probe (boards, name)) != 0){
314 cards [boards] = *g;
315 graphics_ops_post_init (boards);
316 boards++;
317 console = 0;
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");
324 prom_halt ();