375 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			375 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /**
 | |
| 	@brief vos mailbox (virtual-os user-space)
 | |
| 
 | |
| 	@file vos_user_mailbox.c
 | |
| 
 | |
| 	@ingroup vos_user
 | |
| 
 | |
| 	@note Nothing.
 | |
| 
 | |
| 	Copyright Novatek Microelectronics Corp. 2019.  All rights reserved.
 | |
| */
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| /* Include Header Files                                                        */
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| #define __MODULE__    vos_user_mailbox
 | |
| #define __DBGLVL__    7
 | |
| #include <kwrap/debug.h>
 | |
| #include <kwrap/mailbox.h>
 | |
| 
 | |
| #include <errno.h>
 | |
| #include <fcntl.h>
 | |
| #include <mqueue.h>
 | |
| #include <pthread.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <sys/ipc.h>
 | |
| #include <sys/stat.h>
 | |
| #include <unistd.h>
 | |
| 
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| /* Local Constant Definitions                                                  */
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| #define VOS_MBX_MIN_VALID_ID    1
 | |
| #define VOS_MBX_DEV_PATH        "/dev/RTOS_MBox"
 | |
| #define VOS_MBX_MQUEUE_NAME     "/vos_mqueue_name"
 | |
| #define VOS_MBX_MSG_PRIO        0
 | |
| #define RTOS_MBX_INITED_TAG     MAKEFOURCC('R', 'M', 'B', 'X') ///< a key value
 | |
| #define _BUFFER_SIZE_           32
 | |
| #define VOS_MBX_USE_IOCTL       0
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| /* Extern Global Variables                                                     */
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| /* Extern Function Prototype                                                   */
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| /* Local Function Protype                                                      */
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| /* Local Types Declarations                                                    */
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| typedef struct {
 | |
| 	int st_used;
 | |
| 	mqd_t st_mqd;
 | |
| 	UINT st_msgsize;
 | |
| } MBX_CELL_T;
 | |
| 
 | |
| typedef struct {
 | |
| 	int ioctl_fd;
 | |
| 	MBX_CELL_T *p_cell;
 | |
| } MBX_CTRL_T;
 | |
| 
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| /* Local Global Variables                                                      */
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| UINT g_max_mbxid_num = 0;
 | |
| UINT g_cur_mbxid = 0;
 | |
| 
 | |
| static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
 | |
| static MBX_CTRL_T g_ctrl = {.ioctl_fd = -1, .p_cell = NULL};
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| /* Interface Functions                                                         */
 | |
| /*-----------------------------------------------------------------------------*/
 | |
| ER vos_mbx_init(UINT max_mbxid_num)
 | |
