You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
430 lines
16 KiB
430 lines
16 KiB
/*
|
|
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/**
|
|
* @file ump_osu.h
|
|
* Defines the OS abstraction layer for the base driver
|
|
*/
|
|
|
|
#ifndef __UMP_OSU_H__
|
|
#define __UMP_OSU_H__
|
|
|
|
#include <stdarg.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C"
|
|
{
|
|
#endif
|
|
|
|
|
|
typedef unsigned int u32;
|
|
#ifdef _MSC_VER
|
|
typedef unsigned __int64 u64;
|
|
typedef signed __int64 s64;
|
|
#else
|
|
typedef unsigned long long u64;
|
|
typedef signed long long s64;
|
|
#endif
|
|
|
|
#ifndef NULL
|
|
#define NULL ((void*)0)
|
|
#endif
|
|
|
|
typedef unsigned long ump_bool;
|
|
|
|
#ifndef UMP_TRUE
|
|
#define UMP_TRUE ((ump_bool)1)
|
|
#endif
|
|
|
|
#ifndef UMP_FALSE
|
|
#define UMP_FALSE ((ump_bool)0)
|
|
#endif
|
|
|
|
#define UMP_STATIC static
|
|
|
|
/**
|
|
* @addtogroup ump_user_space_api Unified Device Driver (UDD) APIs used by UMP
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* @defgroup ump_osuapi UDD OS Abstraction for User-side (OSU) APIs for UMP
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
/* The following is necessary to prevent the _ump_osk_errcode_t doxygen from
|
|
* becoming unreadable: */
|
|
/** @cond OSU_COPY_OF__UMP_OSU_ERRCODE_T */
|
|
|
|
/**
|
|
* @brief OSU/OSK Error codes.
|
|
*
|
|
* Each OS may use its own set of error codes, and may require that the
|
|
* User/Kernel interface take certain error code. This means that the common
|
|
* error codes need to be sufficiently rich to pass the correct error code
|
|
* through from the OSK/OSU to U/K layer, across all OSs.
|
|
*
|
|
* The result is that some error codes will appear redundant on some OSs.
|
|
* Under all OSs, the OSK/OSU layer must translate native OS error codes to
|
|
* _ump_osk/u_errcode_t codes. Similarly, the U/K layer must translate from
|
|
* _ump_osk/u_errcode_t codes to native OS error codes.
|
|
*
|
|
*/
|
|
typedef enum
|
|
{
|
|
_UMP_OSK_ERR_OK = 0, /**< Success. */
|
|
_UMP_OSK_ERR_FAULT = -1, /**< General non-success */
|
|
_UMP_OSK_ERR_INVALID_FUNC = -2, /**< Invalid function requested through User/Kernel interface (e.g. bad IOCTL number) */
|
|
_UMP_OSK_ERR_INVALID_ARGS = -3, /**< Invalid arguments passed through User/Kernel interface */
|
|
_UMP_OSK_ERR_NOMEM = -4, /**< Insufficient memory */
|
|
_UMP_OSK_ERR_TIMEOUT = -5, /**< Timeout occured */
|
|
_UMP_OSK_ERR_RESTARTSYSCALL = -6, /**< Special: On certain OSs, must report when an interruptable mutex is interrupted. Ignore otherwise. */
|
|
_UMP_OSK_ERR_ITEM_NOT_FOUND = -7, /**< Table Lookup failed */
|
|
_UMP_OSK_ERR_BUSY = -8, /**< Device/operation is busy. Try again later */
|
|
_UMP_OSK_ERR_UNSUPPORTED = -9, /**< Optional part of the interface used, and is unsupported */
|
|
} _ump_osk_errcode_t;
|
|
|
|
/** @endcond */ /* end cond OSU_COPY_OF__UMP_OSU_ERRCODE_T */
|
|
|
|
/**
|
|
* @brief OSU Error codes.
|
|
*
|
|
* OSU error codes - enum values intentionally same as OSK
|
|
*/
|
|
typedef enum
|
|
{
|
|
_UMP_OSU_ERR_OK = 0, /**< Success. */
|
|
_UMP_OSU_ERR_FAULT = -1, /**< General non-success */
|
|
_UMP_OSU_ERR_TIMEOUT = -2, /**< Timeout occured */
|
|
} _ump_osu_errcode_t;
|
|
|
|
/** @brief Translate OSU error code to base driver error code.
|
|
*
|
|
* The _UMP_OSU_TRANSLATE_ERROR macro translates an OSU error code to the
|
|
* error codes in use by the base driver.
|
|
*/
|
|
#define _UMP_OSU_TRANSLATE_ERROR(_ump_osu_errcode) ( ( _UMP_OSU_ERR_OK == (_ump_osu_errcode) ) ? UMP_ERR_NO_ERROR : UMP_ERR_FUNCTION_FAILED)
|
|
|
|
/** @defgroup _ump_osu_lock OSU Mutual Exclusion Locks
|
|
* @{ */
|
|
|
|
/** @brief OSU Mutual Exclusion Lock flags type.
|
|
*
|
|
* This is made to look like and function identically to the OSK locks (refer
|
|
* to \ref _ump_osk_lock). However, please note the following \b important
|
|
* differences:
|
|
* - the OSU default lock is a Sleeping, non-interruptible mutex.
|
|
* - the OSU adds the ANYUNLOCK type of lock which allows a thread which doesn't
|
|
* own the lock to release the lock.
|
|
* - the order parameter when creating a lock is currently unused
|
|
*
|
|
* @note Pay careful attention to the difference in default locks for OSU and
|
|
* OSK locks; OSU locks are always non-interruptible, but OSK locks are by
|
|
* default, interruptible. This has implications for systems that do not
|
|
* distinguish between user and kernel mode.
|
|
*/
|
|
typedef enum
|
|
{
|
|
_UMP_OSU_LOCKFLAG_DEFAULT = 0, /**< Default lock type. */
|
|
/** @enum _ump_osu_lock_flags_t
|
|
*
|
|
* Flags from 0x8000--0x1 are RESERVED for Kernel-mode
|
|
*/
|
|
_UMP_OSU_LOCKFLAG_ANYUNLOCK = 0x10000, /**< Mutex that guarantees that any thread can unlock it when locked. Otherwise, this will not be possible. */
|
|
/** @enum _ump_osu_lock_flags_t
|
|
*
|
|
* Flags from 0x80000000 are RESERVED for User-mode
|
|
*/
|
|
_UMP_OSU_LOCKFLAG_STATIC = 0x80000000, /* Flag in OSU reserved range to identify lock as a statically initialized lock */
|
|
|
|
} _ump_osu_lock_flags_t;
|
|
|
|
typedef enum
|
|
{
|
|
_UMP_OSU_LOCKMODE_UNDEF = -1, /**< Undefined lock mode. For internal use only */
|
|
_UMP_OSU_LOCKMODE_RW = 0x0, /**< Default. Lock is used to protect data that is read from and written to */
|
|
/** @enum _ump_osu_lock_mode_t
|
|
*
|
|
* Lock modes 0x1--0x3F are RESERVED for Kernel-mode */
|
|
} _ump_osu_lock_mode_t;
|
|
|
|
/** @brief Private type for Mutual Exclusion lock objects. */
|
|
typedef struct _ump_osu_lock_t_struct _ump_osu_lock_t;
|
|
|
|
/** @brief The number of static locks supported in _ump_osu_lock_static(). */
|
|
#define UMP_OSU_STATIC_LOCK_COUNT (sizeof(_ump_osu_static_locks) / sizeof(_ump_osu_lock_t))
|
|
|
|
/** @} */ /* end group _ump_osu_lock */
|
|
|
|
/** @defgroup _ump_osu_memory OSU Memory Allocation
|
|
* @{ */
|
|
|
|
/** @brief Allocate zero-initialized memory.
|
|
*
|
|
* Returns a buffer capable of containing at least \a n elements of \a size
|
|
* bytes each. The buffer is initialized to zero.
|
|
*
|
|
* The buffer is suitably aligned for storage and subsequent access of every
|
|
* type that the compiler supports. Therefore, the pointer to the start of the
|
|
* buffer may be cast into any pointer type, and be subsequently accessed from
|
|
* such a pointer, without loss of information.
|
|
*
|
|
* When the buffer is no longer in use, it must be freed with _ump_osu_free().
|
|
* Failure to do so will cause a memory leak.
|
|
*
|
|
* @note Most toolchains supply memory allocation functions that meet the
|
|
* compiler's alignment requirements.
|
|
*
|
|
* @param n Number of elements to allocate
|
|
* @param size Size of each element
|
|
* @return On success, the zero-initialized buffer allocated. NULL on failure
|
|
*/
|
|
void *_ump_osu_calloc( u32 n, u32 size );
|
|
|
|
/** @brief Allocate memory.
|
|
*
|
|
* Returns a buffer capable of containing at least \a size bytes. The
|
|
* contents of the buffer are undefined.
|
|
*
|
|
* The buffer is suitably aligned for storage and subsequent access of every
|
|
* type that the compiler supports. Therefore, the pointer to the start of the
|
|
* buffer may be cast into any pointer type, and be subsequently accessed from
|
|
* such a pointer, without loss of information.
|
|
*
|
|
* When the buffer is no longer in use, it must be freed with _ump_osu_free().
|
|
* Failure to do so will cause a memory leak.
|
|
*
|
|
* @note Most toolchains supply memory allocation functions that meet the
|
|
* compiler's alignment requirements.
|
|
*
|
|
* Remember to free memory using _ump_osu_free().
|
|
* @param size Number of bytes to allocate
|
|
* @return On success, the buffer allocated. NULL on failure.
|
|
*/
|
|
void *_ump_osu_malloc( u32 size );
|
|
|
|
/** @brief Free memory.
|
|
*
|
|
* Reclaims the buffer pointed to by the parameter \a ptr for the system.
|
|
* All memory returned from _ump_osu_malloc(), _ump_osu_calloc() and
|
|
* _ump_osu_realloc() must be freed before the application exits. Otherwise,
|
|
* a memory leak will occur.
|
|
*
|
|
* Memory must be freed once. It is an error to free the same non-NULL pointer
|
|
* more than once.
|
|
*
|
|
* It is legal to free the NULL pointer.
|
|
*
|
|
* @param ptr Pointer to buffer to free
|
|
*/
|
|
void _ump_osu_free( void *ptr );
|
|
|
|
/** @brief Copies memory.
|
|
*
|
|
* Copies the \a len bytes from the buffer pointed by the parameter \a src
|
|
* directly to the buffer pointed by \a dst.
|
|
*
|
|
* It is an error for \a src to overlap \a dst anywhere in \a len bytes.
|
|
*
|
|
* @param dst Pointer to the destination array where the content is to be
|
|
* copied.
|
|
* @param src Pointer to the source of data to be copied.
|
|
* @param len Number of bytes to copy.
|
|
* @return \a dst is always passed through unmodified.
|
|
*/
|
|
void *_ump_osu_memcpy( void *dst, const void *src, u32 len );
|
|
|
|
/** @brief Fills memory.
|
|
*
|
|
* Sets the first \a size bytes of the block of memory pointed to by \a ptr to
|
|
* the specified value
|
|
* @param ptr Pointer to the block of memory to fill.
|
|
* @param chr Value to be set, passed as u32. Only the 8 Least Significant Bits (LSB)
|
|
* are used.
|
|
* @param size Number of bytes to be set to the value.
|
|
* @return \a ptr is always passed through unmodified
|
|
*/
|
|
void *_ump_osu_memset( void *ptr, u32 chr, u32 size );
|
|
|
|
/** @} */ /* end group _ump_osu_memory */
|
|
|
|
|
|
/** @addtogroup _ump_osu_lock
|
|
* @{ */
|
|
|
|
/** @brief Initialize a Mutual Exclusion Lock.
|
|
*
|
|
* Locks are created in the signalled (unlocked) state.
|
|
*
|
|
* The parameter \a initial must be zero.
|
|
*
|
|
* At present, the parameter \a order must be zero. It remains for future
|
|
* expansion for mutex order checking.
|
|
*
|
|
* @param flags flags combined with bitwise OR ('|'), or zero. There are
|
|
* restrictions on which flags can be combined, see \ref _ump_osu_lock_flags_t.
|
|
* @param initial For future expansion into semaphores. SBZ.
|
|
* @param order The locking order of the mutex. SBZ.
|
|
* @return On success, a pointer to a \ref _ump_osu_lock_t object. NULL on failure.
|
|
*/
|
|
_ump_osu_lock_t *_ump_osu_lock_init( _ump_osu_lock_flags_t flags, u32 initial, u32 order );
|
|
|
|
/** @brief Obtain a statically initialized Mutual Exclusion Lock.
|
|
*
|
|
* Retrieves a reference to a statically initialized lock. Up to
|
|
* _UMP_OSU_STATIC_LOCK_COUNT statically initialized locks are
|
|
* available. Only _ump_osu_lock_wait(), _ump_osu_lock_trywait(),
|
|
* _ump_osu_lock_signal() can be used with statically initialized locks.
|
|
* _UMP_OSU_LOCKMODE_RW mode should be used when waiting and signalling
|
|
* statically initialized locks.
|
|
*
|
|
* For the same \a nr a pointer to the same statically initialized lock is
|
|
* returned. That is, given the following code:
|
|
* @code
|
|
* extern u32 n;
|
|
*
|
|
* _ump_osu_lock_t *locka = _ump_osu_lock_static(n);
|
|
* _ump_osu_lock_t *lockb = _ump_osu_lock_static(n);
|
|
* @endcode
|
|
* Then (locka == lockb), for all 0 <= n < UMP_OSU_STATIC_LOCK_COUNT.
|
|
*
|
|
* @param nr index of a statically initialized lock [0..UMP_OSU_STATIC_LOCK_COUNT-1]
|
|
* @return On success, a pointer to a _ump_osu_lock_t object. NULL on failure.
|
|
*/
|
|
_ump_osu_lock_t *_ump_osu_lock_static( u32 nr );
|
|
|
|
/** @brief Initialize a Mutual Exclusion Lock safely across multiple threads.
|
|
*
|
|
* The _ump_osu_lock_auto_init() function guarantees that the given lock will
|
|
* be initialized once and precisely once, even in a situation involving
|
|
* multiple threads.
|
|
*
|
|
* This is necessary because the first call to certain Public API functions must
|
|
* initialize the API. However, there can be a race involved to call the first
|
|
* library function in multi-threaded applications. To resolve this race, a
|
|
* mutex can be used. This mutex must be initialized, but initialized only once
|
|
* by any thread that might compete for its initialization. This function
|
|
* guarantees the initialization to happen correctly, even when there is an
|
|
* initialization race between multiple threads.
|
|
*
|
|
* Otherwise, the operation is identical to the _ump_osu_lock_init() function.
|
|
* For more details, refer to _ump_osu_lock_init().
|
|
*
|
|
* @param pplock pointer to storage for a _ump_osu_lock_t pointer. This
|
|
* _ump_osu_lock_t pointer may point to a _ump_osu_lock_t that has been
|
|
* initialized already
|
|
* @param flags flags combined with bitwise OR ('|'), or zero. There are
|
|
* restrictions on which flags can be combined. Refer to
|
|
* \ref _ump_osu_lock_flags_t for more information.
|
|
* The absence of any flags (the value 0) results in a sleeping-mutex,
|
|
* which is non-interruptible.
|
|
* @param initial For future expansion into semaphores. SBZ.
|
|
* @param order The locking order of the mutex. SBZ.
|
|
* @return On success, _UMP_OSU_ERR_OK is returned and a pointer to an
|
|
* initialized \ref _ump_osu_lock_t object is written into \a *pplock.
|
|
* _UMP_OSU_ERR_FAULT is returned on failure.
|
|
*/
|
|
_ump_osu_errcode_t _ump_osu_lock_auto_init( _ump_osu_lock_t **pplock, _ump_osu_lock_flags_t flags, u32 initial, u32 order );
|
|
|
|
/** @brief Wait for a lock to be signalled (obtained).
|
|
*
|
|
* After a thread has successfully waited on the lock, the lock is obtained by
|
|
* the thread, and is marked as unsignalled. The thread releases the lock by
|
|
* signalling it.
|
|
*
|
|
* To prevent deadlock, locks must always be obtained in the same order.
|
|
*
|
|
* @param lock the lock to wait upon (obtain).
|
|
* @param mode the mode in which the lock should be obtained. Currently this
|
|
* must be _UMP_OSU_LOCKMODE_RW.
|
|
* @return On success, _UMP_OSU_ERR_OK, _UMP_OSU_ERR_FAULT on error.
|
|
*/
|
|
_ump_osu_errcode_t _ump_osu_lock_wait( _ump_osu_lock_t *lock, _ump_osu_lock_mode_t mode);
|
|
|
|
/** @brief Wait for a lock to be signalled (obtained) with timeout
|
|
*
|
|
* After a thread has successfully waited on the lock, the lock is obtained by
|
|
* the thread, and is marked as unsignalled. The thread releases the lock by
|
|
* signalling it.
|
|
*
|
|
* To prevent deadlock, locks must always be obtained in the same order.
|
|
*
|
|
* This version can return early if it cannot obtain the lock within the given timeout.
|
|
*
|
|
* @param lock the lock to wait upon (obtain).
|
|
* @param mode the mode in which the lock should be obtained. Currently this
|
|
* must be _UMP_OSU_LOCKMODE_RW.
|
|
* @param timeout Relative time in microseconds for the timeout
|
|
* @return _UMP_OSU_ERR_OK if the lock was obtained, _UMP_OSU_ERR_TIMEOUT if the timeout expired or _UMP_OSU_ERR_FAULT on error.
|
|
*/
|
|
_ump_osu_errcode_t _ump_osu_lock_timed_wait( _ump_osu_lock_t *lock, _ump_osu_lock_mode_t mode, u64 timeout);
|
|
|
|
/** @brief Test for a lock to be signalled and obtains the lock when so.
|
|
*
|
|
* Obtains the lock only when it is in signalled state. The lock is then
|
|
* marked as unsignalled. The lock is released again by signalling
|
|
* it by _ump_osu_lock_signal().
|
|
*
|
|
* If the lock could not be obtained immediately (that is, another thread
|
|
* currently holds the lock), then this function \b does \b not wait for the
|
|
* lock to be in a signalled state. Instead, an error code is immediately
|
|
* returned to indicate that the thread could not obtain the lock.
|
|
*
|
|
* To prevent deadlock, locks must always be obtained in the same order.
|
|
*
|
|
* @param lock the lock to wait upon (obtain).
|
|
* @param mode the mode in which the lock should be obtained. Currently this
|
|
* must be _UMP_OSU_LOCKMODE_RW.
|
|
* @return When the lock was obtained, _UMP_OSU_ERR_OK. If the lock could not
|
|
* be obtained, _UMP_OSU_ERR_FAULT.
|
|
*/
|
|
_ump_osu_errcode_t _ump_osu_lock_trywait( _ump_osu_lock_t *lock, _ump_osu_lock_mode_t mode);
|
|
|
|
/** @brief Signal (release) a lock.
|
|
*
|
|
* Locks may only be signalled by the thread that originally waited upon the
|
|
* lock, unless the lock was created using the _UMP_OSU_LOCKFLAG_ANYUNLOCK flag.
|
|
*
|
|
* @param lock the lock to signal (release).
|
|
* @param mode the mode in which the lock should be obtained. This must match
|
|
* the mode in which the lock was waited upon.
|
|
*/
|
|
void _ump_osu_lock_signal( _ump_osu_lock_t *lock, _ump_osu_lock_mode_t mode );
|
|
|
|
/** @brief Terminate a lock.
|
|
*
|
|
* This terminates a lock and frees all associated resources.
|
|
*
|
|
* It is a programming error to terminate the lock when it is held (unsignalled)
|
|
* by a thread.
|
|
*
|
|
* @param lock the lock to terminate.
|
|
*/
|
|
void _ump_osu_lock_term( _ump_osu_lock_t *lock );
|
|
/** @} */ /* end group _ump_osu_lock */
|
|
|
|
/** @} */ /* end group osuapi */
|
|
|
|
/** @} */ /* end group uddapi */
|
|
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* __UMP_OSU_H__ */
|
|
|