#include <linux/fs.h>

#include "headers.h"
/***************************************************************
* Function	  - bcm_char_open()
*
* Description - This is the "open" entry point for the character
*				driver.
*
* Parameters  - inode: Pointer to the Inode structure of char device
*				filp : File pointer of the char device
*
* Returns	  - Zero(Success)
****************************************************************/

static int bcm_char_open(struct inode *inode, struct file * filp)
{
	PMINI_ADAPTER       Adapter = NULL;
	PPER_TARANG_DATA    pTarang = NULL;

	Adapter = GET_BCM_ADAPTER(gblpnetdev);
	pTarang = kzalloc(sizeof(PER_TARANG_DATA), GFP_KERNEL);
	if (!pTarang)
		return -ENOMEM;

	pTarang->Adapter = Adapter;
	pTarang->RxCntrlMsgBitMask = 0xFFFFFFFF & ~(1 << 0xB);

	down(&Adapter->RxAppControlQueuelock);
	pTarang->next = Adapter->pTarangs;
	Adapter->pTarangs = pTarang;
	up(&Adapter->RxAppControlQueuelock);

	/* Store the Adapter structure */
	filp->private_data = pTarang;

	/* Start Queuing the control response Packets */
	atomic_inc(&Adapter->ApplicationRunning);

	nonseekable_open(inode, filp);
	return 0;
}

static int bcm_char_release(struct inode *inode, struct file *filp)
{
	PPER_TARANG_DATA pTarang, tmp, ptmp;
	PMINI_ADAPTER Adapter = NULL;
	struct sk_buff *pkt, *npkt;

	pTarang = (PPER_TARANG_DATA)filp->private_data;

	if (pTarang == NULL) {
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
				"ptarang is null\n");
		return 0;
	}

	Adapter = pTarang->Adapter;

	down(&Adapter->RxAppControlQueuelock);

	tmp = Adapter->pTarangs;
	for (ptmp = NULL; tmp; ptmp = tmp, tmp = tmp->next) {
		if (tmp == pTarang)
			break;
	}

	if (tmp) {
		if (!ptmp)
			Adapter->pTarangs = tmp->next;
		else
			ptmp->next = tmp->next;
	} else {
		up(&Adapter->RxAppControlQueuelock);
		return 0;
	}

	pkt = pTarang->RxAppControlHead;
	while (pkt) {
		npkt = pkt->next;
		kfree_skb(pkt);
		pkt = npkt;
	}

	up(&Adapter->RxAppControlQueuelock);

	/* Stop Queuing the control response Packets */
	atomic_dec(&Adapter->ApplicationRunning);

	kfree(pTarang);

	/* remove this filp from the asynchronously notified filp's */
	filp->private_data = NULL;
	return 0;
}

static ssize_t bcm_char_read(struct file *filp, char __user *buf, size_t size,
			     loff_t *f_pos)
{
	PPER_TARANG_DATA pTarang = filp->private_data;
	PMINI_ADAPTER	Adapter = pTarang->Adapter;
	struct sk_buff *Packet = NULL;
	ssize_t PktLen = 0;
	int wait_ret_val = 0;
	unsigned long ret = 0;

	wait_ret_val = wait_event_interruptible(Adapter->process_read_wait_queue,
						(pTarang->RxAppControlHead ||
						 Adapter->device_removed));
	if ((wait_ret_val == -ERESTARTSYS)) {
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
				"Exiting as i've been asked to exit!!!\n");
		return wait_ret_val;
	}

	if (Adapter->device_removed) {
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
				"Device Removed... Killing the Apps...\n");
		return -ENODEV;
	}

	if (FALSE == Adapter->fw_download_done)
		return -EACCES;

	down(&Adapter->RxAppControlQueuelock);

	if (pTarang->RxAppControlHead) {
		Packet = pTarang->RxAppControlHead;
		DEQUEUEPACKET(pTarang->RxAppControlHead,
			      pTarang->RxAppControlTail);
		pTarang->AppCtrlQueueLen--;
	}

	up(&Adapter->RxAppControlQueuelock);

	if (Packet) {
		PktLen = Packet->len;
		ret = copy_to_user(buf, Packet->data,
				   min_t(size_t, PktLen, size));
		if (ret) {
			dev_kfree_skb(Packet);
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
					"Returning from copy to user failure\n");
			return -EFAULT;
		}
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
				"Read %zd Bytes From Adapter packet = %p by process %d!\n",
				PktLen, Packet, current->pid);
		dev_kfree_skb(Packet);
	}

	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "<\n");
	return PktLen;
}

static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
{
	PPER_TARANG_DATA  pTarang = filp->private_data;
	void __user *argp = (void __user *)arg;
	PMINI_ADAPTER Adapter = pTarang->Adapter;
	INT Status = STATUS_FAILURE;
	int timeout = 0;
	IOCTL_BUFFER IoBuffer;
	int bytes;

	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Parameters Passed to control IOCTL cmd=0x%X arg=0x%lX", cmd, arg);

	if (_IOC_TYPE(cmd) != BCM_IOCTL)
		return -EFAULT;
	if (_IOC_DIR(cmd) & _IOC_READ)
		Status = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd));
	else if (_IOC_DIR(cmd) & _IOC_WRITE)
		Status = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd));
	else if (_IOC_NONE == (_IOC_DIR(cmd) & _IOC_NONE))
		Status = STATUS_SUCCESS;

	if (Status)
		return -EFAULT;

	if (Adapter->device_removed)
		return -EFAULT;

	if (FALSE == Adapter->fw_download_done) {
		switch (cmd) {
		case IOCTL_MAC_ADDR_REQ:
		case IOCTL_LINK_REQ:
		case IOCTL_CM_REQUEST:
		case IOCTL_SS_INFO_REQ:
		case IOCTL_SEND_CONTROL_MESSAGE:
		case IOCTL_IDLE_REQ:
		case IOCTL_BCM_GPIO_SET_REQUEST:
		case IOCTL_BCM_GPIO_STATUS_REQUEST:
			return -EACCES;
		default:
			break;
		}
	}

	Status = vendorextnIoctl(Adapter, cmd, arg);
	if (Status != CONTINUE_COMMON_PATH)
		return Status;

	switch (cmd) {
	/* Rdms for Swin Idle... */
	case IOCTL_BCM_REGISTER_READ_PRIVATE: {
		RDM_BUFFER  sRdmBuffer = {0};
		PCHAR temp_buff;
		UINT Bufflen;
		u16 temp_value;

		/* Copy Ioctl Buffer structure */
		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
			return -EFAULT;

		if (IoBuffer.InputLength > sizeof(sRdmBuffer))
			return -EINVAL;

		if (copy_from_user(&sRdmBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength))
			return -EFAULT;

		if (IoBuffer.OutputLength > USHRT_MAX ||
			IoBuffer.OutputLength == 0) {
			return -EINVAL;
		}

		Bufflen = IoBuffer.OutputLength;
		temp_value = 4 - (Bufflen % 4);
		Bufflen += temp_value % 4;

		temp_buff = kmalloc(Bufflen, GFP_KERNEL);
		if (!temp_buff)
			return -ENOMEM;

		bytes = rdmalt(Adapter, (UINT)sRdmBuffer.Register,
				(PUINT)temp_buff, Bufflen);
		if (bytes > 0) {
			Status = STATUS_SUCCESS;
			if (copy_to_user(IoBuffer.OutputBuffer, temp_buff, bytes)) {
				kfree(temp_buff);
				return -EFAULT;
			}
		} else {
			Status = bytes;
		}

		kfree(temp_buff);
		break;
	}

	case IOCTL_BCM_REGISTER_WRITE_PRIVATE: {
		WRM_BUFFER  sWrmBuffer = {0};
		UINT uiTempVar = 0;
		/* Copy Ioctl Buffer structure */

		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
			return -EFAULT;

		if (IoBuffer.InputLength > sizeof(sWrmBuffer))
			return -EINVAL;

		/* Get WrmBuffer structure */
		if (copy_from_user(&sWrmBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength))
			return -EFAULT;

		uiTempVar = sWrmBuffer.Register & EEPROM_REJECT_MASK;
		if (!((Adapter->pstargetparams->m_u32Customize) & VSG_MODE) &&
			((uiTempVar == EEPROM_REJECT_REG_1) ||
				(uiTempVar == EEPROM_REJECT_REG_2) ||
				(uiTempVar == EEPROM_REJECT_REG_3) ||
				(uiTempVar == EEPROM_REJECT_REG_4))) {

			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "EEPROM Access Denied, not in VSG Mode\n");
			return -EFAULT;
		}

		Status = wrmalt(Adapter, (UINT)sWrmBuffer.Register,
				(PUINT)sWrmBuffer.Data, sizeof(ULONG));

		if (Status == STATUS_SUCCESS) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "WRM Done\n");
		} else {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "WRM Failed\n");
			Status = -EFAULT;
		}
		break;
	}

	case IOCTL_BCM_REGISTER_READ:
	case IOCTL_BCM_EEPROM_REGISTER_READ: {
		RDM_BUFFER  sRdmBuffer = {0};
		PCHAR temp_buff = NULL;
		UINT uiTempVar = 0;
		if ((Adapter->IdleMode == TRUE) ||
			(Adapter->bShutStatus == TRUE) ||
			(Adapter->bPreparingForLowPowerMode == TRUE)) {

			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Device in Idle Mode, Blocking Rdms\n");
			return -EACCES;
		}

		/* Copy Ioctl Buffer structure */
		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
			return -EFAULT;

		if (IoBuffer.InputLength > sizeof(sRdmBuffer))
			return -EINVAL;

		if (copy_from_user(&sRdmBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength))
			return -EFAULT;

		if (IoBuffer.OutputLength > USHRT_MAX ||
			IoBuffer.OutputLength == 0) {
			return -EINVAL;
		}

		temp_buff = kmalloc(IoBuffer.OutputLength, GFP_KERNEL);
		if (!temp_buff)
			return STATUS_FAILURE;

		if ((((ULONG)sRdmBuffer.Register & 0x0F000000) != 0x0F000000) ||
			((ULONG)sRdmBuffer.Register & 0x3)) {

			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "RDM Done On invalid Address : %x Access Denied.\n",
					(int)sRdmBuffer.Register);

			kfree(temp_buff);
			return -EINVAL;
		}

		uiTempVar = sRdmBuffer.Register & EEPROM_REJECT_MASK;
		bytes = rdmaltWithLock(Adapter, (UINT)sRdmBuffer.Register, (PUINT)temp_buff, IoBuffer.OutputLength);

		if (bytes > 0) {
			Status = STATUS_SUCCESS;
			if (copy_to_user(IoBuffer.OutputBuffer, temp_buff, bytes)) {
				kfree(temp_buff);
				return -EFAULT;
			}
		} else {
			Status = bytes;
		}

		kfree(temp_buff);
		break;
	}
	case IOCTL_BCM_REGISTER_WRITE:
	case IOCTL_BCM_EEPROM_REGISTER_WRITE: {
		WRM_BUFFER  sWrmBuffer = {0};
		UINT uiTempVar = 0;
		if ((Adapter->IdleMode == TRUE) ||
			(Adapter->bShutStatus == TRUE) ||
			(Adapter->bPreparingForLowPowerMode == TRUE)) {

			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Device in Idle Mode, Blocking Wrms\n");
			return -EACCES;
		}

		/* Copy Ioctl Buffer structure */
		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
			return -EFAULT;

		if (IoBuffer.InputLength > sizeof(sWrmBuffer))
			return -EINVAL;

		/* Get WrmBuffer structure */
		if (copy_from_user(&sWrmBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength))
			return -EFAULT;

		if ((((ULONG)sWrmBuffer.Register & 0x0F000000) != 0x0F000000) ||
			((ULONG)sWrmBuffer.Register & 0x3)) {

			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "WRM Done On invalid Address : %x Access Denied.\n", (int)sWrmBuffer.Register);
			return -EINVAL;
		}

		uiTempVar = sWrmBuffer.Register & EEPROM_REJECT_MASK;
		if (!((Adapter->pstargetparams->m_u32Customize) & VSG_MODE) &&
				((uiTempVar == EEPROM_REJECT_REG_1) ||
				(uiTempVar == EEPROM_REJECT_REG_2) ||
				(uiTempVar == EEPROM_REJECT_REG_3) ||
				(uiTempVar == EEPROM_REJECT_REG_4)) &&
				(cmd == IOCTL_BCM_REGISTER_WRITE)) {

				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "EEPROM Access Denied, not in VSG Mode\n");
				return -EFAULT;
		}

		Status = wrmaltWithLock(Adapter, (UINT)sWrmBuffer.Register,
					(PUINT)sWrmBuffer.Data, sWrmBuffer.Length);

		if (Status == STATUS_SUCCESS) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, OSAL_DBG, DBG_LVL_ALL, "WRM Done\n");
		} else {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "WRM Failed\n");
			Status = -EFAULT;
		}
		break;
	}
	case IOCTL_BCM_GPIO_SET_REQUEST: {
		UCHAR ucResetValue[4];
		UINT value = 0;
		UINT uiBit = 0;
		UINT uiOperation = 0;

		GPIO_INFO   gpio_info = {0};
		if ((Adapter->IdleMode == TRUE) ||
			(Adapter->bShutStatus == TRUE) ||
			(Adapter->bPreparingForLowPowerMode == TRUE)) {

			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "GPIO Can't be set/clear in Low power Mode");
			return -EACCES;
		}

		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
			return -EFAULT;

		if (IoBuffer.InputLength > sizeof(gpio_info))
			return -EINVAL;

		if (copy_from_user(&gpio_info, IoBuffer.InputBuffer, IoBuffer.InputLength))
			return -EFAULT;

		uiBit  = gpio_info.uiGpioNumber;
		uiOperation = gpio_info.uiGpioValue;
		value = (1<<uiBit);

		if (IsReqGpioIsLedInNVM(Adapter, value) == FALSE) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Sorry, Requested GPIO<0x%X> is not correspond to LED !!!", value);
			Status = -EINVAL;
			break;
		}

		/* Set - setting 1 */
		if (uiOperation) {
			/* Set the gpio output register */
			Status = wrmaltWithLock(Adapter, BCM_GPIO_OUTPUT_SET_REG, (PUINT)(&value), sizeof(UINT));

			if (Status == STATUS_SUCCESS) {
				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Set the GPIO bit\n");
			} else {
				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Failed to set the %dth GPIO\n", uiBit);
				break;
			}
		} else {
			/* Set the gpio output register */
			Status = wrmaltWithLock(Adapter, BCM_GPIO_OUTPUT_CLR_REG, (PUINT)(&value), sizeof(UINT));

			if (Status == STATUS_SUCCESS) {
				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Set the GPIO bit\n");
			} else {
				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Failed to clear the %dth GPIO\n", uiBit);
				break;
			}
		}

		bytes = rdmaltWithLock(Adapter, (UINT)GPIO_MODE_REGISTER, (PUINT)ucResetValue, sizeof(UINT));
		if (bytes < 0) {
			Status = bytes;
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
					"GPIO_MODE_REGISTER read failed");
			break;
		} else {
			Status = STATUS_SUCCESS;
		}

		/* Set the gpio mode register to output */
		*(UINT *)ucResetValue |= (1<<uiBit);
		Status = wrmaltWithLock(Adapter, GPIO_MODE_REGISTER,
					(PUINT)ucResetValue, sizeof(UINT));

		if (Status == STATUS_SUCCESS) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Set the GPIO to output Mode\n");
		} else {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Failed to put GPIO in Output Mode\n");
			break;
		}
	}
	break;

	case BCM_LED_THREAD_STATE_CHANGE_REQ: {
		USER_THREAD_REQ threadReq = {0};
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "User made LED thread InActive");

		if ((Adapter->IdleMode == TRUE) ||
			(Adapter->bShutStatus == TRUE) ||
			(Adapter->bPreparingForLowPowerMode == TRUE)) {

			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "GPIO Can't be set/clear in Low power Mode");
			Status = -EACCES;
			break;
		}

		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
			return -EFAULT;

		if (IoBuffer.InputLength > sizeof(threadReq))
			return -EINVAL;

		if (copy_from_user(&threadReq, IoBuffer.InputBuffer, IoBuffer.InputLength))
			return -EFAULT;

		/* if LED thread is running(Actively or Inactively) set it state to make inactive */
		if (Adapter->LEDInfo.led_thread_running) {
			if (threadReq.ThreadState == LED_THREAD_ACTIVATION_REQ) {
				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Activating thread req");
				Adapter->DriverState = LED_THREAD_ACTIVE;
			} else {
				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "DeActivating Thread req.....");
				Adapter->DriverState = LED_THREAD_INACTIVE;
			}

			/* signal thread. */
			wake_up(&Adapter->LEDInfo.notify_led_event);
		}
	}
	break;

	case IOCTL_BCM_GPIO_STATUS_REQUEST: {
		ULONG uiBit = 0;
		UCHAR ucRead[4];
		GPIO_INFO   gpio_info = {0};

		if ((Adapter->IdleMode == TRUE) ||
			(Adapter->bShutStatus == TRUE) ||
			(Adapter->bPreparingForLowPowerMode == TRUE))
			return -EACCES;

		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
			return -EFAULT;

		if (IoBuffer.InputLength > sizeof(gpio_info))
			return -EINVAL;

		if (copy_from_user(&gpio_info, IoBuffer.InputBuffer, IoBuffer.InputLength))
			return -EFAULT;

		uiBit = gpio_info.uiGpioNumber;

		/* Set the gpio output register */
		bytes = rdmaltWithLock(Adapter, (UINT)GPIO_PIN_STATE_REGISTER,
					(PUINT)ucRead, sizeof(UINT));

		if (bytes < 0) {
			Status = bytes;
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "RDM Failed\n");
			return Status;
		} else {
			Status = STATUS_SUCCESS;
		}
	}
	break;

	case IOCTL_BCM_GPIO_MULTI_REQUEST: {
		UCHAR ucResetValue[4];
		GPIO_MULTI_INFO gpio_multi_info[MAX_IDX];
		PGPIO_MULTI_INFO pgpio_multi_info = (PGPIO_MULTI_INFO)gpio_multi_info;

		memset(pgpio_multi_info, 0, MAX_IDX * sizeof(GPIO_MULTI_INFO));

		if ((Adapter->IdleMode == TRUE) ||
			(Adapter->bShutStatus == TRUE) ||
			(Adapter->bPreparingForLowPowerMode == TRUE))
			return -EINVAL;

		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
			return -EFAULT;

		if (IoBuffer.InputLength > sizeof(gpio_multi_info))
			return -EINVAL;

		if (copy_from_user(&gpio_multi_info, IoBuffer.InputBuffer, IoBuffer.InputLength))
			return -EFAULT;

		if (IsReqGpioIsLedInNVM(Adapter, pgpio_multi_info[WIMAX_IDX].uiGPIOMask) == FALSE) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
					"Sorry, Requested GPIO<0x%X> is not correspond to NVM LED bit map<0x%X>!!!",
					pgpio_multi_info[WIMAX_IDX].uiGPIOMask, Adapter->gpioBitMap);
			Status = -EINVAL;
			break;
		}

		/* Set the gpio output register */
		if ((pgpio_multi_info[WIMAX_IDX].uiGPIOMask) &
			(pgpio_multi_info[WIMAX_IDX].uiGPIOCommand)) {
			/* Set 1's in GPIO OUTPUT REGISTER */
			*(UINT *)ucResetValue =  pgpio_multi_info[WIMAX_IDX].uiGPIOMask &
				pgpio_multi_info[WIMAX_IDX].uiGPIOCommand &
				pgpio_multi_info[WIMAX_IDX].uiGPIOValue;

			if (*(UINT *) ucResetValue)
				Status = wrmaltWithLock(Adapter, BCM_GPIO_OUTPUT_SET_REG,
							(PUINT)ucResetValue, sizeof(ULONG));

			if (Status != STATUS_SUCCESS) {
				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "WRM to BCM_GPIO_OUTPUT_SET_REG Failed.");
				return Status;
			}

			/* Clear to 0's in GPIO OUTPUT REGISTER */
			*(UINT *)ucResetValue = (pgpio_multi_info[WIMAX_IDX].uiGPIOMask &
						pgpio_multi_info[WIMAX_IDX].uiGPIOCommand &
						(~(pgpio_multi_info[WIMAX_IDX].uiGPIOValue)));

			if (*(UINT *) ucResetValue)
				Status = wrmaltWithLock(Adapter, BCM_GPIO_OUTPUT_CLR_REG, (PUINT)ucResetValue, sizeof(ULONG));

			if (Status != STATUS_SUCCESS) {
				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "WRM to BCM_GPIO_OUTPUT_CLR_REG Failed.");
				return Status;
			}
		}

		if (pgpio_multi_info[WIMAX_IDX].uiGPIOMask) {
			bytes = rdmaltWithLock(Adapter, (UINT)GPIO_PIN_STATE_REGISTER, (PUINT)ucResetValue, sizeof(UINT));

			if (bytes < 0) {
				Status = bytes;
				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "RDM to GPIO_PIN_STATE_REGISTER Failed.");
				return Status;
			} else {
				Status = STATUS_SUCCESS;
			}

			pgpio_multi_info[WIMAX_IDX].uiGPIOValue = (*(UINT *)ucResetValue &
								pgpio_multi_info[WIMAX_IDX].uiGPIOMask);
		}

		Status = copy_to_user(IoBuffer.OutputBuffer, &gpio_multi_info, IoBuffer.OutputLength);
		if (Status) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
					"Failed while copying Content to IOBufer for user space err:%d", Status);
			return -EFAULT;
		}
	}
	break;

	case IOCTL_BCM_GPIO_MODE_REQUEST: {
		UCHAR ucResetValue[4];
		GPIO_MULTI_MODE gpio_multi_mode[MAX_IDX];
		PGPIO_MULTI_MODE pgpio_multi_mode = (PGPIO_MULTI_MODE)gpio_multi_mode;

		if ((Adapter->IdleMode == TRUE) ||
			(Adapter->bShutStatus == TRUE) ||
			(Adapter->bPreparingForLowPowerMode == TRUE))
			return -EINVAL;

		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
			return -EFAULT;

		if (IoBuffer.InputLength > sizeof(gpio_multi_mode))
			return -EINVAL;

		if (copy_from_user(&gpio_multi_mode, IoBuffer.InputBuffer, IoBuffer.InputLength))
			return -EFAULT;

		bytes = rdmaltWithLock(Adapter, (UINT)GPIO_MODE_REGISTER, (PUINT)ucResetValue, sizeof(UINT));

		if (bytes < 0) {
			Status = bytes;
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Read of GPIO_MODE_REGISTER failed");
			return Status;
		} else {
			Status = STATUS_SUCCESS;
		}

		/* Validating the request */
		if (IsReqGpioIsLedInNVM(Adapter, pgpio_multi_mode[WIMAX_IDX].uiGPIOMask) == FALSE) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
					"Sorry, Requested GPIO<0x%X> is not correspond to NVM LED bit map<0x%X>!!!",
					pgpio_multi_mode[WIMAX_IDX].uiGPIOMask, Adapter->gpioBitMap);
			Status = -EINVAL;
			break;
		}

		if (pgpio_multi_mode[WIMAX_IDX].uiGPIOMask) {
			/* write all OUT's (1's) */
			*(UINT *) ucResetValue |= (pgpio_multi_mode[WIMAX_IDX].uiGPIOMode &
						pgpio_multi_mode[WIMAX_IDX].uiGPIOMask);

			/* write all IN's (0's) */
			*(UINT *) ucResetValue &= ~((~pgpio_multi_mode[WIMAX_IDX].uiGPIOMode) &
						pgpio_multi_mode[WIMAX_IDX].uiGPIOMask);

			/* Currently implemented return the modes of all GPIO's
			 * else needs to bit AND with  mask
			 */
			pgpio_multi_mode[WIMAX_IDX].uiGPIOMode = *(UINT *)ucResetValue;

			Status = wrmaltWithLock(Adapter, GPIO_MODE_REGISTER, (PUINT)ucResetValue, sizeof(ULONG));
			if (Status == STATUS_SUCCESS) {
				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
						"WRM to GPIO_MODE_REGISTER Done");
			} else {
				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
						"WRM to GPIO_MODE_REGISTER Failed");
				Status = -EFAULT;
				break;
			}
		} else {
/* if uiGPIOMask is 0 then return mode register configuration */
			pgpio_multi_mode[WIMAX_IDX].uiGPIOMode = *(UINT *)ucResetValue;
		}

		Status = copy_to_user(IoBuffer.OutputBuffer, &gpio_multi_mode, IoBuffer.OutputLength);
		if (Status) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
					"Failed while copying Content to IOBufer for user space err:%d", Status);
			return -EFAULT;
		}
	}
	break;

	case IOCTL_MAC_ADDR_REQ:
	case IOCTL_LINK_REQ:
	case IOCTL_CM_REQUEST:
	case IOCTL_SS_INFO_REQ:
	case IOCTL_SEND_CONTROL_MESSAGE:
	case IOCTL_IDLE_REQ: {
		PVOID pvBuffer = NULL;

		/* Copy Ioctl Buffer structure */
		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
			return -EFAULT;

		if (IoBuffer.InputLength < sizeof(struct link_request))
			return -EINVAL;

		if (IoBuffer.InputLength > MAX_CNTL_PKT_SIZE)
			return -EINVAL;

		pvBuffer = kmalloc(IoBuffer.InputLength, GFP_KERNEL);
		if (!pvBuffer)
			return -ENOMEM;

		if (copy_from_user(pvBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength)) {
			kfree(pvBuffer);
			return -EFAULT;
		}

		down(&Adapter->LowPowerModeSync);
		Status = wait_event_interruptible_timeout(Adapter->lowpower_mode_wait_queue,
							!Adapter->bPreparingForLowPowerMode,
							(1 * HZ));
		if (Status == -ERESTARTSYS)
			goto cntrlEnd;

		if (Adapter->bPreparingForLowPowerMode) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
					"Preparing Idle Mode is still True - Hence Rejecting control message\n");
			Status = STATUS_FAILURE;
			goto cntrlEnd;
		}
		Status = CopyBufferToControlPacket(Adapter, (PVOID)pvBuffer);

cntrlEnd:
		up(&Adapter->LowPowerModeSync);
		kfree(pvBuffer);
		break;
	}

	case IOCTL_BCM_BUFFER_DOWNLOAD_START: {
		if (down_trylock(&Adapter->NVMRdmWrmLock)) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
					"IOCTL_BCM_CHIP_RESET not allowed as EEPROM Read/Write is in progress\n");
			return -EACCES;
		}

		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
				"Starting the firmware download PID =0x%x!!!!\n", current->pid);

		if (down_trylock(&Adapter->fw_download_sema))
			return -EBUSY;

		Adapter->bBinDownloaded = FALSE;
		Adapter->fw_download_process_pid = current->pid;
		Adapter->bCfgDownloaded = FALSE;
		Adapter->fw_download_done = FALSE;
		netif_carrier_off(Adapter->dev);
		netif_stop_queue(Adapter->dev);
		Status = reset_card_proc(Adapter);
		if (Status) {
			pr_err(PFX "%s: reset_card_proc Failed!\n", Adapter->dev->name);
			up(&Adapter->fw_download_sema);
			up(&Adapter->NVMRdmWrmLock);
			return Status;
		}
		mdelay(10);

		up(&Adapter->NVMRdmWrmLock);
		return Status;
	}

	case IOCTL_BCM_BUFFER_DOWNLOAD: {
		FIRMWARE_INFO *psFwInfo = NULL;
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Starting the firmware download PID =0x%x!!!!\n", current->pid);

		if (!down_trylock(&Adapter->fw_download_sema)) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
					"Invalid way to download buffer. Use Start and then call this!!!\n");
			up(&Adapter->fw_download_sema);
			Status = -EINVAL;
			return Status;
		}

		/* Copy Ioctl Buffer structure */
		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) {
			up(&Adapter->fw_download_sema);
			return -EFAULT;
		}

		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
				"Length for FW DLD is : %lx\n", IoBuffer.InputLength);

		if (IoBuffer.InputLength > sizeof(FIRMWARE_INFO)) {
			up(&Adapter->fw_download_sema);
			return -EINVAL;
		}

		psFwInfo = kmalloc(sizeof(*psFwInfo), GFP_KERNEL);
		if (!psFwInfo) {
			up(&Adapter->fw_download_sema);
			return -ENOMEM;
		}

		if (copy_from_user(psFwInfo, IoBuffer.InputBuffer, IoBuffer.InputLength)) {
			up(&Adapter->fw_download_sema);
			return -EFAULT;
		}

		if (!psFwInfo->pvMappedFirmwareAddress ||
			(psFwInfo->u32FirmwareLength == 0)) {

			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Something else is wrong %lu\n",
					psFwInfo->u32FirmwareLength);
			up(&Adapter->fw_download_sema);
			Status = -EINVAL;
			return Status;
		}

		Status = bcm_ioctl_fw_download(Adapter, psFwInfo);

		if (Status != STATUS_SUCCESS) {
			if (psFwInfo->u32StartingAddress == CONFIG_BEGIN_ADDR)
				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "IOCTL: Configuration File Upload Failed\n");
			else
				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,	"IOCTL: Firmware File Upload Failed\n");

			/* up(&Adapter->fw_download_sema); */

			if (Adapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) {
				Adapter->DriverState = DRIVER_INIT;
				Adapter->LEDInfo.bLedInitDone = FALSE;
				wake_up(&Adapter->LEDInfo.notify_led_event);
			}
		}

		if (Status != STATUS_SUCCESS)
			up(&Adapter->fw_download_sema);

		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, OSAL_DBG, DBG_LVL_ALL, "IOCTL: Firmware File Uploaded\n");
		kfree(psFwInfo);
		return Status;
	}

	case IOCTL_BCM_BUFFER_DOWNLOAD_STOP: {
		if (!down_trylock(&Adapter->fw_download_sema)) {
			up(&Adapter->fw_download_sema);
			return -EINVAL;
		}

		if (down_trylock(&Adapter->NVMRdmWrmLock)) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
					"FW download blocked as EEPROM Read/Write is in progress\n");
			up(&Adapter->fw_download_sema);
			return -EACCES;
		}

		Adapter->bBinDownloaded = TRUE;
		Adapter->bCfgDownloaded = TRUE;
		atomic_set(&Adapter->CurrNumFreeTxDesc, 0);
		Adapter->CurrNumRecvDescs = 0;
		Adapter->downloadDDR = 0;

		/* setting the Mips to Run */
		Status = run_card_proc(Adapter);

		if (Status) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Firm Download Failed\n");
			up(&Adapter->fw_download_sema);
			up(&Adapter->NVMRdmWrmLock);
			return Status;
		} else {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
					DBG_LVL_ALL, "Firm Download Over...\n");
		}

		mdelay(10);

		/* Wait for MailBox Interrupt */
		if (StartInterruptUrb((PS_INTERFACE_ADAPTER)Adapter->pvInterfaceAdapter))
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Unable to send interrupt...\n");

		timeout = 5*HZ;
		Adapter->waiting_to_fw_download_done = FALSE;
		wait_event_timeout(Adapter->ioctl_fw_dnld_wait_queue,
				Adapter->waiting_to_fw_download_done, timeout);
		Adapter->fw_download_process_pid = INVALID_PID;
		Adapter->fw_download_done = TRUE;
		atomic_set(&Adapter->CurrNumFreeTxDesc, 0);
		Adapter->CurrNumRecvDescs = 0;
		Adapter->PrevNumRecvDescs = 0;
		atomic_set(&Adapter->cntrlpktCnt, 0);
		Adapter->LinkUpStatus = 0;
		Adapter->LinkStatus = 0;

		if (Adapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) {
			Adapter->DriverState = FW_DOWNLOAD_DONE;
			wake_up(&Adapter->LEDInfo.notify_led_event);
		}

		if (!timeout)
			Status = -ENODEV;

		up(&Adapter->fw_download_sema);
		up(&Adapter->NVMRdmWrmLock);
		return Status;
	}

	case IOCTL_BE_BUCKET_SIZE:
		Status = 0;
		if (get_user(Adapter->BEBucketSize, (unsigned long __user *)arg))
			Status = -EFAULT;
		break;

	case IOCTL_RTPS_BUCKET_SIZE:
		Status = 0;
		if (get_user(Adapter->rtPSBucketSize, (unsigned long __user *)arg))
			Status = -EFAULT;
		break;

	case IOCTL_CHIP_RESET: {
		INT NVMAccess = down_trylock(&Adapter->NVMRdmWrmLock);
		if (NVMAccess) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, " IOCTL_BCM_CHIP_RESET not allowed as EEPROM Read/Write is in progress\n");
			return -EACCES;
		}

		down(&Adapter->RxAppControlQueuelock);
		Status = reset_card_proc(Adapter);
		flushAllAppQ();
		up(&Adapter->RxAppControlQueuelock);
		up(&Adapter->NVMRdmWrmLock);
		ResetCounters(Adapter);
		break;
	}

	case IOCTL_QOS_THRESHOLD: {
		USHORT uiLoopIndex;

		Status = 0;
		for (uiLoopIndex = 0; uiLoopIndex < NO_OF_QUEUES; uiLoopIndex++) {
			if (get_user(Adapter->PackInfo[uiLoopIndex].uiThreshold,
					(unsigned long __user *)arg)) {
				Status = -EFAULT;
				break;
			}
		}
		break;
	}

	case IOCTL_DUMP_PACKET_INFO:
		DumpPackInfo(Adapter);
		DumpPhsRules(&Adapter->stBCMPhsContext);
		Status = STATUS_SUCCESS;
		break;

	case IOCTL_GET_PACK_INFO:
		if (copy_to_user(argp, &Adapter->PackInfo, sizeof(PacketInfo)*NO_OF_QUEUES))
			return -EFAULT;
		Status = STATUS_SUCCESS;
		break;

	case IOCTL_BCM_SWITCH_TRANSFER_MODE: {
		UINT uiData = 0;
		if (copy_from_user(&uiData, argp, sizeof(UINT)))
			return -EFAULT;

		if (uiData) {
			/* Allow All Packets */
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_SWITCH_TRANSFER_MODE: ETH_PACKET_TUNNELING_MODE\n");
				Adapter->TransferMode = ETH_PACKET_TUNNELING_MODE;
		} else {
			/* Allow IP only Packets */
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_SWITCH_TRANSFER_MODE: IP_PACKET_ONLY_MODE\n");
			Adapter->TransferMode = IP_PACKET_ONLY_MODE;
		}
		Status = STATUS_SUCCESS;
		break;
	}

	case IOCTL_BCM_GET_DRIVER_VERSION: {
		ulong len;

		/* Copy Ioctl Buffer structure */
		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
			return -EFAULT;

		len = min_t(ulong, IoBuffer.OutputLength, strlen(VER_FILEVERSION_STR) + 1);

		if (copy_to_user(IoBuffer.OutputBuffer, VER_FILEVERSION_STR, len))
			return -EFAULT;
		Status = STATUS_SUCCESS;
		break;
	}

	case IOCTL_BCM_GET_CURRENT_STATUS: {
		LINK_STATE link_state;

		/* Copy Ioctl Buffer structure */
		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "copy_from_user failed..\n");
			return -EFAULT;
		}

		if (IoBuffer.OutputLength != sizeof(link_state)) {
			Status = -EINVAL;
			break;
		}

		memset(&link_state, 0, sizeof(link_state));
		link_state.bIdleMode = Adapter->IdleMode;
		link_state.bShutdownMode = Adapter->bShutStatus;
		link_state.ucLinkStatus = Adapter->LinkStatus;

		if (copy_to_user(IoBuffer.OutputBuffer, &link_state, min_t(size_t, sizeof(link_state), IoBuffer.OutputLength))) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy_to_user Failed..\n");
			return -EFAULT;
		}
		Status = STATUS_SUCCESS;
		break;
	}

	case IOCTL_BCM_SET_MAC_TRACING: {
		UINT  tracing_flag;

		/* copy ioctl Buffer structure */
		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
			return -EFAULT;

		if (copy_from_user(&tracing_flag, IoBuffer.InputBuffer, sizeof(UINT)))
			return -EFAULT;

		if (tracing_flag)
			Adapter->pTarangs->MacTracingEnabled = TRUE;
		else
			Adapter->pTarangs->MacTracingEnabled = FALSE;
		break;
	}

	case IOCTL_BCM_GET_DSX_INDICATION: {
		ULONG ulSFId = 0;
		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
			return -EFAULT;

		if (IoBuffer.OutputLength < sizeof(stLocalSFAddIndicationAlt)) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
					"Mismatch req: %lx needed is =0x%zx!!!",
					IoBuffer.OutputLength, sizeof(stLocalSFAddIndicationAlt));
			return -EINVAL;
		}

		if (copy_from_user(&ulSFId, IoBuffer.InputBuffer, sizeof(ulSFId)))
			return -EFAULT;

		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Get DSX Data SF ID is =%lx\n", ulSFId);
		get_dsx_sf_data_to_application(Adapter, ulSFId, IoBuffer.OutputBuffer);
		Status = STATUS_SUCCESS;
	}
	break;

	case IOCTL_BCM_GET_HOST_MIBS: {
		PVOID temp_buff;

		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
			return -EFAULT;

		if (IoBuffer.OutputLength != sizeof(S_MIBS_HOST_STATS_MIBS)) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
					"Length Check failed %lu %zd\n",
					IoBuffer.OutputLength, sizeof(S_MIBS_HOST_STATS_MIBS));
			return -EINVAL;
		}

		/* FIXME: HOST_STATS are too big for kmalloc (122048)! */
		temp_buff = kzalloc(sizeof(S_MIBS_HOST_STATS_MIBS), GFP_KERNEL);
		if (!temp_buff)
			return STATUS_FAILURE;

		Status = ProcessGetHostMibs(Adapter, temp_buff);
		GetDroppedAppCntrlPktMibs(temp_buff, pTarang);

		if (Status != STATUS_FAILURE)
			if (copy_to_user(IoBuffer.OutputBuffer, temp_buff, sizeof(S_MIBS_HOST_STATS_MIBS))) {
				kfree(temp_buff);
				return -EFAULT;
			}

		kfree(temp_buff);
		break;
	}

	case IOCTL_BCM_WAKE_UP_DEVICE_FROM_IDLE:
		if ((FALSE == Adapter->bTriedToWakeUpFromlowPowerMode) && (TRUE == Adapter->IdleMode)) {
			Adapter->usIdleModePattern = ABORT_IDLE_MODE;
			Adapter->bWakeUpDevice = TRUE;
			wake_up(&Adapter->process_rx_cntrlpkt);
		}

		Status = STATUS_SUCCESS;
		break;

	case IOCTL_BCM_BULK_WRM: {
		PBULKWRM_BUFFER pBulkBuffer;
		UINT uiTempVar = 0;
		PCHAR pvBuffer = NULL;

		if ((Adapter->IdleMode == TRUE) ||
			(Adapter->bShutStatus == TRUE) ||
			(Adapter->bPreparingForLowPowerMode == TRUE)) {

			BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "Device in Idle/Shutdown Mode, Blocking Wrms\n");
			Status = -EACCES;
			break;
		}

		/* Copy Ioctl Buffer structure */
		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
			return -EFAULT;

		if (IoBuffer.InputLength < sizeof(ULONG) * 2)
			return -EINVAL;

		pvBuffer = kmalloc(IoBuffer.InputLength, GFP_KERNEL);
		if (!pvBuffer)
			return -ENOMEM;

		/* Get WrmBuffer structure */
		if (copy_from_user(pvBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength)) {
			kfree(pvBuffer);
			return -EFAULT;
		}

		pBulkBuffer = (PBULKWRM_BUFFER)pvBuffer;

		if (((ULONG)pBulkBuffer->Register & 0x0F000000) != 0x0F000000 ||
			((ULONG)pBulkBuffer->Register & 0x3)) {
			kfree(pvBuffer);
			BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "WRM Done On invalid Address : %x Access Denied.\n", (int)pBulkBuffer->Register);
			Status = -EINVAL;
			break;
		}

		uiTempVar = pBulkBuffer->Register & EEPROM_REJECT_MASK;
		if (!((Adapter->pstargetparams->m_u32Customize)&VSG_MODE) &&
			((uiTempVar == EEPROM_REJECT_REG_1) ||
				(uiTempVar == EEPROM_REJECT_REG_2) ||
				(uiTempVar == EEPROM_REJECT_REG_3) ||
				(uiTempVar == EEPROM_REJECT_REG_4)) &&
			(cmd == IOCTL_BCM_REGISTER_WRITE)) {

			kfree(pvBuffer);
			BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "EEPROM Access Denied, not in VSG Mode\n");
			Status = -EFAULT;
			break;
		}

		if (pBulkBuffer->SwapEndian == FALSE)
			Status = wrmWithLock(Adapter, (UINT)pBulkBuffer->Register, (PCHAR)pBulkBuffer->Values, IoBuffer.InputLength - 2*sizeof(ULONG));
		else
			Status = wrmaltWithLock(Adapter, (UINT)pBulkBuffer->Register, (PUINT)pBulkBuffer->Values, IoBuffer.InputLength - 2*sizeof(ULONG));

		if (Status != STATUS_SUCCESS)
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "WRM Failed\n");

		kfree(pvBuffer);
		break;
	}

	case IOCTL_BCM_GET_NVM_SIZE:
		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
			return -EFAULT;

		if (Adapter->eNVMType == NVM_EEPROM || Adapter->eNVMType == NVM_FLASH) {
			if (copy_to_user(IoBuffer.OutputBuffer, &Adapter->uiNVMDSDSize, sizeof(UINT)))
				return -EFAULT;
		}

		Status = STATUS_SUCCESS;
		break;

	case IOCTL_BCM_CAL_INIT: {
		UINT uiSectorSize = 0 ;
		if (Adapter->eNVMType == NVM_FLASH) {
			if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
				return -EFAULT;

			if (copy_from_user(&uiSectorSize, IoBuffer.InputBuffer, sizeof(UINT)))
				return -EFAULT;

			if ((uiSectorSize < MIN_SECTOR_SIZE) || (uiSectorSize > MAX_SECTOR_SIZE)) {
				if (copy_to_user(IoBuffer.OutputBuffer, &Adapter->uiSectorSize,
							sizeof(UINT)))
					return -EFAULT;
			} else {
				if (IsFlash2x(Adapter)) {
					if (copy_to_user(IoBuffer.OutputBuffer,	&Adapter->uiSectorSize, sizeof(UINT)))
						return -EFAULT;
				} else {
					if ((TRUE == Adapter->bShutStatus) || (TRUE == Adapter->IdleMode)) {
						BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Device is in Idle/Shutdown Mode\n");
						return -EACCES;
					}

					Adapter->uiSectorSize = uiSectorSize;
					BcmUpdateSectorSize(Adapter, Adapter->uiSectorSize);
				}
			}
			Status = STATUS_SUCCESS;
		} else {
			Status = STATUS_FAILURE;
		}
	}
	break;

	case IOCTL_BCM_SET_DEBUG:
#ifdef DEBUG
	{
		USER_BCM_DBG_STATE sUserDebugState;

		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "In SET_DEBUG ioctl\n");
		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
			return -EFAULT;

		if (copy_from_user(&sUserDebugState, IoBuffer.InputBuffer, sizeof(USER_BCM_DBG_STATE)))
			return -EFAULT;

		BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "IOCTL_BCM_SET_DEBUG: OnOff=%d Type = 0x%x ",
				sUserDebugState.OnOff, sUserDebugState.Type);
		/* sUserDebugState.Subtype <<= 1; */
		sUserDebugState.Subtype = 1 << sUserDebugState.Subtype;
		BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "actual Subtype=0x%x\n", sUserDebugState.Subtype);

		/* Update new 'DebugState' in the Adapter */
		Adapter->stDebugState.type |= sUserDebugState.Type;
		/* Subtype: A bitmap of 32 bits for Subtype per Type.
		 * Valid indexes in 'subtype' array: 1,2,4,8
		 * corresponding to valid Type values. Hence we can use the 'Type' field
		 * as the index value, ignoring the array entries 0,3,5,6,7 !
		 */
		if (sUserDebugState.OnOff)
			Adapter->stDebugState.subtype[sUserDebugState.Type] |= sUserDebugState.Subtype;
		else
			Adapter->stDebugState.subtype[sUserDebugState.Type] &= ~sUserDebugState.Subtype;

		BCM_SHOW_DEBUG_BITMAP(Adapter);
	}
#endif
	break;

	case IOCTL_BCM_NVM_READ:
	case IOCTL_BCM_NVM_WRITE: {
		NVM_READWRITE  stNVMReadWrite;
		PUCHAR pReadData = NULL;
		ULONG ulDSDMagicNumInUsrBuff = 0;
		struct timeval tv0, tv1;
		memset(&tv0, 0, sizeof(struct timeval));
		memset(&tv1, 0, sizeof(struct timeval));
		if ((Adapter->eNVMType == NVM_FLASH) && (Adapter->uiFlashLayoutMajorVersion == 0)) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "The Flash Control Section is Corrupted. Hence Rejection on NVM Read/Write\n");
			return -EFAULT;
		}

		if (IsFlash2x(Adapter)) {
			if ((Adapter->eActiveDSD != DSD0) &&
				(Adapter->eActiveDSD != DSD1) &&
				(Adapter->eActiveDSD != DSD2)) {

				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "No DSD is active..hence NVM Command is blocked");
				return STATUS_FAILURE;
			}
		}

		/* Copy Ioctl Buffer structure */
		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
			return -EFAULT;

		if (copy_from_user(&stNVMReadWrite,
					(IOCTL_BCM_NVM_READ == cmd) ? IoBuffer.OutputBuffer : IoBuffer.InputBuffer,
					sizeof(NVM_READWRITE)))
			return -EFAULT;

		/*
		 * Deny the access if the offset crosses the cal area limit.
		 */

		if ((stNVMReadWrite.uiOffset + stNVMReadWrite.uiNumBytes) > Adapter->uiNVMDSDSize) {
			/* BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Can't allow access beyond NVM Size: 0x%x 0x%x\n", stNVMReadWrite.uiOffset, stNVMReadWrite.uiNumBytes); */
			return STATUS_FAILURE;
		}

		pReadData = kzalloc(stNVMReadWrite.uiNumBytes, GFP_KERNEL);
		if (!pReadData)
			return -ENOMEM;

		if (copy_from_user(pReadData, stNVMReadWrite.pBuffer, stNVMReadWrite.uiNumBytes)) {
			kfree(pReadData);
			return -EFAULT;
		}

		do_gettimeofday(&tv0);
		if (IOCTL_BCM_NVM_READ == cmd) {
			down(&Adapter->NVMRdmWrmLock);

			if ((Adapter->IdleMode == TRUE) ||
				(Adapter->bShutStatus == TRUE) ||
				(Adapter->bPreparingForLowPowerMode == TRUE)) {

				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n");
				up(&Adapter->NVMRdmWrmLock);
				kfree(pReadData);
				return -EACCES;
			}

			Status = BeceemNVMRead(Adapter, (PUINT)pReadData, stNVMReadWrite.uiOffset, stNVMReadWrite.uiNumBytes);
			up(&Adapter->NVMRdmWrmLock);

			if (Status != STATUS_SUCCESS) {
				kfree(pReadData);
				return Status;
			}

			if (copy_to_user(stNVMReadWrite.pBuffer, pReadData, stNVMReadWrite.uiNumBytes)) {
				kfree(pReadData);
				return -EFAULT;
			}
		} else {
			down(&Adapter->NVMRdmWrmLock);

			if ((Adapter->IdleMode == TRUE) ||
				(Adapter->bShutStatus == TRUE) ||
				(Adapter->bPreparingForLowPowerMode == TRUE)) {

				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n");
				up(&Adapter->NVMRdmWrmLock);
				kfree(pReadData);
				return -EACCES;
			}

			Adapter->bHeaderChangeAllowed = TRUE;
			if (IsFlash2x(Adapter)) {
				/*
				 *			New Requirement:-
				 *			DSD section updation will be allowed in two case:-
				 *			1.  if DSD sig is present in DSD header means dongle is ok and updation is fruitfull
				 *			2.  if point 1 failes then user buff should have DSD sig. this point ensures that if dongle is
				 *			      corrupted then user space program first modify the DSD header with valid DSD sig so
				 *			      that this as well as further write may be worthwhile.
				 *
				 *			 This restriction has been put assuming that if DSD sig is corrupted, DSD
				 *			 data won't be considered valid.
				 */

				Status = BcmFlash2xCorruptSig(Adapter, Adapter->eActiveDSD);
				if (Status != STATUS_SUCCESS) {
					if (((stNVMReadWrite.uiOffset + stNVMReadWrite.uiNumBytes) != Adapter->uiNVMDSDSize) ||
						(stNVMReadWrite.uiNumBytes < SIGNATURE_SIZE)) {

						BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "DSD Sig is present neither in Flash nor User provided Input..");
						up(&Adapter->NVMRdmWrmLock);
						kfree(pReadData);
						return Status;
					}

					ulDSDMagicNumInUsrBuff = ntohl(*(PUINT)(pReadData + stNVMReadWrite.uiNumBytes - SIGNATURE_SIZE));
					if (ulDSDMagicNumInUsrBuff != DSD_IMAGE_MAGIC_NUMBER) {
						BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "DSD Sig is present neither in Flash nor User provided Input..");
						up(&Adapter->NVMRdmWrmLock);
						kfree(pReadData);
						return Status;
					}
				}
			}

			Status = BeceemNVMWrite(Adapter, (PUINT)pReadData, stNVMReadWrite.uiOffset, stNVMReadWrite.uiNumBytes, stNVMReadWrite.bVerify);
			if (IsFlash2x(Adapter))
				BcmFlash2xWriteSig(Adapter, Adapter->eActiveDSD);

			Adapter->bHeaderChangeAllowed = FALSE;

			up(&Adapter->NVMRdmWrmLock);

			if (Status != STATUS_SUCCESS) {
				kfree(pReadData);
				return Status;
			}
		}

		do_gettimeofday(&tv1);
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, " timetaken by Write/read :%ld msec\n", (tv1.tv_sec - tv0.tv_sec)*1000 + (tv1.tv_usec - tv0.tv_usec)/1000);

		kfree(pReadData);
		return STATUS_SUCCESS;
	}

	case IOCTL_BCM_FLASH2X_SECTION_READ: {
		FLASH2X_READWRITE sFlash2xRead = {0};
		PUCHAR pReadBuff = NULL ;
		UINT NOB = 0;
		UINT BuffSize = 0;
		UINT ReadBytes = 0;
		UINT ReadOffset = 0;
		void __user *OutPutBuff;

		if (IsFlash2x(Adapter) != TRUE)	{
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Does not have 2.x map");
			return -EINVAL;
		}

		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_FLASH2X_SECTION_READ Called");
		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
			return -EFAULT;

		/* Reading FLASH 2.x READ structure */
		if (copy_from_user(&sFlash2xRead, IoBuffer.InputBuffer, sizeof(FLASH2X_READWRITE)))
			return -EFAULT;

		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\nsFlash2xRead.Section :%x", sFlash2xRead.Section);
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\nsFlash2xRead.offset :%x", sFlash2xRead.offset);
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\nsFlash2xRead.numOfBytes :%x", sFlash2xRead.numOfBytes);
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\nsFlash2xRead.bVerify :%x\n", sFlash2xRead.bVerify);

		/* This was internal to driver for raw read. now it has ben exposed to user space app. */
		if (validateFlash2xReadWrite(Adapter, &sFlash2xRead) == FALSE)
			return STATUS_FAILURE;

		NOB = sFlash2xRead.numOfBytes;
		if (NOB > Adapter->uiSectorSize)
			BuffSize = Adapter->uiSectorSize;
		else
			BuffSize = NOB;

		ReadOffset = sFlash2xRead.offset ;
		OutPutBuff = IoBuffer.OutputBuffer;
		pReadBuff = (PCHAR)kzalloc(BuffSize , GFP_KERNEL);

		if (pReadBuff == NULL) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Memory allocation failed for Flash 2.x Read Structure");
			return -ENOMEM;
		}
		down(&Adapter->NVMRdmWrmLock);

		if ((Adapter->IdleMode == TRUE) ||
			(Adapter->bShutStatus == TRUE) ||
			(Adapter->bPreparingForLowPowerMode == TRUE)) {

			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n");
			up(&Adapter->NVMRdmWrmLock);
			kfree(pReadBuff);
			return -EACCES;
		}

		while (NOB) {
			if (NOB > Adapter->uiSectorSize)
				ReadBytes = Adapter->uiSectorSize;
			else
				ReadBytes = NOB;

			/* Reading the data from Flash 2.x */
			Status = BcmFlash2xBulkRead(Adapter, (PUINT)pReadBuff, sFlash2xRead.Section, ReadOffset, ReadBytes);
			if (Status) {
				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Flash 2x read err with Status :%d", Status);
				break;
			}

			BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, pReadBuff, ReadBytes);

			Status = copy_to_user(OutPutBuff, pReadBuff, ReadBytes);
			if (Status) {
				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Copy to use failed with status :%d", Status);
				up(&Adapter->NVMRdmWrmLock);
				kfree(pReadBuff);
				return -EFAULT;
			}
			NOB = NOB - ReadBytes;
			if (NOB) {
				ReadOffset = ReadOffset + ReadBytes;
				OutPutBuff = OutPutBuff + ReadBytes ;
			}
		}

		up(&Adapter->NVMRdmWrmLock);
		kfree(pReadBuff);
	}
	break;

	case IOCTL_BCM_FLASH2X_SECTION_WRITE: {
		FLASH2X_READWRITE sFlash2xWrite = {0};
		PUCHAR pWriteBuff;
		void __user *InputAddr;
		UINT NOB = 0;
		UINT BuffSize = 0;
		UINT WriteOffset = 0;
		UINT WriteBytes = 0;

		if (IsFlash2x(Adapter) != TRUE) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Does not have 2.x map");
			return -EINVAL;
		}

		/* First make this False so that we can enable the Sector Permission Check in BeceemFlashBulkWrite */
		Adapter->bAllDSDWriteAllow = FALSE;

		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_FLASH2X_SECTION_WRITE Called");

		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
			return -EFAULT;

		/* Reading FLASH 2.x READ structure */
		if (copy_from_user(&sFlash2xWrite, IoBuffer.InputBuffer, sizeof(FLASH2X_READWRITE)))
			return -EFAULT;

		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\nsFlash2xRead.Section :%x", sFlash2xWrite.Section);
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\nsFlash2xRead.offset :%d", sFlash2xWrite.offset);
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\nsFlash2xRead.numOfBytes :%x", sFlash2xWrite.numOfBytes);
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\nsFlash2xRead.bVerify :%x\n", sFlash2xWrite.bVerify);

		if ((sFlash2xWrite.Section != VSA0) && (sFlash2xWrite.Section != VSA1) && (sFlash2xWrite.Section != VSA2)) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Only VSA write is allowed");
			return -EINVAL;
		}

		if (validateFlash2xReadWrite(Adapter, &sFlash2xWrite) == FALSE)
			return STATUS_FAILURE;

		InputAddr = sFlash2xWrite.pDataBuff;
		WriteOffset = sFlash2xWrite.offset;
		NOB = sFlash2xWrite.numOfBytes;

		if (NOB > Adapter->uiSectorSize)
			BuffSize = Adapter->uiSectorSize;
		else
			BuffSize = NOB ;

		pWriteBuff = kmalloc(BuffSize, GFP_KERNEL);

		if (pWriteBuff == NULL)
			return -ENOMEM;

		/* extracting the remainder of the given offset. */
		WriteBytes = Adapter->uiSectorSize;
		if (WriteOffset % Adapter->uiSectorSize)
			WriteBytes = Adapter->uiSectorSize - (WriteOffset % Adapter->uiSectorSize);

		if (NOB < WriteBytes)
			WriteBytes = NOB;

		down(&Adapter->NVMRdmWrmLock);

		if ((Adapter->IdleMode == TRUE) ||
			(Adapter->bShutStatus == TRUE) ||
			(Adapter->bPreparingForLowPowerMode == TRUE)) {

			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n");
			up(&Adapter->NVMRdmWrmLock);
			kfree(pWriteBuff);
			return -EACCES;
		}

		BcmFlash2xCorruptSig(Adapter, sFlash2xWrite.Section);
		do {
			Status = copy_from_user(pWriteBuff, InputAddr, WriteBytes);
			if (Status) {
				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy to user failed with status :%d", Status);
				up(&Adapter->NVMRdmWrmLock);
				kfree(pWriteBuff);
				return -EFAULT;
			}
			BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, pWriteBuff, WriteBytes);

			/* Writing the data from Flash 2.x */
			Status = BcmFlash2xBulkWrite(Adapter, (PUINT)pWriteBuff, sFlash2xWrite.Section, WriteOffset, WriteBytes, sFlash2xWrite.bVerify);

			if (Status) {
				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash 2x read err with Status :%d", Status);
				break;
			}

			NOB = NOB - WriteBytes;
			if (NOB) {
				WriteOffset = WriteOffset + WriteBytes;
				InputAddr = InputAddr + WriteBytes;
				if (NOB > Adapter->uiSectorSize)
					WriteBytes = Adapter->uiSectorSize;
				else
					WriteBytes = NOB;
			}
		} while (NOB > 0);

		BcmFlash2xWriteSig(Adapter, sFlash2xWrite.Section);
		up(&Adapter->NVMRdmWrmLock);
		kfree(pWriteBuff);
	}
	break;

	case IOCTL_BCM_GET_FLASH2X_SECTION_BITMAP: {
		PFLASH2X_BITMAP psFlash2xBitMap;
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_GET_FLASH2X_SECTION_BITMAP Called");

		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
			return -EFAULT;

		if (IoBuffer.OutputLength != sizeof(FLASH2X_BITMAP))
			return -EINVAL;

		psFlash2xBitMap = kzalloc(sizeof(FLASH2X_BITMAP), GFP_KERNEL);
		if (psFlash2xBitMap == NULL) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Memory is not available");
			return -ENOMEM;
		}

		/* Reading the Flash Sectio Bit map */
		down(&Adapter->NVMRdmWrmLock);

		if ((Adapter->IdleMode == TRUE) ||
			(Adapter->bShutStatus == TRUE) ||
			(Adapter->bPreparingForLowPowerMode == TRUE)) {

			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n");
			up(&Adapter->NVMRdmWrmLock);
			kfree(psFlash2xBitMap);
			return -EACCES;
		}

		BcmGetFlash2xSectionalBitMap(Adapter, psFlash2xBitMap);
		up(&Adapter->NVMRdmWrmLock);
		if (copy_to_user(IoBuffer.OutputBuffer, psFlash2xBitMap, sizeof(FLASH2X_BITMAP))) {
			kfree(psFlash2xBitMap);
			return -EFAULT;
		}

		kfree(psFlash2xBitMap);
	}
	break;

	case IOCTL_BCM_SET_ACTIVE_SECTION: {
		FLASH2X_SECTION_VAL eFlash2xSectionVal = 0;
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_SET_ACTIVE_SECTION Called");

		if (IsFlash2x(Adapter) != TRUE) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Does not have 2.x map");
			return -EINVAL;
		}

		Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER));
		if (Status) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed");
			return -EFAULT;
		}

		Status = copy_from_user(&eFlash2xSectionVal, IoBuffer.InputBuffer, sizeof(INT));
		if (Status) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of flash section val failed");
			return -EFAULT;
		}

		down(&Adapter->NVMRdmWrmLock);

		if ((Adapter->IdleMode == TRUE) ||
			(Adapter->bShutStatus == TRUE) ||
			(Adapter->bPreparingForLowPowerMode == TRUE)) {

			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n");
			up(&Adapter->NVMRdmWrmLock);
			return -EACCES;
		}

		Status = BcmSetActiveSection(Adapter, eFlash2xSectionVal);
		if (Status)
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Failed to make it's priority Highest. Status %d", Status);

		up(&Adapter->NVMRdmWrmLock);
	}
	break;

	case IOCTL_BCM_IDENTIFY_ACTIVE_SECTION: {
		/* Right Now we are taking care of only DSD */
		Adapter->bAllDSDWriteAllow = FALSE;
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_IDENTIFY_ACTIVE_SECTION called");
		Status = STATUS_SUCCESS;
	}
	break;

	case IOCTL_BCM_COPY_SECTION: {
		FLASH2X_COPY_SECTION sCopySectStrut = {0};
		Status = STATUS_SUCCESS;
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_COPY_SECTION  Called");

		Adapter->bAllDSDWriteAllow = FALSE;
		if (IsFlash2x(Adapter) != TRUE) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Does not have 2.x map");
			return -EINVAL;
		}

		Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER));
		if (Status) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed Status :%d", Status);
			return -EFAULT;
		}

		Status = copy_from_user(&sCopySectStrut, IoBuffer.InputBuffer, sizeof(FLASH2X_COPY_SECTION));
		if (Status) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of Copy_Section_Struct failed with Status :%d", Status);
			return -EFAULT;
		}

		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Source SEction :%x", sCopySectStrut.SrcSection);
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Destination SEction :%x", sCopySectStrut.DstSection);
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "offset :%x", sCopySectStrut.offset);
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "NOB :%x", sCopySectStrut.numOfBytes);

		if (IsSectionExistInFlash(Adapter, sCopySectStrut.SrcSection) == FALSE) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Source Section<%x> does not exixt in Flash ", sCopySectStrut.SrcSection);
			return -EINVAL;
		}

		if (IsSectionExistInFlash(Adapter, sCopySectStrut.DstSection) == FALSE) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Destinatio Section<%x> does not exixt in Flash ", sCopySectStrut.DstSection);
			return -EINVAL;
		}

		if (sCopySectStrut.SrcSection == sCopySectStrut.DstSection) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Source and Destination section should be different");
			return -EINVAL;
		}

		down(&Adapter->NVMRdmWrmLock);

		if ((Adapter->IdleMode == TRUE) ||
			(Adapter->bShutStatus == TRUE) ||
			(Adapter->bPreparingForLowPowerMode == TRUE)) {

			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n");
			up(&Adapter->NVMRdmWrmLock);
			return -EACCES;
		}

		if (sCopySectStrut.SrcSection == ISO_IMAGE1 || sCopySectStrut.SrcSection == ISO_IMAGE2) {
			if (IsNonCDLessDevice(Adapter)) {
				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Device is Non-CDLess hence won't have ISO !!");
				Status = -EINVAL;
			} else if (sCopySectStrut.numOfBytes == 0) {
				Status = BcmCopyISO(Adapter, sCopySectStrut);
			} else {
				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Partial Copy of ISO section is not Allowed..");
				Status = STATUS_FAILURE;
			}
			up(&Adapter->NVMRdmWrmLock);
			return Status;
		}

		Status = BcmCopySection(Adapter, sCopySectStrut.SrcSection,
					sCopySectStrut.DstSection, sCopySectStrut.offset, sCopySectStrut.numOfBytes);
		up(&Adapter->NVMRdmWrmLock);
	}
	break;

	case IOCTL_BCM_GET_FLASH_CS_INFO: {
		Status = STATUS_SUCCESS;
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, " IOCTL_BCM_GET_FLASH_CS_INFO Called");

		Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER));
		if (Status) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed");
			return -EFAULT;
		}

		if (Adapter->eNVMType != NVM_FLASH) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Connected device does not have flash");
			Status = -EINVAL;
			break;
		}

		if (IsFlash2x(Adapter) == TRUE) {
			if (IoBuffer.OutputLength < sizeof(FLASH2X_CS_INFO))
				return -EINVAL;

			if (copy_to_user(IoBuffer.OutputBuffer, Adapter->psFlash2xCSInfo, sizeof(FLASH2X_CS_INFO)))
				return -EFAULT;
		} else {
			if (IoBuffer.OutputLength < sizeof(FLASH_CS_INFO))
				return -EINVAL;

			if (copy_to_user(IoBuffer.OutputBuffer, Adapter->psFlashCSInfo, sizeof(FLASH_CS_INFO)))
				return -EFAULT;
		}
	}
	break;

	case IOCTL_BCM_SELECT_DSD: {
		UINT SectOfset = 0;
		FLASH2X_SECTION_VAL eFlash2xSectionVal;
		eFlash2xSectionVal = NO_SECTION_VAL;
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_SELECT_DSD Called");

		if (IsFlash2x(Adapter) != TRUE) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Does not have 2.x map");
			return -EINVAL;
		}

		Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER));
		if (Status) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed");
			return -EFAULT;
		}
		Status = copy_from_user(&eFlash2xSectionVal, IoBuffer.InputBuffer, sizeof(INT));
		if (Status) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of flash section val failed");
			return -EFAULT;
		}

		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Read Section :%d", eFlash2xSectionVal);
		if ((eFlash2xSectionVal != DSD0) &&
			(eFlash2xSectionVal != DSD1) &&
			(eFlash2xSectionVal != DSD2)) {

			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Passed section<%x> is not DSD section", eFlash2xSectionVal);
			return STATUS_FAILURE;
		}

		SectOfset = BcmGetSectionValStartOffset(Adapter, eFlash2xSectionVal);
		if (SectOfset == INVALID_OFFSET) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Provided Section val <%d> does not exixt in Flash 2.x", eFlash2xSectionVal);
			return -EINVAL;
		}

		Adapter->bAllDSDWriteAllow = TRUE;
		Adapter->ulFlashCalStart = SectOfset;
		Adapter->eActiveDSD = eFlash2xSectionVal;
	}
	Status = STATUS_SUCCESS;
	break;

	case IOCTL_BCM_NVM_RAW_READ: {
		NVM_READWRITE stNVMRead;
		INT NOB ;
		INT BuffSize ;
		INT ReadOffset = 0;
		UINT ReadBytes = 0 ;
		PUCHAR pReadBuff;
		void __user *OutPutBuff;

		if (Adapter->eNVMType != NVM_FLASH) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "NVM TYPE is not Flash");
			return -EINVAL;
		}

		/* Copy Ioctl Buffer structure */
		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "copy_from_user 1 failed\n");
			return -EFAULT;
		}

		if (copy_from_user(&stNVMRead, IoBuffer.OutputBuffer, sizeof(NVM_READWRITE)))
			return -EFAULT;

		NOB = stNVMRead.uiNumBytes;
		/* In Raw-Read max Buff size : 64MB */

		if (NOB > DEFAULT_BUFF_SIZE)
			BuffSize = DEFAULT_BUFF_SIZE;
		else
			BuffSize = NOB;

		ReadOffset = stNVMRead.uiOffset;
		OutPutBuff = stNVMRead.pBuffer;

		pReadBuff = kzalloc(BuffSize , GFP_KERNEL);
		if (pReadBuff == NULL) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Memory allocation failed for Flash 2.x Read Structure");
			Status = -ENOMEM;
			break;
		}
		down(&Adapter->NVMRdmWrmLock);

		if ((Adapter->IdleMode == TRUE) ||
			(Adapter->bShutStatus == TRUE) ||
			(Adapter->bPreparingForLowPowerMode == TRUE)) {

			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n");
			kfree(pReadBuff);
			up(&Adapter->NVMRdmWrmLock);
			return -EACCES;
		}

		Adapter->bFlashRawRead = TRUE;

		while (NOB) {
			if (NOB > DEFAULT_BUFF_SIZE)
				ReadBytes = DEFAULT_BUFF_SIZE;
			else
				ReadBytes = NOB;

			/* Reading the data from Flash 2.x */
			Status = BeceemNVMRead(Adapter, (PUINT)pReadBuff, ReadOffset, ReadBytes);
			if (Status) {
				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash 2x read err with Status :%d", Status);
				break;
			}

			BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, pReadBuff, ReadBytes);

			Status = copy_to_user(OutPutBuff, pReadBuff, ReadBytes);
			if (Status) {
				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy to use failed with status :%d", Status);
				up(&Adapter->NVMRdmWrmLock);
				kfree(pReadBuff);
				return -EFAULT;
			}
			NOB = NOB - ReadBytes;
			if (NOB) {
				ReadOffset = ReadOffset + ReadBytes;
				OutPutBuff = OutPutBuff + ReadBytes;
			}
		}
		Adapter->bFlashRawRead = FALSE;
		up(&Adapter->NVMRdmWrmLock);
		kfree(pReadBuff);
		break;
	}

	case IOCTL_BCM_CNTRLMSG_MASK: {
		ULONG RxCntrlMsgBitMask = 0;

		/* Copy Ioctl Buffer structure */
		Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER));
		if (Status) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "copy of Ioctl buffer is failed from user space");
			return -EFAULT;
		}

		if (IoBuffer.InputLength != sizeof(unsigned long)) {
			Status = -EINVAL;
			break;
		}

		Status = copy_from_user(&RxCntrlMsgBitMask, IoBuffer.InputBuffer, IoBuffer.InputLength);
		if (Status) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "copy of control bit mask failed from user space");
			return -EFAULT;
		}
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\n Got user defined cntrl msg bit mask :%lx", RxCntrlMsgBitMask);
		pTarang->RxCntrlMsgBitMask = RxCntrlMsgBitMask;
	}
	break;

	case IOCTL_BCM_GET_DEVICE_DRIVER_INFO: {
		DEVICE_DRIVER_INFO DevInfo;

		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Called IOCTL_BCM_GET_DEVICE_DRIVER_INFO\n");

		DevInfo.MaxRDMBufferSize = BUFFER_4K;
		DevInfo.u32DSDStartOffset = EEPROM_CALPARAM_START;
		DevInfo.u32RxAlignmentCorrection = 0;
		DevInfo.u32NVMType = Adapter->eNVMType;
		DevInfo.u32InterfaceType = BCM_USB;

		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
			return -EFAULT;

		if (IoBuffer.OutputLength < sizeof(DevInfo))
			return -EINVAL;

		if (copy_to_user(IoBuffer.OutputBuffer, &DevInfo, sizeof(DevInfo)))
			return -EFAULT;
	}
	break;

	case IOCTL_BCM_TIME_SINCE_NET_ENTRY: {
		ST_TIME_ELAPSED stTimeElapsedSinceNetEntry = {0};

		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_TIME_SINCE_NET_ENTRY called");

		if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
			return -EFAULT;

		if (IoBuffer.OutputLength < sizeof(ST_TIME_ELAPSED))
			return -EINVAL;

		stTimeElapsedSinceNetEntry.ul64TimeElapsedSinceNetEntry = get_seconds() - Adapter->liTimeSinceLastNetEntry;

		if (copy_to_user(IoBuffer.OutputBuffer, &stTimeElapsedSinceNetEntry, sizeof(ST_TIME_ELAPSED)))
			return -EFAULT;
	}
	break;

	case IOCTL_CLOSE_NOTIFICATION:
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_CLOSE_NOTIFICATION");
		break;

	default:
		pr_info(DRV_NAME ": unknown ioctl cmd=%#x\n", cmd);
		Status = STATUS_FAILURE;
		break;
	}
	return Status;
}


static const struct file_operations bcm_fops = {
	.owner    = THIS_MODULE,
	.open     = bcm_char_open,
	.release  = bcm_char_release,
	.read     = bcm_char_read,
	.unlocked_ioctl    = bcm_char_ioctl,
	.llseek = no_llseek,
};

int register_control_device_interface(PMINI_ADAPTER Adapter)
{

	if (Adapter->major > 0)
		return Adapter->major;

	Adapter->major = register_chrdev(0, DEV_NAME, &bcm_fops);
	if (Adapter->major < 0) {
		pr_err(DRV_NAME ": could not created character device\n");
		return Adapter->major;
	}

	Adapter->pstCreatedClassDevice = device_create(bcm_class, NULL,
						MKDEV(Adapter->major, 0),
						Adapter, DEV_NAME);

	if (IS_ERR(Adapter->pstCreatedClassDevice)) {
		pr_err(DRV_NAME ": class device create failed\n");
		unregister_chrdev(Adapter->major, DEV_NAME);
		return PTR_ERR(Adapter->pstCreatedClassDevice);
	}

	return 0;
}

void unregister_control_device_interface(PMINI_ADAPTER Adapter)
{
	if (Adapter->major > 0) {
		device_destroy(bcm_class, MKDEV(Adapter->major, 0));
		unregister_chrdev(Adapter->major, DEV_NAME);
	}
}