/*****************************************************************************
 函 数 名  : mailbox_request_channel
 接口类型  : 对外接口
 功能描述  : 打开一个邮箱通道,准备开始写或者一封邮件。
             根据现有的邮箱通道号,创建一个邮箱操作符号,并根据邮箱头填充邮箱操作符信息
 输入参数  : struct mb *mailbox 邮箱控制总句柄
             unsigned long     mailcode  -- 待访问邮件的ID
 输出参数  : 无
 返 回 值  : 一个邮箱通道的操作符
 调用函数  :

 被调函数  :

 修改历史      :
  1.日    期   : 2012年9月27日
    作    者   : 莫南 00176101
    修改内容   : 新生成函数

*****************************************************************************/
MAILBOX_EXTERN struct mb_buff *mailbox_get_channel_handle(
                struct mb *mailbox,
                unsigned long mailcode)
{
    struct mb_link          *link_array   = MAILBOX_NULL;
    struct mb_buff                 *mbuff   = MAILBOX_NULL;
    unsigned long            src_id        = 0;
    unsigned long            dst_id        = 0;
    unsigned long            carrier_id    = 0;

    src_id       = mailbox_get_src_id(mailcode);
    dst_id       = mailbox_get_dst_id(mailcode);
    carrier_id   = mailbox_get_carrier_id(mailcode);

    if (src_id == mailbox->local_id) {
        if (dst_id < MAILBOX_CPUID_BUTT) {
            link_array = &mailbox->send_tbl[dst_id];
        } else {
            /*无效目标号,数组越界*/
            mailbox_logerro_p1(MAILBOX_ERR_GUT_INVALID_CHANNEL_ID, mailcode);
            return MAILBOX_NULL;
        }
    } else if (dst_id == mailbox->local_id) {
        if (src_id < MAILBOX_CPUID_BUTT) {
            link_array = &mailbox->recv_tbl[src_id];
        } else {
            /*无效目标号,数组越界*/
            mailbox_logerro_p1(MAILBOX_ERR_GUT_INVALID_CHANNEL_ID, mailcode);
            return MAILBOX_NULL;
        }
    } else {
        /*此处已在收发入口判断*/
    }

    if ((MAILBOX_NULL == link_array) || (0 == link_array->carrier_butt)) {
        /*当前两个CPU之间不存在任何邮箱通道*/
        mailbox_logerro_p1(MAILBOX_ERR_GUT_INVALID_CPU_LINK, mailcode);
        return MAILBOX_NULL;
    }

    /*获得通道操作句柄*/
    if (carrier_id < link_array->carrier_butt) {
        mbuff = &link_array->channel_buff[carrier_id];
    } else {
        /*非法载体号,数组越界*/
        mailbox_logerro_p1(MAILBOX_ERR_GUT_INVALID_CARRIER_ID, mailcode);
        return MAILBOX_NULL;
    }

    /*检查mail code中 use ID的合法性*/
    if (mailbox_get_use_id(mailcode) >= mailbox_get_use_id(mbuff->config->butt_id)) {
        mailbox_logerro_p1(MAILBOX_ERR_GUT_INVALID_USER_ID, mailcode);

        #ifndef _DRV_LLT_ /*PC工程允许发送非法use ID,用于测试接收通道代码分支*/
        return MAILBOX_NULL;
        #endif
    }

    return mbuff;
}
/*获取一个邮箱物理通道buff*/
MAILBOX_EXTERN long mailbox_request_buff(unsigned long mailcode,  struct mb_buff** mb_buf)
{
    struct mb        *mailbox     = MAILBOX_NULL;
    unsigned long     ret_val       = MAILBOX_OK;
    struct mb_buff ** mbuf  = (struct mb_buff **)mb_buf;

    mailbox     = mailbox_get_mb();
    *mbuf = MAILBOX_NULL;
    if (MAILBOX_NULL == mailbox){
        return mailbox_logerro_p1(MAILBOX_ERR_GUT_INPUT_PARAMETER, mailcode);
    }

    /*检查是否为发送通道*/
    if (mailbox->local_id != mailbox_get_src_id(mailcode)){
        return mailbox_logerro_p1(MAILBOX_ERR_GUT_INVALID_SRC_CPU, mailcode);
    }

    /*获得此邮件邮箱通道的操作句柄: open mail*/
    ret_val = mailbox_request_channel(mailbox, mbuf, mailcode);
    if (MAILBOX_OK == ret_val){
        (*mbuf)->mb = mailbox;
        ret_val = mailbox_init_usr_queue(*mbuf);
        if (MAILBOX_OK == ret_val) {
            return  MAILBOX_OK;
        } else {
            mailbox_release_channel(mailbox, *mbuf);
            *mbuf = MAILBOX_NULL;
            return ret_val;
        }
    } else {
        return ret_val;
    }
}
MAILBOX_LOCAL int mailbox_request_channel(
                struct mb *mb,
                struct mb_buff ** mb_buf,
                unsigned int mailcode)
{
    struct mb_head       *head  = MAILBOX_NULL;
    struct mb_queue      *queue = MAILBOX_NULL;
    struct mb_buff       *mbuff = MAILBOX_NULL;
    int ret_val = MAILBOX_OK;

    *mb_buf = MAILBOX_NULL;
    mbuff = mailbox_get_channel_handle(mb, mailcode);
    if (MAILBOX_NULL == mbuff) {
        ret_val = (int)MAILBOX_ERRO;
        goto request_erro;/*lint --e{801}*/
    }

    /*通过判断通道保护字,检查通道有没有初始化*/
    head = (struct mb_head*)mbuff->config->head_addr;
    if ((  (MAILBOX_PROTECT1 != head->ulProtectWord1) )
        || (MAILBOX_PROTECT2 != head->ulProtectWord2)
       ||(MAILBOX_PROTECT1 != head->ulProtectWord3)
       || (MAILBOX_PROTECT2 != head->ulProtectWord4)) {
        /*保护字不正确,说明邮箱未初始化,或者内存被踩,报错。*/
        ret_val = mailbox_logerro_p1(MAILBOX_NOT_READY, mailcode);
        goto request_erro;/*lint --e{801}*/
    }

    if(mailbox_get_src_id(mailcode) == mb->local_id) {
         /* 不允许在中断中发邮件*/
        if (MAILBOX_TRUE == mailbox_int_context()) {
            //TODO:接下来的开发(IFC for 低功耗)可能需要支持在中断中发送邮件,这里就需要锁中断。
            ret_val = mailbox_logerro_p1(MAILBOX_ERR_GUT_SEND_MAIL_IN_INT_CONTEXT, mailcode);
            goto request_erro;/*lint --e{801}*/
        } else {
            if (MAILBOX_OK != mailbox_mutex_lock(&mbuff->mutex)) {
                /*非中断发送,需要资源保护,获取当前通道资源。*/
                ret_val = mailbox_logerro_p1(MAILBOX_CRIT_GUT_MUTEX_LOCK_FAILED, mailcode);
                goto request_erro;/*lint --e{801}*/
            }
        }
    }

    mbuff->mailcode = mailcode;

    /*共享内存队列,需要依据邮箱头信息对队列操作符进行填充*/
    queue = &mbuff->mail_queue;
    queue->front = queue->base + head->ulFront * sizeof(unsigned int);
    queue->rear  = queue->base + head->ulRear * sizeof(unsigned int);

    mbuff->mb = mb;
    *mb_buf = mbuff;

    return MAILBOX_OK;

request_erro:
    //mailbox_out(("###mailbox_request_channel ERR!"RT));
    return ret_val;
}
/*****************************************************************************
 函 数 名  : mailbox_calculate_space
 接口类型  : 对内接口
 功能描述  : 统计通道信息,计算需要分配的内存空间
 输入参数  : struct mb        *mb  -- 邮箱总句柄
             struct mb_cfg    *config  -- 邮箱通道的全局配置表。
             unsigned long     CpuID     -- 注册此通道的CPU号。
 输出参数  : 无
 返 回 值  : 邮箱操作句柄
 调用函数  :
 被调函数  :

 修改历史      :
  1.日    期   : 2012年9月7日
    作    者   : 莫南 00176101
    修改内容   : 新生成函数

*****************************************************************************/
MAILBOX_LOCAL long mailbox_calculate_space(
                struct mb           *mb,
                struct mb_cfg    *config,
                unsigned long     cpu_id)
{
    struct mb_link          *send_link    = MAILBOX_NULL;/*指向主结构体的发送通道数组基地址*/
    struct mb_link          *recev_link   = MAILBOX_NULL;/*指向主结构体的接收通道数组基地址*/
    unsigned long            ret_val      = MAILBOX_OK;
    unsigned long            src_id       = 0;
    unsigned long            dst_id       = 0;
    unsigned long            carrier_id   = 0;

    send_link   =  mb->send_tbl;
    recev_link  =  mb->recv_tbl;

    while (MAILBOX_MAILCODE_INVALID != config->butt_id) {
        src_id       = mailbox_get_src_id(config->butt_id);
        dst_id       = mailbox_get_dst_id(config->butt_id);
        carrier_id   = mailbox_get_carrier_id(config->butt_id);

        /*检查是不是本CPU发送通道*/
        if (cpu_id == src_id) {
            /*检查目的CPU的有效性*/
            if (dst_id < MAILBOX_CPUID_BUTT) {
                /*记录此CPU连接的最大通道*/
                if ((carrier_id + 1) > send_link[dst_id].carrier_butt) {
                    send_link[dst_id].carrier_butt = (carrier_id + 1);
                } else {
                    /*不记录*/
                }
            } else {
                /*数组越界*/
                ret_val = mailbox_logerro_p1(MAILBOX_ERR_GUT_INVALID_CHANNEL_ID,
                                             config->butt_id);
            }
        }
         /*检查是不是本CPU接收通道*/
        if (cpu_id == dst_id) {
            /*检查发送CPU的有效性*/
            if (src_id < MAILBOX_CPUID_BUTT) {
                /*记录此CPU连接的最大通道*/
                if ((carrier_id + 1) > recev_link[src_id].carrier_butt) {
                    recev_link[src_id].carrier_butt = (carrier_id + 1);
                } else {
                    /*不记录*/
                }
            } else {
                /*数组越界*/
                ret_val = mailbox_logerro_p1(MAILBOX_ERR_GUT_INVALID_CHANNEL_ID,
                                             config->butt_id);
            }
        }

        config++;
    }

    return ret_val;
}
/*****************************************************************************
 函 数 名  : mailbox_release_channel
 接口类型  : 对内接口
 功能描述  : 关闭邮箱,释放资源。

 输入参数  : mb_buff* mbuff  - 邮箱通道缓存操作符
 输出参数  : 无
 返 回 值  : 邮箱关闭是否成功
 调用函数  :
 被调函数  :

 修改历史      :
  1.日    期   : 2012年9月27日
    作    者   : 莫南 00176101
    修改内容   : 新生成函数

*****************************************************************************/
MAILBOX_LOCAL long mailbox_release_channel(struct mb *mb,
                struct mb_buff *mbuff)
{
    unsigned long         channel_id    = mbuff->channel_id;

