Merge remote-tracking branch 'lsk/v3.10/topic/aosp' into linux-linaro-lsk-android

Conflicts:
	drivers/staging/android/ion/ion_chunk_heap.c
	kernel/printk.c
This commit is contained in:
Mark Brown 2013-12-13 18:52:59 +00:00
commit 358194677f
60 changed files with 2094 additions and 1482 deletions

View File

@ -11,3 +11,5 @@ way to enable these options would be:
This will generate a .config that can then be used to save a new defconfig or
compile a new kernel with Android features enabled.
Because there is no tool to consistently generate these config fragments,
lets keep them alphabetically sorted instead of random.

View File

@ -1,3 +1,4 @@
# KEEP ALPHABETICALLY SORTED
# CONFIG_INET_LRO is not set
# CONFIG_MODULES is not set
# CONFIG_OABI_COMPAT is not set

View File

@ -1,7 +1,4 @@
CONFIG_PANIC_TIMEOUT=5
CONFIG_KALLSYMS_ALL=y
CONFIG_PERF_EVENTS=y
CONFIG_COMPACTION=y
# KEEP ALPHABETICALLY SORTED
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_LEGACY_PTYS is not set
@ -14,6 +11,7 @@ CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=8192
CONFIG_COMPACTION=y
CONFIG_DM_UEVENT=y
CONFIG_DRAGONRISE_FF=y
CONFIG_EXT4_FS=y
@ -81,6 +79,7 @@ CONFIG_ION=y
CONFIG_JOYSTICK_XPAD=y
CONFIG_JOYSTICK_XPAD_FF=y
CONFIG_JOYSTICK_XPAD_LEDS=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KSM=y
CONFIG_LOGIG940_FF=y
CONFIG_LOGIRUMBLEPAD2_FF=y
@ -88,7 +87,9 @@ CONFIG_LOGITECH_FF=y
CONFIG_MD=y
CONFIG_MEDIA_SUPPORT=y
CONFIG_MSDOS_FS=y
CONFIG_PANIC_TIMEOUT=5
CONFIG_PANTHERLORD_FF=y
CONFIG_PERF_EVENTS=y
CONFIG_PM_DEBUG=y
CONFIG_PM_RUNTIME=y
CONFIG_PM_WAKELOCKS_LIMIT=0

View File

@ -14,6 +14,7 @@
ifneq ($(MACHINE),)
include $(srctree)/$(MACHINE)/Makefile.boot
endif
include $(srctree)/arch/arm/boot/dts/Makefile
# Note: the following conditions must always be true:
# ZRELADDR == virt_to_phys(PAGE_OFFSET + TEXT_OFFSET)

View File

@ -22,13 +22,14 @@
/* fiq stack: r0-r15,cpsr,spsr of interrupted mode */
ENTRY(fiq_glue)
/* store pc, cpsr from previous mode */
/* store pc, cpsr from previous mode, reserve space for spsr */
mrs r12, spsr
sub r11, lr, #4
sub lr, lr, #4
subs r10, #1
bne nested_fiq
stmfd sp!, {r11-r12, lr}
str r12, [sp, #-8]!
str lr, [sp, #-4]!
/* store r8-r14 from previous mode */
sub sp, sp, #(7 * 4)
@ -85,12 +86,15 @@ fiq_from_usr_mode_exit:
msr cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)
ldmfd sp!, {r0-r7}
add sp, sp, #(7 * 4)
ldmfd sp!, {r11-r12, lr}
ldr lr, [sp, #(4 * 7)]
ldr r12, [sp, #(4 * 8)]
add sp, sp, #(10 * 4)
exit_fiq:
msr spsr_cxsf, r12
add r10, #1
movs pc, r11
cmp r11, #0
moveqs pc, lr
bx r11 /* jump to custom fiq return function */
nested_fiq:
orr r12, r12, #(PSR_F_BIT)
@ -98,14 +102,17 @@ nested_fiq:
fiq_glue_end:
ENTRY(fiq_glue_setup) /* func, data, sp */
mrs r3, cpsr
ENTRY(fiq_glue_setup) /* func, data, sp, smc call number */
stmfd sp!, {r4}
mrs r4, cpsr
msr cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)
movs r8, r0
mov r9, r1
mov sp, r2
mov r11, r3
moveq r10, #0
movne r10, #1
msr cpsr_c, r3
msr cpsr_c, r4
ldmfd sp!, {r4}
bx lr

View File

@ -18,20 +18,23 @@
#include <asm/fiq_glue.h>
extern unsigned char fiq_glue, fiq_glue_end;
extern void fiq_glue_setup(void *func, void *data, void *sp);
extern void fiq_glue_setup(void *func, void *data, void *sp,
fiq_return_handler_t fiq_return_handler);
static struct fiq_handler fiq_debbuger_fiq_handler = {
.name = "fiq_glue",
};
DEFINE_PER_CPU(void *, fiq_stack);
static struct fiq_glue_handler *current_handler;
static fiq_return_handler_t fiq_return_handler;
static DEFINE_MUTEX(fiq_glue_lock);
static void fiq_glue_setup_helper(void *info)
{
struct fiq_glue_handler *handler = info;
fiq_glue_setup(handler->fiq, handler,
__get_cpu_var(fiq_stack) + THREAD_START_SP);
__get_cpu_var(fiq_stack) + THREAD_START_SP,
fiq_return_handler);
}
int fiq_glue_register_handler(struct fiq_glue_handler *handler)
@ -80,6 +83,49 @@ int fiq_glue_register_handler(struct fiq_glue_handler *handler)
return ret;
}
static void fiq_glue_update_return_handler(void (*fiq_return)(void))
{
fiq_return_handler = fiq_return;
if (current_handler)
on_each_cpu(fiq_glue_setup_helper, current_handler, true);
}
int fiq_glue_set_return_handler(void (*fiq_return)(void))
{
int ret;
mutex_lock(&fiq_glue_lock);
if (fiq_return_handler) {
ret = -EBUSY;
goto err_busy;
}
fiq_glue_update_return_handler(fiq_return);
ret = 0;
err_busy:
mutex_unlock(&fiq_glue_lock);
return ret;
}
EXPORT_SYMBOL(fiq_glue_set_return_handler);
int fiq_glue_clear_return_handler(void (*fiq_return)(void))
{
int ret;
mutex_lock(&fiq_glue_lock);
if (WARN_ON(fiq_return_handler != fiq_return)) {
ret = -EINVAL;
goto err_inval;
}
fiq_glue_update_return_handler(NULL);
ret = 0;
err_inval:
mutex_unlock(&fiq_glue_lock);
return ret;
}
EXPORT_SYMBOL(fiq_glue_clear_return_handler);
/**
* fiq_glue_resume - Restore fiqs after suspend or low power idle states
*
@ -93,7 +139,8 @@ void fiq_glue_resume(void)
if (!current_handler)
return;
fiq_glue_setup(current_handler->fiq, current_handler,
__get_cpu_var(fiq_stack) + THREAD_START_SP);
__get_cpu_var(fiq_stack) + THREAD_START_SP,
fiq_return_handler);
if (current_handler->resume)
current_handler->resume(current_handler);
}

View File

@ -18,8 +18,11 @@ struct fiq_glue_handler {
void (*fiq)(struct fiq_glue_handler *h, void *regs, void *svc_sp);
void (*resume)(struct fiq_glue_handler *h);
};
typedef void (*fiq_return_handler_t)(void);
int fiq_glue_register_handler(struct fiq_glue_handler *handler);
int fiq_glue_set_return_handler(fiq_return_handler_t fiq_return);
int fiq_glue_clear_return_handler(fiq_return_handler_t fiq_return);
#ifdef CONFIG_FIQ_GLUE
void fiq_glue_resume(void);

View File

@ -1,2 +1,2 @@
obj-y += drm/ vga/ ion/
obj-y += drm/ vga/
obj-$(CONFIG_TEGRA_HOST1X) += host1x/

View File

@ -1,14 +0,0 @@
menuconfig ION
tristate "Ion Memory Manager"
depends on ARM
select GENERIC_ALLOCATOR
select DMA_SHARED_BUFFER
help
Chose this option to enable the ION Memory Manager.
config ION_TEGRA
tristate "Ion for Tegra"
depends on ARCH_TEGRA && ION
help
Choose this option if you wish to use ion on an nVidia Tegra.

View File

@ -1,114 +0,0 @@
/*
* drivers/gpu/ion/ion_system_mapper.c
*
* Copyright (C) 2011 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/err.h>
#include <linux/ion.h>
#include <linux/memory.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include "ion_priv.h"
/*
* This mapper is valid for any heap that allocates memory that already has
* a kernel mapping, this includes vmalloc'd memory, kmalloc'd memory,
* pages obtained via io_remap, etc.
*/
static void *ion_kernel_mapper_map(struct ion_mapper *mapper,
struct ion_buffer *buffer,
struct ion_mapping **mapping)
{
if (!((1 << buffer->heap->type) & mapper->heap_mask)) {
pr_err("%s: attempting to map an unsupported heap\n", __func__);
return ERR_PTR(-EINVAL);
}
/* XXX REVISIT ME!!! */
*((unsigned long *)mapping) = (unsigned long)buffer->priv;
return buffer->priv;
}
static void ion_kernel_mapper_unmap(struct ion_mapper *mapper,
struct ion_buffer *buffer,
struct ion_mapping *mapping)
{
if (!((1 << buffer->heap->type) & mapper->heap_mask))
pr_err("%s: attempting to unmap an unsupported heap\n",
__func__);
}
static void *ion_kernel_mapper_map_kernel(struct ion_mapper *mapper,
struct ion_buffer *buffer,
struct ion_mapping *mapping)
{
if (!((1 << buffer->heap->type) & mapper->heap_mask)) {
pr_err("%s: attempting to unmap an unsupported heap\n",
__func__);
return ERR_PTR(-EINVAL);
}
return buffer->priv;
}
static int ion_kernel_mapper_map_user(struct ion_mapper *mapper,
struct ion_buffer *buffer,
struct vm_area_struct *vma,
struct ion_mapping *mapping)
{
int ret;
switch (buffer->heap->type) {
case ION_HEAP_KMALLOC:
{
unsigned long pfn = __phys_to_pfn(virt_to_phys(buffer->priv));
ret = remap_pfn_range(vma, vma->vm_start, pfn + vma->vm_pgoff,
vma->vm_end - vma->vm_start,
vma->vm_page_prot);
break;
}
case ION_HEAP_VMALLOC:
ret = remap_vmalloc_range(vma, buffer->priv, vma->vm_pgoff);
break;
default:
pr_err("%s: attempting to map unsupported heap to userspace\n",
__func__);
return -EINVAL;
}
return ret;
}
static struct ion_mapper_ops ops = {
.map = ion_kernel_mapper_map,
.map_kernel = ion_kernel_mapper_map_kernel,
.map_user = ion_kernel_mapper_map_user,
.unmap = ion_kernel_mapper_unmap,
};
struct ion_mapper *ion_system_mapper_create(void)
{
struct ion_mapper *mapper;
mapper = kzalloc(sizeof(struct ion_mapper), GFP_KERNEL);
if (!mapper)
return ERR_PTR(-ENOMEM);
mapper->type = ION_SYSTEM_MAPPER;
mapper->ops = &ops;
mapper->heap_mask = (1 << ION_HEAP_VMALLOC) | (1 << ION_HEAP_KMALLOC);
return mapper;
}
void ion_system_mapper_destroy(struct ion_mapper *mapper)
{
kfree(mapper);
}

View File

@ -108,6 +108,8 @@ config SW_SYNC_USER
*WARNING* improper use of this can result in deadlocking kernel
drivers from userspace.
source "drivers/staging/android/ion/Kconfig"
endif # if ANDROID
endmenu

View File

@ -1,5 +1,7 @@
ccflags-y += -I$(src) # needed for trace events
obj-y += ion/
obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o
obj-$(CONFIG_ASHMEM) += ashmem.o
obj-$(CONFIG_ANDROID_LOGGER) += logger.o

View File

@ -16,50 +16,10 @@
#ifndef _LINUX_ANDROID_ALARM_H
#define _LINUX_ANDROID_ALARM_H
#include <linux/ioctl.h>
#include <linux/time.h>
#include <linux/compat.h>
#include <linux/ioctl.h>
enum android_alarm_type {
/* return code bit numbers or set alarm arg */
ANDROID_ALARM_RTC_WAKEUP,
ANDROID_ALARM_RTC,
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
ANDROID_ALARM_ELAPSED_REALTIME,
ANDROID_ALARM_SYSTEMTIME,
ANDROID_ALARM_TYPE_COUNT,
/* return code bit numbers */
/* ANDROID_ALARM_TIME_CHANGE = 16 */
};
enum android_alarm_return_flags {
ANDROID_ALARM_RTC_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_WAKEUP,
ANDROID_ALARM_RTC_MASK = 1U << ANDROID_ALARM_RTC,
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK =
1U << ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
ANDROID_ALARM_ELAPSED_REALTIME_MASK =
1U << ANDROID_ALARM_ELAPSED_REALTIME,
ANDROID_ALARM_SYSTEMTIME_MASK = 1U << ANDROID_ALARM_SYSTEMTIME,
ANDROID_ALARM_TIME_CHANGE_MASK = 1U << 16
};
/* Disable alarm */
#define ANDROID_ALARM_CLEAR(type) _IO('a', 0 | ((type) << 4))
/* Ack last alarm and wait for next */
#define ANDROID_ALARM_WAIT _IO('a', 1)
#define ALARM_IOW(c, type, size) _IOW('a', (c) | ((type) << 4), size)
/* Set alarm */
#define ANDROID_ALARM_SET(type) ALARM_IOW(2, type, struct timespec)
#define ANDROID_ALARM_SET_AND_WAIT(type) ALARM_IOW(3, type, struct timespec)
#define ANDROID_ALARM_GET_TIME(type) ALARM_IOW(4, type, struct timespec)
#define ANDROID_ALARM_SET_RTC _IOW('a', 5, struct timespec)
#define ANDROID_ALARM_BASE_CMD(cmd) (cmd & ~(_IOC(0, 0, 0xf0, 0)))
#define ANDROID_ALARM_IOCTL_TO_TYPE(cmd) (_IOC_NR(cmd) >> 4)
#include "uapi/android_alarm.h"
#ifdef CONFIG_COMPAT
#define ANDROID_ALARM_SET_COMPAT(type) ALARM_IOW(2, type, \

View File

@ -16,35 +16,7 @@
#include <linux/ioctl.h>
#include <linux/compat.h>
#define ASHMEM_NAME_LEN 256
#define ASHMEM_NAME_DEF "dev/ashmem"
/* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */
#define ASHMEM_NOT_PURGED 0
#define ASHMEM_WAS_PURGED 1
/* Return values from ASHMEM_GET_PIN_STATUS: Is the mapping pinned? */
#define ASHMEM_IS_UNPINNED 0
#define ASHMEM_IS_PINNED 1
struct ashmem_pin {
__u32 offset; /* offset into region, in bytes, page-aligned */
__u32 len; /* length forward from offset, in bytes, page-aligned */
};
#define __ASHMEMIOC 0x77
#define ASHMEM_SET_NAME _IOW(__ASHMEMIOC, 1, char[ASHMEM_NAME_LEN])
#define ASHMEM_GET_NAME _IOR(__ASHMEMIOC, 2, char[ASHMEM_NAME_LEN])
#define ASHMEM_SET_SIZE _IOW(__ASHMEMIOC, 3, size_t)
#define ASHMEM_GET_SIZE _IO(__ASHMEMIOC, 4)
#define ASHMEM_SET_PROT_MASK _IOW(__ASHMEMIOC, 5, unsigned long)
#define ASHMEM_GET_PROT_MASK _IO(__ASHMEMIOC, 6)
#define ASHMEM_PIN _IOW(__ASHMEMIOC, 7, struct ashmem_pin)
#define ASHMEM_UNPIN _IOW(__ASHMEMIOC, 8, struct ashmem_pin)
#define ASHMEM_GET_PIN_STATUS _IO(__ASHMEMIOC, 9)
#define ASHMEM_PURGE_ALL_CACHES _IO(__ASHMEMIOC, 10)
#include "uapi/ashmem.h"
/* support of 32bit userspace on 64bit platforms */
#ifdef CONFIG_COMPAT

View File

