/* * <:copyright-BRCM:2016:DUAL/GPL:standard * * Copyright (c) 2016 Broadcom * All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2, as published by * the Free Software Foundation (the "GPL"). * * 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. * * * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php, or by * writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * :> */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(CONFIG_BCM_6802_MoCA) #include "./moca/board_moca.h" #include "./bbsi/bbsi.h" #else #include #endif #include #if defined(CONFIG_BCM_FTTDP) #include #endif #include "bcm_otp.h" #include "board_ioctl.h" #include "board_util.h" #include "board_image.h" #include "board_dg.h" #include "board_wl.h" #include "board_wd.h" #if defined(HAVE_UNLOCKED_IOCTL) static DEFINE_MUTEX(ioctlMutex); #endif #if defined(HAVE_UNLOCKED_IOCTL) long board_unlocked_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { struct inode *inode; long rt; #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0) inode = filep->f_dentry->d_inode; #else inode = file_inode(filep); #endif mutex_lock(&ioctlMutex); rt = board_ioctl( inode, filep, cmd, arg ); mutex_unlock(&ioctlMutex); return rt; } #endif //******************************************************************************************** // misc. ioctl calls come to here. (flash, led, reset, kernel memory access, etc.) //******************************************************************************************** int board_ioctl( struct inode *inode, struct file *flip, unsigned int command, unsigned long arg ) { int ret = 0; BOARD_IOCTL_PARMS ctrlParms; unsigned char ucaMacAddr[NVRAM_MAC_ADDRESS_LEN]; char *param=NULL, *value=NULL; switch (command) { #if defined(CONFIG_BCM_FTTDP) case BOARD_IOCTL_FTTDP_DSP_BOOTER: download_dsp_booter(); break; #endif case BOARD_IOCTL_FLASH_WRITE: if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { switch (ctrlParms.action) { case SCRATCH_PAD: if (ctrlParms.offset == -1) ret = kerSysScratchPadClearAll(); else ret = kerSysScratchPadSet(ctrlParms.string, ctrlParms.buf, ctrlParms.offset); break; case PERSISTENT: ret = kerSysPersistentSet(ctrlParms.string, ctrlParms.strLen, ctrlParms.offset); break; case BACKUP_PSI: ret = kerSysBackupPsiSet(ctrlParms.string, ctrlParms.strLen, ctrlParms.offset); break; case SYSLOG: ret = kerSysSyslogSet(ctrlParms.string, ctrlParms.strLen, ctrlParms.offset); break; case NVRAM: { ret = setUserNvRam(ctrlParms.string, ctrlParms.strLen, ctrlParms.offset); break; } case ENVRAM: { param = (unsigned char *)kmalloc(strlen(ctrlParms.param)+1, GFP_KERNEL); if (param == NULL) { ret = -EFAULT; break; } memset(param, '\0', strlen(ctrlParms.param)+1); value = (unsigned char *)kmalloc(ctrlParms.value_length+1, GFP_KERNEL); if (value == NULL) { kfree(param); ret = -EFAULT; break; } memset(value, '\0', ctrlParms.value_length+1); ret = -EFAULT; if(copy_from_user(param, ctrlParms.param, strlen(ctrlParms.param)) == 0) { if(copy_from_user(value, ctrlParms.value, ctrlParms.value_length) == 0) { ret=-1; if(envram_sync_set_locked(param, value) > 0) { ret=0; } } } kfree(param); kfree(value); break; } case BCM_IMAGE_CFE: { unsigned int not_used; if(kerSysBlParmsGetInt(NAND_RFS_OFS_NAME, (int *)¬_used)==0) { printk("\nERROR: Image does not support a NAND flash device.\n\n"); ret = -1; break; } if( ctrlParms.strLen <= 0 || ctrlParms.strLen > FLASH_LENGTH_BOOT_ROM ) { printk("Illegal CFE size [%d]. Size allowed: [%d]\n", ctrlParms.strLen, FLASH_LENGTH_BOOT_ROM); ret = -1; break; } ret = commonImageWrite(ctrlParms.offset + BOOT_OFFSET + IMAGE_OFFSET, ctrlParms.string, ctrlParms.strLen, NULL, 0); } break; case BCM_IMAGE_FS: { int numPartitions = 1; int noReboot = FLASH_IS_NO_REBOOT(ctrlParms.offset); int partition = FLASH_GET_PARTITION(ctrlParms.offset); unsigned int not_used; #if defined(CONFIG_BCM_WATCHDOG_TIMER) int resumeWD; #endif if(kerSysBlParmsGetInt(NAND_RFS_OFS_NAME, (int *)¬_used)==0) { printk("\nERROR: Image does not support a NAND flash device.\n\n"); ret = -1; break; } #if defined(CONFIG_BCM_WATCHDOG_TIMER) resumeWD = bcm_suspend_watchdog(); #endif ret = flashFsKernelImage(ctrlParms.string, ctrlParms.strLen, partition, &numPartitions); #if defined(CONFIG_BCM_WATCHDOG_TIMER) if (resumeWD) bcm_resume_watchdog(); #endif if(ret == 0 && (numPartitions == 1 || noReboot == 0)) resetPwrmgmtDdrMips(); } break; case BCM_IMAGE_KERNEL: // not used for now. break; case BCM_IMAGE_WHOLE: { int noReboot = FLASH_IS_NO_REBOOT(ctrlParms.offset); int partition = FLASH_GET_PARTITION(ctrlParms.offset); #if defined(CONFIG_BCM_WATCHDOG_TIMER) int resumeWD; #endif if(ctrlParms.strLen <= 0) { printk("Illegal flash image size [%d].\n", ctrlParms.strLen); ret = -1; break; } #if defined(CONFIG_BCM_WATCHDOG_TIMER) resumeWD = bcm_suspend_watchdog(); #endif ret = commonImageWrite(FLASH_BASE, ctrlParms.string, ctrlParms.strLen, &noReboot, partition ); #if defined(CONFIG_BCM_WATCHDOG_TIMER) if (resumeWD) bcm_resume_watchdog(); #endif if(ret == 0 && noReboot == 0) { resetPwrmgmtDdrMips(); } else { if (ret != 0) printk("flash of whole image failed, ret=%d\n", ret); } } break; default: ret = -EINVAL; printk("flash_ioctl_command: invalid command %d\n", ctrlParms.action); break; } ctrlParms.result = ret; __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); } else ret = -EFAULT; break; case BOARD_IOCTL_FLASH_READ: if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { switch (ctrlParms.action) { case SCRATCH_PAD: ret = kerSysScratchPadGet(ctrlParms.string, ctrlParms.buf, ctrlParms.offset); break; case PERSISTENT: ret = kerSysPersistentGet(ctrlParms.string, ctrlParms.strLen, ctrlParms.offset); break; case BACKUP_PSI: ret = kerSysBackupPsiGet(ctrlParms.string, ctrlParms.strLen, ctrlParms.offset); break; case SYSLOG: ret = kerSysSyslogGet(ctrlParms.string, ctrlParms.strLen, ctrlParms.offset); break; case NVRAM: kerSysNvRamGet(ctrlParms.string, ctrlParms.strLen, ctrlParms.offset); ret = 0; break; case ENVRAM: param = (unsigned char *)kmalloc(strlen(ctrlParms.param)+1, GFP_KERNEL); if (param == NULL) { ret = -EFAULT; break; } memset(param, '\0', strlen(ctrlParms.param)+1); value = (unsigned char *)kmalloc(ctrlParms.value_length, GFP_KERNEL); if (value == NULL) { kfree(param); ret = -EFAULT; break; } memset(value, '\0', ctrlParms.value_length); ret=-EFAULT; if(copy_from_user(param, ctrlParms.param, strlen(ctrlParms.param)) == 0) { ret=envram_get_locked(param, value, ctrlParms.value_length); if(ret) { ret=-EFAULT; if(copy_to_user(ctrlParms.value, value, ctrlParms.value_length) == 0) ret=0; } else ret=-1; } kfree(param); kfree(value); break; case FLASH_SIZE: ret = kerSysFlashSizeGet(); break; default: ret = -EINVAL; printk("Not supported. invalid command %d\n", ctrlParms.action); break; } ctrlParms.result = ret; __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); } else ret = -EFAULT; break; case BOARD_IOCTL_FLASH_LIST: if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { switch (ctrlParms.action) { case SCRATCH_PAD: ret = kerSysScratchPadList(ctrlParms.buf, ctrlParms.offset); break; default: ret = -EINVAL; printk("Not supported. invalid command %d\n", ctrlParms.action); break; } ctrlParms.result = ret; __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); } else ret = -EFAULT; break; case BOARD_IOCTL_DUMP_ADDR: if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { dumpaddr( (unsigned char *) ctrlParms.string, ctrlParms.strLen ); ctrlParms.result = 0; __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = 0; } else ret = -EFAULT; break; case BOARD_IOCTL_SET_MEMORY: if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { unsigned int *pul = (unsigned int *) ctrlParms.string; unsigned short *pus = (unsigned short *) ctrlParms.string; unsigned char *puc = (unsigned char *) ctrlParms.string; switch( ctrlParms.strLen ) { case 4: *pul = (unsigned int) ctrlParms.offset; break; case 2: *pus = (unsigned short) ctrlParms.offset; break; case 1: *puc = (unsigned char) ctrlParms.offset; break; } /* This is placed as MoCA blocks are 32-bit only * accessible and following call makes access in terms * of bytes. Probably MoCA address range can be checked * here. */ dumpaddr( (unsigned char *) ctrlParms.string, sizeof(int) ); ctrlParms.result = 0; __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = 0; } else ret = -EFAULT; break; case BOARD_IOCTL_MIPS_SOFT_RESET: kernel_restart(NULL); break; case BOARD_IOCTL_LED_CTRL: if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { kerSysLedCtrl((BOARD_LED_NAME)ctrlParms.strLen, (BOARD_LED_STATE)ctrlParms.offset); ret = 0; } break; case BOARD_IOCTL_GET_ID: if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { if( ctrlParms.string ) { char p[NVRAM_BOARD_ID_STRING_LEN]; kerSysNvRamGetBoardId(p); if( strlen(p) + 1 < ctrlParms.strLen ) ctrlParms.strLen = strlen(p) + 1; __copy_to_user(ctrlParms.string, p, ctrlParms.strLen); } ctrlParms.result = 0; __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); } break; case BOARD_IOCTL_GET_MAC_ADDRESS: if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { ctrlParms.result = kerSysGetMacAddress( ucaMacAddr, ctrlParms.offset ); if( ctrlParms.result == 0 ) { __copy_to_user(ctrlParms.string, ucaMacAddr, sizeof(ucaMacAddr)); } __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = ctrlParms.result; } else ret = -EFAULT; break; case BOARD_IOCTL_ALLOC_MAC_ADDRESSES: if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { ctrlParms.result = kerSysGetMacAddresses( ucaMacAddr, *((UINT32 *)ctrlParms.buf), ctrlParms.offset ); if( ctrlParms.result == 0 ) { __copy_to_user(ctrlParms.string, ucaMacAddr, sizeof(ucaMacAddr)); } __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = ctrlParms.result; } else ret = -EFAULT; break; case BOARD_IOCTL_RELEASE_MAC_ADDRESSES: if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { if (copy_from_user((void*)ucaMacAddr, (void*)ctrlParms.string, \ NVRAM_MAC_ADDRESS_LEN) == 0) { ctrlParms.result = kerSysReleaseMacAddresses( ucaMacAddr, *((UINT32 *)ctrlParms.buf) ); } else { ctrlParms.result = -EACCES; } __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = ctrlParms.result; } else ret = -EFAULT; break; case BOARD_IOCTL_RELEASE_MAC_ADDRESS: if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { if (copy_from_user((void*)ucaMacAddr, (void*)ctrlParms.string, \ NVRAM_MAC_ADDRESS_LEN) == 0) { ctrlParms.result = kerSysReleaseMacAddress( ucaMacAddr ); } else { ctrlParms.result = -EACCES; } __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = ctrlParms.result; } else ret = -EFAULT; break; case BOARD_IOCTL_GET_PSI_SIZE: { FLASH_ADDR_INFO fInfo; kerSysFlashAddrInfoGet(&fInfo); ctrlParms.result = fInfo.flash_persistent_length; __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = 0; } break; case BOARD_IOCTL_GET_BACKUP_PSI_SIZE: { FLASH_ADDR_INFO fInfo; kerSysFlashAddrInfoGet(&fInfo); // if number_blks > 0, that means there is a backup psi, but length is the same // as the primary psi (persistent). ctrlParms.result = (fInfo.flash_backup_psi_number_blk > 0) ? fInfo.flash_persistent_length : 0; printk("backup_psi_number_blk=%d result=%d\n", fInfo.flash_backup_psi_number_blk, fInfo.flash_persistent_length); __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = 0; } break; case BOARD_IOCTL_GET_SYSLOG_SIZE: { FLASH_ADDR_INFO fInfo; kerSysFlashAddrInfoGet(&fInfo); ctrlParms.result = fInfo.flash_syslog_length; __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = 0; } break; case BOARD_IOCTL_GET_SDRAM_SIZE: ctrlParms.result = (int) kerSysGetSdramSize(); __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = 0; break; case BOARD_IOCTL_GET_BASE_MAC_ADDRESS: if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { //TODO: get_man-info doesn't work, returns NULL //PMAC_INFO pMacInfo = get_mac_info(); //__copy_to_user(ctrlParms.string, pMacInfo->ucaBaseMacAddr, NVRAM_MAC_ADDRESS_LEN); ctrlParms.result = 0; __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = 0; } else ret = -EFAULT; break; case BOARD_IOCTL_GET_CHIP_ID: ctrlParms.result = kerSysGetChipId(); __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = 0; break; case BOARD_IOCTL_GET_CHIP_REV: ctrlParms.result = UtilGetChipRev(); __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = 0; break; case BOARD_IOCTL_GET_NUM_ENET_MACS: case BOARD_IOCTL_GET_NUM_ENET_PORTS: { const ETHERNET_MAC_INFO *EnetInfos; int i, cnt, numEthPorts = 0; if ( ( EnetInfos = BpGetEthernetMacInfoArrayPtr() ) != NULL ) { for( i = 0; i < BP_MAX_ENET_MACS; i++) { if (EnetInfos[i].ucPhyType != BP_ENET_NO_PHY) { bitcount(cnt, EnetInfos[i].sw.port_map); numEthPorts += cnt; } } ctrlParms.result = numEthPorts; __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = 0; } else { ret = -EFAULT; } break; } case BOARD_IOCTL_GET_CFE_VER: if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { unsigned char vertag[CFE_VERSION_MARK_SIZE+CFE_VERSION_SIZE]; kerSysCfeVersionGet(vertag, sizeof(vertag)); if (ctrlParms.strLen < CFE_VERSION_SIZE) { ctrlParms.result = 0; __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = -EFAULT; } else if (strncmp(vertag, "cfe-v", 5)) { // no tag info in flash ctrlParms.result = 0; __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = 0; } else { ctrlParms.result = 1; __copy_to_user(ctrlParms.string, vertag+CFE_VERSION_MARK_SIZE, CFE_VERSION_SIZE); __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = 0; } } else { ret = -EFAULT; } break; #if defined (WIRELESS) case BOARD_IOCTL_GET_WLAN_ANT_INUSE: if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { unsigned short antInUse = 0; if (BpGetWirelessAntInUse(&antInUse) == BP_SUCCESS) { if (ctrlParms.strLen == sizeof(antInUse)) { __copy_to_user(ctrlParms.string, &antInUse, sizeof(antInUse)); ctrlParms.result = 0; __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = 0; } else ret = -EFAULT; } else { ret = -EFAULT; } break; } else { ret = -EFAULT; } break; #endif case BOARD_IOCTL_SET_TRIGGER_EVENT: if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { BOARD_IOC *board_ioc = (BOARD_IOC *)flip->private_data; ctrlParms.result = -EFAULT; ret = -EFAULT; if (ctrlParms.strLen == sizeof(unsigned int)) { board_ioc->eventmask |= *((int*)ctrlParms.string); #if defined (WIRELESS) if((board_ioc->eventmask & SES_EVENTS)) { ctrlParms.result = 0; ret = 0; } #endif __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); } break; } else { ret = -EFAULT; } break; case BOARD_IOCTL_GET_TRIGGER_EVENT: if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { BOARD_IOC *board_ioc = (BOARD_IOC *)flip->private_data; if (ctrlParms.strLen == sizeof(unsigned int)) { __copy_to_user(ctrlParms.string, &board_ioc->eventmask, sizeof(unsigned int)); ctrlParms.result = 0; __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = 0; } else ret = -EFAULT; break; } else { ret = -EFAULT; } break; case BOARD_IOCTL_UNSET_TRIGGER_EVENT: if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { if (ctrlParms.strLen == sizeof(unsigned int)) { BOARD_IOC *board_ioc = (BOARD_IOC *)flip->private_data; board_ioc->eventmask &= (~(*((int*)ctrlParms.string))); ctrlParms.result = 0; __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = 0; } else ret = -EFAULT; break; } else { ret = -EFAULT; } break; #if defined (WIRELESS) case BOARD_IOCTL_SET_SES_LED: if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { if (ctrlParms.strLen == sizeof(int)) { sesLed_ctrl(*(int*)ctrlParms.string); ctrlParms.result = 0; __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = 0; } else ret = -EFAULT; break; } else { ret = -EFAULT; } break; #endif case BOARD_IOCTL_GET_GPIOVERLAYS: if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { unsigned int GPIOOverlays = 0; ret = 0; if (BP_SUCCESS == (ctrlParms.result = BpGetGPIOverlays(&GPIOOverlays) )) { __copy_to_user(ctrlParms.string, &GPIOOverlays, sizeof(unsigned int)); if(__copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS))!=0) ret = -EFAULT; } }else ret = -EFAULT; break; case BOARD_IOCTL_SET_MONITOR_FD: if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { kerSysSetMonitorTaskPid(ctrlParms.offset); printk(KERN_INFO "monitor task is initialized pid= %d \n",ctrlParms.offset); } break; case BOARD_IOCTL_WAKEUP_MONITOR_TASK: kerSysSendtoMonitorTask(MSG_NETLINK_BRCM_WAKEUP_MONITOR_TASK, NULL, 0); break; case BOARD_IOCTL_SET_CS_PAR: if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { ret = ConfigCs(&ctrlParms); __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); } else { ret = -EFAULT; } break; case BOARD_IOCTL_SET_GPIO: if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { kerSysSetGpioState(ctrlParms.strLen, ctrlParms.offset); __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = 0; } else { ret = -EFAULT; } break; case BOARD_IOCTL_BOOT_IMAGE_OPERATION: if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { switch(ctrlParms.offset) { case BOOT_SET_PART1_IMAGE: case BOOT_SET_PART2_IMAGE: case BOOT_SET_PART1_IMAGE_ONCE: case BOOT_SET_PART2_IMAGE_ONCE: case BOOT_SET_OLD_IMAGE: case BOOT_SET_NEW_IMAGE: case BOOT_SET_NEW_IMAGE_ONCE: ctrlParms.result = kerSysSetBootImageState(ctrlParms.offset); /* Clean up image version. */ if (ctrlParms.result == 0) clearImageVersion(); break; case BOOT_GET_BOOT_IMAGE_STATE: ctrlParms.result = kerSysGetBootImageState(); break; case BOOT_GET_IMAGE_VERSION: /* ctrlParms.action is parition number */ ctrlParms.result = getImageVersion((int) ctrlParms.action, ctrlParms.string, ctrlParms.strLen); break; case BOOT_GET_BOOTED_IMAGE_ID: /* ctrlParm.strLen == 1: partition or == 0: id (new or old) */ ctrlParms.result = getBootedValue(ctrlParms.strLen); break; default: ctrlParms.result = -EFAULT; break; } __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = 0; } else { ret = -EFAULT; } break; case BOARD_IOCTL_GET_SEQUENCE_NUMBER: if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { ctrlParms.result = kerSysGetSequenceNumber(ctrlParms.offset); __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = 0; } else { ret = -EFAULT; } break; case BOARD_IOCTL_GETSET_BOOT_INACTIVE_IMAGE: ret = 0; #if !defined(CONFIG_BCM947189) if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { if ((ctrlParms.offset != 0) && (ctrlParms.offset != 1)) { // get whether we boot the inactive image ctrlParms.result = (BCM_MBOX_INACTIVE_IMAGE_GET() ? 1 : 0); __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); } else { // set to boot or not boot the inactive image if (ctrlParms.offset == 1) { BCM_MBOX_SOFT_RESET_SAFE_EN; BCM_MBOX_INACTIVE_IMAGE_SET(0x1); } else { BCM_MBOX_INACTIVE_IMAGE_CLR(); } } } else { ret = -EFAULT; } #else memset((BOARD_IOCTL_PARMS*)arg, 0, sizeof(BOARD_IOCTL_PARMS)); #endif break; case BOARD_IOCTL_GET_TIMEMS: ret = jiffies_to_msecs(jiffies - INITIAL_JIFFIES); break; #if defined(CONFIG_BCM963268) || defined(CONFIG_BCM_6802_MoCA) || defined(CONFIG_BCM_FTTDP) case BOARD_IOCTL_SPI_SLAVE_INIT: ret = 0; if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { /* Using the 'result' field to specify the SPI device */ if (kerSysBcmSpiSlaveInit(ctrlParms.result) != SPI_STATUS_OK) { ret = -EFAULT; } } else { ret = -EFAULT; } break; case BOARD_IOCTL_SPI_SLAVE_READ: ret = 0; if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { /* Using the 'result' field to specify the SPI device for reads */ if (kerSysBcmSpiSlaveRead(ctrlParms.result, ctrlParms.offset, (unsigned int *)ctrlParms.buf, ctrlParms.strLen) != SPI_STATUS_OK) { ret = -EFAULT; } else { __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); } } else { ret = -EFAULT; } break; case BOARD_IOCTL_SPI_SLAVE_WRITE_BUF: ret = 0; if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { /* Using the 'result' field to specify the SPI device for write buf */ if (kerSysBcmSpiSlaveWriteBuf(ctrlParms.result, ctrlParms.offset, (unsigned int *)ctrlParms.buf, ctrlParms.strLen, 4) != SPI_STATUS_OK) { ret = -EFAULT; } else { __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); } } else { ret = -EFAULT; } break; case BOARD_IOCTL_SPI_SLAVE_WRITE: ret = 0; if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { /* Using the 'buf' field to specify the SPI device for writes */ int devid = (uintptr_t)ctrlParms.buf & 0xFFFFFFFF; if (kerSysBcmSpiSlaveWrite(devid, ctrlParms.offset, ctrlParms.result, ctrlParms.strLen) != SPI_STATUS_OK) { ret = -EFAULT; } else { __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); } } else { ret = -EFAULT; } break; case BOARD_IOCTL_SPI_SLAVE_SET_BITS: ret = 0; #if defined(CONFIG_BCM_6802_MoCA) if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { /* Using the 'buf' field to specify the SPI device for set bits */ int devid = (uintptr_t)ctrlParms.buf & 0xFFFFFFFF; if (kerSysBcmSpiSlaveModify(devid, ctrlParms.offset, ctrlParms.result, ctrlParms.result, ctrlParms.strLen) != SPI_STATUS_OK) { ret = -EFAULT; } else { __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); } } else { ret = -EFAULT; } #endif break; case BOARD_IOCTL_SPI_SLAVE_CLEAR_BITS: ret = 0; #if defined(CONFIG_BCM_6802_MoCA) if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { /* Using the 'buf' field to specify the SPI device for clear bits */ int devid = (uintptr_t)ctrlParms.buf & 0xFFFFFFFF; if (kerSysBcmSpiSlaveModify(devid, ctrlParms.offset, 0, ctrlParms.result, ctrlParms.strLen) != SPI_STATUS_OK) { ret = -EFAULT; } else { __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); } } else { ret = -EFAULT; } #endif break; #endif #if defined(CONFIG_EPON_SDK) case BOARD_IOCTL_GET_PORT_MAC_TYPE: { unsigned short port; unsigned int mac_type; if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { port = ctrlParms.offset; if (BpGetPortMacType(port, &mac_type) == BP_SUCCESS) { ctrlParms.result = (unsigned int)mac_type; __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = 0; } else { ret = -EFAULT; } break; } } case BOARD_IOCTL_GET_NUM_FE_PORTS: { unsigned int fe_ports; if (BpGetNumFePorts(&fe_ports) == BP_SUCCESS) { ctrlParms.result = fe_ports; __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = 0; } else { ret = -EFAULT; } break; } case BOARD_IOCTL_GET_NUM_GE_PORTS: { unsigned int ge_ports; if (BpGetNumGePorts(&ge_ports) == BP_SUCCESS) { ctrlParms.result = ge_ports; __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = 0; } else { ret = -EFAULT; } break; } case BOARD_IOCTL_GET_NUM_VOIP_PORTS: { unsigned int voip_ports; if (BpGetNumVoipPorts(&voip_ports) == BP_SUCCESS) { ctrlParms.result = voip_ports; __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = 0; } else { ret = -EFAULT; } break; } case BOARD_IOCTL_GET_SWITCH_PORT_MAP: { unsigned int port_map; if (BpGetSwitchPortMap(&port_map) == BP_SUCCESS) { ctrlParms.result = port_map; __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); ret = 0; } else { ret = -EFAULT; } break; } case BOARD_IOCTL_GET_EPON_GPIOS: { int i, rc = 0, gpionum; unsigned short *pusGpio, gpio; if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { if( ctrlParms.string ) { /* walk through the epon gpio list */ i = 0; pusGpio = (unsigned short *)ctrlParms.string; gpionum = ctrlParms.strLen/sizeof(unsigned short); for(;;) { rc = BpGetEponGpio(i, &gpio); if( rc == BP_MAX_ITEM_EXCEEDED || i >= gpionum ) break; else { if( rc == BP_SUCCESS ) *pusGpio = gpio; else *pusGpio = BP_GPIO_NONE; pusGpio++; } i++; } ctrlParms.result = 0; __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS)); } else { ret = -EFAULT; } } break; } #endif case BOARD_IOCTL_GET_BATTERY_ENABLE: ret = kerSysIsBatteryEnabled(); break; case BOARD_IOCTL_MEM_ACCESS: { BOARD_MEMACCESS_IOCTL_PARMS parms; unsigned char* kbuf=NULL; int blen; if (copy_from_user((void*)&parms, (void*)arg, sizeof(parms))) { ret = -EFAULT; break; } if (parms.op == BOARD_MEMACCESS_IOCTL_OP_FILL) { blen = parms.size; } else { blen = parms.size * parms.count; } kbuf = (unsigned char *)kmalloc(blen, GFP_KERNEL); if (kbuf == NULL) { ret = -EFAULT; break; } if (copy_from_user((void*)kbuf, (void*)parms.buf, blen)) { ret = -EFAULT; kfree(kbuf); break; } ret = board_ioctl_mem_access(&parms, kbuf, blen); __copy_to_user((void *)parms.buf, (void*)kbuf, blen); kfree(kbuf); } break; #if !defined(CONFIG_BCM960333) && !defined(CONFIG_BCM947189) case BOARD_IOCTL_SET_DYING_GASP_INTERRUPT: if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) { kerSysDyingGaspIoctl(ctrlParms.offset); } break; #endif case BOARD_IOCTL_GET_BOOT_SECURE: ctrlParms.result = 0; #if !defined(CONFIG_BCM960333) && !defined(CONFIG_BCM947189) ctrlParms.result = bcm_otp_is_boot_secure(); #endif __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(ctrlParms)); ret = 0; break; case BOARD_IOCTL_GET_BTRM_BOOT: ctrlParms.result = 0; #if !defined(CONFIG_BCM960333) && !defined(CONFIG_BCM947189) ctrlParms.result = bcm_otp_is_btrm_boot(); #endif __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(ctrlParms)); ret = 0; break; case BOARD_IOCTL_GET_BOOT_MFG_SECURE: #if defined(CONFIG_BCM94908) || defined(CONFIG_BCM96858) || \ defined(CONFIG_BCM963158) || defined(CONFIG_BCM96846) || defined(CONFIG_BCM96856) || defined(CONFIG_BCM96878) || defined(CONFIG_BCM96855) ctrlParms.result = bcm_otp_is_boot_mfg_secure(); #else ctrlParms.result = 0; #endif __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(ctrlParms)); ret = 0; break; #if defined(CONFIG_BCM963138) || defined(CONFIG_BCM963148) case BOARD_IOCTL_SATA_TEST: if( bcm_sata_test_ioctl_fn) { ret = bcm_sata_test_ioctl_fn((void*)arg); } else { printk("SATA TEST module not loaded\n"); } break; #endif #if defined(CONFIG_BCM963138) || defined(CONFIG_BCM963148) || defined(CONFIG_BCM94908) || defined(CONFIG_BCM963158) case BOARD_IOCTL_BT_GPIO: // bluetooth gpio for reset / wake if (copy_from_user((void *)&ctrlParms, (void *)arg, sizeof ctrlParms) == 0) { unsigned short gpio; // get or set bt gpio switch (ctrlParms.strLen) { case BOARD_IOCTL_BT_GPIO_RESET: if (BpGetBtResetGpio(&gpio) != BP_SUCCESS) { ret = -ENOSYS; } else { if (ctrlParms.offset < 0) { ctrlParms.offset = kerSysGetGpioValue(gpio); __copy_to_user((void *)arg, &ctrlParms, sizeof ctrlParms); } else { kerSysSetGpioState(gpio, ctrlParms.offset); } } break; case BOARD_IOCTL_BT_GPIO_WAKE: if (BpGetBtWakeGpio(&gpio) != BP_SUCCESS) { ret = -ENOSYS; } else { if (ctrlParms.offset < 0) { ctrlParms.offset = kerSysGetGpioValue(gpio); __copy_to_user((void *)arg, &ctrlParms, sizeof ctrlParms); } else { kerSysSetGpioState(gpio, ctrlParms.offset); } } break; default: ret = -EFAULT; } } else ret = -EFAULT; break; #endif case BOARD_IOCTL_GET_FLASH_TYPE: ctrlParms.result = flash_get_flash_type(); __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(ctrlParms)); ret = 0; break; default: ret = -EINVAL; ctrlParms.result = 0; printk("board_ioctl: invalid command %x, cmd %d .\n",command,_IOC_NR(command)); break; } /* switch */ return (ret); } /* board_ioctl */