From e448862a47c08eb23185aaed574b39264f5005fc Mon Sep 17 00:00:00 2001 From: Andre Eisenbach Date: Wed, 22 Feb 2012 13:18:21 -0800 Subject: Initial Bluedroid stack commit --- gki/Android.mk | 33 ++ gki/common/gki.h | 490 ++++++++++++++++ gki/common/gki_buffer.c | 1474 +++++++++++++++++++++++++++++++++++++++++++++++ gki/common/gki_common.h | 384 ++++++++++++ gki/common/gki_debug.c | 348 +++++++++++ gki/common/gki_inet.h | 42 ++ gki/common/gki_time.c | 1016 ++++++++++++++++++++++++++++++++ gki/ulinux/data_types.h | 71 +++ gki/ulinux/gki_int.h | 111 ++++ gki/ulinux/gki_ulinux.c | 1355 +++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 5324 insertions(+) create mode 100644 gki/Android.mk create mode 100644 gki/common/gki.h create mode 100644 gki/common/gki_buffer.c create mode 100644 gki/common/gki_common.h create mode 100644 gki/common/gki_debug.c create mode 100644 gki/common/gki_inet.h create mode 100644 gki/common/gki_time.c create mode 100644 gki/ulinux/data_types.h create mode 100644 gki/ulinux/gki_int.h create mode 100644 gki/ulinux/gki_ulinux.c (limited to 'gki') diff --git a/gki/Android.mk b/gki/Android.mk new file mode 100644 index 0000000..2317fc0 --- /dev/null +++ b/gki/Android.mk @@ -0,0 +1,33 @@ +ifneq ($(TARGET_SIMULATOR),true) + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_C_INCLUDES:= $(LOCAL_PATH)/common \ + $(LOCAL_PATH)/ulinux \ + $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/../stack/include/ + + +LOCAL_CFLAGS += -Werror + +ifeq ($(BOARD_HAVE_BLUETOOTH_BCM),true) +LOCAL_CFLAGS += \ + -DBOARD_HAVE_BLUETOOTH_BCM +endif + +LOCAL_PRELINK_MODULE:=false +LOCAL_SRC_FILES:= \ + ./ulinux/gki_ulinux.c \ + ./common/gki_debug.c \ + ./common/gki_time.c \ + ./common/gki_buffer.c + +LOCAL_MODULE := libbt-brcm_gki +LOCAL_MODULE_TAGS := eng +LOCAL_SHARED_LIBRARIES := libcutils libc + +include $(BUILD_STATIC_LIBRARY) + +endif # TARGET_SIMULATOR != true diff --git a/gki/common/gki.h b/gki/common/gki.h new file mode 100644 index 0000000..a3272d5 --- /dev/null +++ b/gki/common/gki.h @@ -0,0 +1,490 @@ +/**************************************************************************** +** +** Name gki.h +** +** Function This file contains GKI public definitions +** +** +** Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ +#ifndef GKI_H +#define GKI_H + +#ifdef BUILDCFG +#include "buildcfg.h" +#endif + +/* Include platform-specific over-rides */ +#if (defined(NFC_STANDALONE) && (NFC_STANDALONE == TRUE)) + #include "gki_target.h" +#else + /* For non-nfc_standalone, include Bluetooth definitions */ + #include "bt_target.h" +#endif + + + +#include "bt_types.h" + +/* Error codes */ +#define GKI_SUCCESS 0x00 +#define GKI_FAILURE 0x01 +#define GKI_INVALID_TASK 0xF0 +#define GKI_INVALID_POOL 0xFF + + +/************************************************************************ +** Mailbox definitions. Each task has 4 mailboxes that are used to +** send buffers to the task. +*/ +#define TASK_MBOX_0 0 +#define TASK_MBOX_1 1 +#define TASK_MBOX_2 2 +#define TASK_MBOX_3 3 + +#define NUM_TASK_MBOX 4 + +/************************************************************************ +** Event definitions. +** +** There are 4 reserved events used to signal messages rcvd in task mailboxes. +** There are 4 reserved events used to signal timeout events. +** There are 8 general purpose events available for applications. +*/ +#define MAX_EVENTS 16 + +#define TASK_MBOX_0_EVT_MASK 0x0001 +#define TASK_MBOX_1_EVT_MASK 0x0002 +#define TASK_MBOX_2_EVT_MASK 0x0004 +#define TASK_MBOX_3_EVT_MASK 0x0008 + + +#define TIMER_0 0 +#define TIMER_1 1 +#define TIMER_2 2 +#define TIMER_3 3 + +#define TIMER_0_EVT_MASK 0x0010 +#define TIMER_1_EVT_MASK 0x0020 +#define TIMER_2_EVT_MASK 0x0040 +#define TIMER_3_EVT_MASK 0x0080 + +#define APPL_EVT_0 8 +#define APPL_EVT_1 9 +#define APPL_EVT_2 10 +#define APPL_EVT_3 11 +#define APPL_EVT_4 12 +#define APPL_EVT_5 13 +#define APPL_EVT_6 14 +#define APPL_EVT_7 15 + +#define EVENT_MASK(evt) ((UINT16)(0x0001 << (evt))) + +/************************************************************************ +** Max Time Queue +**/ +#ifndef GKI_MAX_TIMER_QUEUES +#define GKI_MAX_TIMER_QUEUES 3 +#endif + +/************************************************************************ +** Macro to determine the pool buffer size based on the GKI POOL ID at compile time. +** Pool IDs index from 0 to GKI_NUM_FIXED_BUF_POOLS - 1 +*/ + +#if (GKI_NUM_FIXED_BUF_POOLS < 1) + +#ifndef GKI_POOL_ID_0 +#define GKI_POOL_ID_0 0 +#endif /* ifndef GKI_POOL_ID_0 */ + +#ifndef GKI_BUF0_SIZE +#define GKI_BUF0_SIZE 0 +#endif /* ifndef GKI_BUF0_SIZE */ + +#endif /* GKI_NUM_FIXED_BUF_POOLS < 1 */ + + +#if (GKI_NUM_FIXED_BUF_POOLS < 2) + +#ifndef GKI_POOL_ID_1 +#define GKI_POOL_ID_1 0 +#endif /* ifndef GKI_POOL_ID_1 */ + +#ifndef GKI_BUF1_SIZE +#define GKI_BUF1_SIZE 0 +#endif /* ifndef GKI_BUF1_SIZE */ + +#endif /* GKI_NUM_FIXED_BUF_POOLS < 2 */ + + +#if (GKI_NUM_FIXED_BUF_POOLS < 3) + +#ifndef GKI_POOL_ID_2 +#define GKI_POOL_ID_2 0 +#endif /* ifndef GKI_POOL_ID_2 */ + +#ifndef GKI_BUF2_SIZE +#define GKI_BUF2_SIZE 0 +#endif /* ifndef GKI_BUF2_SIZE */ + +#endif /* GKI_NUM_FIXED_BUF_POOLS < 3 */ + + +#if (GKI_NUM_FIXED_BUF_POOLS < 4) + +#ifndef GKI_POOL_ID_3 +#define GKI_POOL_ID_3 0 +#endif /* ifndef GKI_POOL_ID_4 */ + +#ifndef GKI_BUF3_SIZE +#define GKI_BUF3_SIZE 0 +#endif /* ifndef GKI_BUF3_SIZE */ + +#endif /* GKI_NUM_FIXED_BUF_POOLS < 4 */ + + +#if (GKI_NUM_FIXED_BUF_POOLS < 5) + +#ifndef GKI_POOL_ID_4 +#define GKI_POOL_ID_4 0 +#endif /* ifndef GKI_POOL_ID_4 */ + +#ifndef GKI_BUF4_SIZE +#define GKI_BUF4_SIZE 0 +#endif /* ifndef GKI_BUF4_SIZE */ + +#endif /* GKI_NUM_FIXED_BUF_POOLS < 5 */ + + +#if (GKI_NUM_FIXED_BUF_POOLS < 6) + +#ifndef GKI_POOL_ID_5 +#define GKI_POOL_ID_5 0 +#endif /* ifndef GKI_POOL_ID_5 */ + +#ifndef GKI_BUF5_SIZE +#define GKI_BUF5_SIZE 0 +#endif /* ifndef GKI_BUF5_SIZE */ + +#endif /* GKI_NUM_FIXED_BUF_POOLS < 6 */ + + +#if (GKI_NUM_FIXED_BUF_POOLS < 7) + +#ifndef GKI_POOL_ID_6 +#define GKI_POOL_ID_6 0 +#endif /* ifndef GKI_POOL_ID_6 */ + +#ifndef GKI_BUF6_SIZE +#define GKI_BUF6_SIZE 0 +#endif /* ifndef GKI_BUF6_SIZE */ + +#endif /* GKI_NUM_FIXED_BUF_POOLS < 7 */ + + +#if (GKI_NUM_FIXED_BUF_POOLS < 8) + +#ifndef GKI_POOL_ID_7 +#define GKI_POOL_ID_7 0 +#endif /* ifndef GKI_POOL_ID_7 */ + +#ifndef GKI_BUF7_SIZE +#define GKI_BUF7_SIZE 0 +#endif /* ifndef GKI_BUF7_SIZE */ + +#endif /* GKI_NUM_FIXED_BUF_POOLS < 8 */ + + +#if (GKI_NUM_FIXED_BUF_POOLS < 9) + +#ifndef GKI_POOL_ID_8 +#define GKI_POOL_ID_8 0 +#endif /* ifndef GKI_POOL_ID_8 */ + +#ifndef GKI_BUF8_SIZE +#define GKI_BUF8_SIZE 0 +#endif /* ifndef GKI_BUF8_SIZE */ + +#endif /* GKI_NUM_FIXED_BUF_POOLS < 9 */ + + +#if (GKI_NUM_FIXED_BUF_POOLS < 10) + +#ifndef GKI_POOL_ID_9 +#define GKI_POOL_ID_9 0 +#endif /* ifndef GKI_POOL_ID_9 */ + +#ifndef GKI_BUF9_SIZE +#define GKI_BUF9_SIZE 0 +#endif /* ifndef GKI_BUF9_SIZE */ + +#endif /* GKI_NUM_FIXED_BUF_POOLS < 10 */ + + +#if (GKI_NUM_FIXED_BUF_POOLS < 11) + +#ifndef GKI_POOL_ID_10 +#define GKI_POOL_ID_10 0 +#endif /* ifndef GKI_POOL_ID_10 */ + +#ifndef GKI_BUF10_SIZE +#define GKI_BUF10_SIZE 0 +#endif /* ifndef GKI_BUF10_SIZE */ + +#endif /* GKI_NUM_FIXED_BUF_POOLS < 11 */ + + +#if (GKI_NUM_FIXED_BUF_POOLS < 12) + +#ifndef GKI_POOL_ID_11 +#define GKI_POOL_ID_11 0 +#endif /* ifndef GKI_POOL_ID_11 */ + +#ifndef GKI_BUF11_SIZE +#define GKI_BUF11_SIZE 0 +#endif /* ifndef GKI_BUF11_SIZE */ + +#endif /* GKI_NUM_FIXED_BUF_POOLS < 12 */ + + +#if (GKI_NUM_FIXED_BUF_POOLS < 13) + +#ifndef GKI_POOL_ID_12 +#define GKI_POOL_ID_12 0 +#endif /* ifndef GKI_POOL_ID_12 */ + +#ifndef GKI_BUF12_SIZE +#define GKI_BUF12_SIZE 0 +#endif /* ifndef GKI_BUF12_SIZE */ + +#endif /* GKI_NUM_FIXED_BUF_POOLS < 13 */ + + +#if (GKI_NUM_FIXED_BUF_POOLS < 14) + +#ifndef GKI_POOL_ID_13 +#define GKI_POOL_ID_13 0 +#endif /* ifndef GKI_POOL_ID_13 */ + +#ifndef GKI_BUF13_SIZE +#define GKI_BUF13_SIZE 0 +#endif /* ifndef GKI_BUF13_SIZE */ + +#endif /* GKI_NUM_FIXED_BUF_POOLS < 14 */ + + +#if (GKI_NUM_FIXED_BUF_POOLS < 15) + +#ifndef GKI_POOL_ID_14 +#define GKI_POOL_ID_14 0 +#endif /* ifndef GKI_POOL_ID_14 */ + +#ifndef GKI_BUF14_SIZE +#define GKI_BUF14_SIZE 0 +#endif /* ifndef GKI_BUF14_SIZE */ + +#endif /* GKI_NUM_FIXED_BUF_POOLS < 15 */ + + +#if (GKI_NUM_FIXED_BUF_POOLS < 16) + +#ifndef GKI_POOL_ID_15 +#define GKI_POOL_ID_15 0 +#endif /* ifndef GKI_POOL_ID_15 */ + +#ifndef GKI_BUF15_SIZE +#define GKI_BUF15_SIZE 0 +#endif /* ifndef GKI_BUF15_SIZE */ + +#endif /* GKI_NUM_FIXED_BUF_POOLS < 16 */ + + +/* Timer list entry callback type +*/ +typedef void (TIMER_CBACK)(void *p_tle); +#ifndef TIMER_PARAM_TYPE +#ifdef WIN2000 +#define TIMER_PARAM_TYPE void * +#else +#define TIMER_PARAM_TYPE UINT32 +#endif +#endif +/* Define a timer list entry +*/ +typedef struct _tle +{ + struct _tle *p_next; + struct _tle *p_prev; + TIMER_CBACK *p_cback; + INT32 ticks; + TIMER_PARAM_TYPE param; + UINT16 event; + UINT8 in_use; +} TIMER_LIST_ENT; + +/* Define a timer list queue +*/ +typedef struct +{ + TIMER_LIST_ENT *p_first; + TIMER_LIST_ENT *p_last; + INT32 last_ticks; +} TIMER_LIST_Q; + + +/*********************************************************************** +** This queue is a general purpose buffer queue, for application use. +*/ +typedef struct +{ + void *p_first; + void *p_last; + UINT16 count; +} BUFFER_Q; + +#define GKI_IS_QUEUE_EMPTY(p_q) ((p_q)->count == 0) + +/* Task constants +*/ +#ifndef TASKPTR +typedef void (*TASKPTR)(UINT32); +#endif + + +#define GKI_PUBLIC_POOL 0 /* General pool accessible to GKI_getbuf() */ +#define GKI_RESTRICTED_POOL 1 /* Inaccessible pool to GKI_getbuf() */ + +/*********************************************************************** +** Function prototypes +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Task management +*/ +GKI_API extern UINT8 GKI_create_task (TASKPTR, UINT8, INT8 *, UINT16 *, UINT16); +GKI_API extern void GKI_destroy_task(UINT8 task_id); +GKI_API extern void GKI_exit_task(UINT8); +GKI_API extern UINT8 GKI_get_taskid(void); +GKI_API extern void GKI_init(void); +GKI_API extern void GKI_shutdown(void); +GKI_API extern INT8 *GKI_map_taskname(UINT8); +GKI_API extern UINT8 GKI_resume_task(UINT8); +GKI_API extern void GKI_run(void *); +GKI_API extern void GKI_freeze(void); +GKI_API extern void GKI_stop(void); +GKI_API extern UINT8 GKI_suspend_task(UINT8); +GKI_API extern UINT8 GKI_is_task_running(UINT8); + +/* memory management +*/ +GKI_API extern void GKI_shiftdown (UINT8 *p_mem, UINT32 len, UINT32 shift_amount); +GKI_API extern void GKI_shiftup (UINT8 *p_dest, UINT8 *p_src, UINT32 len); + +/* To send buffers and events between tasks +*/ +GKI_API extern UINT8 GKI_isend_event (UINT8, UINT16); +GKI_API extern void GKI_isend_msg (UINT8, UINT8, void *); +GKI_API extern void *GKI_read_mbox (UINT8); +GKI_API extern void GKI_send_msg (UINT8, UINT8, void *); +GKI_API extern UINT8 GKI_send_event (UINT8, UINT16); + + +/* To get and release buffers, change owner and get size +*/ +GKI_API extern void GKI_change_buf_owner (void *, UINT8); +GKI_API extern UINT8 GKI_create_pool (UINT16, UINT16, UINT8, void *); +GKI_API extern void GKI_delete_pool (UINT8); +GKI_API extern void *GKI_find_buf_start (void *); +GKI_API extern void GKI_freebuf (void *); +GKI_API extern void *GKI_getbuf (UINT16); +GKI_API extern UINT16 GKI_get_buf_size (void *); +GKI_API extern void *GKI_getpoolbuf (UINT8); +GKI_API extern UINT16 GKI_poolcount (UINT8); +GKI_API extern UINT16 GKI_poolfreecount (UINT8); +GKI_API extern UINT16 GKI_poolutilization (UINT8); +GKI_API extern void GKI_register_mempool (void *p_mem); +GKI_API extern UINT8 GKI_set_pool_permission(UINT8, UINT8); + + +/* User buffer queue management +*/ +GKI_API extern void *GKI_dequeue (BUFFER_Q *); +GKI_API extern void GKI_enqueue (BUFFER_Q *, void *); +GKI_API extern void GKI_enqueue_head (BUFFER_Q *, void *); +GKI_API extern void *GKI_getfirst (BUFFER_Q *); +GKI_API extern void *GKI_getlast (BUFFER_Q *); +GKI_API extern void *GKI_getnext (void *); +GKI_API extern void GKI_init_q (BUFFER_Q *); +GKI_API extern BOOLEAN GKI_queue_is_empty(BUFFER_Q *); +GKI_API extern void *GKI_remove_from_queue (BUFFER_Q *, void *); +GKI_API extern UINT16 GKI_get_pool_bufsize (UINT8); + +/* Timer management +*/ +GKI_API extern void GKI_add_to_timer_list (TIMER_LIST_Q *, TIMER_LIST_ENT *); +GKI_API extern void GKI_delay(UINT32); +GKI_API extern UINT32 GKI_get_tick_count(void); +GKI_API extern INT8 *GKI_get_time_stamp(INT8 *); +GKI_API extern void GKI_init_timer_list (TIMER_LIST_Q *); +GKI_API extern void GKI_init_timer_list_entry (TIMER_LIST_ENT *); +GKI_API extern INT32 GKI_ready_to_sleep (void); +GKI_API extern void GKI_remove_from_timer_list (TIMER_LIST_Q *, TIMER_LIST_ENT *); +GKI_API extern void GKI_start_timer(UINT8, INT32, BOOLEAN); +GKI_API extern void GKI_stop_timer (UINT8); +GKI_API extern void GKI_timer_update(INT32); +GKI_API extern UINT16 GKI_update_timer_list (TIMER_LIST_Q *, INT32); +GKI_API extern UINT32 GKI_get_remaining_ticks (TIMER_LIST_Q *, TIMER_LIST_ENT *); +GKI_API extern UINT16 GKI_wait(UINT16, UINT32); + +/* Start and Stop system time tick callback + * true for start system tick if time queue is not empty + * false to stop system tick if time queue is empty +*/ +typedef void (SYSTEM_TICK_CBACK)(BOOLEAN); + +/* Time queue management for system ticks +*/ +GKI_API extern BOOLEAN GKI_timer_queue_empty (void); +GKI_API extern void GKI_timer_queue_register_callback(SYSTEM_TICK_CBACK *); + +/* Disable Interrupts, Enable Interrupts +*/ +GKI_API extern void GKI_enable(void); +GKI_API extern void GKI_disable(void); +GKI_API extern void GKI_sched_lock(void); +GKI_API extern void GKI_sched_unlock(void); + +/* Allocate (Free) memory from an OS +*/ +GKI_API extern void *GKI_os_malloc (UINT32); +GKI_API extern void GKI_os_free (void *); + +/* os timer operation */ +GKI_API extern UINT32 GKI_get_os_tick_count(void); + +/* Exception handling +*/ +GKI_API extern void GKI_exception (UINT16, char *); + +#if GKI_DEBUG == TRUE +GKI_API extern void GKI_PrintBufferUsage(UINT8 *p_num_pools, UINT16 *p_cur_used); +GKI_API extern void GKI_PrintBuffer(void); +GKI_API extern void GKI_print_task(void); +#else +#undef GKI_PrintBufferUsage +#define GKI_PrintBuffer() NULL +#endif + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/gki/common/gki_buffer.c b/gki/common/gki_buffer.c new file mode 100644 index 0000000..a32c275 --- /dev/null +++ b/gki/common/gki_buffer.c @@ -0,0 +1,1474 @@ +/******************************************************************************** +** * +** Name gki_buffer.c * +** * +** Function this file contains GKI buffer handling functions * +** * +** * +** Copyright (c) 1999-2009, Broadcom Corp., All Rights Reserved. * +** Proprietary and confidential. * +** * +*********************************************************************************/ +#include "gki_int.h" + +#if (GKI_NUM_TOTAL_BUF_POOLS > 16) +#error Number of pools out of range (16 Max)! +#endif + +static void gki_add_to_pool_list(UINT8 pool_id); +static void gki_remove_from_pool_list(UINT8 pool_id); + +/******************************************************************************* +** +** Function gki_init_free_queue +** +** Description Internal function called at startup to initialize a free +** queue. It is called once for each free queue. +** +** Returns void +** +*******************************************************************************/ +static void gki_init_free_queue (UINT8 id, UINT16 size, UINT16 total, void *p_mem) +{ + UINT16 i; + UINT16 act_size; + BUFFER_HDR_T *hdr; + BUFFER_HDR_T *hdr1 = NULL; + UINT32 *magic; + INT32 tempsize = size; + tGKI_COM_CB *p_cb = &gki_cb.com; + + /* Ensure an even number of longwords */ + tempsize = (INT32)ALIGN_POOL(size); + act_size = (UINT16)(tempsize + BUFFER_PADDING_SIZE); + + /* Remember pool start and end addresses */ +// btla-specific ++ + if(p_mem) + { + p_cb->pool_start[id] = (UINT8 *)p_mem; + p_cb->pool_end[id] = (UINT8 *)p_mem + (act_size * total); + } +// btla-specific -- + + p_cb->pool_size[id] = act_size; + + p_cb->freeq[id].size = (UINT16) tempsize; + p_cb->freeq[id].total = total; + p_cb->freeq[id].cur_cnt = 0; + p_cb->freeq[id].max_cnt = 0; + + /* Initialize index table */ +// btla-specific ++ + if(p_mem) + { + hdr = (BUFFER_HDR_T *)p_mem; + p_cb->freeq[id].p_first = hdr; + for (i = 0; i < total; i++) + { + hdr->task_id = GKI_INVALID_TASK; + hdr->q_id = id; + hdr->status = BUF_STATUS_FREE; + magic = (UINT32 *)((UINT8 *)hdr + BUFFER_HDR_SIZE + tempsize); + *magic = MAGIC_NO; + hdr1 = hdr; + hdr = (BUFFER_HDR_T *)((UINT8 *)hdr + act_size); + hdr1->p_next = hdr; + } + hdr1->p_next = NULL; + p_cb->freeq[id].p_last = hdr1; + } +// btla-specific -- + return; +} + +// btla-specific ++ +#ifdef GKI_USE_DEFERED_ALLOC_BUF_POOLS +static BOOLEAN gki_alloc_free_queue(UINT8 id) +{ + FREE_QUEUE_T *Q; + tGKI_COM_CB *p_cb = &gki_cb.com; + GKI_TRACE("\ngki_alloc_free_queue in, id:%d \n", id); + + Q = &p_cb->freeq[p_cb->pool_list[id]]; + + if(Q->p_first == 0) + { + void* p_mem = GKI_os_malloc((Q->size + BUFFER_PADDING_SIZE) * Q->total); + if(p_mem) + { + //re-initialize the queue with allocated memory + GKI_TRACE("\ngki_alloc_free_queue calling gki_init_free_queue, id:%d size:%d, totol:%d\n", id, Q->size, Q->total); + gki_init_free_queue(id, Q->size, Q->total, p_mem); + GKI_TRACE("\ngki_alloc_free_queue ret OK, id:%d size:%d, totol:%d\n", id, Q->size, Q->total); + return TRUE; + } + GKI_exception (GKI_ERROR_BUF_SIZE_TOOBIG, "gki_alloc_free_queue: Not enough memory"); + } + GKI_TRACE("\ngki_alloc_free_queue out failed, id:%d\n", id); + return FALSE; +} + +void gki_dealloc_free_queue(void) +{ + UINT8 i; + tGKI_COM_CB *p_cb = &gki_cb.com; + + for (i=0; i < p_cb->curr_total_no_of_pools; i++) + { + if ( 0 < p_cb->freeq[i].max_cnt ) + { + GKI_os_free(p_cb->pool_start[i]); + + p_cb->freeq[i].cur_cnt = 0; + p_cb->freeq[i].max_cnt = 0; + p_cb->freeq[i].p_first = NULL; + p_cb->freeq[i].p_last = NULL; + + p_cb->pool_start[i] = NULL; + p_cb->pool_end[i] = NULL; + p_cb->pool_size[i] = 0; + } + } +} + +#endif +// btla-specific -- + +/******************************************************************************* +** +** Function gki_buffer_init +** +** Description Called once internally by GKI at startup to initialize all +** buffers and free buffer pools. +** +** Returns void +** +*******************************************************************************/ +void gki_buffer_init(void) +{ + UINT8 i, tt, mb; + tGKI_COM_CB *p_cb = &gki_cb.com; + + /* Initialize mailboxes */ + for (tt = 0; tt < GKI_MAX_TASKS; tt++) + { + for (mb = 0; mb < NUM_TASK_MBOX; mb++) + { + p_cb->OSTaskQFirst[tt][mb] = NULL; + p_cb->OSTaskQLast [tt][mb] = NULL; + } + } + + for (tt = 0; tt < GKI_NUM_TOTAL_BUF_POOLS; tt++) + { + p_cb->pool_start[tt] = NULL; + p_cb->pool_end[tt] = NULL; + p_cb->pool_size[tt] = 0; + + p_cb->freeq[tt].p_first = 0; + p_cb->freeq[tt].p_last = 0; + p_cb->freeq[tt].size = 0; + p_cb->freeq[tt].total = 0; + p_cb->freeq[tt].cur_cnt = 0; + p_cb->freeq[tt].max_cnt = 0; + } + + /* Use default from target.h */ + p_cb->pool_access_mask = GKI_DEF_BUFPOOL_PERM_MASK; + +// btla-specific ++ +#if (!defined GKI_USE_DEFERED_ALLOC_BUF_POOLS && (GKI_USE_DYNAMIC_BUFFERS == TRUE)) +// btla-specific -- + +#if (GKI_NUM_FIXED_BUF_POOLS > 0) + p_cb->bufpool0 = (UINT8 *)GKI_os_malloc ((GKI_BUF0_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF0_MAX); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 1) + p_cb->bufpool1 = (UINT8 *)GKI_os_malloc ((GKI_BUF1_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF1_MAX); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 2) + p_cb->bufpool2 = (UINT8 *)GKI_os_malloc ((GKI_BUF2_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF2_MAX); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 3) + p_cb->bufpool3 = (UINT8 *)GKI_os_malloc ((GKI_BUF3_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF3_MAX); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 4) + p_cb->bufpool4 = (UINT8 *)GKI_os_malloc ((GKI_BUF4_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF4_MAX); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 5) + p_cb->bufpool5 = (UINT8 *)GKI_os_malloc ((GKI_BUF5_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF5_MAX); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 6) + p_cb->bufpool6 = (UINT8 *)GKI_os_malloc ((GKI_BUF6_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF6_MAX); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 7) + p_cb->bufpool7 = (UINT8 *)GKI_os_malloc ((GKI_BUF7_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF7_MAX); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 8) + p_cb->bufpool8 = (UINT8 *)GKI_os_malloc ((GKI_BUF8_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF8_MAX); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 9) + p_cb->bufpool9 = (UINT8 *)GKI_os_malloc ((GKI_BUF9_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF9_MAX); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 10) + p_cb->bufpool10 = (UINT8 *)GKI_os_malloc ((GKI_BUF10_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF10_MAX); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 11) + p_cb->bufpool11 = (UINT8 *)GKI_os_malloc ((GKI_BUF11_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF11_MAX); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 12) + p_cb->bufpool12 = (UINT8 *)GKI_os_malloc ((GKI_BUF12_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF12_MAX); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 13) + p_cb->bufpool13 = (UINT8 *)GKI_os_malloc ((GKI_BUF13_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF13_MAX); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 14) + p_cb->bufpool14 = (UINT8 *)GKI_os_malloc ((GKI_BUF14_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF14_MAX); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 15) + p_cb->bufpool15 = (UINT8 *)GKI_os_malloc ((GKI_BUF15_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF15_MAX); +#endif + +#endif + + +#if (GKI_NUM_FIXED_BUF_POOLS > 0) + gki_init_free_queue(0, GKI_BUF0_SIZE, GKI_BUF0_MAX, p_cb->bufpool0); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 1) + gki_init_free_queue(1, GKI_BUF1_SIZE, GKI_BUF1_MAX, p_cb->bufpool1); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 2) + gki_init_free_queue(2, GKI_BUF2_SIZE, GKI_BUF2_MAX, p_cb->bufpool2); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 3) + gki_init_free_queue(3, GKI_BUF3_SIZE, GKI_BUF3_MAX, p_cb->bufpool3); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 4) + gki_init_free_queue(4, GKI_BUF4_SIZE, GKI_BUF4_MAX, p_cb->bufpool4); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 5) + gki_init_free_queue(5, GKI_BUF5_SIZE, GKI_BUF5_MAX, p_cb->bufpool5); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 6) + gki_init_free_queue(6, GKI_BUF6_SIZE, GKI_BUF6_MAX, p_cb->bufpool6); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 7) + gki_init_free_queue(7, GKI_BUF7_SIZE, GKI_BUF7_MAX, p_cb->bufpool7); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 8) + gki_init_free_queue(8, GKI_BUF8_SIZE, GKI_BUF8_MAX, p_cb->bufpool8); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 9) + gki_init_free_queue(9, GKI_BUF9_SIZE, GKI_BUF9_MAX, p_cb->bufpool9); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 10) + gki_init_free_queue(10, GKI_BUF10_SIZE, GKI_BUF10_MAX, p_cb->bufpool10); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 11) + gki_init_free_queue(11, GKI_BUF11_SIZE, GKI_BUF11_MAX, p_cb->bufpool11); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 12) + gki_init_free_queue(12, GKI_BUF12_SIZE, GKI_BUF12_MAX, p_cb->bufpool12); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 13) + gki_init_free_queue(13, GKI_BUF13_SIZE, GKI_BUF13_MAX, p_cb->bufpool13); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 14) + gki_init_free_queue(14, GKI_BUF14_SIZE, GKI_BUF14_MAX, p_cb->bufpool14); +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 15) + gki_init_free_queue(15, GKI_BUF15_SIZE, GKI_BUF15_MAX, p_cb->bufpool15); +#endif + + /* add pools to the pool_list which is arranged in the order of size */ + for(i=0; i < GKI_NUM_FIXED_BUF_POOLS ; i++) + { + p_cb->pool_list[i] = i; + } + + p_cb->curr_total_no_of_pools = GKI_NUM_FIXED_BUF_POOLS; + + return; +} + + +/******************************************************************************* +** +** Function GKI_init_q +** +** Description Called by an application to initialize a buffer queue. +** +** Returns void +** +*******************************************************************************/ +void GKI_init_q (BUFFER_Q *p_q) +{ + p_q->p_first = p_q->p_last = NULL; + p_q->count = 0; + + return; +} + + +/******************************************************************************* +** +** Function GKI_getbuf +** +** Description Called by an application to get a free buffer which +** is of size greater or equal to the requested size. +** +** Note: This routine only takes buffers from public pools. +** It will not use any buffers from pools +** marked GKI_RESTRICTED_POOL. +** +** Parameters size - (input) number of bytes needed. +** +** Returns A pointer to the buffer, or NULL if none available +** +*******************************************************************************/ +void *GKI_getbuf (UINT16 size) +{ + UINT8 i; + FREE_QUEUE_T *Q; + BUFFER_HDR_T *p_hdr; + tGKI_COM_CB *p_cb = &gki_cb.com; + + if (size == 0) + { + GKI_exception (GKI_ERROR_BUF_SIZE_ZERO, "getbuf: Size is zero"); + return (NULL); + } + + /* Find the first buffer pool that is public that can hold the desired size */ + for (i=0; i < p_cb->curr_total_no_of_pools; i++) + { + if ( size <= p_cb->freeq[p_cb->pool_list[i]].size ) + break; + } + + if(i == p_cb->curr_total_no_of_pools) + { + GKI_exception (GKI_ERROR_BUF_SIZE_TOOBIG, "getbuf: Size is too big"); + return (NULL); + } + + /* Make sure the buffers aren't disturbed til finished with allocation */ + GKI_disable(); + + /* search the public buffer pools that are big enough to hold the size + * until a free buffer is found */ + for ( ; i < p_cb->curr_total_no_of_pools; i++) + { + /* Only look at PUBLIC buffer pools (bypass RESTRICTED pools) */ + if (((UINT16)1 << p_cb->pool_list[i]) & p_cb->pool_access_mask) + continue; + + Q = &p_cb->freeq[p_cb->pool_list[i]]; + if(Q->cur_cnt < Q->total) + { +// btla-specific ++ + #ifdef GKI_USE_DEFERED_ALLOC_BUF_POOLS + if(Q->p_first == 0 && gki_alloc_free_queue(i) != TRUE) + return NULL; + #endif +// btla-specific -- + p_hdr = Q->p_first; + Q->p_first = p_hdr->p_next; + + if (!Q->p_first) + Q->p_last = NULL; + + if(++Q->cur_cnt > Q->max_cnt) + Q->max_cnt = Q->cur_cnt; + + GKI_enable(); + + p_hdr->task_id = GKI_get_taskid(); + + p_hdr->status = BUF_STATUS_UNLINKED; + p_hdr->p_next = NULL; + p_hdr->Type = 0; + + return ((void *) ((UINT8 *)p_hdr + BUFFER_HDR_SIZE)); + } + } + + GKI_enable(); + + return (NULL); +} + + +/******************************************************************************* +** +** Function GKI_getpoolbuf +** +** Description Called by an application to get a free buffer from +** a specific buffer pool. +** +** Note: If there are no more buffers available from the pool, +** the public buffers are searched for an available buffer. +** +** Parameters pool_id - (input) pool ID to get a buffer out of. +** +** Returns A pointer to the buffer, or NULL if none available +** +*******************************************************************************/ +void *GKI_getpoolbuf (UINT8 pool_id) +{ + FREE_QUEUE_T *Q; + BUFFER_HDR_T *p_hdr; + tGKI_COM_CB *p_cb = &gki_cb.com; + + if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS) + return (NULL); + + /* Make sure the buffers aren't disturbed til finished with allocation */ + GKI_disable(); + + Q = &p_cb->freeq[pool_id]; + if(Q->cur_cnt < Q->total) + { +// btla-specific ++ +#ifdef GKI_USE_DEFERED_ALLOC_BUF_POOLS + if(Q->p_first == 0 && gki_alloc_free_queue(pool_id) != TRUE) + return NULL; +#endif +// btla-specific -- + p_hdr = Q->p_first; + Q->p_first = p_hdr->p_next; + + if (!Q->p_first) + Q->p_last = NULL; + + if(++Q->cur_cnt > Q->max_cnt) + Q->max_cnt = Q->cur_cnt; + + GKI_enable(); + + + p_hdr->task_id = GKI_get_taskid(); + + p_hdr->status = BUF_STATUS_UNLINKED; + p_hdr->p_next = NULL; + p_hdr->Type = 0; + + return ((void *) ((UINT8 *)p_hdr + BUFFER_HDR_SIZE)); + } + + /* If here, no buffers in the specified pool */ + GKI_enable(); + + /* try for free buffers in public pools */ + return (GKI_getbuf(p_cb->freeq[pool_id].size)); + +} + +/******************************************************************************* +** +** Function GKI_freebuf +** +** Description Called by an application to return a buffer to the free pool. +** +** Parameters p_buf - (input) address of the beginning of a buffer. +** +** Returns void +** +*******************************************************************************/ +void GKI_freebuf (void *p_buf) +{ + FREE_QUEUE_T *Q; + BUFFER_HDR_T *p_hdr; + +#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE) + if (!p_buf || gki_chk_buf_damage(p_buf)) + { + GKI_exception(GKI_ERROR_BUF_CORRUPTED, "Free - Buf Corrupted"); + return; + } +#endif + + p_hdr = (BUFFER_HDR_T *) ((UINT8 *)p_buf - BUFFER_HDR_SIZE); + + if (p_hdr->status != BUF_STATUS_UNLINKED) + { + GKI_exception(GKI_ERROR_FREEBUF_BUF_LINKED, "Freeing Linked Buf"); + return; + } + + if (p_hdr->q_id >= GKI_NUM_TOTAL_BUF_POOLS) + { + GKI_exception(GKI_ERROR_FREEBUF_BAD_QID, "Bad Buf QId"); + return; + } + + GKI_disable(); + + /* + ** Release the buffer + */ + Q = &gki_cb.com.freeq[p_hdr->q_id]; + if (Q->p_last) + Q->p_last->p_next = p_hdr; + else + Q->p_first = p_hdr; + + Q->p_last = p_hdr; + p_hdr->p_next = NULL; + p_hdr->status = BUF_STATUS_FREE; + p_hdr->task_id = GKI_INVALID_TASK; + if (Q->cur_cnt > 0) + Q->cur_cnt--; + + GKI_enable(); + + return; +} + + +/******************************************************************************* +** +** Function GKI_get_buf_size +** +** Description Called by an application to get the size of a buffer. +** +** Parameters p_buf - (input) address of the beginning of a buffer. +** +** Returns the size of the buffer +** +*******************************************************************************/ +UINT16 GKI_get_buf_size (void *p_buf) +{ + BUFFER_HDR_T *p_hdr; + + p_hdr = (BUFFER_HDR_T *)((UINT8 *) p_buf - BUFFER_HDR_SIZE); + + if ((UINT32)p_hdr & 1) + return (0); + + if (p_hdr->q_id < GKI_NUM_TOTAL_BUF_POOLS) + { + return (gki_cb.com.freeq[p_hdr->q_id].size); + } + + return (0); +} + +/******************************************************************************* +** +** Function gki_chk_buf_damage +** +** Description Called internally by OSS to check for buffer corruption. +** +** Returns TRUE if there is a problem, else FALSE +** +*******************************************************************************/ +BOOLEAN gki_chk_buf_damage(void *p_buf) +{ +#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE) + + UINT32 *magic; + magic = (UINT32 *)((UINT8 *) p_buf + GKI_get_buf_size(p_buf)); + + if ((UINT32)magic & 1) + return (TRUE); + + if (*magic == MAGIC_NO) + return (FALSE); + + return (TRUE); + +#else + + return (FALSE); + +#endif +} + +/******************************************************************************* +** +** Function GKI_send_msg +** +** Description Called by applications to send a buffer to a task +** +** Returns Nothing +** +*******************************************************************************/ +void GKI_send_msg (UINT8 task_id, UINT8 mbox, void *msg) +{ + BUFFER_HDR_T *p_hdr; + tGKI_COM_CB *p_cb = &gki_cb.com; + + /* If task non-existant or not started, drop buffer */ + if ((task_id >= GKI_MAX_TASKS) || (mbox >= NUM_TASK_MBOX) || (p_cb->OSRdyTbl[task_id] == TASK_DEAD)) + { + GKI_exception(GKI_ERROR_SEND_MSG_BAD_DEST, "Sending to unknown dest"); + GKI_freebuf (msg); + return; + } + +#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE) + if (gki_chk_buf_damage(msg)) + { + GKI_exception(GKI_ERROR_BUF_CORRUPTED, "Send - Buffer corrupted"); + return; + } +#endif + + p_hdr = (BUFFER_HDR_T *) ((UINT8 *) msg - BUFFER_HDR_SIZE); + + if (p_hdr->status != BUF_STATUS_UNLINKED) + { + GKI_exception(GKI_ERROR_SEND_MSG_BUF_LINKED, "Send - buffer linked"); + return; + } + + GKI_disable(); + + if (p_cb->OSTaskQFirst[task_id][mbox]) + p_cb->OSTaskQLast[task_id][mbox]->p_next = p_hdr; + else + p_cb->OSTaskQFirst[task_id][mbox] = p_hdr; + + p_cb->OSTaskQLast[task_id][mbox] = p_hdr; + + p_hdr->p_next = NULL; + p_hdr->status = BUF_STATUS_QUEUED; + p_hdr->task_id = task_id; + + + GKI_enable(); + + GKI_send_event(task_id, (UINT16)EVENT_MASK(mbox)); + + return; +} + +/******************************************************************************* +** +** Function GKI_read_mbox +** +** Description Called by applications to read a buffer from one of +** the task mailboxes. A task can only read its own mailbox. +** +** Parameters: mbox - (input) mailbox ID to read (0, 1, 2, or 3) +** +** Returns NULL if the mailbox was empty, else the address of a buffer +** +*******************************************************************************/ +void *GKI_read_mbox (UINT8 mbox) +{ + UINT8 task_id = GKI_get_taskid(); + void *p_buf = NULL; + BUFFER_HDR_T *p_hdr; + + if ((task_id >= GKI_MAX_TASKS) || (mbox >= NUM_TASK_MBOX)) + return (NULL); + + GKI_disable(); + + if (gki_cb.com.OSTaskQFirst[task_id][mbox]) + { + p_hdr = gki_cb.com.OSTaskQFirst[task_id][mbox]; + gki_cb.com.OSTaskQFirst[task_id][mbox] = p_hdr->p_next; + + p_hdr->p_next = NULL; + p_hdr->status = BUF_STATUS_UNLINKED; + + p_buf = (UINT8 *)p_hdr + BUFFER_HDR_SIZE; + } + + GKI_enable(); + + return (p_buf); +} + + + +/******************************************************************************* +** +** Function GKI_enqueue +** +** Description Enqueue a buffer at the tail of the queue +** +** Parameters: p_q - (input) pointer to a queue. +** p_buf - (input) address of the buffer to enqueue +** +** Returns void +** +*******************************************************************************/ +void GKI_enqueue (BUFFER_Q *p_q, void *p_buf) +{ + BUFFER_HDR_T *p_hdr; + +#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE) + if (gki_chk_buf_damage(p_buf)) + { + GKI_exception(GKI_ERROR_BUF_CORRUPTED, "Enqueue - Buffer corrupted"); + return; + } +#endif + + p_hdr = (BUFFER_HDR_T *) ((UINT8 *) p_buf - BUFFER_HDR_SIZE); + + if (p_hdr->status != BUF_STATUS_UNLINKED) + { + GKI_exception(GKI_ERROR_ENQUEUE_BUF_LINKED, "Eneueue - buf already linked"); + return; + } + + GKI_disable(); + + /* Since the queue is exposed (C vs C++), keep the pointers in exposed format */ + if (p_q->p_last) + { + BUFFER_HDR_T *p_last_hdr = (BUFFER_HDR_T *)((UINT8 *)p_q->p_last - BUFFER_HDR_SIZE); + p_last_hdr->p_next = p_hdr; + } + else + p_q->p_first = p_buf; + + p_q->p_last = p_buf; + p_q->count++; + + p_hdr->p_next = NULL; + p_hdr->status = BUF_STATUS_QUEUED; + + GKI_enable(); + + return; +} + + +/******************************************************************************* +** +** Function GKI_enqueue_head +** +** Description Enqueue a buffer at the head of the queue +** +** Parameters: p_q - (input) pointer to a queue. +** p_buf - (input) address of the buffer to enqueue +** +** Returns void +** +*******************************************************************************/ +void GKI_enqueue_head (BUFFER_Q *p_q, void *p_buf) +{ + BUFFER_HDR_T *p_hdr; + +#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE) + if (gki_chk_buf_damage(p_buf)) + { + GKI_exception(GKI_ERROR_BUF_CORRUPTED, "Enqueue - Buffer corrupted"); + return; + } +#endif + + p_hdr = (BUFFER_HDR_T *) ((UINT8 *) p_buf - BUFFER_HDR_SIZE); + + if (p_hdr->status != BUF_STATUS_UNLINKED) + { + GKI_exception(GKI_ERROR_ENQUEUE_BUF_LINKED, "Eneueue head - buf already linked"); + return; + } + + GKI_disable(); + + if (p_q->p_first) + { + p_hdr->p_next = (BUFFER_HDR_T *)((UINT8 *)p_q->p_first - BUFFER_HDR_SIZE); + p_q->p_first = p_buf; + } + else + { + p_q->p_first = p_buf; + p_q->p_last = p_buf; + p_hdr->p_next = NULL; + } + p_q->count++; + + p_hdr->status = BUF_STATUS_QUEUED; + + GKI_enable(); + + return; +} + + +/******************************************************************************* +** +** Function GKI_dequeue +** +** Description Dequeues a buffer from the head of a queue +** +** Parameters: p_q - (input) pointer to a queue. +** +** Returns NULL if queue is empty, else buffer +** +*******************************************************************************/ +void *GKI_dequeue (BUFFER_Q *p_q) +{ + BUFFER_HDR_T *p_hdr; + + GKI_disable(); + + if (!p_q || !p_q->count) + { + GKI_enable(); + return (NULL); + } + + p_hdr = (BUFFER_HDR_T *)((UINT8 *)p_q->p_first - BUFFER_HDR_SIZE); + + /* Keep buffers such that GKI header is invisible + */ + if (p_hdr->p_next) + p_q->p_first = ((UINT8 *)p_hdr->p_next + BUFFER_HDR_SIZE); + else + { + p_q->p_first = NULL; + p_q->p_last = NULL; + } + + p_q->count--; + + p_hdr->p_next = NULL; + p_hdr->status = BUF_STATUS_UNLINKED; + + GKI_enable(); + + return ((UINT8 *)p_hdr + BUFFER_HDR_SIZE); +} + + +/******************************************************************************* +** +** Function GKI_remove_from_queue +** +** Description Dequeue a buffer from the middle of the queue +** +** Parameters: p_q - (input) pointer to a queue. +** p_buf - (input) address of the buffer to enqueue +** +** Returns NULL if queue is empty, else buffer +** +*******************************************************************************/ +void *GKI_remove_from_queue (BUFFER_Q *p_q, void *p_buf) +{ + BUFFER_HDR_T *p_prev; + BUFFER_HDR_T *p_buf_hdr; + + GKI_disable(); + + if (p_buf == p_q->p_first) + { + GKI_enable(); + return (GKI_dequeue (p_q)); + } + + p_buf_hdr = (BUFFER_HDR_T *)((UINT8 *)p_buf - BUFFER_HDR_SIZE); + p_prev = (BUFFER_HDR_T *)((UINT8 *)p_q->p_first - BUFFER_HDR_SIZE); + + for ( ; p_prev; p_prev = p_prev->p_next) + { + /* If the previous points to this one, move the pointers around */ + if (p_prev->p_next == p_buf_hdr) + { + p_prev->p_next = p_buf_hdr->p_next; + + /* If we are removing the last guy in the queue, update p_last */ + if (p_buf == p_q->p_last) + p_q->p_last = p_prev + 1; + + /* One less in the queue */ + p_q->count--; + + /* The buffer is now unlinked */ + p_buf_hdr->p_next = NULL; + p_buf_hdr->status = BUF_STATUS_UNLINKED; + + GKI_enable(); + return (p_buf); + } + } + + GKI_enable(); + return (NULL); +} + +/******************************************************************************* +** +** Function GKI_getfirst +** +** Description Return a pointer to the first buffer in a queue +** +** Parameters: p_q - (input) pointer to a queue. +** +** Returns NULL if queue is empty, else buffer address +** +*******************************************************************************/ +void *GKI_getfirst (BUFFER_Q *p_q) +{ + return (p_q->p_first); +} + + +/******************************************************************************* +** +** Function GKI_getlast +** +** Description Return a pointer to the last buffer in a queue +** +** Parameters: p_q - (input) pointer to a queue. +** +** Returns NULL if queue is empty, else buffer address +** +*******************************************************************************/ +void *GKI_getlast (BUFFER_Q *p_q) +{ + return (p_q->p_last); +} + +/******************************************************************************* +** +** Function GKI_getnext +** +** Description Return a pointer to the next buffer in a queue +** +** Parameters: p_buf - (input) pointer to the buffer to find the next one from. +** +** Returns NULL if no more buffers in the queue, else next buffer address +** +*******************************************************************************/ +void *GKI_getnext (void *p_buf) +{ + BUFFER_HDR_T *p_hdr; + + p_hdr = (BUFFER_HDR_T *) ((UINT8 *) p_buf - BUFFER_HDR_SIZE); + + if (p_hdr->p_next) + return ((UINT8 *)p_hdr->p_next + BUFFER_HDR_SIZE); + else + return (NULL); +} + + + +/******************************************************************************* +** +** Function GKI_queue_is_empty +** +** Description Check the status of a queue. +** +** Parameters: p_q - (input) pointer to a queue. +** +** Returns TRUE if queue is empty, else FALSE +** +*******************************************************************************/ +BOOLEAN GKI_queue_is_empty(BUFFER_Q *p_q) +{ + return ((BOOLEAN) (p_q->count == 0)); +} + +/******************************************************************************* +** +** Function GKI_find_buf_start +** +** Description This function is called with an address inside a buffer, +** and returns the start address ofthe buffer. +** +** The buffer should be one allocated from one of GKI's pools. +** +** Parameters: p_user_area - (input) address of anywhere in a GKI buffer. +** +** Returns void * - Address of the beginning of the specified buffer if successful, +** otherwise NULL if unsuccessful +** +*******************************************************************************/ +void *GKI_find_buf_start (void *p_user_area) +{ + UINT16 xx, size; + UINT32 yy; + tGKI_COM_CB *p_cb = &gki_cb.com; + UINT8 *p_ua = (UINT8 *)p_user_area; + + for (xx = 0; xx < GKI_NUM_TOTAL_BUF_POOLS; xx++) + { + if ((p_ua > p_cb->pool_start[xx]) && (p_ua < p_cb->pool_end[xx])) + { + yy = (UINT32)(p_ua - p_cb->pool_start[xx]); + + size = p_cb->pool_size[xx]; + + yy = (yy / size) * size; + + return ((void *) (p_cb->pool_start[xx] + yy + sizeof(BUFFER_HDR_T)) ); + } + } + + /* If here, invalid address - not in one of our buffers */ + GKI_exception (GKI_ERROR_BUF_SIZE_ZERO, "GKI_get_buf_start:: bad addr"); + + return (NULL); +} + + +/******************************************************************************* +** +** Function GKI_set_pool_permission +** +** Description This function is called to set or change the permissions for +** the specified pool ID. +** +** Parameters pool_id - (input) pool ID to be set or changed +** permission - (input) GKI_PUBLIC_POOL or GKI_RESTRICTED_POOL +** +** Returns GKI_SUCCESS if successful +** GKI_INVALID_POOL if unsuccessful +** +*******************************************************************************/ +UINT8 GKI_set_pool_permission(UINT8 pool_id, UINT8 permission) +{ + tGKI_COM_CB *p_cb = &gki_cb.com; + + if (pool_id < GKI_NUM_TOTAL_BUF_POOLS) + { + if (permission == GKI_RESTRICTED_POOL) + p_cb->pool_access_mask = (UINT16)(p_cb->pool_access_mask | (1 << pool_id)); + + else /* mark the pool as public */ + p_cb->pool_access_mask = (UINT16)(p_cb->pool_access_mask & ~(1 << pool_id)); + + return (GKI_SUCCESS); + } + else + return (GKI_INVALID_POOL); +} + +/******************************************************************************* +** +** Function gki_add_to_pool_list +** +** Description Adds pool to the pool list which is arranged in the +** order of size +** +** Returns void +** +*******************************************************************************/ +static void gki_add_to_pool_list(UINT8 pool_id) +{ + + INT32 i, j; + tGKI_COM_CB *p_cb = &gki_cb.com; + + /* Find the position where the specified pool should be inserted into the list */ + for(i=0; i < p_cb->curr_total_no_of_pools; i++) + { + + if(p_cb->freeq[pool_id].size <= p_cb->freeq[ p_cb->pool_list[i] ].size) + break; + } + + /* Insert the new buffer pool ID into the list of pools */ + for(j = p_cb->curr_total_no_of_pools; j > i; j--) + { + p_cb->pool_list[j] = p_cb->pool_list[j-1]; + } + + p_cb->pool_list[i] = pool_id; + + return; +} + +/******************************************************************************* +** +** Function gki_remove_from_pool_list +** +** Description Removes pool from the pool list. Called when a pool is deleted +** +** Returns void +** +*******************************************************************************/ +static void gki_remove_from_pool_list(UINT8 pool_id) +{ + tGKI_COM_CB *p_cb = &gki_cb.com; + UINT8 i; + + for(i=0; i < p_cb->curr_total_no_of_pools; i++) + { + if(pool_id == p_cb->pool_list[i]) + break; + } + + while (i < (p_cb->curr_total_no_of_pools - 1)) + { + p_cb->pool_list[i] = p_cb->pool_list[i+1]; + i++; + } + + return; +} + +/******************************************************************************* +** +** Function GKI_igetpoolbuf +** +** Description Called by an interrupt service routine to get a free buffer from +** a specific buffer pool. +** +** Parameters pool_id - (input) pool ID to get a buffer out of. +** +** Returns A pointer to the buffer, or NULL if none available +** +*******************************************************************************/ +void *GKI_igetpoolbuf (UINT8 pool_id) +{ + FREE_QUEUE_T *Q; + BUFFER_HDR_T *p_hdr; + + if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS) + return (NULL); + + + Q = &gki_cb.com.freeq[pool_id]; + if(Q->cur_cnt < Q->total) + { + p_hdr = Q->p_first; + Q->p_first = p_hdr->p_next; + + if (!Q->p_first) + Q->p_last = NULL; + + if(++Q->cur_cnt > Q->max_cnt) + Q->max_cnt = Q->cur_cnt; + + p_hdr->task_id = GKI_get_taskid(); + + p_hdr->status = BUF_STATUS_UNLINKED; + p_hdr->p_next = NULL; + p_hdr->Type = 0; + + return ((void *) ((UINT8 *)p_hdr + BUFFER_HDR_SIZE)); + } + + return (NULL); +} + +/******************************************************************************* +** +** Function GKI_poolcount +** +** Description Called by an application to get the total number of buffers +** in the specified buffer pool. +** +** Parameters pool_id - (input) pool ID to get the free count of. +** +** Returns the total number of buffers in the pool +** +*******************************************************************************/ +UINT16 GKI_poolcount (UINT8 pool_id) +{ + if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS) + return (0); + + return (gki_cb.com.freeq[pool_id].total); +} + +/******************************************************************************* +** +** Function GKI_poolfreecount +** +** Description Called by an application to get the number of free buffers +** in the specified buffer pool. +** +** Parameters pool_id - (input) pool ID to get the free count of. +** +** Returns the number of free buffers in the pool +** +*******************************************************************************/ +UINT16 GKI_poolfreecount (UINT8 pool_id) +{ + FREE_QUEUE_T *Q; + + if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS) + return (0); + + Q = &gki_cb.com.freeq[pool_id]; + + return ((UINT16)(Q->total - Q->cur_cnt)); +} + +/******************************************************************************* +** +** Function GKI_change_buf_owner +** +** Description Called to change the task ownership of a buffer. +** +** Parameters: p_buf - (input) pointer to the buffer +** task_id - (input) task id to change ownership to +** +** Returns void +** +*******************************************************************************/ +void GKI_change_buf_owner (void *p_buf, UINT8 task_id) +{ + BUFFER_HDR_T *p_hdr = (BUFFER_HDR_T *) ((UINT8 *) p_buf - BUFFER_HDR_SIZE); + + p_hdr->task_id = task_id; + + return; +} + +#if (defined(GKI_SEND_MSG_FROM_ISR) && GKI_SEND_MSG_FROM_ISR == TRUE) +/******************************************************************************* +** +** Function GKI_isend_msg +** +** Description Called from interrupt context to send a buffer to a task +** +** Returns Nothing +** +*******************************************************************************/ +void GKI_isend_msg (UINT8 task_id, UINT8 mbox, void *msg) +{ + BUFFER_HDR_T *p_hdr; + tGKI_COM_CB *p_cb = &gki_cb.com; + + /* If task non-existant or not started, drop buffer */ + if ((task_id >= GKI_MAX_TASKS) || (mbox >= NUM_TASK_MBOX) || (p_cb->OSRdyTbl[task_id] == TASK_DEAD)) + { + GKI_exception(GKI_ERROR_SEND_MSG_BAD_DEST, "Sending to unknown dest"); + GKI_freebuf (msg); + return; + } + +#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE) + if (gki_chk_buf_damage(msg)) + { + GKI_exception(GKI_ERROR_BUF_CORRUPTED, "Send - Buffer corrupted"); + return; + } +#endif + +#if (GKI_ENABLE_OWNER_CHECK == TRUE) + if (gki_chk_buf_owner(msg)) + { + GKI_exception(GKI_ERROR_NOT_BUF_OWNER, "Send by non-owner"); + return; + } +#endif + + p_hdr = (BUFFER_HDR_T *) ((UINT8 *) msg - BUFFER_HDR_SIZE); + + if (p_hdr->status != BUF_STATUS_UNLINKED) + { + GKI_exception(GKI_ERROR_SEND_MSG_BUF_LINKED, "Send - buffer linked"); + return; + } + + if (p_cb->OSTaskQFirst[task_id][mbox]) + p_cb->OSTaskQLast[task_id][mbox]->p_next = p_hdr; + else + p_cb->OSTaskQFirst[task_id][mbox] = p_hdr; + + p_cb->OSTaskQLast[task_id][mbox] = p_hdr; + + p_hdr->p_next = NULL; + p_hdr->status = BUF_STATUS_QUEUED; + p_hdr->task_id = task_id; + + GKI_isend_event(task_id, (UINT16)EVENT_MASK(mbox)); + + return; +} +#endif + +/******************************************************************************* +** +** Function GKI_create_pool +** +** Description Called by applications to create a buffer pool. +** +** Parameters: size - (input) length (in bytes) of each buffer in the pool +** count - (input) number of buffers to allocate for the pool +** permission - (input) restricted or public access? +** (GKI_PUBLIC_POOL or GKI_RESTRICTED_POOL) +** p_mem_pool - (input) pointer to an OS memory pool, NULL if not provided +** +** Returns the buffer pool ID, which should be used in calls to +** GKI_getpoolbuf(). If a pool could not be created, this +** function returns 0xff. +** +*******************************************************************************/ +UINT8 GKI_create_pool (UINT16 size, UINT16 count, UINT8 permission, void *p_mem_pool) +{ + UINT8 xx; + UINT32 mem_needed; + INT32 tempsize = size; + tGKI_COM_CB *p_cb = &gki_cb.com; + + /* First make sure the size of each pool has a valid size with room for the header info */ + if (size > MAX_USER_BUF_SIZE) + return (GKI_INVALID_POOL); + + /* First, look for an unused pool */ + for (xx = 0; xx < GKI_NUM_TOTAL_BUF_POOLS; xx++) + { + if (!p_cb->pool_start[xx]) + break; + } + + if (xx == GKI_NUM_TOTAL_BUF_POOLS) + return (GKI_INVALID_POOL); + + /* Ensure an even number of longwords */ + tempsize = (INT32)ALIGN_POOL(size); + + mem_needed = (tempsize + BUFFER_PADDING_SIZE) * count; + + if (!p_mem_pool) + p_mem_pool = GKI_os_malloc(mem_needed); + + if (p_mem_pool) + { + /* Initialize the new pool */ + gki_init_free_queue (xx, size, count, p_mem_pool); + gki_add_to_pool_list(xx); + (void) GKI_set_pool_permission (xx, permission); + p_cb->curr_total_no_of_pools++; + + return (xx); + } + else + return (GKI_INVALID_POOL); +} + +/******************************************************************************* +** +** Function GKI_delete_pool +** +** Description Called by applications to delete a buffer pool. The function +** calls the operating specific function to free the actual memory. +** An exception is generated if an error is detected. +** +** Parameters: pool_id - (input) Id of the poll being deleted. +** +** Returns void +** +*******************************************************************************/ +void GKI_delete_pool (UINT8 pool_id) +{ + FREE_QUEUE_T *Q; + tGKI_COM_CB *p_cb = &gki_cb.com; + + if ((pool_id >= GKI_NUM_TOTAL_BUF_POOLS) || (!p_cb->pool_start[pool_id])) + return; + + GKI_disable(); + Q = &p_cb->freeq[pool_id]; + + if (!Q->cur_cnt) + { + Q->size = 0; + Q->total = 0; + Q->cur_cnt = 0; + Q->max_cnt = 0; + Q->p_first = NULL; + Q->p_last = NULL; + + GKI_os_free (p_cb->pool_start[pool_id]); + + p_cb->pool_start[pool_id] = NULL; + p_cb->pool_end[pool_id] = NULL; + p_cb->pool_size[pool_id] = 0; + + gki_remove_from_pool_list(pool_id); + p_cb->curr_total_no_of_pools--; + } + else + GKI_exception(GKI_ERROR_DELETE_POOL_BAD_QID, "Deleting bad pool"); + + GKI_enable(); + + return; +} + + +/******************************************************************************* +** +** Function GKI_get_pool_bufsize +** +** Description Called by an application to get the size of buffers in a pool +** +** Parameters Pool ID. +** +** Returns the size of buffers in the pool +** +*******************************************************************************/ +UINT16 GKI_get_pool_bufsize (UINT8 pool_id) +{ + if (pool_id < GKI_NUM_TOTAL_BUF_POOLS) + return (gki_cb.com.freeq[pool_id].size); + + return (0); +} + +/******************************************************************************* +** +** Function GKI_poolutilization +** +** Description Called by an application to get the buffer utilization +** in the specified buffer pool. +** +** Parameters pool_id - (input) pool ID to get the free count of. +** +** Returns % of buffers used from 0 to 100 +** +*******************************************************************************/ +UINT16 GKI_poolutilization (UINT8 pool_id) +{ + FREE_QUEUE_T *Q; + + if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS) + return (100); + + Q = &gki_cb.com.freeq[pool_id]; + + if (Q->total == 0) + return (100); + + return ((Q->cur_cnt * 100) / Q->total); +} + diff --git a/gki/common/gki_common.h b/gki/common/gki_common.h new file mode 100644 index 0000000..6093abf --- /dev/null +++ b/gki/common/gki_common.h @@ -0,0 +1,384 @@ +/**************************************************************************** +** +** Name gki_common.h +** +** Function This file contains GKI private definitions +** +** +** Copyright (c) 1999-2006, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ +#ifndef GKI_COMMON_H +#define GKI_COMMON_H + +#include "gki.h" +#include "dyn_mem.h" + +/* Task States: (For OSRdyTbl) */ +#define TASK_DEAD 0 /* b0000 */ +#define TASK_READY 1 /* b0001 */ +#define TASK_WAIT 2 /* b0010 */ +#define TASK_DELAY 4 /* b0100 */ +#define TASK_SUSPEND 8 /* b1000 */ + + +/******************************************************************** +** Internal Error codes +*********************************************************************/ +#define GKI_ERROR_BUF_CORRUPTED 0xFFFF +#define GKI_ERROR_NOT_BUF_OWNER 0xFFFE +#define GKI_ERROR_FREEBUF_BAD_QID 0xFFFD +#define GKI_ERROR_FREEBUF_BUF_LINKED 0xFFFC +#define GKI_ERROR_SEND_MSG_BAD_DEST 0xFFFB +#define GKI_ERROR_SEND_MSG_BUF_LINKED 0xFFFA +#define GKI_ERROR_ENQUEUE_BUF_LINKED 0xFFF9 +#define GKI_ERROR_DELETE_POOL_BAD_QID 0xFFF8 +#define GKI_ERROR_BUF_SIZE_TOOBIG 0xFFF7 +#define GKI_ERROR_BUF_SIZE_ZERO 0xFFF6 +#define GKI_ERROR_ADDR_NOT_IN_BUF 0xFFF5 + + +/******************************************************************** +** Misc constants +*********************************************************************/ + +#define GKI_MAX_INT32 (0x7fffffffL) +#define GKI_MAX_TIMESTAMP (0xffffffffL) + +/******************************************************************** +** Buffer Management Data Structures +*********************************************************************/ + +typedef struct _buffer_hdr +{ + struct _buffer_hdr *p_next; /* next buffer in the queue */ + UINT8 q_id; /* id of the queue */ + UINT8 task_id; /* task which allocated the buffer*/ + UINT8 status; /* FREE, UNLINKED or QUEUED */ + UINT8 Type; +} BUFFER_HDR_T; + +typedef struct _free_queue +{ + BUFFER_HDR_T *p_first; /* first buffer in the queue */ + BUFFER_HDR_T *p_last; /* last buffer in the queue */ + UINT16 size; /* size of the buffers in the pool */ + UINT16 total; /* toatal number of buffers */ + UINT16 cur_cnt; /* number of buffers currently allocated */ + UINT16 max_cnt; /* maximum number of buffers allocated at any time */ +} FREE_QUEUE_T; + + +/* Buffer related defines +*/ +#define ALIGN_POOL(pl_size) ( (((pl_size) + 3) / sizeof(UINT32)) * sizeof(UINT32)) +#define BUFFER_HDR_SIZE (sizeof(BUFFER_HDR_T)) /* Offset past header */ +#define BUFFER_PADDING_SIZE (sizeof(BUFFER_HDR_T) + sizeof(UINT32)) /* Header + Magic Number */ +#define MAX_USER_BUF_SIZE ((UINT16)0xffff - BUFFER_PADDING_SIZE) /* pool size must allow for header */ +#define MAGIC_NO 0xDDBADDBA + +#define BUF_STATUS_FREE 0 +#define BUF_STATUS_UNLINKED 1 +#define BUF_STATUS_QUEUED 2 + +// btla-specific ++ +#define GKI_USE_DEFERED_ALLOC_BUF_POOLS +// btla-specific -- + +/* Exception related structures (Used in debug mode only) +*/ +#if (GKI_DEBUG == TRUE) +typedef struct +{ + UINT16 type; + UINT8 taskid; + UINT8 msg[GKI_MAX_EXCEPTION_MSGLEN]; +} EXCEPTION_T; +#endif + + +/* Put all GKI variables into one control block +*/ +typedef struct +{ + /* Task management variables + */ + /* The stack and stack size are not used on Windows + */ +// btla-specific ++ +#if (!defined GKI_USE_DEFERED_ALLOC_BUF_POOLS && (GKI_USE_DYNAMIC_BUFFERS == FALSE)) +// btla-specific -- + +#if (GKI_NUM_FIXED_BUF_POOLS > 0) + UINT8 bufpool0[(ALIGN_POOL(GKI_BUF0_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF0_MAX]; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 1) + UINT8 bufpool1[(ALIGN_POOL(GKI_BUF1_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF1_MAX]; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 2) + UINT8 bufpool2[(ALIGN_POOL(GKI_BUF2_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF2_MAX]; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 3) + UINT8 bufpool3[(ALIGN_POOL(GKI_BUF3_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF3_MAX]; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 4) + UINT8 bufpool4[(ALIGN_POOL(GKI_BUF4_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF4_MAX]; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 5) + UINT8 bufpool5[(ALIGN_POOL(GKI_BUF5_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF5_MAX]; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 6) + UINT8 bufpool6[(ALIGN_POOL(GKI_BUF6_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF6_MAX]; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 7) + UINT8 bufpool7[(ALIGN_POOL(GKI_BUF7_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF7_MAX]; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 8) + UINT8 bufpool8[(ALIGN_POOL(GKI_BUF8_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF8_MAX]; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 9) + UINT8 bufpool9[(ALIGN_POOL(GKI_BUF9_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF9_MAX]; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 10) + UINT8 bufpool10[(ALIGN_POOL(GKI_BUF10_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF10_MAX]; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 11) + UINT8 bufpool11[(ALIGN_POOL(GKI_BUF11_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF11_MAX]; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 12) + UINT8 bufpool12[(ALIGN_POOL(GKI_BUF12_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF12_MAX]; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 13) + UINT8 bufpool13[(ALIGN_POOL(GKI_BUF13_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF13_MAX]; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 14) + UINT8 bufpool14[(ALIGN_POOL(GKI_BUF14_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF14_MAX]; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 15) + UINT8 bufpool15[(ALIGN_POOL(GKI_BUF15_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF15_MAX]; +#endif + +#else +/* Definitions for dynamic buffer use */ +#if (GKI_NUM_FIXED_BUF_POOLS > 0) + UINT8 *bufpool0; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 1) + UINT8 *bufpool1; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 2) + UINT8 *bufpool2; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 3) + UINT8 *bufpool3; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 4) + UINT8 *bufpool4; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 5) + UINT8 *bufpool5; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 6) + UINT8 *bufpool6; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 7) + UINT8 *bufpool7; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 8) + UINT8 *bufpool8; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 9) + UINT8 *bufpool9; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 10) + UINT8 *bufpool10; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 11) + UINT8 *bufpool11; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 12) + UINT8 *bufpool12; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 13) + UINT8 *bufpool13; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 14) + UINT8 *bufpool14; +#endif + +#if (GKI_NUM_FIXED_BUF_POOLS > 15) + UINT8 *bufpool15; +#endif + +#endif + + UINT8 *OSStack[GKI_MAX_TASKS]; /* pointer to beginning of stack */ + UINT16 OSStackSize[GKI_MAX_TASKS]; /* stack size available to each task */ + + + INT8 *OSTName[GKI_MAX_TASKS]; /* name of the task */ + + UINT8 OSRdyTbl[GKI_MAX_TASKS]; /* current state of the task */ + UINT16 OSWaitEvt[GKI_MAX_TASKS]; /* events that have to be processed by the task */ + UINT16 OSWaitForEvt[GKI_MAX_TASKS]; /* events the task is waiting for*/ + + UINT32 OSTicks; /* system ticks from start */ + UINT32 OSIdleCnt; /* idle counter */ + INT16 OSDisableNesting; /* counter to keep track of interrupt disable nesting */ + INT16 OSLockNesting; /* counter to keep track of sched lock nesting */ + INT16 OSIntNesting; /* counter to keep track of interrupt nesting */ + + /* Timer related variables + */ + INT32 OSTicksTilExp; /* Number of ticks till next timer expires */ +#if (defined(GKI_DELAY_STOP_SYS_TICK) && (GKI_DELAY_STOP_SYS_TICK > 0)) + UINT32 OSTicksTilStop; /* inactivity delay timer; OS Ticks till stopping system tick */ +#endif + INT32 OSNumOrigTicks; /* Number of ticks between last timer expiration to the next one */ + + INT32 OSWaitTmr [GKI_MAX_TASKS]; /* ticks the task has to wait, for specific events */ + + /* Only take up space timers used in the system (GKI_NUM_TIMERS defined in target.h) */ +#if (GKI_NUM_TIMERS > 0) + INT32 OSTaskTmr0 [GKI_MAX_TASKS]; + INT32 OSTaskTmr0R [GKI_MAX_TASKS]; +#endif + +#if (GKI_NUM_TIMERS > 1) + INT32 OSTaskTmr1 [GKI_MAX_TASKS]; + INT32 OSTaskTmr1R [GKI_MAX_TASKS]; +#endif + +#if (GKI_NUM_TIMERS > 2) + INT32 OSTaskTmr2 [GKI_MAX_TASKS]; + INT32 OSTaskTmr2R [GKI_MAX_TASKS]; +#endif + +#if (GKI_NUM_TIMERS > 3) + INT32 OSTaskTmr3 [GKI_MAX_TASKS]; + INT32 OSTaskTmr3R [GKI_MAX_TASKS]; +#endif + + + + /* Buffer related variables + */ + BUFFER_HDR_T *OSTaskQFirst[GKI_MAX_TASKS][NUM_TASK_MBOX]; /* array of pointers to the first event in the task mailbox */ + BUFFER_HDR_T *OSTaskQLast [GKI_MAX_TASKS][NUM_TASK_MBOX]; /* array of pointers to the last event in the task mailbox */ + + /* Define the buffer pool management variables + */ + FREE_QUEUE_T freeq[GKI_NUM_TOTAL_BUF_POOLS]; + + UINT16 pool_buf_size[GKI_NUM_TOTAL_BUF_POOLS]; + UINT16 pool_max_count[GKI_NUM_TOTAL_BUF_POOLS]; + UINT16 pool_additions[GKI_NUM_TOTAL_BUF_POOLS]; + + /* Define the buffer pool start addresses + */ + UINT8 *pool_start[GKI_NUM_TOTAL_BUF_POOLS]; /* array of pointers to the start of each buffer pool */ + UINT8 *pool_end[GKI_NUM_TOTAL_BUF_POOLS]; /* array of pointers to the end of each buffer pool */ + UINT16 pool_size[GKI_NUM_TOTAL_BUF_POOLS]; /* actual size of the buffers in a pool */ + + /* Define the buffer pool access control variables */ + void *p_user_mempool; /* User O/S memory pool */ + UINT16 pool_access_mask; /* Bits are set if the corresponding buffer pool is a restricted pool */ + UINT8 pool_list[GKI_NUM_TOTAL_BUF_POOLS]; /* buffer pools arranged in the order of size */ + UINT8 curr_total_no_of_pools; /* number of fixed buf pools + current number of dynamic pools */ + + BOOLEAN timer_nesting; /* flag to prevent timer interrupt nesting */ + + /* Time queue arrays */ + TIMER_LIST_Q *timer_queues[GKI_MAX_TIMER_QUEUES]; + /* System tick callback */ + SYSTEM_TICK_CBACK *p_tick_cb; + BOOLEAN system_tick_running; /* TRUE if system tick is running. Valid only if p_tick_cb is not NULL */ + +#if (GKI_DEBUG == TRUE) + UINT16 ExceptionCnt; /* number of GKI exceptions that have happened */ + EXCEPTION_T Exception[GKI_MAX_EXCEPTION]; +#endif + +} tGKI_COM_CB; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Internal GKI function prototypes +*/ +GKI_API extern BOOLEAN gki_chk_buf_damage(void *); +extern BOOLEAN gki_chk_buf_owner(void *); +extern void gki_buffer_init (void); +extern void gki_timers_init(void); +extern void gki_adjust_timer_count (INT32); + +#ifdef GKI_USE_DEFERED_ALLOC_BUF_POOLS +extern void gki_dealloc_free_queue(void); +#endif + +extern void OSStartRdy(void); +extern void OSCtxSw(void); +extern void OSIntCtxSw(void); +extern void OSSched(void); +extern void OSIntEnter(void); +extern void OSIntExit(void); + + +/* Debug aids +*/ +typedef void (*FP_PRINT)(char *, ...); + +#if (GKI_DEBUG == TRUE) + +typedef void (*PKT_PRINT)(UINT8 *, UINT16); + +extern void gki_print_task(FP_PRINT); +extern void gki_print_exception(FP_PRINT); +extern void gki_print_timer(FP_PRINT); +extern void gki_print_stack(FP_PRINT); +extern void gki_print_buffer(FP_PRINT); +extern void gki_print_buffer_statistics(FP_PRINT, INT16); +GKI_API extern void gki_print_used_bufs (FP_PRINT, UINT8); +extern void gki_dump(UINT8 *, UINT16, FP_PRINT); +extern void gki_dump2(UINT16 *, UINT16, FP_PRINT); +extern void gki_dump4(UINT32 *, UINT16, FP_PRINT); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/gki/common/gki_debug.c b/gki/common/gki_debug.c new file mode 100644 index 0000000..3ec8fc5 --- /dev/null +++ b/gki/common/gki_debug.c @@ -0,0 +1,348 @@ +/**************************************************************************** +** +** Name gki_debug.c +** +** Function this file contains some sample GKI debug aid functions +** +** +** Copyright (c) 1999-2004, WIDCOMM Inc., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ + +#include "gki_int.h" + +#if (GKI_DEBUG == TRUE) + +const INT8 * const OSTaskStates[] = +{ + (INT8 *)"DEAD", /* 0 */ + (INT8 *)"REDY", /* 1 */ + (INT8 *)"WAIT", /* 2 */ + (INT8 *)"", + (INT8 *)"DELY", /* 4 */ + (INT8 *)"", + (INT8 *)"", + (INT8 *)"", + (INT8 *)"SUSP", /* 8 */ +}; + + +/******************************************************************************* +** +** Function GKI_PrintBufferUsage +** +** Description Displays Current Buffer Pool summary +** +** Returns void +** +*******************************************************************************/ +void GKI_PrintBufferUsage(UINT8 *p_num_pools, UINT16 *p_cur_used) +{ + int i; + FREE_QUEUE_T *p; + UINT8 num = gki_cb.com.curr_total_no_of_pools; + UINT16 cur[GKI_NUM_TOTAL_BUF_POOLS]; + + GKI_TRACE_0(""); + GKI_TRACE_0("--- GKI Buffer Pool Summary (R - restricted, P - public) ---"); + + GKI_TRACE_0("POOL SIZE USED MAXU TOTAL"); + GKI_TRACE_0("------------------------------"); + for (i = 0; i < gki_cb.com.curr_total_no_of_pools; i++) + { + p = &gki_cb.com.freeq[i]; + if ((1 << i) & gki_cb.com.pool_access_mask) + { + GKI_TRACE_5("%02d: (R), %4d, %3d, %3d, %3d", + i, p->size, p->cur_cnt, p->max_cnt, p->total); + } + else + { + GKI_TRACE_5("%02d: (P), %4d, %3d, %3d, %3d", + i, p->size, p->cur_cnt, p->max_cnt, p->total); + } + cur[i] = p->cur_cnt; + } + if (p_num_pools) + *p_num_pools = num; + if (p_cur_used) + memcpy(p_cur_used, cur, num*2); +} + +/******************************************************************************* +** +** Function GKI_PrintBuffer +** +** Description Called internally by OSS to print the buffer pools +** +** Returns void +** +*******************************************************************************/ +void GKI_PrintBuffer(void) +{ + UINT16 i; + for(i=0; i GKI_NUM_TOTAL_BUF_POOLS || pool < 0) + { + print("Not a valid Buffer pool\n"); + return; + } + + size = gki_cb.com.freeq[pool].size; + maxbuffs = gki_cb.com.freeq[pool].total; + act_size = size + BUFFER_PADDING_SIZE; + print("Buffer Pool[%u] size=%u cur_cnt=%u max_cnt=%u total=%u\n", + pool, gki_cb.com.freeq[pool].size, + gki_cb.com.freeq[pool].cur_cnt, gki_cb.com.freeq[pool].max_cnt, gki_cb.com.freeq[pool].total); + + print(" Owner State Sanity\n"); + print("----------------------------\n"); + hdr = (BUFFER_HDR_T *)(gki_cb.com.pool_start[pool]); + for(i=0; itask_id, hdr->status, (*magic == MAGIC_NO)?"OK":"CORRUPTED"); + hdr = (BUFFER_HDR_T *)((UINT8 *)hdr + act_size); + } + return; +} + + +/******************************************************************************* +** +** Function gki_print_used_bufs +** +** Description Dumps used buffers in the particular pool +** +*******************************************************************************/ +GKI_API void gki_print_used_bufs (FP_PRINT print, UINT8 pool_id) +{ + UINT8 *p_start; + UINT16 buf_size; + UINT16 num_bufs; + BUFFER_HDR_T *p_hdr; + UINT16 i; + UINT32 *magic; + UINT16 *p; + + + if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS && gki_cb.com.pool_start[pool_id] != 0) + { + print("Not a valid Buffer pool\n"); + return; + } + + p_start = gki_cb.com.pool_start[pool_id]; + buf_size = gki_cb.com.freeq[pool_id].size + BUFFER_PADDING_SIZE; + num_bufs = gki_cb.com.freeq[pool_id].total; + + for (i = 0; i < num_bufs; i++, p_start += buf_size) + { + p_hdr = (BUFFER_HDR_T *)p_start; + magic = (UINT32 *)((UINT8 *)p_hdr + buf_size - sizeof(UINT32)); + p = (UINT16 *) p_hdr; + + if (p_hdr->status != BUF_STATUS_FREE) + { + print ("%d:0x%x (Q:%d,Task:%s,Stat:%d,%s) %04x %04x %04x %04x %04x %04x %04x %04x\n", + i, p_hdr, + p_hdr->q_id, + GKI_map_taskname(p_hdr->task_id), + p_hdr->status, + (*magic == MAGIC_NO)? "OK" : "CORRUPTED", + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); + } + } +} + + +/******************************************************************************* +** +** Function gki_print_task +** +** Description This function prints the task states. +** +** Returns void +** +*******************************************************************************/ +void gki_print_task (FP_PRINT print) +{ + UINT8 i; + + print("TID VID TASKNAME STATE WAIT WAITFOR TIMEOUT STACK\n"); + print("-------------------------------------------------\n"); + for(i=0; itype, (INT32)pExp->taskid, (INT8 *)pExp->msg); + } +} + + +/*****************************************************************************/ +void gki_dump (UINT8 *s, UINT16 len, FP_PRINT print) +{ + UINT16 i, j; + + for(i=0, j=0; i> 8) & 0x00ff))) +#define nettohl(n) ((((n) & 0x000000ff) << 24) | (((n) << 8) & 0x00ff0000) | \ + (((n) >> 8) & 0x0000ff00) | (((n) >> 24) & 0x000000ff)) +#endif + +#endif /* GKI_INET_H */ + diff --git a/gki/common/gki_time.c b/gki/common/gki_time.c new file mode 100644 index 0000000..8121654 --- /dev/null +++ b/gki/common/gki_time.c @@ -0,0 +1,1016 @@ + +/**************************************************************************** +** +** Name GKI_time.c +** +** Function this file contains GKI time related functions +** +** Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ + +#include "gki_int.h" + +#ifndef BT_ERROR_TRACE_0 +#define BT_ERROR_TRACE_0(l,m) +#endif + +/* Make sure that this has been defined in target.h */ +#ifndef GKI_NUM_TIMERS +#error NO TIMERS: Must define at least 1 timer in the system! +#endif + + +#define GKI_NO_NEW_TMRS_STARTED (0x7fffffffL) /* Largest signed positive timer count */ +#define GKI_UNUSED_LIST_ENTRY (0x80000000L) /* Marks an unused timer list entry (initial value) */ +#define GKI_MAX_INT32 (0x7fffffffL) + +/******************************************************************************* +** +** Function gki_timers_init +** +** Description This internal function is called once at startup to initialize +** all the timer structures. +** +** Returns void +** +*******************************************************************************/ +void gki_timers_init(void) +{ + UINT8 tt; + + gki_cb.com.OSTicksTilExp = 0; /* Remaining time (of OSTimeCurTimeout) before next timer expires */ + gki_cb.com.OSNumOrigTicks = 0; +#if (defined(GKI_DELAY_STOP_SYS_TICK) && (GKI_DELAY_STOP_SYS_TICK > 0)) + gki_cb.com.OSTicksTilStop = 0; /* clear inactivity delay timer */ +#endif + + for (tt = 0; tt < GKI_MAX_TASKS; tt++) + { + gki_cb.com.OSWaitTmr [tt] = 0; + +#if (GKI_NUM_TIMERS > 0) + gki_cb.com.OSTaskTmr0 [tt] = 0; + gki_cb.com.OSTaskTmr0R [tt] = 0; +#endif + +#if (GKI_NUM_TIMERS > 1) + gki_cb.com.OSTaskTmr1 [tt] = 0; + gki_cb.com.OSTaskTmr1R [tt] = 0; +#endif + +#if (GKI_NUM_TIMERS > 2) + gki_cb.com.OSTaskTmr2 [tt] = 0; + gki_cb.com.OSTaskTmr2R [tt] = 0; +#endif + +#if (GKI_NUM_TIMERS > 3) + gki_cb.com.OSTaskTmr3 [tt] = 0; + gki_cb.com.OSTaskTmr3R [tt] = 0; +#endif + } + + for (tt = 0; tt < GKI_MAX_TIMER_QUEUES; tt++) + { + gki_cb.com.timer_queues[tt] = NULL; + } + + gki_cb.com.p_tick_cb = NULL; + gki_cb.com.system_tick_running = FALSE; + + return; +} + +/******************************************************************************* +** +** Function gki_timers_is_timer_running +** +** Description This internal function is called to test if any gki timer are running +** +** +** Returns TRUE if at least one time is running in the system, FALSE else. +** +*******************************************************************************/ +BOOLEAN gki_timers_is_timer_running(void) +{ + UINT8 tt; + for (tt = 0; tt < GKI_MAX_TASKS; tt++) + { + +#if (GKI_NUM_TIMERS > 0) + if(gki_cb.com.OSTaskTmr0 [tt]) + { + return TRUE; + } +#endif + +#if (GKI_NUM_TIMERS > 1) + if(gki_cb.com.OSTaskTmr1 [tt] ) + { + return TRUE; + } +#endif + +#if (GKI_NUM_TIMERS > 2) + if(gki_cb.com.OSTaskTmr2 [tt] ) + { + return TRUE; + } +#endif + +#if (GKI_NUM_TIMERS > 3) + if(gki_cb.com.OSTaskTmr3 [tt] ) + { + return TRUE; + } +#endif + } + + return FALSE; + +} + +/******************************************************************************* +** +** Function GKI_get_tick_count +** +** Description This function returns the current system ticks +** +** Returns The current number of system ticks +** +*******************************************************************************/ +UINT32 GKI_get_tick_count(void) +{ + return gki_cb.com.OSTicks; +} + + +/******************************************************************************* +** +** Function GKI_ready_to_sleep +** +** Description This function returns the number of system ticks until the +** next timer will expire. It is typically called by a power +** savings manager to find out how long it can have the system +** sleep before it needs to service the next entry. +** +** Parameters: None +** +** Returns Number of ticks til the next timer expires +** Note: the value is a signed value. This value should be +** compared to x > 0, to avoid misinterpreting negative tick +** values. +** +*******************************************************************************/ +INT32 GKI_ready_to_sleep (void) +{ + return (gki_cb.com.OSTicksTilExp); +} + + +/******************************************************************************* +** +** Function GKI_start_timer +** +** Description An application can call this function to start one of +** it's four general purpose timers. Any of the four timers +** can be 1-shot or continuous. If a timer is already running, +** it will be reset to the new parameters. +** +** Parameters tnum - (input) timer number to be started (TIMER_0, +** TIMER_1, TIMER_2, or TIMER_3) +** ticks - (input) the number of system ticks til the +** timer expires. +** is_continuous - (input) TRUE if timer restarts automatically, +** else FALSE if it is a 'one-shot'. +** +** Returns void +** +*******************************************************************************/ +void GKI_start_timer (UINT8 tnum, INT32 ticks, BOOLEAN is_continuous) +{ + INT32 reload; + INT32 orig_ticks; + UINT8 task_id = GKI_get_taskid(); + BOOLEAN bad_timer = FALSE; + + if (ticks <= 0) + ticks = 1; + + orig_ticks = ticks; /* save the ticks in case adjustment is necessary */ + + + /* If continuous timer, set reload, else set it to 0 */ + if (is_continuous) + reload = ticks; + else + reload = 0; + + GKI_disable(); + + if(gki_timers_is_timer_running() == FALSE) + { +#if (defined(GKI_DELAY_STOP_SYS_TICK) && (GKI_DELAY_STOP_SYS_TICK > 0)) + /* if inactivity delay timer is not running, start system tick */ + if(gki_cb.com.OSTicksTilStop == 0) + { +#endif + if(gki_cb.com.p_tick_cb) + { + /* start system tick */ + gki_cb.com.system_tick_running = TRUE; + (gki_cb.com.p_tick_cb) (TRUE); + } +#if (defined(GKI_DELAY_STOP_SYS_TICK) && (GKI_DELAY_STOP_SYS_TICK > 0)) + } + else + { + /* clear inactivity delay timer */ + gki_cb.com.OSTicksTilStop = 0; + } +#endif + } + /* Add the time since the last task timer update. + ** Note that this works when no timers are active since + ** both OSNumOrigTicks and OSTicksTilExp are 0. + */ + if (GKI_MAX_INT32 - (gki_cb.com.OSNumOrigTicks - gki_cb.com.OSTicksTilExp) > ticks) + { + ticks += gki_cb.com.OSNumOrigTicks - gki_cb.com.OSTicksTilExp; + } + else + ticks = GKI_MAX_INT32; + + switch (tnum) + { +#if (GKI_NUM_TIMERS > 0) + case TIMER_0: + gki_cb.com.OSTaskTmr0R[task_id] = reload; + gki_cb.com.OSTaskTmr0 [task_id] = ticks; + break; +#endif + +#if (GKI_NUM_TIMERS > 1) + case TIMER_1: + gki_cb.com.OSTaskTmr1R[task_id] = reload; + gki_cb.com.OSTaskTmr1 [task_id] = ticks; + break; +#endif + +#if (GKI_NUM_TIMERS > 2) + case TIMER_2: + gki_cb.com.OSTaskTmr2R[task_id] = reload; + gki_cb.com.OSTaskTmr2 [task_id] = ticks; + break; +#endif + +#if (GKI_NUM_TIMERS > 3) + case TIMER_3: + gki_cb.com.OSTaskTmr3R[task_id] = reload; + gki_cb.com.OSTaskTmr3 [task_id] = ticks; + break; +#endif + default: + bad_timer = TRUE; /* Timer number is bad, so do not use */ + } + + /* Update the expiration timeout if a legitimate timer */ + if (!bad_timer) + { + /* Only update the timeout value if it is less than any other newly started timers */ + gki_adjust_timer_count (orig_ticks); + } + + GKI_enable(); + +} + +/******************************************************************************* +** +** Function GKI_stop_timer +** +** Description An application can call this function to stop one of +** it's four general purpose timers. There is no harm in +** stopping a timer that is already stopped. +** +** Parameters tnum - (input) timer number to be started (TIMER_0, +** TIMER_1, TIMER_2, or TIMER_3) +** Returns void +** +*******************************************************************************/ +void GKI_stop_timer (UINT8 tnum) +{ + UINT8 task_id = GKI_get_taskid(); + + switch (tnum) + { +#if (GKI_NUM_TIMERS > 0) + case TIMER_0: + gki_cb.com.OSTaskTmr0R[task_id] = 0; + gki_cb.com.OSTaskTmr0 [task_id] = 0; + break; +#endif + +#if (GKI_NUM_TIMERS > 1) + case TIMER_1: + gki_cb.com.OSTaskTmr1R[task_id] = 0; + gki_cb.com.OSTaskTmr1 [task_id] = 0; + break; +#endif + +#if (GKI_NUM_TIMERS > 2) + case TIMER_2: + gki_cb.com.OSTaskTmr2R[task_id] = 0; + gki_cb.com.OSTaskTmr2 [task_id] = 0; + break; +#endif + +#if (GKI_NUM_TIMERS > 3) + case TIMER_3: + gki_cb.com.OSTaskTmr3R[task_id] = 0; + gki_cb.com.OSTaskTmr3 [task_id] = 0; + break; +#endif + } + + GKI_disable(); + + if (gki_timers_is_timer_running() == FALSE) + { + if (gki_cb.com.p_tick_cb) + { +#if (defined(GKI_DELAY_STOP_SYS_TICK) && (GKI_DELAY_STOP_SYS_TICK > 0)) + /* if inactivity delay timer is not running */ + if ((gki_cb.com.system_tick_running)&&(gki_cb.com.OSTicksTilStop == 0)) + { + /* set inactivity delay timer */ + /* when timer expires, system tick will be stopped */ + gki_cb.com.OSTicksTilStop = GKI_DELAY_STOP_SYS_TICK; + } +#else + gki_cb.com.system_tick_running = FALSE; + gki_cb.com.p_tick_cb(FALSE); /* stop system tick */ +#endif + } + } + + GKI_enable(); + + +} + + +/******************************************************************************* +** +** Function GKI_timer_update +** +** Description This function is called by an OS to drive the GKI's timers. +** It is typically called at every system tick to +** update the timers for all tasks, and check for timeouts. +** +** Note: It has been designed to also allow for variable tick updates +** so that systems with strict power savings requirements can +** have the update occur at variable intervals. +** +** Parameters: ticks_since_last_update - (input) This is the number of TICKS that have +** occurred since the last time GKI_timer_update was called. +** +** Returns void +** +*******************************************************************************/ +void GKI_timer_update (INT32 ticks_since_last_update) +{ + UINT8 task_id; + long next_expiration; /* Holds the next soonest expiration time after this update */ + + /* Increment the number of ticks used for time stamps */ + gki_cb.com.OSTicks += ticks_since_last_update; + + /* If any timers are running in any tasks, decrement the remaining time til + * the timer updates need to take place (next expiration occurs) + */ + gki_cb.com.OSTicksTilExp -= ticks_since_last_update; + + /* Don't allow timer interrupt nesting */ + if (gki_cb.com.timer_nesting) + return; + + gki_cb.com.timer_nesting = 1; + +#if (defined(GKI_DELAY_STOP_SYS_TICK) && (GKI_DELAY_STOP_SYS_TICK > 0)) + /* if inactivity delay timer is set and expired */ + if (gki_cb.com.OSTicksTilStop) + { + if( gki_cb.com.OSTicksTilStop <= (UINT32)ticks_since_last_update ) + { + if(gki_cb.com.p_tick_cb) + { + gki_cb.com.system_tick_running = FALSE; + (gki_cb.com.p_tick_cb) (FALSE); /* stop system tick */ + } + gki_cb.com.OSTicksTilStop = 0; /* clear inactivity delay timer */ + gki_cb.com.timer_nesting = 0; + return; + } + else + gki_cb.com.OSTicksTilStop -= ticks_since_last_update; + } +#endif + + /* No need to update the ticks if no timeout has occurred */ + if (gki_cb.com.OSTicksTilExp > 0) + { + gki_cb.com.timer_nesting = 0; + return; + } + + next_expiration = GKI_NO_NEW_TMRS_STARTED; + + /* If here then gki_cb.com.OSTicksTilExp <= 0. If negative, then increase gki_cb.com.OSNumOrigTicks + to account for the difference so timer updates below are decremented by the full number + of ticks. gki_cb.com.OSNumOrigTicks is reset at the bottom of this function so changing this + value only affects the timer updates below + */ + gki_cb.com.OSNumOrigTicks -= gki_cb.com.OSTicksTilExp; + +#if GKI_TIMER_LIST_NOPREEMPT == TRUE + /* Protect this section because if a GKI_timer_stop happens between: + * - gki_cb.com.OSTaskTmr0[task_id] -= gki_cb.com.OSNumOrigTicks; + * - gki_cb.com.OSTaskTmr0[task_id] = gki_cb.com.OSTaskTmr0R[task_id]; + * then the timer may appear stopped while it is about to be reloaded. + * Note: Not needed if this function cannot be preempted (typical). + */ + GKI_disable(); +#endif + + /* Check for OS Task Timers */ + for (task_id = 0; task_id < GKI_MAX_TASKS; task_id++) + { + if (gki_cb.com.OSWaitTmr[task_id] > 0) /* If timer is running */ + { + gki_cb.com.OSWaitTmr[task_id] -= gki_cb.com.OSNumOrigTicks; + if (gki_cb.com.OSWaitTmr[task_id] <= 0) + { + /* Timer Expired */ + gki_cb.com.OSRdyTbl[task_id] = TASK_READY; + } + } + +#if (GKI_NUM_TIMERS > 0) + /* If any timer is running, decrement */ + if (gki_cb.com.OSTaskTmr0[task_id] > 0) + { + gki_cb.com.OSTaskTmr0[task_id] -= gki_cb.com.OSNumOrigTicks; + + if (gki_cb.com.OSTaskTmr0[task_id] <= 0) + { + /* Reload timer and set Timer 0 Expired event mask */ + gki_cb.com.OSTaskTmr0[task_id] = gki_cb.com.OSTaskTmr0R[task_id]; + +#if (defined(GKI_TIMER_UPDATES_FROM_ISR) && GKI_TIMER_UPDATES_FROM_ISR == TRUE) + GKI_isend_event (task_id, TIMER_0_EVT_MASK); +#else + GKI_send_event (task_id, TIMER_0_EVT_MASK); +#endif + } + } + + /* Check to see if this timer is the next one to expire */ + if (gki_cb.com.OSTaskTmr0[task_id] > 0 && gki_cb.com.OSTaskTmr0[task_id] < next_expiration) + next_expiration = gki_cb.com.OSTaskTmr0[task_id]; +#endif + +#if (GKI_NUM_TIMERS > 1) + /* If any timer is running, decrement */ + if (gki_cb.com.OSTaskTmr1[task_id] > 0) + { + gki_cb.com.OSTaskTmr1[task_id] -= gki_cb.com.OSNumOrigTicks; + + if (gki_cb.com.OSTaskTmr1[task_id] <= 0) + { + /* Reload timer and set Timer 1 Expired event mask */ + gki_cb.com.OSTaskTmr1[task_id] = gki_cb.com.OSTaskTmr1R[task_id]; + +#if (defined(GKI_TIMER_UPDATES_FROM_ISR) && GKI_TIMER_UPDATES_FROM_ISR == TRUE) + GKI_isend_event (task_id, TIMER_1_EVT_MASK); +#else + GKI_send_event (task_id, TIMER_1_EVT_MASK); +#endif + } + } + + /* Check to see if this timer is the next one to expire */ + if (gki_cb.com.OSTaskTmr1[task_id] > 0 && gki_cb.com.OSTaskTmr1[task_id] < next_expiration) + next_expiration = gki_cb.com.OSTaskTmr1[task_id]; +#endif + +#if (GKI_NUM_TIMERS > 2) + /* If any timer is running, decrement */ + if (gki_cb.com.OSTaskTmr2[task_id] > 0) + { + gki_cb.com.OSTaskTmr2[task_id] -= gki_cb.com.OSNumOrigTicks; + + if (gki_cb.com.OSTaskTmr2[task_id] <= 0) + { + /* Reload timer and set Timer 2 Expired event mask */ + gki_cb.com.OSTaskTmr2[task_id] = gki_cb.com.OSTaskTmr2R[task_id]; + +#if (defined(GKI_TIMER_UPDATES_FROM_ISR) && GKI_TIMER_UPDATES_FROM_ISR == TRUE) + GKI_isend_event (task_id, TIMER_2_EVT_MASK); +#else + GKI_send_event (task_id, TIMER_2_EVT_MASK); +#endif + } + } + + /* Check to see if this timer is the next one to expire */ + if (gki_cb.com.OSTaskTmr2[task_id] > 0 && gki_cb.com.OSTaskTmr2[task_id] < next_expiration) + next_expiration = gki_cb.com.OSTaskTmr2[task_id]; +#endif + +#if (GKI_NUM_TIMERS > 3) + /* If any timer is running, decrement */ + if (gki_cb.com.OSTaskTmr3[task_id] > 0) + { + gki_cb.com.OSTaskTmr3[task_id] -= gki_cb.com.OSNumOrigTicks; + + if (gki_cb.com.OSTaskTmr3[task_id] <= 0) + { + /* Reload timer and set Timer 3 Expired event mask */ + gki_cb.com.OSTaskTmr3[task_id] = gki_cb.com.OSTaskTmr3R[task_id]; + +#if (defined(GKI_TIMER_UPDATES_FROM_ISR) && GKI_TIMER_UPDATES_FROM_ISR == TRUE) + GKI_isend_event (task_id, TIMER_3_EVT_MASK); +#else + GKI_send_event (task_id, TIMER_3_EVT_MASK); +#endif + } + } + + /* Check to see if this timer is the next one to expire */ + if (gki_cb.com.OSTaskTmr3[task_id] > 0 && gki_cb.com.OSTaskTmr3[task_id] < next_expiration) + next_expiration = gki_cb.com.OSTaskTmr3[task_id]; +#endif + + } + +#if GKI_TIMER_LIST_NOPREEMPT == TRUE + /* End the critical section */ + GKI_enable(); +#endif + + /* Set the next timer experation value if there is one to start */ + if (next_expiration < GKI_NO_NEW_TMRS_STARTED) + { + gki_cb.com.OSTicksTilExp = gki_cb.com.OSNumOrigTicks = next_expiration; + } + else + { + gki_cb.com.OSTicksTilExp = gki_cb.com.OSNumOrigTicks = 0; + } + + gki_cb.com.timer_nesting = 0; + + return; +} + + +/******************************************************************************* +** +** Function GKI_timer_queue_empty +** +** Description This function is called by applications to see whether the timer +** queue is empty +** +** Parameters +** +** Returns BOOLEAN +** +*******************************************************************************/ +BOOLEAN GKI_timer_queue_empty (void) +{ + UINT8 tt; + + for (tt = 0; tt < GKI_MAX_TIMER_QUEUES; tt++) + { + if (gki_cb.com.timer_queues[tt]) + return FALSE; + } + + return TRUE; +} + +/******************************************************************************* +** +** Function GKI_timer_queue_register_callback +** +** Description This function is called by applications to register system tick +** start/stop callback for time queues +** +** +** Parameters p_callback - (input) pointer to the system tick callback +** +** Returns BOOLEAN +** +*******************************************************************************/ +void GKI_timer_queue_register_callback (SYSTEM_TICK_CBACK *p_callback) +{ + gki_cb.com.p_tick_cb = p_callback; + + return; +} + +/******************************************************************************* +** +** Function GKI_init_timer_list +** +** Description This function is called by applications when they +** want to initialize a timer list. +** +** Parameters p_timer_listq - (input) pointer to the timer list queue object +** +** Returns void +** +*******************************************************************************/ +void GKI_init_timer_list (TIMER_LIST_Q *p_timer_listq) +{ + p_timer_listq->p_first = NULL; + p_timer_listq->p_last = NULL; + p_timer_listq->last_ticks = 0; + + return; +} + +/******************************************************************************* +** +** Function GKI_init_timer_list_entry +** +** Description This function is called by the applications when they +** want to initialize a timer list entry. This must be +** done prior to first use of the entry. +** +** Parameters p_tle - (input) pointer to a timer list queue entry +** +** Returns void +** +*******************************************************************************/ +void GKI_init_timer_list_entry (TIMER_LIST_ENT *p_tle) +{ + p_tle->p_next = NULL; + p_tle->p_prev = NULL; + p_tle->ticks = GKI_UNUSED_LIST_ENTRY; + p_tle->in_use = FALSE; +} + + +/******************************************************************************* +** +** Function GKI_update_timer_list +** +** Description This function is called by the applications when they +** want to update a timer list. This should be at every +** timer list unit tick, e.g. once per sec, once per minute etc. +** +** Parameters p_timer_listq - (input) pointer to the timer list queue object +** num_units_since_last_update - (input) number of units since the last update +** (allows for variable unit update) +** +** NOTE: The following timer list update routines should not be used for exact time +** critical purposes. The timer tasks should be used when exact timing is needed. +** +** Returns the number of timers that have expired +** +*******************************************************************************/ +UINT16 GKI_update_timer_list (TIMER_LIST_Q *p_timer_listq, INT32 num_units_since_last_update) +{ + TIMER_LIST_ENT *p_tle; + UINT16 num_time_out = 0; + INT32 rem_ticks; + INT32 temp_ticks; + + p_tle = p_timer_listq->p_first; + + /* First, get the guys who have previously timed out */ + /* Note that the tick value of the timers should always be '0' */ + while ((p_tle) && (p_tle->ticks <= 0)) + { + num_time_out++; + p_tle = p_tle->p_next; + } + + /* Timer entriy tick values are relative to the preceeding entry */ + rem_ticks = num_units_since_last_update; + + /* Now, adjust remaining timer entries */ + while ((p_tle != NULL) && (rem_ticks > 0)) + { + temp_ticks = p_tle->ticks; + p_tle->ticks -= rem_ticks; + + /* See if this timer has just timed out */ + if (p_tle->ticks <= 0) + { + /* We set the number of ticks to '0' so that the legacy code + * that assumes a '0' or nonzero value will still work as coded. */ + p_tle->ticks = 0; + + num_time_out++; + } + + rem_ticks -= temp_ticks; /* Decrement the remaining ticks to process */ + p_tle = p_tle->p_next; + } + + if (p_timer_listq->last_ticks > 0) + { + p_timer_listq->last_ticks -= num_units_since_last_update; + + /* If the last timer has expired set last_ticks to 0 so that other list update + * functions will calculate correctly + */ + if (p_timer_listq->last_ticks < 0) + p_timer_listq->last_ticks = 0; + } + + return (num_time_out); +} + +/******************************************************************************* +** +** Function GKI_get_remaining_ticks +** +** Description This function is called by an application to get remaining +** ticks to expire +** +** Parameters p_timer_listq - (input) pointer to the timer list queue object +** p_target_tle - (input) pointer to a timer list queue entry +** +** Returns 0 if timer is not used or timer is not in the list +** remaining ticks if success +** +*******************************************************************************/ +UINT32 GKI_get_remaining_ticks (TIMER_LIST_Q *p_timer_listq, TIMER_LIST_ENT *p_target_tle) +{ + TIMER_LIST_ENT *p_tle; + UINT32 rem_ticks = 0; + + if (p_target_tle->in_use) + { + p_tle = p_timer_listq->p_first; + + /* adding up all of ticks in previous entries */ + while ((p_tle)&&(p_tle != p_target_tle)) + { + rem_ticks += p_tle->ticks; + p_tle = p_tle->p_next; + } + + /* if found target entry */ + if (p_tle == p_target_tle) + { + rem_ticks += p_tle->ticks; + } + else + { + BT_ERROR_TRACE_0(TRACE_LAYER_GKI, "GKI_get_remaining_ticks: No timer entry in the list"); + return(0); + } + } + else + { + BT_ERROR_TRACE_0(TRACE_LAYER_GKI, "GKI_get_remaining_ticks: timer entry is not active"); + } + + return (rem_ticks); +} + +/******************************************************************************* +** +** Function GKI_add_to_timer_list +** +** Description This function is called by an application to add a timer +** entry to a timer list. +** +** Note: A timer value of '0' will effectively insert an already +** expired event. Negative tick values will be ignored. +** +** Parameters p_timer_listq - (input) pointer to the timer list queue object +** p_tle - (input) pointer to a timer list queue entry +** +** Returns void +** +*******************************************************************************/ +void GKI_add_to_timer_list (TIMER_LIST_Q *p_timer_listq, TIMER_LIST_ENT *p_tle) +{ + UINT32 nr_ticks_total; + UINT8 tt; + TIMER_LIST_ENT *p_temp; + + /* Only process valid tick values */ + if (p_tle->ticks >= 0) + { + /* If this entry is the last in the list */ + if (p_tle->ticks >= p_timer_listq->last_ticks) + { + /* If this entry is the only entry in the list */ + if (p_timer_listq->p_first == NULL) + p_timer_listq->p_first = p_tle; + else + { + /* Insert the entry onto the end of the list */ + if (p_timer_listq->p_last != NULL) + p_timer_listq->p_last->p_next = p_tle; + + p_tle->p_prev = p_timer_listq->p_last; + } + + p_tle->p_next = NULL; + p_timer_listq->p_last = p_tle; + nr_ticks_total = p_tle->ticks; + p_tle->ticks -= p_timer_listq->last_ticks; + + p_timer_listq->last_ticks = nr_ticks_total; + } + else /* This entry needs to be inserted before the last entry */ + { + /* Find the entry that the new one needs to be inserted in front of */ + p_temp = p_timer_listq->p_first; + while (p_tle->ticks > p_temp->ticks) + { + /* Update the tick value if looking at an unexpired entry */ + if (p_temp->ticks > 0) + p_tle->ticks -= p_temp->ticks; + + p_temp = p_temp->p_next; + } + + /* The new entry is the first in the list */ + if (p_temp == p_timer_listq->p_first) + { + p_tle->p_next = p_timer_listq->p_first; + p_timer_listq->p_first->p_prev = p_tle; + p_timer_listq->p_first = p_tle; + } + else + { + p_temp->p_prev->p_next = p_tle; + p_tle->p_prev = p_temp->p_prev; + p_temp->p_prev = p_tle; + p_tle->p_next = p_temp; + } + p_temp->ticks -= p_tle->ticks; + } + + p_tle->in_use = TRUE; + + /* if we already add this timer queue to the array */ + for (tt = 0; tt < GKI_MAX_TIMER_QUEUES; tt++) + { + if (gki_cb.com.timer_queues[tt] == p_timer_listq) + return; + } + /* add this timer queue to the array */ + for (tt = 0; tt < GKI_MAX_TIMER_QUEUES; tt++) + { + if (gki_cb.com.timer_queues[tt] == NULL) + break; + } + if (tt < GKI_MAX_TIMER_QUEUES) + { + gki_cb.com.timer_queues[tt] = p_timer_listq; + } + } + + return; +} + + +/******************************************************************************* +** +** Function GKI_remove_from_timer_list +** +** Description This function is called by an application to remove a timer +** entry from a timer list. +** +** Parameters p_timer_listq - (input) pointer to the timer list queue object +** p_tle - (input) pointer to a timer list queue entry +** +** Returns void +** +*******************************************************************************/ +void GKI_remove_from_timer_list (TIMER_LIST_Q *p_timer_listq, TIMER_LIST_ENT *p_tle) +{ + UINT8 tt; + + /* Verify that the entry is valid */ + if (p_tle == NULL || p_tle->in_use == FALSE || p_timer_listq->p_first == NULL) + { + return; + } + + /* Add the ticks remaining in this timer (if any) to the next guy in the list. + ** Note: Expired timers have a tick value of '0'. + */ + if (p_tle->p_next != NULL) + { + p_tle->p_next->ticks += p_tle->ticks; + } + else + { + p_timer_listq->last_ticks -= p_tle->ticks; + } + + /* Unlink timer from the list. + */ + if (p_timer_listq->p_first == p_tle) + { + p_timer_listq->p_first = p_tle->p_next; + + if (p_timer_listq->p_first != NULL) + p_timer_listq->p_first->p_prev = NULL; + + if (p_timer_listq->p_last == p_tle) + p_timer_listq->p_last = NULL; + } + else + { + if (p_timer_listq->p_last == p_tle) + { + p_timer_listq->p_last = p_tle->p_prev; + + if (p_timer_listq->p_last != NULL) + p_timer_listq->p_last->p_next = NULL; + } + else + { + if (p_tle->p_next != NULL && p_tle->p_next->p_prev == p_tle) + p_tle->p_next->p_prev = p_tle->p_prev; + else + { + /* Error case - chain messed up ?? */ + return; + } + + if (p_tle->p_prev != NULL && p_tle->p_prev->p_next == p_tle) + p_tle->p_prev->p_next = p_tle->p_next; + else + { + /* Error case - chain messed up ?? */ + return; + } + } + } + + p_tle->p_next = p_tle->p_prev = NULL; + p_tle->ticks = GKI_UNUSED_LIST_ENTRY; + p_tle->in_use = FALSE; + + /* if timer queue is empty */ + if (p_timer_listq->p_first == NULL && p_timer_listq->p_last == NULL) + { + for (tt = 0; tt < GKI_MAX_TIMER_QUEUES; tt++) + { + if (gki_cb.com.timer_queues[tt] == p_timer_listq) + { + gki_cb.com.timer_queues[tt] = NULL; + break; + } + } + } + + return; +} + + +/******************************************************************************* +** +** Function gki_adjust_timer_count +** +** Description This function is called whenever a new timer or GKI_wait occurs +** to adjust (if necessary) the current time til the first expiration. +** This only needs to make an adjustment if the new timer (in ticks) is +** less than the number of ticks remaining on the current timer. +** +** Parameters: ticks - (input) number of system ticks of the new timer entry +** +** NOTE: This routine MUST be called while interrupts are disabled to +** avoid updates while adjusting the timer variables. +** +** Returns void +** +*******************************************************************************/ +void gki_adjust_timer_count (INT32 ticks) +{ + if (ticks > 0) + { + /* See if the new timer expires before the current first expiration */ + if (gki_cb.com.OSNumOrigTicks == 0 || (ticks < gki_cb.com.OSTicksTilExp && gki_cb.com.OSTicksTilExp > 0)) + { + gki_cb.com.OSNumOrigTicks = (gki_cb.com.OSNumOrigTicks - gki_cb.com.OSTicksTilExp) + ticks; + gki_cb.com.OSTicksTilExp = ticks; + } + } + + return; +} diff --git a/gki/ulinux/data_types.h b/gki/ulinux/data_types.h new file mode 100644 index 0000000..5263bba --- /dev/null +++ b/gki/ulinux/data_types.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Name data_types.h +** $Header: /Bluetooth/gki/data_types.h 7 9/13/00 11:01a Jjose $ +** +** Function this file contains common data type definitions used +** throughout the Widcomm Bluetooth code +** +** Date Modification +** ----------------------- +** 3/12/99 Create +** 07/27/00 Added nettohs macro for Little Endian +** +** Copyright (c) 1999- 2002, Widcomm Inc., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ + +#ifndef DATA_TYPES_H +#define DATA_TYPES_H + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +typedef unsigned char UINT8; +typedef unsigned short UINT16; +typedef unsigned long UINT32; +typedef signed long INT32; +typedef signed char INT8; +typedef signed short INT16; +typedef unsigned char BOOLEAN; + + +typedef UINT32 TIME_STAMP; + +#ifndef TRUE +#define TRUE (!FALSE) +#endif + +typedef unsigned char UBYTE; + +#ifdef __arm +#define PACKED __packed +#define INLINE __inline +#else +#define PACKED +#define INLINE +#endif + +#ifndef BIG_ENDIAN +#define BIG_ENDIAN FALSE +#endif + +#define UINT16_LOW_BYTE(x) ((x) & 0xff) +#define UINT16_HI_BYTE(x) ((x) >> 8) + + +#define BCM_STRCAT_S(x1,x2,x3) strcat((x1),(x3)) +#define BCM_STRNCAT_S(x1,x2,x3,x4) strncat((x1),(x3),(x4)) +#define BCM_STRCPY_S(x1,x2,x3) strcpy((x1),(x3)) +#define BCM_STRNCPY_S(x1,x2,x3,x4) strncpy((x1),(x3),(x4)) + + + +#endif + diff --git a/gki/ulinux/gki_int.h b/gki/ulinux/gki_int.h new file mode 100644 index 0000000..4aaf500 --- /dev/null +++ b/gki/ulinux/gki_int.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Name gki_int.h +** +** Function This file contains GKI private definitions +** +** +** Copyright (c) 1999-2010, Widcomm Inc., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ +#ifndef GKI_INT_H +#define GKI_INT_H + +#include "gki_common.h" +#include +#include + +/********************************************************************** +** OS specific definitions +*/ +/* The base priority used for pthread based GKI task. below value is to keep it retro compatible. + * It is recommended to use (GKI_MAX_TASKS+3), this will assign real time priorities GKI_MAX_TASKS- + * task_id -2 to the thread */ +#ifndef GKI_LINUX_BASE_PRIORITY +#define GKI_LINUX_BASE_PRIORITY 30 +#endif + +/* The base policy used for pthread based GKI task. the sched defines are defined here to avoid undefined values due + * to missing header file, see pthread functions! Overall it is recommend however to use SCHED_NOMRAL */ +#define GKI_SCHED_NORMAL 0 +#define GKI_SCHED_FIFO 1 +#define GKI_SCHED_RR 2 +#ifndef GKI_LINUX_BASE_POLICY +#define GKI_LINUX_BASE_POLICY GKI_SCHED_NORMAL +#endif + +/* GKI timer bases should use GKI_SCHED_FIFO to ensure the least jitter possible */ +#ifndef GKI_LINUX_TIMER_POLICY +#define GKI_LINUX_TIMER_POLICY GKI_SCHED_FIFO +#endif + +/* the GKI_timer_update() thread should have the highest real time priority to ensue correct + * timer expiry. + */ +#ifndef GKI_LINUX_TIMER_TICK_PRIORITY +#define GKI_LINUX_TIMER_TICK_PRIORITY GKI_LINUX_BASE_PRIORITY+2 +#endif + +/* the AV timer should preferably run above the gki timer tick to ensure precise AV timing + * If you observe AV jitter under have load you may increase this one */ +#ifndef GKI_LINUX_AV_TIMER_PRIORITY +#define GKI_LINUX_AV_TIMER_PRIORITY GKI_LINUX_BASE_PRIORITY+3 +#endif + +/* defines by how much the nice value of the PROCESS should be changed. Values allowed: + * -19 to +19. a negative value give higher priority to btld compared to the default nice value + * of 20. in case of SCHED_NORMAL, a level of -5 should give a good btld/bt performance. + * In case of real time scheduling, leave default value. + */ +#ifndef GKI_LINUX_DEFAULT_NICE_INC +#define GKI_LINUX_DEFAULT_NICE_INC -7 +#endif + +typedef struct +{ + pthread_mutex_t GKI_mutex; + pthread_t thread_id[GKI_MAX_TASKS]; + pthread_mutex_t thread_evt_mutex[GKI_MAX_TASKS]; + pthread_cond_t thread_evt_cond[GKI_MAX_TASKS]; + pthread_mutex_t thread_timeout_mutex[GKI_MAX_TASKS]; + pthread_cond_t thread_timeout_cond[GKI_MAX_TASKS]; + int no_timer_suspend; /* 1: no suspend, 0 stop calling GKI_timer_update() */ + pthread_mutex_t gki_timer_mutex; + pthread_cond_t gki_timer_cond; +#if (GKI_DEBUG == TRUE) + pthread_mutex_t GKI_trace_mutex; +#endif +} tGKI_OS; + +/* condition to exit or continue GKI_run() timer loop */ +#define GKI_TIMER_TICK_RUN_COND 1 +#define GKI_TIMER_TICK_STOP_COND 0 + +extern void gki_system_tick_start_stop_cback(BOOLEAN start); + +/* Contains common control block as well as OS specific variables */ +typedef struct +{ + tGKI_OS os; + tGKI_COM_CB com; +} tGKI_CB; + + +#ifdef __cplusplus +extern "C" { +#endif + +#if GKI_DYNAMIC_MEMORY == FALSE +GKI_API extern tGKI_CB gki_cb; +#else +GKI_API extern tGKI_CB *gki_cb_ptr; +#define gki_cb (*gki_cb_ptr) +#endif + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/gki/ulinux/gki_ulinux.c b/gki/ulinux/gki_ulinux.c new file mode 100644 index 0000000..73e93dc --- /dev/null +++ b/gki/ulinux/gki_ulinux.c @@ -0,0 +1,1355 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2012 Broadcom Corporation + * + * This program is the proprietary software of Broadcom Corporation and/or its + * licensors, and may only be used, duplicated, modified or distributed + * pursuant to the terms and conditions of a separate, written license + * agreement executed between you and Broadcom (an "Authorized License"). + * Except as set forth in an Authorized License, Broadcom grants no license + * (express or implied), right to use, or waiver of any kind with respect to + * the Software, and Broadcom expressly reserves all rights in and to the + * Software and all intellectual property rights therein. + * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS + * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE + * ALL USE OF THE SOFTWARE. + * + * Except as expressly set forth in the Authorized License, + * + * 1. This program, including its structure, sequence and organization, + * constitutes the valuable trade secrets of Broadcom, and you shall + * use all reasonable efforts to protect the confidentiality thereof, + * and to use this information only in connection with your use of + * Broadcom integrated circuit products. + * + * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED + * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES, + * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, + * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY + * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, + * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, + * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR + * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING + * OUT OF USE OR PERFORMANCE OF THE SOFTWARE. + * + * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM + * OR ITS LICENSORS BE LIABLE FOR + * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY + * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO + * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM + * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR + * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE + * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE + * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF + * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY. + * + *****************************************************************************/ + +/**************************************************************************** +** +** Name gki_linux_pthreads.c +** +** Function pthreads version of Linux GKI. This version is used for +** settop projects that already use pthreads and not pth. +** +*****************************************************************************/ + +#include +#include +#include +#include + +#include /* must be 1st header defined */ +#include +#include "gki_int.h" + +#define LOG_TAG "GKI_LINUX" + +#include + +/***************************************************************************** +** Constants & Macros +******************************************************************************/ + +#ifndef GKI_TICK_TIMER_DEBUG +#define GKI_TICK_TIMER_DEBUG FALSE +#endif + + +/* always log errors */ +#define GKI_ERROR_LOG(fmt, ...) LOGE ("##### ERROR : %s: " fmt "#####", __FUNCTION__, ## __VA_ARGS__) + +#if defined (GKI_TICK_TIMER_DEBUG) && (GKI_TICK_TIMER_DEBUG == TRUE) +#define GKI_TIMER_TRACE(fmt, ...) LOGI ("%s: " fmt, __FUNCTION__, ## __VA_ARGS__) +#else +#define GKI_TIMER_TRACE(fmt, ...) +#endif + + +#define SCHED_NORMAL 0 +#define SCHED_FIFO 1 +#define SCHED_RR 2 +#define SCHED_BATCH 3 + +#define NANOSEC_PER_MILLISEC (1000000) +#define NSEC_PER_SEC (1000*NANOSEC_PER_MILLISEC) + +/* works only for 1ms to 1000ms heart beat ranges */ +#define LINUX_SEC (1000/TICKS_PER_SEC) + +#define LOCK(m) pthread_mutex_lock(&m) +#define UNLOCK(m) pthread_mutex_unlock(&m) +#define INIT(m) pthread_mutex_init(&m, NULL) + +#define WAKE_LOCK_ID "brcm_btld" +#define PARTIAL_WAKE_LOCK 1 + +#if GKI_DYNAMIC_MEMORY == FALSE +tGKI_CB gki_cb; +#endif + +#ifdef NO_GKI_RUN_RETURN +static pthread_t timer_thread_id = 0; +static int shutdown_timer = 0; +#endif + +#ifndef GKI_SHUTDOWN_EVT +#define GKI_SHUTDOWN_EVT APPL_EVT_7 +#endif + +/***************************************************************************** +** Local type definitions +******************************************************************************/ + +#define pthread_cond_timedwait_monotonic pthread_cond_timedwait + +typedef struct +{ + UINT8 task_id; /* GKI task id */ + TASKPTR task_entry; /* Task entry function*/ + UINT32 params; /* Extra params to pass to task entry function */ +} gki_pthread_info_t; + + +/***************************************************************************** +** Static variables +******************************************************************************/ + +int g_GkiTimerWakeLockOn = 0; +gki_pthread_info_t gki_pthread_info[GKI_MAX_TASKS]; + +/***************************************************************************** +** Static functions +******************************************************************************/ + +/***************************************************************************** +** Externs +******************************************************************************/ + +extern int acquire_wake_lock(int lock, const char* id); +extern int release_wake_lock(const char* id); + +/***************************************************************************** +** Functions +******************************************************************************/ + + +/***************************************************************************** +** +** Function gki_task_entry +** +** Description GKI pthread callback +** +** Returns void +** +*******************************************************************************/ + +void gki_task_entry(UINT32 params) +{ + gki_pthread_info_t *p_pthread_info = (gki_pthread_info_t *)params; + gki_cb.os.thread_id[p_pthread_info->task_id] = pthread_self(); + + prctl(PR_SET_NAME, (unsigned long)gki_cb.com.OSTName[p_pthread_info->task_id], 0, 0, 0); + + GKI_TRACE("gki_task_entry task_id=%i\n", p_pthread_info->task_id); + + /* Call the actual thread entry point */ + (p_pthread_info->task_entry)(p_pthread_info->params); + + GKI_TRACE("gki_task task_id=%i terminating\n", p_pthread_info->task_id); + + pthread_exit(0); /* GKI tasks have no return value */ +} +/* end android */ + +/******************************************************************************* +** +** Function GKI_init +** +** Description This function is called once at startup to initialize +** all the timer structures. +** +** Returns void +** +*******************************************************************************/ + +void GKI_init(void) +{ + pthread_mutexattr_t attr; + tGKI_OS *p_os; + + memset (&gki_cb, 0, sizeof (gki_cb)); + + gki_buffer_init(); + gki_timers_init(); + gki_cb.com.OSTicks = (UINT32) times(0); + + pthread_mutexattr_init(&attr); + +#ifndef __CYGWIN__ + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); +#endif + p_os = &gki_cb.os; + pthread_mutex_init(&p_os->GKI_mutex, &attr); + /* pthread_mutex_init(&GKI_sched_mutex, NULL); */ +#if (GKI_DEBUG == TRUE) + pthread_mutex_init(&p_os->GKI_trace_mutex, NULL); +#endif + /* pthread_mutex_init(&thread_delay_mutex, NULL); */ /* used in GKI_delay */ + /* pthread_cond_init (&thread_delay_cond, NULL); */ + + /* Initialiase GKI_timer_update suspend variables & mutexes to be in running state. + * this works too even if GKI_NO_TICK_STOP is defined in btld.txt */ + p_os->no_timer_suspend = GKI_TIMER_TICK_RUN_COND; + pthread_mutex_init(&p_os->gki_timer_mutex, NULL); + pthread_cond_init(&p_os->gki_timer_cond, NULL); +} + + +/******************************************************************************* +** +** Function GKI_get_os_tick_count +** +** Description This function is called to retrieve the native OS system tick. +** +** Returns Tick count of native OS. +** +*******************************************************************************/ +UINT32 GKI_get_os_tick_count(void) +{ + /* TODO - add any OS specific code here */ + return (gki_cb.com.OSTicks); +} + +/******************************************************************************* +** +** Function GKI_create_task +** +** Description This function is called to create a new OSS task. +** +** Parameters: task_entry - (input) pointer to the entry function of the task +** task_id - (input) Task id is mapped to priority +** taskname - (input) name given to the task +** stack - (input) pointer to the top of the stack (highest memory location) +** stacksize - (input) size of the stack allocated for the task +** +** Returns GKI_SUCCESS if all OK, GKI_FAILURE if any problem +** +** NOTE This function take some parameters that may not be needed +** by your particular OS. They are here for compatability +** of the function prototype. +** +*******************************************************************************/ +UINT8 GKI_create_task (TASKPTR task_entry, UINT8 task_id, INT8 *taskname, UINT16 *stack, UINT16 stacksize) +{ + UINT16 i; + UINT8 *p; + struct sched_param param; + int policy, ret = 0; + pthread_attr_t attr1; + + GKI_TRACE( "GKI_create_task %x %d %s %x %d\n", task_entry, task_id, taskname, stack, + stacksize); + + if (task_id >= GKI_MAX_TASKS) + { + GKI_TRACE("Error! task ID > max task allowed"); + return (GKI_FAILURE); + } + + + gki_cb.com.OSRdyTbl[task_id] = TASK_READY; + gki_cb.com.OSTName[task_id] = taskname; + gki_cb.com.OSWaitTmr[task_id] = 0; + gki_cb.com.OSWaitEvt[task_id] = 0; + + /* Initialize mutex and condition variable objects for events and timeouts */ + pthread_mutex_init(&gki_cb.os.thread_evt_mutex[task_id], NULL); + pthread_cond_init (&gki_cb.os.thread_evt_cond[task_id], NULL); + pthread_mutex_init(&gki_cb.os.thread_timeout_mutex[task_id], NULL); + pthread_cond_init (&gki_cb.os.thread_timeout_cond[task_id], NULL); + + pthread_attr_init(&attr1); + /* by default, pthread creates a joinable thread */ +#if ( FALSE == GKI_PTHREAD_JOINABLE ) + pthread_attr_setdetachstate(&attr1, PTHREAD_CREATE_DETACHED); + + GKI_TRACE("GKI creating task %i\n", task_id); +#else + GKI_TRACE("GKI creating JOINABLE task %i\n", task_id); +#endif + + /* On Android, the new tasks starts running before 'gki_cb.os.thread_id[task_id]' is initialized */ + /* Pass task_id to new task so it can initialize gki_cb.os.thread_id[task_id] for it calls GKI_wait */ + gki_pthread_info[task_id].task_id = task_id; + gki_pthread_info[task_id].task_entry = task_entry; + gki_pthread_info[task_id].params = 0; + + ret = pthread_create( &gki_cb.os.thread_id[task_id], + &attr1, + (void *)gki_task_entry, + &gki_pthread_info[task_id]); + + if (ret != 0) + { + printf("pthread_create failed(%d), %s!\n\r", ret, taskname); + return GKI_FAILURE; + } + + if(pthread_getschedparam(gki_cb.os.thread_id[task_id], &policy, ¶m)==0) + { +#if (GKI_LINUX_BASE_POLICY!=GKI_SCHED_NORMAL) +#if defined(PBS_SQL_TASK) + if (task_id == PBS_SQL_TASK) + { + GKI_TRACE("PBS SQL lowest priority task"); + policy = SCHED_NORMAL; + } + else +#endif +#endif + { + /* check if define in gki_int.h is correct for this compile environment! */ + policy = GKI_LINUX_BASE_POLICY; +#if (GKI_LINUX_BASE_POLICY!=GKI_SCHED_NORMAL) + param.sched_priority = GKI_LINUX_BASE_PRIORITY - task_id - 2; +#endif + } + pthread_setschedparam(gki_cb.os.thread_id[task_id], policy, ¶m); + } + + GKI_TRACE( "Leaving GKI_create_task %x %d %x %s %x %d\n", + task_entry, + task_id, + gki_cb.os.thread_id[task_id], + taskname, + stack, + stacksize); + + return (GKI_SUCCESS); +} + +void GKI_destroy_task(UINT8 task_id) +{ +#if ( FALSE == GKI_PTHREAD_JOINABLE ) + int i = 0; +#else + int result; +#endif + if (gki_cb.com.OSRdyTbl[task_id] != TASK_DEAD) + { + gki_cb.com.OSRdyTbl[task_id] = TASK_DEAD; + + /* paranoi settings, make sure that we do not execute any mailbox events */ + gki_cb.com.OSWaitEvt[task_id] &= ~(TASK_MBOX_0_EVT_MASK|TASK_MBOX_1_EVT_MASK| + TASK_MBOX_2_EVT_MASK|TASK_MBOX_3_EVT_MASK); + GKI_send_event(task_id, EVENT_MASK(GKI_SHUTDOWN_EVT)); + +#if ( FALSE == GKI_PTHREAD_JOINABLE ) + i = 0; + + while ((gki_cb.com.OSWaitEvt[task_id] != 0) && (++i < 10)) + usleep(100 * 1000); +#else + result = pthread_join( gki_cb.os.thread_id[task_id], NULL ); + if ( result < 0 ) + { + GKI_TRACE( "pthread_join() FAILED: result: %d", result ); + } +#endif + GKI_ERROR_LOG( "GKI_shutdown(): task %s dead\n", gki_cb.com.OSTName[task_id]); + GKI_exit_task(task_id); + } + +} + + +/******************************************************************************* +** +** Function GKI_shutdown +** +** Description shutdowns the GKI tasks/threads in from max task id to 0 and frees +** pthread resources! +** IMPORTANT: in case of join method, GKI_shutdown must be called outside +** a GKI thread context! +** +** Returns void +** +*******************************************************************************/ + +void GKI_shutdown(void) +{ + UINT8 task_id; +#if ( FALSE == GKI_PTHREAD_JOINABLE ) + int i = 0; +#else + int result; +#endif + +#ifdef GKI_USE_DEFERED_ALLOC_BUF_POOLS + gki_dealloc_free_queue(); +#endif + + /* release threads and set as TASK_DEAD. going from low to high priority fixes + * GKI_exception problem due to btu->hci sleep request events */ + for (task_id = GKI_MAX_TASKS; task_id > 0; task_id--) + { + if (gki_cb.com.OSRdyTbl[task_id - 1] != TASK_DEAD) + { + gki_cb.com.OSRdyTbl[task_id - 1] = TASK_DEAD; + + /* paranoi settings, make sure that we do not execute any mailbox events */ + gki_cb.com.OSWaitEvt[task_id-1] &= ~(TASK_MBOX_0_EVT_MASK|TASK_MBOX_1_EVT_MASK| + TASK_MBOX_2_EVT_MASK|TASK_MBOX_3_EVT_MASK); + GKI_send_event(task_id - 1, EVENT_MASK(GKI_SHUTDOWN_EVT)); + +#if ( FALSE == GKI_PTHREAD_JOINABLE ) + i = 0; + + while ((gki_cb.com.OSWaitEvt[task_id - 1] != 0) && (++i < 10)) + usleep(100 * 1000); +#else + result = pthread_join( gki_cb.os.thread_id[task_id-1], NULL ); + + if ( result < 0 ) + { + LOGE( "pthread_join() FAILED: result: %d", result ); + } +#endif + // GKI_ERROR_LOG( "GKI_shutdown(): task %s dead\n", gki_cb.com.OSTName[task_id]); + GKI_exit_task(task_id - 1); + } + } + + /* Destroy mutex and condition variable objects */ + pthread_mutex_destroy(&gki_cb.os.GKI_mutex); + + /* pthread_mutex_destroy(&GKI_sched_mutex); */ +#if (GKI_DEBUG == TRUE) + pthread_mutex_destroy(&gki_cb.os.GKI_trace_mutex); +#endif + /* pthread_mutex_destroy(&thread_delay_mutex); + pthread_cond_destroy (&thread_delay_cond); */ +#if ( FALSE == GKI_PTHREAD_JOINABLE ) + i = 0; +#endif + +#ifdef NO_GKI_RUN_RETURN + shutdown_timer = 1; +#endif + if (g_GkiTimerWakeLockOn) + { + GKI_TRACE("GKI_shutdown : release_wake_lock(brcm_btld)"); + release_wake_lock(WAKE_LOCK_ID); + g_GkiTimerWakeLockOn = 0; + } +} + +/******************************************************************************* + ** + ** Function gki_system_tick_start_stop_cback + ** + ** Description This function runs a task + ** + ** Parameters: start: TRUE start system tick (again), FALSE stop + ** + ** Returns void + ** + *********************************************************************************/ + +void gki_system_tick_start_stop_cback(BOOLEAN start) +{ + tGKI_OS *p_os = &gki_cb.os; + volatile int *p_run_cond = &p_os->no_timer_suspend; + static int wake_lock_count; + if ( FALSE == start ) + { + /* this can lead to a race condition. however as we only read this variable in the timer loop + * we should be fine with this approach. otherwise uncomment below mutexes. + */ + /* GKI_disable(); */ + *p_run_cond = GKI_TIMER_TICK_STOP_COND; + /* GKI_enable(); */ + + GKI_TIMER_TRACE(">>> STOP GKI_timer_update(), wake_lock_count:%d", --wake_lock_count); + + release_wake_lock(WAKE_LOCK_ID); + g_GkiTimerWakeLockOn = 0; + } + else + { + /* restart GKI_timer_update() loop */ + acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); + + g_GkiTimerWakeLockOn = 1; + *p_run_cond = GKI_TIMER_TICK_RUN_COND; + + pthread_mutex_lock( &p_os->gki_timer_mutex ); + pthread_cond_signal( &p_os->gki_timer_cond ); + pthread_mutex_unlock( &p_os->gki_timer_mutex ); + + GKI_TIMER_TRACE(">>> START GKI_timer_update(), wake_lock_count:%d", ++wake_lock_count ); + } +} + + +/******************************************************************************* +** +** Function GKI_run +** +** Description This function runs a task +**** +** Returns void +** +** NOTE This function is only needed for operating systems where +** starting a task is a 2-step process. Most OS's do it in +** one step, If your OS does it in one step, this function +** should be empty. +*********************************************************************************/ + +#ifdef NO_GKI_RUN_RETURN +void* timer_thread(void *arg) +{ + struct timespec delay; + int err; + + while(!shutdown_timer) + { + delay.tv_sec = LINUX_SEC / 1000; + delay.tv_nsec = 1000 * 1000 * (LINUX_SEC%1000); + + /* [u]sleep can't be used because it uses SIGALRM */ + + do { + err = nanosleep(&delay, &delay); + } while (err < 0 && errno ==EINTR); + + GKI_timer_update(1); + } + GKI_TRACE("gki_ulinux: Exiting timer_thread"); + pthread_exit(NULL); + return NULL; +} +#endif + + +/***************************************************************************** +** +** Function gki_set_timer_scheduling +** +** Description helper function to set scheduling policy and priority of btdl +** +** Returns void +** +*******************************************************************************/ + +static void gki_set_timer_scheduling( void ) +{ + pid_t main_pid = getpid(); + struct sched_param param; + int policy; + + policy = sched_getscheduler(main_pid); + + if ( policy != -1 ) + { + GKI_TRACE("gki_set_timer_scheduling(()::scheduler current policy: %d", policy); + + /* ensure highest priority in the system + 2 to allow space for read threads */ + param.sched_priority = GKI_LINUX_TIMER_TICK_PRIORITY; + + if ( 0!=sched_setscheduler(main_pid, GKI_LINUX_TIMER_POLICY, ¶m ) ) + { + GKI_TRACE("sched_setscheduler() failed with error: %d", errno); + } + } + else + { + GKI_TRACE( "getscheduler failed: %d", errno); + } +} + + +/***************************************************************************** +** +** Function GKI_freeze +** +** Description Freeze GKI. Relevant only when NO_GKI_RUN_RETURN is defined +** +** Returns +** +*******************************************************************************/ + +void GKI_freeze() +{ +#ifdef NO_GKI_RUN_RETURN + shutdown_timer = 1; + /* Ensure that the timer thread exits */ + pthread_join(timer_thread_id, NULL); +#endif +} + +/***************************************************************************** +** +** Function GKI_run +** +** Description Main GKI loop +** +** Returns +** +*******************************************************************************/ + +void GKI_run (void *p_task_id) +{ + struct timespec delay; + int err; + volatile int * p_run_cond = &gki_cb.os.no_timer_suspend; + +#ifndef GKI_NO_TICK_STOP + /* adjust btld scheduling scheme now */ + gki_set_timer_scheduling(); + + /* register start stop function which disable timer loop in GKI_run() when no timers are + * in any GKI/BTA/BTU this should save power when BTLD is idle! */ + GKI_timer_queue_register_callback( gki_system_tick_start_stop_cback ); + GKI_TRACE( "GKI_run(): Start/Stop GKI_timer_update_registered!" ); +#endif + +#ifdef NO_GKI_RUN_RETURN + pthread_attr_t timer_attr; + + shutdown_timer = 0; + + pthread_attr_init(&timer_attr); + if (pthread_create( &timer_thread_id, + &timer_attr, + timer_thread, + NULL) != 0 ) + { + printf("GKI_run: pthread_create failed to create timer_thread!\n\r"); + return; + } + + prctl(PR_SET_NAME, (unsigned long)"gki timer", 0, 0, 0); + +#else + GKI_TRACE("GKI_run "); + for (;;) + { + do + { + /* adjust hear bit tick in btld by changning TICKS_PER_SEC!!!!! this formula works only for + * 1-1000ms heart beat units! */ + delay.tv_sec = LINUX_SEC / 1000; + delay.tv_nsec = 1000 * 1000 * (LINUX_SEC % 1000); + + /* [u]sleep can't be used because it uses SIGALRM */ + do + { + err = nanosleep(&delay, &delay); + } while (err < 0 && errno == EINTR); + + /* the unit should be alsways 1 (1 tick). only if you vary for some reason heart beat tick + * e.g. power saving you may want to provide more ticks + */ + GKI_timer_update( 1 ); + /* BT_TRACE_2( TRACE_LAYER_HCI, TRACE_TYPE_DEBUG, "update: tv_sec: %d, tv_nsec: %d", delay.tv_sec, delay.tv_nsec ); */ + } while ( GKI_TIMER_TICK_RUN_COND == *p_run_cond ); + + /* currently on reason to exit above loop is no_timer_suspend == GKI_TIMER_TICK_STOP_COND + * block timer main thread till re-armed by */ + + GKI_TIMER_TRACE(">>> SUSPENDED GKI_timer_update()" ); + + pthread_mutex_lock( &gki_cb.os.gki_timer_mutex ); + pthread_cond_wait( &gki_cb.os.gki_timer_cond, &gki_cb.os.gki_timer_mutex ); + pthread_mutex_unlock( &gki_cb.os.gki_timer_mutex ); + + /* potentially we need to adjust os gki_cb.com.OSTicks */ + GKI_TIMER_TRACE(">>> RESTARTED GKI_timer_update(): run_cond: %d", + *p_run_cond ); + + } +#endif + return; +} + + +/******************************************************************************* +** +** Function GKI_stop +** +** Description This function is called to stop +** the tasks and timers when the system is being stopped +** +** Returns void +** +** NOTE This function is NOT called by the Widcomm stack and +** profiles. If you want to use it in your own implementation, +** put specific code here. +** +*******************************************************************************/ + +void GKI_stop (void) +{ + UINT8 task_id; + + /* gki_queue_timer_cback(FALSE); */ + /* TODO - add code here if needed*/ + + for(task_id = 0; task_id NSEC_PER_SEC) + { + abstime.tv_sec += (abstime.tv_nsec / NSEC_PER_SEC); + abstime.tv_nsec = abstime.tv_nsec % NSEC_PER_SEC; + } + abstime.tv_sec += sec; + + pthread_cond_timedwait_monotonic(&gki_cb.os.thread_evt_cond[rtask], + &gki_cb.os.thread_evt_mutex[rtask], &abstime); + + } + else + { + pthread_cond_wait(&gki_cb.os.thread_evt_cond[rtask], &gki_cb.os.thread_evt_mutex[rtask]); + } + + /* TODO: check, this is probably neither not needed depending on phtread_cond_wait() implmentation, + e.g. it looks like it is implemented as a counter in which case multiple cond_signal + should NOT be lost! */ + + /* we are waking up after waiting for some events, so refresh variables + no need to call GKI_disable() here as we know that we will have some events as we've been waking + up after condition pending or timeout */ + + if (gki_cb.com.OSTaskQFirst[rtask][0]) + gki_cb.com.OSWaitEvt[rtask] |= TASK_MBOX_0_EVT_MASK; + if (gki_cb.com.OSTaskQFirst[rtask][1]) + gki_cb.com.OSWaitEvt[rtask] |= TASK_MBOX_1_EVT_MASK; + if (gki_cb.com.OSTaskQFirst[rtask][2]) + gki_cb.com.OSWaitEvt[rtask] |= TASK_MBOX_2_EVT_MASK; + if (gki_cb.com.OSTaskQFirst[rtask][3]) + gki_cb.com.OSWaitEvt[rtask] |= TASK_MBOX_3_EVT_MASK; + + if (gki_cb.com.OSRdyTbl[rtask] == TASK_DEAD) + { + gki_cb.com.OSWaitEvt[rtask] = 0; + /* unlock thread_evt_mutex as pthread_cond_wait() does auto lock when cond is met */ + pthread_mutex_unlock(&gki_cb.os.thread_evt_mutex[rtask]); + return (EVENT_MASK(GKI_SHUTDOWN_EVT)); + } + } + + /* Clear the wait for event mask */ + gki_cb.com.OSWaitForEvt[rtask] = 0; + + /* Return only those bits which user wants... */ + evt = gki_cb.com.OSWaitEvt[rtask] & flag; + + /* Clear only those bits which user wants... */ + gki_cb.com.OSWaitEvt[rtask] &= ~flag; + + /* unlock thread_evt_mutex as pthread_cond_wait() does auto lock mutex when cond is met */ + pthread_mutex_unlock(&gki_cb.os.thread_evt_mutex[rtask]); + + GKI_TRACE("GKI_wait %d %x %d %x done", rtask, flag, timeout, evt); + return (evt); +} + + +/******************************************************************************* +** +** Function GKI_delay +** +** Description This function is called by tasks to sleep unconditionally +** for a specified amount of time. The duration is in milliseconds +** +** Parameters: timeout - (input) the duration in milliseconds +** +** Returns void +** +*******************************************************************************/ + +void GKI_delay (UINT32 timeout) +{ + UINT8 rtask = GKI_get_taskid(); + struct timespec delay; + int err; + + GKI_TRACE("GKI_delay %d %d", rtask, timeout); + + delay.tv_sec = timeout / 1000; + delay.tv_nsec = 1000 * 1000 * (timeout%1000); + + /* [u]sleep can't be used because it uses SIGALRM */ + + do { + err = nanosleep(&delay, &delay); + } while (err < 0 && errno ==EINTR); + + /* Check if task was killed while sleeping */ + + /* NOTE : if you do not implement task killing, you do not need this check */ + + if (rtask && gki_cb.com.OSRdyTbl[rtask] == TASK_DEAD) + { + } + + GKI_TRACE("GKI_delay %d %d done", rtask, timeout); + + return; +} + + +/******************************************************************************* +** +** Function GKI_send_event +** +** Description This function is called by tasks to send events to other +** tasks. Tasks can also send events to themselves. +** +** Parameters: task_id - (input) The id of the task to which the event has to +** be sent +** event - (input) The event that has to be sent +** +** +** Returns GKI_SUCCESS if all OK, else GKI_FAILURE +** +*******************************************************************************/ + +UINT8 GKI_send_event (UINT8 task_id, UINT16 event) +{ + GKI_TRACE("GKI_send_event %d %x", task_id, event); + + /* use efficient coding to avoid pipeline stalls */ + if (task_id < GKI_MAX_TASKS) + { + /* protect OSWaitEvt[task_id] from manipulation in GKI_wait() */ + pthread_mutex_lock(&gki_cb.os.thread_evt_mutex[task_id]); + + /* Set the event bit */ + gki_cb.com.OSWaitEvt[task_id] |= event; + + pthread_cond_signal(&gki_cb.os.thread_evt_cond[task_id]); + + pthread_mutex_unlock(&gki_cb.os.thread_evt_mutex[task_id]); + + GKI_TRACE("GKI_send_event %d %x done", task_id, event); + return ( GKI_SUCCESS ); + } + return (GKI_FAILURE); +} + + +/******************************************************************************* +** +** Function GKI_isend_event +** +** Description This function is called from ISRs to send events to other +** tasks. The only difference between this function and GKI_send_event +** is that this function assumes interrupts are already disabled. +** +** Parameters: task_id - (input) The destination task Id for the event. +** event - (input) The event flag +** +** Returns GKI_SUCCESS if all OK, else GKI_FAILURE +** +** NOTE This function is NOT called by the Widcomm stack and +** profiles. If you want to use it in your own implementation, +** put your code here, otherwise you can delete the entire +** body of the function. +** +*******************************************************************************/ +UINT8 GKI_isend_event (UINT8 task_id, UINT16 event) +{ + GKI_TRACE("GKI_isend_event %d %x", task_id, event); + GKI_TRACE("GKI_isend_event %d %x done", task_id, event); + return GKI_send_event(task_id, event); +} + + +/******************************************************************************* +** +** Function GKI_get_taskid +** +** Description This function gets the currently running task ID. +** +** Returns task ID +** +** NOTE The Widcomm upper stack and profiles may run as a single task. +** If you only have one GKI task, then you can hard-code this +** function to return a '1'. Otherwise, you should have some +** OS-specific method to determine the current task. +** +*******************************************************************************/ +UINT8 GKI_get_taskid (void) +{ + int i; + + pthread_t thread_id = pthread_self( ); + + GKI_TRACE("GKI_get_taskid %x", thread_id); + + for (i = 0; i < GKI_MAX_TASKS; i++) { + if (gki_cb.os.thread_id[i] == thread_id) { + //GKI_TRACE("GKI_get_taskid %x %d done", thread_id, i); + return(i); + } + } + + GKI_TRACE("GKI_get_taskid: task id = -1"); + + return(-1); +} + + +/******************************************************************************* +** +** Function GKI_map_taskname +** +** Description This function gets the task name of the taskid passed as arg. +** If GKI_MAX_TASKS is passed as arg the currently running task +** name is returned +** +** Parameters: task_id - (input) The id of the task whose name is being +** sought. GKI_MAX_TASKS is passed to get the name of the +** currently running task. +** +** Returns pointer to task name +** +** NOTE this function needs no customization +** +*******************************************************************************/ + +INT8 *GKI_map_taskname (UINT8 task_id) +{ + GKI_TRACE("GKI_map_taskname %d", task_id); + + if (task_id < GKI_MAX_TASKS) + { + GKI_TRACE("GKI_map_taskname %d %s done", task_id, gki_cb.com.OSTName[task_id]); + return (gki_cb.com.OSTName[task_id]); + } + else if (task_id == GKI_MAX_TASKS ) + { + return (gki_cb.com.OSTName[GKI_get_taskid()]); + } + else + { + return (INT8*)"BAD"; + } +} + + +/******************************************************************************* +** +** Function GKI_enable +** +** Description This function enables interrupts. +** +** Returns void +** +*******************************************************************************/ +void GKI_enable (void) +{ + GKI_TRACE("GKI_enable"); + pthread_mutex_unlock(&gki_cb.os.GKI_mutex); + GKI_TRACE("Leaving GKI_enable"); + return; +} + + +/******************************************************************************* +** +** Function GKI_disable +** +** Description This function disables interrupts. +** +** Returns void +** +*******************************************************************************/ + +void GKI_disable (void) +{ + GKI_TRACE("GKI_disable"); + + pthread_mutex_lock(&gki_cb.os.GKI_mutex); + + GKI_TRACE("Leaving GKI_disable"); + return; +} + + +/******************************************************************************* +** +** Function GKI_exception +** +** Description This function throws an exception. +** This is normally only called for a nonrecoverable error. +** +** Parameters: code - (input) The code for the error +** msg - (input) The message that has to be logged +** +** Returns void +** +*******************************************************************************/ + +void GKI_exception (UINT16 code, char *msg) +{ + UINT8 task_id; + int i = 0; + + GKI_ERROR_LOG( "GKI_exception(): Task State Table\n"); + + for(task_id = 0; task_id < GKI_MAX_TASKS; task_id++) + { + GKI_ERROR_LOG( "TASK ID [%d] task name [%s] state [%d]\n", + task_id, + gki_cb.com.OSTName[task_id], + gki_cb.com.OSRdyTbl[task_id]); + } + + GKI_TRACE("GKI_exception %d %s", code, msg); + GKI_ERROR_LOG( "\n********************************************************************\n"); + GKI_ERROR_LOG( "* GKI_exception(): %d %s\n", code, msg); + GKI_ERROR_LOG( "********************************************************************\n"); + +#if 0//(GKI_DEBUG == TRUE) + GKI_disable(); + + if (gki_cb.com.ExceptionCnt < GKI_MAX_EXCEPTION) + { + EXCEPTION_T *pExp; + + pExp = &gki_cb.com.Exception[gki_cb.com.ExceptionCnt++]; + pExp->type = code; + pExp->taskid = GKI_get_taskid(); + strncpy((char *)pExp->msg, msg, GKI_MAX_EXCEPTION_MSGLEN - 1); + } + + GKI_enable(); +#endif + + GKI_TRACE("GKI_exception %d %s done", code, msg); + + + return; +} + + +/******************************************************************************* +** +** Function GKI_get_time_stamp +** +** Description This function formats the time into a user area +** +** Parameters: tbuf - (output) the address to the memory containing the +** formatted time +** +** Returns the address of the user area containing the formatted time +** The format of the time is ???? +** +** NOTE This function is only called by OBEX. +** +*******************************************************************************/ +INT8 *GKI_get_time_stamp (INT8 *tbuf) +{ + UINT32 ms_time; + UINT32 s_time; + UINT32 m_time; + UINT32 h_time; + INT8 *p_out = tbuf; + + gki_cb.com.OSTicks = times(0); + ms_time = GKI_TICKS_TO_MS(gki_cb.com.OSTicks); + s_time = ms_time/100; /* 100 Ticks per second */ + m_time = s_time/60; + h_time = m_time/60; + + ms_time -= s_time*100; + s_time -= m_time*60; + m_time -= h_time*60; + + *p_out++ = (INT8)((h_time / 10) + '0'); + *p_out++ = (INT8)((h_time % 10) + '0'); + *p_out++ = ':'; + *p_out++ = (INT8)((m_time / 10) + '0'); + *p_out++ = (INT8)((m_time % 10) + '0'); + *p_out++ = ':'; + *p_out++ = (INT8)((s_time / 10) + '0'); + *p_out++ = (INT8)((s_time % 10) + '0'); + *p_out++ = ':'; + *p_out++ = (INT8)((ms_time / 10) + '0'); + *p_out++ = (INT8)((ms_time % 10) + '0'); + *p_out++ = ':'; + *p_out = 0; + + return (tbuf); +} + + +/******************************************************************************* +** +** Function GKI_register_mempool +** +** Description This function registers a specific memory pool. +** +** Parameters: p_mem - (input) pointer to the memory pool +** +** Returns void +** +** NOTE This function is NOT called by the Widcomm stack and +** profiles. If your OS has different memory pools, you +** can tell GKI the pool to use by calling this function. +** +*******************************************************************************/ +void GKI_register_mempool (void *p_mem) +{ + gki_cb.com.p_user_mempool = p_mem; + + return; +} + +/******************************************************************************* +** +** Function GKI_os_malloc +** +** Description This function allocates memory +** +** Parameters: size - (input) The size of the memory that has to be +** allocated +** +** Returns the address of the memory allocated, or NULL if failed +** +** NOTE This function is called by the Widcomm stack when +** dynamic memory allocation is used. (see dyn_mem.h) +** +*******************************************************************************/ +void *GKI_os_malloc (UINT32 size) +{ + return (malloc(size)); +} + +/******************************************************************************* +** +** Function GKI_os_free +** +** Description This function frees memory +** +** Parameters: size - (input) The address of the memory that has to be +** freed +** +** Returns void +** +** NOTE This function is NOT called by the Widcomm stack and +** profiles. It is only called from within GKI if dynamic +** +*******************************************************************************/ +void GKI_os_free (void *p_mem) +{ + if(p_mem != NULL) + free(p_mem); + return; +} + + +/******************************************************************************* +** +** Function GKI_suspend_task() +** +** Description This function suspends the task specified in the argument. +** +** Parameters: task_id - (input) the id of the task that has to suspended +** +** Returns GKI_SUCCESS if all OK, else GKI_FAILURE +** +** NOTE This function is NOT called by the Widcomm stack and +** profiles. If you want to implement task suspension capability, +** put specific code here. +** +*******************************************************************************/ +UINT8 GKI_suspend_task (UINT8 task_id) +{ + GKI_TRACE("GKI_suspend_task %d - NOT implemented", task_id); + + + GKI_TRACE("GKI_suspend_task %d done", task_id); + + return (GKI_SUCCESS); +} + + +/******************************************************************************* +** +** Function GKI_resume_task() +** +** Description This function resumes the task specified in the argument. +** +** Parameters: task_id - (input) the id of the task that has to resumed +** +** Returns GKI_SUCCESS if all OK +** +** NOTE This function is NOT called by the Widcomm stack and +** profiles. If you want to implement task suspension capability, +** put specific code here. +** +*******************************************************************************/ +UINT8 GKI_resume_task (UINT8 task_id) +{ + GKI_TRACE("GKI_resume_task %d - NOT implemented", task_id); + + + GKI_TRACE("GKI_resume_task %d done", task_id); + + return (GKI_SUCCESS); +} + + +/******************************************************************************* +** +** Function GKI_exit_task +** +** Description This function is called to stop a GKI task. +** +** Parameters: task_id - (input) the id of the task that has to be stopped +** +** Returns void +** +** NOTE This function is NOT called by the Widcomm stack and +** profiles. If you want to use it in your own implementation, +** put specific code here to kill a task. +** +*******************************************************************************/ +void GKI_exit_task (UINT8 task_id) +{ + GKI_disable(); + gki_cb.com.OSRdyTbl[task_id] = TASK_DEAD; + + /* Destroy mutex and condition variable objects */ + pthread_mutex_destroy(&gki_cb.os.thread_evt_mutex[task_id]); + pthread_cond_destroy (&gki_cb.os.thread_evt_cond[task_id]); + pthread_mutex_destroy(&gki_cb.os.thread_timeout_mutex[task_id]); + pthread_cond_destroy (&gki_cb.os.thread_timeout_cond[task_id]); + + GKI_enable(); + + //GKI_send_event(task_id, EVENT_MASK(GKI_SHUTDOWN_EVT)); + + GKI_TRACE("GKI_exit_task %d done", task_id); + return; +} + + +/******************************************************************************* +** +** Function GKI_sched_lock +** +** Description This function is called by tasks to disable scheduler +** task context switching. +** +** Returns void +** +** NOTE This function is NOT called by the Widcomm stack and +** profiles. If you want to use it in your own implementation, +** put code here to tell the OS to disable context switching. +** +*******************************************************************************/ +void GKI_sched_lock(void) +{ + GKI_TRACE("GKI_sched_lock"); + return; +} + + +/******************************************************************************* +** +** Function GKI_sched_unlock +** +** Description This function is called by tasks to enable scheduler switching. +** +** Returns void +** +** NOTE This function is NOT called by the Widcomm stack and +** profiles. If you want to use it in your own implementation, +** put code here to tell the OS to re-enable context switching. +** +*******************************************************************************/ +void GKI_sched_unlock(void) +{ + GKI_TRACE("GKI_sched_unlock"); +} + + -- cgit v1.1