ffb_drv.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:10k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* $Id: ffb_drv.c,v 1.16 2001/10/18 16:00:24 davem Exp $
  2.  * ffb_drv.c: Creator/Creator3D direct rendering driver.
  3.  *
  4.  * Copyright (C) 2000 David S. Miller (davem@redhat.com)
  5.  */
  6. #include <linux/config.h>
  7. #include "ffb.h"
  8. #include "drmP.h"
  9. #include "ffb_drv.h"
  10. #include <linux/sched.h>
  11. #include <linux/smp_lock.h>
  12. #include <asm/shmparam.h>
  13. #include <asm/oplib.h>
  14. #include <asm/upa.h>
  15. #define DRIVER_AUTHOR "David S. Miller"
  16. #define DRIVER_NAME "ffb"
  17. #define DRIVER_DESC "Creator/Creator3D"
  18. #define DRIVER_DATE "20000517"
  19. #define DRIVER_MAJOR 0
  20. #define DRIVER_MINOR 0
  21. #define DRIVER_PATCHLEVEL 1
  22. #define DRIVER_FOPS
  23. static struct file_operations DRM(fops) = {
  24. owner:    THIS_MODULE,
  25. open:   DRM(open),
  26. flush:   DRM(flush),
  27. release:  DRM(release),
  28. ioctl:   DRM(ioctl),
  29. mmap:   DRM(mmap),
  30. read:   DRM(read),
  31. fasync:   DRM(fasync),
  32. poll:   DRM(poll),
  33. get_unmapped_area: ffb_get_unmapped_area,
  34. }
  35. #define DRIVER_COUNT_CARDS() ffb_count_card_instances()
  36. /* Allocate private structure and fill it */
  37. #define DRIVER_PRESETUP() do {
  38. int _ret;
  39. _ret = ffb_presetup(dev);
  40. if (_ret != 0) return _ret;
  41. } while(0)
  42. /* Free private structure */
  43. #define DRIVER_PRETAKEDOWN() do {
  44. if (dev->dev_private) kfree(dev->dev_private);
  45. } while(0)
  46. #define DRIVER_POSTCLEANUP() do {
  47. if (ffb_position != NULL) kfree(ffb_position);
  48. } while(0)
  49. /* We have to free up the rogue hw context state holding error or 
  50.  * else we will leak it.
  51.  */
  52. #define DRIVER_RELEASE() do {
  53. ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) dev->dev_private;
  54. int context = _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock);
  55. int idx;
  56. idx = context - 1;
  57. if (fpriv &&
  58.     context != DRM_KERNEL_CONTEXT &&
  59.     fpriv->hw_state[idx] != NULL) {
  60. kfree(fpriv->hw_state[idx]);
  61. fpriv->hw_state[idx] = NULL;
  62. }
  63. } while(0)
  64. /* For mmap customization */
  65. #define DRIVER_GET_MAP_OFS() (map->offset & 0xffffffff)
  66. #define DRIVER_GET_REG_OFS() ffb_get_reg_offset(dev)
  67. typedef struct _ffb_position_t {
  68. int node;
  69. int root;
  70. } ffb_position_t;
  71. static ffb_position_t *ffb_position;
  72. static void get_ffb_type(ffb_dev_priv_t *ffb_priv, int instance)
  73. {
  74. volatile unsigned char *strap_bits;
  75. unsigned char val;
  76. strap_bits = (volatile unsigned char *)
  77. (ffb_priv->card_phys_base + 0x00200000UL);
  78. /* Don't ask, you have to read the value twice for whatever
  79.  * reason to get correct contents.
  80.  */
  81. val = upa_readb(strap_bits);
  82. val = upa_readb(strap_bits);
  83. switch (val & 0x78) {
  84. case (0x0 << 5) | (0x0 << 3):
  85. ffb_priv->ffb_type = ffb1_prototype;
  86. printk("ffb%d: Detected FFB1 pre-FCS prototypen", instance);
  87. break;
  88. case (0x0 << 5) | (0x1 << 3):
  89. ffb_priv->ffb_type = ffb1_standard;
  90. printk("ffb%d: Detected FFB1n", instance);
  91. break;
  92. case (0x0 << 5) | (0x3 << 3):
  93. ffb_priv->ffb_type = ffb1_speedsort;
  94. printk("ffb%d: Detected FFB1-SpeedSortn", instance);
  95. break;
  96. case (0x1 << 5) | (0x0 << 3):
  97. ffb_priv->ffb_type = ffb2_prototype;
  98. printk("ffb%d: Detected FFB2/vertical pre-FCS prototypen", instance);
  99. break;
  100. case (0x1 << 5) | (0x1 << 3):
  101. ffb_priv->ffb_type = ffb2_vertical;
  102. printk("ffb%d: Detected FFB2/verticaln", instance);
  103. break;
  104. case (0x1 << 5) | (0x2 << 3):
  105. ffb_priv->ffb_type = ffb2_vertical_plus;
  106. printk("ffb%d: Detected FFB2+/verticaln", instance);
  107. break;
  108. case (0x2 << 5) | (0x0 << 3):
  109. ffb_priv->ffb_type = ffb2_horizontal;
  110. printk("ffb%d: Detected FFB2/horizontaln", instance);
  111. break;
  112. case (0x2 << 5) | (0x2 << 3):
  113. ffb_priv->ffb_type = ffb2_horizontal;
  114. printk("ffb%d: Detected FFB2+/horizontaln", instance);
  115. break;
  116. default:
  117. ffb_priv->ffb_type = ffb2_vertical;
  118. printk("ffb%d: Unknown boardID[%08x], assuming FFB2n", instance, val);
  119. break;
  120. };
  121. }
  122. static void ffb_apply_upa_parent_ranges(int parent, 
  123. struct linux_prom64_registers *regs)
  124. {
  125. struct linux_prom64_ranges ranges[PROMREG_MAX];
  126. char name[128];
  127. int len, i;
  128. prom_getproperty(parent, "name", name, sizeof(name));
  129. if (strcmp(name, "upa") != 0)
  130. return;
  131. len = prom_getproperty(parent, "ranges", (void *) ranges, sizeof(ranges));
  132. if (len <= 0)
  133. return;
  134. len /= sizeof(struct linux_prom64_ranges);
  135. for (i = 0; i < len; i++) {
  136. struct linux_prom64_ranges *rng = &ranges[i];
  137. u64 phys_addr = regs->phys_addr;
  138. if (phys_addr >= rng->ot_child_base &&
  139.     phys_addr < (rng->ot_child_base + rng->or_size)) {
  140. regs->phys_addr -= rng->ot_child_base;
  141. regs->phys_addr += rng->ot_parent_base;
  142. return;
  143. }
  144. }
  145. return;
  146. }
  147. static int ffb_init_one(drm_device_t *dev, int prom_node, int parent_node,
  148. int instance)
  149. {
  150. struct linux_prom64_registers regs[2*PROMREG_MAX];
  151. ffb_dev_priv_t *ffb_priv = (ffb_dev_priv_t *)dev->dev_private;
  152. int i;
  153. ffb_priv->prom_node = prom_node;
  154. if (prom_getproperty(ffb_priv->prom_node, "reg",
  155.      (void *)regs, sizeof(regs)) <= 0) {
  156. return -EINVAL;
  157. }
  158. ffb_apply_upa_parent_ranges(parent_node, &regs[0]);
  159. ffb_priv->card_phys_base = regs[0].phys_addr;
  160. ffb_priv->regs = (ffb_fbcPtr)
  161. (regs[0].phys_addr + 0x00600000UL);
  162. get_ffb_type(ffb_priv, instance);
  163. for (i = 0; i < FFB_MAX_CTXS; i++)
  164. ffb_priv->hw_state[i] = NULL;
  165. return 0;
  166. }
  167. static int __init ffb_count_siblings(int root)
  168. {
  169. int node, child, count = 0;
  170. child = prom_getchild(root);
  171. for (node = prom_searchsiblings(child, "SUNW,ffb"); node;
  172.      node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb"))
  173. count++;
  174. return count;
  175. }
  176. static int __init ffb_scan_siblings(int root, int instance)
  177. {
  178. int node, child;
  179. child = prom_getchild(root);
  180. for (node = prom_searchsiblings(child, "SUNW,ffb"); node;
  181.      node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) {
  182. ffb_position[instance].node = node;
  183. ffb_position[instance].root = root;
  184. instance++;
  185. }
  186. return instance;
  187. }
  188. static int ffb_presetup(drm_device_t *);
  189. static int __init ffb_count_card_instances(void)
  190. {
  191. int root, total, instance;
  192. total = ffb_count_siblings(prom_root_node);
  193. root = prom_getchild(prom_root_node);
  194. for (root = prom_searchsiblings(root, "upa"); root;
  195.      root = prom_searchsiblings(prom_getsibling(root), "upa"))
  196. total += ffb_count_siblings(root);
  197. ffb_position = kmalloc(sizeof(ffb_position_t) * total, GFP_KERNEL);
  198. /* Actual failure will be caught during ffb_presetup b/c we can't catch
  199.  * it easily here.
  200.  */
  201. if (!ffb_position)
  202. return -ENOMEM;
  203. instance = ffb_scan_siblings(prom_root_node, 0);
  204. root = prom_getchild(prom_root_node);
  205. for (root = prom_searchsiblings(root, "upa"); root;
  206.      root = prom_searchsiblings(prom_getsibling(root), "upa"))
  207. instance = ffb_scan_siblings(root, instance);
  208. return total;
  209. }
  210. static drm_map_t *ffb_find_map(struct file *filp, unsigned long off)
  211. {
  212. drm_file_t *priv = filp->private_data;
  213. drm_device_t *dev;
  214. drm_map_list_t  *r_list;
  215. struct list_head *list;
  216. drm_map_t *map;
  217. if (!priv || (dev = priv->dev) == NULL)
  218. return NULL;
  219. list_for_each(list, &dev->maplist->head) {
  220. unsigned long uoff;
  221. r_list = (drm_map_list_t *)list;
  222. map = r_list->map;
  223. if (!map)
  224. continue;
  225. uoff = (map->offset & 0xffffffff);
  226. if (uoff == off)
  227. return map;
  228. }
  229. return NULL;
  230. }
  231. static unsigned long ffb_get_unmapped_area(struct file *filp,
  232.    unsigned long hint,
  233.    unsigned long len,
  234.    unsigned long pgoff,
  235.    unsigned long flags)
  236. {
  237. drm_map_t *map = ffb_find_map(filp, pgoff << PAGE_SHIFT);
  238. unsigned long addr = -ENOMEM;
  239. if (!map)
  240. return get_unmapped_area(NULL, hint, len, pgoff, flags);
  241. if (map->type == _DRM_FRAME_BUFFER ||
  242.     map->type == _DRM_REGISTERS) {
  243. #ifdef HAVE_ARCH_FB_UNMAPPED_AREA
  244. addr = get_fb_unmapped_area(filp, hint, len, pgoff, flags);
  245. #else
  246. addr = get_unmapped_area(NULL, hint, len, pgoff, flags);
  247. #endif
  248. } else if (map->type == _DRM_SHM && SHMLBA > PAGE_SIZE) {
  249. unsigned long slack = SHMLBA - PAGE_SIZE;
  250. addr = get_unmapped_area(NULL, hint, len + slack, pgoff, flags);
  251. if (!(addr & ~PAGE_MASK)) {
  252. unsigned long kvirt = (unsigned long) map->handle;
  253. if ((kvirt & (SHMLBA - 1)) != (addr & (SHMLBA - 1))) {
  254. unsigned long koff, aoff;
  255. koff = kvirt & (SHMLBA - 1);
  256. aoff = addr & (SHMLBA - 1);
  257. if (koff < aoff)
  258. koff += SHMLBA;
  259. addr += (koff - aoff);
  260. }
  261. }
  262. } else {
  263. addr = get_unmapped_area(NULL, hint, len, pgoff, flags);
  264. }
  265. return addr;
  266. }
  267. static unsigned long ffb_get_reg_offset(drm_device_t *dev)
  268. {
  269. ffb_dev_priv_t *ffb_priv = (ffb_dev_priv_t *)dev->dev_private;
  270. if (ffb_priv)
  271. return ffb_priv->card_phys_base;
  272. return 0;
  273. }
  274. #include "drm_auth.h"
  275. #include "drm_bufs.h"
  276. #include "drm_dma.h"
  277. #include "drm_drawable.h"
  278. #include "drm_drv.h"
  279. /* This functions must be here since it references DRM(numdevs)
  280.  * which drm_drv.h declares.
  281.  */
  282. static int ffb_presetup(drm_device_t *dev)
  283. {
  284. ffb_dev_priv_t *ffb_priv;
  285. drm_device_t *temp_dev;
  286. int ret = 0;
  287. int i;
  288. /* Check for the case where no device was found. */
  289. if (ffb_position == NULL)
  290. return -ENODEV;
  291. /* Find our instance number by finding our device in dev structure */
  292. for (i = 0; i < DRM(numdevs); i++) {
  293. temp_dev = &(DRM(device)[i]);
  294. if(temp_dev == dev)
  295. break;
  296. }
  297. if (i == DRM(numdevs))
  298. return -ENODEV;
  299. ffb_priv = kmalloc(sizeof(ffb_dev_priv_t), GFP_KERNEL);
  300. if (!ffb_priv)
  301. return -ENOMEM;
  302. memset(ffb_priv, 0, sizeof(*ffb_priv));
  303. dev->dev_private = ffb_priv;
  304. ret = ffb_init_one(dev,
  305.    ffb_position[i].node,
  306.    ffb_position[i].root,
  307.    i);
  308. return ret;
  309. }
  310. #ifndef MODULE
  311. /* DRM(options) is called by the kernel to parse command-line options
  312.  * passed via the boot-loader (e.g., LILO).  It calls the insmod option
  313.  * routine, drm_parse_drm.
  314.  */
  315. /* JH- We have to hand expand the string ourselves because of the cpp.  If
  316.  * anyone can think of a way that we can fit into the __setup macro without
  317.  * changing it, then please send the solution my way.
  318.  */
  319. static int __init ffb_options(char *str)
  320. {
  321. DRM(parse_options)(str);
  322. return 1;
  323. }
  324. __setup(DRIVER_NAME "=", ffb_options);
  325. #endif
  326. #include "drm_fops.h"
  327. #include "drm_init.h"
  328. #include "drm_ioctl.h"
  329. #include "drm_lock.h"
  330. #include "drm_memory.h"
  331. #include "drm_proc.h"
  332. #include "drm_vm.h"
  333. #include "drm_stub.h"