/******************************************************************************
 *
 * Copyright(c) 2007 - 2020 Realtek Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 *****************************************************************************/
#if defined(CONFIG_MP_INCLUDED)
#include <rtw_efuse.h>

static u8 rtw_efuse_cmd(_adapter *padapter,
							struct rtw_efuse_phl_arg *pefuse_arg ,
							enum rtw_efuse_phl_cmdid cmdid)
{
	u32 i = 0;
	u8 ret = _FAIL;
	pefuse_arg->mp_class = RTW_MP_CLASS_EFUSE;
	pefuse_arg->cmd = cmdid;
	pefuse_arg->cmd_ok = 0;


	rtw_mp_set_phl_cmd(padapter, (void*)pefuse_arg, sizeof(struct rtw_efuse_phl_arg));

	while (i <= 50) {
		rtw_msleep_os(10);
		rtw_mp_get_phl_cmd(padapter, (void*)pefuse_arg, sizeof(struct rtw_efuse_phl_arg));
		if (pefuse_arg->cmd_ok && pefuse_arg->status == RTW_PHL_STATUS_SUCCESS) {
			RTW_INFO("%s,eFuse GET CMD OK !!!\n", __func__);
			ret = _SUCCESS;
			break;
		} else {
			rtw_msleep_os(10);
			if (i > 50) {
				RTW_INFO("%s, eFuse GET CMD FAIL !!!\n", __func__);
				break;
			}
			i++;
		}
	}

	return ret;
}

u32 rtw_efuse_get_map_size(_adapter *padapter , u16 *size , enum rtw_efuse_phl_cmdid cmdid)
{
	struct rtw_efuse_phl_arg *efuse_arg = NULL;
	u8 res = _FAIL;

	efuse_arg = _rtw_malloc(sizeof(struct rtw_efuse_phl_arg));
	if (efuse_arg) {
		_rtw_memset((void *)efuse_arg, 0, sizeof(struct rtw_efuse_phl_arg));
		rtw_efuse_cmd(padapter, efuse_arg, cmdid);
		if (efuse_arg->cmd_ok && efuse_arg->status == RTW_PHL_STATUS_SUCCESS) {
				*size = efuse_arg->io_value;
				res = _SUCCESS;
		} else {
				*size = 0;
				res = _FAIL;
		}
	}
	if (efuse_arg)
		_rtw_mfree(efuse_arg, sizeof(struct rtw_efuse_phl_arg));

	return res;
}

u32 rtw_efuse_get_available_size(_adapter *padapter , u16 *size, u8 efuse_type)
{
	struct rtw_efuse_phl_arg *efuse_arg = NULL;
	u8 res = _FAIL;

	efuse_arg = _rtw_malloc(sizeof(struct rtw_efuse_phl_arg));

	if (efuse_arg) {
		_rtw_memset((void *)efuse_arg, 0, sizeof(struct rtw_efuse_phl_arg));

		if (efuse_type == RTW_EFUSE_WIFI)
			rtw_efuse_cmd(padapter, efuse_arg, RTW_EFUSE_CMD_WIFI_GET_AVL_SIZE);
		else
			rtw_efuse_cmd(padapter, efuse_arg, RTW_EFUSE_CMD_BT_GET_AVL_SIZE);

		if (efuse_arg->cmd_ok && efuse_arg->status == RTW_PHL_STATUS_SUCCESS) {
				*size = efuse_arg->io_value;
				res = _SUCCESS;
		} else {
				*size = 0;
				res = _FAIL;
		}
	}
	if (efuse_arg)
		_rtw_mfree(efuse_arg, sizeof(struct rtw_efuse_phl_arg));

	return res;
}

static u8 rtw_efuse_fake2map(_adapter *padapter, u8 efuse_type)
{
	struct rtw_efuse_phl_arg *efuse_arg = NULL;
	u8 res = _SUCCESS;

	efuse_arg = _rtw_malloc(sizeof(struct rtw_efuse_phl_arg));
	if (efuse_arg) {
		_rtw_memset((void *)efuse_arg, 0, sizeof(struct rtw_efuse_phl_arg));

		if (efuse_type == RTW_EFUSE_WIFI)
			rtw_efuse_cmd(padapter, efuse_arg, RTW_EFUSE_CMD_WIFI_UPDATE);
		else if (efuse_type == RTW_EFUSE_BT)
			rtw_efuse_cmd(padapter, efuse_arg, RTW_EFUSE_CMD_BT_UPDATE);

		if (efuse_arg->cmd_ok && efuse_arg->status == RTW_PHL_STATUS_SUCCESS)
			res = _SUCCESS;
		else
			res = _FAIL;
	}
	if (efuse_arg)
		_rtw_mfree(efuse_arg, sizeof(struct rtw_efuse_phl_arg));

	return res;
}

u8 rtw_efuse_read_map2shadow(_adapter *padapter, u8 efuse_type)
{
	struct rtw_efuse_phl_arg *efuse_arg = NULL;
	u8 res = _SUCCESS;

	efuse_arg = _rtw_malloc(sizeof(struct rtw_efuse_phl_arg));
	if (efuse_arg) {
		_rtw_memset((void *)efuse_arg, 0, sizeof(struct rtw_efuse_phl_arg));
		if (efuse_type == RTW_EFUSE_WIFI)
		    rtw_efuse_cmd(padapter, efuse_arg, RTW_EFUSE_CMD_WIFI_UPDATE_MAP);
		else if (efuse_type == RTW_EFUSE_BT)
			rtw_efuse_cmd(padapter, efuse_arg, RTW_EFUSE_CMD_BT_UPDATE_MAP);
		if (efuse_arg->cmd_ok && efuse_arg->status == RTW_PHL_STATUS_SUCCESS)
				res = _SUCCESS;
		else
				res = _FAIL;
	}
	if (efuse_arg)
		_rtw_mfree(efuse_arg, sizeof(struct rtw_efuse_phl_arg));

	return res;
}

static u8 rtw_efuse_get_shadow_map(_adapter *padapter, u8 *map, u16 size, u8 efuse_type)
{
	struct rtw_efuse_phl_arg *efuse_arg = NULL;
	u8 res = _FAIL;

	efuse_arg = _rtw_malloc(sizeof(struct rtw_efuse_phl_arg));
	if (efuse_arg) {

		efuse_arg->buf_len = size;
		if (efuse_type == RTW_EFUSE_WIFI)
		    rtw_efuse_cmd(padapter, efuse_arg, RTW_EFUSE_CMD_SHADOW_MAP2BUF);
		else if (efuse_type == RTW_EFUSE_BT)
			rtw_efuse_cmd(padapter, efuse_arg, RTW_EFUSE_CMD_BT_SHADOW_MAP2BUF);
		if (efuse_arg->cmd_ok && efuse_arg->status == RTW_PHL_STATUS_SUCCESS) {
				_rtw_memcpy((void *)map, efuse_arg->poutbuf, size);
				res = _SUCCESS;
		} else
				res = _FAIL;
	}
	if (efuse_arg)
		_rtw_mfree(efuse_arg, sizeof(struct rtw_efuse_phl_arg));

	return res;
}

static u8 rtw_efuse_renew_update(_adapter *padapter, u8 efuse_type)
{
	struct rtw_efuse_phl_arg *efuse_arg = NULL;
	u8 res = _SUCCESS;

	efuse_arg = _rtw_malloc(sizeof(struct rtw_efuse_phl_arg));
	if (efuse_arg) {
		_rtw_memset((void *)efuse_arg, 0, sizeof(struct rtw_efuse_phl_arg));

		if (efuse_type == RTW_EFUSE_WIFI)
			rtw_efuse_cmd(padapter, efuse_arg, RTW_MP_EFUSE_CMD_WIFI_SET_RENEW);
		else if (efuse_type == RTW_EFUSE_BT)
			RTW_INFO("halmac_get_logical_efuse_size fail\n");

		if (efuse_arg->cmd_ok && efuse_arg->status == RTW_PHL_STATUS_SUCCESS)
			res = _SUCCESS;
		else
			res = _FAIL;
	}
	if (efuse_arg)
		_rtw_mfree(efuse_arg, sizeof(struct rtw_efuse_phl_arg));

	return res;
}