@ -20,311 +20,7 @@
#ifndef _LINUX_BINDER_H
#define _LINUX_BINDER_H
#include <linux/ioctl.h>
#define B_PACK_CHARS(c1, c2, c3, c4) \
((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4))
#define B_TYPE_LARGE 0x85
enum {
BINDER_TYPE_BINDER = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE),
BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE),
BINDER_TYPE_HANDLE = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE),
BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE),
BINDER_TYPE_FD = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE),
};
enum {
FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff,
FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100,
};
/*
* This is the flattened representation of a Binder object for transfer
* between processes. The 'offsets' supplied as part of a binder transaction
* contains offsets into the data where these structures occur. The Binder
* driver takes care of re-writing the structure type and data as it moves
* between processes.
*/
struct flat_binder_object {
/* 8 bytes for large_flat_header. */
unsigned long type;
unsigned long flags;
/* 8 bytes of data. */
union {
void __user *binder; /* local object */
signed long handle; /* remote object */
};
/* extra data associated with local object */
void __user *cookie;
};
/*
* On 64-bit platforms where user code may run in 32-bits the driver must
* translate the buffer (and local binder) addresses appropriately.
*/
struct binder_write_read {
signed long write_size; /* bytes to write */
signed long write_consumed; /* bytes consumed by driver */
unsigned long write_buffer;
signed long read_size; /* bytes to read */
signed long read_consumed; /* bytes consumed by driver */
unsigned long read_buffer;
};
/* Use with BINDER_VERSION, driver fills in fields. */
struct binder_version {
/* driver protocol version -- increment with incompatible change */
signed long protocol_version;
};
/* This is the current protocol version. */
#define BINDER_CURRENT_PROTOCOL_VERSION 7
#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)
#define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64)
#define BINDER_SET_MAX_THREADS _IOW('b', 5, size_t)
#define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, __s32)
#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32)
#define BINDER_THREAD_EXIT _IOW('b', 8, __s32)
#define BINDER_VERSION _IOWR('b', 9, struct binder_version)
/*
* NOTE: Two special error codes you should check for when calling
* in to the driver are:
*
* EINTR -- The operation has been interupted. This should be
* handled by retrying the ioctl() until a different error code
* is returned.
*
* ECONNREFUSED -- The driver is no longer accepting operations
* from your process. That is, the process is being destroyed.
* You should handle this by exiting from your process. Note
* that once this error code is returned, all further calls to
* the driver from any thread will return this same code.
*/
enum transaction_flags {
TF_ONE_WAY = 0x01, /* this is a one-way call: async, no return */
TF_ROOT_OBJECT = 0x04, /* contents are the component's root object */
TF_STATUS_CODE = 0x08, /* contents are a 32-bit status code */
TF_ACCEPT_FDS = 0x10, /* allow replies with file descriptors */
};
struct binder_transaction_data {
/* The first two are only used for bcTRANSACTION and brTRANSACTION,
* identifying the target and contents of the transaction.
*/
union {
size_t handle; /* target descriptor of command transaction */
void *ptr; /* target descriptor of return transaction */
} target;
void *cookie; /* target object cookie */
unsigned int code; /* transaction command */
/* General information about the transaction. */
unsigned int flags;
pid_t sender_pid;
uid_t sender_euid;
size_t data_size; /* number of bytes of data */
size_t offsets_size; /* number of bytes of offsets */
/* If this transaction is inline, the data immediately
* follows here; otherwise, it ends with a pointer to
* the data buffer.
*/
union {
struct {
/* transaction data */
const void __user *buffer;
/* offsets from buffer to flat_binder_object structs */
const void __user *offsets;
} ptr;
uint8_t buf[8];
} data;
};
struct binder_ptr_cookie {
void *ptr;
void *cookie;
};
struct binder_pri_desc {
int priority;
int desc;
};
struct binder_pri_ptr_cookie {
int priority;
void *ptr;
void *cookie;
};
enum binder_driver_return_protocol {
BR_ERROR = _IOR('r', 0, int),
/*
* int: error code
*/
BR_OK = _IO('r', 1),
/* No parameters! */
BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data),
BR_REPLY = _IOR('r', 3, struct binder_transaction_data),
/*
* binder_transaction_data: the received command.
*/
BR_ACQUIRE_RESULT = _IOR('r', 4, int),
/*
* not currently supported
* int: 0 if the last bcATTEMPT_ACQUIRE was not successful.
* Else the remote object has acquired a primary reference.
*/
BR_DEAD_REPLY = _IO('r', 5),
/*
* The target of the last transaction (either a bcTRANSACTION or
* a bcATTEMPT_ACQUIRE) is no longer with us. No parameters.
*/
BR_TRANSACTION_COMPLETE = _IO('r', 6),
/*
* No parameters... always refers to the last transaction requested
* (including replies). Note that this will be sent even for
* asynchronous transactions.
*/
BR_INCREFS = _IOR('r', 7, struct binder_ptr_cookie),
BR_ACQUIRE = _IOR('r', 8, struct binder_ptr_cookie),
BR_RELEASE = _IOR('r', 9, struct binder_ptr_cookie),
BR_DECREFS = _IOR('r', 10, struct binder_ptr_cookie),
/*
* void *: ptr to binder
* void *: cookie for binder
*/
BR_ATTEMPT_ACQUIRE = _IOR('r', 11, struct binder_pri_ptr_cookie),
/*
* not currently supported
* int: priority
* void *: ptr to binder
* void *: cookie for binder
*/
BR_NOOP = _IO('r', 12),
/*
* No parameters. Do nothing and examine the next command. It exists
* primarily so that we can replace it with a BR_SPAWN_LOOPER command.
*/
BR_SPAWN_LOOPER = _IO('r', 13),
/*
* No parameters. The driver has determined that a process has no
* threads waiting to service incoming transactions. When a process
* receives this command, it must spawn a new service thread and
* register it via bcENTER_LOOPER.
*/
BR_FINISHED = _IO('r', 14),
/*
* not currently supported
* stop threadpool thread
*/
BR_DEAD_BINDER = _IOR('r', 15, void *),
/*
* void *: cookie
*/
BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR('r', 16, void *),
/*
* void *: cookie
*/
BR_FAILED_REPLY = _IO('r', 17),
/*
* The the last transaction (either a bcTRANSACTION or
* a bcATTEMPT_ACQUIRE) failed (e.g. out of memory). No parameters.
*/
};
enum binder_driver_command_protocol {
BC_TRANSACTION = _IOW('c', 0, struct binder_transaction_data),
BC_REPLY = _IOW('c', 1, struct binder_transaction_data),
/*
* binder_transaction_data: the sent command.
*/
BC_ACQUIRE_RESULT = _IOW('c', 2, int),
/*
* not currently supported
* int: 0 if the last BR_ATTEMPT_ACQUIRE was not successful.
* Else you have acquired a primary reference on the object.
*/
BC_FREE_BUFFER = _IOW('c', 3, int),
/*
* void *: ptr to transaction data received on a read
*/
BC_INCREFS = _IOW('c', 4, int),
BC_ACQUIRE = _IOW('c', 5, int),
BC_RELEASE = _IOW('c', 6, int),
BC_DECREFS = _IOW('c', 7, int),
/*
* int: descriptor
*/
BC_INCREFS_DONE = _IOW('c', 8, struct binder_ptr_cookie),
BC_ACQUIRE_DONE = _IOW('c', 9, struct binder_ptr_cookie),
/*
* void *: ptr to binder
* void *: cookie for binder
*/
BC_ATTEMPT_ACQUIRE = _IOW('c', 10, struct binder_pri_desc),
/*
* not currently supported
* int: priority
* int: descriptor
*/
BC_REGISTER_LOOPER = _IO('c', 11),
/*
* No parameters.
* Register a spawned looper thread with the device.
*/
BC_ENTER_LOOPER = _IO('c', 12),
BC_EXIT_LOOPER = _IO('c', 13),
/*
* No parameters.
* These two commands are sent as an application-level thread
* enters and exits the binder loop, respectively. They are
* used so the binder can have an accurate count of the number
* of looping threads it has available.
*/
BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14, struct binder_ptr_cookie),
/*
* void *: ptr to binder
* void *: cookie
*/
BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15, struct binder_ptr_cookie),
/*
* void *: ptr to binder
* void *: cookie
*/
BC_DEAD_BINDER_DONE = _IOW('c', 16, void *),
/*
* void *: cookie
*/
};
#include "uapi/binder.h"
#endif /* _LINUX_BINDER_H */

View File

@ -0,0 +1,24 @@
menuconfig ION
tristate "Ion Memory Manager"
select GENERIC_ALLOCATOR
select DMA_SHARED_BUFFER
---help---
Chose this option to enable the ION Memory Manager,
used by Android to efficiently allocate buffers
from userspace that can be shared between drivers.
If you're not using Android its probably safe to
say N here.
config ION_TEST
tristate "Ion Test Device"
depends on ION
help
Choose this option to create a device that can be used to test the
kernel and device side ION functions.
config ION_TEGRA
tristate "Ion for Tegra"
depends on ARCH_TEGRA && ION
help
Choose this option if you wish to use ion on an nVidia Tegra.

View File

@ -1,5 +1,6 @@
obj-$(CONFIG_ION) += ion.o ion_heap.o ion_page_pool.o ion_system_heap.o \
ion_carveout_heap.o ion_chunk_heap.o ion_cma_heap.o
obj-$(CONFIG_ION_TEST) += ion_test.o
ifdef CONFIG_COMPAT
obj-$(CONFIG_ION) += compat_ion.o
endif

View File

