/****************************************************************************/
/*	Copyright (c) 2009, Bendor Research Pty. Ltd. All rights reserved.		*/
/*	This software is released under the GNU General Public License, version	*/
/*	3, with the exemptions that 1) the header files installed by this 	 	*/
/*	package can be included in closed-source code and 2) the libraries		*/
/*	built by this package can be statically linked into a closed-source 	*/
/*	binary. See the file LICENSE for the details.							*/
/*	This software is provided "AS IS", without any warranty or guarantee.	*/
/*	By using this software you acknowledge that neither Bendor Research nor	*/
/*	any of its personnel or affiliates can be held liable for any damages,	*/
/*	including, but not limited to, loss of business, loss of money, loss of */
/*	life, loss of reputation, arising out of this software being faulty or	*/
/*	not performing as advertised, even if Bendor Research was aware of such	*/
/*	faults in the software. You use this software at your own risk, any and */
/*	all liabilities that arise out of your using this software are strictly	*/
/*	yours.																	*/
/****************************************************************************/

#ifndef _BX_H
#define	_BX_H

/****************************************************************************/
/*				Definitions needed for local macros							*/
/****************************************************************************/

#ifndef NULL
#define	NULL	((void*)0)
#endif

#define	BX_PRIO_MIN		0
#define	BX_PRIO_MAX		255

/****************************************************************************/
/*				General definitions											*/
/****************************************************************************/

/** @addtogroup kernel */
/** @{ */

/**
*	Error codes.
*/

typedef enum {

	BX_ERR_SUSPEND	= -1,		//!< Caller should, but can not be suspended
	BX_ERR_CONTEXT	= -2,		//!< This function can not be called from ISR
	BX_ERR_OBJECT	= -3,		//!< Invalid or uninitialised object
	BX_ERR_PARAM	= -4,		//!< A function parameter had an illegal value
	BX_ERR_INUSE	= -5,		//!< The object is in use
	BX_ERR_NOTOWNER	= -6,		//!< The object is not owned by the caller
	BX_ERR_ISOWNER	= -7,		//!< The caller already owns the object
	BX_ERR_INACTIVE	= -8		//!< The object is not active

} BX_ERROR;

/**
*	Waiting policies
*/

typedef enum {

	BX_POLICY_FIFO = 0,			//!< First in, first out
	BX_POLICY_PRIO,				//!< Highest priority first
	BX_POLICY_FPCL,				//!< FIFO order, priority ceiling
	BX_POLICY_FPIN,				//!< FIFO order, priority inheritance
	BX_POLICY_PPCL,				//!< Priority order, priority ceiling
	BX_POLICY_PPIN,				//!< Priority order, priority inheritance
	BX_POLICY_SRQF,				//!< Smallest request first
	BX_POLICY_LRQF,				//!< Largest request first

} BX_POLICY;

/** @} */

/*
*	Kernel object types.
*
*	If you are interested, the hex code is a 5 letter name
*	of the object type encoded in Baudot code.
*/

enum {

	BX_TYPE_PROC = 0x21450469,	// Process descriptor
	BX_TYPE_LOCK = 0x387807a4,	// Mutual exlusivity lock
	BX_TYPE_SEMA = 0x0a1e0ed4,	// Counting smaphore
	BX_TYPE_TIME = 0x0103702a,	// Timer
};

/*
*	Common header for objects that a process can be queued on
*/

struct _bx_wait {

	unsigned int	type;		// Object type
	struct _bx_proc	*head;		// Head of the waiting list
	struct _bx_proc	*tail;		// Tail of the waiting list
	struct _bx_poli	*ftab;		// Policy function table
};

/*
*	Common header for waitable objects that can mutate priorities
*/

struct _bx_pmut {

	struct _bx_wait	wait;		// Common header
	struct _bx_pmut	*next;		// Next element of the list
	struct _bx_pmut *prev;		// Previous element of the list
	struct _bx_proc *proc;		// Owner of the object
	unsigned int	prio;		// Current max. priority
	unsigned int	ceil;		// Ceiling priority (if exists)
};

/****************************************************************************/
/*				Exported kernel objects										*/
/****************************************************************************/

extern const struct _bx_poli	_bx_poli_fifo;
extern const struct _bx_poli	_bx_poli_srqf;
extern const struct _bx_poli	_bx_poli_lrqf;
extern const struct _bx_poli	_bx_poli_prio;
extern const struct _bx_poli	_bx_poli_fpcl;
extern const struct _bx_poli	_bx_poli_fpin;
extern const struct _bx_poli	_bx_poli_ppcl;
extern const struct _bx_poli	_bx_poli_ppin;

/****************************************************************************/
/*				Kernel initialisation										*/
/****************************************************************************/

/** @addtogroup bx_init */
/** @{ */

/**
*	Prototype for ISR functions.
*/