static bool rtw_file_efuse_ismasked(_adapter *padapter, u16 offset, u8 *maskbuf)
{
	int r = offset / 16;
	int c = (offset % 16) / 2;
	int result = 0;

	if (padapter->registrypriv.boffefusemask)
		return _FALSE;

	if (c < 4) /* Upper double word */
		result = (maskbuf[r] & (0x10 << c));
	else
		result = (maskbuf[r] & (0x01 << (c - 4)));

	return (result > 0) ? 0 : 1;
}

static u8 rtw_efuse_compare_data(_adapter *padapter,
				u16 addr, u32 len, u8 *dst, u8 *src, u8 efuse_type)
{
	struct rtw_efuse_phl_arg *efuse_arg = NULL;
	enum rtw_efuse_phl_cmdid cmdid = RTW_EFUSE_CMD_WIFI_GET_MASK_BUF;
	u8 res = _FAIL;
	u16 idx = 0;

	efuse_arg = _rtw_malloc(sizeof(struct rtw_efuse_phl_arg));

	if (efuse_arg) {
		_rtw_memset((void *)efuse_arg, 0, sizeof(struct rtw_efuse_phl_arg));


		if (efuse_type == RTW_EFUSE_WIFI)
			cmdid = RTW_EFUSE_CMD_WIFI_GET_MASK_BUF;
		else if (efuse_type == RTW_EFUSE_BT)
			cmdid = RTW_EFUSE_CMD_BT_GET_MASK_BUF;

		efuse_arg->status = 0;
		efuse_arg->cmd_ok = 0;
		efuse_arg->buf_len = 0;

		if (rtw_efuse_cmd(padapter, efuse_arg, cmdid) == _SUCCESS) {

			RTW_MAP_DUMP_SEL(RTW_DBGDUMP, "efuse mask buf:",
				efuse_arg->poutbuf, efuse_arg->buf_len);

			for (idx = 0; idx + addr < (addr + len); idx++) {
					u16 chkaddr = idx + addr;

				if (!rtw_file_efuse_ismasked(padapter, chkaddr, efuse_arg->poutbuf)) {
					if (_rtw_memcmp((void *)dst + chkaddr , (void *)src + idx, 1)) {
						RTW_INFO("mask cmp success addr: 0x%x cur dst: %02x <=> PG src:%02x\n",
										idx, dst[chkaddr], src[idx]);
						res = _SUCCESS;
					} else {
						RTW_INFO("mask cmp Fail addr: 0x%x cur dst: %02x <=> PG src:%02x\n",
										chkaddr, dst[chkaddr], src[idx]);
						res  = _FAIL;
						break;
					}
				}
			}
		} else {
			RTW_INFO("rtw_efuse_cmd:%d, status:%d,mask len: %d\n",
				efuse_arg->cmd_ok, efuse_arg->status, efuse_arg->buf_len);
			res  = _FAIL;
		}
	}
	if (efuse_arg)
		_rtw_mfree(efuse_arg, sizeof(struct rtw_efuse_phl_arg));
	return res;
}

u8 rtw_efuse_map_read(_adapter * adapter, u16 addr, u16 cnts, u8 *data, u8 efuse_type)
{
	struct dvobj_priv *d;
	u8 *efuse = NULL;
	u16 size, i;
	int err = _FAIL;
	u8 status = _SUCCESS;

	if (efuse_type == RTW_EFUSE_WIFI)
		err = rtw_efuse_get_map_size(adapter, &size, RTW_EFUSE_CMD_WIFI_GET_LOG_SIZE);
	else if (efuse_type == RTW_EFUSE_BT)
		err = rtw_efuse_get_map_size(adapter, &size, RTW_EFUSE_CMD_BT_GET_LOG_SIZE);

	if (err == _FAIL) {
		status = _FAIL;
		RTW_INFO("halmac_get_logical_efuse_size fail\n");
		goto exit;
	}
	/* size error handle */
	if ((addr + cnts) > size) {
		if (addr < size)
			cnts = size - addr;
		else {
			status = _FAIL;
			RTW_INFO(" %s() ,addr + cnts) > size fail\n", __func__);
			goto exit;
		}
	}

	efuse = rtw_zmalloc(size);
	if (efuse) {
		if (rtw_efuse_read_map2shadow(adapter, efuse_type) == _SUCCESS) {
			err = rtw_efuse_get_shadow_map(adapter, efuse, size, efuse_type);
			if (err == _FAIL) {
				rtw_mfree(efuse, size);
				status = _FAIL;
				RTW_INFO(" %s() ,halmac_read_logical_efus map fail\n", __func__);
				goto exit;
			}
		} else {
			RTW_INFO(" %s() ,rtw_efuse_read_map2shadow FAIL !!!\n", __func__);
			rtw_mfree(efuse, size);
			status = _FAIL;
			goto exit;
		}
		if (efuse) {
			RTW_INFO(" %s() ,cp efuse to data\n", __func__);
			_rtw_memcpy(data, efuse + addr, cnts);
			rtw_mfree(efuse, size);
		}
	} else {
			RTW_INFO(" %s() ,alloc efuse fail\n", __func__);
			goto exit;
	}
	status = _SUCCESS;
exit:

	return status;
}

u8 rtw_efuse_map_write(_adapter * adapter, u16 addr, u16 cnts, u8 *data, u8 efuse_type, u8 bpg)
{
	struct dvobj_priv *d;
	struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
	u16 size;
	int err = _FAIL;
	u8 mask_buf[64] = "";
	u32 backupRegs[4] = {0};
	u8 status = _SUCCESS;
	struct rtw_efuse_phl_arg *efuse_arg = NULL;
	u16 i = 0;

	efuse_arg = rtw_zmalloc(sizeof(struct rtw_efuse_phl_arg));

	if (efuse_type == RTW_EFUSE_WIFI)
		err = rtw_efuse_get_map_size(adapter, &size, RTW_EFUSE_CMD_WIFI_GET_LOG_SIZE);
	else if (efuse_type == RTW_EFUSE_BT)
		err = rtw_efuse_get_map_size(adapter, &size, RTW_EFUSE_CMD_BT_GET_LOG_SIZE);

	if (err == _FAIL) {
		status = _FAIL;
		goto exit;
	}

	if ((addr + cnts) > size) {
		status = _FAIL;
		goto exit;
	}

	if (efuse_type == RTW_EFUSE_WIFI) {
		while (i != cnts) {
			efuse_arg->io_type = 1;
			efuse_arg->io_offset = addr + i;
			efuse_arg->io_value = data[i];
			rtw_efuse_cmd(adapter, efuse_arg, RTW_EFUSE_CMD_WIFI_WRITE);
			if (i > cnts)
				break;
			i++;
		}
	} else if (efuse_type == RTW_EFUSE_BT) {
		while (i != cnts) {
			efuse_arg->io_type = 1;
			efuse_arg->io_offset = addr + i;
			efuse_arg->io_value = data[i];
			rtw_efuse_cmd(adapter, efuse_arg, RTW_EFUSE_CMD_BT_WRITE);
			if (i > cnts)
				break;
			i++;
		}
	}

	if (bpg) {
		RTW_INFO(" in PG state !!!\n");
		if (efuse_type == RTW_EFUSE_WIFI)
			err = rtw_efuse_fake2map(adapter, efuse_type);
		else if (efuse_type == RTW_EFUSE_BT) {
			u8 reg2chkbt = 0;

			rtw_phl_write8(dvobj->phl, 0xa3, 0x05);
			rtw_msleep_os(10);
			reg2chkbt = rtw_phl_read8(dvobj->phl, 0xa0);

			if (reg2chkbt != 0x04) {
				RTW_ERR("BT State not Active:0x%x ,can't Write \n", reg2chkbt);
				goto exit;
			}

			err = rtw_efuse_fake2map(adapter, efuse_type);
		}

		if (err == _FAIL) {
			status = _FAIL;
			goto exit;
		}
	}
	status = _SUCCESS;
exit :
	if (efuse_arg)
		_rtw_mfree(efuse_arg, sizeof(struct rtw_efuse_phl_arg));

	return status;
}

