#include "drStd.h"
#include "DrApi/DrApiMm.h"
#if TBASE_API_LEVEL >= 5
#include "DrApi/DrApiMmExt.h"
#include "DrApi/DrApiError.h"
#endif
#include "DrApi/DrApiThread.h"
#include "log.h"
#include "sec_log.h"
#include "debug_log.h"
#include "drTimaMm.h"
#include <string.h>

log_header_t g_log_hdr;

#if TBASE_API_LEVEL >= 5
addr_t tima_sec_log_page_va, tima_dbg_log_page_va;
#endif

long inline get_time(
	void
)
{
	return 0;
}

/* @log_start: starting virtual address of the log 
 * @log_size: MISLEADING WARNING: This is the nr_bytes that need to be memset to zero
 * 		NOT the actual size of the log.
 */
int log_init(
	log_info_t log_info
)
{
	log_header_t *header_ptr;

	header_ptr = (log_header_t *) log_info.log_hdr_vaddr;
	TTY_LOG("log.c[1]: header_ptr->magic is 0x%x", header_ptr->magic);
	TTY_LOG("log.c[1]: header_ptr->log_start_addr is 0x%x", header_ptr->log_start_addr);
	TTY_LOG("log.c[1]: header_ptr->log_write_addr is 0x%x", header_ptr->log_write_addr);
	TTY_LOG("log.c[1]: header_ptr->num_log_entries is 0x%x", header_ptr->num_log_entries);

	if (header_ptr->magic != LOG_MAGIC) {
		memset((void *)log_info.log_hdr_vaddr, 0, TIMA_LOG_MAP_SIZE);
		header_ptr->magic = LOG_MAGIC;
		header_ptr->log_start_addr =
		    log_info.log_start_paddr + sizeof(log_header_t);
		header_ptr->log_write_addr =
		    log_info.log_start_paddr + sizeof(log_header_t);
		header_ptr->num_log_entries = 0;
	}
	TTY_LOG("log.c[2]: header_ptr->magic is 0x%x", header_ptr->magic);
	TTY_LOG("log.c[2]: header_ptr->log_start_addr is 0x%x", header_ptr->log_start_addr);
	TTY_LOG("log.c[2]: header_ptr->log_write_addr is 0x%x", header_ptr->log_write_addr);
	TTY_LOG("log.c[2]: header_ptr->num_log_entries is 0x%x", header_ptr->num_log_entries);

	return 0;
}

int32_t log_read(
	int32_t region,
	int32_t entry_index,
	void *rsp
)
{
	int32_t ret = 0;

	//buf_address = TIMA_SEC_LOG_VADDR;
#if 0
	ret =
	    qsee_register_shared_buffer((void *)(buf_address & SECT_MASK),
					1 << 20);
	if (ret != 0)
		return -1;
	memcpy(rsp, (void *)buf_address, 1 << 19);
	qsee_deregister_shared_buffer((void *)(buf_address & SECT_MASK));
#endif
	return ret;
}

int log_update_header(
	log_info_t log_info,
	uint32_t log_write_addr
)
{
	log_header_t *header_ptr = (log_header_t *) log_info.log_hdr_vaddr;

	/* num_log_entries counts total entries, not just circular buffer entries */
	header_ptr->num_log_entries++;

	if (log_write_addr + sizeof(log_entry_t) >=
	    (log_info.log_start_paddr + log_info.log_size))
		/* Reset pointer to the start of the log. Circular */
		header_ptr->log_write_addr =
		    log_info.log_start_paddr + sizeof(log_header_t);
	else
		header_ptr->log_write_addr =
		    log_write_addr + sizeof(log_entry_t);

	return 0;
}

int log_add_entry(
	log_info_t log_info,
	log_entry_t * pentry
)
{
	log_header_t *header_ptr;
	uint32_t write_ptr_paddr, write_ptr_vaddr;
	drApiResult_t drRet;

	header_ptr = (log_header_t *) log_info.log_hdr_vaddr;
	write_ptr_paddr = header_ptr->log_write_addr;

	if ((write_ptr_paddr < TIMA_DBG_LOG_PADDR) || (write_ptr_paddr >= (TIMA_DBG_LOG_PADDR + TIMA_DBG_LOG_SIZE + TIMA_SEC_LOG_SIZE))) {
		TTY_LOG("tima log buffer is out of range!!!");
		return -1;
	}
	TTY_LOG("write_ptr_paddr is %x", write_ptr_paddr);

	/* Initialize sec_log memory */
#if TBASE_API_LEVEL >= 5
	drRet = drApiMapPhysicalBuffer((write_ptr_paddr & ~TIMA_LOG_MAP_MASK),
			TIMA_LOG_MAP_SIZE,
			MAP_READABLE | MAP_WRITABLE | MAP_UNCACHED,
			(void **)&tima_sec_log_page_va);
	if (drRet != DRAPI_OK) {
		TTY_LOG("Cannot map tima_sec_log_page_va: %x", drRet);
		return -1;
	}
	log_info.log_data_vaddr = (uint32_t)(uint32_t *)tima_sec_log_page_va;
	
	write_ptr_vaddr = (uint32_t)tima_sec_log_page_va + (write_ptr_paddr & TIMA_LOG_MAP_MASK);
	
	memcpy((addr_t) write_ptr_vaddr, pentry, sizeof(log_entry_t));
	drRet = drApiUnmapBuffer(tima_sec_log_page_va);
	if (drRet != DRAPI_OK) {
		TTY_LOG("Cannot unmap tima_sec_log_page_va: %x", drRet);
		return -1;
	}
#else
	drRet = drApiMapPhys((addr_t) TIMA_SEC_LOG_PAGE, TIMA_LOG_MAP_SIZE,
			     (addr_t) (write_ptr_paddr & ~TIMA_LOG_MAP_MASK),
			     MAP_READABLE | MAP_WRITABLE | MAP_UNCACHED);
	if (E_OK != drRet) {
		dbgSN("Cannot map sec_log val");
		return -1;
	}
	write_ptr_vaddr =
	    TIMA_SEC_LOG_PAGE + (write_ptr_paddr & TIMA_LOG_MAP_MASK);
	memcpy((addr_t) write_ptr_vaddr, pentry, sizeof(log_entry_t));
	drApiUnmap((addr_t) TIMA_SEC_LOG_PAGE, TIMA_LOG_MAP_SIZE);
#endif
	log_update_header(log_info, header_ptr->log_write_addr);
	return 0;
}

log_entry_t g_entry_ptr;
void log_msg(
	log_info_t log_info,
	char *msg
)
{
	memset(&g_entry_ptr, 0, sizeof(log_entry_t));
	g_entry_ptr.logger_id = 1;	/*FIXME */
	g_entry_ptr.timestamp = 9999;	/*FIXME how to get timestamp?   */
	snprintf(g_entry_ptr.log_msg, LOG_MSG_SIZE - 1, "%s", msg);
	log_add_entry(log_info, &g_entry_ptr);
	dbgSN(msg);
}
