Two parts to this, one is simple unplug from sysfs for the device node.
The second adds an unplugged state, if we have device opens, we
just set the unplugged state and return, if we have no device
opens we drop the drm device.
If after a lastclose we discover we are unplugged we then
drop the drm device.
v2: use an atomic for unplugged and wrap it for users,
add checks on open + mmap + ioctl entry points.
Signed-off-by: Dave Airlie <airlied@redhat.com>
unsigned int usize, asize;
dev = file_priv->minor->dev;
+
+ if (drm_device_is_unplugged(dev))
+ return -ENODEV;
+
atomic_inc(&dev->ioctl_count);
atomic_inc(&dev->counts[_DRM_STAT_IOCTLS]);
++file_priv->ioctl_count;
if (!(dev = minor->dev))
return -ENODEV;
+ if (drm_device_is_unplugged(dev))
+ return -ENODEV;
+
retcode = drm_open_helper(inode, filp, dev);
if (!retcode) {
atomic_inc(&dev->counts[_DRM_STAT_OPENS]);
if (!(dev = minor->dev))
goto out;
+ if (drm_device_is_unplugged(dev))
+ goto out;
+
old_fops = filp->f_op;
filp->f_op = fops_get(dev->driver->fops);
if (filp->f_op == NULL) {
retcode = -EBUSY;
} else
retcode = drm_lastclose(dev);
+ if (drm_device_is_unplugged(dev))
+ drm_put_dev(dev);
}
mutex_unlock(&drm_global_mutex);
struct drm_hash_item *hash;
int ret = 0;
+ if (drm_device_is_unplugged(dev))
+ return -ENODEV;
+
mutex_lock(&dev->struct_mutex);
if (drm_ht_find_item(&mm->offset_hash, vma->vm_pgoff, &hash)) {
return 0;
}
+static void drm_unplug_minor(struct drm_minor *minor)
+{
+ drm_sysfs_device_remove(minor);
+}
+
/**
* Called via drm_exit() at module unload time or when pci device is
* unplugged.
kfree(dev);
}
EXPORT_SYMBOL(drm_put_dev);
+
+void drm_unplug_dev(struct drm_device *dev)
+{
+ /* for a USB device */
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
+ drm_unplug_minor(dev->control);
+ drm_unplug_minor(dev->primary);
+
+ mutex_lock(&drm_global_mutex);
+
+ drm_device_set_unplugged(dev);
+
+ if (dev->open_count == 0) {
+ drm_put_dev(dev);
+ }
+ mutex_unlock(&drm_global_mutex);
+}
+EXPORT_SYMBOL(drm_unplug_dev);
struct drm_device *dev = priv->minor->dev;
int ret;
+ if (drm_device_is_unplugged(dev))
+ return -ENODEV;
+
mutex_lock(&dev->struct_mutex);
ret = drm_mmap_locked(filp, vma);
mutex_unlock(&dev->struct_mutex);
struct idr object_name_idr;
/*@} */
int switch_power_state;
+
+ atomic_t unplugged; /* device has been unplugged or gone away */
};
#define DRM_SWITCH_POWER_ON 0
}
#endif
+static inline void drm_device_set_unplugged(struct drm_device *dev)
+{
+ smp_wmb();
+ atomic_set(&dev->unplugged, 1);
+}
+
+static inline int drm_device_is_unplugged(struct drm_device *dev)
+{
+ int ret = atomic_read(&dev->unplugged);
+ smp_rmb();
+ return ret;
+}
+
/******************************************************************/
/** \name Internal function definitions */
/*@{*/
extern void drm_put_dev(struct drm_device *dev);
extern int drm_put_minor(struct drm_minor **minor);
+extern void drm_unplug_dev(struct drm_device *dev);
extern unsigned int drm_debug;
extern unsigned int drm_vblank_offdelay;