| /* | 
 |  * Copyright 2011 Red Hat, Inc. | 
 |  * Copyright © 2014 The Chromium OS Authors | 
 |  * | 
 |  * Permission is hereby granted, free of charge, to any person obtaining a | 
 |  * copy of this software and associated documentation files (the "Software") | 
 |  * to deal in the software without restriction, including without limitation | 
 |  * on the rights to use, copy, modify, merge, publish, distribute, sub | 
 |  * license, and/or sell copies of the Software, and to permit persons to whom | 
 |  * them Software is furnished to do so, subject to the following conditions: | 
 |  * | 
 |  * The above copyright notice and this permission notice (including the next | 
 |  * paragraph) shall be included in all copies or substantial portions of the | 
 |  * Software. | 
 |  * | 
 |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
 |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTIBILITY, | 
 |  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL | 
 |  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER | 
 |  * IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF OR IN | 
 |  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | 
 |  * | 
 |  * Authors: | 
 |  *	Adam Jackson <ajax@redhat.com> | 
 |  *	Ben Widawsky <ben@bwidawsk.net> | 
 |  */ | 
 |  | 
 | /* | 
 |  * This is vgem, a (non-hardware-backed) GEM service.  This is used by Mesa's | 
 |  * software renderer and the X server for efficient buffer sharing. | 
 |  */ | 
 |  | 
 | #include <linux/dma-buf.h> | 
 | #include <linux/module.h> | 
 | #include <linux/platform_device.h> | 
 | #include <linux/shmem_fs.h> | 
 | #include <linux/vmalloc.h> | 
 |  | 
 | #include <drm/drm_drv.h> | 
 | #include <drm/drm_file.h> | 
 | #include <drm/drm_gem_shmem_helper.h> | 
 | #include <drm/drm_ioctl.h> | 
 | #include <drm/drm_managed.h> | 
 | #include <drm/drm_prime.h> | 
 |  | 
 | #include "vgem_drv.h" | 
 |  | 
 | #define DRIVER_NAME	"vgem" | 
 | #define DRIVER_DESC	"Virtual GEM provider" | 
 | #define DRIVER_DATE	"20120112" | 
 | #define DRIVER_MAJOR	1 | 
 | #define DRIVER_MINOR	0 | 
 |  | 
 | static struct vgem_device { | 
 | 	struct drm_device drm; | 
 | 	struct platform_device *platform; | 
 | } *vgem_device; | 
 |  | 
 | static int vgem_open(struct drm_device *dev, struct drm_file *file) | 
 | { | 
 | 	struct vgem_file *vfile; | 
 | 	int ret; | 
 |  | 
 | 	vfile = kzalloc(sizeof(*vfile), GFP_KERNEL); | 
 | 	if (!vfile) | 
 | 		return -ENOMEM; | 
 |  | 
 | 	file->driver_priv = vfile; | 
 |  | 
 | 	ret = vgem_fence_open(vfile); | 
 | 	if (ret) { | 
 | 		kfree(vfile); | 
 | 		return ret; | 
 | 	} | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static void vgem_postclose(struct drm_device *dev, struct drm_file *file) | 
 | { | 
 | 	struct vgem_file *vfile = file->driver_priv; | 
 |  | 
 | 	vgem_fence_close(vfile); | 
 | 	kfree(vfile); | 
 | } | 
 |  | 
 | static struct drm_ioctl_desc vgem_ioctls[] = { | 
 | 	DRM_IOCTL_DEF_DRV(VGEM_FENCE_ATTACH, vgem_fence_attach_ioctl, DRM_RENDER_ALLOW), | 
 | 	DRM_IOCTL_DEF_DRV(VGEM_FENCE_SIGNAL, vgem_fence_signal_ioctl, DRM_RENDER_ALLOW), | 
 | }; | 
 |  | 
 | DEFINE_DRM_GEM_FOPS(vgem_driver_fops); | 
 |  | 
 | static struct drm_gem_object *vgem_gem_create_object(struct drm_device *dev, size_t size) | 
 | { | 
 | 	struct drm_gem_shmem_object *obj; | 
 |  | 
 | 	obj = kzalloc(sizeof(*obj), GFP_KERNEL); | 
 | 	if (!obj) | 
 | 		return NULL; | 
 |  | 
 | 	/* | 
 | 	 * vgem doesn't have any begin/end cpu access ioctls, therefore must use | 
 | 	 * coherent memory or dma-buf sharing just wont work. | 
 | 	 */ | 
 | 	obj->map_wc = true; | 
 |  | 
 | 	return &obj->base; | 
 | } | 
 |  | 
 | static const struct drm_driver vgem_driver = { | 
 | 	.driver_features		= DRIVER_GEM | DRIVER_RENDER, | 
 | 	.open				= vgem_open, | 
 | 	.postclose			= vgem_postclose, | 
 | 	.ioctls				= vgem_ioctls, | 
 | 	.num_ioctls 			= ARRAY_SIZE(vgem_ioctls), | 
 | 	.fops				= &vgem_driver_fops, | 
 |  | 
 | 	DRM_GEM_SHMEM_DRIVER_OPS, | 
 | 	.gem_create_object		= vgem_gem_create_object, | 
 |  | 
 | 	.name	= DRIVER_NAME, | 
 | 	.desc	= DRIVER_DESC, | 
 | 	.date	= DRIVER_DATE, | 
 | 	.major	= DRIVER_MAJOR, | 
 | 	.minor	= DRIVER_MINOR, | 
 | }; | 
 |  | 
 | static int __init vgem_init(void) | 
 | { | 
 | 	int ret; | 
 | 	struct platform_device *pdev; | 
 |  | 
 | 	pdev = platform_device_register_simple("vgem", -1, NULL, 0); | 
 | 	if (IS_ERR(pdev)) | 
 | 		return PTR_ERR(pdev); | 
 |  | 
 | 	if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) { | 
 | 		ret = -ENOMEM; | 
 | 		goto out_unregister; | 
 | 	} | 
 |  | 
 | 	dma_coerce_mask_and_coherent(&pdev->dev, | 
 | 				     DMA_BIT_MASK(64)); | 
 |  | 
 | 	vgem_device = devm_drm_dev_alloc(&pdev->dev, &vgem_driver, | 
 | 					 struct vgem_device, drm); | 
 | 	if (IS_ERR(vgem_device)) { | 
 | 		ret = PTR_ERR(vgem_device); | 
 | 		goto out_devres; | 
 | 	} | 
 | 	vgem_device->platform = pdev; | 
 |  | 
 | 	/* Final step: expose the device/driver to userspace */ | 
 | 	ret = drm_dev_register(&vgem_device->drm, 0); | 
 | 	if (ret) | 
 | 		goto out_devres; | 
 |  | 
 | 	return 0; | 
 |  | 
 | out_devres: | 
 | 	devres_release_group(&pdev->dev, NULL); | 
 | out_unregister: | 
 | 	platform_device_unregister(pdev); | 
 | 	return ret; | 
 | } | 
 |  | 
 | static void __exit vgem_exit(void) | 
 | { | 
 | 	struct platform_device *pdev = vgem_device->platform; | 
 |  | 
 | 	drm_dev_unregister(&vgem_device->drm); | 
 | 	devres_release_group(&pdev->dev, NULL); | 
 | 	platform_device_unregister(pdev); | 
 | } | 
 |  | 
 | module_init(vgem_init); | 
 | module_exit(vgem_exit); | 
 |  | 
 | MODULE_AUTHOR("Red Hat, Inc."); | 
 | MODULE_AUTHOR("Intel Corporation"); | 
 | MODULE_DESCRIPTION(DRIVER_DESC); | 
 | MODULE_LICENSE("GPL and additional rights"); |