@ -14,14 +14,14 @@
*
*/
#include <linux/ion.h>
#include <linux/compat.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include "ion.h"
#include "compat_ion.h"
/* See include/linux/ion.h for the definition of these structs */
/* See drivers/staging/android/uapi/ion.h for the definition of these structs */
struct compat_ion_allocation_data {
compat_size_t len;
compat_size_t align;
@ -35,6 +35,12 @@ struct compat_ion_custom_data {
compat_ulong_t arg;
};
#define COMPAT_ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, \
struct compat_ion_allocation_data)
#define COMPAT_ION_IOC_FREE _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data)
#define COMPAT_ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, \
struct compat_ion_custom_data)
static int compat_get_ion_allocation_data(
struct compat_ion_allocation_data __user *data32,
struct ion_allocation_data __user *data)
@ -85,8 +91,8 @@ static int compat_get_ion_custom_data(
struct compat_ion_custom_data __user *data32,
struct ion_custom_data __user *data)
{
compat_uint_t cmd;
compat_ulong_t arg;
compat_uint_t cmd;
compat_ulong_t arg;
int err;
err = get_user(cmd, &data32->cmd);
@ -105,7 +111,7 @@ long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return -ENOTTY;
switch (cmd) {
case ION_IOC_ALLOC:
case COMPAT_ION_IOC_ALLOC:
{
struct compat_ion_allocation_data __user *data32;
struct ion_allocation_data __user *data;
@ -119,13 +125,12 @@ long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
err = compat_get_ion_allocation_data(data32, data);
if (err)
return err;
ret = filp->f_op->unlocked_ioctl(filp, cmd,
ret = filp->f_op->unlocked_ioctl(filp, ION_IOC_ALLOC,
(unsigned long)data);
err = compat_put_ion_allocation_data(data32, data);
return ret ? ret : err;
}
case ION_IOC_FREE:
case COMPAT_ION_IOC_FREE:
{
struct compat_ion_allocation_data __user *data32;
struct ion_allocation_data __user *data;
@ -140,10 +145,10 @@ long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (err)
return err;
return filp->f_op->unlocked_ioctl(filp, cmd,
return filp->f_op->unlocked_ioctl(filp, ION_IOC_FREE,
(unsigned long)data);
}
case ION_IOC_CUSTOM: {
case COMPAT_ION_IOC_CUSTOM: {
struct compat_ion_custom_data __user *data32;
struct ion_custom_data __user *data;
int err;
@ -157,7 +162,7 @@ long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (err)
return err;
return filp->f_op->unlocked_ioctl(filp, cmd,
return filp->f_op->unlocked_ioctl(filp, ION_IOC_CUSTOM,
(unsigned long)data);
}
case ION_IOC_SHARE:

View File

@ -20,7 +20,6 @@
#include <linux/freezer.h>
#include <linux/fs.h>
#include <linux/anon_inodes.h>
#include <linux/ion.h>
#include <linux/kthread.h>
#include <linux/list.h>
#include <linux/memblock.h>
@ -37,6 +36,7 @@
#include <linux/dma-buf.h>
#include <linux/idr.h>
#include "ion.h"
#include "ion_priv.h"
#include "compat_ion.h"
@ -110,8 +110,8 @@ struct ion_handle {
bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer)
{
return ((buffer->flags & ION_FLAG_CACHED) &&
!(buffer->flags & ION_FLAG_CACHED_NEEDS_SYNC));
return (buffer->flags & ION_FLAG_CACHED) &&
!(buffer->flags & ION_FLAG_CACHED_NEEDS_SYNC);
}
bool ion_buffer_cached(struct ion_buffer *buffer)
@ -202,7 +202,8 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
buffer->size = len;
table = heap->ops->map_dma(heap, buffer);
if (WARN_ONCE(table == NULL, "heap->ops->map_dma should return ERR_PTR on error"))
if (WARN_ONCE(table == NULL,
"heap->ops->map_dma should return ERR_PTR on error"))
table = ERR_PTR(-EINVAL);
if (IS_ERR(table)) {
heap->ops->free(buffer);
@ -224,7 +225,7 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
for_each_sg(table->sgl, sg, table->nents, i) {
struct page *page = sg_page(sg);
for (j = 0; j < sg_dma_len(sg) / PAGE_SIZE; j++)
for (j = 0; j < sg->length / PAGE_SIZE; j++)
buffer->pages[k++] = page++;
}
@ -383,7 +384,14 @@ static void ion_handle_get(struct ion_handle *handle)
static int ion_handle_put(struct ion_handle *handle)
{
return kref_put(&handle->ref, ion_handle_destroy);
struct ion_client *client = handle->client;
int ret;
mutex_lock(&client->lock);
ret = kref_put(&handle->ref, ion_handle_destroy);
mutex_unlock(&client->lock);
return ret;
}
static struct ion_handle *ion_handle_lookup(struct ion_client *client,
@ -403,34 +411,39 @@ static struct ion_handle *ion_handle_lookup(struct ion_client *client,
return ERR_PTR(-EINVAL);
}
static struct ion_handle *ion_uhandle_get(struct ion_client *client, int id)
static struct ion_handle *ion_handle_get_by_id(struct ion_client *client,
int id)
{
return idr_find(&client->idr, id);
struct ion_handle *handle;
mutex_lock(&client->lock);
handle = idr_find(&client->idr, id);
if (handle)
ion_handle_get(handle);
mutex_unlock(&client->lock);
return handle ? handle : ERR_PTR(-EINVAL);
}
static bool ion_handle_validate(struct ion_client *client, struct ion_handle *handle)
static bool ion_handle_validate(struct ion_client *client,
struct ion_handle *handle)
{
return (ion_uhandle_get(client, handle->id) == handle);
WARN_ON(!mutex_is_locked(&client->lock));
return (idr_find(&client->idr, handle->id) == handle);
}
static int ion_handle_add(struct ion_client *client, struct ion_handle *handle)
{
int rc;
int id;
struct rb_node **p = &client->handles.rb_node;
struct rb_node *parent = NULL;
struct ion_handle *entry;
do {
int id;
rc = idr_pre_get(&client->idr, GFP_KERNEL);
if (!rc)
return -ENOMEM;
rc = idr_get_new_above(&client->idr, handle, 1, &id);
handle->id = id;
} while (rc == -EAGAIN);
id = idr_alloc(&client->idr, handle, 1, 0, GFP_KERNEL);
if (id < 0)
return id;
if (rc < 0)
return rc;
handle->id = id;
while (*p) {
parent = *p;
@ -460,7 +473,7 @@ struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
struct ion_heap *heap;
int ret;
pr_debug("%s: len %d align %d heap_id_mask %u flags %x\n", __func__,
pr_debug("%s: len %zu align %zu heap_id_mask %u flags %x\n", __func__,
len, align, heap_id_mask, flags);
/*
* traverse the list of heaps available in this system in priority
@ -468,11 +481,11 @@ struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
* request of the caller allocate from it. Repeat until allocate has
* succeeded or all heaps have been tried
*/
if (WARN_ON(!len))
return ERR_PTR(-EINVAL);
len = PAGE_ALIGN(len);
if (!len)
return ERR_PTR(-EINVAL);
down_read(&dev->lock);
plist_for_each_entry(heap, &dev->heaps, node) {
/* if the caller didn't specify this heap id */
@ -503,11 +516,11 @@ struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
mutex_lock(&client->lock);
ret = ion_handle_add(client, handle);
mutex_unlock(&client->lock);
if (ret) {
ion_handle_put(handle);
handle = ERR_PTR(ret);
}
mutex_unlock(&client->lock);
return handle;
}
@ -527,8 +540,8 @@ void ion_free(struct ion_client *client, struct ion_handle *handle)
mutex_unlock(&client->lock);
return;
}
ion_handle_put(handle);
mutex_unlock(&client->lock);
ion_handle_put(handle);
}
EXPORT_SYMBOL(ion_free);
@ -567,7 +580,8 @@ static void *ion_buffer_kmap_get(struct ion_buffer *buffer)
return buffer->vaddr;
}
vaddr = buffer->heap->ops->map_kernel(buffer->heap, buffer);
if (WARN_ONCE(vaddr == NULL, "heap->ops->map_kernel should return ERR_PTR on error"))
if (WARN_ONCE(vaddr == NULL,
"heap->ops->map_kernel should return ERR_PTR on error"))
return ERR_PTR(-EINVAL);
if (IS_ERR(vaddr))
return vaddr;
@ -658,7 +672,7 @@ static int ion_debug_client_show(struct seq_file *s, void *unused)
struct ion_client *client = s->private;
struct rb_node *n;
size_t sizes[ION_NUM_HEAP_IDS] = {0};
const char *names[ION_NUM_HEAP_IDS] = {0};
const char *names[ION_NUM_HEAP_IDS] = {NULL};
int i;
mutex_lock(&client->lock);
@ -677,7 +691,7 @@ static int ion_debug_client_show(struct seq_file *s, void *unused)
for (i = 0; i < ION_NUM_HEAP_IDS; i++) {
if (!names[i])
continue;
seq_printf(s, "%16.16s: %16u\n", names[i], sizes[i]);
seq_printf(s, "%16.16s: %16zu\n", names[i], sizes[i]);
}
return 0;
}
@ -769,7 +783,6 @@ void ion_client_destroy(struct ion_client *client)
ion_handle_destroy(&handle->ref);
}
idr_remove_all(&client->idr);
idr_destroy(&client->idr);
down_write(&dev->lock);
@ -823,6 +836,22 @@ static void ion_unmap_dma_buf(struct dma_buf_attachment *attachment,
{
}
void ion_pages_sync_for_device(struct device *dev, struct page *page,
size_t size, enum dma_data_direction dir)
{
struct scatterlist sg;
sg_init_table(&sg, 1);
sg_set_page(&sg, page, size, 0);
/*
* This is not correct - sg_dma_address needs a dma_addr_t that is valid
* for the the targeted device, but this works on the currently targeted
* hardware.
*/
sg_dma_address(&sg) = page_to_phys(page);
dma_sync_sg_for_device(dev, &sg, 1, dir);
}
struct ion_vma_list {
struct list_head list;
struct vm_area_struct *vma;
@ -847,7 +876,9 @@ static void ion_buffer_sync_for_device(struct ion_buffer *buffer,
struct page *page = buffer->pages[i];
if (ion_buffer_page_is_dirty(page))
__dma_page_cpu_to_dev(page, 0, PAGE_SIZE, dir);
ion_pages_sync_for_device(dev, ion_buffer_page(page),
PAGE_SIZE, dir);
ion_buffer_page_clean(buffer->pages + i);
}
list_for_each_entry(vma_list, &buffer->vmas, list) {
@ -859,17 +890,18 @@ static void ion_buffer_sync_for_device(struct ion_buffer *buffer,
mutex_unlock(&buffer->lock);
}
int ion_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
static int ion_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct ion_buffer *buffer = vma->vm_private_data;
unsigned long pfn;
int ret;
mutex_lock(&buffer->lock);
ion_buffer_page_dirty(buffer->pages + vmf->pgoff);
BUG_ON(!buffer->pages || !buffer->pages[vmf->pgoff]);
ret = vm_insert_page(vma, (unsigned long)vmf->virtual_address,
ion_buffer_page(buffer->pages[vmf->pgoff]));
pfn = page_to_pfn(ion_buffer_page(buffer->pages[vmf->pgoff]));
ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn);
mutex_unlock(&buffer->lock);
if (ret)
return VM_FAULT_ERROR;
@ -910,7 +942,7 @@ static void ion_vm_close(struct vm_area_struct *vma)
mutex_unlock(&buffer->lock);
}
struct vm_operations_struct ion_vma_ops = {
static struct vm_operations_struct ion_vma_ops = {
.open = ion_vm_open,
.close = ion_vm_close,
.fault = ion_vm_fault,
@ -928,6 +960,8 @@ static int ion_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
}
if (ion_buffer_fault_user_mappings(buffer)) {
vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND |
VM_DONTDUMP;
vma->vm_private_data = buffer;
vma->vm_ops = &ion_vma_ops;
ion_vm_open(vma);
@ -999,7 +1033,7 @@ static void ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf, size_t start,
mutex_unlock(&buffer->lock);
}
struct dma_buf_ops dma_buf_ops = {
static struct dma_buf_ops dma_buf_ops = {
.map_dma_buf = ion_map_dma_buf,
.unmap_dma_buf = ion_unmap_dma_buf,
.mmap = ion_mmap,
@ -1021,14 +1055,15 @@ struct dma_buf *ion_share_dma_buf(struct ion_client *client,
mutex_lock(&client->lock);
valid_handle = ion_handle_validate(client, handle);
mutex_unlock(&client->lock);
if (!valid_handle) {
WARN(1, "%s: invalid handle passed to share.\n", __func__);
mutex_unlock(&client->lock);
return ERR_PTR(-EINVAL);
}
buffer = handle->buffer;
ion_buffer_get(buffer);
mutex_unlock(&client->lock);
dmabuf = dma_buf_export(buffer, &dma_buf_ops, buffer->size, O_RDWR);
if (IS_ERR(dmabuf)) {
ion_buffer_put(buffer);
@ -1081,18 +1116,24 @@ struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd)
handle = ion_handle_lookup(client, buffer);
if (!IS_ERR(handle)) {
ion_handle_get(handle);
mutex_unlock(&client->lock);
goto end;
}
mutex_unlock(&client->lock);
handle = ion_handle_create(client, buffer);
if (IS_ERR(handle))
goto end;
mutex_lock(&client->lock);
ret = ion_handle_add(client, handle);
mutex_unlock(&client->lock);
if (ret) {
ion_handle_put(handle);
handle = ERR_PTR(ret);
}
end:
mutex_unlock(&client->lock);
dma_buf_put(dmabuf);
return handle;
}
@ -1122,110 +1163,120 @@ static int ion_sync_for_device(struct ion_client *client, int fd)
return 0;
}
/* fix up the cases where the ioctl direction bits are incorrect */
static unsigned int ion_ioctl_dir(unsigned int cmd)
{
switch (cmd) {
case ION_IOC_SYNC:
case ION_IOC_FREE:
case ION_IOC_CUSTOM:
return _IOC_WRITE;
default:
return _IOC_DIR(cmd);
}
}
static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct ion_client *client = filp->private_data;
struct ion_device *dev = client->dev;
struct ion_handle *cleanup_handle = NULL;
int ret = 0;
unsigned int dir;
union {
struct ion_fd_data fd;
struct ion_allocation_data allocation;
struct ion_handle_data handle;
struct ion_custom_data custom;
} data;
dir = ion_ioctl_dir(cmd);
if (_IOC_SIZE(cmd) > sizeof(data))
return -EINVAL;
if (dir & _IOC_WRITE)
if (copy_from_user(&data, (void __user *)arg, _IOC_SIZE(cmd)))
return -EFAULT;
switch (cmd) {
case ION_IOC_ALLOC:
{
struct ion_allocation_data data;
struct ion_handle *handle;
if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
return -EFAULT;
handle = ion_alloc(client, data.len, data.align,
data.heap_id_mask, data.flags);
handle = ion_alloc(client, data.allocation.len,
data.allocation.align,
data.allocation.heap_id_mask,
data.allocation.flags);
if (IS_ERR(handle))
return PTR_ERR(handle);
data.handle = handle->id;
data.allocation.handle = handle->id;
if (copy_to_user((void __user *)arg, &data, sizeof(data))) {
ion_free(client, handle);
return -EFAULT;
}
cleanup_handle = handle;
break;
}
case ION_IOC_FREE:
{
struct ion_handle_data data;
struct ion_handle *handle;
if (copy_from_user(&data, (void __user *)arg,
sizeof(struct ion_handle_data)))
return -EFAULT;
mutex_lock(&client->lock);
handle = ion_uhandle_get(client, data.handle);
mutex_unlock(&client->lock);
if (!handle)
return -EINVAL;
handle = ion_handle_get_by_id(client, data.handle.handle);
if (IS_ERR(handle))
return PTR_ERR(handle);
ion_free(client, handle);
ion_handle_put(handle);
break;
}
case ION_IOC_SHARE:
case ION_IOC_MAP:
{
struct ion_fd_data data;
struct ion_handle *handle;
if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
return -EFAULT;
handle = ion_uhandle_get(client, data.handle);
data.fd = ion_share_dma_buf_fd(client, handle);
if (copy_to_user((void __user *)arg, &data, sizeof(data)))
return -EFAULT;
if (data.fd < 0)
return data.fd;
handle = ion_handle_get_by_id(client, data.handle.handle);
if (IS_ERR(handle))
return PTR_ERR(handle);
data.fd.fd = ion_share_dma_buf_fd(client, handle);
ion_handle_put(handle);
if (data.fd.fd < 0)
ret = data.fd.fd;
break;
}
case ION_IOC_IMPORT:
{
struct ion_fd_data data;
struct ion_handle *handle;
int ret = 0;
if (copy_from_user(&data, (void __user *)arg,
sizeof(struct ion_fd_data)))
return -EFAULT;
handle = ion_import_dma_buf(client, data.fd);
handle = ion_import_dma_buf(client, data.fd.fd);
if (IS_ERR(handle))
ret = PTR_ERR(handle);
else
data.handle = handle->id;
if (copy_to_user((void __user *)arg, &data,
sizeof(struct ion_fd_data)))
return -EFAULT;
if (ret < 0)
return ret;
data.handle.handle = handle->id;
break;
}
case ION_IOC_SYNC:
{
struct ion_fd_data data;
if (copy_from_user(&data, (void __user *)arg,
sizeof(struct ion_fd_data)))
return -EFAULT;
ion_sync_for_device(client, data.fd);
ret = ion_sync_for_device(client, data.fd.fd);
break;
}
case ION_IOC_CUSTOM:
{
struct ion_device *dev = client->dev;
struct ion_custom_data data;
if (!dev->custom_ioctl)
return -ENOTTY;
if (copy_from_user(&data, (void __user *)arg,
sizeof(struct ion_custom_data)))
return -EFAULT;
return dev->custom_ioctl(client, data.cmd, data.arg);
ret = dev->custom_ioctl(client, data.custom.cmd,
data.custom.arg);
break;
}
default:
return -ENOTTY;
}
return 0;
if (dir & _IOC_READ) {
if (copy_to_user((void __user *)arg, &data, _IOC_SIZE(cmd))) {
if (cleanup_handle)
ion_free(client, cleanup_handle);
return -EFAULT;
}
}
return ret;
}
static int ion_release(struct inode *inode, struct file *file)
@ -1299,10 +1350,10 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused)
char task_comm[TASK_COMM_LEN];
get_task_comm(task_comm, client->task);
seq_printf(s, "%16.s %16u %16u\n", task_comm,
seq_printf(s, "%16.s %16u %16zu\n", task_comm,
client->pid, size);
} else {
seq_printf(s, "%16.s %16u %16u\n", client->name,
seq_printf(s, "%16.s %16u %16zu\n", client->name,
client->pid, size);
}
}
@ -1317,19 +1368,20 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused)
continue;
total_size += buffer->size;
if (!buffer->handle_count) {
seq_printf(s, "%16.s %16u %16u %d %d\n", buffer->task_comm,
buffer->pid, buffer->size, buffer->kmap_cnt,
seq_printf(s, "%16.s %16u %16zu %d %d\n",
buffer->task_comm, buffer->pid,
buffer->size, buffer->kmap_cnt,
atomic_read(&buffer->ref.refcount));
total_orphaned_size += buffer->size;
}
}
mutex_unlock(&dev->buffer_lock);
seq_printf(s, "----------------------------------------------------\n");
seq_printf(s, "%16.s %16u\n", "total orphaned",
seq_printf(s, "%16.s %16zu\n", "total orphaned",
total_orphaned_size);
seq_printf(s, "%16.s %16u\n", "total ", total_size);
seq_printf(s, "%16.s %16zu\n", "total ", total_size);
if (heap->flags & ION_HEAP_FLAG_DEFER_FREE)
seq_printf(s, "%16.s %16u\n", "deferred free",
seq_printf(s, "%16.s %16zu\n", "deferred free",
heap->free_list_size);
seq_printf(s, "----------------------------------------------------\n");
@ -1354,39 +1406,39 @@ static const struct file_operations debug_heap_fops = {
#ifdef DEBUG_HEAP_SHRINKER
static int debug_shrink_set(void *data, u64 val)
{
struct ion_heap *heap = data;
struct shrink_control sc;
int objs;
struct ion_heap *heap = data;
struct shrink_control sc;
int objs;
sc.gfp_mask = -1;
sc.nr_to_scan = 0;
sc.gfp_mask = -1;
sc.nr_to_scan = 0;
if (!val)
return 0;
if (!val)
return 0;
objs = heap->shrinker.shrink(&heap->shrinker, &sc);
sc.nr_to_scan = objs;
objs = heap->shrinker.shrink(&heap->shrinker, &sc);
sc.nr_to_scan = objs;
heap->shrinker.shrink(&heap->shrinker, &sc);
return 0;
heap->shrinker.shrink(&heap->shrinker, &sc);
return 0;
}
static int debug_shrink_get(void *data, u64 *val)
{
struct ion_heap *heap = data;
struct shrink_control sc;
int objs;
struct ion_heap *heap = data;
struct shrink_control sc;
int objs;
sc.gfp_mask = -1;
sc.nr_to_scan = 0;
sc.gfp_mask = -1;
sc.nr_to_scan = 0;
objs = heap->shrinker.shrink(&heap->shrinker, &sc);
*val = objs;
return 0;
objs = heap->shrinker.shrink(&heap->shrinker, &sc);
*val = objs;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(debug_shrink_fops, debug_shrink_get,
debug_shrink_set, "%llu\n");
debug_shrink_set, "%llu\n");
#endif
void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap)
@ -1485,11 +1537,11 @@ void __init ion_reserve(struct ion_platform_data *data)
int ret = memblock_reserve(data->heaps[i].base,
data->heaps[i].size);
if (ret)
pr_err("memblock reserve of %x@%lx failed\n",
pr_err("memblock reserve of %zx@%lx failed\n",
data->heaps[i].size,
data->heaps[i].base);
}
pr_info("%s: %s reserved base %lx size %d\n", __func__,
pr_info("%s: %s reserved base %lx size %zu\n", __func__,
data->heaps[i].name,
data->heaps[i].base,
data->heaps[i].size);

View File

@ -1,5 +1,5 @@
/*
* include/linux/ion.h
* drivers/staging/android/ion/ion.h
*
* Copyright (C) 2011 Google, Inc.
*
@ -19,51 +19,8 @@
#include <linux/types.h>
typedef int ion_user_handle_t;
#include "../uapi/ion.h"
/**
* enum ion_heap_types - list of all possible types of heaps
* @ION_HEAP_TYPE_SYSTEM: memory allocated via vmalloc
* @ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kmalloc
* @ION_HEAP_TYPE_CARVEOUT: memory allocated from a prereserved
* carveout heap, allocations are physically
* contiguous
* @ION_HEAP_TYPE_DMA: memory allocated via DMA API
* @ION_NUM_HEAPS: helper for iterating over heaps, a bit mask
* is used to identify the heaps, so only 32
* total heap types are supported
*/
enum ion_heap_type {
ION_HEAP_TYPE_SYSTEM,
ION_HEAP_TYPE_SYSTEM_CONTIG,
ION_HEAP_TYPE_CARVEOUT,
ION_HEAP_TYPE_CHUNK,
ION_HEAP_TYPE_DMA,
ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always
are at the end of this enum */
ION_NUM_HEAPS = 16,
};
#define ION_HEAP_SYSTEM_MASK (1 << ION_HEAP_TYPE_SYSTEM)
#define ION_HEAP_SYSTEM_CONTIG_MASK (1 << ION_HEAP_TYPE_SYSTEM_CONTIG)
#define ION_HEAP_CARVEOUT_MASK (1 << ION_HEAP_TYPE_CARVEOUT)
#define ION_HEAP_TYPE_DMA_MASK (1 << ION_HEAP_TYPE_DMA)
#define ION_NUM_HEAP_IDS sizeof(unsigned int) * 8
/**
* allocation flags - the lower 16 bits are used by core ion, the upper 16
* bits are reserved for use by the heaps themselves.
*/
#define ION_FLAG_CACHED 1 /* mappings of this buffer should be
cached, ion will do cache
maintenance when the buffer is
mapped for dma */
#define ION_FLAG_CACHED_NEEDS_SYNC 2 /* mappings of this buffer will created
at mmap time, if this is set
caches must be managed manually */
#ifdef __KERNEL__
struct ion_handle;
struct ion_device;
struct ion_heap;
@ -81,7 +38,7 @@ struct ion_buffer;
* struct ion_platform_heap - defines a heap in the given platform
* @type: type of the heap from ion_heap_type enum
* @id: unique identifier for heap. When allocating higher numbers
* will be allocated from first. At allocation these are passed
* will be allocated from first. At allocation these are passed
* as a bit mask and therefore can not exceed ION_NUM_HEAP_IDS.
* @name: used for debug purposes
* @base: base address of heap in physical memory if applicable
@ -244,135 +201,4 @@ int ion_share_dma_buf_fd(struct ion_client *client, struct ion_handle *handle);
*/
struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd);
#endif /* __KERNEL__ */
/**
* DOC: Ion Userspace API
*
* create a client by opening /dev/ion
* most operations handled via following ioctls
*
*/
/**
* struct ion_allocation_data - metadata passed from userspace for allocations
* @len: size of the allocation
* @align: required alignment of the allocation
* @heap_id_mask: mask of heap ids to allocate from
* @flags: flags passed to heap
* @handle: pointer that will be populated with a cookie to use to
* refer to this allocation
*
* Provided by userspace as an argument to the ioctl
*/
struct ion_allocation_data {
size_t len;
size_t align;
unsigned int heap_id_mask;
unsigned int flags;
ion_user_handle_t handle;
};
/**
* struct ion_fd_data - metadata passed to/from userspace for a handle/fd pair
* @handle: a handle
* @fd: a file descriptor representing that handle
*
* For ION_IOC_SHARE or ION_IOC_MAP userspace populates the handle field with
* the handle returned from ion alloc, and the kernel returns the file
* descriptor to share or map in the fd field. For ION_IOC_IMPORT, userspace
* provides the file descriptor and the kernel returns the handle.
*/
struct ion_fd_data {
ion_user_handle_t handle;
int fd;
};
/**
* struct ion_handle_data - a handle passed to/from the kernel
* @handle: a handle
*/
struct ion_handle_data {
ion_user_handle_t handle;
};
/**
* struct ion_custom_data - metadata passed to/from userspace for a custom ioctl
* @cmd: the custom ioctl function to call
* @arg: additional data to pass to the custom ioctl, typically a user
* pointer to a predefined structure
*
* This works just like the regular cmd and arg fields of an ioctl.
*/
struct ion_custom_data {
unsigned int cmd;
unsigned long arg;
};
#define ION_IOC_MAGIC 'I'
/**
* DOC: ION_IOC_ALLOC - allocate memory
*
* Takes an ion_allocation_data struct and returns it with the handle field
* populated with the opaque handle for the allocation.
*/
#define ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, \
struct ion_allocation_data)
/**
* DOC: ION_IOC_FREE - free memory
*
* Takes an ion_handle_data struct and frees the handle.
*/
#define ION_IOC_FREE _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data)
/**
* DOC: ION_IOC_MAP - get a file descriptor to mmap
*
* Takes an ion_fd_data struct with the handle field populated with a valid
* opaque handle. Returns the struct with the fd field set to a file
* descriptor open in the current address space. This file descriptor
* can then be used as an argument to mmap.
*/
#define ION_IOC_MAP _IOWR(ION_IOC_MAGIC, 2, struct ion_fd_data)
/**
* DOC: ION_IOC_SHARE - creates a file descriptor to use to share an allocation
*
* Takes an ion_fd_data struct with the handle field populated with a valid
* opaque handle. Returns the struct with the fd field set to a file
* descriptor open in the current address space. This file descriptor
* can then be passed to another process. The corresponding opaque handle can
* be retrieved via ION_IOC_IMPORT.
*/
#define ION_IOC_SHARE _IOWR(ION_IOC_MAGIC, 4, struct ion_fd_data)
/**
* DOC: ION_IOC_IMPORT - imports a shared file descriptor
*
* Takes an ion_fd_data struct with the fd field populated with a valid file
* descriptor obtained from ION_IOC_SHARE and returns the struct with the handle
* filed set to the corresponding opaque handle.
*/
#define ION_IOC_IMPORT _IOWR(ION_IOC_MAGIC, 5, struct ion_fd_data)
/**
* DOC: ION_IOC_SYNC - syncs a shared file descriptors to memory
*
* Deprecated in favor of using the dma_buf api's correctly (syncing
* will happend automatically when the buffer is mapped to a device).
* If necessary should be used after touching a cached buffer from the cpu,
* this will make the buffer in memory coherent.
*/
#define ION_IOC_SYNC _IOWR(ION_IOC_MAGIC, 7, struct ion_fd_data)
/**
* DOC: ION_IOC_CUSTOM - call architecture specific ion ioctl
*
* Takes the argument of the architecture specific ioctl to call and
* passes appropriate userdata for that ioctl
*/
#define ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data)
#endif /* _LINUX_ION_H */

View File

@ -14,19 +14,17 @@
*
*/
#include <linux/spinlock.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/genalloc.h>
#include <linux/io.h>
#include <linux/ion.h>
#include <linux/mm.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include "ion.h"
#include "ion_priv.h"
#include <asm/mach/map.h>
struct ion_carveout_heap {
struct ion_heap heap;
struct gen_pool *pool;
@ -62,7 +60,11 @@ static int ion_carveout_heap_phys(struct ion_heap *heap,
struct ion_buffer *buffer,
ion_phys_addr_t *addr, size_t *len)
{
*addr = buffer->priv_phys;
struct sg_table *table = buffer->priv_virt;
struct page *page = sg_page(table->sgl);
ion_phys_addr_t paddr = PFN_PHYS(page_to_pfn(page));
*addr = paddr;
*len = buffer->size;
return 0;
}
@ -72,91 +74,95 @@ static int ion_carveout_heap_allocate(struct ion_heap *heap,
unsigned long size, unsigned long align,
unsigned long flags)
{
buffer->priv_phys = ion_carveout_allocate(heap, size, align);
return buffer->priv_phys == ION_CARVEOUT_ALLOCATE_FAIL ? -ENOMEM : 0;
struct sg_table *table;
ion_phys_addr_t paddr;
int ret;
if (align > PAGE_SIZE)
return -EINVAL;
table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
if (!table)
return -ENOMEM;
ret = sg_alloc_table(table, 1, GFP_KERNEL);
if (ret)
goto err_free;
paddr = ion_carveout_allocate(heap, size, align);
if (paddr == ION_CARVEOUT_ALLOCATE_FAIL) {
ret = -ENOMEM;
goto err_free_table;
}
sg_set_page(table->sgl, pfn_to_page(PFN_DOWN(paddr)), size, 0);
buffer->priv_virt = table;
return 0;
err_free_table:
sg_free_table(table);
err_free:
kfree(table);
return ret;
}
static void ion_carveout_heap_free(struct ion_buffer *buffer)
{
struct ion_heap *heap = buffer->heap;
struct sg_table *table = buffer->priv_virt;
struct page *page = sg_page(table->sgl);
ion_phys_addr_t paddr = PFN_PHYS(page_to_pfn(page));
ion_carveout_free(heap, buffer->priv_phys, buffer->size);
buffer->priv_phys = ION_CARVEOUT_ALLOCATE_FAIL;
ion_heap_buffer_zero(buffer);
if (ion_buffer_cached(buffer))
dma_sync_sg_for_device(NULL, table->sgl, table->nents,
DMA_BIDIRECTIONAL);
ion_carveout_free(heap, paddr, buffer->size);
sg_free_table(table);
kfree(table);
}
struct sg_table *ion_carveout_heap_map_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
static struct sg_table *ion_carveout_heap_map_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
struct sg_table *table;
int ret;
table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
if (!table)
return ERR_PTR(-ENOMEM);
ret = sg_alloc_table(table, 1, GFP_KERNEL);
if (ret) {
kfree(table);
return ERR_PTR(ret);
}
sg_set_page(table->sgl, phys_to_page(buffer->priv_phys), buffer->size,
0);
return table;
return buffer->priv_virt;
}
void ion_carveout_heap_unmap_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
static void ion_carveout_heap_unmap_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
sg_free_table(buffer->sg_table);
}
void *ion_carveout_heap_map_kernel(struct ion_heap *heap,
struct ion_buffer *buffer)
{
void *ret;
int mtype = MT_MEMORY_NONCACHED;
if (buffer->flags & ION_FLAG_CACHED)
mtype = MT_MEMORY;
ret = __arm_ioremap(buffer->priv_phys, buffer->size,
mtype);
if (ret == NULL)
return ERR_PTR(-ENOMEM);
return ret;
}
void ion_carveout_heap_unmap_kernel(struct ion_heap *heap,
struct ion_buffer *buffer)
{
__arm_iounmap(buffer->vaddr);
buffer->vaddr = NULL;
return;
}
int ion_carveout_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
struct vm_area_struct *vma)
{
return remap_pfn_range(vma, vma->vm_start,
__phys_to_pfn(buffer->priv_phys) + vma->vm_pgoff,
vma->vm_end - vma->vm_start,
pgprot_noncached(vma->vm_page_prot));
}
static struct ion_heap_ops carveout_heap_ops = {
.allocate = ion_carveout_heap_allocate,
.free = ion_carveout_heap_free,
.phys = ion_carveout_heap_phys,
.map_dma = ion_carveout_heap_map_dma,
.unmap_dma = ion_carveout_heap_unmap_dma,
.map_user = ion_carveout_heap_map_user,
.map_kernel = ion_carveout_heap_map_kernel,
.unmap_kernel = ion_carveout_heap_unmap_kernel,
.map_user = ion_heap_map_user,
.map_kernel = ion_heap_map_kernel,
.unmap_kernel = ion_heap_unmap_kernel,
};
struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *heap_data)
{
struct ion_carveout_heap *carveout_heap;
int ret;
struct page *page;
size_t size;
page = pfn_to_page(PFN_DOWN(heap_data->base));
size = heap_data->size;
ion_pages_sync_for_device(NULL, page, size, DMA_BIDIRECTIONAL);
ret = ion_heap_pages_zero(page, size, pgprot_writecombine(PAGE_KERNEL));
if (ret)
return ERR_PTR(ret);
carveout_heap = kzalloc(sizeof(struct ion_carveout_heap), GFP_KERNEL);
if (!carveout_heap)
@ -172,6 +178,7 @@ struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *heap_data)
-1);
carveout_heap->heap.ops = &carveout_heap_ops;
carveout_heap->heap.type = ION_HEAP_TYPE_CARVEOUT;
carveout_heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE;
return &carveout_heap->heap;
}

View File

@ -13,20 +13,17 @@
* GNU General Public License for more details.
*
*/
//#include <linux/spinlock.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/genalloc.h>
#include <linux/io.h>
#include <linux/ion.h>
#include <linux/mm.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include "ion.h"
#include "ion_priv.h"
#include <asm/mach/map.h>
struct ion_chunk_heap {
struct ion_heap heap;
struct gen_pool *pool;
@ -49,8 +46,8 @@ static int ion_chunk_heap_allocate(struct ion_heap *heap,
unsigned long num_chunks;
unsigned long allocated_size;
if (ion_buffer_fault_user_mappings(buffer))
return -ENOMEM;
if (align > chunk_heap->chunk_size)
return -EINVAL;
allocated_size = ALIGN(size, chunk_heap->chunk_size);
num_chunks = allocated_size / chunk_heap->chunk_size;
@ -73,7 +70,8 @@ static int ion_chunk_heap_allocate(struct ion_heap *heap,
chunk_heap->chunk_size);
if (!paddr)
goto err;
sg_set_page(sg, phys_to_page(paddr), chunk_heap->chunk_size, 0);
sg_set_page(sg, pfn_to_page(PFN_DOWN(paddr)),
chunk_heap->chunk_size, 0);
sg = sg_next(sg);
}
@ -84,7 +82,7 @@ static int ion_chunk_heap_allocate(struct ion_heap *heap,
sg = table->sgl;
for (i -= 1; i >= 0; i--) {
gen_pool_free(chunk_heap->pool, page_to_phys(sg_page(sg)),
sg_dma_len(sg));
sg->length);
sg = sg_next(sg);
}
sg_free_table(table);
@ -106,27 +104,27 @@ static void ion_chunk_heap_free(struct ion_buffer *buffer)
ion_heap_buffer_zero(buffer);
if (ion_buffer_cached(buffer))
dma_sync_sg_for_device(NULL, table->sgl, table->nents,
DMA_BIDIRECTIONAL);
for_each_sg(table->sgl, sg, table->nents, i) {
if (ion_buffer_cached(buffer))
arm_dma_ops.sync_single_for_device(NULL,
pfn_to_dma(NULL, page_to_pfn(sg_page(sg))),
sg_dma_len(sg), DMA_BIDIRECTIONAL);
gen_pool_free(chunk_heap->pool, page_to_phys(sg_page(sg)),
sg_dma_len(sg));
sg->length);
}
chunk_heap->allocated -= allocated_size;
sg_free_table(table);
kfree(table);
}
struct sg_table *ion_chunk_heap_map_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
static struct sg_table *ion_chunk_heap_map_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
return buffer->priv_virt;
}
void ion_chunk_heap_unmap_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
static void ion_chunk_heap_unmap_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
return;
}
@ -144,10 +142,18 @@ static struct ion_heap_ops chunk_heap_ops = {
struct ion_heap *ion_chunk_heap_create(struct ion_platform_heap *heap_data)
{
struct ion_chunk_heap *chunk_heap;
struct vm_struct *vm_struct;
pgprot_t pgprot = pgprot_writecombine(PAGE_KERNEL);
int i, ret;
int ret;
struct page *page;
size_t size;
page = pfn_to_page(PFN_DOWN(heap_data->base));
size = heap_data->size;
ion_pages_sync_for_device(NULL, page, size, DMA_BIDIRECTIONAL);
ret = ion_heap_pages_zero(page, size, pgprot_writecombine(PAGE_KERNEL));
if (ret)
return ERR_PTR(ret);
chunk_heap = kzalloc(sizeof(struct ion_chunk_heap), GFP_KERNEL);
if (!chunk_heap)
@ -164,39 +170,15 @@ struct ion_heap *ion_chunk_heap_create(struct ion_platform_heap *heap_data)
chunk_heap->size = heap_data->size;
chunk_heap->allocated = 0;
vm_struct = get_vm_area(PAGE_SIZE, VM_ALLOC);
if (!vm_struct) {
ret = -ENOMEM;
goto error;
}
for (i = 0; i < chunk_heap->size; i += PAGE_SIZE) {
struct page *page = phys_to_page(chunk_heap->base + i);
struct page **pages = &page;
ret = map_vm_area(vm_struct, pgprot, &pages);
if (ret)
goto error_map_vm_area;
memset(vm_struct->addr, 0, PAGE_SIZE);
unmap_kernel_range((unsigned long)vm_struct->addr, PAGE_SIZE);
}
free_vm_area(vm_struct);
arm_dma_ops.sync_single_for_device(NULL,
pfn_to_dma(NULL, page_to_pfn(phys_to_page(heap_data->base))),
heap_data->size, DMA_BIDIRECTIONAL);
gen_pool_add(chunk_heap->pool, chunk_heap->base, heap_data->size, -1);
chunk_heap->heap.ops = &chunk_heap_ops;
chunk_heap->heap.type = ION_HEAP_TYPE_CHUNK;
chunk_heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE;
pr_info("%s: base %lu size %zu align %ld\n", __func__,
chunk_heap->base, heap_data->size, heap_data->align);
pr_info("%s: base %lu size %zu align %ld\n", __func__, chunk_heap->base,
heap_data->size, heap_data->align);
return &chunk_heap->heap;
error_map_vm_area:
free_vm_area(vm_struct);
error:
gen_pool_destroy(chunk_heap->pool);
error_gen_pool_create:
kfree(chunk_heap);
return ERR_PTR(ret);

View File

@ -16,13 +16,12 @@
*/
#include <linux/device.h>
#include <linux/ion.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/dma-mapping.h>
/* for ion_heap_ops structure */
#include "ion.h"
#include "ion_priv.h"
#define ION_CMA_ALLOCATE_FAILED -1
@ -45,8 +44,8 @@ struct ion_cma_buffer_info {
* This function could be replaced by dma_common_get_sgtable
* as soon as it will avalaible.
*/
int ion_cma_get_sgtable(struct device *dev, struct sg_table *sgt,
void *cpu_addr, dma_addr_t handle, size_t size)
static int ion_cma_get_sgtable(struct device *dev, struct sg_table *sgt,
void *cpu_addr, dma_addr_t handle, size_t size)
{
struct page *page = virt_to_page(cpu_addr);
int ret;
@ -70,13 +69,20 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer,
dev_dbg(dev, "Request buffer allocation len %ld\n", len);
if (buffer->flags & ION_FLAG_CACHED)
return -EINVAL;
if (align > PAGE_SIZE)
return -EINVAL;
info = kzalloc(sizeof(struct ion_cma_buffer_info), GFP_KERNEL);
if (!info) {
dev_err(dev, "Can't allocate buffer info\n");
return ION_CMA_ALLOCATE_FAILED;
}
info->cpu_addr = dma_alloc_coherent(dev, len, &(info->handle), 0);
info->cpu_addr = dma_alloc_coherent(dev, len, &(info->handle),
GFP_HIGHUSER | __GFP_ZERO);
if (!info->cpu_addr) {
dev_err(dev, "Fail to allocate buffer\n");
@ -129,8 +135,8 @@ static int ion_cma_phys(struct ion_heap *heap, struct ion_buffer *buffer,
struct device *dev = cma_heap->dev;
struct ion_cma_buffer_info *info = buffer->priv_virt;
dev_dbg(dev, "Return buffer %p physical address 0x%x\n", buffer,
info->handle);
dev_dbg(dev, "Return buffer %p physical address 0x%pa\n", buffer,
&info->handle);
*addr = info->handle;
*len = buffer->size;
@ -138,16 +144,16 @@ static int ion_cma_phys(struct ion_heap *heap, struct ion_buffer *buffer,
return 0;
}
struct sg_table *ion_cma_heap_map_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
static struct sg_table *ion_cma_heap_map_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
struct ion_cma_buffer_info *info = buffer->priv_virt;
return info->table;
}
void ion_cma_heap_unmap_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
static void ion_cma_heap_unmap_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
return;
}
@ -163,13 +169,19 @@ static int ion_cma_mmap(struct ion_heap *mapper, struct ion_buffer *buffer,
buffer->size);
}
void *ion_cma_map_kernel(struct ion_heap *heap, struct ion_buffer *buffer)
static void *ion_cma_map_kernel(struct ion_heap *heap,
struct ion_buffer *buffer)
{
struct ion_cma_buffer_info *info = buffer->priv_virt;
/* kernel memory mapping has been done at allocation time */
return info->cpu_addr;
}
static void ion_cma_unmap_kernel(struct ion_heap *heap,
struct ion_buffer *buffer)
{
}
static struct ion_heap_ops ion_cma_ops = {
.allocate = ion_cma_allocate,
.free = ion_cma_free,
@ -178,6 +190,7 @@ static struct ion_heap_ops ion_cma_ops = {
.phys = ion_cma_phys,
.map_user = ion_cma_mmap,
.map_kernel = ion_cma_map_kernel,
.unmap_kernel = ion_cma_unmap_kernel,
};
struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *data)

View File

@ -16,13 +16,13 @@
#include <linux/err.h>
#include <linux/freezer.h>
#include <linux/ion.h>
#include <linux/kthread.h>
#include <linux/mm.h>
#include <linux/rtmutex.h>
#include <linux/sched.h>
#include <linux/scatterlist.h>
#include <linux/vmalloc.h>
#include "ion.h"
#include "ion_priv.h"
void *ion_heap_map_kernel(struct ion_heap *heap,
@ -38,7 +38,7 @@ void *ion_heap_map_kernel(struct ion_heap *heap,
struct page **tmp = pages;
if (!pages)
return 0;
return NULL;
if (buffer->flags & ION_FLAG_CACHED)
pgprot = PAGE_KERNEL;
@ -46,12 +46,11 @@ void *ion_heap_map_kernel(struct ion_heap *heap,
pgprot = pgprot_writecombine(PAGE_KERNEL);
for_each_sg(table->sgl, sg, table->nents, i) {
int npages_this_entry = PAGE_ALIGN(sg_dma_len(sg)) / PAGE_SIZE;
int npages_this_entry = PAGE_ALIGN(sg->length) / PAGE_SIZE;
struct page *page = sg_page(sg);
BUG_ON(i >= npages);
for (j = 0; j < npages_this_entry; j++) {
for (j = 0; j < npages_this_entry; j++)
*(tmp++) = page++;
}
}
vaddr = vmap(pages, npages, VM_MAP, pgprot);
vfree(pages);
@ -76,23 +75,26 @@ int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
unsigned long offset = vma->vm_pgoff * PAGE_SIZE;
struct scatterlist *sg;
int i;
int ret;
for_each_sg(table->sgl, sg, table->nents, i) {
struct page *page = sg_page(sg);
unsigned long remainder = vma->vm_end - addr;
unsigned long len = sg_dma_len(sg);
unsigned long len = sg->length;
if (offset >= sg_dma_len(sg)) {
offset -= sg_dma_len(sg);
if (offset >= sg->length) {
offset -= sg->length;
continue;
} else if (offset) {
page += offset / PAGE_SIZE;
len = sg_dma_len(sg) - offset;
len = sg->length - offset;
offset = 0;
}
len = min(len, remainder);
remap_pfn_range(vma, addr, page_to_pfn(page), len,
ret = remap_pfn_range(vma, addr, page_to_pfn(page), len,
vma->vm_page_prot);
if (ret)
return ret;
addr += len;
if (addr >= vma->vm_end)
return 0;
@ -100,71 +102,63 @@ int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
return 0;
}
static int ion_heap_clear_pages(struct page **pages, int num, pgprot_t pgprot)
{
void *addr = vm_map_ram(pages, num, -1, pgprot);
if (!addr)
return -ENOMEM;
memset(addr, 0, PAGE_SIZE * num);
vm_unmap_ram(addr, num);
return 0;
}
static int ion_heap_sglist_zero(struct scatterlist *sgl, unsigned int nents,
pgprot_t pgprot)
{
int p = 0;
int ret = 0;
struct sg_page_iter piter;
struct page *pages[32];
for_each_sg_page(sgl, &piter, nents, 0) {
pages[p++] = sg_page_iter_page(&piter);
if (p == ARRAY_SIZE(pages)) {
ret = ion_heap_clear_pages(pages, p, pgprot);
if (ret)
return ret;
p = 0;
}
}
if (p)
ret = ion_heap_clear_pages(pages, p, pgprot);
return ret;
}
int ion_heap_buffer_zero(struct ion_buffer *buffer)
{
struct sg_table *table = buffer->sg_table;
pgprot_t pgprot;
struct scatterlist *sg;
struct vm_struct *vm_struct;
int i, j, ret = 0;
if (buffer->flags & ION_FLAG_CACHED)
pgprot = PAGE_KERNEL;
else
pgprot = pgprot_writecombine(PAGE_KERNEL);
vm_struct = get_vm_area(PAGE_SIZE, VM_ALLOC);
if (!vm_struct)
return -ENOMEM;
for_each_sg(table->sgl, sg, table->nents, i) {
struct page *page = sg_page(sg);
unsigned long len = sg_dma_len(sg);
for (j = 0; j < len / PAGE_SIZE; j++) {
struct page *sub_page = page + j;
struct page **pages = &sub_page;
ret = map_vm_area(vm_struct, pgprot, &pages);
if (ret)
goto end;
memset(vm_struct->addr, 0, PAGE_SIZE);
unmap_kernel_range((unsigned long)vm_struct->addr,
PAGE_SIZE);
}
}
end:
free_vm_area(vm_struct);
return ret;
return ion_heap_sglist_zero(table->sgl, table->nents, pgprot);
}
struct page *ion_heap_alloc_pages(struct ion_buffer *buffer, gfp_t gfp_flags,
unsigned int order)
int ion_heap_pages_zero(struct page *page, size_t size, pgprot_t pgprot)
{
struct page *page = alloc_pages(gfp_flags, order);
struct scatterlist sg;
if (!page)
return page;
if (ion_buffer_fault_user_mappings(buffer))
split_page(page, order);
return page;
sg_init_table(&sg, 1);
sg_set_page(&sg, page, size, 0);
return ion_heap_sglist_zero(&sg, 1, pgprot);
}
void ion_heap_free_pages(struct ion_buffer *buffer, struct page *page,
unsigned int order)
{
int i;
if (!ion_buffer_fault_user_mappings(buffer)) {
__free_pages(page, order);
return;
}
for (i = 0; i < (1 << order); i++)
__free_page(page + i);
}
void ion_heap_freelist_add(struct ion_heap *heap, struct ion_buffer * buffer)
void ion_heap_freelist_add(struct ion_heap *heap, struct ion_buffer *buffer)
{
rt_mutex_lock(&heap->lock);
list_add(&buffer->list, &heap->free_list);
@ -200,16 +194,16 @@ size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size)
if (total_drained >= size)
break;
list_del(&buffer->list);
ion_buffer_destroy(buffer);
heap->free_list_size -= buffer->size;
total_drained += buffer->size;
ion_buffer_destroy(buffer);
}
rt_mutex_unlock(&heap->lock);
return total_drained;
}
int ion_heap_deferred_free(void *data)
static int ion_heap_deferred_free(void *data)
{
struct ion_heap *heap = data;
@ -281,7 +275,7 @@ struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data)
}
if (IS_ERR_OR_NULL(heap)) {
pr_err("%s: error creating heap %s type %d base %lu size %u\n",
pr_err("%s: error creating heap %s type %d base %lu size %zu\n",
__func__, heap_data->name, heap_data->type,
heap_data->base, heap_data->size);
return ERR_PTR(-EINVAL);

View File

@ -34,13 +34,8 @@ static void *ion_page_pool_alloc_pages(struct ion_page_pool *pool)
if (!page)
return NULL;
/* this is only being used to flush the page for dma,
this api is not really suitable for calling from a driver
but no better way to flush a page for dma exist at this time */
arm_dma_ops.sync_single_for_device(NULL,
pfn_to_dma(NULL, page_to_pfn(page)),
PAGE_SIZE << pool->order,
DMA_BIDIRECTIONAL);
ion_pages_sync_for_device(NULL, page, PAGE_SIZE << pool->order,
DMA_BIDIRECTIONAL);
return page;
}
@ -113,7 +108,7 @@ void *ion_page_pool_alloc(struct ion_page_pool *pool)
return page;
}
void ion_page_pool_free(struct ion_page_pool *pool, struct page* page)
void ion_page_pool_free(struct ion_page_pool *pool, struct page *page)
{
int ret;
@ -139,7 +134,7 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
int i;
bool high;
high = gfp_mask & __GFP_HIGHMEM;
high = !!(gfp_mask & __GFP_HIGHMEM);
if (nr_to_scan == 0)
return ion_page_pool_total(pool, high);
@ -148,10 +143,10 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
struct page *page;
mutex_lock(&pool->mutex);
if (high && pool->high_count) {
page = ion_page_pool_remove(pool, true);
} else if (pool->low_count) {
if (pool->low_count) {
page = ion_page_pool_remove(pool, false);
} else if (high && pool->high_count) {
page = ion_page_pool_remove(pool, true);
} else {
mutex_unlock(&pool->mutex);
break;

View File

@ -17,7 +17,7 @@
#ifndef _ION_PRIV_H
#define _ION_PRIV_H
#include <linux/ion.h>
#include <linux/dma-direction.h>
#include <linux/kref.h>
#include <linux/mm_types.h>
#include <linux/mutex.h>
@ -26,6 +26,8 @@
#include <linux/shrinker.h>
#include <linux/types.h>
#include "ion.h"
struct ion_buffer *ion_handle_buffer(struct ion_handle *handle);
/**
@ -213,19 +215,7 @@ void ion_heap_unmap_kernel(struct ion_heap *, struct ion_buffer *);
int ion_heap_map_user(struct ion_heap *, struct ion_buffer *,
struct vm_area_struct *);
int ion_heap_buffer_zero(struct ion_buffer *buffer);
/**
* ion_heap_alloc_pages - allocate pages from alloc_pages
* @buffer: the buffer to allocate for, used to extract the flags
* @gfp_flags: the gfp_t for the allocation
* @order: the order of the allocatoin
*
* This funciton allocations from alloc pages and also does any other
* necessary operations based on the buffer->flags. For buffers which
* will be faulted in the pages are split using split_page
*/
struct page *ion_heap_alloc_pages(struct ion_buffer *buffer, gfp_t gfp_flags,
unsigned int order);
int ion_heap_pages_zero(struct page *page, size_t size, pgprot_t pgprot);
/**
* ion_heap_init_deferred_free -- initialize deferred free functionality
@ -240,7 +230,7 @@ int ion_heap_init_deferred_free(struct ion_heap *heap);
/**
* ion_heap_freelist_add - add a buffer to the deferred free list
* @heap: the heap
* @buffer: the buffer
* @buffer: the buffer
*
* Adds an item to the deferred freelist.
*/
@ -356,4 +346,15 @@ void ion_page_pool_free(struct ion_page_pool *, struct page *);
int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
int nr_to_scan);
/**
* ion_pages_sync_for_device - cache flush pages for use with the specified
* device
* @dev: the device the pages will be used with
* @page: the first page to be flushed
* @size: size in bytes of region to be flushed
* @dir: direction of dma transfer
*/
void ion_pages_sync_for_device(struct device *dev, struct page *page,
size_t size, enum dma_data_direction dir);
#endif /* _ION_PRIV_H */

View File

@ -18,19 +18,17 @@
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/highmem.h>
#include <linux/ion.h>
#include <linux/mm.h>
#include <linux/scatterlist.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include "ion.h"
#include "ion_priv.h"
static unsigned int high_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO |
__GFP_NOWARN | __GFP_NORETRY) &
~__GFP_WAIT;
static unsigned int low_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO |
__GFP_NOWARN);
static gfp_t high_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO | __GFP_NOWARN |
__GFP_NORETRY) & ~__GFP_WAIT;
static gfp_t low_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO | __GFP_NOWARN);
static const unsigned int orders[] = {8, 4, 0};
static const int num_orders = ARRAY_SIZE(orders);
static int order_to_index(unsigned int order)
@ -74,15 +72,14 @@ static struct page *alloc_buffer_page(struct ion_system_heap *heap,
if (order > 4)
gfp_flags = high_order_gfp_flags;
page = ion_heap_alloc_pages(buffer, gfp_flags, order);
page = alloc_pages(gfp_flags, order);
if (!page)
return 0;
arm_dma_ops.sync_single_for_device(NULL,
pfn_to_dma(NULL, page_to_pfn(page)),
PAGE_SIZE << order, DMA_BIDIRECTIONAL);
return NULL;
ion_pages_sync_for_device(NULL, page, PAGE_SIZE << order,
DMA_BIDIRECTIONAL);
}
if (!page)
return 0;
return NULL;
return page;
}
@ -92,15 +89,10 @@ static void free_buffer_page(struct ion_system_heap *heap,
unsigned int order)
{
bool cached = ion_buffer_cached(buffer);
bool split_pages = ion_buffer_fault_user_mappings(buffer);
int i;
if (!cached) {
struct ion_page_pool *pool = heap->pools[order_to_index(order)];
ion_page_pool_free(pool, page);
} else if (split_pages) {
for (i = 0; i < (1 << order); i++)
__free_page(page + i);
} else {
__free_pages(page, order);
}
@ -151,9 +143,13 @@ static int ion_system_heap_allocate(struct ion_heap *heap,
long size_remaining = PAGE_ALIGN(size);
unsigned int max_order = orders[0];
if (align > PAGE_SIZE)
return -EINVAL;
INIT_LIST_HEAD(&pages);
while (size_remaining > 0) {
info = alloc_largest_available(sys_heap, buffer, size_remaining, max_order);
info = alloc_largest_available(sys_heap, buffer, size_remaining,
max_order);
if (!info)
goto err;
list_add_tail(&info->list, &pages);
@ -161,8 +157,7 @@ static int ion_system_heap_allocate(struct ion_heap *heap,
max_order = info->order;
i++;
}
table = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
if (!table)
goto err;
@ -184,14 +179,14 @@ static int ion_system_heap_allocate(struct ion_heap *heap,
err1:
kfree(table);
err:
list_for_each_entry(info, &pages, list) {
list_for_each_entry_safe(info, tmp_info, &pages, list) {
free_buffer_page(sys_heap, buffer, info->page, info->order);
kfree(info);
}
return -ENOMEM;
}
void ion_system_heap_free(struct ion_buffer *buffer)
static void ion_system_heap_free(struct ion_buffer *buffer)
{
struct ion_heap *heap = buffer->heap;
struct ion_system_heap *sys_heap = container_of(heap,
@ -210,19 +205,19 @@ void ion_system_heap_free(struct ion_buffer *buffer)
for_each_sg(table->sgl, sg, table->nents, i)
free_buffer_page(sys_heap, buffer, sg_page(sg),
get_order(sg_dma_len(sg)));
get_order(sg->length));
sg_free_table(table);
kfree(table);
}
struct sg_table *ion_system_heap_map_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
static struct sg_table *ion_system_heap_map_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
return buffer->priv_virt;
}
void ion_system_heap_unmap_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
static void ion_system_heap_unmap_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
return;
}
@ -363,61 +358,83 @@ static int ion_system_contig_heap_allocate(struct ion_heap *heap,
unsigned long align,
unsigned long flags)
{
buffer->priv_virt = kzalloc(len, GFP_KERNEL);
if (!buffer->priv_virt)
int order = get_order(len);
struct page *page;
struct sg_table *table;
unsigned long i;
int ret;
if (align > (PAGE_SIZE << order))
return -EINVAL;
page = alloc_pages(low_order_gfp_flags, order);
if (!page)
return -ENOMEM;
split_page(page, order);
len = PAGE_ALIGN(len);
for (i = len >> PAGE_SHIFT; i < (1 << order); i++)
__free_page(page + i);
table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
if (!table) {
ret = -ENOMEM;
goto out;
}
ret = sg_alloc_table(table, 1, GFP_KERNEL);
if (ret)
goto out;
sg_set_page(table->sgl, page, len, 0);
buffer->priv_virt = table;
ion_pages_sync_for_device(NULL, page, len, DMA_BIDIRECTIONAL);
return 0;
out:
for (i = 0; i < len >> PAGE_SHIFT; i++)
__free_page(page + i);
kfree(table);
return ret;
}
void ion_system_contig_heap_free(struct ion_buffer *buffer)
static void ion_system_contig_heap_free(struct ion_buffer *buffer)
{
kfree(buffer->priv_virt);
struct sg_table *table = buffer->priv_virt;
struct page *page = sg_page(table->sgl);
unsigned long pages = PAGE_ALIGN(buffer->size) >> PAGE_SHIFT;
unsigned long i;
for (i = 0; i < pages; i++)
__free_page(page + i);
sg_free_table(table);
kfree(table);
}
static int ion_system_contig_heap_phys(struct ion_heap *heap,
struct ion_buffer *buffer,
ion_phys_addr_t *addr, size_t *len)
{
*addr = virt_to_phys(buffer->priv_virt);
struct sg_table *table = buffer->priv_virt;
struct page *page = sg_page(table->sgl);
*addr = page_to_phys(page);
*len = buffer->size;
return 0;
}
struct sg_table *ion_system_contig_heap_map_dma(struct ion_heap *heap,
static struct sg_table *ion_system_contig_heap_map_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
struct sg_table *table;
int ret;
table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
if (!table)
return ERR_PTR(-ENOMEM);
ret = sg_alloc_table(table, 1, GFP_KERNEL);
if (ret) {
kfree(table);
return ERR_PTR(ret);
}
sg_set_page(table->sgl, virt_to_page(buffer->priv_virt), buffer->size,
0);
return table;
return buffer->priv_virt;
}
void ion_system_contig_heap_unmap_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
static void ion_system_contig_heap_unmap_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
sg_free_table(buffer->sg_table);
kfree(buffer->sg_table);
}
int ion_system_contig_heap_map_user(struct ion_heap *heap,
struct ion_buffer *buffer,
struct vm_area_struct *vma)
{
unsigned long pfn = __phys_to_pfn(virt_to_phys(buffer->priv_virt));
return remap_pfn_range(vma, vma->vm_start, pfn + vma->vm_pgoff,
vma->vm_end - vma->vm_start,
vma->vm_page_prot);
}
static struct ion_heap_ops kmalloc_ops = {
@ -428,7 +445,7 @@ static struct ion_heap_ops kmalloc_ops = {
.unmap_dma = ion_system_contig_heap_unmap_dma,
.map_kernel = ion_heap_map_kernel,
.unmap_kernel = ion_heap_unmap_kernel,
.map_user = ion_system_contig_heap_map_user,
.map_user = ion_heap_map_user,
};
struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *unused)

View File

@ -0,0 +1,281 @@
/*
*
* Copyright (C) 2013 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#define pr_fmt(fmt) "ion-test: " fmt
#include <linux/dma-buf.h>
#include <linux/dma-direction.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include "ion.h"
#include "../uapi/ion_test.h"
#define u64_to_uptr(x) ((void __user *)(unsigned long)(x))
struct ion_test_device {
struct miscdevice misc;
};
struct ion_test_data {
struct dma_buf *dma_buf;
struct device *dev;
};
static int ion_handle_test_dma(struct device *dev, struct dma_buf *dma_buf,
void __user *ptr, size_t offset, size_t size, bool write)
{
int ret = 0;
struct dma_buf_attachment *attach;
struct sg_table *table;
pgprot_t pgprot = pgprot_writecombine(PAGE_KERNEL);
enum dma_data_direction dir = write ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
struct sg_page_iter sg_iter;
unsigned long offset_page;
attach = dma_buf_attach(dma_buf, dev);
if (IS_ERR(attach))
return PTR_ERR(attach);
table = dma_buf_map_attachment(attach, dir);
if (IS_ERR(table))
return PTR_ERR(table);
offset_page = offset >> PAGE_SHIFT;
offset %= PAGE_SIZE;
for_each_sg_page(table->sgl, &sg_iter, table->nents, offset_page) {
struct page *page = sg_page_iter_page(&sg_iter);
void *vaddr = vmap(&page, 1, VM_MAP, pgprot);
size_t to_copy = PAGE_SIZE - offset;
to_copy = min(to_copy, size);
if (!vaddr) {
ret = -ENOMEM;
goto err;
}
if (write)
ret = copy_from_user(vaddr + offset, ptr, to_copy);
else
ret = copy_to_user(ptr, vaddr + offset, to_copy);
vunmap(vaddr);
if (ret) {
ret = -EFAULT;
goto err;
}
size -= to_copy;
if (!size)
break;
ptr += to_copy;
offset = 0;
}
err:
dma_buf_unmap_attachment(attach, table, dir);
dma_buf_detach(dma_buf, attach);
return ret;
}
static int ion_handle_test_kernel(struct dma_buf *dma_buf, void __user *ptr,
size_t offset, size_t size, bool write)
{
int ret;
unsigned long page_offset = offset >> PAGE_SHIFT;
size_t copy_offset = offset % PAGE_SIZE;
size_t copy_size = size;
enum dma_data_direction dir = write ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
if (offset > dma_buf->size || size > dma_buf->size - offset)
return -EINVAL;
ret = dma_buf_begin_cpu_access(dma_buf, offset, size, dir);
if (ret)
return ret;
while (copy_size > 0) {
size_t to_copy;
void *vaddr = dma_buf_kmap(dma_buf, page_offset);
if (!vaddr)
goto err;
to_copy = min_t(size_t, PAGE_SIZE - copy_offset, copy_size);
if (write)
ret = copy_from_user(vaddr + copy_offset, ptr, to_copy);
else
ret = copy_to_user(ptr, vaddr + copy_offset, to_copy);
dma_buf_kunmap(dma_buf, page_offset, vaddr);
if (ret) {
ret = -EFAULT;
goto err;
}
copy_size -= to_copy;
ptr += to_copy;
page_offset++;
copy_offset = 0;
}
err:
dma_buf_end_cpu_access(dma_buf, offset, size, dir);
return ret;
}
static long ion_test_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
struct ion_test_data *test_data = filp->private_data;
int ret = 0;
union {
struct ion_test_rw_data test_rw;
} data;
if (_IOC_SIZE(cmd) > sizeof(data))
return -EINVAL;
if (_IOC_DIR(cmd) & _IOC_WRITE)
if (copy_from_user(&data, (void __user *)arg, _IOC_SIZE(cmd)))
return -EFAULT;
switch (cmd) {
case ION_IOC_TEST_SET_FD:
{
struct dma_buf *dma_buf = NULL;
int fd = arg;
if (fd >= 0) {
dma_buf = dma_buf_get((int)arg);
if (IS_ERR(dma_buf))
return PTR_ERR(dma_buf);
}
if (test_data->dma_buf)
dma_buf_put(test_data->dma_buf);
test_data->dma_buf = dma_buf;
break;
}
case ION_IOC_TEST_DMA_MAPPING:
{
ret = ion_handle_test_dma(test_data->dev, test_data->dma_buf,
u64_to_uptr(data.test_rw.ptr),
data.test_rw.offset, data.test_rw.size,
data.test_rw.write);
break;
}
case ION_IOC_TEST_KERNEL_MAPPING:
{
ret = ion_handle_test_kernel(test_data->dma_buf,
u64_to_uptr(data.test_rw.ptr),
data.test_rw.offset, data.test_rw.size,
data.test_rw.write);
break;
}
default:
return -ENOTTY;
}
if (_IOC_DIR(cmd) & _IOC_READ) {
if (copy_to_user((void __user *)arg, &data, sizeof(data)))
return -EFAULT;
}
return ret;
}
static int ion_test_open(struct inode *inode, struct file *file)
{
struct ion_test_data *data;
struct miscdevice *miscdev = file->private_data;
data = kzalloc(sizeof(struct ion_test_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->dev = miscdev->parent;
file->private_data = data;
return 0;
}
static int ion_test_release(struct inode *inode, struct file *file)
{
struct ion_test_data *data = file->private_data;
kfree(data);
return 0;
}
static const struct file_operations ion_test_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = ion_test_ioctl,
.open = ion_test_open,
.release = ion_test_release,
};
static int __init ion_test_probe(struct platform_device *pdev)
{
int ret;
struct ion_test_device *testdev;
testdev = devm_kzalloc(&pdev->dev, sizeof(struct ion_test_device),
GFP_KERNEL);
if (!testdev)
return -ENOMEM;
testdev->misc.minor = MISC_DYNAMIC_MINOR;
testdev->misc.name = "ion-test";
testdev->misc.fops = &ion_test_fops;
testdev->misc.parent = &pdev->dev;
ret = misc_register(&testdev->misc);
if (ret) {
pr_err("failed to register misc device.\n");
return ret;
}
platform_set_drvdata(pdev, testdev);
return 0;
}
static struct platform_driver ion_test_platform_driver = {
.driver = {
.name = "ion-test",
},
};
static int __init ion_test_init(void)
{
platform_device_register_simple("ion-test", -1, NULL, 0);
return platform_driver_probe(&ion_test_platform_driver, ion_test_probe);
}
static void __exit ion_test_exit(void)
{
platform_driver_unregister(&ion_test_platform_driver);
}
module_init(ion_test_init);
module_exit(ion_test_exit);

View File

@ -15,9 +15,9 @@
*/
#include <linux/err.h>
#include <linux/ion.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "../ion.h"
#include "../ion_priv.h"
struct ion_device *idev;

View File

@ -18,11 +18,9 @@
#define _LINUX_SW_SYNC_H
#include <linux/types.h>
#ifdef __KERNEL__
#include <linux/kconfig.h>
#include "sync.h"
#include "uapi/sw_sync.h"
struct sw_sync_timeline {
struct sync_timeline obj;
@ -58,19 +56,4 @@ static inline struct sync_pt *sw_sync_pt_create(struct sw_sync_timeline *obj,
}
#endif /* IS_ENABLED(CONFIG_SW_SYNC) */
#endif /* __KERNEL __ */
struct sw_sync_create_fence_data {
__u32 value;
char name[32];
__s32 fence; /* fd of new fence */
};
#define SW_SYNC_IOC_MAGIC 'W'
#define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0,\
struct sw_sync_create_fence_data)
#define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32)
#endif /* _LINUX_SW_SYNC_H */

View File

@ -14,14 +14,14 @@
#define _LINUX_SYNC_H
#include <linux/types.h>
#ifdef __KERNEL__
#include <linux/kref.h>
#include <linux/ktime.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
#include "uapi/sync.h"
struct sync_timeline;
struct sync_pt;
struct sync_fence;
@ -341,86 +341,4 @@ int sync_fence_cancel_async(struct sync_fence *fence,
*/
int sync_fence_wait(struct sync_fence *fence, long timeout);
#endif /* __KERNEL__ */
/**
* struct sync_merge_data - data passed to merge ioctl
* @fd2: file descriptor of second fence
* @name: name of new fence
* @fence: returns the fd of the new fence to userspace
*/
struct sync_merge_data {
__s32 fd2; /* fd of second fence */
char name[32]; /* name of new fence */
__s32 fence; /* fd on newly created fence */
};
/**
* struct sync_pt_info - detailed sync_pt information
* @len: length of sync_pt_info including any driver_data
* @obj_name: name of parent sync_timeline
* @driver_name: name of driver implmenting the parent
* @status: status of the sync_pt 0:active 1:signaled <0:error
* @timestamp_ns: timestamp of status change in nanoseconds
* @driver_data: any driver dependant data
*/
struct sync_pt_info {
__u32 len;
char obj_name[32];
char driver_name[32];
__s32 status;
__u64 timestamp_ns;
__u8 driver_data[0];
};
/**
* struct sync_fence_info_data - data returned from fence info ioctl
* @len: ioctl caller writes the size of the buffer its passing in.
* ioctl returns length of sync_fence_data reutnred to userspace
* including pt_info.
* @name: name of fence
* @status: status of fence. 1: signaled 0:active <0:error
* @pt_info: a sync_pt_info struct for every sync_pt in the fence
*/
struct sync_fence_info_data {
__u32 len;
char name[32];
__s32 status;
__u8 pt_info[0];
};
#define SYNC_IOC_MAGIC '>'
/**
* DOC: SYNC_IOC_WAIT - wait for a fence to signal
*
* pass timeout in milliseconds. Waits indefinitely timeout < 0.
*/
#define SYNC_IOC_WAIT _IOW(SYNC_IOC_MAGIC, 0, __s32)
/**
* DOC: SYNC_IOC_MERGE - merge two fences
*
* Takes a struct sync_merge_data. Creates a new fence containing copies of
* the sync_pts in both the calling fd and sync_merge_data.fd2. Returns the
* new fence's fd in sync_merge_data.fence
*/
#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 1, struct sync_merge_data)
/**
* DOC: SYNC_IOC_FENCE_INFO - get detailed information on a fence
*
* Takes a struct sync_fence_info_data with extra space allocated for pt_info.
* Caller should write the size of the buffer into len. On return, len is
* updated to reflect the total size of the sync_fence_info_data including
* pt_info.
*
* pt_info is a buffer containing sync_pt_infos for every sync_pt in the fence.
* To itterate over the sync_pt_infos, use the sync_pt_info.len field.
*/
#define SYNC_IOC_FENCE_INFO _IOWR(SYNC_IOC_MAGIC, 2,\
struct sync_fence_info_data)
#endif /* _LINUX_SYNC_H */

View File

@ -0,0 +1,62 @@
/* drivers/staging/android/uapi/android_alarm.h
*
* Copyright (C) 2006-2007 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _UAPI_LINUX_ANDROID_ALARM_H
#define _UAPI_LINUX_ANDROID_ALARM_H
#include <linux/ioctl.h>
#include <linux/time.h>
enum android_alarm_type {
/* return code bit numbers or set alarm arg */
ANDROID_ALARM_RTC_WAKEUP,
ANDROID_ALARM_RTC,
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
ANDROID_ALARM_ELAPSED_REALTIME,
ANDROID_ALARM_SYSTEMTIME,
ANDROID_ALARM_TYPE_COUNT,
/* return code bit numbers */
/* ANDROID_ALARM_TIME_CHANGE = 16 */
};
enum android_alarm_return_flags {
ANDROID_ALARM_RTC_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_WAKEUP,
ANDROID_ALARM_RTC_MASK = 1U << ANDROID_ALARM_RTC,
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK =
1U << ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
ANDROID_ALARM_ELAPSED_REALTIME_MASK =
1U << ANDROID_ALARM_ELAPSED_REALTIME,
ANDROID_ALARM_SYSTEMTIME_MASK = 1U << ANDROID_ALARM_SYSTEMTIME,
ANDROID_ALARM_TIME_CHANGE_MASK = 1U << 16
};
/* Disable alarm */
#define ANDROID_ALARM_CLEAR(type) _IO('a', 0 | ((type) << 4))
/* Ack last alarm and wait for next */
#define ANDROID_ALARM_WAIT _IO('a', 1)
#define ALARM_IOW(c, type, size) _IOW('a', (c) | ((type) << 4), size)
/* Set alarm */
#define ANDROID_ALARM_SET(type) ALARM_IOW(2, type, struct timespec)
#define ANDROID_ALARM_SET_AND_WAIT(type) ALARM_IOW(3, type, struct timespec)
#define ANDROID_ALARM_GET_TIME(type) ALARM_IOW(4, type, struct timespec)
#define ANDROID_ALARM_SET_RTC _IOW('a', 5, struct timespec)
#define ANDROID_ALARM_BASE_CMD(cmd) (cmd & ~(_IOC(0, 0, 0xf0, 0)))
#define ANDROID_ALARM_IOCTL_TO_TYPE(cmd) (_IOC_NR(cmd) >> 4)
#endif

View File

@ -0,0 +1,47 @@
/*
* drivers/staging/android/uapi/ashmem.h
*
* Copyright 2008 Google Inc.
* Author: Robert Love
*
* This file is dual licensed. It may be redistributed and/or modified
* under the terms of the Apache 2.0 License OR version 2 of the GNU
* General Public License.
*/
#ifndef _UAPI_LINUX_ASHMEM_H
#define _UAPI_LINUX_ASHMEM_H
#include <linux/ioctl.h>
#define ASHMEM_NAME_LEN 256
#define ASHMEM_NAME_DEF "dev/ashmem"
/* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */
#define ASHMEM_NOT_PURGED 0
#define ASHMEM_WAS_PURGED 1
/* Return values from ASHMEM_GET_PIN_STATUS: Is the mapping pinned? */
#define ASHMEM_IS_UNPINNED 0
#define ASHMEM_IS_PINNED 1
struct ashmem_pin {
__u32 offset; /* offset into region, in bytes, page-aligned */
__u32 len; /* length forward from offset, in bytes, page-aligned */
};
#define __ASHMEMIOC 0x77
#define ASHMEM_SET_NAME _IOW(__ASHMEMIOC, 1, char[ASHMEM_NAME_LEN])
#define ASHMEM_GET_NAME _IOR(__ASHMEMIOC, 2, char[ASHMEM_NAME_LEN])
#define ASHMEM_SET_SIZE _IOW(__ASHMEMIOC, 3, size_t)
#define ASHMEM_GET_SIZE _IO(__ASHMEMIOC, 4)
#define ASHMEM_SET_PROT_MASK _IOW(__ASHMEMIOC, 5, unsigned long)
#define ASHMEM_GET_PROT_MASK _IO(__ASHMEMIOC, 6)
#define ASHMEM_PIN _IOW(__ASHMEMIOC, 7, struct ashmem_pin)
#define ASHMEM_UNPIN _IOW(__ASHMEMIOC, 8, struct ashmem_pin)
#define ASHMEM_GET_PIN_STATUS _IO(__ASHMEMIOC, 9)
#define ASHMEM_PURGE_ALL_CACHES _IO(__ASHMEMIOC, 10)
#endif /* _UAPI_LINUX_ASHMEM_H */

View File

@ -0,0 +1,330 @@
/*
* Copyright (C) 2008 Google, Inc.
*
* Based on, but no longer compatible with, the original
* OpenBinder.org binder driver interface, which is:
*
* Copyright (c) 2005 Palmsource, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _UAPI_LINUX_BINDER_H
#define _UAPI_LINUX_BINDER_H
#include <linux/ioctl.h>
#define B_PACK_CHARS(c1, c2, c3, c4) \
((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4))
#define B_TYPE_LARGE 0x85
enum {
BINDER_TYPE_BINDER = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE),
BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE),
BINDER_TYPE_HANDLE = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE),
BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE),
BINDER_TYPE_FD = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE),
};
enum {
FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff,
FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100,
};
/*
* This is the flattened representation of a Binder object for transfer
* between processes. The 'offsets' supplied as part of a binder transaction
* contains offsets into the data where these structures occur. The Binder
* driver takes care of re-writing the structure type and data as it moves
* between processes.
*/
struct flat_binder_object {
/* 8 bytes for large_flat_header. */
unsigned long type;
unsigned long flags;
/* 8 bytes of data. */
union {
void __user *binder; /* local object */
signed long handle; /* remote object */
};
/* extra data associated with local object */
void __user *cookie;
};
/*
* On 64-bit platforms where user code may run in 32-bits the driver must
* translate the buffer (and local binder) addresses appropriately.
*/
struct binder_write_read {
signed long write_size; /* bytes to write */
signed long write_consumed; /* bytes consumed by driver */
unsigned long write_buffer;
signed long read_size; /* bytes to read */
signed long read_consumed; /* bytes consumed by driver */
unsigned long read_buffer;
};
/* Use with BINDER_VERSION, driver fills in fields. */
struct binder_version {
/* driver protocol version -- increment with incompatible change */
signed long protocol_version;
};
/* This is the current protocol version. */
#define BINDER_CURRENT_PROTOCOL_VERSION 7
#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)
#define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64)
#define BINDER_SET_MAX_THREADS _IOW('b', 5, size_t)
#define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, __s32)
#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32)
#define BINDER_THREAD_EXIT _IOW('b', 8, __s32)
#define BINDER_VERSION _IOWR('b', 9, struct binder_version)
/*
* NOTE: Two special error codes you should check for when calling
* in to the driver are:
*
* EINTR -- The operation has been interupted. This should be
* handled by retrying the ioctl() until a different error code
* is returned.
*
* ECONNREFUSED -- The driver is no longer accepting operations
* from your process. That is, the process is being destroyed.
* You should handle this by exiting from your process. Note
* that once this error code is returned, all further calls to
* the driver from any thread will return this same code.
*/
enum transaction_flags {
TF_ONE_WAY = 0x01, /* this is a one-way call: async, no return */
TF_ROOT_OBJECT = 0x04, /* contents are the component's root object */
TF_STATUS_CODE = 0x08, /* contents are a 32-bit status code */
TF_ACCEPT_FDS = 0x10, /* allow replies with file descriptors */
};
struct binder_transaction_data {
/* The first two are only used for bcTRANSACTION and brTRANSACTION,
* identifying the target and contents of the transaction.
*/
union {
size_t handle; /* target descriptor of command transaction */
void *ptr; /* target descriptor of return transaction */
} target;
void *cookie; /* target object cookie */
unsigned int code; /* transaction command */
/* General information about the transaction. */
unsigned int flags;
pid_t sender_pid;
uid_t sender_euid;
size_t data_size; /* number of bytes of data */
size_t offsets_size; /* number of bytes of offsets */
/* If this transaction is inline, the data immediately
* follows here; otherwise, it ends with a pointer to
* the data buffer.
*/
union {
struct {
/* transaction data */
const void __user *buffer;
/* offsets from buffer to flat_binder_object structs */
const void __user *offsets;
} ptr;
uint8_t buf[8];
} data;
};
struct binder_ptr_cookie {
void *ptr;
void *cookie;
};
struct binder_pri_desc {
int priority;
int desc;
};
struct binder_pri_ptr_cookie {
int priority;
void *ptr;
void *cookie;
};
enum binder_driver_return_protocol {
BR_ERROR = _IOR('r', 0, int),
/*
* int: error code
*/
BR_OK = _IO('r', 1),
/* No parameters! */
BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data),
BR_REPLY = _IOR('r', 3, struct binder_transaction_data),
/*
* binder_transaction_data: the received command.
*/
BR_ACQUIRE_RESULT = _IOR('r', 4, int),
/*
* not currently supported
* int: 0 if the last bcATTEMPT_ACQUIRE was not successful.
* Else the remote object has acquired a primary reference.
*/
BR_DEAD_REPLY = _IO('r', 5),
/*
* The target of the last transaction (either a bcTRANSACTION or
* a bcATTEMPT_ACQUIRE) is no longer with us. No parameters.
*/
BR_TRANSACTION_COMPLETE = _IO('r', 6),
/*
* No parameters... always refers to the last transaction requested
* (including replies). Note that this will be sent even for
* asynchronous transactions.
*/
BR_INCREFS = _IOR('r', 7, struct binder_ptr_cookie),
BR_ACQUIRE = _IOR('r', 8, struct binder_ptr_cookie),
BR_RELEASE = _IOR('r', 9, struct binder_ptr_cookie),
BR_DECREFS = _IOR('r', 10, struct binder_ptr_cookie),
/*
* void *: ptr to binder
* void *: cookie for binder
*/
BR_ATTEMPT_ACQUIRE = _IOR('r', 11, struct binder_pri_ptr_cookie),
/*
* not currently supported
* int: priority
* void *: ptr to binder
* void *: cookie for binder
*/
BR_NOOP = _IO('r', 12),
/*
* No parameters. Do nothing and examine the next command. It exists
* primarily so that we can replace it with a BR_SPAWN_LOOPER command.
*/
BR_SPAWN_LOOPER = _IO('r', 13),
/*
* No parameters. The driver has determined that a process has no
* threads waiting to service incoming transactions. When a process
* receives this command, it must spawn a new service thread and
* register it via bcENTER_LOOPER.
*/
BR_FINISHED = _IO('r', 14),
/*
* not currently supported
* stop threadpool thread
*/
BR_DEAD_BINDER = _IOR('r', 15, void *),
/*
* void *: cookie
*/
BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR('r', 16, void *),
/*
* void *: cookie
*/
BR_FAILED_REPLY = _IO('r', 17),
/*
* The the last transaction (either a bcTRANSACTION or
* a bcATTEMPT_ACQUIRE) failed (e.g. out of memory). No parameters.
*/
};
enum binder_driver_command_protocol {
BC_TRANSACTION = _IOW('c', 0, struct binder_transaction_data),
BC_REPLY = _IOW('c', 1, struct binder_transaction_data),
/*
* binder_transaction_data: the sent command.
*/
BC_ACQUIRE_RESULT = _IOW('c', 2, int),
/*
* not currently supported
* int: 0 if the last BR_ATTEMPT_ACQUIRE was not successful.
* Else you have acquired a primary reference on the object.
*/
BC_FREE_BUFFER = _IOW('c', 3, int),
/*
* void *: ptr to transaction data received on a read
*/
BC_INCREFS = _IOW('c', 4, int),
BC_ACQUIRE = _IOW('c', 5, int),
BC_RELEASE = _IOW('c', 6, int),
BC_DECREFS = _IOW('c', 7, int),
/*
* int: descriptor
*/
BC_INCREFS_DONE = _IOW('c', 8, struct binder_ptr_cookie),
BC_ACQUIRE_DONE = _IOW('c', 9, struct binder_ptr_cookie),
/*
* void *: ptr to binder
* void *: cookie for binder
*/
BC_ATTEMPT_ACQUIRE = _IOW('c', 10, struct binder_pri_desc),
/*
* not currently supported
* int: priority
* int: descriptor
*/
BC_REGISTER_LOOPER = _IO('c', 11),
/*
* No parameters.
* Register a spawned looper thread with the device.
*/
BC_ENTER_LOOPER = _IO('c', 12),
BC_EXIT_LOOPER = _IO('c', 13),
/*
* No parameters.
* These two commands are sent as an application-level thread
* enters and exits the binder loop, respectively. They are
* used so the binder can have an accurate count of the number
* of looping threads it has available.
*/
BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14, struct binder_ptr_cookie),
/*
* void *: ptr to binder
* void *: cookie
*/
BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15, struct binder_ptr_cookie),
/*
* void *: ptr to binder
* void *: cookie
*/
BC_DEAD_BINDER_DONE = _IOW('c', 16, void *),
/*
* void *: cookie
*/
};
#endif /* _UAPI_LINUX_BINDER_H */