    /*需要区分是读还是写*/
    if (mb->local_id == mailbox_get_src_id(channel_id)) {
        if (MAILBOX_TRUE == mailbox_int_context()) {
            /*TODO:接下来的开发(IFC for 低功耗)可能需要支持在中断中发送邮件,
               这里就需要解锁中断。*/
        } else {
            mailbox_mutex_unlock(&mbuff->mutex);
        }
    }

    return MAILBOX_OK;
}
/*****************************************************************************
 函 数 名  : mailbox_flush_buff
 接口类型  : 对内接口
 功能描述  : 把邮箱消息队列的头尾指针写入邮箱头

 输入参数  : mb_buff* mbuff  - 邮箱通道操作符
 输出参数  : 无
 返 回 值  : MAILBOX_OK
 调用函数  :
 被调函数  :

 修改历史      :
  1.日    期   : 2013年5月08日
    作    者   : 莫南 00176101
    修改内容   : 新生成函数

*****************************************************************************/
MAILBOX_EXTERN long mailbox_flush_buff( struct mb_buff *mbuff)
{
    struct mb_head       *head = MAILBOX_NULL;
    struct mb_queue      *queue   = MAILBOX_NULL;
    unsigned long         channel_id    = mbuff->channel_id;
    struct mb *mb         = mbuff->mb;
    /*把邮箱通道操作符的信息写回邮箱头。*/
    head = (struct mb_head*)mbuff->config->head_addr;
    queue   = &mbuff->mail_queue;

    /*需要区分是读还是写*/
    if (mb->local_id == mailbox_get_src_id(channel_id)) {
        /*写关闭,更新邮箱头写指针,同时释放邮箱资源*/
        head->ulFront      = (queue->front - queue->base ) / sizeof(unsigned long) ;
        head->ulFrontslice = mailbox_get_timestamp();

    } else if (mb->local_id == mailbox_get_dst_id(channel_id)) {
        /*读关闭,只更新邮箱头读指针*/
        head->ulRear        =  (queue->rear - queue->base ) / sizeof(unsigned long);
        head->ulRearslice   =  mailbox_get_timestamp();
    }

    return MAILBOX_OK;
}
/*****************************************************************************
 函 数 名  : mailbox_init_all_handle
 接口类型  : 对内接口
 功能描述  : 初始化邮箱的所有通道句柄
 输入参数  : struct mb *mb  -- 邮箱总句柄
             struct mb_cfg *config  -- 邮箱通道的全局配置表。
             unsigned long  cpu_id     -- 注册此通道的CPU号。
 输出参数  : 无
 返 回 值  : 邮箱操作句柄
 调用函数  :
 被调函数  :

 修改历史      :
  1.日    期   : 2012年9月7日
    作    者   : 莫南 00176101
    修改内容   : 新生成函数

*****************************************************************************/
MAILBOX_LOCAL long mailbox_init_all_handle(
                struct mb           *mb,
                struct mb_cfg    *config,
                unsigned long     cpu_id)
{
    struct mb_queue        *queue  = MAILBOX_NULL;
    unsigned long           direct= MIALBOX_DIRECTION_INVALID; /*标记当前邮箱通道
                                            是不是本核相关的有效通道*/
    unsigned long           ret_val      = MAILBOX_OK;
    struct mb_link         *send_link    = MAILBOX_NULL;/*指向主结构体的发送通道
                                                          数组基地址*/
    struct mb_link         *recv_link = MAILBOX_NULL;   /*指向主结构体的接收通道
                                                          数组基地址*/
    struct mb_buff         *mbuf_prob   = &g_mailbox_channel_handle_pool[0];
    struct mb_cb           *cb_prob  = &g_mailbox_user_cb_pool[0];
    struct mb_buff         *mbuf_cur = MAILBOX_NULL;    /*指向正在处理的邮箱通道*/
    unsigned long           channel_sum    = 0;
    unsigned long           use_sum    = 0;
    unsigned long           src_id       = 0;
    unsigned long           dst_id       = 0;
    unsigned long           carrier_id   = 0;
    unsigned long           use_max      = 0;

    send_link  =  mb->send_tbl;
    recv_link  =  mb->recv_tbl;

    /*第二次循环对每个通道句柄分配空间,并赋值。(这段代码变量太多,不方便拆开另建函数)*/
    /*初始化每个邮箱的控制句柄*/
    while (MAILBOX_MAILCODE_INVALID != config->butt_id) {
        direct = MIALBOX_DIRECTION_INVALID;
        src_id       = mailbox_get_src_id(config->butt_id);
        dst_id       = mailbox_get_dst_id(config->butt_id);
        carrier_id   = mailbox_get_carrier_id(config->butt_id);
        use_max      = mailbox_get_use_id(config->butt_id);

        /*检查是不是本CPU发送通道*/
        if (cpu_id == src_id) {
            direct = MIALBOX_DIRECTION_SEND;

            /*没有分配空间则分配空间*/
            if (MAILBOX_NULL == send_link[dst_id].channel_buff) {
                send_link[dst_id].channel_buff = mbuf_prob;
                mbuf_prob += (send_link[dst_id].carrier_butt);
                channel_sum  += (send_link[dst_id].carrier_butt);
                if (channel_sum > MAILBOX_CHANNEL_NUM) {
                    return mailbox_logerro_p1(MAILBOX_CRIT_GUT_INIT_CHANNEL_POOL_TOO_SMALL,
                                                channel_sum);
                }
            }
            mbuf_cur = &send_link[dst_id].channel_buff[carrier_id];
        }

        /*检查是不是本CPU接收通道*/
        if (cpu_id == dst_id) {
             direct = MIALBOX_DIRECTION_RECEIVE;

            /*没有分配空间则分配空间*/
            if (MAILBOX_NULL == recv_link[src_id].channel_buff) {
                recv_link[src_id].channel_buff = mbuf_prob;
                mbuf_prob += (recv_link[src_id].carrier_butt);
                channel_sum  += (recv_link[src_id].carrier_butt);
                if (channel_sum > MAILBOX_CHANNEL_NUM) {
                    return mailbox_logerro_p1(MAILBOX_CRIT_GUT_INIT_CHANNEL_POOL_TOO_SMALL,
                                                channel_sum);
                }
            }

            mbuf_cur = &recv_link[src_id].channel_buff[carrier_id];

            /*1。为邮件注册回调函数申请空间*/
            mbuf_cur->read_cb = cb_prob;
            cb_prob += use_max;
            use_sum   += use_max;
            if (use_sum > MAILBOX_USER_NUM) {
                return mailbox_logerro_p1(MAILBOX_CRIT_GUT_INIT_USER_POOL_TOO_SMALL, use_sum);
            }

            /*3.注册邮箱线程回调接口,用于获取共享内存邮箱数据的处理*/
            ret_val = mailbox_process_register(mailbox_get_channel_id(config->butt_id),
                                                mailbox_read_channel, mbuf_cur);

            /*4.初始化邮箱共享内存,设置标志位。*/
            ret_val |= mailbox_init_mem(config);

        }

        if ((MIALBOX_DIRECTION_INVALID != direct ) && (MAILBOX_NULL != mbuf_cur)) {
            /*给控制句柄赋予邮箱ID号*/
            mbuf_cur->channel_id = mailbox_get_channel_id(config->butt_id);
            mbuf_cur->seq_num = MAILBOX_SEQNUM_START;
#ifdef MAILBOX_OPEN_MNTN
            mbuf_cur->mntn.peak_traffic_left = MAILBOX_QUEUE_LEFT_INVALID;
            mbuf_cur->mntn.mbuff    = mbuf_cur;
#endif
            /*给邮箱配置物理资源*/
            mbuf_cur->config = config;

            /*初始化通道资源*/
            queue = &(mbuf_cur->mail_queue);

            /*初始化邮箱通道的环形队列控制符,以下两项是初始化以后不会再变化的。*/
            queue->length  = mbuf_cur->config->data_size -
                            (MAILBOX_DATA_LEN_PROTECT_NUM * MAILBOX_PROTECT_LEN);
            queue->base    = mbuf_cur->config->data_addr +
                           (MAILBOX_DATA_BASE_PROTECT_NUM * MAILBOX_PROTECT_LEN);


            /*把此通道注册到具体平台*/
            ret_val = mailbox_channel_register(mailbox_get_channel_id(config->butt_id), /*lint !e539*/
                       config->int_src,
                       mailbox_get_dst_id(config->butt_id),
                       direct,
                       &mbuf_cur->mutex);
        }

        config++;
    }

    /*检查内存池大小是否刚好,如果报错,请检查宏设置是否匹配:
      这里检查下面三个数组的空间是否适配。
        g_mailbox_global_cfg_tbl[];
        g_mailbox_channel_handle_pool[MAILBOX_CHANNEL_NUM];
        g_mailbox_user_cb_pool[MAILBOX_USER_NUM];
    */
    if((unsigned long)MAILBOX_CHANNEL_NUM != channel_sum ) {
        ret_val = mailbox_logerro_p1(MAILBOX_ERR_GUT_INIT_CHANNEL_POOL_TOO_LARGE,
                                    (MAILBOX_CHANNEL_NUM<<16) | channel_sum);
    }

    if(MAILBOX_USER_NUM != use_sum) {
       ret_val = mailbox_logerro_p1(MAILBOX_ERR_GUT_INIT_USER_POOL_TOO_LARGE, use_sum);
    }

    return ret_val;
}
MAILBOX_LOCAL long mailbox_request_channel(
	struct mb *mb,
	struct mb_buff ** mb_buf,
	unsigned long mailcode)
{
	struct mb_head		 *head	= MAILBOX_NULL;
	struct mb_queue 	 *queue = MAILBOX_NULL;
	struct mb_buff		 *mbuff = MAILBOX_NULL;
	long ret_val = MAILBOX_OK;

	mailbox_dpm_device_get();

	*mb_buf = MAILBOX_NULL;
	mbuff = mailbox_get_channel_handle(mb, mailcode);
	if (MAILBOX_NULL == mbuff) {
		ret_val = MAILBOX_ERRO;
		goto request_erro;
	}

	/*通过判断通道保护字,检查通道有没有初始化*/
	head = (struct mb_head*)mbuff->config->head_addr;
	if ((  (MAILBOX_PROTECT1 != head->ulProtectWord1) )
		|| (MAILBOX_PROTECT2 != head->ulProtectWord2)
		||(MAILBOX_PROTECT1 != head->ulProtectWord3)
		|| (MAILBOX_PROTECT2 != head->ulProtectWord4)) {
#if 1/*k3 modify 保护字不正确重新初始化一下邮箱头,不要return影响通信流程,后续再找根因*/
		/*保护字不正确,说明邮箱未初始化,或者内存被踩,报错。*/
		/* do not check cause hifi maybe not pwr on when the first ipc message send */

		mailbox_init_mem(mbuff->config);

		mailbox_logerro_p1(MAILBOX_NOT_READY, mailcode);
#endif
	}

	if(mailbox_get_src_id(mailcode) == mb->local_id) {
		/* 不允许在中断中发邮件*/
		if (MAILBOX_TRUE == mailbox_int_context()) {
//TODO:接下来的开发(IFC for 低功耗)可能需要支持在中断中发送邮件,这里就需要锁中断。
			ret_val = mailbox_logerro_p1(MAILBOX_ERR_GUT_SEND_MAIL_IN_INT_CONTEXT, mailcode);
			goto request_erro;
		} else {
			if (MAILBOX_OK != mailbox_mutex_lock(&mbuff->mutex)) {
				/*非中断发送,需要资源保护,获取当前通道资源。*/
				ret_val = mailbox_logerro_p1(MAILBOX_CRIT_GUT_MUTEX_LOCK_FAILED, mailcode);
				goto request_erro;
			}
		}
	}

	mbuff->mailcode = mailcode;

	/*共享内存队列,需要依据邮箱头信息对队列操作符进行填充*/
	queue = &mbuff->mail_queue;
	queue->front = queue->base + head->ulFront * sizeof(unsigned long);
	queue->rear  = queue->base + head->ulRear * sizeof(unsigned long);

	mbuff->mb = mb;
	*mb_buf = mbuff;
	return MAILBOX_OK;
request_erro:
	mailbox_out(("###mailbox_request_channel ERR! \n"));
	mailbox_dpm_device_put();
	return ret_val;
}