int drm_vblank_get(struct drm_device *dev, int crtc) { struct drm_vblank_info *vbl = dev->vblank; int ret = 0; if (dev->irq_enabled == 0) return (EINVAL); mtx_enter(&vbl->vb_lock); DPRINTF("%s: %d refs = %d\n", __func__, crtc, vbl->vb_crtcs[crtc].vbl_refs); vbl->vb_crtcs[crtc].vbl_refs++; if (vbl->vb_crtcs[crtc].vbl_refs == 1 && vbl->vb_crtcs[crtc].vbl_enabled == 0) { if ((ret = dev->driver->enable_vblank(dev, crtc)) == 0) { vbl->vb_crtcs[crtc].vbl_enabled = 1; drm_update_vblank_count(dev, crtc); } else { vbl->vb_crtcs[crtc].vbl_refs--; } } mtx_leave(&vbl->vb_lock); return (ret); }
/** * drm_vblank_get - get a reference count on vblank events * @dev: DRM device * @crtc: which CRTC to own * * Acquire a reference count on vblank events to avoid having them disabled * while in use. * * RETURNS * Zero on success, nonzero on failure. */ int drm_vblank_get(struct drm_device *dev, int crtc) { int ret = 0; mtx_enter(&dev->vbl_lock); /* Going from 0->1 means we have to enable interrupts again */ if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) { mtx_enter(&dev->vblank_time_lock); if (!dev->vblank_enabled[crtc]) { /* Enable vblank irqs under vblank_time_lock protection. * All vblank count & timestamp updates are held off * until we are done reinitializing master counter and * timestamps. Filtercode in drm_handle_vblank() will * prevent double-accounting of same vblank interval. */ ret = dev->driver->enable_vblank(dev, crtc); DPRINTF("enabling vblank on crtc %d, ret: %d\n", crtc, ret); if (ret) atomic_dec(&dev->vblank_refcount[crtc]); else { dev->vblank_enabled[crtc] = 1; drm_update_vblank_count(dev, crtc); } } mtx_leave(&dev->vblank_time_lock); } else { if (!dev->vblank_enabled[crtc]) { atomic_dec(&dev->vblank_refcount[crtc]); ret = -EINVAL; } } mtx_leave(&dev->vbl_lock); return ret; }