View File

@ -0,0 +1,196 @@
/*
* drivers/staging/android/uapi/ion.h
*
* Copyright (C) 2011 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _UAPI_LINUX_ION_H
#define _UAPI_LINUX_ION_H
#include <linux/ioctl.h>
#include <linux/types.h>
typedef int ion_user_handle_t;
/**
* enum ion_heap_types - list of all possible types of heaps
* @ION_HEAP_TYPE_SYSTEM: memory allocated via vmalloc
* @ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kmalloc
* @ION_HEAP_TYPE_CARVEOUT: memory allocated from a prereserved
* carveout heap, allocations are physically
* contiguous
* @ION_HEAP_TYPE_DMA: memory allocated via DMA API
* @ION_NUM_HEAPS: helper for iterating over heaps, a bit mask
* is used to identify the heaps, so only 32
* total heap types are supported
*/
enum ion_heap_type {
ION_HEAP_TYPE_SYSTEM,
ION_HEAP_TYPE_SYSTEM_CONTIG,
ION_HEAP_TYPE_CARVEOUT,
ION_HEAP_TYPE_CHUNK,
ION_HEAP_TYPE_DMA,
ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always
are at the end of this enum */
ION_NUM_HEAPS = 16,
};
#define ION_HEAP_SYSTEM_MASK (1 << ION_HEAP_TYPE_SYSTEM)
#define ION_HEAP_SYSTEM_CONTIG_MASK (1 << ION_HEAP_TYPE_SYSTEM_CONTIG)
#define ION_HEAP_CARVEOUT_MASK (1 << ION_HEAP_TYPE_CARVEOUT)
#define ION_HEAP_TYPE_DMA_MASK (1 << ION_HEAP_TYPE_DMA)
#define ION_NUM_HEAP_IDS sizeof(unsigned int) * 8
/**
* allocation flags - the lower 16 bits are used by core ion, the upper 16
* bits are reserved for use by the heaps themselves.
*/
#define ION_FLAG_CACHED 1 /* mappings of this buffer should be
cached, ion will do cache
maintenance when the buffer is
mapped for dma */
#define ION_FLAG_CACHED_NEEDS_SYNC 2 /* mappings of this buffer will created
at mmap time, if this is set
caches must be managed manually */
/**
* DOC: Ion Userspace API
*
* create a client by opening /dev/ion
* most operations handled via following ioctls
*
*/
/**
* struct ion_allocation_data - metadata passed from userspace for allocations
* @len: size of the allocation
* @align: required alignment of the allocation
* @heap_id_mask: mask of heap ids to allocate from
* @flags: flags passed to heap
* @handle: pointer that will be populated with a cookie to use to
* refer to this allocation
*
* Provided by userspace as an argument to the ioctl
*/
struct ion_allocation_data {
size_t len;
size_t align;
unsigned int heap_id_mask;
unsigned int flags;
ion_user_handle_t handle;
};
/**
* struct ion_fd_data - metadata passed to/from userspace for a handle/fd pair
* @handle: a handle
* @fd: a file descriptor representing that handle
*
* For ION_IOC_SHARE or ION_IOC_MAP userspace populates the handle field with
* the handle returned from ion alloc, and the kernel returns the file
* descriptor to share or map in the fd field. For ION_IOC_IMPORT, userspace
* provides the file descriptor and the kernel returns the handle.
*/
struct ion_fd_data {
ion_user_handle_t handle;
int fd;
};
/**
* struct ion_handle_data - a handle passed to/from the kernel
* @handle: a handle
*/
struct ion_handle_data {
ion_user_handle_t handle;
};
/**
* struct ion_custom_data - metadata passed to/from userspace for a custom ioctl
* @cmd: the custom ioctl function to call
* @arg: additional data to pass to the custom ioctl, typically a user
* pointer to a predefined structure
*
* This works just like the regular cmd and arg fields of an ioctl.
*/
struct ion_custom_data {
unsigned int cmd;
unsigned long arg;
};
#define ION_IOC_MAGIC 'I'
/**
* DOC: ION_IOC_ALLOC - allocate memory
*
* Takes an ion_allocation_data struct and returns it with the handle field
* populated with the opaque handle for the allocation.
*/
#define ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, \
struct ion_allocation_data)
/**
* DOC: ION_IOC_FREE - free memory
*
* Takes an ion_handle_data struct and frees the handle.
*/
#define ION_IOC_FREE _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data)
/**
* DOC: ION_IOC_MAP - get a file descriptor to mmap
*
* Takes an ion_fd_data struct with the handle field populated with a valid
* opaque handle. Returns the struct with the fd field set to a file
* descriptor open in the current address space. This file descriptor
* can then be used as an argument to mmap.
*/
#define ION_IOC_MAP _IOWR(ION_IOC_MAGIC, 2, struct ion_fd_data)
/**
* DOC: ION_IOC_SHARE - creates a file descriptor to use to share an allocation
*
* Takes an ion_fd_data struct with the handle field populated with a valid
* opaque handle. Returns the struct with the fd field set to a file
* descriptor open in the current address space. This file descriptor
* can then be passed to another process. The corresponding opaque handle can
* be retrieved via ION_IOC_IMPORT.
*/
#define ION_IOC_SHARE _IOWR(ION_IOC_MAGIC, 4, struct ion_fd_data)
/**
* DOC: ION_IOC_IMPORT - imports a shared file descriptor
*
* Takes an ion_fd_data struct with the fd field populated with a valid file
* descriptor obtained from ION_IOC_SHARE and returns the struct with the handle
* filed set to the corresponding opaque handle.
*/
#define ION_IOC_IMPORT _IOWR(ION_IOC_MAGIC, 5, struct ion_fd_data)
/**
* DOC: ION_IOC_SYNC - syncs a shared file descriptors to memory
*
* Deprecated in favor of using the dma_buf api's correctly (syncing
* will happend automatically when the buffer is mapped to a device).
* If necessary should be used after touching a cached buffer from the cpu,
* this will make the buffer in memory coherent.
*/
#define ION_IOC_SYNC _IOWR(ION_IOC_MAGIC, 7, struct ion_fd_data)
/**
* DOC: ION_IOC_CUSTOM - call architecture specific ion ioctl
*
* Takes the argument of the architecture specific ioctl to call and
* passes appropriate userdata for that ioctl
*/
#define ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data)
#endif /* _UAPI_LINUX_ION_H */

