ump_osu.h 15.8 KB
Newer Older
Luc Verhaegen's avatar
Luc Verhaegen committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
/*
 * Copyright (C) 2010-2012 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 0x0--0x8000 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 0x10000 are RESERVED for User-mode
	 */
	_UMP_OSU_LOCKFLAG_STATIC = 0x20000, /* 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__ */