| {
 | |
| 	ER ret = E_OK;
 | |
| 
 | |
| 	pthread_mutex_lock(&g_mutex);
 | |
| 
 | |
| 	if (g_ctrl.ioctl_fd >= 0) {
 | |
| 		DBG_WRN("Already initialized, please call vos_mbx_exit first\r\n");
 | |
| 		ret = E_OK;
 | |
| 		goto vos_mbx_init_end; //already initialized
 | |
| 	}
 | |
| 
 | |
| 	if (!max_mbxid_num) {
 | |
| 		DBG_ERR("Invalid param, max_mbxid_num %d\r\n", max_mbxid_num);
 | |
| 		ret = E_PAR;
 | |
| 		goto vos_mbx_init_end;
 | |
| 	}
 | |
| 
 | |
| 	g_ctrl.p_cell = calloc(1, max_mbxid_num * sizeof(MBX_CELL_T));
 | |
| 	if (NULL == g_ctrl.p_cell) {
 | |
| 		DBG_ERR("get memory failed\r\n");
 | |
| 		ret = E_NOMEM;
 | |
| 		goto vos_mbx_init_end;
 | |
| 	}
 | |
| 
 | |
| #if VOS_MBX_USE_IOCTL
 | |
| 	g_ctrl.ioctl_fd = open(VOS_MBX_DEV_PATH, O_RDWR);
 | |
| 	if (-1 == g_ctrl.ioctl_fd) {
 | |
| 		DBG_ERR("open %s failed\r\n", VOS_MBX_DEV_PATH);
 | |
| 		ret = E_SYS;
 | |
| 		goto vos_mbx_init_end;
 | |
| 	}
 | |
| #else
 | |
| 	g_ctrl.ioctl_fd = 0; //set 0 to pretend initialized
 | |
| #endif
 | |
| 
 | |
| 	g_max_mbxid_num = max_mbxid_num;
 | |
| 
 | |
| 	DBG_IND("g_max_mbxid_num %d\r\n", g_max_mbxid_num);
 | |
| 
 | |
| vos_mbx_init_end:
 | |
| 	if (E_OK != ret) {
 | |
| 		if (g_ctrl.p_cell) {
 | |
| 			free(g_ctrl.p_cell);
 | |
| 			g_ctrl.p_cell = NULL;
 | |
| 		}
 | |
| 	}
 | |
| 	pthread_mutex_unlock(&g_mutex);
 | |
| 
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| ER vos_mbx_exit(void)
 | |
| {
 | |
| 	ER ret = E_OK;
 | |
| 
 | |
| 	pthread_mutex_lock(&g_mutex);
 | |
| 
 | |
| 	if (g_ctrl.ioctl_fd < 0) {
 | |
| 		ret = E_OK;
 | |
| 		goto vos_mbx_exit_end; //already uninitialized
 | |
| 	}
 | |
| 
 | |
| #if VOS_MBX_USE_IOCTL
 | |
| 	if (0 != close(g_ctrl.ioctl_fd)) {
 | |
| 		DBG_ERR("close fails, ioctl_fd 0x%X\r\n", g_ctrl.ioctl_fd);
 | |
| 		ret = E_SYS;
 | |
| 		goto vos_mbx_exit_end;
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| 	g_ctrl.ioctl_fd = -1;
 | |
| 
 | |
| vos_mbx_exit_end:
 | |
| 	pthread_mutex_unlock(&g_mutex);
 | |
| 
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| static MBX_CELL_T* vos_mbx_get_cell(ID mbxid)
 | |
| {
 | |
| 	MBX_CELL_T *p_cell;
 | |
| 
 | |
| 	if (NULL == g_ctrl.p_cell || 0 == g_max_mbxid_num) {
 | |
| 		DBG_ERR("Please call vos_mbx_init first\r\n");
 | |
| 		return NULL;
 | |
| 	}
 | |
| 
 | |
| 	if ((UINT)mbxid < VOS_MBX_MIN_VALID_ID || (UINT)mbxid > g_max_mbxid_num) {
 | |
| 		DBG_ERR("Invalid mbxid %d, should be %d ~ %d\r\n", mbxid, VOS_MBX_MIN_VALID_ID, g_max_mbxid_num);
 | |
| 		return NULL;
 | |
| 	}
 | |
| 
 | |
| 	p_cell = g_ctrl.p_cell + (mbxid - VOS_MBX_MIN_VALID_ID);
 | |
| 
 | |
| 	if (RTOS_MBX_INITED_TAG != p_cell->st_used) {
 | |
| 		DBG_ERR("mbxid %d not created\r\n", mbxid);
 | |
| 		return NULL;
 | |
| 	}
 | |
| 
 | |
| 	return p_cell;
 | |
| }
 | |
| 
 | |
| static void vos_mbx_dump_mqattr(mqd_t mqd)
 | |
| {
 | |
| 	struct mq_attr attr;
 | |
| 
 | |
| 	if (-1 == mq_getattr(mqd, &attr)) {
 | |
| 		DBG_ERR("mq_getattr failed\r\n");
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	DBG_DUMP("mq_flags 0x%lX, mq_maxmsg %ld, mq_msgsize %ld, mq_curmsgs %ld\r\n",
 | |
| 		attr.mq_flags, attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs);
 | |
| }
 | |
| 
 | |
| //! Common api
 | |
| ER vos_mbx_create(ID *p_mbxid, VOS_MBX_PARAM *p_param)
 | |
| {
 | |
| 	char mqueue_name[_BUFFER_SIZE_];
 | |
| 	struct mq_attr attr;
 | |
| 	UINT new_mbxid;
 | |
| 	int loop_count;
 | |
| 	MBX_CELL_T *p_cell = NULL;
 | |
| 	ER ret = E_OK;
 | |
| 	int is_found = 0;
 | |
| 	mqd_t mqd;
 | |
| 
 | |
| 	// error check before lock
 | |
| 	if (g_max_mbxid_num < 1) {
 | |
| 		DBG_ERR("Please call vos_mbx_init first\r\n");
 | |
| 		return E_SYS;
 | |
| 	}
 | |
| 
 | |
| 	if (NULL == p_param) {
 | |
| 		DBG_ERR("p_param is NULL\r\n");
 | |
| 		return E_PAR;
 | |
| 	}
 | |
| 
 | |
| 	if (0 == p_param->maxmsg || 0 == p_param->msgsize) {
 | |
| 		DBG_ERR("Invalid param, maxmsg %d, msgsize %d\r\n", p_param->maxmsg, p_param->msgsize);
 | |
| 		return E_PAR;
 | |
| 	}
 | |
| 
 | |
| 	pthread_mutex_lock(&g_mutex);
 | |
| 
 | |
| 	// loop initial state
 | |
| 	new_mbxid = g_cur_mbxid;
 | |
| 	loop_count = g_max_mbxid_num;
 | |
| 
 | |
| 	while(loop_count--) {
 | |
| 		new_mbxid++;
 | |
| 		if (new_mbxid > g_max_mbxid_num) {
 | |
| 			new_mbxid = VOS_MBX_MIN_VALID_ID;
 | |
| 		}
 | |
| 
 | |
| 		p_cell = &g_ctrl.p_cell[new_mbxid - VOS_MBX_MIN_VALID_ID]; //mbxid to mbx array index
 | |
| 		if (0 == p_cell->st_used) {
 | |
| 			// found a free cell
 | |
| 			is_found = 1;
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (!is_found) {
 | |
| 		DBG_ERR("no free mbx id\r\n");
 | |
| 		ret = E_SYS;
 | |
| 		goto vos_mbx_create_end;
 | |
| 	}
 | |
| 
 | |
| 	// already found here
 | |
| 	attr.mq_flags = 0; //Flags: 0 or O_NONBLOCK
 | |
| 	attr.mq_maxmsg = (long)p_param->maxmsg;
 | |
| 	attr.mq_msgsize = (long)p_param->msgsize;
 | |
| 	attr.mq_curmsgs = 0; //dummy
 | |
| 
 | |
| 	snprintf((char*)mqueue_name, _BUFFER_SIZE_, "%s_%d", VOS_MBX_MQUEUE_NAME, new_mbxid);
 | |
| 	mqd = mq_open(mqueue_name, O_CREAT | O_RDWR, 0644, &attr);
 | |
| 	if (((mqd_t)-1) == mqd) {
 | |
| 		DBG_ERR("mq_open %s failed, errno %d\r\n", mqueue_name, errno);
 | |
| 		ret = E_SYS;
 | |
| 		goto vos_mbx_create_end;
 | |
| 	}
 | |
| 
 | |
| 	p_cell->st_used = RTOS_MBX_INITED_TAG;
 | |
| 	p_cell->st_mqd = mqd;
 | |
| 	p_cell->st_msgsize = p_param->msgsize;
 | |
| 
 | |
| 	g_cur_mbxid = new_mbxid;
 | |
| 	*p_mbxid = new_mbxid;
 | |
| 
 | |
| vos_mbx_create_end:
 | |
| 	if (E_OK != ret) {
 | |
| 		*p_mbxid = 0;
 | |
| 	}
 | |
| 	pthread_mutex_unlock(&g_mutex);
 | |
| 
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| void vos_mbx_destroy(ID mbxid)
 | |
| {
 | |
| 	MBX_CELL_T *p_cell;
 | |
| 
 | |
| 	pthread_mutex_lock(&g_mutex);
 | |
| 
 | |
| 	p_cell = vos_mbx_get_cell(mbxid);
 | |
| 	if (NULL == p_cell) {
 | |
| 		DBG_ERR("get cell failed, mbxid %d\r\n", mbxid);
 | |
| 		goto vos_mbx_destroy_end;
 | |
| 	}
 | |
| 
 | |
| 	if (-1 == mq_close(p_cell->st_mqd)) {
 | |
| 		DBG_ERR("mq_close failed, mbxid %d, errno %d\r\n", mbxid, errno);
 | |
| 		goto vos_mbx_destroy_end;
 | |
| 	}
 | |
| 
 | |
| 	memset(p_cell, 0, sizeof(MBX_CELL_T));
 | |
| 
 | |
| vos_mbx_destroy_end:
 | |
| 	pthread_mutex_unlock(&g_mutex);
 | |
| }
 | |
| 
 | |
| ER vos_mbx_snd(ID mbxid, void *p_data, UINT size)
 | |
| {
 | |
| 	MBX_CELL_T *p_cell;
 | |
| 
 | |
| 	p_cell = vos_mbx_get_cell(mbxid);
 | |
| 	if (NULL == p_cell) {
 | |
| 		DBG_ERR("get cell failed, mbxid %d\r\n", mbxid);
 | |
| 		return E_PAR;
 | |
| 	}
 | |
| 
 | |
| 	if (-1 == mq_send(p_cell->st_mqd, p_data, size, VOS_MBX_MSG_PRIO)) {
 | |
| 		if (EBADF == errno) {
 | |
| 			DBG_ERR("Invalid mqd, mbxid %d\r\n", mbxid);
 | |
| 		} else if (EMSGSIZE == errno) {
 | |
| 			DBG_ERR("snd size (%d) exceeds msgsize\r\n", size);
 | |
| 			vos_mbx_dump_mqattr(p_cell->st_mqd);
 | |
| 		} else {
 | |
| 			DBG_ERR("mq_send failed, mbxid %d, errno %d\r\n", mbxid, errno);
 | |
| 			vos_mbx_dump_mqattr(p_cell->st_mqd);
 | |
| 		}
 | |
| 		return E_SYS;
 | |
| 	}
 | |
| 
 | |
| 	return E_OK;
 | |
| }
 | |
| 
 | |
| ER vos_mbx_rcv(ID mbxid, void *p_data, UINT size)
 | |
| {
 | |
| 	MBX_CELL_T *p_cell;
 | |
| 
 | |
| 	p_cell = vos_mbx_get_cell(mbxid);
 | |
| 	if (NULL == p_cell) {
 | |
| 		DBG_ERR("get cell failed, mbxid %d\r\n", mbxid);
 | |
| 		return E_PAR;
 | |
| 	}
 | |
| 
 | |
| 	if (size < p_cell->st_msgsize) {
 | |
| 		DBG_ERR("size(%d) < msgsize(%d)\r\n", size, p_cell->st_msgsize);
 | |
| 		return E_PAR; //if size < mq_msgsize, mq_receive will return fail
 | |
| 	}
 | |
| 
 | |
| 	if (-1 == mq_receive(p_cell->st_mqd, p_data, size, NULL)) {
 | |
| 		if (EBADF == errno) {
 | |
| 			DBG_ERR("Invalid mqd, mbxid %d\r\n", mbxid);
 | |
| 		} else if (EMSGSIZE == errno) {
 | |
| 			DBG_ERR("rcv size (%d) not enouth\r\n", size);
 | |
| 			vos_mbx_dump_mqattr(p_cell->st_mqd);
 | |
| 		} else {
 | |
| 			DBG_ERR("mq_receive failed, mbxid %d, errno %d\r\n", mbxid, errno);
 | |
| 			vos_mbx_dump_mqattr(p_cell->st_mqd);
 | |
| 		}
 | |
| 		return E_SYS;
 | |
| 	}
 | |
| 
 | |
| 	return E_OK;
 | |
| }
 | |
| 
 | |
| UINT vos_mbx_is_empty(ID mbxid)
 | |
| {
 | |
| 	struct mq_attr attr;
 | |
| 	MBX_CELL_T *p_cell;
 | |
| 
 | |
| 	p_cell = vos_mbx_get_cell(mbxid);
 | |
| 	if (NULL == p_cell) {
 | |
| 		DBG_ERR("get cell failed, mbxid %d\r\n", mbxid);
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	if (-1 == mq_getattr(p_cell->st_mqd, &attr)) {
 | |
| 		DBG_ERR("mq_getattr failed\r\n");
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	DBG_DUMP("mq_flags 0x%lX, mq_maxmsg %ld, mq_msgsize %ld, mq_curmsgs %ld\r\n",
 | |
| 		attr.mq_flags, attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs);
 | |
| 
 | |
| 	return (attr.mq_curmsgs == 0);
 | |
| }
 | 