typedef	void	(*BX_ISR_FUNC)( void );

/**
*	Prototype for delayed/soft ISR functions.
*/

typedef void	(*BX_DISR_FUNC)( void *, void * );

/**
*	Prototype for process entry point functions.
*/

typedef void	(*BX_PROC_FUNC)( void * );

/**
*	A macro to work out how many ints are needed for the event queue
*
*	@param	len		The length of the event queue
*
*	@return			The number of ints to allocate
*/

#define	BX_EQSIZE( len )	(3*(len))

/**
*	The kernel init parameter structure.
*/

typedef struct _bx_init {

	unsigned int	evtq_size;		//!< Length of the event queue
	unsigned int	evtq_wmrk;		//!< Event queue watermark
	int				*evtq_buff;		//!< The event queue, 3*eq_length ints
	BX_ISR_FUNC		uirq_func;		//!< The user's interrupt handler
	BX_ISR_FUNC		idle_func;		//!< The user's idle state function
	BX_ISR_FUNC		init_func;		//!< The user's first process to start
	struct _bx_proc	*init_desc;		//!< Process descriptor for the process
	int				*init_stack;	//!< Stack for the process
	int				*kern_stack;	//!< Stack for the kernel

} BX_INIT;

/*
*	Kernel initialisation function prototype
*/

void	BX_Init( const BX_INIT *init ) __attribute__ ((noreturn));

/** @} */

/****************************************************************************/
/*				Counting semaphore											*/
/****************************************************************************/

/** @addtogroup bx_sema */
/** @{ */

/**
*	Semaphore object.
*/

typedef struct _bx_sema {

	struct _bx_wait	base;			// Common fields for all waitables
	unsigned int	cntr;			// Current semaphore count

} BX_SEMA;

/*
*	Semaphore function prototypes
*/

int		BX_SemaInit( BX_SEMA *sema, BX_POLICY policy, unsigned value );
int		BX_SemaGet( BX_SEMA *sema, unsigned value, unsigned timeout );
int		BX_SemaPut( BX_SEMA *sema, unsigned value );

/**
*	Static initialiser for a semaphore.
*
*	@param	policy	The semaphore's waiting policy, one of BX_POLICY_FIFO,
*					BX_POLICY_PRIO, BX_POLICY_LRQF or BX_POLICY_SRQF.
*
*	@param	count	The initial count on the semaphore.
*/

#define	BX_SEMA_INIT( policy, count )							\
{																\
	.base = {													\
		.type = BX_TYPE_SEMA,									\
		.head = NULL,											\
		.tail = NULL,											\
		.ftab = (struct _bx_poli *) (							\
				(policy) == BX_POLICY_SRQF ? &_bx_poli_srqf :	\
				(policy) == BX_POLICY_LRQF ? &_bx_poli_lrqf :	\
				(policy) == BX_POLICY_PRIO ? &_bx_poli_prio :	\
				&_bx_poli_fifo )								\
	},															\
	.cntr = (count)												\
}

/** @} */

/****************************************************************************/
/*				Mutual exclusivity lock										*/
/****************************************************************************/

/** @addtogroup bx_lock */
/** @{ */

/**
*	Lock object.
*/

typedef struct _bx_lock {

	struct _bx_pmut	pmut;			// The lock only has the common structure

} BX_LOCK;

/*
*	Lock function prototypes
*/

int		BX_LockInit( BX_LOCK *lock, BX_POLICY policy, unsigned ceilprio );
int		BX_LockAttempt( BX_LOCK *lock, unsigned timeout );
int		BX_LockObtain( BX_LOCK *lock, unsigned timeout );
int		BX_LockRelease( BX_LOCK *lock );

/**
*	Static initialiser for a lock.
*
*	@param	policy	The locks waiting policy, one of BX_POLICY_FIFO,
*					BX_POLICY_PRIO, BX_POLICY_FPCL, BX_POLICY_FPIN,
*					BX_POLICY_PPCL, BX_POLICY_PPIN as defined by BX_POLICY .
*
*	@param	ceiling	The ceiling priority if the policy is BX_POLICY_FPCL or
*					BX_POLICY_PPCL. In any other case its value is ignored.
*/

#define	BX_LOCK_INIT( policy, ceiling )								\
{																	\
	.pmut = {														\
		.wait = {													\
			.type = BX_TYPE_LOCK,									\
			.head = NULL,											\
			.tail = NULL,											\
			.ftab = (struct _bx_poli *) (							\
					(policy) == BX_POLICY_PRIO ? &_bx_poli_prio :	\
					(policy) == BX_POLICY_FPCL ? &_bx_poli_fpcl :	\
					(policy) == BX_POLICY_FPIN ? &_bx_poli_fpin :	\
					(policy) == BX_POLICY_PPCL ? &_bx_poli_ppcl :	\
					(policy) == BX_POLICY_PPIN ? &_bx_poli_ppin :	\
					&_bx_poli_fifo )								\
		},															\
		.ceil = (ceiling),											\
		.next = NULL,												\
		.prev = NULL,												\
		.proc = NULL,												\
		.prio = 0													\
	}																\
}

/** @} */

/****************************************************************************/
/*						Timers												*/
/****************************************************************************/

/** @addtogroup bx_time */
/** @{ */

/**
*	Timer object.
*/

typedef struct _bx_time {

	unsigned		type;			// Object type
	struct _bx_time	*next;			// Next timer on the queue
	struct _bx_time	*prev;			// Previous timer on the queue
	unsigned		peri;			// Period time
	BX_DISR_FUNC	func;			// Call-back function
	void			*par1;			// Call-back parameter 1
	void			*par2;			// Call-back parameter 2

	unsigned		wait;			// Remaining time on the queue
	unsigned		load;			// Time to load (or reload)
	unsigned char	stat;			// The state of the timer
	unsigned char	runs;			// Indicates that timer is on the queue

} BX_TIME;

int		BX_TimerTick( int usec );
void	BX_TimerInit( BX_TIME *timer );
int		BX_TimerSleep( unsigned usec );
int		BX_TimerStart( BX_TIME *timer, unsigned expire, unsigned period );
int		BX_TimerCancel( BX_TIME *timer );
int		BX_TimerReload( BX_TIME *timer, unsigned value );
int		BX_TimerAction( BX_TIME *timer, BX_DISR_FUNC func,
					    void *par1, void *par2 );
unsigned long long BX_TimerUptime( void );

/**
*	Static initialiser for a timer.
*/

#define	BX_TIME_INIT()								\
{													\
	.type = BX_TYPE_TIME,							\
	.next = NULL,									\
	.prev = NULL,									\
	.wait = 0,										\
	.load = 0,										\
	.peri = 0,										\
	.stat = 0,										\
	.runs = 0,										\
	.func = NULL,									\
	.par1 = NULL,									\
	.par2 = NULL									\
}

/** @} */

/****************************************************************************/
/*				Process handling											*/
/****************************************************************************/

/*
*	Process descriptor structure
*/

/** @addtogroup bx_proc */
/** @{ */

/**
*	Process descriptor object.
*/

typedef struct _bx_proc {

	unsigned int	type;			// Object type
	struct _bx_proc	*next;			// Next element of the process list
	struct _bx_proc *prev;			// Previous element of the process list
	struct _bx_wait	*wait;			// Object the process is waiting on
	struct _bx_pmut	*head;			// Head of owned object list
	struct _bx_pmut	*tail;			// Tail of owned object list
	struct _bx_time	timo;			// Time-out timer
	unsigned char	prot;			// Mode flags
	unsigned char	rpri;			// Real priority
	unsigned char	epri;			// Effective priority
	unsigned int	mask;			// Signal wait mask
	unsigned int	sigs;			// Pending signals
	unsigned int	ramt;			// Request amount
	unsigned int	cntx[ 17 ];		// Processor context

} BX_PROC;

/**
*	Process protection levels.
*/

typedef enum {

	BX_PROT_NORM = 0,	//!< Normal, not protected, preemptable mode
	BX_PROT_COOP = 1,	//!< Cooperative mode, suspend only when requested
	BX_PROT_IRQD = 2,	//!< IRQ disabled mode, no preemption or suspension
	BX_PROT_FIQD = 3	//!< IRQ and FIQ disabled, no preemption or suspension

} BX_PROT;

/*
*	Process function prototypes
*/

int		BX_ProcSpawn( BX_PROC *proc, BX_PROC_FUNC func, void *parm,
					  int *stack, unsigned prio, BX_PROT prot );
int		BX_ProcProtLower( BX_PROT prot );
int		BX_ProcProtRaise( BX_PROT prot );
int		BX_ProcNice( int prio );
BX_PROC	*BX_ProcSelf( void );

/** @} */

/****************************************************************************/
/*				Simple event handling										*/
/****************************************************************************/

/** @addtogroup bx_sigs */
/** @{ */

/**
*	The event that is always set.
*/

#define	BX_EVENT_ALWAYS	0x80000000

/*
*	Event function prototypes
*/

int		BX_EventPost( BX_PROC *proc, int sigs );
int		BX_EventWait( int wait );

/** @} */

/****************************************************************************/
/*				Interrupt related functions									*/
/****************************************************************************/

int		BX_AtomicSwapWord( int, int * );
int		BX_AtomicSwapByte( int, unsigned char * );
int		BX_SoftInterrupt( BX_DISR_FUNC func, void *par1, void *par2 );

void	BX_TraceFirst( char *buff, int size );
int		BX_TraceNext( char *buff, int size );

#endif

