⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gamma_dma.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 2 页
字号:
			continue;		}		buf = dma->buflist[ idx ];		if (buf->pid != current->pid) {			DRM_ERROR("Process %d using buffer owned by %d\n",				  current->pid, buf->pid);			retcode = -EINVAL;			goto cleanup;		}		if (buf->list != DRM_LIST_NONE) {			DRM_ERROR("Process %d using %d's buffer on list %d\n",				  current->pid, buf->pid, buf->list);			retcode = -EINVAL;			goto cleanup;		}				/* This isn't a race condition on				   buf->list, since our concern is the				   buffer reclaim during the time the				   process closes the /dev/drm? handle, so				   it can't also be doing DMA. */		buf->list	  = DRM_LIST_PRIO;		buf->used	  = d->send_sizes[i];		buf->context	  = d->context;		buf->while_locked = d->flags & _DRM_DMA_WHILE_LOCKED;		address		  = (unsigned long)buf->address;		length		  = buf->used;		if (!length) {			DRM_ERROR("0 length buffer\n");		}		if (buf->pending) {			DRM_ERROR("Sending pending buffer:"				  " buffer %d, offset %d\n",				  d->send_indices[i], i);			retcode = -EINVAL;			goto cleanup;		}		if (buf->waiting) {			DRM_ERROR("Sending waiting buffer:"				  " buffer %d, offset %d\n",				  d->send_indices[i], i);			retcode = -EINVAL;			goto cleanup;		}		buf->pending = 1;				if (dev->last_context != buf->context		    && !(dev->queuelist[buf->context]->flags			 & _DRM_CONTEXT_PRESERVED)) {			add_wait_queue(&dev->context_wait, &entry);			current->state = TASK_INTERRUPTIBLE;				/* PRE: dev->last_context != buf->context */			drm_context_switch(dev, dev->last_context,					   buf->context);				/* POST: we will wait for the context				   switch and will dispatch on a later call				   when dev->last_context == buf->context.				   NOTE WE HOLD THE LOCK THROUGHOUT THIS				   TIME! */			schedule();			current->state = TASK_RUNNING;			remove_wait_queue(&dev->context_wait, &entry);			if (signal_pending(current)) {				retcode = -EINTR;				goto cleanup;			}			if (dev->last_context != buf->context) {				DRM_ERROR("Context mismatch: %d %d\n",					  dev->last_context,					  buf->context);			}		}#if DRM_DMA_HISTOGRAM		buf->time_queued     = get_cycles();		buf->time_dispatched = buf->time_queued;#endif		gamma_dma_dispatch(dev, address, length);		atomic_add(length, &dma->total_bytes);		atomic_inc(&dma->total_dmas);				if (last_buf) {			drm_free_buffer(dev, last_buf);		}		last_buf = buf;	}cleanup:	if (last_buf) {		gamma_dma_ready(dev);		drm_free_buffer(dev, last_buf);	}		if (must_free && !dev->context_flag) {		if (drm_lock_free(dev, &dev->lock.hw_lock->lock,				  DRM_KERNEL_CONTEXT)) {			DRM_ERROR("\n");		}	}	clear_bit(0, &dev->interrupt_flag);	return retcode;}static int gamma_dma_send_buffers(drm_device_t *dev, drm_dma_t *d){	DECLARE_WAITQUEUE(entry, current);	drm_buf_t	  *last_buf = NULL;	int		  retcode   = 0;	drm_device_dma_t  *dma	    = dev->dma;	if (d->flags & _DRM_DMA_BLOCK) {		last_buf = dma->buflist[d->send_indices[d->send_count-1]];		add_wait_queue(&last_buf->dma_wait, &entry);	}		if ((retcode = drm_dma_enqueue(dev, d))) {		if (d->flags & _DRM_DMA_BLOCK)			remove_wait_queue(&last_buf->dma_wait, &entry);		return retcode;	}		gamma_dma_schedule(dev, 0);		if (d->flags & _DRM_DMA_BLOCK) {		DRM_DEBUG("%d waiting\n", current->pid);		for (;;) {			current->state = TASK_INTERRUPTIBLE;			if (!last_buf->waiting && !last_buf->pending)				break; /* finished */			schedule();			if (signal_pending(current)) {				retcode = -EINTR; /* Can't restart */				break;			}		}		current->state = TASK_RUNNING;		DRM_DEBUG("%d running\n", current->pid);		remove_wait_queue(&last_buf->dma_wait, &entry);		if (!retcode		    || (last_buf->list==DRM_LIST_PEND && !last_buf->pending)) {			if (!waitqueue_active(&last_buf->dma_wait)) {				drm_free_buffer(dev, last_buf);			}		}		if (retcode) {			DRM_ERROR("ctx%d w%d p%d c%d i%d l%d %d/%d\n",				  d->context,				  last_buf->waiting,				  last_buf->pending,				  DRM_WAITCOUNT(dev, d->context),				  last_buf->idx,				  last_buf->list,				  last_buf->pid,				  current->pid);		}	}	return retcode;}int gamma_dma(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_device_dma_t  *dma	    = dev->dma;	int		  retcode   = 0;	drm_dma_t	  d;	if (copy_from_user(&d, (drm_dma_t *)arg, sizeof(d)))		return -EFAULT;	DRM_DEBUG("%d %d: %d send, %d req\n",		  current->pid, d.context, d.send_count, d.request_count);	if (d.context == DRM_KERNEL_CONTEXT || d.context >= dev->queue_slots) {		DRM_ERROR("Process %d using context %d\n",			  current->pid, d.context);		return -EINVAL;	}	if (d.send_count < 0 || d.send_count > dma->buf_count) {		DRM_ERROR("Process %d trying to send %d buffers (of %d max)\n",			  current->pid, d.send_count, dma->buf_count);		return -EINVAL;	}	if (d.request_count < 0 || d.request_count > dma->buf_count) {		DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",			  current->pid, d.request_count, dma->buf_count);		return -EINVAL;	}	if (d.send_count) {		if (d.flags & _DRM_DMA_PRIORITY)			retcode = gamma_dma_priority(dev, &d);		else 			retcode = gamma_dma_send_buffers(dev, &d);	}	d.granted_count = 0;	if (!retcode && d.request_count) {		retcode = drm_dma_get_buffers(dev, &d);	}	DRM_DEBUG("%d returning, granted = %d\n",		  current->pid, d.granted_count);	if (copy_to_user((drm_dma_t *)arg, &d, sizeof(d)))		return -EFAULT;	return retcode;}int gamma_irq_install(drm_device_t *dev, int irq){	int retcode;	if (!irq)     return -EINVAL;		down(&dev->struct_sem);	if (dev->irq) {		up(&dev->struct_sem);		return -EBUSY;	}	dev->irq = irq;	up(&dev->struct_sem);		DRM_DEBUG("%d\n", irq);	dev->context_flag     = 0;	dev->interrupt_flag   = 0;	dev->dma_flag	      = 0;		dev->dma->next_buffer = NULL;	dev->dma->next_queue  = NULL;	dev->dma->this_buffer = NULL;	INIT_LIST_HEAD(&dev->tq.list);	dev->tq.sync	      = 0;	dev->tq.routine	      = gamma_dma_schedule_tq_wrapper;	dev->tq.data	      = dev;				/* Before installing handler */	GAMMA_WRITE(GAMMA_GCOMMANDMODE, 0);	GAMMA_WRITE(GAMMA_GDMACONTROL, 0);					/* Install handler */	if ((retcode = request_irq(dev->irq,				   gamma_dma_service,				   0,				   dev->devname,				   dev))) {		down(&dev->struct_sem);		dev->irq = 0;		up(&dev->struct_sem);		return retcode;	}				/* After installing handler */	GAMMA_WRITE(GAMMA_GINTENABLE,	    0x2001);	GAMMA_WRITE(GAMMA_COMMANDINTENABLE, 0x0008);	GAMMA_WRITE(GAMMA_GDELAYTIMER,	   0x39090);		return 0;}int gamma_irq_uninstall(drm_device_t *dev){	int irq;	down(&dev->struct_sem);	irq	 = dev->irq;	dev->irq = 0;	up(&dev->struct_sem);		if (!irq) return -EINVAL;		DRM_DEBUG("%d\n", irq);		GAMMA_WRITE(GAMMA_GDELAYTIMER,	    0);	GAMMA_WRITE(GAMMA_COMMANDINTENABLE, 0);	GAMMA_WRITE(GAMMA_GINTENABLE,	    0);	free_irq(irq, dev);	return 0;}int gamma_control(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_control_t	ctl;	int		retcode;		if (copy_from_user(&ctl, (drm_control_t *)arg, sizeof(ctl)))		return -EFAULT;		switch (ctl.func) {	case DRM_INST_HANDLER:		if ((retcode = gamma_irq_install(dev, ctl.irq)))			return retcode;		break;	case DRM_UNINST_HANDLER:		if ((retcode = gamma_irq_uninstall(dev)))			return retcode;		break;	default:		return -EINVAL;	}	return 0;}int gamma_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;	drm_queue_t	  *q;#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 (lock.context < 0 || lock.context >= dev->queue_count)		return -EINVAL;	q = dev->queuelist[lock.context];		ret = drm_flush_block_and_flush(dev, lock.context, lock.flags);	if (!ret) {		if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)		    != lock.context) {			long j = jiffies - dev->lock.lock_time;			if (j > 0 && j <= DRM_LOCK_SLICE) {				/* Can't take lock if we just had it and				   there is contention. */				current->state = TASK_INTERRUPTIBLE;				schedule_timeout(j);			}		}		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);				atomic_inc(&q->total_locks);				break;	/* Got lock */			}							/* Contention */			atomic_inc(&dev->total_sleeps);			schedule();			if (signal_pending(current)) {				ret = -ERESTARTSYS;				break;			}		}		current->state = TASK_RUNNING;		remove_wait_queue(&dev->lock.lock_queue, &entry);	}	drm_flush_unblock(dev, lock.context, lock.flags); /* cleanup phase */		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)			gamma_dma_ready(dev);		if (lock.flags & _DRM_LOCK_QUIESCENT) {			if (gamma_found() == 1) {				gamma_dma_quiescent_single(dev);			} else {				gamma_dma_quiescent_dual(dev);			}		}	}	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;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -