Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.18-rc1 356 lines 8.7 kB view raw
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 7#include "ffb.h" 8#include "drmP.h" 9 10#include "ffb_drv.h" 11 12#include <linux/sched.h> 13#include <linux/smp_lock.h> 14#include <asm/shmparam.h> 15#include <asm/oplib.h> 16#include <asm/upa.h> 17 18#define DRIVER_AUTHOR "David S. Miller" 19 20#define DRIVER_NAME "ffb" 21#define DRIVER_DESC "Creator/Creator3D" 22#define DRIVER_DATE "20000517" 23 24#define DRIVER_MAJOR 0 25#define DRIVER_MINOR 0 26#define DRIVER_PATCHLEVEL 1 27 28typedef struct _ffb_position_t { 29 int node; 30 int root; 31} ffb_position_t; 32 33static ffb_position_t *ffb_position; 34 35static void get_ffb_type(ffb_dev_priv_t * ffb_priv, int instance) 36{ 37 volatile unsigned char *strap_bits; 38 unsigned char val; 39 40 strap_bits = (volatile unsigned char *) 41 (ffb_priv->card_phys_base + 0x00200000UL); 42 43 /* Don't ask, you have to read the value twice for whatever 44 * reason to get correct contents. 45 */ 46 val = upa_readb(strap_bits); 47 val = upa_readb(strap_bits); 48 switch (val & 0x78) { 49 case (0x0 << 5) | (0x0 << 3): 50 ffb_priv->ffb_type = ffb1_prototype; 51 printk("ffb%d: Detected FFB1 pre-FCS prototype\n", instance); 52 break; 53 case (0x0 << 5) | (0x1 << 3): 54 ffb_priv->ffb_type = ffb1_standard; 55 printk("ffb%d: Detected FFB1\n", instance); 56 break; 57 case (0x0 << 5) | (0x3 << 3): 58 ffb_priv->ffb_type = ffb1_speedsort; 59 printk("ffb%d: Detected FFB1-SpeedSort\n", instance); 60 break; 61 case (0x1 << 5) | (0x0 << 3): 62 ffb_priv->ffb_type = ffb2_prototype; 63 printk("ffb%d: Detected FFB2/vertical pre-FCS prototype\n", 64 instance); 65 break; 66 case (0x1 << 5) | (0x1 << 3): 67 ffb_priv->ffb_type = ffb2_vertical; 68 printk("ffb%d: Detected FFB2/vertical\n", instance); 69 break; 70 case (0x1 << 5) | (0x2 << 3): 71 ffb_priv->ffb_type = ffb2_vertical_plus; 72 printk("ffb%d: Detected FFB2+/vertical\n", instance); 73 break; 74 case (0x2 << 5) | (0x0 << 3): 75 ffb_priv->ffb_type = ffb2_horizontal; 76 printk("ffb%d: Detected FFB2/horizontal\n", instance); 77 break; 78 case (0x2 << 5) | (0x2 << 3): 79 ffb_priv->ffb_type = ffb2_horizontal; 80 printk("ffb%d: Detected FFB2+/horizontal\n", instance); 81 break; 82 default: 83 ffb_priv->ffb_type = ffb2_vertical; 84 printk("ffb%d: Unknown boardID[%08x], assuming FFB2\n", 85 instance, val); 86 break; 87 }; 88} 89 90static void ffb_apply_upa_parent_ranges(int parent, 91 struct linux_prom64_registers *regs) 92{ 93 struct linux_prom64_ranges ranges[PROMREG_MAX]; 94 char name[128]; 95 int len, i; 96 97 prom_getproperty(parent, "name", name, sizeof(name)); 98 if (strcmp(name, "upa") != 0) 99 return; 100 101 len = 102 prom_getproperty(parent, "ranges", (void *)ranges, sizeof(ranges)); 103 if (len <= 0) 104 return; 105 106 len /= sizeof(struct linux_prom64_ranges); 107 for (i = 0; i < len; i++) { 108 struct linux_prom64_ranges *rng = &ranges[i]; 109 u64 phys_addr = regs->phys_addr; 110 111 if (phys_addr >= rng->ot_child_base && 112 phys_addr < (rng->ot_child_base + rng->or_size)) { 113 regs->phys_addr -= rng->ot_child_base; 114 regs->phys_addr += rng->ot_parent_base; 115 return; 116 } 117 } 118 119 return; 120} 121 122static int ffb_init_one(drm_device_t * dev, int prom_node, int parent_node, 123 int instance) 124{ 125 struct linux_prom64_registers regs[2 * PROMREG_MAX]; 126 ffb_dev_priv_t *ffb_priv = (ffb_dev_priv_t *) dev->dev_private; 127 int i; 128 129 ffb_priv->prom_node = prom_node; 130 if (prom_getproperty(ffb_priv->prom_node, "reg", 131 (void *)regs, sizeof(regs)) <= 0) { 132 return -EINVAL; 133 } 134 ffb_apply_upa_parent_ranges(parent_node, &regs[0]); 135 ffb_priv->card_phys_base = regs[0].phys_addr; 136 ffb_priv->regs = (ffb_fbcPtr) 137 (regs[0].phys_addr + 0x00600000UL); 138 get_ffb_type(ffb_priv, instance); 139 for (i = 0; i < FFB_MAX_CTXS; i++) 140 ffb_priv->hw_state[i] = NULL; 141 142 return 0; 143} 144 145static drm_map_t *ffb_find_map(struct file *filp, unsigned long off) 146{ 147 drm_file_t *priv = filp->private_data; 148 drm_device_t *dev; 149 drm_map_list_t *r_list; 150 struct list_head *list; 151 drm_map_t *map; 152 153 if (!priv || (dev = priv->dev) == NULL) 154 return NULL; 155 156 list_for_each(list, &dev->maplist->head) { 157 r_list = (drm_map_list_t *) list; 158 map = r_list->map; 159 if (!map) 160 continue; 161 if (r_list->user_token == off) 162 return map; 163 } 164 165 return NULL; 166} 167 168unsigned long ffb_get_unmapped_area(struct file *filp, 169 unsigned long hint, 170 unsigned long len, 171 unsigned long pgoff, unsigned long flags) 172{ 173 drm_map_t *map = ffb_find_map(filp, pgoff << PAGE_SHIFT); 174 unsigned long addr = -ENOMEM; 175 176 if (!map) 177 return get_unmapped_area(NULL, hint, len, pgoff, flags); 178 179 if (map->type == _DRM_FRAME_BUFFER || map->type == _DRM_REGISTERS) { 180#ifdef HAVE_ARCH_FB_UNMAPPED_AREA 181 addr = get_fb_unmapped_area(filp, hint, len, pgoff, flags); 182#else 183 addr = get_unmapped_area(NULL, hint, len, pgoff, flags); 184#endif 185 } else if (map->type == _DRM_SHM && SHMLBA > PAGE_SIZE) { 186 unsigned long slack = SHMLBA - PAGE_SIZE; 187 188 addr = get_unmapped_area(NULL, hint, len + slack, pgoff, flags); 189 if (!(addr & ~PAGE_MASK)) { 190 unsigned long kvirt = (unsigned long)map->handle; 191 192 if ((kvirt & (SHMLBA - 1)) != (addr & (SHMLBA - 1))) { 193 unsigned long koff, aoff; 194 195 koff = kvirt & (SHMLBA - 1); 196 aoff = addr & (SHMLBA - 1); 197 if (koff < aoff) 198 koff += SHMLBA; 199 200 addr += (koff - aoff); 201 } 202 } 203 } else { 204 addr = get_unmapped_area(NULL, hint, len, pgoff, flags); 205 } 206 207 return addr; 208} 209 210static int ffb_presetup(drm_device_t * dev) 211{ 212 ffb_dev_priv_t *ffb_priv; 213 int ret = 0; 214 int i = 0; 215 216 /* Check for the case where no device was found. */ 217 if (ffb_position == NULL) 218 return -ENODEV; 219 220 /* code used to use numdevs no numdevs anymore */ 221 ffb_priv = kmalloc(sizeof(ffb_dev_priv_t), GFP_KERNEL); 222 if (!ffb_priv) 223 return -ENOMEM; 224 memset(ffb_priv, 0, sizeof(*ffb_priv)); 225 dev->dev_private = ffb_priv; 226 227 ret = ffb_init_one(dev, ffb_position[i].node, ffb_position[i].root, i); 228 return ret; 229} 230 231static void ffb_driver_release(drm_device_t * dev, struct file *filp) 232{ 233 ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) dev->dev_private; 234 int context = _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock); 235 int idx; 236 237 idx = context - 1; 238 if (fpriv && 239 context != DRM_KERNEL_CONTEXT && fpriv->hw_state[idx] != NULL) { 240 kfree(fpriv->hw_state[idx]); 241 fpriv->hw_state[idx] = NULL; 242 } 243} 244 245static void ffb_driver_pretakedown(drm_device_t * dev) 246{ 247 kfree(dev->dev_private); 248} 249 250static int ffb_driver_postcleanup(drm_device_t * dev) 251{ 252 kfree(ffb_position); 253 return 0; 254} 255 256static void ffb_driver_kernel_context_switch_unlock(struct drm_device *dev, 257 drm_lock_t * lock) 258{ 259 dev->lock.filp = 0; 260 { 261 __volatile__ unsigned int *plock = &dev->lock.hw_lock->lock; 262 unsigned int old, new, prev, ctx; 263 264 ctx = lock->context; 265 do { 266 old = *plock; 267 new = ctx; 268 prev = cmpxchg(plock, old, new); 269 } while (prev != old); 270 } 271 wake_up_interruptible(&dev->lock.lock_queue); 272} 273 274static unsigned long ffb_driver_get_map_ofs(drm_map_t * map) 275{ 276 return (map->offset & 0xffffffff); 277} 278 279static unsigned long ffb_driver_get_reg_ofs(drm_device_t * dev) 280{ 281 ffb_dev_priv_t *ffb_priv = (ffb_dev_priv_t *) dev->dev_private; 282 283 if (ffb_priv) 284 return ffb_priv->card_phys_base; 285 286 return 0; 287} 288 289static int postinit(struct drm_device *dev, unsigned long flags) 290{ 291 DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", 292 DRIVER_NAME, 293 DRIVER_MAJOR, 294 DRIVER_MINOR, DRIVER_PATCHLEVEL, DRIVER_DATE, dev->minor); 295 return 0; 296} 297 298static int version(drm_version_t * version) 299{ 300 int len; 301 302 version->version_major = DRIVER_MAJOR; 303 version->version_minor = DRIVER_MINOR; 304 version->version_patchlevel = DRIVER_PATCHLEVEL; 305 DRM_COPY(version->name, DRIVER_NAME); 306 DRM_COPY(version->date, DRIVER_DATE); 307 DRM_COPY(version->desc, DRIVER_DESC); 308 return 0; 309} 310 311static drm_ioctl_desc_t ioctls[] = { 312 313}; 314 315static struct drm_driver driver = { 316 .driver_features = 0, 317 .dev_priv_size = sizeof(u32), 318 .release = ffb_driver_release, 319 .presetup = ffb_presetup, 320 .pretakedown = ffb_driver_pretakedown, 321 .postcleanup = ffb_driver_postcleanup, 322 .kernel_context_switch = ffb_driver_context_switch, 323 .kernel_context_switch_unlock = ffb_driver_kernel_context_switch_unlock, 324 .get_map_ofs = ffb_driver_get_map_ofs, 325 .get_reg_ofs = ffb_driver_get_reg_ofs, 326 .postinit = postinit, 327 .version = version, 328 .ioctls = ioctls, 329 .num_ioctls = DRM_ARRAY_SIZE(ioctls), 330 .fops = { 331 .owner = THIS_MODULE, 332 .open = drm_open, 333 .release = drm_release, 334 .ioctl = drm_ioctl, 335 .mmap = drm_mmap, 336 .poll = drm_poll, 337 .fasync = drm_fasync, 338 } 339 , 340}; 341 342static int __init ffb_init(void) 343{ 344 return -ENODEV; 345} 346 347static void __exit ffb_exit(void) 348{ 349} 350 351module_init(ffb_init); 352module_exit(ffb_exit); 353 354MODULE_AUTHOR(DRIVER_AUTHOR); 355MODULE_DESCRIPTION(DRIVER_DESC); 356MODULE_LICENSE("GPL and additional rights");