graphics.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:9k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * gfx.c: support for SGI's /dev/graphics, /dev/opengl
  3.  *
  4.  * Author: Miguel de Icaza (miguel@nuclecu.unam.mx)
  5.  *         Ralf Baechle (ralf@gnu.org)
  6.  *         Ulf Carlsson (ulfc@bun.falkenberg.se)
  7.  *
  8.  * On IRIX, /dev/graphics is [10, 146]
  9.  *          /dev/opengl   is [10, 147]
  10.  *
  11.  * From a mail with Mark J. Kilgard, /dev/opengl and /dev/graphics are
  12.  * the same thing, the use of /dev/graphics seems deprecated though.
  13.  *
  14.  * The reason that the original SGI programmer had to use only one
  15.  * device for all the graphic cards on the system will remain a
  16.  * mistery for the rest of our lives.  Why some ioctls take a board
  17.  * number and some others not?  Mistery.  Why do they map the hardware
  18.  * registers into the user address space with an ioctl instead of
  19.  * mmap?  Mistery too.  Why they did not use the standard way of
  20.  * making ioctl constants and instead sticked a random constant?
  21.  * Mistery too.
  22.  *
  23.  * We implement those misterious things, and tried not to think about
  24.  * the reasons behind them.
  25.  */
  26. #include <linux/kernel.h>
  27. #include <linux/fs.h>
  28. #include <linux/init.h>
  29. #include <linux/miscdevice.h>
  30. #include <linux/sched.h>
  31. #include <linux/mm.h>
  32. #include <linux/mman.h>
  33. #include <linux/slab.h>
  34. #include <linux/module.h>
  35. #include <linux/smp_lock.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 <video/newport.h>
  45. #define DEBUG
  46. /* The boards */
  47. extern struct graphics_ops *newport_probe (int, const char **);
  48. static struct graphics_ops cards [MAXCARDS];
  49. static int boards;
  50. #define GRAPHICS_CARD(inode) 0
  51. /*
  52. void enable_gconsole(void) {};
  53. void disable_gconsole(void) {};
  54. */
  55. int
  56. sgi_graphics_open (struct inode *inode, struct file *file)
  57. {
  58. struct newport_regs *nregs =
  59. (struct newport_regs *) KSEG1ADDR(cards[0].g_regs);
  60. newport_wait();
  61. nregs->set.wrmask = 0xffffffff;
  62. nregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
  63.      NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX |
  64.      NPORT_DMODE0_STOPY);
  65. nregs->set.colori = 1;
  66. nregs->set.xystarti = (0 << 16) | 0;
  67. nregs->go.xyendi = (1280 << 16) | 1024;
  68. return 0;
  69. }
  70. int
  71. sgi_graphics_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
  72. {
  73. unsigned int board;
  74. unsigned int devnum = GRAPHICS_CARD (inode->i_rdev);
  75. int i;
  76. if ((cmd >= RRM_BASE) && (cmd <= RRM_CMD_LIMIT))
  77. return rrm_command (cmd-RRM_BASE, (void *) arg);
  78. switch (cmd){
  79. case GFX_GETNUM_BOARDS:
  80. return boards;
  81. case GFX_GETBOARD_INFO: {
  82. struct gfx_getboardinfo_args *bia = (void *) arg;
  83. void   *dest_buf;
  84. int    max_len;
  85. i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct gfx_getboardinfo_args));
  86. if (i) return i;
  87. if (__get_user (board,    &bia->board) ||
  88.     __get_user (dest_buf, &bia->buf) ||
  89.     __get_user (max_len,  &bia->len))
  90. return -EFAULT;
  91. if (board >= boards)
  92. return -EINVAL;
  93. if (max_len < sizeof (struct gfx_getboardinfo_args))
  94. return -EINVAL;
  95. if (max_len > cards [board].g_board_info_len)
  96. max_len = cards [boards].g_board_info_len;
  97. i = verify_area (VERIFY_WRITE, dest_buf, max_len);
  98. if (i) return i;
  99. if (copy_to_user (dest_buf, cards [board].g_board_info, max_len))
  100. return -EFAULT;
  101. return max_len;
  102. }
  103. case GFX_ATTACH_BOARD: {
  104. struct gfx_attach_board_args *att = (void *) arg;
  105. void *vaddr;
  106. int  r;
  107. i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct gfx_attach_board_args));
  108. if (i) return i;
  109. if (__get_user (board, &att->board) ||
  110.     __get_user (vaddr, &att->vaddr))
  111. return -EFAULT;
  112. /* Ok for now we are assuming /dev/graphicsN -> head N even
  113.  * if the ioctl api suggests that this is not quite the case.
  114.  *
  115.  * Otherwise we fail, we use this assumption in the mmap code
  116.  * below to find our board information.
  117.  */
  118. if (board != devnum){
  119. printk ("Parameter board does not match the current boardn");
  120. return -EINVAL;
  121. }
  122. if (board >= boards)
  123. return -EINVAL;
  124. /* If it is the first opening it, then make it the board owner */
  125. if (!cards [board].g_owner)
  126. cards [board].g_owner = current;
  127. /*
  128.  * Ok, we now call mmap on this file, which will end up calling
  129.  * sgi_graphics_mmap
  130.  */
  131. disable_gconsole ();
  132. down_write(&current->mm->mmap_sem);
  133. r = do_mmap (file, (unsigned long)vaddr,
  134.      cards[board].g_regs_size, PROT_READ|PROT_WRITE,
  135.      MAP_FIXED|MAP_PRIVATE, 0);
  136. up_write(&current->mm->mmap_sem);
  137. if (r)
  138. return r;
  139. }
  140. /* Strange, the real mapping seems to be done at GFX_ATTACH_BOARD,
  141.  * GFX_MAPALL is not even used by IRIX X server
  142.  */
  143. case GFX_MAPALL:
  144. return 0;
  145. case GFX_LABEL:
  146. return 0;
  147. /* Version check
  148.  * for my IRIX 6.2 X server, this is what the kernel returns
  149.  */
  150. case 1:
  151. return 3;
  152. /* Xsgi does not use this one, I assume minor is the board being queried */
  153. case GFX_IS_MANAGED:
  154. if (devnum > boards)
  155. return -EINVAL;
  156. return (cards [devnum].g_owner != 0);
  157. default:
  158. if (cards [devnum].g_ioctl)
  159. return (*cards [devnum].g_ioctl)(devnum, cmd, arg);
  160. }
  161. return -EINVAL;
  162. }
  163. int
  164. sgi_graphics_close (struct inode *inode, struct file *file)
  165. {
  166. int board = GRAPHICS_CARD (inode->i_rdev);
  167. /* Tell the rendering manager that one client is going away */
  168. lock_kernel();
  169. rrm_close (inode, file);
  170. /* Was this file handle from the board owner?, clear it */
  171. if (current == cards [board].g_owner){
  172. cards [board].g_owner = 0;
  173. if (cards [board].g_reset_console)
  174. (*cards [board].g_reset_console)();
  175. enable_gconsole ();
  176. }
  177. unlock_kernel();
  178. return 0;
  179. }
  180. /* 
  181.  * This is the core of the direct rendering engine.
  182.  */
  183. struct page *
  184. sgi_graphics_nopage (struct vm_area_struct *vma, unsigned long address, int
  185.      no_share)
  186. {
  187. pgd_t *pgd; pmd_t *pmd; pte_t *pte; 
  188. int board = GRAPHICS_CARD (vma->vm_dentry->d_inode->i_rdev);
  189. unsigned long virt_add, phys_add;
  190. #ifdef DEBUG
  191. printk ("Got a page fault for board %d address=%lx guser=%lxn", board,
  192. address, (unsigned long) cards[board].g_user);
  193. #endif
  194. /* Figure out if another process has this mapped, and revoke the mapping
  195.  * in that case. */
  196. if (cards[board].g_user && cards[board].g_user != current) {
  197. /* FIXME: save graphics context here, dump it to rendering
  198.  * node? */
  199. remove_mapping(cards[board].g_user, vma->vm_start, vma->vm_end);
  200. }
  201. cards [board].g_user = current;
  202. /* Map the physical address of the newport registers into the address
  203.  * space of this process */
  204. virt_add = address & PAGE_MASK;
  205. phys_add = cards[board].g_regs + virt_add - vma->vm_start;
  206. remap_page_range(virt_add, phys_add, PAGE_SIZE, vma->vm_page_prot);
  207. pgd = pgd_offset(current->mm, address);
  208. pmd = pmd_offset(pgd, address);
  209. pte = pte_offset(pmd, address);
  210. return pte_page(*pte);
  211. }
  212. /*
  213.  * We convert a GFX ioctl for mapping hardware registers, in a nice sys_mmap
  214.  * call, which takes care of everything that must be taken care of.
  215.  *
  216.  */
  217. static struct vm_operations_struct graphics_mmap = {
  218. nopage: sgi_graphics_nopage, /* our magic no-page fault handler */
  219. };
  220. int
  221. sgi_graphics_mmap (struct file *file, struct vm_area_struct *vma)
  222. {
  223. uint size;
  224. size = vma->vm_end - vma->vm_start;
  225. /* 1. Set our special graphic virtualizer  */
  226. vma->vm_ops = &graphics_mmap;
  227. /* 2. Set the special tlb permission bits */
  228. vma->vm_page_prot = PAGE_USERIO;
  229. /* final setup */
  230. vma->vm_file = file;
  231. return 0;
  232. }
  233. #if 0
  234. /* Do any post card-detection setup on graphics_ops */
  235. static void
  236. graphics_ops_post_init (int slot)
  237. {
  238. /* There is no owner for the card initially */
  239. cards [slot].g_owner = (struct task_struct *) 0;
  240. cards [slot].g_user  = (struct task_struct *) 0;
  241. }
  242. #endif
  243. struct file_operations sgi_graphics_fops = {
  244. ioctl: sgi_graphics_ioctl,
  245. mmap: sgi_graphics_mmap,
  246. open: sgi_graphics_open,
  247. release: sgi_graphics_close,
  248. };
  249. /* /dev/graphics */
  250. static struct miscdevice dev_graphics = {
  251. SGI_GRAPHICS_MINOR, "sgi-graphics", &sgi_graphics_fops
  252. };
  253. /* /dev/opengl */
  254. static struct miscdevice dev_opengl = {
  255. SGI_OPENGL_MINOR, "sgi-opengl", &sgi_graphics_fops
  256. };
  257. /* This is called later from the misc-init routine */
  258. void __init gfx_register (void)
  259. {
  260. misc_register (&dev_graphics);
  261. misc_register (&dev_opengl);
  262. }
  263. void __init gfx_init (const char **name)
  264. {
  265. #if 0
  266. struct console_ops *console;
  267. struct graphics_ops *g;
  268. #endif
  269. printk ("GFX INIT: ");
  270. shmiq_init ();
  271. usema_init ();
  272. boards++;
  273. #if 0
  274. if ((g = newport_probe (boards, name)) != 0) {
  275. cards [boards] = *g;
  276. graphics_ops_post_init (boards);
  277. boards++;
  278. console = 0;
  279. }
  280. /* Add more graphic drivers here */
  281. /* Keep passing console around */
  282. #endif
  283. if (boards > MAXCARDS)
  284. printk (KERN_WARNING "Too many cards found on the systemn");
  285. }
  286. #ifdef MODULE
  287. MODULE_LICENSE("GPL");
  288. int init_module(void) {
  289. static int initiated = 0;
  290. printk("SGI Newport Graphics version %i.%i.%in",42,54,69);
  291. if (!initiated++) {
  292. shmiq_init();
  293. usema_init();
  294. printk("Adding first boardn");
  295. boards++;
  296. cards[0].g_regs = 0x1f0f0000;
  297. cards[0].g_regs_size = sizeof (struct newport_regs);
  298. }
  299. printk("Boards: %dn", boards);
  300. misc_register (&dev_graphics);
  301. misc_register (&dev_opengl);
  302. return 0;
  303. }
  304. void cleanup_module(void) {
  305. printk("Shutting down SGI Newport Graphicsn");
  306. misc_deregister (&dev_graphics);
  307. misc_deregister (&dev_opengl);
  308. }
  309. #endif