/*---------------------------------------------------------------------------* * Routine: RX62N_PWM_MTU_SetMatchRegister *---------------------------------------------------------------------------* * Description: * Configure one of the several match registers for this PWM bank. * Outputs: * void *aWorkspace -- PWM's workspace * TUInt8 aMatchRegister -- Index to match register (0-7) * TUInt32 aMatchPoint -- Number of PWM cycles until match * TBool aDoInterrupt -- ETrue if want an interrupt, else EFalse * (NOTE: Interrupts currently not * implemented) * TBool aDoCounterReset -- ETrue if counter for this PWM bank is * to be reset on match. * TBool aDoStop -- ETrue if counter is to be stopped * when match occurs. *---------------------------------------------------------------------------*/ static T_uezError RX62N_PWM_MTU_SetMatchRegister( void *aWorkspace, TUInt8 aMatchRegister, TUInt32 aMatchPoint, TBool aDoInterrupt, TBool aDoCounterReset, TBool aDoStop) { T_RX62N_MTU_Workspace *p = (T_RX62N_MTU_Workspace *)aWorkspace; const T_RX62N_MTU_Info *p_info = p->iInfo; if(aMatchRegister >= p_info->iNumOutputs) return UEZ_ERROR_ILLEGAL_ARGUMENT; aMatchPoint /= 2; // Adjust Fcclk to Fpclk *p_info->iTGR[aMatchRegister] = (aMatchPoint/4); if( p->iMatchCallback[aMatchRegister] && !InterruptIsRegistered(p_info->iVECT[aMatchRegister]) ) { InterruptRegister( p_info->iVECT[aMatchRegister], p_info->iVectISR[aMatchRegister], p->iISRPriority, p_info->iVectName[aMatchRegister]); *p_info->iTIER |= 1 << aMatchRegister; } return UEZ_ERROR_NONE; }
/*---------------------------------------------------------------------------* * Routine: IInitialize *---------------------------------------------------------------------------* * Description: * Initialize the EEPROM workspace. * Inputs: * T_EEPROM_NXP_LPC17xx_40xx_Workspace *p -- Workspace *---------------------------------------------------------------------------*/ static void IInitialize(T_EEPROM_NXP_LPC17xx_40xx_Workspace *p) { uint32_t v; LPC_EEPROM->PWRDWN = 0x0; v = PROCESSOR_OSCILLATOR_FREQUENCY / 375000; LPC_EEPROM->CLKDIV = v; v = LPC_EEPROM->CLKDIV; v = ((((PROCESSOR_OSCILLATOR_FREQUENCY / 1000000) * 15) / 1000) + 1); v |= (((((PROCESSOR_OSCILLATOR_FREQUENCY / 1000000) * 55) / 1000) + 1) << 8); v |= (((((PROCESSOR_OSCILLATOR_FREQUENCY / 1000000) * 35) / 1000) + 1) << 16); LPC_EEPROM->WSTATE = v; v = LPC_EEPROM->WSTATE; LPC_EEPROM->INTENSET = ((0x1 << END_OF_RDWR) | (0x1 << END_OF_PROG)); /* Enable the KFLASH Interrupt */ InterruptRegister( KFLASH_IRQn, IFlashIRQHandler, INTERRUPT_PRIORITY_NORMAL, "KFlash"); InterruptEnable(KFLASH_IRQn); UEZSemaphoreCreateBinary(&p->iIRQReadySem); p->iInitialized = ETrue; }
static HAL_Status RtkI2SIrqInit( IN PHAL_I2S_ADAPTER pI2SAdapter ) { PIRQ_HANDLE pIrqHandle; if (pI2SAdapter->DevNum > I2S_MAX_ID) { DBG_I2S_ERR("RtkI2SIrqInit: Invalid I2S Index(&d)\r\n", pI2SAdapter->DevNum); return HAL_ERR_PARA; } pIrqHandle = &pI2SAdapter->IrqHandle; switch (pI2SAdapter->DevNum){ case I2S0_SEL: pIrqHandle->IrqNum = I2S0_PCM0_IRQ; break; case I2S1_SEL: pIrqHandle->IrqNum = I2S1_PCM1_IRQ; break; default: return HAL_ERR_PARA; } pIrqHandle->Data = (u32) (pI2SAdapter); pIrqHandle->IrqFun = (IRQ_FUN) I2SISRHandle; pIrqHandle->Priority = 3; InterruptRegister(pIrqHandle); InterruptEn(pIrqHandle); return HAL_OK; }
void LPC17xx_40xx_SSP2_Require( T_uezGPIOPortPin aPinSCK2, T_uezGPIOPortPin aPinMISO2, T_uezGPIOPortPin aPinMOSI2, T_uezGPIOPortPin aPinSSEL2) { static const T_LPC17xx_40xx_IOCON_ConfigList sck2[] = { {GPIO_P1_0, IOCON_D_DEFAULT(4)}, }; static const T_LPC17xx_40xx_IOCON_ConfigList ssel2[] = { {GPIO_P1_8, IOCON_D_DEFAULT(4)}, }; static const T_LPC17xx_40xx_IOCON_ConfigList miso2[] = { {GPIO_P1_4, IOCON_D_DEFAULT(4)}, }; static const T_LPC17xx_40xx_IOCON_ConfigList mosi2[] = { {GPIO_P1_1, IOCON_D_DEFAULT(4)}, }; HAL_DEVICE_REQUIRE_ONCE(); // Register SSP2 HALInterfaceRegister("SSP2", (T_halInterface *)&SSP_LPC17xx_40xx_Port2_Interface, 0, 0); LPC17xx_40xx_IOCON_ConfigPinOrNone(aPinSCK2, sck2, ARRAY_COUNT(sck2)); LPC17xx_40xx_IOCON_ConfigPinOrNone(aPinSSEL2, ssel2, ARRAY_COUNT(ssel2)); LPC17xx_40xx_IOCON_ConfigPinOrNone(aPinMISO2, miso2, ARRAY_COUNT(miso2)); LPC17xx_40xx_IOCON_ConfigPinOrNone(aPinMOSI2, mosi2, ARRAY_COUNT(mosi2)); LPC17xx_40xxPowerOn(1<<20); // Setup interrupt, but do not enable InterruptRegister(SSP2_IRQn, ISSP2IRQ, INTERRUPT_PRIORITY_HIGH, "SSP2"); InterruptDisable(SSP2_IRQn); }
int32_t serial_send_stream_dma (serial_t *obj, char *ptxbuf, uint32_t len) { PHAL_RUART_OP pHalRuartOp; PHAL_RUART_ADAPTER pHalRuartAdapter=(PHAL_RUART_ADAPTER)&(obj->hal_uart_adp); u8 uart_idx = pHalRuartAdapter->UartIndex; int32_t ret; pHalRuartOp = &(obj->hal_uart_op); if ((serial_dma_en[uart_idx] & SERIAL_TX_DMA_EN)==0) { PUART_DMA_CONFIG pHalRuartDmaCfg; pHalRuartDmaCfg = &obj->uart_gdma_cfg; #if 0 pHalRuartOp->HalRuartTxGdmaLoadDef (pHalRuartAdapter, pHalRuartDmaCfg); pHalRuartOp->HalRuartDmaInit (pHalRuartAdapter); InterruptRegister(&pHalRuartDmaCfg->TxGdmaIrqHandle); InterruptEn(&pHalRuartDmaCfg->TxGdmaIrqHandle); serial_dma_en[uart_idx] |= SERIAL_TX_DMA_EN; #else if (HAL_OK == HalRuartTxGdmaInit(pHalRuartOp, pHalRuartAdapter, pHalRuartDmaCfg)) { serial_dma_en[uart_idx] |= SERIAL_TX_DMA_EN; } else { return HAL_BUSY; } #endif } ret = pHalRuartOp->HalRuartDmaSend(pHalRuartAdapter, (u8*)ptxbuf, len); return (ret); }
/*---------------------------------------------------------------------------* * Routine: RX62N_PWM_MTU_SetMaster *---------------------------------------------------------------------------* * Description: * PWM is going to start -- chip select enabled for device * Outputs: * void *aWorkspace -- Workspace for PWM * TUInt32 aPeriod -- Number of Fpclk intervals per period * TUInt8 aMatchRegister -- Which register is used for master counter *---------------------------------------------------------------------------*/ static T_uezError RX62N_PWM_MTU_SetMaster( void *aWorkspace, TUInt32 aPeriod, TUInt8 aMatchRegister) { T_RX62N_MTU_Workspace *p = (T_RX62N_MTU_Workspace *)aWorkspace; const T_RX62N_MTU_Info *p_info = p->iInfo; if(aMatchRegister >= p_info->iNumOutputs) return UEZ_ERROR_ILLEGAL_ARGUMENT; // Ensure MTU is on SYSTEM.MSTPCRA.LONG &= ~(1<<p_info->iMSTPBit); // MSTP(MTUx) = 0; // Ensure it is stopped *p_info->iTSTR &= ~(1<<p_info->iCSTBit); // CST = 0; // Set clear control bit to this match register if(aMatchRegister == 0) *p_info->iTCR = 1 << 5; else if(aMatchRegister == 1) *p_info->iTCR = 2 << 5; else if(aMatchRegister == 2) *p_info->iTCR = 5 << 5; else if(aMatchRegister == 3) *p_info->iTCR = 6 << 5; *p_info->iTCR |= 0 << 3; // Clock on rising edge *p_info->iTCR |= 1 << 0, // PCLK/4, for now *p_info->iTMDR = 2 << 0; // PWM mode 1: TMDR.MD = 2 aPeriod /= 2; // Adjust Fcclk to Fpclk // Set Period *p_info->iTGR[aMatchRegister] = (aPeriod/4); // Configure Interrupt if Needed if( p->iMatchCallback[aMatchRegister] && !InterruptIsRegistered(p_info->iVECT[aMatchRegister]) ) { InterruptRegister( p_info->iVECT[aMatchRegister], p_info->iVectISR[aMatchRegister], p->iISRPriority, p_info->iVectName[aMatchRegister]); *p_info->iTIER |= 1 << aMatchRegister; } // Set start bit *p_info->iTSTR |= (1<<p_info->iCSTBit); // CST = 1; return UEZ_ERROR_NONE; }
/*---------------------------------------------------------------------------* * Routine: LPC1768_Serial_Configure *---------------------------------------------------------------------------* * Description: * Link the serial port to a pair of callback routines and an * associated callback workspace. The callbacks are called when * a byte is received and when the transmit buffer becomes empty. * Inputs: * void *aWorkspace -- Serial port workspace * void *aCallbackWorkspace -- Callback's workspace * HAL_Serial_Callback_Received_Byte aReceivedByteCallback * -- Callback routine for received bytes * HAL_Serial_Callback_Transmit_Empty aTransmitEmptyCallback * -- Callback routine for transmit empty * Outputs: * T_uezError -- Error code *---------------------------------------------------------------------------*/ T_uezError LPC1768_Serial_Configure( void *aWorkspace, void *aCallbackWorkspace, HAL_Serial_Callback_Received_Byte aReceivedByteCallback, HAL_Serial_Callback_Transmit_Empty aTransmitEmptyCallback) { T_Serial_LPC1768_Workspace *p = (T_Serial_LPC1768_Workspace *)aWorkspace; const T_Serial_LPC1768_SerialInfo *p_info = p->iInfo; TUInt32 divider ; InterruptDisable(p->iInfo->iInterruptChannel); // Ensure power is on to the part // PCONP |= p->iPowerBit; // Configure the PCLK divider here to be CCLK/1 on UART0, 1/ // TBD: UART3 and 4 should be CCLK/1! SC->PCLKSEL0 = (SC->PCLKSEL0 & ~(3<<6)) | (1<<6); SC->PCLKSEL0 = (SC->PCLKSEL0 & ~(3<<8)) | (1<<8); SC->PCLKSEL1 = (SC->PCLKSEL1 & ~(3<<16)) | (1<<16); SC->PCLKSEL1 = (SC->PCLKSEL1 & ~(3<<18)) | (1<<18); p->iReceivedByteFunc = aReceivedByteCallback; p->iTransmitEmptyFunc = aTransmitEmptyCallback; p->iCallbackWorkspace = aCallbackWorkspace; divider = BAUD_DIVIDER(SERIAL_PORTS_DEFAULT_BAUD); // Set the FIFO enable bit in the FCR register. This bit must be set for // proper UART operation. p_info->iUART->u3.FCR = 7; // FCRFE|RFR|TFR // Set baudrate p_info->iUART->LCR |= 0x80; p_info->iUART->u1.DLL = divider & 0x00ff; p_info->iUART->u2.DLM = (divider >> 8) & 0x00ff; p_info->iUART->LCR &= ~0x80; // Set default mode (8 bits, 1 stop bit, no parity) p_info->iUART->LCR = 0x03; //Enable UART0 interrupts p_info->iUART->u2.IER = 0x03; // Interrupts and TX and RX InterruptRegister( p_info->iInterruptChannel, p_info->iISR, p_info->iPriority, p->iHAL->iInterface.iName); //TBD: For now, leave serial port deactivated // InterruptEnable(p_info->iInterruptChannel); return UEZ_ERROR_NONE; }
/*---------------------------------------------------------------------------* * Routine: USBSharedInterruptSetup *---------------------------------------------------------------------------* * Description: * Both Host and Device setup their interrupts by calling this routine * Outputs: * T_LPC247x_SSP_Workspace *aW -- Particular SSP workspace * SSP_Request *aRequest -- Configuration of SSP device *---------------------------------------------------------------------------*/ void USBSharedInterruptSetup(void) { if (!InterruptIsRegistered(USB_IRQn)) { InterruptRegister( USB_IRQn, ILPC17xx_40xx_USB_InterruptVector, INTERRUPT_PRIORITY_NORMAL, "USB"); InterruptEnable(USB_IRQn); } }
/*---------------------------------------------------------------------------* * Routine: *---------------------------------------------------------------------------* * Description: * * Inputs: * * Outputs: * *---------------------------------------------------------------------------*/ T_uezError LPC1768_I2S_config_TX( void *aWorkspace, HAL_I2S_Callback_Transmit_Low aTransmitLowCallback) { //Initialize the workspace T_lpc1768_i2s_Workspace *p = (T_lpc1768_i2s_Workspace *)aWorkspace; //Disable Interrupts //InterruptDisable(I2S_IRQn); //Power up the PCONP for the I2S LPC1768PowerOn(1 << 27); //Initialize function pointer p->iTransmitLowFunc = aTransmitLowCallback; //Setup the SDAO register //Disable data output (stop and reset, then release reset) I2S->I2SDAO |= 0x18; //I2SDAO &= 0x10; //Configure I2S output for I2S->I2SDAO = 0x18 | (I2S_SETTING_SAMPLE_SIZE_16BIT << 0) | (I2S_SETTING_SAMPLE_FORMAT_MONO << 2) | (0 << 5) | //only supporting mater mode at this time (15 << 6); //Cacluate the RATE and configure the register I2S->I2STXRATE = (1 << 8) | 2; I2S->I2STXBITRATE = (((PROCESSOR_OSCILLATOR_FREQUENCY) / 2) / (44100 * 16 * 1)); //Set the frequency of the I2S to be 36 MHz (divide 72 MHz PCLK by 2) //divided by a 44 kHz signal of 16 bits by 2 I2S->I2SIRQ = 0; // Set the TXFIFO depth to be 4 (sets irq flag) I2S->I2SIRQ &= ~(0xFF << 16); I2S->I2SIRQ |= (4 << 16); //Enable DAO (go and release reset) I2S->I2SDAO &= ~0x18; if (!intRegistered) { InterruptRegister(I2S_IRQn, ILPC1768_I2SInterruptHandler, INTERRUPT_PRIORITY_NORMAL, "I2S"); InterruptEnable(I2S_IRQn); intRegistered = 1; } G_lpc1768_i2s_Workspace = p; return UEZ_ERROR_NONE; }
/*---------------------------------------------------------------------------* * Routine: LPC2478_Serial_Configure *---------------------------------------------------------------------------* * Description: * Link the serial port to a pair of callback routines and an * associated callback workspace. The callbacks are called when * a byte is received and when the transmit buffer becomes empty. * Inputs: * void *aWorkspace -- Serial port workspace * void *aCallbackWorkspace -- Callback's workspace * HAL_Serial_Callback_Received_Byte aReceivedByteCallback * -- Callback routine for received bytes * HAL_Serial_Callback_Transmit_Empty aTransmitEmptyCallback * -- Callback routine for transmit empty * Outputs: * T_uezError -- Error code *---------------------------------------------------------------------------*/ T_uezError LPC2478_Serial_Configure( void *aWorkspace, void *aCallbackWorkspace, HAL_Serial_Callback_Received_Byte aReceivedByteCallback, HAL_Serial_Callback_Transmit_Empty aTransmitEmptyCallback) { T_Serial_LPC2478_Workspace *p = (T_Serial_LPC2478_Workspace *)aWorkspace; const T_Serial_LPC2478_SerialInfo *p_info = p->iInfo; TUInt32 divider ; InterruptDisable(p->iInfo->iInterruptChannel); // Ensure power is on to the part LPC2478PowerOn(1UL << p->iInfo->iPowerBitIndex); p->iReceivedByteFunc = aReceivedByteCallback; p->iTransmitEmptyFunc = aTransmitEmptyCallback; p->iCallbackWorkspace = aCallbackWorkspace; divider = PROCESSOR_OSCILLATOR_FREQUENCY; divider = BAUD_DIVIDER(SERIAL_PORTS_DEFAULT_BAUD); // Set the FIFO enable bit in the FCR register. This bit must be set for // proper UART operation. p_info->iUART->reg08.FCR = 7; // FCRFE|RFR|TFR // Set baudrate p_info->iUART->LCR |= 0x80; p_info->iUART->reg00.DLL = divider & 0x00ff; p_info->iUART->reg04.DLM = (divider >> 8) & 0x00ff; p_info->iUART->LCR &= ~0x80; // Set default mode (8 bits, 1 stop bit, no parity) p_info->iUART->LCR = 0x03; //Enable UART0 interrupts p_info->iUART->reg04.IER = 0x03; // Interrupts and TX and RX InterruptRegister( p_info->iInterruptChannel, p_info->iISR, p_info->iPriority, p->iHAL->iInterface.iName); //TBD: For now, leave serial port deactivated // InterruptEnable(p_info->iInterruptChannel); return UEZ_ERROR_NONE; }
/*---------------------------------------------------------------------------* * Routine: RX63N_ADC_S12AD_InitializeWorkspace *---------------------------------------------------------------------------* * Description: * Setup the RX63N S12AD workspace. * Inputs: * void *aW -- Particular ADC workspace * Outputs: * T_uezError -- Error code *---------------------------------------------------------------------------*/ T_uezError RX63N_ADC_S12AD_InitializeWorkspace(void *aWorkspace) { T_RX63N_ADC_Workspace *p = (T_RX63N_ADC_Workspace *)aWorkspace; G_S12ADWorkspace = p; p->iInterruptChannel = VECT_S12AD0_S12ADI0; // Register an interrupt for this ADC but don't start it. InterruptRegister( p->iInterruptChannel, IRX63N_ADC_S12AD_Interrupt, INTERRUPT_PRIORITY_NORMAL, "S12AD"); return UEZ_ERROR_NONE; }
/*---------------------------------------------------------------------------* * Routine: RX62N_PWM_MTU_EnableSingleEdgeOutput *---------------------------------------------------------------------------* * Description: * PWM is going to have a single edge output (high until matches, then * low, reset counter goes back to high). * Inputs: * void *aWorkspace -- PWM's workspace * TUInt8 aMatchRegister -- Point in Fpclk cycles where PWM switches * Outputs: * T_uezError -- UEZ_ERROR_NONE *---------------------------------------------------------------------------*/ static T_uezError RX62N_PWM_MTU_EnableSingleEdgeOutput( void *aWorkspace, TUInt8 aMatchRegister) { T_RX62N_MTU_Workspace *p = (T_RX62N_MTU_Workspace *)aWorkspace; const T_RX62N_MTU_Info *p_info = p->iInfo; TUInt8 i; if(aMatchRegister >= p_info->iNumOutputs) return UEZ_ERROR_ILLEGAL_ARGUMENT; // This needs to be changed once there is a rx62n timer driver // - for now, if a callback is set, output is software controlled if( p->iMatchCallback[aMatchRegister] && !InterruptIsRegistered(p_info->iVECT[aMatchRegister]) ) { InterruptRegister( p_info->iVECT[aMatchRegister], p_info->iVectISR[aMatchRegister], p->iISRPriority, p_info->iVectName[aMatchRegister]); *p_info->iTIER |= 1 << aMatchRegister; } if(!InterruptIsRegistered(p_info->iVECT[aMatchRegister])) { if(aMatchRegister == 0) *p_info->iTIORH |= 5; else if(aMatchRegister == 1) *p_info->iTIORH |= (1<<5); else if(aMatchRegister == 2) *p_info->iTIORL |= 5; else if(aMatchRegister == 3) *p_info->iTIORL |= (1<<5); } else { // Enable any registered interrupts for(i=0; i<p_info->iNumOutputs; i++) { if(InterruptIsRegistered(p_info->iVECT[i])) InterruptEnable(p_info->iVECT[i]); } } return UEZ_ERROR_NONE; }
VOID HalMiiGmacInitIrqRtl8195a( IN VOID *Data ) { IRQ_HANDLE MiiIrqHandle_Master; PMII_ADAPTER pMiiAdapter = (PMII_ADAPTER) Data; MiiIrqHandle_Master.Data = (u32) (pMiiAdapter); MiiIrqHandle_Master.IrqNum = GMAC_IRQ; MiiIrqHandle_Master.IrqFun = (IRQ_FUN) MiiIrqHandle; MiiIrqHandle_Master.Priority = 0; InterruptRegister(&MiiIrqHandle_Master); InterruptEn(&MiiIrqHandle_Master); }
/** * Load UART HAL GDMA default setting * * Call this function to load the default setting for UART GDMA * * */ VOID HalRuartTxGdmaInit( PRUART_ADAPTER pRuartAdapter ) { PHAL_RUART_OP pHalRuartOp; PHAL_RUART_ADAPTER pHalRuartAdapter; PUART_DMA_CONFIG pUartGdmaConfig; PHAL_GDMA_ADAPTER pHalGdmaAdapter; if (NULL == pRuartAdapter) { return; } pHalRuartOp = pRuartAdapter->pHalRuartOp; pHalRuartAdapter = pRuartAdapter->pHalRuartAdapter; pUartGdmaConfig = pRuartAdapter->pHalRuartDmaCfg; if ((NULL == pHalRuartOp) || (NULL == pHalRuartAdapter) || (NULL == pUartGdmaConfig)) { return; } // Load default setting if (pHalRuartOp->HalRuartTxGdmaLoadDef != NULL) { HalGdmaOpInit((VOID*) (pUartGdmaConfig->pHalGdmaOp)); pHalRuartOp->HalRuartTxGdmaLoadDef (pHalRuartAdapter, pUartGdmaConfig); } else { // Initial your GDMA setting here } // Start to patch the default setting pHalGdmaAdapter = (PHAL_GDMA_ADAPTER)pUartGdmaConfig->pTxHalGdmaAdapter; pHalGdmaAdapter->GdmaIndex = 0; // GDMA0 pHalGdmaAdapter->ChNum = 4; // GDMA Channel pHalGdmaAdapter->ChEn = GdmaCh4; // GDMA Channel Enable // pUartGdmaConfig->TxGdmaIrqHandle.Data = pHalRuartAdapter; pUartGdmaConfig->TxGdmaIrqHandle.IrqNum = GDMA0_CHANNEL4_IRQ; // pUartGdmaConfig->TxGdmaIrqHandle.IrqFun = (IRQ_FUN)_UartTxDmaIrqHandle pUartGdmaConfig->TxGdmaIrqHandle.Priority = 0x20; pHalRuartOp->HalRuartDmaInit (pHalRuartAdapter); InterruptRegister(&pUartGdmaConfig->TxGdmaIrqHandle); InterruptEn(&pUartGdmaConfig->TxGdmaIrqHandle); }
/* PitInitialize * Initializes the PIT unit on the system. */ OsStatus_t PitInitialize(void) { DeviceInterrupt_t Interrupt = { { 0 } }; size_t Divisor = 1193181; // Debug TRACE("PitInitialize()"); // Allocate a new instance of the pit-data memset(&PitUnit, 0, sizeof(Pit_t)); // Initialize the interrupt request Interrupt.Line = PIT_IRQ; Interrupt.Pin = INTERRUPT_NONE; Interrupt.Vectors[0] = INTERRUPT_NONE; Interrupt.FastInterrupt.Handler = PitInterrupt; PitUnit.NsTick = 1000; // Install interrupt in system // Install a fast interrupt handler PitUnit.Irq = InterruptRegister(&Interrupt, INTERRUPT_NOTSHARABLE | INTERRUPT_KERNEL); // Register our irq as a system timer if (PitUnit.Irq != UUID_INVALID) { TimersRegisterSystemTimer(PitUnit.Irq, PitUnit.NsTick, PitGetTicks, PitResetTicks); } else { ERROR("Failed to register interrupt"); return OsError; } // We want a frequncy of 1000 hz Divisor /= 1000; // We use counter 0, select counter 0 and configure it WriteDirectIo(DeviceIoPortBased, PIT_IO_BASE + PIT_REGISTER_COMMAND, 1, PIT_COMMAND_MODE3 | PIT_COMMAND_FULL | PIT_COMMAND_COUNTER_0); // Write divisor to the PIT chip WriteDirectIo(DeviceIoPortBased, PIT_IO_BASE + PIT_REGISTER_COUNTER0, 1, Divisor & 0xFF); WriteDirectIo(DeviceIoPortBased, PIT_IO_BASE + PIT_REGISTER_COUNTER0, 1, (Divisor >> 8) & 0xFF); return OsSuccess; }
void LPC17xx_40xx_SSP1_Require( T_uezGPIOPortPin aPinSCK1, T_uezGPIOPortPin aPinMISO1, T_uezGPIOPortPin aPinMOSI1, T_uezGPIOPortPin aPinSSEL1) { static const T_LPC17xx_40xx_IOCON_ConfigList sck1[] = { {GPIO_P0_7, IOCON_W_DEFAULT(2)}, {GPIO_P1_19, IOCON_D_DEFAULT(5)}, {GPIO_P1_31, IOCON_A_DEFAULT(2)}, {GPIO_P4_20, IOCON_D_DEFAULT(3)}, }; static const T_LPC17xx_40xx_IOCON_ConfigList ssel1[] = { {GPIO_P0_6, IOCON_D_DEFAULT(2)}, {GPIO_P0_14, IOCON_D_DEFAULT(2)}, {GPIO_P4_21, IOCON_D_DEFAULT(3)}, }; static const T_LPC17xx_40xx_IOCON_ConfigList miso1[] = { {GPIO_P0_8, IOCON_W_DEFAULT(2)}, {GPIO_P0_12, IOCON_A_DEFAULT(2)}, {GPIO_P1_18, IOCON_D_DEFAULT(5)}, {GPIO_P4_22, IOCON_D_DEFAULT(3)}, }; static const T_LPC17xx_40xx_IOCON_ConfigList mosi1[] = { {GPIO_P0_9, IOCON_W_DEFAULT(2)}, {GPIO_P0_13, IOCON_A_DEFAULT(2)}, {GPIO_P1_22, IOCON_D_DEFAULT(5)}, {GPIO_P4_23, IOCON_D_DEFAULT(3)}, }; HAL_DEVICE_REQUIRE_ONCE(); // Register SSP1 HALInterfaceRegister("SSP1", (T_halInterface *)&SSP_LPC17xx_40xx_Port1_Interface, 0, 0); LPC17xx_40xx_IOCON_ConfigPinOrNone(aPinSCK1, sck1, ARRAY_COUNT(sck1)); LPC17xx_40xx_IOCON_ConfigPinOrNone(aPinSSEL1, ssel1, ARRAY_COUNT(ssel1)); LPC17xx_40xx_IOCON_ConfigPinOrNone(aPinMISO1, miso1, ARRAY_COUNT(miso1)); LPC17xx_40xx_IOCON_ConfigPinOrNone(aPinMOSI1, mosi1, ARRAY_COUNT(mosi1)); LPC17xx_40xxPowerOn(1<<10); // Setup interrupt, but do not enable InterruptRegister(SSP1_IRQn, ISSP1IRQ, INTERRUPT_PRIORITY_HIGH, "SSP1"); InterruptDisable(SSP1_IRQn); }
/* * InitDebugging: * * - check for WDEBUG.386 * - register an interrupt handler (for handling 16-bit faults) * - register a notify handler (for receiving all system notifications) * - if we have WDEBUG.386, then we load WINT32.DLL, get all its entry * points, and then tell it we want to handle 32-bit faults * - we then get a data segment alias for our code segment, so that we * can write stuff into our code segment (see FAULT.C) * */ char *InitDebugging( void ) { DebuggerState=ACTIVE; StartWDebug386(); faultInstance = MakeProcInstance( (FARPROC)IntHandler, Instance ); if( !InterruptRegister( NULL, faultInstance ) ) { return( TRP_WIN_Failed_to_get_interrupt_hook ); } notifyInstance = MakeProcInstance( (FARPROC)NotifyHandler, Instance ); if( !NotifyRegister( NULL, (LPFNNOTIFYCALLBACK)notifyInstance, NF_NORMAL | NF_RIP ) ) { return( TRP_WIN_Failed_to_get_notify_hook ); } Out(( OUT_INIT,"ds=%04x, faultInstance=%Fp, notifyInstance=%Fp,Instance=%04x", FP_SEG( &faultInstance ), faultInstance, notifyInstance, Instance )); if( WDebug386 ) { wint32 = LoadLibrary( "wint32.dll" ); if( (UINT)wint32 < 32 ) { WDebug386 = FALSE; } else { DoneWithInterrupt = (LPVOID) GetProcAddress( wint32, "DoneWithInterrupt" ); GetDebugInterruptData = (LPVOID) GetProcAddress( wint32, "GetDebugInterruptData" ); ResetDebugInterrupts32 = (LPVOID) GetProcAddress( wint32, "ResetDebugInterrupts32" ); SetDebugInterrupts32 = (LPVOID) GetProcAddress( wint32, "SetDebugInterrupts32" ); DebuggerIsExecuting = (LPVOID) GetProcAddress( wint32, "DebuggerIsExecuting" ); if( !SetDebugInterrupts32() ) { WDebug386 = FALSE; FreeLibrary( wint32 ); } else { DebuggerIsExecuting( 1 ); Out((OUT_INIT,"Hooked Interrupts")); } } } // SubClassProcInstance = MakeProcInstance( (FARPROC)SubClassProc, Instance ); InitDebugHook(); CSAlias = AllocCSToDSAlias( CS() ); return( "" ); } /* InitDebugging */
/*---------------------------------------------------------------------------* * Requirement routines: *---------------------------------------------------------------------------*/ void LPC17xx_40xx_SSP0_Require( T_uezGPIOPortPin aPinSCK0, T_uezGPIOPortPin aPinMISO0, T_uezGPIOPortPin aPinMOSI0, T_uezGPIOPortPin aPinSSEL0) { static const T_LPC17xx_40xx_IOCON_ConfigList sck0[] = { {GPIO_P0_15, IOCON_D_DEFAULT(2)}, {GPIO_P1_20, IOCON_D_DEFAULT(5)}, {GPIO_P2_22, IOCON_D_DEFAULT(2)}, }; static const T_LPC17xx_40xx_IOCON_ConfigList ssel0[] = { {GPIO_P0_16, IOCON_D_DEFAULT(2)}, {GPIO_P1_21, IOCON_D_DEFAULT(3)}, {GPIO_P1_28, IOCON_D_DEFAULT(5)}, {GPIO_P2_23, IOCON_D_DEFAULT(2)}, }; static const T_LPC17xx_40xx_IOCON_ConfigList miso0[] = { {GPIO_P0_17, IOCON_D_DEFAULT(2)}, {GPIO_P1_23, IOCON_D_DEFAULT(5)}, {GPIO_P2_26, IOCON_D_DEFAULT(2)}, }; static const T_LPC17xx_40xx_IOCON_ConfigList mosi0[] = { {GPIO_P0_18, IOCON_D_DEFAULT(2)}, {GPIO_P1_24, IOCON_D_DEFAULT(5)}, {GPIO_P2_27, IOCON_D_DEFAULT(2)}, }; HAL_DEVICE_REQUIRE_ONCE(); // Register SSP0 HALInterfaceRegister("SSP0", (T_halInterface *)&SSP_LPC17xx_40xx_Port0_Interface, 0, 0); LPC17xx_40xx_IOCON_ConfigPinOrNone(aPinSCK0, sck0, ARRAY_COUNT(sck0)); LPC17xx_40xx_IOCON_ConfigPinOrNone(aPinSSEL0, ssel0, ARRAY_COUNT(ssel0)); LPC17xx_40xx_IOCON_ConfigPinOrNone(aPinMISO0, miso0, ARRAY_COUNT(miso0)); LPC17xx_40xx_IOCON_ConfigPinOrNone(aPinMOSI0, mosi0, ARRAY_COUNT(mosi0)); LPC17xx_40xxPowerOn(1<<21); // Setup interrupt, but do not enable InterruptRegister(SSP0_IRQn, ISSP0IRQ, INTERRUPT_PRIORITY_HIGH, "SSP0"); InterruptDisable(SSP0_IRQn); }
/*---------------------------------------------------------------------------* * Routine: LPC2478_GPDMA_Enable *---------------------------------------------------------------------------* * Description: * Enable GPDMA controller and register interrupt handler. * Inputs: * void *aW -- Particular GPDMA workspace * Outputs: * T_uezError -- Error code *---------------------------------------------------------------------------*/ static void LPC2478_GPDMA_Enable(void *aWorkspace) { (void)aWorkspace; // Increase number of G_opened channels. G_opened++; // Enable peripheral power PCONP |= PCONP_PCGPDMA; // Was registered already? if(EFalse == InterruptIsRegistered(INTERRUPT_CHANNEL_GP_DMA)) { // Enable interrupt. InterruptRegister(INTERRUPT_CHANNEL_GP_DMA, (TISRFPtr)IGPDMA, INTERRUPT_PRIORITY_NORMAL, "GPDMA"); InterruptEnable(INTERRUPT_CHANNEL_GP_DMA); } // Enable GPDMA by writing ENABLE bit. // Always little-endian. DMACConfiguration = DMACConfiguration_E; }
/*---------------------------------------------------------------------------* * Routine: LPC247x_Timer_SetMatchCallback *---------------------------------------------------------------------------* * Description: * Setup a callback routine for this timer on one of the match * registers. The callback is called when a match occurs and an * interrupt occurs. The callback is called from within the ISR. * Inputs: * void *aWorkspace -- Timer workspace * TUInt8 aMatchRegister -- Which match register to set callback * T_Timer_Callback aCallbackFunc -- Function to call, or 0 to clear. * void *aCallbackWorkspace -- Workspace to pass to callback * Outputs: * T_uezError -- UEZ_ERROR_ILLEGAL_PARAMETER if match register is out * of range. *---------------------------------------------------------------------------*/ static T_uezError LPC1756_Timer_SetMatchCallback( void *aWorkspace, TUInt8 aMatchRegister, T_HALTimer_Callback aCallbackFunc, void *aCallbackWorkspace) { T_LPC1756_Timer_Workspace *p = (T_LPC1756_Timer_Workspace *)aWorkspace; TBool any; TUInt8 i; // Determine if legal match register if (aMatchRegister >= 4) return UEZ_ERROR_ILLEGAL_PARAMETER; // Set the callback (which can be 0 as well as an address) p->iCallbacks[aMatchRegister].iCallbackFunc = aCallbackFunc; p->iCallbacks[aMatchRegister].iCallbackWorkspace = aCallbackWorkspace; // Check to see if there are any callbacks any = EFalse; for (i = 0; i < 4; i++) { if (p->iCallbacks[i].iCallbackFunc) { any = ETrue; break; } } // Register or deregister the interrupt if (any) { // Register if not already registered if (!InterruptIsRegistered(p->iInfo->iVector)) InterruptRegister(p->iInfo->iVector, p->iInfo->iISR, INTERRUPT_PRIORITY_HIGH, p->iInfo->iName); InterruptEnable(p->iInfo->iVector); } else { // No one registered anymore, turn off this callback (but leave registered) InterruptDisable(p->iInfo->iVector); } return UEZ_ERROR_NONE; }
/** * Load UART HAL default setting * * Call this function to load the default setting for UART HAL adapter * * */ VOID HalRuartAdapterInit( PRUART_ADAPTER pRuartAdapter, u8 UartIdx ) { PHAL_RUART_OP pHalRuartOp; PHAL_RUART_ADAPTER pHalRuartAdapter; if (NULL == pRuartAdapter) { return; } pHalRuartOp = pRuartAdapter->pHalRuartOp; pHalRuartAdapter = pRuartAdapter->pHalRuartAdapter; if ((NULL == pHalRuartOp) || (NULL == pHalRuartAdapter)) { return; } // Load default setting if (pHalRuartOp->HalRuartAdapterLoadDef != NULL) { pHalRuartOp->HalRuartAdapterLoadDef (pHalRuartAdapter, UartIdx); } else { // Initial your UART HAL adapter here } // Start to modify the defualt setting pHalRuartAdapter->PinmuxSelect = RUART0_MUX_TO_GPIOC; pHalRuartAdapter->BaudRate = 38400; // pHalRuartAdapter->IrqHandle.IrqFun = (IRQ_FUN)_UartIrqHandle; // pHalRuartAdapter->IrqHandle.Data = (void *)pHalRuartAdapter; // pHalRuartAdapter->IrqHandle.Priority = 0x20; // Register IRQ InterruptRegister(&pHalRuartAdapter->IrqHandle); }
/*---------------------------------------------------------------------------* * Routine: ExternalInterrupt_NXP_LPC1756_Set *---------------------------------------------------------------------------* * Description: * Set the rate of a given blink register (as close as possible). * Inputs: * void *aW -- Workspace * TUInt32 aChannel -- EINT channel (0 to 3) * TUInt8 aTrigger -- Trigger type (if used) * EINTCallback aCallbackFunc -- Function to call when trigger. * void *aCallbackWorkspace -- Parameter to pass to callback function. * Outputs: * T_uezError -- Error code *---------------------------------------------------------------------------*/ T_uezError ExternalInterrupt_NXP_LPC1756_Set( void *aWorkspace, TUInt32 aChannel, T_EINTTrigger aTrigger, EINT_Callback aCallbackFunc, void *aCallbackWorkspace, T_EINTPriority aPriority, const char *aName) { TUInt32 irqNum; T_ExternalInterrupt_NXP_LPC1756_Workspace *p = (T_ExternalInterrupt_NXP_LPC1756_Workspace *)aWorkspace; T_eintCallback *p_callback; T_uezError error = UEZ_ERROR_NONE; IGrab(p); // Fake loop while (1) { // Is this a valid channel? if (aChannel >= NUM_EXTERNAL_INTERRUPTS) { error = UEZ_ERROR_OUT_OF_RANGE; break; } // Is this external interrupt already in use? p_callback = G_eintCallbacks+aChannel; if (p_callback->iCallbackFunc) { error = UEZ_ERROR_ALREADY_EXISTS; break; } // Is this interrupt already registered? irqNum = EINT0_IRQn+aChannel; if (InterruptIsRegistered(irqNum)) { error = UEZ_ERROR_NOT_AVAILABLE; break; } // Interrupt is available. Register it p_callback->iPriority = (T_irqPriority) aPriority; p_callback->iTrigger = aTrigger; p_callback->iCallbackWorkspace = aCallbackWorkspace; p_callback->iCallbackFunc = aCallbackFunc; // Start disabled InterruptDisable(irqNum); InterruptRegister( irqNum, G_eintFuncs[aChannel], (T_irqPriority) aPriority, aName); // Setup the proper mode (edge or level) if ((aTrigger == EINT_TRIGGER_EDGE_FALLING) || (aTrigger == EINT_TRIGGER_EDGE_RISING)) { // Edge triggered SC->EXTMODE |= (1 << aChannel); } else { // Level triggered SC->EXTMODE &= ~(1 << aChannel); } // Setup the proper polarity if ((aTrigger == EINT_TRIGGER_LEVEL_HIGH) || (aTrigger == EINT_TRIGGER_EDGE_RISING)) { // high or rising is 1 SC->EXTPOLAR |= (1 << aChannel); } else { // low or falling is 0 SC->EXTPOLAR &= ~(1 << aChannel); } // Make sure the external interrupt has been cleared SC->EXTINT = (1<<aChannel); // Do not loop break; } IRelease(p); return error; }
//--------------------------------------------------------------------------------------------------- //Function Name: // RtkI2CIrqInit // // Description: // I2C interrupt initialization function. // For I2C interrupt operation mode, I2C module MUST register itself to the platform // by providing the interrupt handler which contains interrupt input data (arguments), // interrupt service routine, interrupt number, interrupt priority. And then the interrupt // should be enabled. // // Arguments: // [in] VOID *Data - // I2C SAL handle // // Return: // The status of the I2C interrupt initialization process. // _EXIT_SUCCESS if the RtkI2CIrqInit succeeded. // _EXIT_FAILURE if the RtkI2CIrqInit failed. // // Note: // NA // // See Also: // NA // // Author: // By Jason Deng, 2014-04-03. // //---------------------------------------------------------------------------------------------------- static RTK_STATUS RtkDACDMAInit( IN PSAL_DAC_HND pSalDACHND ){ PSAL_DAC_HND_PRIV pSalDACHNDPriv = NULL; PSAL_DAC_MNGT_ADPT pSalDACMngtAdpt = NULL; PHAL_GDMA_ADAPTER pHALDACGdmaAdpt = NULL; PHAL_GDMA_OP pHALDACGdmaOp = NULL; PIRQ_HANDLE pIrqHandleDACGdma = NULL; /* To Get the SAL_I2C_MNGT_ADPT Pointer */ pSalDACHNDPriv = CONTAINER_OF(pSalDACHND, SAL_DAC_HND_PRIV, SalDACHndPriv); pSalDACMngtAdpt = CONTAINER_OF(pSalDACHNDPriv->ppSalDACHnd, SAL_DAC_MNGT_ADPT, pSalHndPriv); pHALDACGdmaAdpt = pSalDACMngtAdpt->pHalGdmaAdp; pHALDACGdmaOp = pSalDACMngtAdpt->pHalGdmaOp; pIrqHandleDACGdma = pSalDACMngtAdpt->pIrqGdmaHnd; if (RtkDACIdxChk(pSalDACHND->DevNum)) return _EXIT_FAILURE; HalGdmaOpInit(pHALDACGdmaOp); _memset((void *)pHALDACGdmaAdpt, 0, sizeof(HAL_GDMA_ADAPTER)); pHALDACGdmaAdpt->GdmaCtl.IntEn = 1; //DAC TX DMA pHALDACGdmaAdpt->GdmaCtl.SrcTrWidth = TrWidthFourBytes; pHALDACGdmaAdpt->GdmaCtl.DstTrWidth = TrWidthFourBytes; pHALDACGdmaAdpt->GdmaCtl.SrcMsize = MsizeFour; pHALDACGdmaAdpt->GdmaCtl.DestMsize = MsizeFour; pHALDACGdmaAdpt->GdmaCtl.Sinc = IncType; pHALDACGdmaAdpt->GdmaCtl.Dinc = NoChange; pHALDACGdmaAdpt->GdmaCtl.Done = 1; pHALDACGdmaAdpt->GdmaCtl.TtFc = (GDMA_CTL_TT_FC_TYPE)0x01; pHALDACGdmaAdpt->GdmaCfg.DestPer = 13; pHALDACGdmaAdpt->GdmaCfg.ReloadSrc = 1; pHALDACGdmaAdpt->MuliBlockCunt = 1; pHALDACGdmaAdpt->MaxMuliBlock = 50000;//MaxLlp; pHALDACGdmaAdpt->GdmaIsrType = (BlockType|TransferType|ErrType); pHALDACGdmaAdpt->IsrCtrl = ENABLE; pHALDACGdmaAdpt->GdmaOnOff = ON; pHALDACGdmaAdpt->ChNum = 4; pHALDACGdmaAdpt->ChEn = GdmaCh4; pHALDACGdmaAdpt->TestItem = 3; //DBG_8195A("pSalDACHND->DevNum:%x\n",pSalDACHND->DevNum); switch (pSalDACHND->DevNum){ #if DAC0_USED case DAC0_SEL: { pHALDACGdmaAdpt->GdmaIndex = 0; pIrqHandleDACGdma->IrqNum = GDMA0_CHANNEL4_IRQ; break; } #endif #if DAC1_USED case DAC1_SEL: { pHALDACGdmaAdpt->GdmaIndex = 1; pIrqHandleDACGdma->IrqNum = GDMA1_CHANNEL4_IRQ; break; } #endif default: return _EXIT_FAILURE; } /* GDMA interrupt register */ pIrqHandleDACGdma->Data = (u32) (pSalDACMngtAdpt); pIrqHandleDACGdma->IrqFun = (IRQ_FUN) DACGDMAISRHandle; pIrqHandleDACGdma->Priority = 2; InterruptRegister(pIrqHandleDACGdma); InterruptEn(pIrqHandleDACGdma); /* GDMA initialization */ /* Enable the whole GDMA module first */ if (pHALDACGdmaAdpt->GdmaIndex == 0) { ACTCK_GDMA0_CCTRL(ON); SLPCK_GDMA0_CCTRL(ON); GDMA0_FCTRL(ON); } else { ACTCK_GDMA1_CCTRL(ON); SLPCK_GDMA1_CCTRL(ON); GDMA1_FCTRL(ON); } pHALDACGdmaOp->HalGdmaOnOff((VOID*)pHALDACGdmaAdpt); pHALDACGdmaOp->HalGdmaChIsrEnAndDis((VOID*)pHALDACGdmaAdpt); pHALDACGdmaOp->HalGdmaChSeting((VOID*)pHALDACGdmaAdpt); return _EXIT_SUCCESS; }
/*---------------------------------------------------------------------------* * Routine: ExternalInterrupt_Renesas_RX62N_Set *---------------------------------------------------------------------------* * Description: * Set the rate of a given blink register (as close as possible). * Inputs: * void *aWorkspace -- Workspace * TUInt32 aChannel -- EINT channel (0 to 15) * TUInt8 aTrigger -- Trigger type (if used) * EINTCallback aCallbackFunc -- Function to call when trigger. * void *aCallbackWorkspace -- Parameter to pass to callback function. * Outputs: * T_uezError -- Error code *---------------------------------------------------------------------------*/ T_uezError ExternalInterrupt_Renesas_RX62N_Set( void *aWorkspace, TUInt32 aChannel, T_EINTTrigger aTrigger, EINT_Callback aCallbackFunc, void *aCallbackWorkspace, T_irqPriority aPriority, const char *aName) { TUInt32 irqNum; // T_ExternalInterrupt_Renesas_RX62N_Workspace *p = // (T_ExternalInterrupt_Renesas_RX62N_Workspace *)aWorkspace; T_eintEntry *p_entry; T_uezError error = UEZ_ERROR_NONE; TUInt8 edge; const T_ExternalInterrupt_Renesas_RX62N_Info *p_info; HAL_GPIOPort **p_gpio; TUInt32 gpioPinIndex; // Fake loop while (1) { // Is this a valid channel? if (aChannel >= NUM_EXTERNAL_INTERRUPTS) { error = UEZ_ERROR_OUT_OF_RANGE; break; } // Is this external interrupt already in use? p_entry = G_eintEntries + aChannel; if (p_entry->iCallbackFunc) { error = UEZ_ERROR_ALREADY_EXISTS; break; } // Is this interrupt already registered? irqNum = VECT_ICU_IRQ0 + aChannel; if (InterruptIsRegistered(irqNum)) { error = UEZ_ERROR_NOT_AVAILABLE; break; } // Interrupt is available. Register it p_entry->iPriority = aPriority; p_entry->iTrigger = aTrigger; p_entry->iCallbackWorkspace = aCallbackWorkspace; p_entry->iCallbackFunc = aCallbackFunc; // Start disabled InterruptDisable(irqNum); // Find the info about this pin p_info = G_eintInfo + aChannel; error = HALInterfaceFind((p_entry->iIsPinSetB) ? p_info->iGPIONameB : p_info->iGPIONameA, (T_halWorkspace **)&p_gpio); if (error) break; gpioPinIndex = (p_entry->iIsPinSetB) ? p_info->iGPIOPinIndexB : p_info->iGPIOPinIndexA; (*p_gpio)->SetInputMode(p_gpio, (1<<gpioPinIndex)); (*p_gpio)->Control(p_gpio, gpioPinIndex, GPIO_CONTROL_ENABLE_INPUT_BUFFER, 0); // Map the trigger type to a constant switch (aTrigger) { case EINT_TRIGGER_EDGE_FALLING: edge = (1 << 3); break; case EINT_TRIGGER_EDGE_RISING: edge = (2 << 3); break; case EINT_TRIGGER_LEVEL_LOW: edge = (0 << 3); break; case EINT_TRIGGER_EDGE_BOTH: edge = (3 << 3); break; case EINT_TRIGGER_LEVEL_HIGH: default: edge = 0xFF; break; } if (edge == 0xFF) { error = UEZ_ERROR_INVALID_PARAMETER; break; } ICU.IRQCR[aChannel].BYTE = edge; // Clear the interrupt ICU.IR[irqNum].BIT.IR = 0; InterruptRegister(irqNum, G_eintFuncs[aChannel], aPriority, aName); // Do not loop break; } return error; }