1ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross/*
2ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross *
3ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross * Copyright (C) 2013 Google, Inc.
4ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross *
5ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross * This software is licensed under the terms of the GNU General Public
6ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross * License version 2, as published by the Free Software Foundation, and
7ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross * may be copied, distributed, and modified under those terms.
8ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross *
9ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross * This program is distributed in the hope that it will be useful,
10ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross * but WITHOUT ANY WARRANTY; without even the implied warranty of
11ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross * GNU General Public License for more details.
13ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross *
14ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross */
15ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
16ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross#define pr_fmt(fmt) "ion-test: " fmt
17ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
18ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross#include <linux/dma-buf.h>
19ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross#include <linux/dma-direction.h>
20ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross#include <linux/fs.h>
21ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross#include <linux/miscdevice.h>
22ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross#include <linux/mm.h>
23ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross#include <linux/module.h>
24ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross#include <linux/platform_device.h>
25ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross#include <linux/sched.h>
26ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross#include <linux/slab.h>
27ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross#include <linux/uaccess.h>
28ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross#include <linux/vmalloc.h>
29ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
30ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross#include "ion.h"
31ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross#include "../uapi/ion_test.h"
32ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
33ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross#define u64_to_uptr(x) ((void __user *)(unsigned long)(x))
34ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
35ceff95d49cc3e28c06c2352e8d94f56046271aebColin Crossstruct ion_test_device {
36ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	struct miscdevice misc;
37ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross};
38ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
39ceff95d49cc3e28c06c2352e8d94f56046271aebColin Crossstruct ion_test_data {
40ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	struct dma_buf *dma_buf;
41ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	struct device *dev;
42ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross};
43ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
44ceff95d49cc3e28c06c2352e8d94f56046271aebColin Crossstatic int ion_handle_test_dma(struct device *dev, struct dma_buf *dma_buf,
45ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		void __user *ptr, size_t offset, size_t size, bool write)
46ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross{
47ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	int ret = 0;
48ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	struct dma_buf_attachment *attach;
49ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	struct sg_table *table;
50ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	pgprot_t pgprot = pgprot_writecombine(PAGE_KERNEL);
51ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	enum dma_data_direction dir = write ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
52ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	struct sg_page_iter sg_iter;
53ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	unsigned long offset_page;
54ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
55ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	attach = dma_buf_attach(dma_buf, dev);
56ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	if (IS_ERR(attach))
57ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		return PTR_ERR(attach);
58ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
59ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	table = dma_buf_map_attachment(attach, dir);
60ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	if (IS_ERR(table))
61ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		return PTR_ERR(table);
62ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
63ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	offset_page = offset >> PAGE_SHIFT;
64ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	offset %= PAGE_SIZE;
65ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
66ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	for_each_sg_page(table->sgl, &sg_iter, table->nents, offset_page) {
67ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		struct page *page = sg_page_iter_page(&sg_iter);
68ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		void *vaddr = vmap(&page, 1, VM_MAP, pgprot);
69ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		size_t to_copy = PAGE_SIZE - offset;
70ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
71ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		to_copy = min(to_copy, size);
72ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		if (!vaddr) {
73ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross			ret = -ENOMEM;
74ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross			goto err;
75ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		}
76ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
77ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		if (write)
78ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross			ret = copy_from_user(vaddr + offset, ptr, to_copy);
79ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		else
80ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross			ret = copy_to_user(ptr, vaddr + offset, to_copy);
81ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
82ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		vunmap(vaddr);
83ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		if (ret) {
84ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross			ret = -EFAULT;
85ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross			goto err;
86ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		}
87ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		size -= to_copy;
88ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		if (!size)
89ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross			break;
90ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		ptr += to_copy;
91ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		offset = 0;
92ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	}
93ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
94ceff95d49cc3e28c06c2352e8d94f56046271aebColin Crosserr:
95ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	dma_buf_unmap_attachment(attach, table, dir);
96ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	dma_buf_detach(dma_buf, attach);
97ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	return ret;
98ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross}
99ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
100ceff95d49cc3e28c06c2352e8d94f56046271aebColin Crossstatic int ion_handle_test_kernel(struct dma_buf *dma_buf, void __user *ptr,
101ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		size_t offset, size_t size, bool write)
102ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross{
103ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	int ret;
104ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	unsigned long page_offset = offset >> PAGE_SHIFT;
105ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	size_t copy_offset = offset % PAGE_SIZE;
106ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	size_t copy_size = size;
107ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	enum dma_data_direction dir = write ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
108ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
109ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	if (offset > dma_buf->size || size > dma_buf->size - offset)
110ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		return -EINVAL;
111ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
112ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	ret = dma_buf_begin_cpu_access(dma_buf, offset, size, dir);
113ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	if (ret)
114ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		return ret;
115ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
116ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	while (copy_size > 0) {
117ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		size_t to_copy;
118ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		void *vaddr = dma_buf_kmap(dma_buf, page_offset);
119ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
120ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		if (!vaddr)
121ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross			goto err;
122ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
123ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		to_copy = min_t(size_t, PAGE_SIZE - copy_offset, copy_size);
124ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
125ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		if (write)
126ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross			ret = copy_from_user(vaddr + copy_offset, ptr, to_copy);
127ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		else
128ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross			ret = copy_to_user(ptr, vaddr + copy_offset, to_copy);
129ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
130ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		dma_buf_kunmap(dma_buf, page_offset, vaddr);
131ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		if (ret) {
132ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross			ret = -EFAULT;
133ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross			goto err;
134ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		}
135ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
136ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		copy_size -= to_copy;
137ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		ptr += to_copy;
138ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		page_offset++;
139ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		copy_offset = 0;
140ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	}
141ceff95d49cc3e28c06c2352e8d94f56046271aebColin Crosserr:
142ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	dma_buf_end_cpu_access(dma_buf, offset, size, dir);
143ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	return ret;
144ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross}
145ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
146ceff95d49cc3e28c06c2352e8d94f56046271aebColin Crossstatic long ion_test_ioctl(struct file *filp, unsigned int cmd,
147ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross						unsigned long arg)
148ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross{
149ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	struct ion_test_data *test_data = filp->private_data;
150ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	int ret = 0;
151ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
152ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	union {
153ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		struct ion_test_rw_data test_rw;
154ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	} data;
155ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
156ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	if (_IOC_SIZE(cmd) > sizeof(data))
157ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		return -EINVAL;
158ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
159ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	if (_IOC_DIR(cmd) & _IOC_WRITE)
160ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		if (copy_from_user(&data, (void __user *)arg, _IOC_SIZE(cmd)))
161ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross			return -EFAULT;
162ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
163ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	switch (cmd) {
164ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	case ION_IOC_TEST_SET_FD:
165ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	{
166ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		struct dma_buf *dma_buf = NULL;
167ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		int fd = arg;
168ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
169ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		if (fd >= 0) {
170ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross			dma_buf = dma_buf_get((int)arg);
171ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross			if (IS_ERR(dma_buf))
172ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross				return PTR_ERR(dma_buf);
173ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		}
174ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		if (test_data->dma_buf)
175ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross			dma_buf_put(test_data->dma_buf);
176ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		test_data->dma_buf = dma_buf;
177ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		break;
178ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	}
179ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	case ION_IOC_TEST_DMA_MAPPING:
180ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	{
181ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		ret = ion_handle_test_dma(test_data->dev, test_data->dma_buf,
182ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross					u64_to_uptr(data.test_rw.ptr),
183ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross					data.test_rw.offset, data.test_rw.size,
184ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross					data.test_rw.write);
185ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		break;
186ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	}
187ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	case ION_IOC_TEST_KERNEL_MAPPING:
188ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	{
189ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		ret = ion_handle_test_kernel(test_data->dma_buf,
190ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross					u64_to_uptr(data.test_rw.ptr),
191ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross					data.test_rw.offset, data.test_rw.size,
192ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross					data.test_rw.write);
193ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		break;
194ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	}
195ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	default:
196ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		return -ENOTTY;
197ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	}
198ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
199ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	if (_IOC_DIR(cmd) & _IOC_READ) {
200ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		if (copy_to_user((void __user *)arg, &data, sizeof(data)))
201ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross			return -EFAULT;
202ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	}
203ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	return ret;
204ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross}
205ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
206ceff95d49cc3e28c06c2352e8d94f56046271aebColin Crossstatic int ion_test_open(struct inode *inode, struct file *file)
207ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross{
208ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	struct ion_test_data *data;
209ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	struct miscdevice *miscdev = file->private_data;
210ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
211ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	data = kzalloc(sizeof(struct ion_test_data), GFP_KERNEL);
212ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	if (!data)
213ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		return -ENOMEM;
214ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
215ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	data->dev = miscdev->parent;
216ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
217ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	file->private_data = data;
218ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
219ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	return 0;
220ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross}
221ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
222ceff95d49cc3e28c06c2352e8d94f56046271aebColin Crossstatic int ion_test_release(struct inode *inode, struct file *file)
223ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross{
224ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	struct ion_test_data *data = file->private_data;
225ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
226ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	kfree(data);
227ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
228ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	return 0;
229ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross}
230ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
231ceff95d49cc3e28c06c2352e8d94f56046271aebColin Crossstatic const struct file_operations ion_test_fops = {
232ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	.owner = THIS_MODULE,
233ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	.unlocked_ioctl = ion_test_ioctl,
23407300f43d63d31294ee22b0d53091a8aec4cbc2dJohn Stultz	.compat_ioctl = ion_test_ioctl,
235ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	.open = ion_test_open,
236ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	.release = ion_test_release,
237ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross};
238ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
239ceff95d49cc3e28c06c2352e8d94f56046271aebColin Crossstatic int __init ion_test_probe(struct platform_device *pdev)
240ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross{
241ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	int ret;
242ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	struct ion_test_device *testdev;
243ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
244ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	testdev = devm_kzalloc(&pdev->dev, sizeof(struct ion_test_device),
245ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross				GFP_KERNEL);
246ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	if (!testdev)
247ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		return -ENOMEM;
248ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
249ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	testdev->misc.minor = MISC_DYNAMIC_MINOR;
250ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	testdev->misc.name = "ion-test";
251ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	testdev->misc.fops = &ion_test_fops;
252ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	testdev->misc.parent = &pdev->dev;
253ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	ret = misc_register(&testdev->misc);
254ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	if (ret) {
255ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		pr_err("failed to register misc device.\n");
256ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		return ret;
257ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	}
258ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
259ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	platform_set_drvdata(pdev, testdev);
260ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
261ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	return 0;
262ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross}
263ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
264ceff95d49cc3e28c06c2352e8d94f56046271aebColin Crossstatic struct platform_driver ion_test_platform_driver = {
265ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	.driver = {
266ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross		.name = "ion-test",
267ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	},
268ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross};
269ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
270ceff95d49cc3e28c06c2352e8d94f56046271aebColin Crossstatic int __init ion_test_init(void)
271ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross{
272ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	platform_device_register_simple("ion-test", -1, NULL, 0);
273ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	return platform_driver_probe(&ion_test_platform_driver, ion_test_probe);
274ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross}
275ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
276ceff95d49cc3e28c06c2352e8d94f56046271aebColin Crossstatic void __exit ion_test_exit(void)
277ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross{
278ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross	platform_driver_unregister(&ion_test_platform_driver);
279ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross}
280ceff95d49cc3e28c06c2352e8d94f56046271aebColin Cross
281ceff95d49cc3e28c06c2352e8d94f56046271aebColin Crossmodule_init(ion_test_init);
282ceff95d49cc3e28c06c2352e8d94f56046271aebColin Crossmodule_exit(ion_test_exit);
283