View File

@ -0,0 +1,71 @@
/*
* drivers/staging/android/uapi/ion.h
*
* Copyright (C) 2011 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _UAPI_LINUX_ION_TEST_H
#define _UAPI_LINUX_ION_TEST_H
#include <linux/ioctl.h>
#include <linux/types.h>
typedef int ion_user_handle_t;
/**
* struct ion_test_rw_data - metadata passed to the kernel to read handle
* @ptr: a pointer to an area at least as large as size
* @offset: offset into the ion buffer to start reading
* @size: size to read or write
* @write: 1 to write, 0 to read
*/
struct ion_test_rw_data {
__u64 ptr;
__u64 offset;
__u64 size;
int write;
};
#define ION_IOC_MAGIC 'I'
/**
* DOC: ION_IOC_TEST_SET_DMA_BUF - attach a dma buf to the test driver
*
* Attaches a dma buf fd to the test driver. Passing a second fd or -1 will
* release the first fd.
*/
#define ION_IOC_TEST_SET_FD \
_IO(ION_IOC_MAGIC, 0xf0)
/**
* DOC: ION_IOC_TEST_DMA_MAPPING - read or write memory from a handle as DMA
*
* Reads or writes the memory from a handle using an uncached mapping. Can be
* used by unit tests to emulate a DMA engine as close as possible. Only
* expected to be used for debugging and testing, may not always be available.
*/
#define ION_IOC_TEST_DMA_MAPPING \
_IOW(ION_IOC_MAGIC, 0xf1, struct ion_test_rw_data)
/**
* DOC: ION_IOC_TEST_KERNEL_MAPPING - read or write memory from a handle
*
* Reads or writes the memory from a handle using a kernel mapping. Can be
* used by unit tests to test heap map_kernel functions. Only expected to be
* used for debugging and testing, may not always be available.
*/
#define ION_IOC_TEST_KERNEL_MAPPING \
_IOW(ION_IOC_MAGIC, 0xf2, struct ion_test_rw_data)
#endif /* _UAPI_LINUX_ION_H */