static u8 rtw_efuse_map_file_load(_adapter *padapter, u8 *filepath, u8 efuse_type)
{
	struct rtw_efuse_phl_arg *efuse_arg = NULL;
	u8 res = _FAIL;

	if (filepath) {
		RTW_INFO("efuse file path %s len %zu", filepath, strlen(filepath));

		efuse_arg = _rtw_malloc(sizeof(struct rtw_efuse_phl_arg));
		efuse_arg->status = RTW_PHL_STATUS_FAILURE;

		if (efuse_arg) {
			_rtw_memset((void *)efuse_arg, 0, sizeof(struct rtw_efuse_phl_arg));
			_rtw_memcpy(efuse_arg->pfile_path, filepath, strlen(filepath));
			if (efuse_type == RTW_EFUSE_WIFI)
				rtw_efuse_cmd(padapter, efuse_arg, RTW_EFUSE_CMD_FILE_MAP_LOAD);
			else
				rtw_efuse_cmd(padapter, efuse_arg, RTW_EFUSE_CMD_BT_FILE_MAP_LOAD);
		}
	}
	if (efuse_arg->cmd_ok && efuse_arg->status == RTW_PHL_STATUS_SUCCESS)
			res = _SUCCESS;
	else
			res = _FAIL;

	if (efuse_arg)
		_rtw_mfree(efuse_arg, sizeof(struct rtw_efuse_phl_arg));

	return res;
}

static u8 rtw_efuse_mask_file_load(_adapter *padapter, u8 *filepath, u8 efuse_type)
{
	struct rtw_efuse_phl_arg *efuse_arg = NULL;
	u8 res = _FAIL;

	if (filepath) {
		RTW_INFO("efuse file path %s len %zu", filepath, strlen(filepath));
		efuse_arg = _rtw_malloc(sizeof(struct rtw_efuse_phl_arg));
		efuse_arg->status = RTW_PHL_STATUS_FAILURE;

		if (efuse_arg) {
			_rtw_memset((void *)efuse_arg, 0, sizeof(struct rtw_efuse_phl_arg));
			_rtw_memcpy(efuse_arg->pfile_path, filepath, strlen(filepath));
			if (efuse_type == RTW_EFUSE_WIFI)
				rtw_efuse_cmd(padapter, efuse_arg, RTW_EFUSE_CMD_FILE_MASK_LOAD);
			else
				rtw_efuse_cmd(padapter, efuse_arg, RTW_EFUSE_CMD_BT_FILE_MASK_LOAD);
		}
	}

	if (efuse_arg->cmd_ok && efuse_arg->status == RTW_PHL_STATUS_SUCCESS)
			res = _SUCCESS;
	else
			res = _FAIL;

	if (efuse_arg)
		_rtw_mfree(efuse_arg, sizeof(struct rtw_efuse_phl_arg));

	return res;
}

int rtw_ioctl_efuse_get(struct net_device *dev,
				struct iw_request_info *info,
				union iwreq_data *wrqu, char *extra)
{
	_adapter *padapter = rtw_netdev_priv(dev);
	struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
	char *pch, *ptmp, *token, *tmp[3] = {0x00, 0x00, 0x00};
	u16 i = 0, j = 0, mapLen = 0, addr = 0, cnts = 0;
	int err = 0;
	char *pextra = NULL;
	u8 *pre_efuse_map = NULL;
	u16 max_available_len = 0;

	if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) {
		err = -EFAULT;
		goto exit;
	}

	*(extra + wrqu->data.length) = '\0';

	pch = extra;
	RTW_INFO("%s: in=%s\n", __FUNCTION__, extra);

	i = 0;
	/* mac 16 "00e04c871200" rmap,00,2 */
	while ((token = strsep(&pch, ",")) != NULL) {
		if (i > 2)
			break;
		tmp[i] = token;
		i++;
	}
	pre_efuse_map = rtw_zmalloc(RTW_MAX_EFUSE_MAP_LEN);
	if (pre_efuse_map == NULL)
			goto exit;

	if (strcmp(tmp[0], "status") == 0) {
		//sprintf(extra, "Load File efuse=%s,Load File MAC=%s"
		//	, efuse->file_status == EFUSE_FILE_FAILED ? "FAIL" : "OK"
		//	, pHalData->macaddr_file_status == MACADDR_FILE_FAILED ? "FAIL" : "OK"
		//       );
		goto exit;
	} else if (strcmp(tmp[0], "drvmap") == 0) {
		static u8 drvmaporder = 0;
		u8 *efuse_data = NULL;
		u32 shift, cnt;
		u32 blksz = 0x200; /* The size of one time show, default 512 */
		//EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, _FALSE);

		//efuse_data = efuse->data;

		shift = blksz * drvmaporder;
		efuse_data += shift;
		cnt = mapLen - shift;

		if (cnt > blksz) {
			cnt = blksz;
			drvmaporder++;
		} else
			drvmaporder = 0;

		sprintf(extra, "\n");
		for (i = 0; i < cnt; i += 16) {
			pextra = extra + strlen(extra);
			pextra += sprintf(pextra, "0x%02x\t", shift + i);
			for (j = 0; j < 8; j++)
				pextra += sprintf(pextra, "%02X ", efuse_data[i + j]);
			pextra += sprintf(pextra, "\t");
			for (; j < 16; j++)
				pextra += sprintf(pextra, "%02X ", efuse_data[i + j]);
			pextra += sprintf(pextra, "\n");
		}
		if ((shift + cnt) < mapLen)
			pextra += sprintf(pextra, "\t...more (left:%d/%d)\n", mapLen-(shift + cnt), mapLen);

	} else if (strcmp(tmp[0], "realmap") == 0) {
		static u8 order = 0;
		u32 shift, cnt;
		u32 blksz = 0x200; /* The size of one time show, default 512 */
		u8 *efuse_data = NULL;

		rtw_efuse_get_map_size(padapter, &mapLen, RTW_EFUSE_CMD_WIFI_GET_LOG_SIZE);

 		if (pre_efuse_map) {
			if (rtw_efuse_map_read(padapter, 0, mapLen, pre_efuse_map, RTW_EFUSE_WIFI) == _FAIL) {
				RTW_INFO("%s: read realmap Fail!!\n", __FUNCTION__);
				err = -EFAULT;
			} else {
				efuse_data = pre_efuse_map;

				_rtw_memset(extra, '\0', strlen(extra));
				shift = blksz * order;
				efuse_data += shift;
				cnt = mapLen - shift;
				if (cnt > blksz) {
					cnt = blksz;
					order++;
				} else
					order = 0;

				sprintf(extra, "\n");
				for (i = 0; i < cnt; i += 16) {
					pextra = extra + strlen(extra);
					pextra += sprintf(pextra, "0x%02x\t", shift + i);
					for (j = 0; j < 8; j++)
						pextra += sprintf(pextra, "%02X ", efuse_data[i + j]);
					pextra += sprintf(pextra, "\t");
					for (; j < 16; j++)
						pextra += sprintf(pextra, "%02X ", efuse_data[i + j]);
					pextra += sprintf(pextra, "\n");

					if (strlen(extra) > 0x7FF)
						break;
				}
				if ((shift + cnt) < mapLen)
					pextra += sprintf(pextra, "\t...more (left:%d/%d)\n", mapLen - (shift + cnt), mapLen);
				}
		}
	} else if (strcmp(tmp[0], "rmap") == 0) {
		u8 *data = NULL;
		if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
			RTW_INFO("%s: rmap Fail!! Parameters error!\n", __FUNCTION__);
			err = -EINVAL;
			goto exit;
		}
		/* rmap addr cnts */
		addr = simple_strtoul(tmp[1], &ptmp, 16);
		RTW_INFO("%s: addr=%x\n", __FUNCTION__, addr);

		cnts = simple_strtoul(tmp[2], &ptmp, 10);
		if (cnts == 0) {
			RTW_INFO("%s: rmap Fail!! cnts error!\n", __FUNCTION__);
			err = -EINVAL;
			goto exit;
		}
		RTW_INFO("%s: cnts=%d\n", __FUNCTION__, cnts);

		rtw_efuse_get_map_size(padapter, &mapLen, RTW_EFUSE_CMD_WIFI_GET_LOG_SIZE);

		if ((addr + cnts) > mapLen) {
			RTW_INFO("%s: addr(0x%X)+cnts(%d) over mapLen %d parameter error!\n", __FUNCTION__, addr, cnts, mapLen);
			err = -EINVAL;
			goto exit;
		}

		if (pre_efuse_map) {
			if (rtw_efuse_map_read(padapter, addr, cnts, pre_efuse_map, RTW_EFUSE_WIFI) == _FAIL) {
				RTW_INFO("%s: rtw_efuse_map_read Fail!!\n", __FUNCTION__);
				err = -EFAULT;
			} else {
				data = pre_efuse_map;
				*extra = 0;
				pextra = extra;
				for (i = 0; i < cnts; i++) {
					pextra += sprintf(pextra, "0x%02X ", data[i]);
				}
			}
		}
	} else if (strcmp(tmp[0], "wlrfkmap") == 0) {
		static u8 order = 0;
		u32 shift, cnt;
		u32 blksz = 0x200; /* The size of one time show, default 512 */
		u8 *efuse_data = NULL;

		rtw_efuse_get_map_size(padapter, &mapLen, RTW_EFUSE_CMD_WIFI_GET_LOG_SIZE);

 		if (pre_efuse_map) {
			if (rtw_efuse_get_shadow_map(padapter, pre_efuse_map, mapLen, RTW_EFUSE_WIFI) == _FAIL) {
				RTW_INFO("%s: read wifi fake map Fail!!\n", __FUNCTION__);
				err = -EFAULT;
			} else {
				efuse_data = pre_efuse_map;

				_rtw_memset(extra, '\0', strlen(extra));
				shift = blksz * order;
				efuse_data += shift;
				cnt = mapLen - shift;
				if (cnt > blksz) {
					cnt = blksz;
					order++;
				} else
					order = 0;

				sprintf(extra, "\n");
				for (i = 0; i < cnt; i += 16) {
					pextra = extra + strlen(extra);
					pextra += sprintf(pextra, "0x%02x\t", shift + i);
					for (j = 0; j < 8; j++)
						pextra += sprintf(pextra, "%02X ", efuse_data[i + j]);
					pextra += sprintf(pextra, "\t");
					for (; j < 16; j++)
						pextra += sprintf(pextra, "%02X ", efuse_data[i + j]);
					pextra += sprintf(pextra, "\n");

					if (strlen(extra) > 0x7FF)
						break;
				}
				if ((shift + cnt) < mapLen)
					pextra += sprintf(pextra, "\t...more (left:%d/%d)\n", mapLen - (shift + cnt), mapLen);
				}
		}
	} else if (strcmp(tmp[0], "wlrfkrmap") == 0) {
		u8 *data = NULL;
		if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
			RTW_INFO("%s: rmap Fail!! Parameters error!\n", __FUNCTION__);
			err = -EINVAL;
			goto exit;
		}
		/* rmap addr cnts */
		addr = simple_strtoul(tmp[1], &ptmp, 16);
		RTW_INFO("%s: addr=%x\n", __FUNCTION__, addr);

		cnts = simple_strtoul(tmp[2], &ptmp, 10);
		if (cnts == 0) {
			RTW_INFO("%s: rmap Fail!! cnts error!\n", __FUNCTION__);
			err = -EINVAL;
			goto exit;
		}
		RTW_INFO("%s: cnts=%d\n", __FUNCTION__, cnts);

		rtw_efuse_get_map_size(padapter, &mapLen, RTW_EFUSE_CMD_WIFI_GET_LOG_SIZE);

		if ((addr + cnts) > mapLen) {
			RTW_INFO("%s: addr(0x%X)+cnts(%d) over mapLen %d parameter error!\n", __FUNCTION__, addr, cnts, mapLen);
			err = -EINVAL;
			goto exit;
		}

		if (pre_efuse_map) {
			if (rtw_efuse_get_shadow_map(padapter, pre_efuse_map, mapLen, RTW_EFUSE_WIFI) == _FAIL) {
				RTW_INFO("%s: read wifi fake map Fail!!\n", __FUNCTION__);
				err = -EFAULT;
			} else {
				data = pre_efuse_map;
				*extra = 0;
				pextra = extra;
				for (i = addr; i < addr + cnts; i++)
					pextra += sprintf(pextra, "0x%02X ", data[i]);
			}
		}
	} else if (strcmp(tmp[0], "btrealmap") == 0) {
		static u8 order = 0;
		u32 shift, cnt;
		u32 blksz = 0x200; /* The size of one time show, default 512 */
		u8 *efuse_data = NULL;

		rtw_efuse_get_map_size(padapter, &mapLen, RTW_EFUSE_CMD_BT_GET_LOG_SIZE);

 		if (pre_efuse_map) {
			if (rtw_efuse_map_read(padapter, 0, mapLen, pre_efuse_map, RTW_EFUSE_BT) == _FAIL) {
				RTW_INFO("%s: read BT realmap Fail!!\n", __FUNCTION__);
				err = -EFAULT;
			} else {
				efuse_data = pre_efuse_map;

				_rtw_memset(extra, '\0', strlen(extra));
				shift = blksz * order;
				efuse_data += shift;
				cnt = mapLen - shift;
				if (cnt > blksz) {
					cnt = blksz;
					order++;
				} else
					order = 0;

				sprintf(extra, "\n");
				for (i = 0; i < cnt; i += 16) {
					pextra = extra + strlen(extra);
					pextra += sprintf(pextra, "0x%02x\t", shift + i);
					for (j = 0; j < 8; j++)
						pextra += sprintf(pextra, "%02X ", efuse_data[i + j]);
					pextra += sprintf(pextra, "\t");
					for (; j < 16; j++)
						pextra += sprintf(pextra, "%02X ", efuse_data[i + j]);
					pextra += sprintf(pextra, "\n");

					if (strlen(extra) > 0x7FF)
						break;
				}
				if ((shift + cnt) < mapLen)
					pextra += sprintf(pextra, "\t...more (left:%d/%d)\n", mapLen - (shift + cnt), mapLen);
			}
 		}
	} else if (strcmp(tmp[0], "btrmap") == 0) {
		u8 *data = NULL;
		if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
			RTW_INFO("%s: btrmap Fail!! Parameters error!\n", __FUNCTION__);
			err = -EINVAL;
			goto exit;
		}
		/* rmap addr cnts */
		addr = simple_strtoul(tmp[1], &ptmp, 16);
		RTW_INFO("%s: addr=%x\n", __FUNCTION__, addr);

		cnts = simple_strtoul(tmp[2], &ptmp, 10);
		if (cnts == 0) {
			RTW_INFO("%s: btrmap Fail!! cnts error!\n", __FUNCTION__);
			err = -EINVAL;
			goto exit;
		}
		RTW_INFO("%s: cnts=%d\n", __FUNCTION__, cnts);

		rtw_efuse_get_map_size(padapter, &mapLen, RTW_EFUSE_CMD_BT_GET_LOG_SIZE);

		if ((addr + cnts) > mapLen) {
			RTW_INFO("%s: addr(0x%X)+cnts(%d) over mapLen %d parameter error!\n", __FUNCTION__, addr, cnts, mapLen);
			err = -EINVAL;
			goto exit;
		}

		if (pre_efuse_map) {
			if (rtw_efuse_map_read(padapter, addr, cnts, pre_efuse_map, RTW_EFUSE_BT) == _FAIL) {
				RTW_INFO("%s: rtw_efuse_map_read Fail!!\n", __FUNCTION__);
				err = -EFAULT;
			} else {
				data = pre_efuse_map;
				*extra = 0;
				pextra = extra;
				for (i = 0; i < cnts; i++)
					pextra += sprintf(pextra, "0x%02X ", data[i]);
			}
		}
	} else if (strcmp(tmp[0], "btrfkmap") == 0) {
		static u8 order = 0;
		u32 shift, cnt;
		u32 blksz = 0x200; /* The size of one time show, default 512 */
		u8 *efuse_data = NULL;

		rtw_efuse_get_map_size(padapter, &mapLen, RTW_EFUSE_CMD_BT_GET_LOG_SIZE);

 		if (pre_efuse_map) {
			if (rtw_efuse_get_shadow_map(padapter, pre_efuse_map, mapLen, RTW_EFUSE_BT) == _FAIL) {
				RTW_INFO("%s: read BT fake map Fail!!\n", __FUNCTION__);
				err = -EFAULT;
			} else {
				efuse_data = pre_efuse_map;

				_rtw_memset(extra, '\0', strlen(extra));
				shift = blksz * order;
				efuse_data += shift;
				cnt = mapLen - shift;
				if (cnt > blksz) {
					cnt = blksz;
					order++;
				} else
					order = 0;

				sprintf(extra, "\n");
				for (i = 0; i < cnt; i += 16) {
					pextra = extra + strlen(extra);
					pextra += sprintf(pextra, "0x%02x\t", shift + i);
					for (j = 0; j < 8; j++)
						pextra += sprintf(pextra, "%02X ", efuse_data[i + j]);
					pextra += sprintf(pextra, "\t");
					for (; j < 16; j++)
						pextra += sprintf(pextra, "%02X ", efuse_data[i + j]);
					pextra += sprintf(pextra, "\n");

					if (strlen(extra) > 0x7FF)
						break;
				}
				if ((shift + cnt) < mapLen)
					pextra += sprintf(pextra, "\t...more (left:%d/%d)\n", mapLen - (shift + cnt), mapLen);
			}
		}
	} else if (strcmp(tmp[0], "ableraw") == 0) {
			rtw_efuse_get_available_size(padapter, &max_available_len, RTW_EFUSE_WIFI);
			sprintf(extra, "[WIFI available raw size]= %d bytes\n", max_available_len);
	} else if (strcmp(tmp[0], "btableraw") == 0) {
			rtw_efuse_get_available_size(padapter, &max_available_len, RTW_EFUSE_BT);
			sprintf(extra, "[BT available raw size]= %d bytes\n", max_available_len);
	} else if (strcmp(tmp[0], "realraw") == 0) {
		static u8 raw_order = 0;
		u32 shift, cnt;
		u32 blksz = 0x200; /* The size of one time show, default 512 */
		u8 *realraw_map_data = NULL;

		rtw_efuse_get_map_size(padapter, &mapLen, RTW_EFUSE_CMD_WIFI_GET_SIZE);

 		if (pre_efuse_map) {
			if (rtw_efuse_raw_map_read (padapter, 0, mapLen, pre_efuse_map, RTW_EFUSE_WIFI) == _FAIL) {
				RTW_INFO("%s: read wifi raw map Fail!!\n", __FUNCTION__);
				err = -EFAULT;
			} else {
				realraw_map_data = pre_efuse_map;

				_rtw_memset(extra, '\0', strlen(extra));
				shift = blksz * raw_order;
				realraw_map_data += shift;
				cnt = mapLen - shift;
				if (cnt > blksz) {
					cnt = blksz;
					raw_order++;
				} else
					raw_order = 0;

				sprintf(extra, "\n");
				for (i = 0; i < cnt; i += 16) {
					pextra = extra + strlen(extra);
					pextra += sprintf(pextra, "0x%02x\t", shift + i);
					for (j = 0; j < 8; j++)
						pextra += sprintf(pextra, "%02X ", realraw_map_data[i + j]);
					pextra += sprintf(pextra, "\t");
					for (; j < 16; j++)
						pextra += sprintf(pextra, "%02X ", realraw_map_data[i + j]);
					pextra += sprintf(pextra, "\n");

					if (strlen(extra) > 0x7FF)
						break;
				}
				if ((shift + cnt) < mapLen)
					pextra += sprintf(pextra, "\t...more (left:%d/%d)\n", mapLen - (shift + cnt), mapLen);
				}
		}
	} else if (strcmp(tmp[0], "btrealraw")== 0) {
		static u8 raw_order = 0;
		u32 shift, cnt;
		u32 blksz = 0x200; /* The size of one time show, default 512 */
		u8 *realraw_map_data = NULL;

		rtw_efuse_get_map_size(padapter, &mapLen, RTW_EFUSE_CMD_BT_GET_SIZE);

 		if (pre_efuse_map) {
			if (rtw_efuse_raw_map_read (padapter, 0, mapLen, pre_efuse_map, RTW_EFUSE_BT) == _FAIL) {
				RTW_INFO("%s: read bt raw map Fail!!\n", __FUNCTION__);
				err = -EFAULT;
			} else {
				realraw_map_data = pre_efuse_map;

				_rtw_memset(extra, '\0', strlen(extra));
				shift = blksz * raw_order;
				realraw_map_data += shift;
				cnt = mapLen - shift;
				if (cnt > blksz) {
					cnt = blksz;
					raw_order++;
				} else
					raw_order = 0;

				sprintf(extra, "\n");
				for (i = 0; i < cnt; i += 16) {
					pextra = extra + strlen(extra);
					pextra += sprintf(pextra, "0x%02x\t", shift + i);
					for (j = 0; j < 8; j++)
						pextra += sprintf(pextra, "%02X ", realraw_map_data[i + j]);
					pextra += sprintf(pextra, "\t");
					for (; j < 16; j++)
						pextra += sprintf(pextra, "%02X ", realraw_map_data[i + j]);
					pextra += sprintf(pextra, "\n");

					if (strlen(extra) > 0x7FF)
						break;
				}
				if ((shift + cnt) < mapLen)
					pextra += sprintf(pextra, "\t...more (left:%d/%d)\n", mapLen - (shift + cnt), mapLen);
				}
		}
	} else
		sprintf(extra, "Command not found!");

exit:
	if (pre_efuse_map)
		rtw_mfree(pre_efuse_map, RTW_MAX_EFUSE_MAP_LEN);
	if (!err)
		wrqu->data.length = strlen(extra);

	*(extra +  wrqu->data.length) = '\0';
	RTW_INFO("%s: strlen(extra) =%zu\n", __FUNCTION__, strlen(extra));
	if (copy_to_user(wrqu->data.pointer, extra, wrqu->data.length))
		err = -EFAULT;

	return err;
}


int rtw_ioctl_efuse_set(struct net_device *dev,
				struct iw_request_info *info,
				union iwreq_data *wdata, char *extra)
{
	struct iw_point *wrqu;
	struct pwrctrl_priv *pwrctrlpriv ;
	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
	struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);

	u32 i = 0, j = 0, jj = 0, kk = 0;
	u8 *setdata = NULL;
	u8 *shadowmap = NULL;
	u8 *setrawdata = NULL;
	char *pch, *ptmp, *token, *tmp[3] = {0x00, 0x00, 0x00};
	u16 addr = 0xFF, cnts = 0, max_available_len = 0;
	u16 wifimaplen = 0;
	int err = 0;
	boolean bcmpchk = _TRUE;
	u8 status = _SUCCESS;
	u16 size = 0;
	u8 bpg = true;

	wrqu = (struct iw_point *)wdata;
	pwrctrlpriv = adapter_to_pwrctl(padapter);

	if (copy_from_user(extra, wrqu->pointer, wrqu->length))
		return -EFAULT;

	*(extra + wrqu->length) = '\0';

	setdata = rtw_zmalloc(RTW_MAX_EFUSE_MAP_LEN);
	if (setdata == NULL) {
		err = -ENOMEM;
		goto exit;
	}

	pch = extra;
	RTW_INFO("%s: in=%s\n", __FUNCTION__, extra);

	i = 0;
	while ((token = strsep(&pch, ",")) != NULL) {
		if (i > 2)
			break;
		tmp[i] = token;
		i++;
	}

	/* tmp[0],[1],[2] */
	/* wmap,addr,00e04c871200 */
	if ((strcmp(tmp[0], "wmap") == 0) || (strcmp(tmp[0], "wlwfake") == 0)) {
		if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
			err = -EINVAL;
			goto exit;
		}

		addr = simple_strtoul(tmp[1], &ptmp, 16);
		addr &= 0xFFF;

		cnts = strlen(tmp[2]);
		if (cnts % 2) {
			err = -EINVAL;
			goto exit;
		}
		cnts /= 2;
		if (cnts == 0) {
			err = -EINVAL;
			goto exit;
		}

		RTW_INFO("%s: addr=0x%X\n", __FUNCTION__, addr);
		RTW_INFO("%s: cnts=%d\n", __FUNCTION__, cnts);
		RTW_INFO("%s: map data=%s\n", __FUNCTION__, tmp[2]);

		for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
			setdata[jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]);

		err = rtw_efuse_get_map_size(padapter, &size, RTW_EFUSE_CMD_WIFI_GET_LOG_SIZE);
		max_available_len = size;

		if (err == _FAIL) {
			status = _FAIL;
			goto exit;
		}

		if ((addr + cnts) > max_available_len) {
			RTW_INFO("%s: addr(0x%X)+cnts(%d) parameter error!\n", __FUNCTION__, addr, cnts);
			err = -EFAULT;
			goto exit;
		}

		if (strcmp(tmp[0], "wlwfake") == 0)
			bpg = false;

		if (rtw_efuse_map_write(padapter, addr, cnts, setdata, RTW_EFUSE_WIFI, bpg) == _FAIL) {
			RTW_INFO("%s: rtw_efuse_map_write error!!\n", __FUNCTION__);
			err = -EFAULT;
			goto exit;
		}

		*extra = 0;
		if (bpg) {
			RTW_INFO("%s: after rtw_efuse_map_write to _rtw_memcmp\n", __func__);
			shadowmap = rtw_zmalloc(size);
			if (shadowmap == NULL) {
				RTW_INFO("%s: ShadowMapWiFi rtw_zmalloc Fail\n", __func__);
				err = 0;
				goto exit;
			}
			if (rtw_efuse_get_shadow_map(padapter, shadowmap, size,RTW_EFUSE_WIFI) == _SUCCESS) {

				if (rtw_efuse_compare_data(padapter, addr, cnts, shadowmap, setdata, RTW_EFUSE_WIFI)) {
					RTW_INFO("%s: WiFi write map afterf compare success\n", __FUNCTION__);
					sprintf(extra, "WiFi write map compare OK\n");
					err = 0;
					goto exit;
				} else {
					RTW_MAP_DUMP_SEL(RTW_DBGDUMP, "shadowmap :", shadowmap + addr, cnts);
					RTW_MAP_DUMP_SEL(RTW_DBGDUMP, "map_pged :", setdata, cnts);
					sprintf(extra, "WiFi write map compare FAIL\n");
					RTW_INFO("%s: WiFi write map compare Fail\n", __FUNCTION__);
					err = 0;
					goto exit;
				}
			}
		} else {
			sprintf(extra, "WiFi write fake map OK\n");
			RTW_INFO("%s: WiFi write fake map OK\n", __FUNCTION__);
			err = 0;
			goto exit;
		}
	} else if ((strcmp(tmp[0], "btwmap") == 0) || (strcmp(tmp[0], "btwfake") == 0)) {
		if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
			err = -EINVAL;
			goto exit;
		}

		addr = simple_strtoul(tmp[1], &ptmp, 16);
		addr &= 0xFFF;

		cnts = strlen(tmp[2]);
		if (cnts % 2) {
			err = -EINVAL;
			goto exit;
		}
		cnts /= 2;
		if (cnts == 0) {
			err = -EINVAL;
			goto exit;
		}

		RTW_INFO("%s: addr=0x%X\n", __FUNCTION__, addr);
		RTW_INFO("%s: cnts=%d\n", __FUNCTION__, cnts);
		RTW_INFO("%s: map data=%s\n", __FUNCTION__, tmp[2]);

		for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
			setdata[jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]);

		err = rtw_efuse_get_map_size(padapter, &size, RTW_EFUSE_CMD_BT_GET_LOG_SIZE);
		max_available_len = size;

		if (err == _FAIL) {
			status = _FAIL;
			goto exit;
		}

		if ((addr + cnts) > max_available_len) {
			RTW_INFO("%s: addr(0x%X)+cnts(%d) parameter error!\n", __FUNCTION__, addr, cnts);
			err = -EFAULT;
			goto exit;
		}

		if (strcmp(tmp[0], "btwfake") == 0)
			bpg = false;

		if (rtw_efuse_map_write(padapter, addr, cnts, setdata, RTW_EFUSE_BT, bpg) == _FAIL) {
			RTW_INFO("%s: rtw_efuse_map_write error!!\n", __FUNCTION__);
			err = -EFAULT;
			goto exit;
		}

		*extra = 0;
		RTW_INFO("%s: after rtw_efuse_map_write to _rtw_memcmp\n", __func__);
		if (bpg) {
			shadowmap = rtw_zmalloc(size);
			if (shadowmap == NULL) {
				RTW_INFO("%s: shadowmap rtw_zmalloc Fail\n", __func__);
				err = 0;
				goto exit;
			}
			if (rtw_efuse_get_shadow_map(padapter, shadowmap, size,RTW_EFUSE_BT) == _SUCCESS) {

				if (rtw_efuse_compare_data(padapter, addr, cnts, shadowmap, setdata, RTW_EFUSE_BT)) {
					RTW_INFO("%s: BT write map afterf compare success\n", __func__);
					sprintf(extra, "BT write map compare OK\n");
					err = 0;
					goto exit;
				} else {
					RTW_MAP_DUMP_SEL(RTW_DBGDUMP, "shadowmap :", shadowmap, cnts);
					RTW_MAP_DUMP_SEL(RTW_DBGDUMP, "map_pged :", setdata, cnts);
					sprintf(extra, "BT write map compare FAIL\n");
					RTW_INFO("%s: BT write map compare Fail\n", __func__);
					err = 0;
					goto exit;
				}
			}
		} else {
			sprintf(extra, "BT write fake map OK\n");
			RTW_INFO("%s: BT write fake map OK\n", __FUNCTION__);
			err = 0;
			goto exit;
		}
	} else if (strcmp(tmp[0], "btwraw") == 0) {
		u8 reg2chkbt = 0;

		if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
			err = -EINVAL;
			goto exit;
		}

		addr = simple_strtoul(tmp[1], &ptmp, 16);
		addr &= 0xFFF;

		cnts = strlen(tmp[2]);
		if (cnts % 2) {
			err = -EINVAL;
			goto exit;
		}
		cnts /= 2;
		if (cnts == 0) {
			err = -EINVAL;
			goto exit;
		}

		RTW_INFO("%s: addr=0x%X\n", __FUNCTION__, addr);
		RTW_INFO("%s: cnts=%d\n", __FUNCTION__, cnts);
		RTW_INFO("%s: raw data=%s\n", __FUNCTION__, tmp[2]);

		rtw_phl_write8(dvobj->phl, 0xa3, 0x05);
		rtw_msleep_os(10);
		reg2chkbt = rtw_phl_read8(dvobj->phl, 0xa0);
		RTW_INFO("%s: btfk2map before read 0xa0 BT Status =0x%x\n", __func__,
			rtw_phl_read32(dvobj->phl, 0xa0));

		if (reg2chkbt != 0x04) {
			sprintf(extra, "Error ! BT State not Active:0x%x ,can't Write \n" , reg2chkbt);
			goto exit;
		}

		for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
			setdata[jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]);

		if (rtw_efuse_bt_write_raw_hidden(padapter, addr, cnts, setdata) == _FAIL) {
			RTW_INFO("%s: rtw_efuse_bt_write_hidden error!!\n", __FUNCTION__);
			err = -EFAULT;
			goto exit;
		}
	} else if (strcmp(tmp[0], "wlfk2map") == 0) {
		u16 mapsize = 0;
		u8 *map_pged = NULL;

		RTW_INFO("%s:do rtw_efuse_fake2map\n", __func__);
		rtw_efuse_get_map_size(padapter, &mapsize, RTW_EFUSE_CMD_WIFI_GET_LOG_SIZE);
		shadowmap = rtw_zmalloc(mapsize);
		if (shadowmap == NULL) {
			RTW_INFO("%s: shadowmap rtw_zmalloc Fail\n", __func__);
			err = 0;
			goto exit;
		}
		if (rtw_efuse_get_shadow_map(padapter, shadowmap, mapsize, RTW_EFUSE_WIFI) == _FAIL) {
			RTW_INFO("%s:rtw_efuse_get_shadow_map Fail\n", __func__);
			err = 0;
			goto exit;
		}

		status = rtw_efuse_fake2map(padapter, RTW_EFUSE_WIFI);
		if (status == _SUCCESS)
			RTW_INFO("WIFI write map OK\n");
		else
			RTW_INFO("WIFI write map FAIL\n");

		map_pged = rtw_zmalloc(mapsize);
		if (map_pged == NULL) {
			RTW_INFO("%s: map_pged rtw_zmalloc Fail\n", __func__);
			err = 0;
			goto exit;
		}
		if (rtw_efuse_map_read(padapter, 0x00, mapsize, map_pged, RTW_EFUSE_WIFI) == _SUCCESS) {

			if (rtw_efuse_compare_data(padapter, 0x00, mapsize, map_pged, shadowmap, RTW_EFUSE_WIFI)) {
				RTW_INFO("%s: WiFi write map afterf compare success\n", __func__);
				sprintf(extra, "WiFi write map compare OK\n");
			} else {
				RTW_MAP_DUMP_SEL(RTW_DBGDUMP, "shadowmap :", shadowmap, mapsize);
				RTW_MAP_DUMP_SEL(RTW_DBGDUMP, "map_pged :", map_pged, mapsize);
				sprintf(extra, "WiFi write map compare FAIL\n");
				RTW_INFO("%s: WiFi write map compare Fail\n", __func__);
			}
		}

		if (map_pged)
			rtw_mfree(map_pged, mapsize);
		err = 0;
		goto exit;
	} else if (strcmp(tmp[0], "btfk2map") == 0) {
		u8 reg2chkbt = 0;
		u16 mapsize = 0;
		u8 *map_pged = NULL;

		RTW_INFO("%s:do rtw_efuse_fake2map\n", __func__);
		rtw_efuse_get_map_size(padapter, &mapsize, RTW_EFUSE_CMD_BT_GET_LOG_SIZE);
		shadowmap = rtw_zmalloc(mapsize);
		if (shadowmap == NULL) {
			RTW_INFO("%s: shadowmap rtw_zmalloc Fail\n", __func__);
			err = 0;
			goto exit;
		}
		if (rtw_efuse_get_shadow_map(padapter, shadowmap, mapsize, RTW_EFUSE_BT) == _FAIL) {
			RTW_INFO("%s:rtw_efuse_get_shadow_map Fail\n", __func__);
			err = 0;
			goto exit;
		}

		rtw_phl_write8(dvobj->phl, 0xa3, 0x05);
		rtw_msleep_os(10);
		reg2chkbt = rtw_phl_read8(dvobj->phl, 0xa0);
		RTW_INFO("%s: btfk2map before read 0xa0 BT Status =0x%x\n", __func__,
			rtw_phl_read32(dvobj->phl, 0xa0));

		if (reg2chkbt != 0x04) {
			sprintf(extra, "Error ! BT State not Active:0x%x ,can't Write \n" , reg2chkbt);
			goto exit;
		}

		status = rtw_efuse_fake2map(padapter, RTW_EFUSE_BT);
		if (status == _SUCCESS)
			RTW_INFO("BT write map OK\n");
		else
			RTW_INFO("BT write map FAIL\n");

		map_pged = rtw_zmalloc(mapsize);
		if (map_pged == NULL) {
			RTW_INFO("%s: map_pged rtw_zmalloc Fail\n", __func__);
			err = 0;
			goto exit;
		}

		if (rtw_efuse_map_read(padapter, 0x00, mapsize, map_pged, RTW_EFUSE_BT) == _SUCCESS) {

			if (rtw_efuse_compare_data(padapter, 0x00, mapsize, map_pged, shadowmap, RTW_EFUSE_BT)) {
				RTW_INFO("%s: BT write map afterf compare success\n", __func__);
				sprintf(extra, "BT write map compare OK\n");
			} else {
				RTW_MAP_DUMP_SEL(RTW_DBGDUMP, "shadowmap :", shadowmap, mapsize);
				RTW_MAP_DUMP_SEL(RTW_DBGDUMP, "map_pged :", map_pged, mapsize);
				sprintf(extra, "BT write map compare FAIL\n");
				RTW_INFO("%s: BT write map compare Fail\n", __func__);
			}
		}

		if (map_pged)
			rtw_mfree(map_pged, mapsize);

		err = 0;
		goto exit;
	} else if (strcmp(tmp[0], "update") == 0) {
		if (rtw_efuse_renew_update(padapter, RTW_EFUSE_WIFI) == _FAIL) {
			RTW_INFO("%s: rtw_efuse_renew_update error!!\n", __FUNCTION__);
			sprintf(extra, "WIFI update FAIL\n");
			err = -EFAULT;
			goto exit;
		} else
			sprintf(extra, "WIFI update OK\n");

	}
exit:
	if (setdata)
		rtw_mfree(setdata, RTW_MAX_EFUSE_MAP_LEN);
	if (shadowmap)
		rtw_mfree(shadowmap, size);

	wrqu->length = strlen(extra);

	return err;
}

int rtw_ioctl_efuse_file_map_load(struct net_device *dev,
				struct iw_request_info *info,
				union iwreq_data *wrqu, char *extra)
{
	char *rtw_efuse_file_map_path;
	u8 Status = 0;
	_adapter *padapter= rtw_netdev_priv(dev);
	struct mp_priv *pmp_priv = &padapter->mppriv;

	if (rtw_do_mp_iwdata_len_chk(__func__, ( wrqu->data.length + 1)))
		return -EFAULT;

	if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length))
		return -EFAULT;
	extra[wrqu->data.length] = '\0';

	rtw_efuse_file_map_path = extra;
	if (rtw_is_file_readable(rtw_efuse_file_map_path) == _TRUE) {
		RTW_INFO("%s do rtw_efuse_mask_file_read = %s!\n", __func__, rtw_efuse_file_map_path);
		Status = rtw_efuse_map_file_load(padapter, rtw_efuse_file_map_path, RTW_EFUSE_WIFI);
		if (Status == _TRUE) {
			pmp_priv->bloadefusemap = _TRUE;
			sprintf(extra, "efuse Map file file_read OK\n");
		} else {
			pmp_priv->bloadefusemap = _FALSE;
			sprintf(extra, "efuse Map file file_read FAIL\n");
		}
	} else {
		sprintf(extra, "efuse file readable FAIL\n");
		RTW_INFO("%s rtw_is_file_readable fail!\n", __func__);
	}

	wrqu->data.length = strlen(extra);
	return 0;
}

int rtw_ioctl_efuse_file_mask_load(struct net_device *dev,
				struct iw_request_info *info,
				union iwreq_data *wrqu, char *extra)
{
	char *rtw_efuse_file_map_path;
	u8 Status = 0;
	_adapter *padapter= rtw_netdev_priv(dev);
	struct mp_priv *pmp_priv = &padapter->mppriv;


	if (rtw_do_mp_iwdata_len_chk(__func__, ( wrqu->data.length + 1)))
		return -EFAULT;

	if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length))
		return -EFAULT;
	extra[wrqu->data.length] = '\0';

	rtw_efuse_file_map_path = extra;
	if (rtw_is_file_readable(rtw_efuse_file_map_path) == _TRUE) {
		RTW_INFO("%s do rtw_efuse_mask_file_read = %s!\n", __func__, rtw_efuse_file_map_path);
		Status = rtw_efuse_mask_file_load(padapter, rtw_efuse_file_map_path, RTW_EFUSE_WIFI);
		if (Status == _TRUE) {
			pmp_priv->bloadefusemap = _TRUE;
			sprintf(extra, "efuse Mask file file_read OK\n");
		} else {
			pmp_priv->bloadefusemap = _FALSE;
			sprintf(extra, "efuse Mask file file_read FAIL\n");
		}
	} else {
		sprintf(extra, "efuse file readable FAIL\n");
		RTW_INFO("%s rtw_is_file_readable fail!\n", __func__);
	}

	wrqu->data.length = strlen(extra);
	return 0;
}


int rtw_ioctl_efuse_bt_file_map_load(struct net_device *dev,
				struct iw_request_info *info,
				union iwreq_data *wrqu, char *extra)
{
	char *rtw_efuse_file_map_path;
	u8 Status = 0;
	_adapter *padapter= rtw_netdev_priv(dev);
	struct mp_priv *pmp_priv = &padapter->mppriv;

	if (rtw_do_mp_iwdata_len_chk(__func__, ( wrqu->data.length + 1)))
		return -EFAULT;

	if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length))
		return -EFAULT;
	extra[wrqu->data.length] = '\0';

	rtw_efuse_file_map_path = extra;
	if (rtw_is_file_readable(rtw_efuse_file_map_path) == _TRUE) {
		RTW_INFO("%s BT do rtw_efuse_mask_file_read = %s!\n", __func__, rtw_efuse_file_map_path);
		Status = rtw_efuse_map_file_load(padapter, rtw_efuse_file_map_path, RTW_EFUSE_BT);
		if (Status == _TRUE) {
			pmp_priv->bloadefusemap = _TRUE;
			sprintf(extra, "BT efuse Map file file_read OK\n");
		} else {
			pmp_priv->bloadefusemap = _FALSE;
			sprintf(extra, "BT efuse Map file file_read FAIL\n");
		}
	} else {
		sprintf(extra, "BT efuse file readable FAIL\n"
				"indicate the file path and directory to CMD next space,\n"
				"CMD format:rtwpriv wlan0 bt_efuse_file /xx/xx/xx/efuse.map\n");
		RTW_INFO("%s BT rtw_is_file_readable fail!\n", __func__);
	}

	wrqu->data.length = strlen(extra);
	return 0;
}

int rtw_ioctl_efuse_bt_file_mask_load(struct net_device *dev,
				struct iw_request_info *info,
				union iwreq_data *wrqu, char *extra)
{
	char *rtw_efuse_file_map_path;
	u8 Status = 0;
	_adapter *padapter= rtw_netdev_priv(dev);
	struct mp_priv *pmp_priv = &padapter->mppriv;

	if (rtw_do_mp_iwdata_len_chk(__func__, ( wrqu->data.length + 1)))
		return -EFAULT;

	if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length))
		return -EFAULT;

	extra[wrqu->data.length] = '\0';

	rtw_efuse_file_map_path = extra;
	if (rtw_is_file_readable(rtw_efuse_file_map_path) == _TRUE) {
		RTW_INFO("%s BT mask do rtw_efuse_mask_file_read = %s!\n", __func__, rtw_efuse_file_map_path);
		Status = rtw_efuse_mask_file_load(padapter, rtw_efuse_file_map_path, RTW_EFUSE_BT);
		if (Status == _TRUE) {
			pmp_priv->bloadefusemap = _TRUE;
			sprintf(extra, "BT efuse Mask file file_read OK\n");
		} else {
			pmp_priv->bloadefusemap = _FALSE;
			sprintf(extra, "BT efuse Mask file file_read FAIL\n");
		}
	} else {
		sprintf(extra, "BT efuse file readable FAIL\n"
			"indicate the file path and directory to CMD next space,\n"
			"CMD format:rtwpriv wlan0 efuse_bt_mask /xx/xx/xx/efuse.mask\n");
		RTW_INFO("%s BT rtw_is_file_readable fail!\n", __func__);
	}

	wrqu->data.length = strlen(extra);
	return 0;
}

s8 rtw_efuse_get_map_from(_adapter *padapter)
{
	struct rtw_efuse_phl_arg *efuse_arg = NULL;
	u8 map_status = -1;

	efuse_arg = _rtw_malloc(sizeof(struct rtw_efuse_phl_arg));
	if (efuse_arg) {
		_rtw_memset((void *)efuse_arg,
				0,
				sizeof(struct rtw_efuse_phl_arg));
		rtw_efuse_cmd(padapter,
				efuse_arg,
				RTW_MP_EFUSE_CMD_WIFI_GET_MAP_FROM);

		if (efuse_arg->cmd_ok && 
			efuse_arg->status == RTW_PHL_STATUS_SUCCESS) {
			map_status = efuse_arg->io_value;
			RTW_INFO("%s: OK value:%d\n",
				__func__, map_status);
		} else {
			map_status = -1;
			RTW_INFO("%s: fail !\n", __func__);
		}
	}
	if (efuse_arg)
		_rtw_mfree(efuse_arg, sizeof(struct rtw_efuse_phl_arg));

	return map_status;
}

static u8 rtw_efuse_get_realraw(_adapter *padapter, u8 *map, u16 addr, u16 size, u8 efuse_type)
{
	struct rtw_efuse_phl_arg *efuse_arg = NULL;
	u8 res = _FAIL;

	efuse_arg = _rtw_malloc(sizeof(struct rtw_efuse_phl_arg));
	if (efuse_arg) {
		efuse_arg->io_offset = addr;
		efuse_arg->buf_len = size;
		if (efuse_type == RTW_EFUSE_WIFI)
		    rtw_efuse_cmd(padapter, efuse_arg, RTW_EFUSE_CMD_WIFI_GET_PHY_MAP);
		else if (efuse_type == RTW_EFUSE_BT)
			rtw_efuse_cmd(padapter, efuse_arg, RTW_EFUSE_CMD_BT_GET_PHY_MAP);
		if (efuse_arg->cmd_ok && efuse_arg->status == RTW_PHL_STATUS_SUCCESS) {
				_rtw_memcpy((void *)map, efuse_arg->poutbuf, size);
				res = _SUCCESS;
		} else
				res = _FAIL;
	}
	if (efuse_arg)
		_rtw_mfree(efuse_arg, sizeof(struct rtw_efuse_phl_arg));

	return res;
}

u8 rtw_efuse_raw_map_read(_adapter * adapter, u16 addr, u16 cnts, u8 *data, u8 efuse_type)
{
	struct dvobj_priv *d;
	u8 *efuse = NULL;
	u16 size, i;
	int err = _FAIL;
	u8 status = _SUCCESS;

	if (efuse_type == RTW_EFUSE_WIFI)
		err = rtw_efuse_get_map_size(adapter, &size, RTW_EFUSE_CMD_WIFI_GET_SIZE);
	else if (efuse_type == RTW_EFUSE_BT)
		err = rtw_efuse_get_map_size(adapter, &size, RTW_EFUSE_CMD_BT_GET_SIZE);

	if (err == _FAIL) {
		status = _FAIL;
		RTW_INFO("get_efuse_size fail\n");
		goto exit;
	}
	/* size error handle */
	if ((addr + cnts) > size) {
		if (addr < size)
			cnts = size - addr;
		else {
			status = _FAIL;
			RTW_INFO(" %s() ,addr + cnts) > size fail\n", __func__);
			goto exit;
		}
	}

	efuse = rtw_zmalloc(size);
	if (efuse) {
		err = rtw_efuse_get_realraw (adapter, efuse, addr, size, efuse_type);
		if (err == _FAIL) {
			rtw_mfree(efuse, size);
			status = _FAIL;
			RTW_INFO(" %s() , phl get realraw fail\n", __func__);
			goto exit;
		}
		if (efuse) {
			RTW_INFO(" %s() ,cp efuse to data\n", __func__);
			_rtw_memcpy(data, efuse + addr, cnts);
			rtw_mfree(efuse, size);
		}
	} else {
			RTW_INFO(" %s() ,alloc efuse fail\n", __func__);
			goto exit;
	}
	status = _SUCCESS;
exit:

	return status;
}

u8 rtw_efuse_bt_write_raw_hidden(_adapter * adapter, u16 addr, u16 cnts, u8 *data)
{
	u8 status = _SUCCESS;
	struct rtw_efuse_phl_arg *efuse_arg = NULL;
	u16 i = 0;

	efuse_arg = _rtw_zmalloc(sizeof(struct rtw_efuse_phl_arg));

	while (i < cnts) {
		efuse_arg->io_type = 1;
		efuse_arg->io_offset = addr + i;
		efuse_arg->io_value = data[i];
		rtw_efuse_cmd(adapter, efuse_arg, RTW_EFUSE_CMD_BT_WRITE_HIDDEN);
		if (efuse_arg->cmd_ok && efuse_arg->status == RTW_PHL_STATUS_SUCCESS)
			status = _SUCCESS;
		else{
			status = _FAIL;
			break;
		}
		i++;
	}
exit :
	if (efuse_arg)
		_rtw_mfree(efuse_arg, sizeof(struct rtw_efuse_phl_arg));

	return status;
}

#endif /*#if defined(CONFIG_MP_INCLUDED)*/

