static long mbochs_ioctl(struct vfio_device *vdev, unsigned int cmd,
			 unsigned long arg)
{
	struct mdev_state *mdev_state =
		container_of(vdev, struct mdev_state, vdev);
	int ret = 0;
	unsigned long minsz, outsz;

	switch (cmd) {
	case VFIO_DEVICE_GET_INFO:
	{
		struct vfio_device_info info;

		minsz = offsetofend(struct vfio_device_info, num_irqs);

		if (copy_from_user(&info, (void __user *)arg, minsz))
			return -EFAULT;

		if (info.argsz < minsz)
			return -EINVAL;

		ret = mbochs_get_device_info(&info);
		if (ret)
			return ret;

		if (copy_to_user((void __user *)arg, &info, minsz))
			return -EFAULT;

		return 0;
	}
	case VFIO_DEVICE_GET_REGION_INFO:
	{
		struct vfio_region_info_ext info;

		minsz = offsetofend(typeof(info), base.offset);

		if (copy_from_user(&info, (void __user *)arg, minsz))
			return -EFAULT;

		outsz = info.base.argsz;
		if (outsz < minsz)
			return -EINVAL;
		if (outsz > sizeof(info))
			return -EINVAL;

		ret = mbochs_get_region_info(mdev_state, &info);
		if (ret)
			return ret;

		if (copy_to_user((void __user *)arg, &info, outsz))
			return -EFAULT;

		return 0;
	}

	case VFIO_DEVICE_GET_IRQ_INFO:
	{
		struct vfio_irq_info info;

		minsz = offsetofend(struct vfio_irq_info, count);

		if (copy_from_user(&info, (void __user *)arg, minsz))
			return -EFAULT;

		if ((info.argsz < minsz) ||
		    (info.index >= VFIO_PCI_NUM_IRQS))
			return -EINVAL;

		ret = mbochs_get_irq_info(&info);
		if (ret)
			return ret;

		if (copy_to_user((void __user *)arg, &info, minsz))
			return -EFAULT;

		return 0;
	}

	case VFIO_DEVICE_QUERY_GFX_PLANE:
	{
		struct vfio_device_gfx_plane_info plane;

		minsz = offsetofend(struct vfio_device_gfx_plane_info,
				    region_index);

		if (copy_from_user(&plane, (void __user *)arg, minsz))
			return -EFAULT;

		if (plane.argsz < minsz)
			return -EINVAL;

		ret = mbochs_query_gfx_plane(mdev_state, &plane);
		if (ret)
			return ret;

		if (copy_to_user((void __user *)arg, &plane, minsz))
			return -EFAULT;

		return 0;
	}

	case VFIO_DEVICE_GET_GFX_DMABUF:
	{
		u32 dmabuf_id;

		if (get_user(dmabuf_id, (__u32 __user *)arg))
			return -EFAULT;

		return mbochs_get_gfx_dmabuf(mdev_state, dmabuf_id);
	}

	case VFIO_DEVICE_SET_IRQS:
		return -EINVAL;

	case VFIO_DEVICE_RESET:
		return mbochs_reset(mdev_state);
	}
	return -ENOTTY;
}
static long mbochs_ioctl(struct vfio_device *vdev, unsigned int cmd,
			 unsigned long arg)
{
	struct mdev_state *mdev_state =
		container_of(vdev, struct mdev_state, vdev);
	int ret = 0;
	unsigned long minsz, outsz;

	switch (cmd) {
	case VFIO_DEVICE_GET_INFO:
	{
		struct vfio_device_info info;

		minsz = offsetofend(struct vfio_device_info, num_irqs);

		if (copy_from_user(&info, (void __user *)arg, minsz))
			return -EFAULT;

		if (info.argsz < minsz)
			return -EINVAL;

		ret = mbochs_get_device_info(&info);
		if (ret)
			return ret;

		if (copy_to_user((void __user *)arg, &info, minsz))
			return -EFAULT;

		return 0;
	}
	case VFIO_DEVICE_GET_REGION_INFO:
	{
		struct vfio_region_info_ext info;

		minsz = offsetofend(typeof(info), base.offset);

		if (copy_from_user(&info, (void __user *)arg, minsz))
			return -EFAULT;

		outsz = info.base.argsz;
		if (outsz < minsz)
			return -EINVAL;
		if (outsz > sizeof(info))
			return -EINVAL;

		ret = mbochs_get_region_info(mdev_state, &info);
		if (ret)
			return ret;

		if (copy_to_user((void __user *)arg, &info, outsz))
			return -EFAULT;

		return 0;
	}

	case VFIO_DEVICE_GET_IRQ_INFO:
	{
		struct vfio_irq_info info;

		minsz = offsetofend(struct vfio_irq_info, count);

		if (copy_from_user(&info, (void __user *)arg, minsz))
			return -EFAULT;

		if ((info.argsz < minsz) ||
		    (info.index >= VFIO_PCI_NUM_IRQS))
			return -EINVAL;

		ret = mbochs_get_irq_info(&info);
		if (ret)
			return ret;

		if (copy_to_user((void __user *)arg, &info, minsz))
			return -EFAULT;

		return 0;
	}

	case VFIO_DEVICE_QUERY_GFX_PLANE:
	{
		struct vfio_device_gfx_plane_info plane;

		minsz = offsetofend(struct vfio_device_gfx_plane_info,
				    region_index);

		if (copy_from_user(&plane, (void __user *)arg, minsz))
			return -EFAULT;

		if (plane.argsz < minsz)
			return -EINVAL;

		ret = mbochs_query_gfx_plane(mdev_state, &plane);
		if (ret)
			return ret;

		if (copy_to_user((void __user *)arg, &plane, minsz))
			return -EFAULT;

		return 0;
	}

	case VFIO_DEVICE_GET_GFX_DMABUF:
	{
		u32 dmabuf_id;

		if (get_user(dmabuf_id, (__u32 __user *)arg))
			return -EFAULT;

		return mbochs_get_gfx_dmabuf(mdev_state, dmabuf_id);
	}

	case VFIO_DEVICE_SET_IRQS:
		return -EINVAL;

	case VFIO_DEVICE_RESET:
		return mbochs_reset(mdev_state);
	}
	return -ENOTTY;
}