View File

@ -0,0 +1,32 @@
/*
* Copyright (C) 2012 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _UAPI_LINUX_SW_SYNC_H
#define _UAPI_LINUX_SW_SYNC_H
#include <linux/types.h>
struct sw_sync_create_fence_data {
__u32 value;
char name[32];
__s32 fence; /* fd of new fence */
};
#define SW_SYNC_IOC_MAGIC 'W'
#define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0,\
struct sw_sync_create_fence_data)
#define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32)
#endif /* _UAPI_LINUX_SW_SYNC_H */

View File

@ -0,0 +1,97 @@
/*
* Copyright (C) 2012 Google, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _UAPI_LINUX_SYNC_H
#define _UAPI_LINUX_SYNC_H
#include <linux/ioctl.h>
#include <linux/types.h>
/**
* struct sync_merge_data - data passed to merge ioctl
* @fd2: file descriptor of second fence
* @name: name of new fence
* @fence: returns the fd of the new fence to userspace
*/
struct sync_merge_data {
__s32 fd2; /* fd of second fence */
char name[32]; /* name of new fence */
__s32 fence; /* fd on newly created fence */
};
/**
* struct sync_pt_info - detailed sync_pt information
* @len: length of sync_pt_info including any driver_data
* @obj_name: name of parent sync_timeline
* @driver_name: name of driver implmenting the parent
* @status: status of the sync_pt 0:active 1:signaled <0:error
* @timestamp_ns: timestamp of status change in nanoseconds
* @driver_data: any driver dependant data
*/
struct sync_pt_info {
__u32 len;
char obj_name[32];
char driver_name[32];
__s32 status;
__u64 timestamp_ns;
__u8 driver_data[0];
};
/**
* struct sync_fence_info_data - data returned from fence info ioctl
* @len: ioctl caller writes the size of the buffer its passing in.
* ioctl returns length of sync_fence_data reutnred to userspace
* including pt_info.
* @name: name of fence
* @status: status of fence. 1: signaled 0:active <0:error
* @pt_info: a sync_pt_info struct for every sync_pt in the fence
*/
struct sync_fence_info_data {
__u32 len;
char name[32];
__s32 status;
__u8 pt_info[0];
};
#define SYNC_IOC_MAGIC '>'
/**
* DOC: SYNC_IOC_WAIT - wait for a fence to signal
*
* pass timeout in milliseconds. Waits indefinitely timeout < 0.
*/
#define SYNC_IOC_WAIT _IOW(SYNC_IOC_MAGIC, 0, __s32)
/**
* DOC: SYNC_IOC_MERGE - merge two fences
*
* Takes a struct sync_merge_data. Creates a new fence containing copies of
* the sync_pts in both the calling fd and sync_merge_data.fd2. Returns the
* new fence's fd in sync_merge_data.fence
*/
#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 1, struct sync_merge_data)
/**
* DOC: SYNC_IOC_FENCE_INFO - get detailed information on a fence
*
* Takes a struct sync_fence_info_data with extra space allocated for pt_info.
* Caller should write the size of the buffer into len. On return, len is
* updated to reflect the total size of the sync_fence_info_data including
* pt_info.
*
* pt_info is a buffer containing sync_pt_infos for every sync_pt in the fence.
* To itterate over the sync_pt_infos, use the sync_pt_info.len field.
*/
#define SYNC_IOC_FENCE_INFO _IOWR(SYNC_IOC_MAGIC, 2,\
struct sync_fence_info_data)
#endif /* _UAPI_LINUX_SYNC_H */

View File

@ -269,6 +269,17 @@ struct mtp_device_status {
__le16 wCode;
};
struct mtp_data_header {
/* length of packet, including this header */
__le32 length;
/* container type (2 for data packet) */
__le16 type;
/* MTP command code */
__le16 command;
/* MTP transaction ID */
__le32 transaction_id;
};
/* temporary variable used between mtp_open() and mtp_gadget_bind() */
static struct mtp_dev *_mtp_dev;

View File

@ -23,8 +23,6 @@ source "drivers/gpu/drm/Kconfig"
source "drivers/gpu/host1x/Kconfig"
source "drivers/gpu/ion/Kconfig"
config VGASTATE
tristate
default n

View File

@ -37,6 +37,8 @@
#define ADF_SHORT_FENCE_TIMEOUT (1 * MSEC_PER_SEC)
#define ADF_LONG_FENCE_TIMEOUT (10 * MSEC_PER_SEC)
static DEFINE_IDR(adf_devices);
static void adf_fence_wait(struct adf_device *dev, struct sync_fence *fence)
{
/* sync_fence_wait() dumps debug information on timeout. Experience
@ -455,23 +457,20 @@ static int adf_obj_init(struct adf_obj *obj, enum adf_obj_type type,
struct idr *idr, struct adf_device *parent,
const struct adf_obj_ops *ops, const char *fmt, va_list args)
{
int ret;
if (ops && ops->supports_event && !ops->set_event) {
pr_err("%s: %s implements supports_event but not set_event\n",
__func__, adf_obj_type_str(type));
return -EINVAL;
}
if (idr) {
int ret = idr_alloc(idr, obj, 0, 0, GFP_KERNEL);
if (ret < 0) {
pr_err("%s: allocating object id failed: %d\n",
__func__, ret);
return ret;
}
obj->id = ret;
} else {
obj->id = -1;
ret = idr_alloc(idr, obj, 0, 0, GFP_KERNEL);
if (ret < 0) {
pr_err("%s: allocating object id failed: %d\n", __func__, ret);
return ret;
}
obj->id = ret;
vscnprintf(obj->name, sizeof(obj->name), fmt, args);
@ -498,8 +497,7 @@ static void adf_obj_destroy(struct adf_obj *obj, struct idr *idr)
}
mutex_destroy(&obj->event_lock);
if (idr)
idr_remove(idr, obj->id);
idr_remove(idr, obj->id);
}
/**
@ -543,8 +541,8 @@ int adf_device_init(struct adf_device *dev, struct device *parent,
memset(dev, 0, sizeof(*dev));
va_start(args, fmt);
ret = adf_obj_init(&dev->base, ADF_OBJ_DEVICE, NULL, dev, &ops->base,
fmt, args);
ret = adf_obj_init(&dev->base, ADF_OBJ_DEVICE, &adf_devices, dev,
&ops->base, fmt, args);
va_end(args);
if (ret < 0)
return ret;
@ -612,7 +610,7 @@ void adf_device_destroy(struct adf_device *dev)
}
mutex_destroy(&dev->post_lock);
mutex_destroy(&dev->client_lock);
adf_obj_destroy(&dev->base, NULL);
adf_obj_destroy(&dev->base, &adf_devices);
}
EXPORT_SYMBOL(adf_device_destroy);

View File

@ -49,6 +49,9 @@ int adf_interface_blank(struct adf_interface *intf, u8 state)
if (!intf->ops || !intf->ops->blank)
return -EOPNOTSUPP;
if (state > DRM_MODE_DPMS_OFF)
return -EINVAL;
mutex_lock(&dev->client_lock);
if (state != DRM_MODE_DPMS_ON)
flush_kthread_worker(&dev->post_worker);

View File

@ -519,10 +519,10 @@ int adf_fbdev_blank(int blank, struct fb_info *info)
dpms_state = DRM_MODE_DPMS_STANDBY;
break;
case FB_BLANK_VSYNC_SUSPEND:
dpms_state = DRM_MODE_DPMS_STANDBY;
dpms_state = DRM_MODE_DPMS_SUSPEND;
break;
case FB_BLANK_HSYNC_SUSPEND:
dpms_state = DRM_MODE_DPMS_SUSPEND;
dpms_state = DRM_MODE_DPMS_STANDBY;
break;
case FB_BLANK_POWERDOWN:
dpms_state = DRM_MODE_DPMS_OFF;

View File

@ -105,11 +105,6 @@ static struct device_attribute adf_interface_attrs[] = {
__ATTR_RO(vsync_timestamp),
};
static char *adf_devnode(struct device *dev, umode_t *mode)
{
return kasprintf(GFP_KERNEL, "adf/%s", dev_name(dev));
}
int adf_obj_sysfs_init(struct adf_obj *obj, struct device *parent)
{
int ret = idr_alloc(&adf_minors, obj, 0, 0, GFP_KERNEL);
@ -142,7 +137,7 @@ static char *adf_device_devnode(struct device *dev, umode_t *mode,
kuid_t *uid, kgid_t *gid)
{
struct adf_obj *obj = container_of(dev, struct adf_obj, dev);
return kasprintf(GFP_KERNEL, "adf/%s/device", obj->name);
return kasprintf(GFP_KERNEL, "adf%d", obj->id);
}
static char *adf_interface_devnode(struct device *dev, umode_t *mode,
@ -151,8 +146,8 @@ static char *adf_interface_devnode(struct device *dev, umode_t *mode,
struct adf_obj *obj = container_of(dev, struct adf_obj, dev);
struct adf_interface *intf = adf_obj_to_interface(obj);
struct adf_device *parent = adf_interface_parent(intf);
return kasprintf(GFP_KERNEL, "adf/%s/interface%d",
parent->base.name, intf->base.id);
return kasprintf(GFP_KERNEL, "adf-interface%d.%d",
parent->base.id, intf->base.id);
}
static char *adf_overlay_engine_devnode(struct device *dev, umode_t *mode,
@ -161,8 +156,8 @@ static char *adf_overlay_engine_devnode(struct device *dev, umode_t *mode,
struct adf_obj *obj = container_of(dev, struct adf_obj, dev);
struct adf_overlay_engine *eng = adf_obj_to_overlay_engine(obj);
struct adf_device *parent = adf_overlay_engine_parent(eng);
return kasprintf(GFP_KERNEL, "adf/%s/overlay-engine%d",
parent->base.name, eng->base.id);
return kasprintf(GFP_KERNEL, "adf-overlay-engine%d.%d",
parent->base.id, eng->base.id);
}
static void adf_noop_release(struct device *dev)
@ -285,7 +280,6 @@ int adf_sysfs_init(void)
goto err_chrdev;
}
class->devnode = adf_devnode;
adf_class = class;
adf_major = ret;
return 0;

View File

@ -18,16 +18,6 @@
#ifndef __LINUX_IF_PPPOLAC_H
#define __LINUX_IF_PPPOLAC_H
#include <linux/socket.h>
#include <linux/types.h>
struct sockaddr_pppolac {
sa_family_t sa_family; /* AF_PPPOX */
unsigned int sa_protocol; /* PX_PROTO_OLAC */
int udp_socket;
struct __attribute__((packed)) {
__u16 tunnel, session;
} local, remote;
} __attribute__((packed));
#include <uapi/linux/if_pppolac.h>
#endif /* __LINUX_IF_PPPOLAC_H */

View File

@ -18,15 +18,6 @@
#ifndef __LINUX_IF_PPPOPNS_H
#define __LINUX_IF_PPPOPNS_H
#include <linux/socket.h>
#include <linux/types.h>
struct sockaddr_pppopns {
sa_family_t sa_family; /* AF_PPPOX */
unsigned int sa_protocol; /* PX_PROTO_OPNS */
int tcp_socket;
__u16 local;
__u16 remote;
} __attribute__((packed));
#include <uapi/linux/if_pppopns.h>
#endif /* __LINUX_IF_PPPOPNS_H */

View File

@ -18,35 +18,6 @@
#ifndef __LINUX_KEYCHORD_H_
#define __LINUX_KEYCHORD_H_
#include <linux/input.h>
#define KEYCHORD_VERSION 1
/*
* One or more input_keychord structs are written to /dev/keychord
* at once to specify the list of keychords to monitor.
* Reading /dev/keychord returns the id of a keychord when the
* keychord combination is pressed. A keychord is signalled when
* all of the keys in the keycode list are in the pressed state.
* The order in which the keys are pressed does not matter.
* The keychord will not be signalled if keys not in the keycode
* list are pressed.
* Keychords will not be signalled on key release events.
*/
struct input_keychord {
/* should be KEYCHORD_VERSION */
__u16 version;
/*
* client specified ID, returned from read()
* when this keychord is pressed.
*/
__u16 id;
/* number of keycodes in this keychord */
__u16 count;
/* variable length array of keycodes */
__u16 keycodes[];
};
#include <uapi/linux/keychord.h>
#endif /* __LINUX_KEYCHORD_H_ */

View File

