*/
  u32 drm_vblank_count(struct drm_device *dev, int crtc)
  {
 -      return atomic_read(&dev->vblank[crtc].count);
 +      struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
 +
+       if (WARN_ON(crtc >= dev->num_crtcs))
+               return 0;
 +      return atomic_read(&vblank->count);
  }
  EXPORT_SYMBOL(drm_vblank_count);
  
  u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
                              struct timeval *vblanktime)
  {
 +      struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
        u32 cur_vblank;
  
+       if (WARN_ON(crtc >= dev->num_crtcs))
+               return 0;
+ 
        /* Read timestamp from slot of _vblank_time ringbuffer
         * that corresponds to current vblank count. Retry if
         * count has incremented during readout. This works like
        unsigned long irqflags;
        int ret = 0;
  
+       if (WARN_ON(crtc >= dev->num_crtcs))
+               return -EINVAL;
+ 
        spin_lock_irqsave(&dev->vbl_lock, irqflags);
        /* Going from 0->1 means we have to enable interrupts again */
 -      if (atomic_add_return(1, &dev->vblank[crtc].refcount) == 1) {
 +      if (atomic_add_return(1, &vblank->refcount) == 1) {
                ret = drm_vblank_enable(dev, crtc);
        } else {
 -              if (!dev->vblank[crtc].enabled) {
 -                      atomic_dec(&dev->vblank[crtc].refcount);
 +              if (!vblank->enabled) {
 +                      atomic_dec(&vblank->refcount);
                        ret = -EINVAL;
                }
        }
   */
  void drm_vblank_put(struct drm_device *dev, int crtc)
  {
 -      BUG_ON(atomic_read(&dev->vblank[crtc].refcount) == 0);
 +      struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
 +
 +      BUG_ON(atomic_read(&vblank->refcount) == 0);
  
+       if (WARN_ON(crtc >= dev->num_crtcs))
+               return;
+ 
        /* Last user schedules interrupt disable */
 -      if (atomic_dec_and_test(&dev->vblank[crtc].refcount) &&
 -          (drm_vblank_offdelay > 0))
 -              mod_timer(&dev->vblank[crtc].disable_timer,
 -                        jiffies + ((drm_vblank_offdelay * HZ)/1000));
 +      if (atomic_dec_and_test(&vblank->refcount)) {
 +              if (drm_vblank_offdelay == 0)
 +                      return;
 +              else if (dev->vblank_disable_immediate || drm_vblank_offdelay < 0)
 +                      vblank_disable_fn((unsigned long)vblank);
 +              else
 +                      mod_timer(&vblank->disable_timer,
 +                                jiffies + ((drm_vblank_offdelay * HZ)/1000));
 +      }
  }
  EXPORT_SYMBOL(drm_vblank_put);
  
        unsigned long irqflags;
        unsigned int seq;
  
 -      spin_lock_irqsave(&dev->vbl_lock, irqflags);
+       if (WARN_ON(crtc >= dev->num_crtcs))
+               return;
+ 
 +      spin_lock_irqsave(&dev->event_lock, irqflags);
 +
 +      spin_lock(&dev->vbl_lock);
        vblank_disable_and_save(dev, crtc);
 -      wake_up(&dev->vblank[crtc].queue);
 +      wake_up(&vblank->queue);
 +
 +      /*
 +       * Prevent subsequent drm_vblank_get() from re-enabling
 +       * the vblank interrupt by bumping the refcount.
 +       */
 +      if (!vblank->inmodeset) {
 +              atomic_inc(&vblank->refcount);
 +              vblank->inmodeset = 1;
 +      }
 +      spin_unlock(&dev->vbl_lock);
  
        /* Send any queued vblank events, lest the natives grow disquiet */
        seq = drm_vblank_count_and_time(dev, crtc, &now);
   */
  void drm_vblank_on(struct drm_device *dev, int crtc)
  {
 +      struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
        unsigned long irqflags;
  
+       if (WARN_ON(crtc >= dev->num_crtcs))
+               return;
+ 
        spin_lock_irqsave(&dev->vbl_lock, irqflags);
 -      /* re-enable interrupts if there's are users left */
 -      if (atomic_read(&dev->vblank[crtc].refcount) != 0)
 +      /* Drop our private "prevent drm_vblank_get" refcount */
 +      if (vblank->inmodeset) {
 +              atomic_dec(&vblank->refcount);
 +              vblank->inmodeset = 0;
 +      }
 +
 +      /*
 +       * sample the current counter to avoid random jumps
 +       * when drm_vblank_enable() applies the diff
 +       *
 +       * -1 to make sure user will never see the same
 +       * vblank counter value before and after a modeset
 +       */
 +      vblank->last =
 +              (dev->driver->get_vblank_counter(dev, crtc) - 1) &
 +              dev->max_vblank_count;
 +      /*
 +       * re-enable interrupts if there are users left, or the
 +       * user wishes vblank interrupts to be enabled all the time.
 +       */
 +      if (atomic_read(&vblank->refcount) != 0 ||
 +          (!dev->vblank_disable_immediate && drm_vblank_offdelay == 0))
                WARN_ON(drm_vblank_enable(dev, crtc));
        spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
  }
        if (!dev->num_crtcs)
                return false;
  
+       if (WARN_ON(crtc >= dev->num_crtcs))
+               return false;
+ 
 +      spin_lock_irqsave(&dev->event_lock, irqflags);
 +
        /* Need timestamp lock to prevent concurrent execution with
         * vblank enable/disable, as this would cause inconsistent
         * or corrupted timestamps and vblank counts.