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