@ -18,129 +18,6 @@
#ifndef __LINUX_USB_F_ACCESSORY_H
#define __LINUX_USB_F_ACCESSORY_H
/* Use Google Vendor ID when in accessory mode */
#define USB_ACCESSORY_VENDOR_ID 0x18D1
/* Product ID to use when in accessory mode */
#define USB_ACCESSORY_PRODUCT_ID 0x2D00
/* Product ID to use when in accessory mode and adb is enabled */
#define USB_ACCESSORY_ADB_PRODUCT_ID 0x2D01
/* Indexes for strings sent by the host via ACCESSORY_SEND_STRING */
#define ACCESSORY_STRING_MANUFACTURER 0
#define ACCESSORY_STRING_MODEL 1
#define ACCESSORY_STRING_DESCRIPTION 2
#define ACCESSORY_STRING_VERSION 3
#define ACCESSORY_STRING_URI 4
#define ACCESSORY_STRING_SERIAL 5
/* Control request for retrieving device's protocol version
*
* requestType: USB_DIR_IN | USB_TYPE_VENDOR
* request: ACCESSORY_GET_PROTOCOL
* value: 0
* index: 0
* data version number (16 bits little endian)
* 1 for original accessory support
* 2 adds HID and device to host audio support
*/
#define ACCESSORY_GET_PROTOCOL 51
/* Control request for host to send a string to the device
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_SEND_STRING
* value: 0
* index: string ID
* data zero terminated UTF8 string
*
* The device can later retrieve these strings via the
* ACCESSORY_GET_STRING_* ioctls
*/
#define ACCESSORY_SEND_STRING 52
/* Control request for starting device in accessory mode.
* The host sends this after setting all its strings to the device.
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_START
* value: 0
* index: 0
* data none
*/
#define ACCESSORY_START 53
/* Control request for registering a HID device.
* Upon registering, a unique ID is sent by the accessory in the
* value parameter. This ID will be used for future commands for
* the device
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_REGISTER_HID_DEVICE
* value: Accessory assigned ID for the HID device
* index: total length of the HID report descriptor
* data none
*/
#define ACCESSORY_REGISTER_HID 54
/* Control request for unregistering a HID device.
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_REGISTER_HID
* value: Accessory assigned ID for the HID device
* index: 0
* data none
*/
#define ACCESSORY_UNREGISTER_HID 55
/* Control request for sending the HID report descriptor.
* If the HID descriptor is longer than the endpoint zero max packet size,
* the descriptor will be sent in multiple ACCESSORY_SET_HID_REPORT_DESC
* commands. The data for the descriptor must be sent sequentially
* if multiple packets are needed.
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_SET_HID_REPORT_DESC
* value: Accessory assigned ID for the HID device
* index: offset of data in descriptor
* (needed when HID descriptor is too big for one packet)
* data the HID report descriptor
*/
#define ACCESSORY_SET_HID_REPORT_DESC 56
/* Control request for sending HID events.
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_SEND_HID_EVENT
* value: Accessory assigned ID for the HID device
* index: 0
* data the HID report for the event
*/
#define ACCESSORY_SEND_HID_EVENT 57
/* Control request for setting the audio mode.
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_SET_AUDIO_MODE
* value: 0 - no audio
* 1 - device to host, 44100 16-bit stereo PCM
* index: 0
* data none
*/
#define ACCESSORY_SET_AUDIO_MODE 58
/* ioctls for retrieving strings set by the host */
#define ACCESSORY_GET_STRING_MANUFACTURER _IOW('M', 1, char[256])
#define ACCESSORY_GET_STRING_MODEL _IOW('M', 2, char[256])
#define ACCESSORY_GET_STRING_DESCRIPTION _IOW('M', 3, char[256])
#define ACCESSORY_GET_STRING_VERSION _IOW('M', 4, char[256])
#define ACCESSORY_GET_STRING_URI _IOW('M', 5, char[256])
#define ACCESSORY_GET_STRING_SERIAL _IOW('M', 6, char[256])
/* returns 1 if there is a start request pending */
#define ACCESSORY_IS_START_REQUESTED _IO('M', 7)
/* returns audio mode (set via the ACCESSORY_SET_AUDIO_MODE control request) */
#define ACCESSORY_GET_AUDIO_MODE _IO('M', 8)
#include <uapi/linux/usb/f_accessory.h>
#endif /* __LINUX_USB_F_ACCESSORY_H */

View File

@ -18,58 +18,6 @@
#ifndef __LINUX_USB_F_MTP_H
#define __LINUX_USB_F_MTP_H
#include <linux/ioctl.h>
#ifdef __KERNEL__
struct mtp_data_header {
/* length of packet, including this header */
uint32_t length;
/* container type (2 for data packet) */
uint16_t type;
/* MTP command code */
uint16_t command;
/* MTP transaction ID */
uint32_t transaction_id;
};
#endif /* __KERNEL__ */
struct mtp_file_range {
/* file descriptor for file to transfer */
int fd;
/* offset in file for start of transfer */
loff_t offset;
/* number of bytes to transfer */
int64_t length;
/* MTP command ID for data header,
* used only for MTP_SEND_FILE_WITH_HEADER
*/
uint16_t command;
/* MTP transaction ID for data header,
* used only for MTP_SEND_FILE_WITH_HEADER
*/
uint32_t transaction_id;
};
struct mtp_event {
/* size of the event */
size_t length;
/* event data to send */
void *data;
};
/* Sends the specified file range to the host */
#define MTP_SEND_FILE _IOW('M', 0, struct mtp_file_range)
/* Receives data from the host and writes it to a file.
* The file is created if it does not exist.
*/
#define MTP_RECEIVE_FILE _IOW('M', 1, struct mtp_file_range)
/* Sends an event to the host via the interrupt endpoint */
#define MTP_SEND_EVENT _IOW('M', 3, struct mtp_event)
/* Sends the specified file range to the host,
* with a 12 byte MTP data packet header at the beginning.
*/
#define MTP_SEND_FILE_WITH_HEADER _IOW('M', 4, struct mtp_file_range)
#include <uapi/linux/usb/f_mtp.h>
#endif /* __LINUX_USB_F_MTP_H */

View File

@ -0,0 +1,33 @@
/* include/uapi/linux/if_pppolac.h
*
* Header for PPP on L2TP Access Concentrator / PPPoLAC Socket (RFC 2661)
*
* Copyright (C) 2009 Google, Inc.
* Author: Chia-chi Yeh <chiachi@android.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _UAPI_LINUX_IF_PPPOLAC_H
#define _UAPI_LINUX_IF_PPPOLAC_H
#include <linux/socket.h>
#include <linux/types.h>
struct sockaddr_pppolac {
sa_family_t sa_family; /* AF_PPPOX */
unsigned int sa_protocol; /* PX_PROTO_OLAC */
int udp_socket;
struct __attribute__((packed)) {
__u16 tunnel, session;
} local, remote;
} __attribute__((packed));
#endif /* _UAPI_LINUX_IF_PPPOLAC_H */

View File

@ -0,0 +1,32 @@
/* include/uapi/linux/if_pppopns.h
*
* Header for PPP on PPTP Network Server / PPPoPNS Socket (RFC 2637)
*
* Copyright (C) 2009 Google, Inc.
* Author: Chia-chi Yeh <chiachi@android.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _UAPI_LINUX_IF_PPPOPNS_H
#define _UAPI_LINUX_IF_PPPOPNS_H
#include <linux/socket.h>
#include <linux/types.h>
struct sockaddr_pppopns {
sa_family_t sa_family; /* AF_PPPOX */
unsigned int sa_protocol; /* PX_PROTO_OPNS */
int tcp_socket;
__u16 local;
__u16 remote;
} __attribute__((packed));
#endif /* _UAPI_LINUX_IF_PPPOPNS_H */

View File

@ -0,0 +1,52 @@
/*
* Key chord input driver
*
* Copyright (C) 2008 Google, Inc.
* Author: Mike Lockwood <lockwood@android.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _UAPI_LINUX_KEYCHORD_H_
#define _UAPI_LINUX_KEYCHORD_H_
#include <linux/input.h>
#define KEYCHORD_VERSION 1
/*
* One or more input_keychord structs are written to /dev/keychord
* at once to specify the list of keychords to monitor.
* Reading /dev/keychord returns the id of a keychord when the
* keychord combination is pressed. A keychord is signalled when
* all of the keys in the keycode list are in the pressed state.
* The order in which the keys are pressed does not matter.
* The keychord will not be signalled if keys not in the keycode
* list are pressed.
* Keychords will not be signalled on key release events.
*/
struct input_keychord {
/* should be KEYCHORD_VERSION */
__u16 version;
/*
* client specified ID, returned from read()
* when this keychord is pressed.
*/
__u16 id;
/* number of keycodes in this keychord */
__u16 count;
/* variable length array of keycodes */
__u16 keycodes[];
};
#endif /* _UAPI_LINUX_KEYCHORD_H_ */

View File

@ -0,0 +1,146 @@
/*
* Gadget Function Driver for Android USB accessories
*
* Copyright (C) 2011 Google, Inc.
* Author: Mike Lockwood <lockwood@android.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _UAPI_LINUX_USB_F_ACCESSORY_H
#define _UAPI_LINUX_USB_F_ACCESSORY_H
/* Use Google Vendor ID when in accessory mode */
#define USB_ACCESSORY_VENDOR_ID 0x18D1
/* Product ID to use when in accessory mode */
#define USB_ACCESSORY_PRODUCT_ID 0x2D00
/* Product ID to use when in accessory mode and adb is enabled */
#define USB_ACCESSORY_ADB_PRODUCT_ID 0x2D01
/* Indexes for strings sent by the host via ACCESSORY_SEND_STRING */
#define ACCESSORY_STRING_MANUFACTURER 0
#define ACCESSORY_STRING_MODEL 1
#define ACCESSORY_STRING_DESCRIPTION 2
#define ACCESSORY_STRING_VERSION 3
#define ACCESSORY_STRING_URI 4
#define ACCESSORY_STRING_SERIAL 5
/* Control request for retrieving device's protocol version
*
* requestType: USB_DIR_IN | USB_TYPE_VENDOR
* request: ACCESSORY_GET_PROTOCOL
* value: 0
* index: 0
* data version number (16 bits little endian)
* 1 for original accessory support
* 2 adds HID and device to host audio support
*/
#define ACCESSORY_GET_PROTOCOL 51
/* Control request for host to send a string to the device
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_SEND_STRING
* value: 0
* index: string ID
* data zero terminated UTF8 string
*
* The device can later retrieve these strings via the
* ACCESSORY_GET_STRING_* ioctls
*/
#define ACCESSORY_SEND_STRING 52
/* Control request for starting device in accessory mode.
* The host sends this after setting all its strings to the device.
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_START
* value: 0
* index: 0
* data none
*/
#define ACCESSORY_START 53
/* Control request for registering a HID device.
* Upon registering, a unique ID is sent by the accessory in the
* value parameter. This ID will be used for future commands for
* the device
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_REGISTER_HID_DEVICE
* value: Accessory assigned ID for the HID device
* index: total length of the HID report descriptor
* data none
*/
#define ACCESSORY_REGISTER_HID 54
/* Control request for unregistering a HID device.
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_REGISTER_HID
* value: Accessory assigned ID for the HID device
* index: 0
* data none
*/
#define ACCESSORY_UNREGISTER_HID 55
/* Control request for sending the HID report descriptor.
* If the HID descriptor is longer than the endpoint zero max packet size,
* the descriptor will be sent in multiple ACCESSORY_SET_HID_REPORT_DESC
* commands. The data for the descriptor must be sent sequentially
* if multiple packets are needed.
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_SET_HID_REPORT_DESC
* value: Accessory assigned ID for the HID device
* index: offset of data in descriptor
* (needed when HID descriptor is too big for one packet)
* data the HID report descriptor
*/
#define ACCESSORY_SET_HID_REPORT_DESC 56
/* Control request for sending HID events.
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_SEND_HID_EVENT
* value: Accessory assigned ID for the HID device
* index: 0
* data the HID report for the event
*/
#define ACCESSORY_SEND_HID_EVENT 57
/* Control request for setting the audio mode.
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_SET_AUDIO_MODE
* value: 0 - no audio
* 1 - device to host, 44100 16-bit stereo PCM
* index: 0
* data none
*/
#define ACCESSORY_SET_AUDIO_MODE 58
/* ioctls for retrieving strings set by the host */
#define ACCESSORY_GET_STRING_MANUFACTURER _IOW('M', 1, char[256])
#define ACCESSORY_GET_STRING_MODEL _IOW('M', 2, char[256])
#define ACCESSORY_GET_STRING_DESCRIPTION _IOW('M', 3, char[256])
#define ACCESSORY_GET_STRING_VERSION _IOW('M', 4, char[256])
#define ACCESSORY_GET_STRING_URI _IOW('M', 5, char[256])
#define ACCESSORY_GET_STRING_SERIAL _IOW('M', 6, char[256])
/* returns 1 if there is a start request pending */
#define ACCESSORY_IS_START_REQUESTED _IO('M', 7)
/* returns audio mode (set via the ACCESSORY_SET_AUDIO_MODE control request) */
#define ACCESSORY_GET_AUDIO_MODE _IO('M', 8)
#endif /* _UAPI_LINUX_USB_F_ACCESSORY_H */

View File

@ -0,0 +1,61 @@
/*
* Gadget Function Driver for MTP
*
* Copyright (C) 2010 Google, Inc.
* Author: Mike Lockwood <lockwood@android.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _UAPI_LINUX_USB_F_MTP_H
#define _UAPI_LINUX_USB_F_MTP_H
#include <linux/ioctl.h>
#include <linux/types.h>
struct mtp_file_range {
/* file descriptor for file to transfer */
int fd;
/* offset in file for start of transfer */
loff_t offset;
/* number of bytes to transfer */
int64_t length;
/* MTP command ID for data header,
* used only for MTP_SEND_FILE_WITH_HEADER
*/
uint16_t command;
/* MTP transaction ID for data header,
* used only for MTP_SEND_FILE_WITH_HEADER
*/
uint32_t transaction_id;
};
struct mtp_event {
/* size of the event */
size_t length;
/* event data to send */
void *data;
};
/* Sends the specified file range to the host */
#define MTP_SEND_FILE _IOW('M', 0, struct mtp_file_range)
/* Receives data from the host and writes it to a file.
* The file is created if it does not exist.
*/
#define MTP_RECEIVE_FILE _IOW('M', 1, struct mtp_file_range)
/* Sends an event to the host via the interrupt endpoint */
#define MTP_SEND_EVENT _IOW('M', 3, struct mtp_event)
/* Sends the specified file range to the host,
* with a 12 byte MTP data packet header at the beginning.
*/
#define MTP_SEND_FILE_WITH_HEADER _IOW('M', 4, struct mtp_file_range)
#endif /* _UAPI_LINUX_USB_F_MTP_H */

View File

@ -22,7 +22,7 @@
#include <drm/drm_mode.h>
#define ADF_NAME_LEN 32
#define ADF_MAX_CUSTOM_DATA_SIZE PAGE_SIZE
#define ADF_MAX_CUSTOM_DATA_SIZE 4096
enum adf_interface_type {
ADF_INTF_DSI = 0,
@ -126,7 +126,7 @@ struct adf_buffer_config {
__s64 acquire_fence;
};
#define ADF_MAX_BUFFERS (PAGE_SIZE / sizeof(struct adf_buffer_config))
#define ADF_MAX_BUFFERS (4096 / sizeof(struct adf_buffer_config))
/**
* struct adf_post_config - request to flip to a new set of buffers
@ -152,7 +152,7 @@ struct adf_post_config {
__s64 complete_fence;
};
#define ADF_MAX_INTERFACES (PAGE_SIZE / sizeof(__u32))
#define ADF_MAX_INTERFACES (4096 / sizeof(__u32))
/**
* struct adf_simple_buffer_allocate - request to allocate a "simple" buffer
@ -233,7 +233,7 @@ struct adf_device_data {
size_t custom_data_size;
void __user *custom_data;
};
#define ADF_MAX_ATTACHMENTS (PAGE_SIZE / sizeof(struct adf_attachment))
#define ADF_MAX_ATTACHMENTS (4096 / sizeof(struct adf_attachment_config))
/**
* struct adf_device_data - describes a display interface
@ -273,7 +273,7 @@ struct adf_interface_data {
size_t custom_data_size;
void __user *custom_data;
};
#define ADF_MAX_MODES (PAGE_SIZE / sizeof(struct drm_mode_modeinfo))
#define ADF_MAX_MODES (4096 / sizeof(struct drm_mode_modeinfo))
/**
* struct adf_overlay_engine_data - describes an overlay engine
@ -293,7 +293,7 @@ struct adf_overlay_engine_data {
size_t custom_data_size;
void __user *custom_data;
};
#define ADF_MAX_SUPPORTED_FORMATS (PAGE_SIZE / sizeof(__u32))
#define ADF_MAX_SUPPORTED_FORMATS (4096 / sizeof(__u32))
#define ADF_SET_EVENT _IOW('D', 0, struct adf_set_event)
#define ADF_BLANK _IOW('D', 1, __u8)

View File

@ -2101,7 +2101,7 @@ static int prctl_get_tid_address(struct task_struct *me, int __user **tid_addr)
}
#endif
#ifdef CONFIG_MMU
static int prctl_update_vma_anon_name(struct vm_area_struct *vma,
struct vm_area_struct **prev,
unsigned long start, unsigned long end,
@ -2240,6 +2240,13 @@ static int prctl_set_vma(unsigned long opt, unsigned long start,
return error;
}
#else /* CONFIG_MMU */
static int prctl_set_vma(unsigned long opt, unsigned long start,
unsigned long len_in, unsigned long arg)
{
return -EINVAL;
}
#endif
SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
unsigned long, arg4, unsigned long, arg5)
@ -2368,9 +2375,6 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
else
return -EINVAL;
break;
case PR_SET_VMA:
error = prctl_set_vma(arg2, arg3, arg4, arg5);
break;
default:
return -EINVAL;
}
@ -2407,6 +2411,9 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
if (arg2 || arg3 || arg4 || arg5)
return -EINVAL;
return current->no_new_privs ? 1 : 0;
case PR_SET_VMA:
error = prctl_set_vma(arg2, arg3, arg4, arg5);
break;
default:
error = -EINVAL;
break;

View File

@ -728,7 +728,7 @@ static int mbind_range(struct mm_struct *mm, unsigned long start,
((vmstart - vma->vm_start) >> PAGE_SHIFT);
prev = vma_merge(mm, prev, vmstart, vmend, vma->vm_flags,
vma->anon_vma, vma->vm_file, pgoff,
new_pol, vma_get_anon_name(name));
new_pol, vma_get_anon_name(vma));
if (prev) {
vma = prev;
next = vma->vm_next;

View File

@ -1496,7 +1496,7 @@ static const struct file_operations proc_iface_stat_fmt_fops = {
.open = proc_iface_stat_fmt_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
.release = seq_release_private,
};
static int __init iface_stat_init(struct proc_dir_entry *parent_procdir)
@ -2904,7 +2904,7 @@ static const struct file_operations proc_qtaguid_ctrl_fops = {
.read = seq_read,
.write = qtaguid_ctrl_proc_write,
.llseek = seq_lseek,
.release = seq_release,
.release = seq_release_private,
};
static const struct seq_operations proc_qtaguid_stats_seqops = {