summaryrefslogtreecommitdiff
path: root/linux
diff options
context:
space:
mode:
authorMichel Daenzer <michel@daenzer.net>2002-09-25 17:18:19 +0000
committerMichel Daenzer <michel@daenzer.net>2002-09-25 17:18:19 +0000
commit55acd0d5a64a2ee6b0cecc75872fbf8c4bb42a0c (patch)
tree35851b96a577b91c5a41de9d4b390d038f558fce /linux
parentf1c8fe95578e15d5eece6ad52540ce2c7c671f70 (diff)
common ioctl to wait for vertical blank IRQs
Diffstat (limited to 'linux')
-rw-r--r--linux/drm.h15
-rw-r--r--linux/drmP.h12
-rw-r--r--linux/drm_dma.h82
-rw-r--r--linux/drm_drv.h4
4 files changed, 110 insertions, 3 deletions
diff --git a/linux/drm.h b/linux/drm.h
index 376568e0..f26d4442 100644
--- a/linux/drm.h
+++ b/linux/drm.h
@@ -345,6 +345,19 @@ typedef struct drm_irq_busid {
int funcnum;
} drm_irq_busid_t;
+typedef enum {
+ _DRM_VBLANK_ABSOLUTE = 0x0, /* Wait for specific vblank sequence number */
+ _DRM_VBLANK_RELATIVE = 0x1 /* Wait for given number of vblanks */
+} drm_vblank_seq_type_t;
+
+typedef struct drm_radeon_vbl_wait {
+ drm_vblank_seq_type_t type;
+ unsigned int sequence;
+ long tval_sec;
+ long tval_usec;
+} drm_wait_vblank_t;
+
+
typedef struct drm_agp_mode {
unsigned long mode;
} drm_agp_mode_t;
@@ -439,6 +452,8 @@ typedef struct drm_scatter_gather {
#define DRM_IOCTL_SG_ALLOC DRM_IOW( 0x38, drm_scatter_gather_t)
#define DRM_IOCTL_SG_FREE DRM_IOW( 0x39, drm_scatter_gather_t)
+#define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, drm_wait_vblank_t)
+
/* Device specfic ioctls should only be in their respective headers
* The device specific ioctl range is 0x40 to 0x79. */
#define DRM_COMMAND_BASE 0x40
diff --git a/linux/drmP.h b/linux/drmP.h
index 7d82fce3..6f6f91c4 100644
--- a/linux/drmP.h
+++ b/linux/drmP.h
@@ -577,6 +577,10 @@ typedef struct drm_device {
int last_context; /* Last current context */
unsigned long last_switch; /* jiffies at last context switch */
struct tq_struct tq;
+#if __HAVE_VBL_IRQ
+ wait_queue_head_t vbl_queue;
+ atomic_t vbl_received;
+#endif
cycles_t ctx_start;
cycles_t lck_start;
#if __HAVE_DMA_HISTOGRAM
@@ -809,6 +813,14 @@ extern int DRM(irq_install)( drm_device_t *dev, int irq );
extern int DRM(irq_uninstall)( drm_device_t *dev );
extern void DRM(dma_service)( int irq, void *device,
struct pt_regs *regs );
+extern void DRM(driver_irq_preinstall)( drm_device_t *dev );
+extern void DRM(driver_irq_postinstall)( drm_device_t *dev );
+extern void DRM(driver_irq_uninstall)( drm_device_t *dev );
+#if __HAVE_VBL_IRQ
+extern int DRM(wait_vblank)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int DRM(vblank_wait)(drm_device_t *dev, unsigned int *vbl_seq);
+#endif
#if __HAVE_DMA_IRQ_BH
extern void DRM(dma_immediate_bh)( void *dev );
#endif
diff --git a/linux/drm_dma.h b/linux/drm_dma.h
index dce376f6..2938c77a 100644
--- a/linux/drm_dma.h
+++ b/linux/drm_dma.h
@@ -538,8 +538,12 @@ int DRM(irq_install)( drm_device_t *dev, int irq )
dev->tq.data = dev;
#endif
+#if __HAVE_VBL_IRQ
+ init_waitqueue_head(&dev->vbl_queue);
+#endif
+
/* Before installing handler */
- DRIVER_PREINSTALL();
+ DRM(driver_irq_preinstall)(dev);
/* Install handler */
ret = request_irq( dev->irq, DRM(dma_service),
@@ -552,7 +556,7 @@ int DRM(irq_install)( drm_device_t *dev, int irq )
}
/* After installing handler */
- DRIVER_POSTINSTALL();
+ DRM(driver_irq_postinstall)(dev);
return 0;
}
@@ -571,7 +575,7 @@ int DRM(irq_uninstall)( drm_device_t *dev )
DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq );
- DRIVER_UNINSTALL();
+ DRM(driver_irq_uninstall)( dev );
free_irq( irq, dev );
@@ -598,6 +602,78 @@ int DRM(control)( struct inode *inode, struct file *filp,
}
}
+#if __HAVE_VBL_IRQ
+
+int DRM(vblank_wait)(drm_device_t *dev, unsigned int *sequence)
+{
+ drm_radeon_private_t *dev_priv =
+ (drm_radeon_private_t *)dev->dev_private;
+ unsigned int cur_vblank;
+ int ret = 0;
+
+ if ( !dev_priv ) {
+ DRM_ERROR( "%s called with no initialization\n", __func__ );
+ return DRM_ERR(EINVAL);
+ }
+
+ /* Assume that the user has missed the current sequence number by about
+ * a day rather than she wants to wait for years using vertical blanks :)
+ */
+ while ( ( ( cur_vblank = atomic_read(&dev->vbl_received ) )
+ + ~*sequence + 1 ) > (1<<23) ) {
+ dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
+#ifdef __linux__
+ interruptible_sleep_on( &dev->vbl_queue );
+
+ if (signal_pending(current)) {
+ ret = -EINTR;
+ break;
+ }
+#endif /* __linux__ */
+#ifdef __FreeBSD__
+ ret = tsleep( &dev_priv->vbl_queue, 3*hz, "rdnvbl", PZERO | PCATCH);
+ if (ret)
+ break;
+#endif /* __FreeBSD__ */
+ }
+
+ *sequence = cur_vblank;
+
+ return ret;
+}
+
+int DRM(wait_vblank)( DRM_IOCTL_ARGS )
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_wait_vblank_t vblwait;
+ struct timeval now;
+ int ret;
+
+ if (!dev->irq)
+ return -EINVAL;
+
+ 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 );
+ }
+
+ ret = DRM(vblank_wait)( dev, &vblwait.sequence );
+
+ do_gettimeofday( &now );
+ vblwait.tval_sec = now.tv_sec;
+ vblwait.tval_usec = now.tv_usec;
+
+ DRM_COPY_TO_USER_IOCTL( (drm_wait_vblank_t *)data, vblwait,
+ sizeof(vblwait) );
+
+ return ret;
+}
+
+#endif /* __HAVE_VBL_IRQ */
+
#else
int DRM(control)( struct inode *inode, struct file *filp,
diff --git a/linux/drm_drv.h b/linux/drm_drv.h
index 7e2cfd8c..3ebe7811 100644
--- a/linux/drm_drv.h
+++ b/linux/drm_drv.h
@@ -222,6 +222,10 @@ static drm_ioctl_desc_t DRM(ioctls)[] = {
[DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = { DRM(sg_free), 1, 1 },
#endif
+#if __HAVE_VBL_IRQ
+ [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = { DRM(wait_vblank), 0, 0 },
+#endif
+
DRIVER_IOCTLS
};