From a885d6786f40fd0c4dbcb09a17f6e103d0949ed7 Mon Sep 17 00:00:00 2001
From: Eric Anholt <anholt@freebsd.org>
Date: Fri, 6 Dec 2002 02:27:30 +0000
Subject: Add vblank signal code for BSD DRM. Untested so far, but working with
 a     4.2.0 userland at least.

---
 bsd-core/drmP.h    | 11 +++++++++
 bsd-core/drm_dma.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 69 insertions(+), 7 deletions(-)

(limited to 'bsd-core')

diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h
index b7b21da4..541bc2eb 100644
--- a/bsd-core/drmP.h
+++ b/bsd-core/drmP.h
@@ -392,6 +392,14 @@ typedef struct drm_map_list_entry {
 	drm_map_t	*map;
 } drm_map_list_entry_t;
 
+TAILQ_HEAD(drm_vbl_sig_list, drm_vbl_sig);
+typedef struct drm_vbl_sig {
+	TAILQ_ENTRY(drm_vbl_sig) link;
+	unsigned int	sequence;
+	int		signo;
+	int		pid;
+} drm_vbl_sig_t;
+
 struct drm_device {
 #ifdef __NetBSD__
 	struct device	  device;	/* NetBSD's softc is an extension of struct device */
@@ -469,6 +477,8 @@ struct drm_device {
 #if __HAVE_VBL_IRQ
    	wait_queue_head_t vbl_queue;	/* vbl wait channel */
    	atomic_t          vbl_received;
+	struct drm_vbl_sig_list vbl_sig_list;
+	DRM_SPINTYPE      vbl_lock;
 #endif
 	cycles_t	  ctx_start;
 	cycles_t	  lck_start;
@@ -613,6 +623,7 @@ extern drm_buf_t     *DRM(freelist_get)(drm_freelist_t *bl, int block);
 #endif /* __HAVE_DMA */
 #if __HAVE_VBL_IRQ
 extern int           DRM(vblank_wait)(drm_device_t *dev, unsigned int *vbl_seq);
+extern void          DRM(vbl_send_signals)( drm_device_t *dev );
 #endif
 
 #if __REALLY_HAVE_AGP
diff --git a/bsd-core/drm_dma.c b/bsd-core/drm_dma.c
index 5632b5a2..69c66c9a 100644
--- a/bsd-core/drm_dma.c
+++ b/bsd-core/drm_dma.c
@@ -524,6 +524,11 @@ int DRM(irq_install)( drm_device_t *dev, int irq )
 	TASK_INIT(&dev->task, 0, DRM(dma_immediate_bh), dev);
 #endif
 
+#if __HAVE_VBL_IRQ
+	DRM_SPININIT( dev->vbl_lock, "vblsig" );
+	TAILQ_INIT( &dev->vbl_sig_list );
+#endif
+
 				/* Before installing handler */
 	DRM(driver_irq_preinstall)( dev );
 
@@ -612,21 +617,67 @@ int DRM(wait_vblank)( DRM_IOCTL_ARGS )
 	DRM_COPY_FROM_USER_IOCTL( vblwait, (drm_wait_vblank_t *)data,
 				  sizeof(vblwait) );
 
-	if ( vblwait.type == _DRM_VBLANK_RELATIVE ) {
-		vblwait.sequence += atomic_read( &dev->vbl_received );
+	if (vblwait.request.type & _DRM_VBLANK_RELATIVE) {
+		vblwait.request.sequence += atomic_read(&dev->vbl_received);
 	}
 
-	ret = DRM(vblank_wait)( dev, &vblwait.sequence );
-
-	microtime( &now );
-	vblwait.tval_sec = now.tv_sec;
-	vblwait.tval_usec = now.tv_usec;
+	flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
+	if (flags & _DRM_VBLANK_SIGNAL) {
+		drm_vbl_sig_t *vbl_sig = DRM_MALLOC(sizeof(drm_vbl_sig_t));
+		if (vbl_sig == NULL)
+			return ENOMEM;
+		bzero(vbl_sig, sizeof(*vbl_sig));
+		
+		vbl_sig->sequence = vblwait.request.sequence;
+		vbl_sig->signo = vblwait.request.signal;
+		vbl_sig->pid = DRM_CURRENTPID;
+
+		vblwait.reply.sequence = atomic_read(&dev->vbl_received);
+		
+		DRM_SPINLOCK(&dev->vbl_lock);
+		TAILQ_INSERT_HEAD(&dev->vbl_sig_list, vbl_sig, link);
+		DRM_SPINUNLOCK(&dev->vbl_lock);
+		ret = 0;
+	} else {
+		ret = DRM(vblank_wait)(dev, &vblwait.request.sequence);
+		
+		microtime(&now);
+		vblwait.reply.tval_sec = now.tv_sec;
+		vblwait.reply.tval_usec = now.tv_usec;
+	}
 
 	DRM_COPY_TO_USER_IOCTL( (drm_wait_vblank_t *)data, vblwait,
 				sizeof(vblwait) );
 
 	return ret;
 }
+
+void DRM(vbl_send_signals)( drm_device_t *dev )
+{
+	drm_vbl_sig_t *vbl_sig;
+	unsigned int vbl_seq = atomic_read( &dev->vbl_received );
+	struct proc *p;
+
+	DRM_SPINLOCK(&dev->vbl_lock);
+
+	vbl_sig = TAILQ_FIRST(&dev->vbl_sig_list);
+	while (vbl_sig != NULL) {
+		drm_vbl_sig_t *next = TAILQ_NEXT(vbl_sig, link);
+
+		if ( ( vbl_seq - vbl_sig->sequence ) <= (1<<23) ) {
+			p = pfind(vbl_sig->pid);
+			if (p != NULL)
+				psignal(p, vbl_sig->signo);
+
+			TAILQ_REMOVE(&dev->vbl_sig_list, vbl_sig, link);
+			DRM_FREE(vbl_sig);
+		}
+		vbl_sig = next;
+	}
+
+	DRM_SPINUNLOCK(&dev->vbl_lock);
+}
+
 #endif /*  __HAVE_VBL_IRQ */
 
 #else
-- 
cgit v1.2.3