📄 tdfx_drv.c
字号:
static void __exit tdfx_cleanup(void){ drm_device_t *dev = &tdfx_device; DRM_DEBUG("\n"); drm_proc_cleanup(); if (misc_deregister(&tdfx_misc)) { DRM_ERROR("Cannot unload module\n"); } else { DRM_INFO("Module unloaded\n"); } drm_ctxbitmap_cleanup(dev); tdfx_takedown(dev);#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) if (dev->agp) { drm_agp_uninit(); drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); dev->agp = NULL; }#endif}module_init(tdfx_init);module_exit(tdfx_cleanup);int tdfx_version(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ drm_version_t version; int len; if (copy_from_user(&version, (drm_version_t *)arg, sizeof(version))) return -EFAULT;#define DRM_COPY(name,value) \ len = strlen(value); \ if (len > name##_len) len = name##_len; \ name##_len = strlen(value); \ if (len && name) { \ if (copy_to_user(name, value, len)) \ return -EFAULT; \ } version.version_major = TDFX_MAJOR; version.version_minor = TDFX_MINOR; version.version_patchlevel = TDFX_PATCHLEVEL; DRM_COPY(version.name, TDFX_NAME); DRM_COPY(version.date, TDFX_DATE); DRM_COPY(version.desc, TDFX_DESC); if (copy_to_user((drm_version_t *)arg, &version, sizeof(version))) return -EFAULT; return 0;}int tdfx_open(struct inode *inode, struct file *filp){ drm_device_t *dev = &tdfx_device; int retcode = 0; DRM_DEBUG("open_count = %d\n", dev->open_count); if (!(retcode = drm_open_helper(inode, filp, dev))) {#if LINUX_VERSION_CODE < 0x020333 MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */#endif atomic_inc(&dev->total_open); spin_lock(&dev->count_lock); if (!dev->open_count++) { spin_unlock(&dev->count_lock); return tdfx_setup(dev); } spin_unlock(&dev->count_lock); } return retcode;}int tdfx_release(struct inode *inode, struct file *filp){ drm_file_t *priv = filp->private_data; drm_device_t *dev; int retcode = 0; lock_kernel(); dev = priv->dev; DRM_DEBUG("open_count = %d\n", dev->open_count); if (!(retcode = drm_release(inode, filp))) {#if LINUX_VERSION_CODE < 0x020333 MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */#endif atomic_inc(&dev->total_close); spin_lock(&dev->count_lock); if (!--dev->open_count) { if (atomic_read(&dev->ioctl_count) || dev->blocked) { DRM_ERROR("Device busy: %d %d\n", atomic_read(&dev->ioctl_count), dev->blocked); spin_unlock(&dev->count_lock); unlock_kernel(); return -EBUSY; } spin_unlock(&dev->count_lock); unlock_kernel(); return tdfx_takedown(dev); } spin_unlock(&dev->count_lock); } unlock_kernel(); return retcode;}/* tdfx_ioctl is called whenever a process performs an ioctl on /dev/drm. */int tdfx_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ int nr = DRM_IOCTL_NR(cmd); drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; int retcode = 0; drm_ioctl_desc_t *ioctl; drm_ioctl_t *func; atomic_inc(&dev->ioctl_count); atomic_inc(&dev->total_ioctl); ++priv->ioctl_count; DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n", current->pid, cmd, nr, dev->device, priv->authenticated); if (nr >= TDFX_IOCTL_COUNT) { retcode = -EINVAL; } else { ioctl = &tdfx_ioctls[nr]; func = ioctl->func; if (!func) { DRM_DEBUG("no function\n"); retcode = -EINVAL; } else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN)) || (ioctl->auth_needed && !priv->authenticated)) { retcode = -EACCES; } else { retcode = (func)(inode, filp, cmd, arg); } } atomic_dec(&dev->ioctl_count); return retcode;}int tdfx_lock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; DECLARE_WAITQUEUE(entry, current); int ret = 0; drm_lock_t lock;#if DRM_DMA_HISTOGRAM cycles_t start; dev->lck_start = start = get_cycles();#endif if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) return -EFAULT; if (lock.context == DRM_KERNEL_CONTEXT) { DRM_ERROR("Process %d using kernel context %d\n", current->pid, lock.context); return -EINVAL; } DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", lock.context, current->pid, dev->lock.hw_lock->lock, lock.flags);#if 0 /* dev->queue_count == 0 right now for tdfx. FIXME? */ if (lock.context < 0 || lock.context >= dev->queue_count) return -EINVAL;#endif if (!ret) {#if 0 if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) != lock.context) { long j = jiffies - dev->lock.lock_time; if (lock.context == tdfx_res_ctx.handle && j >= 0 && j < DRM_LOCK_SLICE) { /* Can't take lock if we just had it and there is contention. */ DRM_DEBUG("%d (pid %d) delayed j=%d dev=%d jiffies=%d\n", lock.context, current->pid, j, dev->lock.lock_time, jiffies); current->state = TASK_INTERRUPTIBLE; current->policy |= SCHED_YIELD; schedule_timeout(DRM_LOCK_SLICE-j); DRM_DEBUG("jiffies=%d\n", jiffies); } }#endif add_wait_queue(&dev->lock.lock_queue, &entry); for (;;) { current->state = TASK_INTERRUPTIBLE; if (!dev->lock.hw_lock) { /* Device has been unregistered */ ret = -EINTR; break; } if (drm_lock_take(&dev->lock.hw_lock->lock, lock.context)) { dev->lock.pid = current->pid; dev->lock.lock_time = jiffies; atomic_inc(&dev->total_locks); break; /* Got lock */ } /* Contention */ atomic_inc(&dev->total_sleeps);#if 1 current->policy |= SCHED_YIELD;#endif schedule(); if (signal_pending(current)) { ret = -ERESTARTSYS; break; } } current->state = TASK_RUNNING; remove_wait_queue(&dev->lock.lock_queue, &entry); }#if 0 if (!ret && dev->last_context != lock.context && lock.context != tdfx_res_ctx.handle && dev->last_context != tdfx_res_ctx.handle) { add_wait_queue(&dev->context_wait, &entry); current->state = TASK_INTERRUPTIBLE; /* PRE: dev->last_context != lock.context */ tdfx_context_switch(dev, dev->last_context, lock.context); /* POST: we will wait for the context switch and will dispatch on a later call when dev->last_context == lock.context NOTE WE HOLD THE LOCK THROUGHOUT THIS TIME! */ current->policy |= SCHED_YIELD; schedule(); current->state = TASK_RUNNING; remove_wait_queue(&dev->context_wait, &entry); if (signal_pending(current)) { ret = -EINTR; } else if (dev->last_context != lock.context) { DRM_ERROR("Context mismatch: %d %d\n", dev->last_context, lock.context); } }#endif if (!ret) { sigemptyset(&dev->sigmask); sigaddset(&dev->sigmask, SIGSTOP); sigaddset(&dev->sigmask, SIGTSTP); sigaddset(&dev->sigmask, SIGTTIN); sigaddset(&dev->sigmask, SIGTTOU); dev->sigdata.context = lock.context; dev->sigdata.lock = dev->lock.hw_lock; block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); if (lock.flags & _DRM_LOCK_READY) { /* Wait for space in DMA/FIFO */ } if (lock.flags & _DRM_LOCK_QUIESCENT) { /* Make hardware quiescent */#if 0 tdfx_quiescent(dev);#endif } }#if LINUX_VERSION_CODE < 0x020400 if (lock.context != tdfx_res_ctx.handle) { current->counter = 5; current->priority = DEF_PRIORITY/4; }#endif DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");#if DRM_DMA_HISTOGRAM atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]);#endif return ret;}int tdfx_unlock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; drm_lock_t lock; if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) return -EFAULT; if (lock.context == DRM_KERNEL_CONTEXT) { DRM_ERROR("Process %d using kernel context %d\n", current->pid, lock.context); return -EINVAL; } DRM_DEBUG("%d frees lock (%d holds)\n", lock.context, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); atomic_inc(&dev->total_unlocks); if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock)) atomic_inc(&dev->total_contends); drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); /* FIXME: Try to send data to card here */ if (!dev->context_flag) { if (drm_lock_free(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT)) { DRM_ERROR("\n"); } }#if LINUX_VERSION_CODE < 0x020400 if (lock.context != tdfx_res_ctx.handle) { current->counter = 5; current->priority = DEF_PRIORITY; }#endif unblock_all_signals(); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -