/* * <: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 #include #include "board_wl.h" #include "board_button.h" #include #include "board_image.h" #if defined (WIRELESS) #include #endif extern wait_queue_head_t g_board_wait_queue; unsigned short sesBtn_irq = BP_NOT_DEFINED; static unsigned short sesBtn_gpio = BP_NOT_DEFINED; static unsigned short sesBtn_polling = 0; static struct timer_list sesBtn_timer; static atomic_t sesBtn_active; static atomic_t sesBtn_forced; static irqreturn_t sesBtn_isr(int irq, void *dev_id); static Bool sesBtn_pressed(void); static int __init sesBtn_mapIntr(int context); static void sesBtn_defaultAction(unsigned long time, void* param); #if defined(WIRELESS) static void sesBtn_releaseAction(unsigned long time, void* param); #endif #define LONG_PUSH_BUTTON_PERIOD (3000) //three seconds #define SHORT_PUSH_BUTTON_PERIOD (1) #if defined (WIRELESS) unsigned long gSesBtnEvOutstanding = 0; unsigned long gLastSesBtnEvTime; static unsigned short sesLed_gpio = BP_NOT_DEFINED; static void __init sesLed_mapGpio(void); static void __init kerSysScreenPciDevices(void); /* This spinlock is used to avoid race conditions caused by the * non-atomic test-and-set of sesBtn_active in sesBtn_read */ static DEFINE_SPINLOCK(sesBtn_newapi_spinlock); #endif void __init ses_board_init() { int ret; ret = sesBtn_mapIntr(0); if (ret) { registerPushButtonPressNotifyHook(PB_BUTTON_1, sesBtn_defaultAction, 0); #if defined(SUPPORT_IEEE1905) //1905 is triggered by the plc uke button action. Attach hook to button 1 if using //the old style of board parms registerPushButtonPressNotifyHook(PB_BUTTON_1, btnHook_PlcUke, 0); #endif } else { #if defined(WIRELESS) /* When new push button is used */ unsigned short btnIdx=0; if(btnGetSesBtnIdx(&btnIdx) == BP_SUCCESS) { registerPushButtonReleaseNotifyHook(btnIdx, sesBtn_releaseAction, SHORT_PUSH_BUTTON_PERIOD,NULL); registerPushButtonReleaseNotifyHook(btnIdx, sesBtn_releaseAction, LONG_PUSH_BUTTON_PERIOD,NULL); } #endif } #if defined(WIRELESS) sesLed_mapGpio(); #endif } void __exit ses_board_deinit() { if( sesBtn_polling == 0 && sesBtn_irq != BP_NOT_DEFINED ) { if(sesBtn_irq) { del_timer(&sesBtn_timer); atomic_set(&sesBtn_active, 0); atomic_set(&sesBtn_forced, 0); #if !defined(CONFIG_BCM947189) if (!IsExtIntrShared(extIntrInfo[sesBtn_irq - INTERRUPT_ID_EXTERNAL_0])) { BcmHalInterruptDisable(sesBtn_irq); } #endif } } } unsigned short sesBtn_getIrq(void) { return sesBtn_irq; } /*************************************************************************** * SES Button ISR/GPIO/LED functions. ***************************************************************************/ static Bool sesBtn_pressed(void) { unsigned int intSts = 0, extIntr, value = 0; int gpioActHigh = 0, isrDectActHigh = 0; int intrActive = 0; Bool pressed = 1; if( sesBtn_polling == 0 ) { #if defined(CONFIG_BCM96838) || defined(CONFIG_BCM94908) if ((sesBtn_irq >= INTERRUPT_ID_EXTERNAL_0) && (sesBtn_irq <= INTERRUPT_ID_EXTERNAL_5)) { #elif defined(CONFIG_BCM963158) || defined(CONFIG_BCM96846) || defined(CONFIG_BCM96858) || defined(CONFIG_BCM96856) || defined(CONFIG_BCM96878) || defined(CONFIG_BCM96855) if ((sesBtn_irq >= INTERRUPT_ID_EXTERNAL_0) && (sesBtn_irq <= INTERRUPT_ID_EXTERNAL_7)) { #elif defined(CONFIG_BCM947189) if (sesBtn_irq == INTERRUPT_ID_EXTERNAL_0) { #else if ((sesBtn_irq >= INTERRUPT_ID_EXTERNAL_0) && (sesBtn_irq <= INTERRUPT_ID_EXTERNAL_3)) { #endif #if defined(CONFIG_BCM963138) || defined(CONFIG_BCM963148) intSts = kerSysGetGpioValue(MAP_EXT_IRQ_TO_GPIO( sesBtn_irq - INTERRUPT_ID_EXTERNAL_0)); #elif defined(CONFIG_BCM963381) || defined(CONFIG_BCM96848) intSts = PERF->ExtIrqSts & (1 << (sesBtn_irq - INTERRUPT_ID_EXTERNAL_0 + EI_STATUS_SHFT)); #elif defined(CONFIG_BCM96858) || defined(CONFIG_BCM94908) || \ defined(CONFIG_BCM963158) || defined(CONFIG_BCM96846) || defined(CONFIG_BCM96856) || defined (CONFIG_BCM947622) || defined(CONFIG_BCM963178) || defined(CONFIG_BCM96878) || defined(CONFIG_BCM96855) //#warinig Verify intSts = PERF->ExtIrqStatus & (1 << (sesBtn_irq - INTERRUPT_ID_EXTERNAL_0 + EI_STATUS_SHFT)); #elif defined(CONFIG_BCM947189) intSts = kerSysGetGpioValue(sesBtn_gpio); #else intSts = PERF->ExtIrqCfg & (1 << (sesBtn_irq - INTERRUPT_ID_EXTERNAL_0 + EI_STATUS_SHFT)); #endif } else return 0; extIntr = extIntrInfo[sesBtn_irq-INTERRUPT_ID_EXTERNAL_0]; #if defined(CONFIG_BCM94908) || defined(CONFIG_BCM963158) || defined(CONFIG_BCM96858) || defined(CONFIG_BCM96846) || defined(CONFIG_BCM96856) || defined(CONFIG_BCM96878) || defined(CONFIG_BCM96855) /* 4908 simplifies the interrupt status reporting. ExtIrqStatus report the actual interrupt state, * not the interupt pin high/low value as in the old chip, so no need to check interrupt detection polarity */ if( intSts ) { (void)isrDectActHigh; intrActive = 1; BcmHalExternalIrqClear(sesBtn_irq); } #else isrDectActHigh = IsExtIntrTypeActHigh(extIntr); if( (isrDectActHigh && intSts) || (!isrDectActHigh && !intSts) ) intrActive = 1; #endif if( intrActive ) { //check the gpio status here too if shared. if( IsExtIntrShared(extIntr) ) { gpioActHigh = sesBtn_gpio&BP_ACTIVE_LOW ? 0 : 1; value = kerSysGetGpioValue(sesBtn_gpio); if( (value&&!gpioActHigh) || (!value&&gpioActHigh) ) pressed = 0; } } else { pressed = 0; } } else { pressed = 0; if( sesBtn_gpio != BP_NOT_DEFINED ) { gpioActHigh = sesBtn_gpio&BP_ACTIVE_LOW ? 0 : 1; value = kerSysGetGpioValue(sesBtn_gpio); if( (value&&gpioActHigh) || (!value&&!gpioActHigh) ) pressed = 1; } } return pressed; } #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0) static void sesBtn_timer_handler(unsigned long arg) #else static void sesBtn_timer_handler(struct timer_list *arg) #endif { unsigned long currentJiffies = jiffies; if ( sesBtn_pressed() ) { doPushButtonHold(PB_BUTTON_1, currentJiffies); mod_timer(&sesBtn_timer, currentJiffies + msecs_to_jiffies(100)); } else { atomic_set(&sesBtn_active, 0); doPushButtonRelease(PB_BUTTON_1, currentJiffies); #if defined(CONFIG_BCM963138) || defined(CONFIG_BCM963148) || defined(CONFIG_BCM94908) || defined(CONFIG_BCM96858) || \ defined(CONFIG_BCM963158) || defined(CONFIG_BCM96846) || defined(CONFIG_BCM96856) || defined(CONFIG_BCM96878) || defined(CONFIG_BCM96855) BcmHalExternalIrqUnmask(sesBtn_irq); #elif defined(CONFIG_BCM947189) GPIO->gpiointmask |= (1 << sesBtn_gpio); #else BcmHalInterruptEnable(sesBtn_irq); #endif } } static void sesBtn_defaultAction(unsigned long time, void* param) { wake_up_interruptible(&g_board_wait_queue); } #if defined(WIRELESS) static void sesBtn_releaseAction(unsigned long time, void* param) { unsigned long flags; spin_lock_irqsave(&sesBtn_newapi_spinlock, flags); if(time>=3000) { printk( "(kernel):%s:%d: *** long released ***\n",__FUNCTION__,__LINE__); atomic_set(&sesBtn_active, SES_BTN_STA); } else { printk( "(kernel):%s:%d: *** short released ***\n",__FUNCTION__,__LINE__); atomic_set(&sesBtn_active, SES_BTN_AP); } spin_unlock_irqrestore(&sesBtn_newapi_spinlock, flags); wake_up_interruptible(&g_board_wait_queue); } #endif static irqreturn_t sesBtn_isr(int irq, void *dev_id) { int ext_irq_idx = 0, value=0; irqreturn_t ret = IRQ_NONE; unsigned long currentJiffies = jiffies; ext_irq_idx = irq - INTERRUPT_ID_EXTERNAL_0; if (IsExtIntrShared(extIntrInfo[ext_irq_idx])) { value = kerSysGetGpioValue(*(int *)dev_id); if( (IsExtIntrTypeActHigh(extIntrInfo[ext_irq_idx]) && value) || (IsExtIntrTypeActLow(extIntrInfo[ext_irq_idx]) && !value) ) { #if defined(CONFIG_BCM947189) if (GPIO->gpiointmask & (1 << sesBtn_gpio)) #endif ret = IRQ_HANDLED; } } else { ret = IRQ_HANDLED; } if (IRQ_HANDLED == ret) { int timerSet = mod_timer(&sesBtn_timer, (currentJiffies + msecs_to_jiffies(100))); /* 100 msec */ #if defined(CONFIG_BCM94908) || defined(CONFIG_BCM96858) || defined(CONFIG_BCM963158) || defined(CONFIG_BCM96856) BcmHalExternalIrqClear(irq); #endif #if defined(CONFIG_BCM963138) || defined(CONFIG_BCM963148) || defined(CONFIG_BCM94908) || defined(CONFIG_BCM96858) || \ defined(CONFIG_BCM963158) || defined(CONFIG_BCM96846) || defined(CONFIG_BCM96856) || defined(CONFIG_BCM96878) || defined(CONFIG_BCM96855) BcmHalExternalIrqMask(irq); #endif #if defined(CONFIG_BCM947189) GPIO->gpiointmask &= ~(1 << sesBtn_gpio); #endif if ( 0 == timerSet ) { atomic_set(&sesBtn_active, SES_BTN_LEGACY); doPushButtonPress(PB_BUTTON_1, currentJiffies); } } #if !defined(CONFIG_BCM_6802_MoCA) && !defined(CONFIG_ARM) && !defined(CONFIG_ARM64) if (IsExtIntrShared(extIntrInfo[ext_irq_idx])) { BcmHalInterruptEnable(sesBtn_irq); } #endif return ret; } // return 1 if interrupt was mapped. Return 0 otherwise static int __init sesBtn_mapIntr(int context) { int ret = 0; int ext_irq_idx; if( BpGetWirelessSesExtIntr(&sesBtn_irq) == BP_SUCCESS ) { BpGetWirelessSesExtIntrGpio(&sesBtn_gpio); if( sesBtn_irq != BP_EXT_INTR_NONE ) { #if defined(CONFIG_BCM960333) if( sesBtn_gpio != BP_NOT_DEFINED && sesBtn_irq != BP_EXT_INTR_NONE) mapBcm960333GpioToIntr(sesBtn_gpio & BP_GPIO_NUM_MASK, sesBtn_irq); #endif printk("SES: Button Interrupt 0x%x is enabled\n", sesBtn_irq); } else { if( sesBtn_gpio != BP_NOT_DEFINED ) { printk("SES: Button Polling is enabled on gpio %x\n", sesBtn_gpio); kerSysSetGpioDirInput(sesBtn_gpio); sesBtn_polling = 1; } } } else return 0; if( sesBtn_irq != BP_EXT_INTR_NONE ) { ext_irq_idx = (sesBtn_irq&~BP_EXT_INTR_FLAGS_MASK)-BP_EXT_INTR_0; #if defined(CONFIG_BCM963381) || defined(CONFIG_BCM96848) kerSysInitPinmuxInterface(BP_PINMUX_FNTYPE_IRQ | ext_irq_idx); #endif if (!IsExtIntrConflict(extIntrInfo[ext_irq_idx])) { static int dev = -1; int hookisr = 1; if (IsExtIntrShared(sesBtn_irq)) { /* get the gpio and make it input dir */ if( sesBtn_gpio != BP_NOT_DEFINED ) { sesBtn_gpio &= BP_GPIO_NUM_MASK;; printk("SES: Button Interrupt gpio is %d\n", sesBtn_gpio); kerSysSetGpioDirInput(sesBtn_gpio); dev = sesBtn_gpio; #if defined (CONFIG_BCM947189) MISC->intmask |= 1; /* enable GPIO interrupts */ if ((sesBtn_irq & BP_ACTIVE_MASK) == BP_ACTIVE_LOW) GPIO->gpiointpolarity |= (1 << sesBtn_gpio); GPIO->gpiointmask |= (1 << sesBtn_gpio); #endif } else { printk("SES: Button Interrupt gpio definition not found \n"); hookisr = 0; } } if(hookisr) { #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0) init_timer(&sesBtn_timer); sesBtn_timer.function = sesBtn_timer_handler; #else timer_setup(&sesBtn_timer, sesBtn_timer_handler, 0); #endif sesBtn_timer.expires = jiffies + msecs_to_jiffies(100); /* 100 msec */ #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0) sesBtn_timer.data = 0; #endif atomic_set(&sesBtn_active, 0); atomic_set(&sesBtn_forced, 0); sesBtn_irq = map_external_irq (sesBtn_irq); ret = 1; BcmHalMapInterrupt((FN_HANDLER)sesBtn_isr, (void*)&dev, sesBtn_irq); #if !defined(CONFIG_ARM) && !defined(CONFIG_ARM64) BcmHalInterruptEnable(sesBtn_irq); #endif } } } return ret; } /** *_get_wl_nandmanufacture check if system is nand system and manufacture bit is set * */ int _get_wl_nandmanufacture(void ) { int is_nand=0,is_m=0,has_size=0; unsigned int rootfs_ofs; NVRAM_DATA *pNvramData; is_nand =( kerSysBlParmsGetInt(NAND_RFS_OFS_NAME, (int *) &rootfs_ofs) != -1 )? WLAN_MFG_PARTITION_ISNAND:0; if (NULL != (pNvramData = readNvramData())) { is_m = (((unsigned char)(pNvramData ->wlanParams[NVRAM_WLAN_PARAMS_LEN-1])) & WLAN_FEATURE_DHD_MFG_ENABLE)?WLAN_MFG_PARTITION_MFGSET:0; has_size= (pNvramData->part_info[WLAN_MFG_PARTITION_INDEX].size>0 && pNvramData->part_info[WLAN_MFG_PARTITION_INDEX].size<0xffff)?WLAN_MFG_PARTITION_HASSIZE:0; kfree(pNvramData); } return is_nand|is_m|has_size; } /** * _wlsrom_write_file - write char content into file * @name file name * @content the content to save * @size size of the conten * * Return 0 success or -1 totherwise */ int _wlsrom_write_file(char *name,char *content,int size) { struct file *fp=filp_open(name,O_WRONLY|O_CREAT,0); int err=0; if(!IS_ERR(fp)) { mm_segment_t old_fs=get_fs(); loff_t pos=0L; set_fs(KERNEL_DS); vfs_write(fp,(void __user *)(content),size,&pos); set_fs(old_fs); err=vfs_fsync(fp,0); if(err) printk("SYNC to disk error!!!\n"); filp_close(fp,NULL); return 0; } return -1; } /***************************************************************************/ // BP_BTN_ACTION_SES void btnHook_Ses(unsigned long timeInMs, void* param) { /* for new button implementation,press will do nothing */ return; } #if defined(WIRELESS) unsigned int sesBtn_poll(struct file *file, struct poll_table_struct *wait) { // this is called by the wireless driver to determine if the button is down. If // we are using the new button method, we simply check if the button trigger // occured within the last second. Otherwise, we fall through to check the // original checks. if (gSesBtnEvOutstanding) { if (time_after(gLastSesBtnEvTime+HZ, jiffies)) { return POLLIN; } else { atomic_set(&sesBtn_active, 0); gSesBtnEvOutstanding = 0; } } if ( sesBtn_polling ) { if ( sesBtn_pressed() ) { return POLLIN; } } else if (atomic_read(&sesBtn_active)) { return POLLIN; } else if (atomic_read(&sesBtn_forced)) { atomic_set(&sesBtn_forced,0); return POLLIN; } return 0; } ssize_t sesBtn_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { volatile unsigned int event=0; ssize_t ret=0; unsigned long flags; int exit = 0; /* Synchronization note: This code does a non-atomic test and set of * sesBtn_active that could cause a race-condition with btnHook_Ses, * so this must be protected with sesBtn_newapi_spinlock. */ /* New button API: Return the type of SES button press (Short/Long) */ spin_lock_irqsave(&sesBtn_newapi_spinlock, flags); if (atomic_read(&sesBtn_active) == SES_BTN_AP) { event = SES_EVENTS | SES_EVENT_BTN_AP; atomic_set(&sesBtn_active, 0); } else if (atomic_read(&sesBtn_active) == SES_BTN_STA) { event = SES_EVENTS | SES_EVENT_BTN_STA; atomic_set(&sesBtn_active, 0); } /* Legacy button API: Return a simple flag (SES_EVENTS) and let the * userspace code call read repeatedly to calculate the press time */ else { if (sesBtn_polling) { if (0 == sesBtn_pressed()) { exit = 1; } } else if (0 == atomic_read(&sesBtn_active)) { exit = 1; } event = SES_EVENTS; } spin_unlock_irqrestore(&sesBtn_newapi_spinlock, flags); if (exit) return ret; gSesBtnEvOutstanding = 0; __copy_to_user((char*)buffer, (char*)&event, sizeof(event)); count -= sizeof(event); buffer += sizeof(event); ret += sizeof(event); return ret; } /*********************************************************************** * Function Name: kerSysScreenPciDevices * Description : Screen Pci Devices before loading modules ***********************************************************************/ static void __init kerSysScreenPciDevices(void) { unsigned short wlFlag; if((BpGetWirelessFlags(&wlFlag) == BP_SUCCESS) && (wlFlag & BP_WLAN_EXCLUDE_ONBOARD)) { /* * scan all available pci devices and delete on board BRCM wireless device * if external slot presents a BRCM wireless device */ int foundPciAddOn = 0; struct pci_dev *pdevToExclude = NULL; struct pci_dev *dev = NULL; while((dev=pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev))!=NULL) { printk("kerSysScreenPciDevices: 0x%x:0x%x:(slot %d) detected\n", dev->vendor, dev->device, PCI_SLOT(dev->devfn)); if((dev->vendor == BRCM_VENDOR_ID) && (((dev->device & 0xff00) == BRCM_WLAN_DEVICE_IDS)|| ((dev->device/1000) == BRCM_WLAN_DEVICE_IDS_DEC))) { if(PCI_SLOT(dev->devfn) != WLAN_ONBOARD_SLOT) { foundPciAddOn++; } else { pdevToExclude = dev; } } } #ifdef CONFIG_PCI if(((wlFlag & BP_WLAN_EXCLUDE_ONBOARD_FORCE) || foundPciAddOn) && pdevToExclude) { printk("kerSysScreenPciDevices: 0x%x:0x%x:(onboard) deleted\n", pdevToExclude->vendor, pdevToExclude->device); #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) pci_remove_bus_device(pdevToExclude); #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) ; //do nothing #else __pci_remove_bus_device(pdevToExclude); #endif } #else #error ATTEMPT TO COMPILE WIRELESS WITHOUT PCI #endif } } /*********************************************************************** * Function Name: kerSetWirelessPD * Description : Control Power Down by Hardware if the board supports ***********************************************************************/ void kerSetWirelessPD(int state) { unsigned short wlanPDGpio; if((BpGetWirelessPowerDownGpio(&wlanPDGpio)) == BP_SUCCESS) { if (wlanPDGpio != BP_NOT_DEFINED) { if(state == WLAN_OFF) kerSysSetGpioState(wlanPDGpio, kGpioActive); else kerSysSetGpioState(wlanPDGpio, kGpioInactive); } } } static void __init sesLed_mapGpio() { if( BpGetWirelessSesLedGpio(&sesLed_gpio) == BP_SUCCESS ) { printk("SES: LED GPIO 0x%x is enabled\n", sesLed_gpio); } } void sesLed_ctrl(int action) { char blinktype = ((action >> 24) & 0xff); /* extract blink type for SES_LED_BLINK */ BOARD_LED_STATE led; if(sesLed_gpio == BP_NOT_DEFINED) return; action &= 0xff; /* extract led */ switch (action) { case SES_LED_ON: led = kLedStateOn; break; case SES_LED_BLINK: if(blinktype) led = blinktype; else led = kLedStateSlowBlinkContinues; break; case SES_LED_OFF: default: led = kLedStateOff; } kerSysLedCtrl(kLedSes, led); } void kerSysSesEventTrigger( int forced ) { if (forced) { atomic_set (&sesBtn_forced, 1); } wake_up_interruptible(&g_board_wait_queue); } /** *kerSysGetWlanSromParamsLen - get wlan calibration data len * */ int kerSysGetWlanSromParamsLen(void ) { int nm=_get_wl_nandmanufacture(); if(nmwlanParams), len ); kfree(pNvramData); } else { struct file *fp=filp_open(WL_SROM_CUSTOMER_FILE,O_RDONLY,0); if(!IS_ERR(fp)) { #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0) int rl=kernel_read(fp,0,wlanParams,len); #else int rl=kernel_read(fp,0,(size_t)wlanParams, (loff_t *)&len); #endif filp_close(fp,NULL); if(rl<=0) return -1; } else { return -1; } } return 0; } EXPORT_SYMBOL(kerSysGetWlanSromParams); unsigned char kerSysGetWlanFeature(void) { NVRAM_DATA *pNvramData; unsigned char wlfeature=0; if (NULL == (pNvramData = readNvramData())) { printk("kerSysGetWlanSromParams: could not read nvram data\n"); return -1; } wlfeature= (unsigned char)(pNvramData ->wlanParams[NVRAM_WLAN_PARAMS_LEN-1]); kfree(pNvramData); return wlfeature; } EXPORT_SYMBOL(kerSysGetWlanFeature); void board_util_wl_godefault(void) { char *envp[]= {"HOME=/",NULL}; char *argv[]= {"/bin/nvram","godefault",NULL}; call_usermodehelper(argv[0],argv,envp,UMH_WAIT_EXEC); } /* Get Internal WiFi Activity Led for the given core */ /* Return 0, if cLED is not cofigured in the board parameters for the core */ /* else return cled name */ unsigned int kerSysGetWifiLed(unsigned char core) { unsigned short cled; unsigned char led_name = 0; switch (core) { case 0: if (BpGetWL0ActLedGpio(&cled) == BP_SUCCESS) led_name = kLedWL0; break; case 1: if (BpGetWL1ActLedGpio(&cled) == BP_SUCCESS) led_name = kLedWL1; break; default: led_name = 0; break; } /* GPIO not configured */ if (cled == 0) led_name = 0; printk("%s(%d) returned %d\n", __FUNCTION__, core, led_name); return led_name; } EXPORT_SYMBOL(kerSysGetWifiLed); void kerSysWifiLed(unsigned int led, unsigned int on) { kerSysLedCtrl(led, (on) ? kLedStateOn : kLedStateOff); } EXPORT_SYMBOL(kerSysWifiLed); #endif /* WIRELESS */ void __init board_wl_init(void) { #if defined (WIRELESS) kerSysScreenPciDevices(); kerSetWirelessPD(WLAN_ON); #endif ses_board_init(); return; } void __exit board_wl_deinit(void) { #if !defined(CONFIG_BCM963138) && !defined(CONFIG_BCM963148) ses_board_deinit(); #endif return; }