diff --git a/ChangeLog b/ChangeLog index de41ca5b15..d209477565 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6618,3 +6618,7 @@ * drivers/lcd/mio283qt9a.c: Bug fix from Toby Duckwork (2014-2-19). * fs/fs_rename.c: 'rename' can now be used to rename nodes in the pseudo-filesystem (2014-2-19). + * arch/arm/src/samd/sam_sercom.c: Move some common SERCOM logic + from the USART-specific files to a share-able file where it can + also be used by SPI and I2C drivers (2014-2-19). + diff --git a/arch/arm/src/samd/Make.defs b/arch/arm/src/samd/Make.defs index a60ff623e2..569d31b572 100644 --- a/arch/arm/src/samd/Make.defs +++ b/arch/arm/src/samd/Make.defs @@ -69,7 +69,8 @@ endif CHIP_ASRCS = CHIP_CSRCS = sam_clockconfig.c sam_idle.c sam_irq.c sam_lowputc.c -CHIP_CSRCS += sam_port.c sam_serial.c sam_start.c sam_timerisr.c sam_usart.c +CHIP_CSRCS += sam_port.c sam_sercom.c sam_serial.c sam_start.c +CHIP_CSRCS += sam_timerisr.c sam_usart.c ifeq ($(CONFIG_NUTTX_KERNEL),y) CHIP_CSRCS += sam_userspace.c diff --git a/arch/arm/src/samd/sam_lowputc.c b/arch/arm/src/samd/sam_lowputc.c index 376358e972..271d23cb7e 100644 --- a/arch/arm/src/samd/sam_lowputc.c +++ b/arch/arm/src/samd/sam_lowputc.c @@ -95,101 +95,6 @@ sam_wait_synchronization(const struct sam_usart_config_s * const config) } #endif -/**************************************************************************** - * Name: sam_gclk_configure - * - * Description: - * Configure the SERCOM USART source clock. - * - * Two generic clocks are used by the SERCOM: GCLK_SERCOMx_CORE and - * GCLK_SERCOMx_SLOW. The core clock (GCLK_SERCOMx_CORE) is required to - * clock the SERCOM while operating as a master, while the slow clock - * (GCLK_SERCOM_SLOW) is only required for certain functions. SERCOM - * modules must share the same slow GCLK channel ID. - * - * The baud-rate generator runs off the GCLK_SERCOMx_CORE clock (or, - * optionally, external clock). - * - ****************************************************************************/ - -#ifdef HAVE_USART -static inline void -sam_gclk_configure(const struct sam_usart_config_s * const config) -{ - uint16_t regval; - uint8_t glckcore; - - /* Set up the SERCOMn_GCLK_ID_CORE clock */ - - glckcore = (uint8_t)SERCOM_GCLK_ID_CORE(config->sercom); - regval = ((uint16_t)glckcore << GCLK_CLKCTRL_ID_SHIFT); - - /* Select and disable the SERCOMn_GCLK_ID_CORE generic clock */ - - putreg16(regval, SAM_GCLK_CLKCTRL); - - /* Wait for clock to become disabled */ - - while ((getreg16(SAM_GCLK_CLKCTRL) & GCLK_CLKCTRL_CLKEN) != 0); - - /* Select the SERCOMn_GCLK_ID_CORE source clock generator */ - - regval |= (uint16_t)config->gclkgen << GCLK_CLKCTRL_GEN_SHIFT; - -#if 0 /* Not yet supported */ - /* Enable write lock if requested to prevent further modification */ - - if (config->wrlock) - { - regval |= GCLK_CLKCTRL_WRTLOCK; - } -#endif - - /* Write the new configuration */ - - putreg16(regval, SAM_GCLK_CLKCTRL); - - /* Enable the SERCOMn_GCLK_ID_CORE generic clock */ - - regval |= GCLK_CLKCTRL_CLKEN; - putreg16(regval, SAM_GCLK_CLKCTRL); - - /* Set up the SERCOM_GCLK_ID_SLOW clock */ - - regval = (SERCOM_GCLK_ID_SLOW << GCLK_CLKCTRL_ID_SHIFT); - - /* Select and disable the SERCOM_GCLK_ID_SLOW generic clock */ - - putreg16(regval, SAM_GCLK_CLKCTRL); - - /* Wait for clock to become disabled */ - - while ((getreg16(SAM_GCLK_CLKCTRL) & GCLK_CLKCTRL_CLKEN) != 0); - - /* Select the SERCOM_GCLK_ID_SLOW clock source generator */ - - regval |= (uint16_t)config->gclkgen << GCLK_CLKCTRL_GEN_SHIFT; - -#if 0 /* Not yet supported */ - /* Enable write lock if requested to prevent further modification */ - - if (config->wrlock) - { - regval |= GCLK_CLKCTRL_WRTLOCK; - } -#endif - - /* Write the new configuration */ - - putreg16(regval, SAM_GCLK_CLKCTRL); - - /* Enable the SERCOM_GCLK_ID_SLOW generic clock */ - - regval |= GCLK_CLKCTRL_CLKEN; - putreg16(regval, SAM_GCLK_CLKCTRL); -} -#endif - /**************************************************************************** * Name: sam_usart_configure * @@ -396,11 +301,12 @@ int sam_usart_internal(const struct sam_usart_config_s * const config) regval |= PM_APBCMASK_SERCOM(config->sercom); putreg32(regval, SAM_PM_APBCMASK); - /* Configure the GCCLK for the SERCOM module */ + /* Configure the GCLKs for the SERCOM module */ - sam_gclk_configure(config); + sercom_coreclk_configure(config->sercom, config->gclkgen, false); + sercom_slowclk_configure(config->gclkgen); - /* Set configuration according to the board configuration */ + /* Set USART configuration according to the board configuration */ ret = sam_usart_configure(config); if (ret == OK) diff --git a/arch/arm/src/samd/sam_lowputc.h b/arch/arm/src/samd/sam_lowputc.h index 6b7036ed98..1158890eb6 100644 --- a/arch/arm/src/samd/sam_lowputc.h +++ b/arch/arm/src/samd/sam_lowputc.h @@ -1,4 +1,4 @@ -/************************************************************************************ +/**************************************************************************** * arch/arm/src/samd/sam_lowputc.h * * Copyright (C) 2014 Gregory Nutt. All rights reserved. @@ -31,29 +31,29 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - ************************************************************************************/ + ****************************************************************************/ #ifndef __ARCH_ARM_SRC_SAMD_SAM_LOWPUTC_H #define __ARCH_ARM_SRC_SAMD_SAM_LOWPUTC_H -/************************************************************************************ +/**************************************************************************** * Included Files - ************************************************************************************/ + ****************************************************************************/ #include #include "sam_config.h" -/************************************************************************************ +/**************************************************************************** * Pre-processor Definitions - ************************************************************************************/ + ****************************************************************************/ -/************************************************************************************ +/**************************************************************************** * Public Types - ************************************************************************************/ + ****************************************************************************/ -/************************************************************************************ +/**************************************************************************** * Public Data - ************************************************************************************/ + ****************************************************************************/ #ifndef __ASSEMBLY__ @@ -66,17 +66,18 @@ extern "C" #define EXTERN extern #endif -/************************************************************************************ - * Public Functions - ************************************************************************************/ +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ -/************************************************************************************ +/**************************************************************************** * Name: sam_lowsetup * * Description: - * Called at the very beginning of _start. Performs low level initialization. + * Called at the very beginning of _start. Performs low level + * initialization. * - ************************************************************************************/ + ****************************************************************************/ void sam_lowsetup(void); @@ -88,7 +89,7 @@ void sam_lowsetup(void); * This configures the SERCOM as a USART, but does not configure USART * interrupts or enable the USART. * - *****************************************************************************/ + ****************************************************************************/ #ifdef HAVE_USART struct sam_usart_config_s; @@ -102,7 +103,7 @@ int sam_usart_initialize(const struct sam_usart_config_s * const config); * Reset the USART SERCOM. This restores all SERCOM register to the * initial state and disables the SERCOM. * - *****************************************************************************/ + ****************************************************************************/ #ifdef HAVE_USART struct sam_usart_config_s; @@ -115,7 +116,7 @@ void sam_usart_reset(const struct sam_usart_config_s * const config); * Description: * Output one character to the USART using a simple polling method. * - *****************************************************************************/ + ****************************************************************************/ #ifdef HAVE_SERIAL_CONSOLE void sam_lowputc(uint32_t ch); diff --git a/arch/arm/src/samd/sam_sercom.c b/arch/arm/src/samd/sam_sercom.c new file mode 100644 index 0000000000..81f0f3aecb --- /dev/null +++ b/arch/arm/src/samd/sam_sercom.c @@ -0,0 +1,182 @@ +/**************************************************************************** + * arch/arm/src/samd/sam_lowputc.c + * + * Copyright (C) 2014 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * References: + * 1. "Atmel SAM D20J / SAM D20G / SAM D20E ARM-Based Microcontroller + * Datasheet", 42129J–SAM–12/2013 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "up_arch.h" + +#include "sam_config.h" + +#include "chip/sam_pm.h" +#include "chip/sam_gclk.h" +#include "chip/sam_sercom.h" + +#include "sam_sercom.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sercom_coreclk_configure + * + * Description: + * Configure the SERCOM core source clock. + * + * Two generic clocks are used by the SERCOM: GCLK_SERCOMx_CORE and + * GCLK_SERCOMx_SLOW. The core clock (GCLK_SERCOMx_CORE) is required to + * clock the SERCOM while operating as a master, while the slow clock + * (GCLK_SERCOM_SLOW) is only required for certain functions. SERCOM + * modules must share the same slow GCLK channel ID. + * + * The baud-rate generator runs off the GCLK_SERCOMx_CORE clock (or, + * optionally, external clock). + * + ****************************************************************************/ + +void sercom_coreclk_configure(int sercom, int gclkgen, bool wrlock) +{ + uint16_t regval; + uint8_t glckcore; + + /* Set up the SERCOMn_GCLK_ID_CORE clock */ + + glckcore = (uint8_t)SERCOM_GCLK_ID_CORE(sercom); + regval = ((uint16_t)glckcore << GCLK_CLKCTRL_ID_SHIFT); + + /* Select and disable the SERCOMn_GCLK_ID_CORE generic clock */ + + putreg16(regval, SAM_GCLK_CLKCTRL); + + /* Wait for clock to become disabled */ + + while ((getreg16(SAM_GCLK_CLKCTRL) & GCLK_CLKCTRL_CLKEN) != 0); + + /* Select the SERCOMn_GCLK_ID_CORE source clock generator */ + + regval |= (uint16_t)gclkgen << GCLK_CLKCTRL_GEN_SHIFT; + + /* Write the new configuration */ + + putreg16(regval, SAM_GCLK_CLKCTRL); + + /* Enable the SERCOMn_GCLK_ID_CORE generic clock, optionally locking + * further writes to this GCLK. + */ + + regval |= GCLK_CLKCTRL_CLKEN; + + if (wrlock) + { + regval |= GCLK_CLKCTRL_WRTLOCK; + } + + putreg16(regval, SAM_GCLK_CLKCTRL); +} + +/**************************************************************************** + * Name: sercom_slowclk_configure + * + * Description: + * Configure the SERCOM slow source clock. + * + * Two generic clocks are used by the SERCOM: GCLK_SERCOMx_CORE and + * GCLK_SERCOMx_SLOW. The core clock (GCLK_SERCOMx_CORE) is required to + * clock the SERCOM while operating as a master, while the slow clock + * (GCLK_SERCOM_SLOW) is only required for certain functions. SERCOM + * modules must share the same slow GCLK channel ID. + * + ****************************************************************************/ + +void sercom_slowclk_configure(int gclkgen) +{ + uint16_t regval; + + /* Set up the SERCOM_GCLK_ID_SLOW clock */ + + regval = (SERCOM_GCLK_ID_SLOW << GCLK_CLKCTRL_ID_SHIFT); + + /* Select and disable the SERCOM_GCLK_ID_SLOW generic clock */ + + putreg16(regval, SAM_GCLK_CLKCTRL); + + /* Wait for clock to become disabled */ + + while ((getreg16(SAM_GCLK_CLKCTRL) & GCLK_CLKCTRL_CLKEN) != 0); + + /* Select the SERCOM_GCLK_ID_SLOW clock source generator */ + + regval |= (uint16_t)gclkgen << GCLK_CLKCTRL_GEN_SHIFT; + + /* Write the new configuration */ + + putreg16(regval, SAM_GCLK_CLKCTRL); + + /* Enable the GCLK_SERCOM_SLOW generic clock and lock further + * writes to this GCLK. When this bit is written, it will lock + * further writes to the generic clock pointed by the CLKCTRL.ID. The + * generic clock generator pointed by CLKCTRL.GEN and the GENDIV.DIV + * will also be locked. + * + * We lock the SERCOM slow clock because it is common to all SERCOM modules + * and, once set, should not be changed again. + */ + + regval |= (GCLK_CLKCTRL_WRTLOCK | GCLK_CLKCTRL_CLKEN); + putreg16(regval, SAM_GCLK_CLKCTRL); +} diff --git a/arch/arm/src/samd/sam_sercom.h b/arch/arm/src/samd/sam_sercom.h new file mode 100644 index 0000000000..2d935ce146 --- /dev/null +++ b/arch/arm/src/samd/sam_sercom.h @@ -0,0 +1,115 @@ +/**************************************************************************** + * arch/arm/src/samd/sam_sercom.h + * + * Copyright (C) 2014 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_SAMD_SAM_SERCOM_H +#define __ARCH_ARM_SRC_SAMD_SAM_SERCOM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "sam_config.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ +/**************************************************************************** + * Name: sercom_coreclk_configure + * + * Description: + * Configure the SERCOM core source clock. + * + * Two generic clocks are used by the SERCOM: GCLK_SERCOMx_CORE and + * GCLK_SERCOMx_SLOW. The core clock (GCLK_SERCOMx_CORE) is required to + * clock the SERCOM while operating as a master, while the slow clock + * (GCLK_SERCOM_SLOW) is only required for certain functions. SERCOM + * modules must share the same slow GCLK channel ID. + * + * The baud-rate generator runs off the GCLK_SERCOMx_CORE clock (or, + * optionally, external clock). + * + ****************************************************************************/ + +void sercom_coreclk_configure(int sercom, int gclkgen, bool wrlock); + +/**************************************************************************** + * Name: sercom_slowclk_configure + * + * Description: + * Configure the SERCOM slow source clock. + * + * Two generic clocks are used by the SERCOM: GCLK_SERCOMx_CORE and + * GCLK_SERCOMx_SLOW. The core clock (GCLK_SERCOMx_CORE) is required to + * clock the SERCOM while operating as a master, while the slow clock + * (GCLK_SERCOM_SLOW) is only required for certain functions. SERCOM + * modules must share the same slow GCLK channel ID. + * + ****************************************************************************/ + +void sercom_slowclk_configure(int gclkgen); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_SAMD_SAM_SERCOM_H */ diff --git a/arch/arm/src/samd/sam_serial.h b/arch/arm/src/samd/sam_serial.h index 182ae064a1..d692a738ee 100644 --- a/arch/arm/src/samd/sam_serial.h +++ b/arch/arm/src/samd/sam_serial.h @@ -1,4 +1,4 @@ -/************************************************************************************ +/**************************************************************************** * arch/arm/src/samd/sam_serial.h * * Copyright (C) 2014 Gregory Nutt. All rights reserved. @@ -31,37 +31,37 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - ************************************************************************************/ + ****************************************************************************/ #ifndef __ARCH_ARM_SRC_SAMD_SAM_SERIAL_H #define __ARCH_ARM_SRC_SAMD_SAM_SERIAL_H -/************************************************************************************ +/**************************************************************************** * Included Files - ************************************************************************************/ + ****************************************************************************/ #include #include "sam_config.h" -/************************************************************************************ +/**************************************************************************** * Pre-processor Definitions - ************************************************************************************/ + ****************************************************************************/ -/************************************************************************************ +/**************************************************************************** * Public Types - ************************************************************************************/ + ****************************************************************************/ -/************************************************************************************ +/**************************************************************************** * Public Data - ************************************************************************************/ + ****************************************************************************/ -/************************************************************************************ +/**************************************************************************** * Inline Functions - ************************************************************************************/ + ****************************************************************************/ -/************************************************************************************ +/**************************************************************************** * Public Functions - ************************************************************************************/ + ****************************************************************************/ #endif /* __ARCH_ARM_SRC_SAMD_SAM_SERIAL_H */ diff --git a/configs/samd20-xplained/src/sam_spi.c b/configs/samd20-xplained/src/sam_spi.c index 4c6b9b008e..605a601e96 100644 --- a/configs/samd20-xplained/src/sam_spi.c +++ b/configs/samd20-xplained/src/sam_spi.c @@ -279,6 +279,7 @@ int sam_spicmddata(FAR struct spi_dev_s *dev, enum spi_dev_e devid, bool cmd) (void)sam_portwrite(PORT_OLED_DATA, !cmd); } #endif - return OK; + + return OK; } #endif diff --git a/configs/samd20-xplained/src/samd20-xplained.h b/configs/samd20-xplained/src/samd20-xplained.h index 4bf014ddc7..14f32d3327 100644 --- a/configs/samd20-xplained/src/samd20-xplained.h +++ b/configs/samd20-xplained/src/samd20-xplained.h @@ -128,11 +128,9 @@ # define PORT_SD_CD (PORT_INTERRUPT | PORT_INT_CHANGE | PORT_PULL_UP | \ PORTF | PORT_PIN5) -# define IRQ_SD_CD SAM_IRQ_PB5 # define PORT_SD_CS (PORT_OUTPUT | PORT_PULL_NONE | PORT_OUTPUT_SET | \ PORTA | PORT_PIN5) -# define SD_CSNO 0 # elif defined(CONFIG_SAMD20_XPLAINED_IOMODULE_EXT2) @@ -143,11 +141,9 @@ # define PORT_CD (PORT_INTERRUPT | PORT_INT_CHANGE | PORT_PULL_UP | \ PORTB | PORT_PIN15) -# define IRQ_CD SAM_IRQ_PB15 # define PORT_SD_CS (PORT_OUTPUT | PORT_PULL_NONE | PORT_OUTPUT_SET | \ PORTA | PORT_PIN17) -# define SD_CSNO 2 # else # error Which connector is the I/O1 module installed in? @@ -200,7 +196,6 @@ PORTB | PORT_PIN5) # define PORT_OLED_CS (PORT_OUTPUT | PORT_PULL_NONE | PORT_OUTPUT_SET | \ PORTA | PORT_PIN5) -# define OLED_CSNO 0 # elif defined(CONFIG_SAMD20_XPLAINED_OLED1MODULE_EXT2) @@ -215,7 +210,6 @@ PORTB | PORT_PIN15) # define PORT_OLED_CS (PORT_OUTPUT | PORT_PULL_NONE | PORT_OUTPUT_SET | \ PORTA | PORT_PIN17) -# define OLED_CSNO 2 # else # error Which connector is the OLED1 module installed in? diff --git a/fs/fs_rename.c b/fs/fs_rename.c index 474a7492ee..405d25cc2e 100644 --- a/fs/fs_rename.c +++ b/fs/fs_rename.c @@ -223,6 +223,6 @@ int rename(FAR const char *oldpath, FAR const char *newpath) errout_with_oldinode: inode_release(oldinode); errout: - set_errno(ret); + set_errno(errcode); return ERROR; }