diff --git a/ChangeLog b/ChangeLog index 52f20dd971f..675c984e20c 100755 --- a/ChangeLog +++ b/ChangeLog @@ -11629,3 +11629,17 @@ no longer qualifies for inclusion in the open source repositories. The code as of this data is still available in the Obsoleted repository at configs/nucleus2g (2016-04-12). + * arch/arm/src/stm32l4: Fix the STM32L4 SPI driver. That SPI driver is + quite different. They now handle frames of arbitrary size between 4 + and 16 bits. It was broken before a new bit has to be set (rx fifo + threshold) to handle <= 8-bit transactions. If not set, the default is + 16-bit packed >=8-bit frames and the RXNE bit is never set (it is set + when 16-bits are received). weird things as always. + This also add 8-bit access routines to the data register, because a + 16-bit access to the data register when the frame size is below 9 bits + is interpreted as a packed dual frame exchange. Sebastien Lorquet + (2016-04-13). + * net/sockets/listen.c and accept.c and include/nuttx/net: Separate + out psock_listen() and psock_accepti() for internal OS usage + (2016-04-14). + diff --git a/arch/arm/src/stm32l4/stm32l4_spi.c b/arch/arm/src/stm32l4/stm32l4_spi.c index 86c7ddbc54a..b6907d5955b 100644 --- a/arch/arm/src/stm32l4/stm32l4_spi.c +++ b/arch/arm/src/stm32l4/stm32l4_spi.c @@ -55,8 +55,7 @@ * ****************************************************c********************************/ -/* - * This driver is ported from the stm32 one, which only supports 8 and 16 bits +/* This driver is ported from the stm32 one, which only supports 8 and 16 bits * transfers. The STM32L4 family supports frame size from 4 to 16 bits, but we do not * support that yet. For the moment, we replace uses of the CR1_DFF bit with a check * of the CR2_DS[0..3] bits. If the value is SPI_CR2_DS_16BIT it means 16 bits, else 8 bits. @@ -90,11 +89,13 @@ #include "stm32l4_dma.h" #include "stm32l4_spi.h" -#if defined(CONFIG_STM32L4_SPI1) || defined(CONFIG_STM32L4_SPI2) || defined(CONFIG_STM32L4_SPI3) +#if defined(CONFIG_STM32L4_SPI1) || defined(CONFIG_STM32L4_SPI2) || \ + defined(CONFIG_STM32L4_SPI3) /************************************************************************************ * Pre-processor Definitions ************************************************************************************/ + /* Configuration ********************************************************************/ /* SPI interrupts */ @@ -414,22 +415,62 @@ static inline uint16_t spi_getreg(FAR struct stm32l4_spidev_s *priv, uint8_t off * ************************************************************************************/ -static inline void spi_putreg(FAR struct stm32l4_spidev_s *priv, uint8_t offset, uint16_t value) +static inline void spi_putreg(FAR struct stm32l4_spidev_s *priv, uint8_t offset, + uint16_t value) { putreg16(value, priv->spibase + offset); } +/************************************************************************************ + * Name: spi_getreg8 + * + * Description: + * Get the contents of the SPI register at offset + * + * Input Parameters: + * priv - private SPI device structure + * offset - offset to the register of interest + * + * Returned Value: + * The contents of the 8-bit register + * + ************************************************************************************/ + +static inline uint8_t spi_getreg8(FAR struct stm32l4_spidev_s *priv, uint8_t offset) +{ + return getreg8(priv->spibase + offset); +} + +/************************************************************************************ + * Name: spi_putreg8 + * + * Description: + * Write a 8-bit value to the SPI register at offset + * + * Input Parameters: + * priv - private SPI device structure + * offset - offset to the register of interest + * value - the 8-bit value to be written + * + ************************************************************************************/ + +static inline void spi_putreg8(FAR struct stm32l4_spidev_s *priv, uint8_t offset, + uint8_t value) +{ + putreg8(value, priv->spibase + offset); +} + /************************************************************************************ * Name: spi_readword * * Description: - * Read one byte from SPI + * Read one word (TWO bytes!) from SPI * * Input Parameters: * priv - Device-specific state data * * Returned Value: - * Byte as read + * Word as read * ************************************************************************************/ @@ -445,14 +486,39 @@ static inline uint16_t spi_readword(FAR struct stm32l4_spidev_s *priv) } /************************************************************************************ - * Name: spi_writeword + * Name: spi_readbyte * * Description: - * Write one byte to SPI + * Read one byte from SPI * * Input Parameters: * priv - Device-specific state data - * byte - Byte to send + * + * Returned Value: + * Byte as read + * + ************************************************************************************/ + +static inline uint8_t spi_readbyte(FAR struct stm32l4_spidev_s *priv) +{ + /* Wait until the receive buffer is not empty */ + + while ((spi_getreg(priv, STM32L4_SPI_SR_OFFSET) & SPI_SR_RXNE) == 0); + + /* Then return the received byte */ + + return spi_getreg8(priv, STM32L4_SPI_DR_OFFSET); +} + +/************************************************************************************ + * Name: spi_writeword + * + * Description: + * Write one 16-bit frame to the SPI FIFO + * + * Input Parameters: + * priv - Device-specific state data + * byte - Word to send * * Returned Value: * None @@ -470,6 +536,32 @@ static inline void spi_writeword(FAR struct stm32l4_spidev_s *priv, uint16_t wor spi_putreg(priv, STM32L4_SPI_DR_OFFSET, word); } +/************************************************************************************ + * Name: spi_writebyte + * + * Description: + * Write one 8-bit frame to the SPI FIFO + * + * Input Parameters: + * priv - Device-specific state data + * byte - Byte to send + * + * Returned Value: + * None + * + ************************************************************************************/ + +static inline void spi_writebyte(FAR struct stm32l4_spidev_s *priv, uint8_t byte) +{ + /* Wait until the transmit buffer is empty */ + + while ((spi_getreg(priv, STM32L4_SPI_SR_OFFSET) & SPI_SR_TXE) == 0); + + /* Then send the byte */ + + spi_putreg8(priv, STM32L4_SPI_DR_OFFSET, byte); +} + /************************************************************************************ * Name: spi_16bitmode * @@ -486,7 +578,22 @@ static inline void spi_writeword(FAR struct stm32l4_spidev_s *priv, uint16_t wor static inline bool spi_16bitmode(FAR struct stm32l4_spidev_s *priv) { - return ((spi_getreg(priv, STM32L4_SPI_CR2_OFFSET) & SPI_CR2_DS_MASK) == SPI_CR2_DS_16BIT); + uint8_t bits = priv->nbits; + + /* Get the real number of bits */ + + if (bits < 0) + { + bits = -bits; + } + + return (bits > 8); + + /* Should we read the hardware regs? seems to be equivalent ~~ sebastien lorquet + * (20160413) + */ + +// return ((spi_getreg(priv, STM32L4_SPI_CR2_OFFSET) & SPI_CR2_DS_MASK) == SPI_CR2_DS_16BIT); } /************************************************************************************ @@ -761,11 +868,12 @@ static inline void spi_dmatxstart(FAR struct stm32l4_spidev_s *priv) static void spi_modifycr(uint32_t addr, FAR struct stm32l4_spidev_s *priv, uint16_t setbits, uint16_t clrbits) { - uint16_t cr1; - cr1 = spi_getreg(priv, addr); - cr1 &= ~clrbits; - cr1 |= setbits; - spi_putreg(priv, addr, cr1); + uint16_t cr; + + cr = spi_getreg(priv, addr); + cr &= ~clrbits; + cr |= setbits; + spi_putreg(priv, addr, cr); } /************************************************************************************ @@ -1007,6 +1115,7 @@ static void spi_setbits(FAR struct spi_dev_s *dev, int nbits) FAR struct stm32l4_spidev_s *priv = (FAR struct stm32l4_spidev_s *)dev; uint16_t setbits1, setbits2; uint16_t clrbits1, clrbits2; + int savbits = nbits; spivdbg("nbits=%d\n", nbits); @@ -1014,11 +1123,10 @@ static void spi_setbits(FAR struct spi_dev_s *dev, int nbits) if (nbits != priv->nbits) { - /* Yes... Set CR1/2 appropriately */ + /* Negative sign means LSBFIRST, set this in CR1*/ - /* negative sign means LSBFIRST, set this in CR1*/ - if(nbits<0) + if (nbits < 0) { setbits1 = SPI_CR1_LSBFIRST; clrbits1 = 0; @@ -1030,8 +1138,9 @@ static void spi_setbits(FAR struct spi_dev_s *dev, int nbits) clrbits1 = SPI_CR1_LSBFIRST; } - /* set the number of bits (valid range 4-16) */ - if(nbits<4 || nbits>16) + /* Set the number of bits (valid range 4-16) */ + + if (nbits < 4 || nbits > 16) { return; } @@ -1039,6 +1148,19 @@ static void spi_setbits(FAR struct spi_dev_s *dev, int nbits) clrbits2 = SPI_CR2_DS_MASK; setbits2 = SPI_CR2_DS_VAL(nbits); + /* If nbits is <=8, then we are in byte mode and FRXTH shall be set + * (else, transaction will not complete). + */ + + if (nbits < 9) + { + setbits2 |= SPI_CR2_FRXTH; /* RX FIFO Threshold = 1 byte */ + } + else + { + clrbits2 |= SPI_CR2_FRXTH; /* RX FIFO Threshold = 2 bytes */ + } + spi_modifycr(STM32L4_SPI_CR1_OFFSET, priv, 0, SPI_CR1_SPE); spi_modifycr(STM32L4_SPI_CR1_OFFSET, priv, setbits1, clrbits1); spi_modifycr(STM32L4_SPI_CR2_OFFSET, priv, setbits2, clrbits2); @@ -1046,7 +1168,7 @@ static void spi_setbits(FAR struct spi_dev_s *dev, int nbits) /* Save the selection so the subsequence re-configurations will be faster */ - priv->nbits = nbits; + priv->nbits = savbits; // nbits has been clobbered... save the signed value. } } @@ -1074,16 +1196,38 @@ static uint16_t spi_send(FAR struct spi_dev_s *dev, uint16_t wd) DEBUGASSERT(priv && priv->spibase); - spi_writeword(priv, wd); - ret = spi_readword(priv); + /* According to the number of bits, access data register as word or byte + * This is absolutely required because of packing. With <=8 bit frames, + * two bytes are received by a 16-bit read of the data register! + */ - /* Check and clear any error flags (Reading from the SR clears the error flags) */ + if (spi_16bitmode(priv)) + { + spi_writeword(priv, wd); + ret = spi_readword(priv); + } + else + { + spi_writebyte(priv, (uint8_t)(wd & 0xFF)); + ret = (uint16_t)spi_readbyte(priv); + } + + /* Check and clear any error flags (Reading from the SR clears the error + * flags). + */ regval = spi_getreg(priv, STM32L4_SPI_SR_OFFSET); - spivdbg("Sent: %04x Return: %04x Status: %02x\n", wd, ret, regval); - UNUSED(regval); + if (spi_16bitmode(priv)) + { + spivdbg("Sent: %04x Return: %04x Status: %02x\n", wd, ret, regval); + } + else + { + spivdbg("Sent: %02x Return: %02x Status: %02x\n", wd, ret, regval); + } + UNUSED(regval); return ret; } @@ -1341,7 +1485,7 @@ static void spi_bus_initialize(FAR struct stm32l4_spidev_s *priv) spi_modifycr(STM32L4_SPI_CR1_OFFSET, priv, setbits, clrbits); clrbits = SPI_CR2_DS_MASK; - setbits = SPI_CR2_DS_8BIT; + setbits = SPI_CR2_DS_8BIT | SPI_CR2_FRXTH; /* FRXTH must be high in 8-bit mode */ spi_modifycr(STM32L4_SPI_CR2_OFFSET, priv, setbits, clrbits); priv->frequency = 0; diff --git a/configs/samv71-xult/knsh/defconfig b/configs/samv71-xult/knsh/defconfig index 9237a360d3a..2716784db29 100644 --- a/configs/samv71-xult/knsh/defconfig +++ b/configs/samv71-xult/knsh/defconfig @@ -85,6 +85,7 @@ CONFIG_ARCH="arm" # CONFIG_ARCH_CHIP_DM320 is not set # CONFIG_ARCH_CHIP_EFM32 is not set # CONFIG_ARCH_CHIP_IMX1 is not set +# CONFIG_ARCH_CHIP_IMX6 is not set # CONFIG_ARCH_CHIP_KINETIS is not set # CONFIG_ARCH_CHIP_KL is not set # CONFIG_ARCH_CHIP_LM is not set @@ -103,6 +104,7 @@ CONFIG_ARCH="arm" CONFIG_ARCH_CHIP_SAMV7=y # CONFIG_ARCH_CHIP_STM32 is not set # CONFIG_ARCH_CHIP_STM32F7 is not set +# CONFIG_ARCH_CHIP_STM32L4 is not set # CONFIG_ARCH_CHIP_STR71X is not set # CONFIG_ARCH_CHIP_TMS570 is not set # CONFIG_ARCH_CHIP_MOXART is not set @@ -124,6 +126,8 @@ CONFIG_ARCH_CORTEXM7=y # CONFIG_ARCH_CORTEXR7F is not set CONFIG_ARCH_FAMILY="armv7-m" CONFIG_ARCH_CHIP="samv7" +# CONFIG_ARM_TOOLCHAIN_IAR is not set +CONFIG_ARM_TOOLCHAIN_GNU=y # CONFIG_ARMV7M_USEBASEPRI is not set CONFIG_ARCH_HAVE_CMNVECTOR=y CONFIG_ARMV7M_CMNVECTOR=y @@ -132,6 +136,7 @@ CONFIG_ARCH_HAVE_FPU=y CONFIG_ARCH_HAVE_DPFPU=y CONFIG_ARCH_FPU=y CONFIG_ARCH_DPFPU=y +# CONFIG_ARCH_HAVE_TRUSTZONE is not set CONFIG_ARM_HAVE_MPU_UNIFIED=y CONFIG_ARM_MPU=y CONFIG_ARM_MPU_NREGIONS=16 @@ -148,6 +153,7 @@ CONFIG_ARMV7M_HAVE_ITCM=y CONFIG_ARMV7M_HAVE_DTCM=y # CONFIG_ARMV7M_ITCM is not set # CONFIG_ARMV7M_DTCM is not set +# CONFIG_ARMV7M_TOOLCHAIN_IARW is not set # CONFIG_ARMV7M_TOOLCHAIN_ATOLLIC is not set # CONFIG_ARMV7M_TOOLCHAIN_BUILDROOT is not set # CONFIG_ARMV7M_TOOLCHAIN_CODEREDW is not set @@ -794,6 +800,8 @@ CONFIG_ARCH_LOWPUTC=y CONFIG_LIB_SENDFILE_BUFSIZE=512 # CONFIG_ARCH_ROMGETC is not set # CONFIG_ARCH_OPTIMIZED_FUNCTIONS is not set +CONFIG_ARCH_HAVE_TLS=y +# CONFIG_TLS is not set # CONFIG_LIBC_NETDB is not set # CONFIG_NETDB_HOSTFILE is not set diff --git a/configs/samv71-xult/module/defconfig b/configs/samv71-xult/module/defconfig index 96ce1959bb4..8300fa0f3a8 100644 --- a/configs/samv71-xult/module/defconfig +++ b/configs/samv71-xult/module/defconfig @@ -99,6 +99,7 @@ CONFIG_ARCH="arm" CONFIG_ARCH_CHIP_SAMV7=y # CONFIG_ARCH_CHIP_STM32 is not set # CONFIG_ARCH_CHIP_STM32F7 is not set +# CONFIG_ARCH_CHIP_STM32L4 is not set # CONFIG_ARCH_CHIP_STR71X is not set # CONFIG_ARCH_CHIP_TMS570 is not set # CONFIG_ARCH_CHIP_MOXART is not set @@ -120,6 +121,8 @@ CONFIG_ARCH_CORTEXM7=y # CONFIG_ARCH_CORTEXR7F is not set CONFIG_ARCH_FAMILY="armv7-m" CONFIG_ARCH_CHIP="samv7" +# CONFIG_ARM_TOOLCHAIN_IAR is not set +CONFIG_ARM_TOOLCHAIN_GNU=y CONFIG_ARMV7M_USEBASEPRI=y CONFIG_ARCH_HAVE_CMNVECTOR=y CONFIG_ARMV7M_CMNVECTOR=y @@ -128,6 +131,7 @@ CONFIG_ARCH_HAVE_FPU=y CONFIG_ARCH_HAVE_DPFPU=y CONFIG_ARCH_FPU=y CONFIG_ARCH_DPFPU=y +# CONFIG_ARCH_HAVE_TRUSTZONE is not set CONFIG_ARM_HAVE_MPU_UNIFIED=y # CONFIG_ARM_MPU is not set @@ -143,6 +147,7 @@ CONFIG_ARMV7M_HAVE_ITCM=y CONFIG_ARMV7M_HAVE_DTCM=y # CONFIG_ARMV7M_ITCM is not set # CONFIG_ARMV7M_DTCM is not set +# CONFIG_ARMV7M_TOOLCHAIN_IARW is not set # CONFIG_ARMV7M_TOOLCHAIN_ATOLLIC is not set # CONFIG_ARMV7M_TOOLCHAIN_BUILDROOT is not set # CONFIG_ARMV7M_TOOLCHAIN_CODEREDW is not set @@ -711,6 +716,8 @@ CONFIG_ARCH_LOWPUTC=y CONFIG_LIB_SENDFILE_BUFSIZE=512 # CONFIG_ARCH_ROMGETC is not set # CONFIG_ARCH_OPTIMIZED_FUNCTIONS is not set +CONFIG_ARCH_HAVE_TLS=y +# CONFIG_TLS is not set # CONFIG_LIBC_NETDB is not set # CONFIG_NETDB_HOSTFILE is not set diff --git a/configs/samv71-xult/netnsh/defconfig b/configs/samv71-xult/netnsh/defconfig index 68b39a691a2..c40145daf3f 100644 --- a/configs/samv71-xult/netnsh/defconfig +++ b/configs/samv71-xult/netnsh/defconfig @@ -81,6 +81,7 @@ CONFIG_ARCH="arm" # CONFIG_ARCH_CHIP_DM320 is not set # CONFIG_ARCH_CHIP_EFM32 is not set # CONFIG_ARCH_CHIP_IMX1 is not set +# CONFIG_ARCH_CHIP_IMX6 is not set # CONFIG_ARCH_CHIP_KINETIS is not set # CONFIG_ARCH_CHIP_KL is not set # CONFIG_ARCH_CHIP_LM is not set @@ -99,6 +100,7 @@ CONFIG_ARCH="arm" CONFIG_ARCH_CHIP_SAMV7=y # CONFIG_ARCH_CHIP_STM32 is not set # CONFIG_ARCH_CHIP_STM32F7 is not set +# CONFIG_ARCH_CHIP_STM32L4 is not set # CONFIG_ARCH_CHIP_STR71X is not set # CONFIG_ARCH_CHIP_TMS570 is not set # CONFIG_ARCH_CHIP_MOXART is not set @@ -120,6 +122,8 @@ CONFIG_ARCH_CORTEXM7=y # CONFIG_ARCH_CORTEXR7F is not set CONFIG_ARCH_FAMILY="armv7-m" CONFIG_ARCH_CHIP="samv7" +# CONFIG_ARM_TOOLCHAIN_IAR is not set +CONFIG_ARM_TOOLCHAIN_GNU=y # CONFIG_ARMV7M_USEBASEPRI is not set CONFIG_ARCH_HAVE_CMNVECTOR=y CONFIG_ARMV7M_CMNVECTOR=y @@ -128,6 +132,7 @@ CONFIG_ARCH_HAVE_FPU=y CONFIG_ARCH_HAVE_DPFPU=y CONFIG_ARCH_FPU=y CONFIG_ARCH_DPFPU=y +# CONFIG_ARCH_HAVE_TRUSTZONE is not set CONFIG_ARM_HAVE_MPU_UNIFIED=y # CONFIG_ARM_MPU is not set @@ -143,6 +148,7 @@ CONFIG_ARMV7M_HAVE_ITCM=y CONFIG_ARMV7M_HAVE_DTCM=y # CONFIG_ARMV7M_ITCM is not set # CONFIG_ARMV7M_DTCM is not set +# CONFIG_ARMV7M_TOOLCHAIN_IARW is not set # CONFIG_ARMV7M_TOOLCHAIN_ATOLLIC is not set # CONFIG_ARMV7M_TOOLCHAIN_BUILDROOT is not set # CONFIG_ARMV7M_TOOLCHAIN_CODEREDW is not set @@ -958,6 +964,8 @@ CONFIG_ARCH_LOWPUTC=y CONFIG_LIB_SENDFILE_BUFSIZE=512 # CONFIG_ARCH_ROMGETC is not set # CONFIG_ARCH_OPTIMIZED_FUNCTIONS is not set +CONFIG_ARCH_HAVE_TLS=y +# CONFIG_TLS is not set CONFIG_LIBC_NETDB=y # CONFIG_NETDB_HOSTFILE is not set CONFIG_NETDB_DNSCLIENT=y diff --git a/configs/samv71-xult/nsh/defconfig b/configs/samv71-xult/nsh/defconfig index ee2472b2ce0..c3c64d50fa0 100644 --- a/configs/samv71-xult/nsh/defconfig +++ b/configs/samv71-xult/nsh/defconfig @@ -80,6 +80,7 @@ CONFIG_ARCH="arm" # CONFIG_ARCH_CHIP_DM320 is not set # CONFIG_ARCH_CHIP_EFM32 is not set # CONFIG_ARCH_CHIP_IMX1 is not set +# CONFIG_ARCH_CHIP_IMX6 is not set # CONFIG_ARCH_CHIP_KINETIS is not set # CONFIG_ARCH_CHIP_KL is not set # CONFIG_ARCH_CHIP_LM is not set @@ -98,6 +99,7 @@ CONFIG_ARCH="arm" CONFIG_ARCH_CHIP_SAMV7=y # CONFIG_ARCH_CHIP_STM32 is not set # CONFIG_ARCH_CHIP_STM32F7 is not set +# CONFIG_ARCH_CHIP_STM32L4 is not set # CONFIG_ARCH_CHIP_STR71X is not set # CONFIG_ARCH_CHIP_TMS570 is not set # CONFIG_ARCH_CHIP_MOXART is not set @@ -119,6 +121,8 @@ CONFIG_ARCH_CORTEXM7=y # CONFIG_ARCH_CORTEXR7F is not set CONFIG_ARCH_FAMILY="armv7-m" CONFIG_ARCH_CHIP="samv7" +# CONFIG_ARM_TOOLCHAIN_IAR is not set +CONFIG_ARM_TOOLCHAIN_GNU=y # CONFIG_ARMV7M_USEBASEPRI is not set CONFIG_ARCH_HAVE_CMNVECTOR=y CONFIG_ARMV7M_CMNVECTOR=y @@ -127,6 +131,7 @@ CONFIG_ARCH_HAVE_FPU=y CONFIG_ARCH_HAVE_DPFPU=y CONFIG_ARCH_FPU=y CONFIG_ARCH_DPFPU=y +# CONFIG_ARCH_HAVE_TRUSTZONE is not set CONFIG_ARM_HAVE_MPU_UNIFIED=y # CONFIG_ARM_MPU is not set @@ -142,6 +147,7 @@ CONFIG_ARMV7M_HAVE_ITCM=y CONFIG_ARMV7M_HAVE_DTCM=y # CONFIG_ARMV7M_ITCM is not set # CONFIG_ARMV7M_DTCM is not set +# CONFIG_ARMV7M_TOOLCHAIN_IARW is not set # CONFIG_ARMV7M_TOOLCHAIN_ATOLLIC is not set # CONFIG_ARMV7M_TOOLCHAIN_BUILDROOT is not set # CONFIG_ARMV7M_TOOLCHAIN_CODEREDW is not set @@ -786,6 +792,8 @@ CONFIG_ARCH_LOWPUTC=y CONFIG_LIB_SENDFILE_BUFSIZE=512 # CONFIG_ARCH_ROMGETC is not set # CONFIG_ARCH_OPTIMIZED_FUNCTIONS is not set +CONFIG_ARCH_HAVE_TLS=y +# CONFIG_TLS is not set # CONFIG_LIBC_NETDB is not set # CONFIG_NETDB_HOSTFILE is not set diff --git a/configs/samv71-xult/nxwm/defconfig b/configs/samv71-xult/nxwm/defconfig index 564779b6518..e12363decd6 100644 --- a/configs/samv71-xult/nxwm/defconfig +++ b/configs/samv71-xult/nxwm/defconfig @@ -80,6 +80,7 @@ CONFIG_ARCH="arm" # CONFIG_ARCH_CHIP_DM320 is not set # CONFIG_ARCH_CHIP_EFM32 is not set # CONFIG_ARCH_CHIP_IMX1 is not set +# CONFIG_ARCH_CHIP_IMX6 is not set # CONFIG_ARCH_CHIP_KINETIS is not set # CONFIG_ARCH_CHIP_KL is not set # CONFIG_ARCH_CHIP_LM is not set @@ -98,6 +99,7 @@ CONFIG_ARCH="arm" CONFIG_ARCH_CHIP_SAMV7=y # CONFIG_ARCH_CHIP_STM32 is not set # CONFIG_ARCH_CHIP_STM32F7 is not set +# CONFIG_ARCH_CHIP_STM32L4 is not set # CONFIG_ARCH_CHIP_STR71X is not set # CONFIG_ARCH_CHIP_TMS570 is not set # CONFIG_ARCH_CHIP_MOXART is not set @@ -119,6 +121,8 @@ CONFIG_ARCH_CORTEXM7=y # CONFIG_ARCH_CORTEXR7F is not set CONFIG_ARCH_FAMILY="armv7-m" CONFIG_ARCH_CHIP="samv7" +# CONFIG_ARM_TOOLCHAIN_IAR is not set +CONFIG_ARM_TOOLCHAIN_GNU=y # CONFIG_ARMV7M_USEBASEPRI is not set CONFIG_ARCH_HAVE_CMNVECTOR=y CONFIG_ARMV7M_CMNVECTOR=y @@ -127,6 +131,7 @@ CONFIG_ARCH_HAVE_FPU=y CONFIG_ARCH_HAVE_DPFPU=y CONFIG_ARCH_FPU=y CONFIG_ARCH_DPFPU=y +# CONFIG_ARCH_HAVE_TRUSTZONE is not set CONFIG_ARM_HAVE_MPU_UNIFIED=y # CONFIG_ARM_MPU is not set @@ -142,6 +147,7 @@ CONFIG_ARMV7M_HAVE_ITCM=y CONFIG_ARMV7M_HAVE_DTCM=y # CONFIG_ARMV7M_ITCM is not set # CONFIG_ARMV7M_DTCM is not set +# CONFIG_ARMV7M_TOOLCHAIN_IARW is not set # CONFIG_ARMV7M_TOOLCHAIN_ATOLLIC is not set # CONFIG_ARMV7M_TOOLCHAIN_BUILDROOT is not set # CONFIG_ARMV7M_TOOLCHAIN_CODEREDW is not set @@ -933,6 +939,8 @@ CONFIG_ARCH_LOWPUTC=y CONFIG_LIB_SENDFILE_BUFSIZE=512 # CONFIG_ARCH_ROMGETC is not set # CONFIG_ARCH_OPTIMIZED_FUNCTIONS is not set +CONFIG_ARCH_HAVE_TLS=y +# CONFIG_TLS is not set # CONFIG_LIBC_NETDB is not set # CONFIG_NETDB_HOSTFILE is not set diff --git a/include/nuttx/net/net.h b/include/nuttx/net/net.h index a11c8bcd2e4..e95c9e82a73 100644 --- a/include/nuttx/net/net.h +++ b/include/nuttx/net/net.h @@ -503,6 +503,106 @@ struct sockaddr; /* Forward reference. Defined in nuttx/include/sys/socket.h */ int psock_bind(FAR struct socket *psock, FAR const struct sockaddr *addr, socklen_t addrlen); +/**************************************************************************** + * Function: psock_listen + * + * Description: + * To accept connections, a socket is first created with psock_socket(), a + * willingness to accept incoming connections and a queue limit for + * incoming connections are specified with psock_listen(), and then the + * connections are accepted with psock_accept(). The psock_listen() call + * applies only to sockets of type SOCK_STREAM or SOCK_SEQPACKET. + * + * Parameters: + * psock Reference to an internal, boound socket structure. + * backlog The maximum length the queue of pending connections may grow. + * If a connection request arrives with the queue full, the client + * may receive an error with an indication of ECONNREFUSED or, + * if the underlying protocol supports retransmission, the request + * may be ignored so that retries succeed. + * + * Returned Value: + * On success, zero is returned. On error, -1 is returned, and errno is set + * appropriately. + * + * EADDRINUSE + * Another socket is already listening on the same port. + * EOPNOTSUPP + * The socket is not of a type that supports the listen operation. + * + ****************************************************************************/ + +int psock_listen(FAR struct socket *psock, int backlog); + +/**************************************************************************** + * Function: psock_accept + * + * Description: + * The psock_accept function is used with connection-based socket types + * (SOCK_STREAM, SOCK_SEQPACKET and SOCK_RDM). It extracts the first + * connection request on the queue of pending connections, creates a new + * connected socket with mostly the same properties as 'sockfd', and + * allocates a new socket descriptor for the socket, which is returned. The + * newly created socket is no longer in the listening state. The original + * socket 'sockfd' is unaffected by this call. Per file descriptor flags + * are not inherited across an psock_accept. + * + * The 'sockfd' argument is a socket descriptor that has been created with + * socket(), bound to a local address with bind(), and is listening for + * connections after a call to listen(). + * + * On return, the 'addr' structure is filled in with the address of the + * connecting entity. The 'addrlen' argument initially contains the size + * of the structure pointed to by 'addr'; on return it will contain the + * actual length of the address returned. + * + * If no pending connections are present on the queue, and the socket is + * not marked as non-blocking, psock_accept blocks the caller until a + * connection is present. If the socket is marked non-blocking and no + * pending connections are present on the queue, psock_accept returns + * EAGAIN. + * + * Parameters: + * psock Reference to the listening socket structure + * addr Receives the address of the connecting client + * addrlen Input: allocated size of 'addr', Return: returned size of 'addr' + * newsock Location to return the accepted socket information. + * + * Returned Value: + * Returns 0 (OK) on success. On failure, it returns -1 (ERROR) with the + * errno variable set to indicate the nature of the error. + * + * EAGAIN or EWOULDBLOCK + * The socket is marked non-blocking and no connections are present to + * be accepted. + * EOPNOTSUPP + * The referenced socket is not of type SOCK_STREAM. + * EINTR + * The system call was interrupted by a signal that was caught before + * a valid connection arrived. + * ECONNABORTED + * A connection has been aborted. + * EINVAL + * Socket is not listening for connections. + * EMFILE + * The per-process limit of open file descriptors has been reached. + * ENFILE + * The system maximum for file descriptors has been reached. + * EFAULT + * The addr parameter is not in a writable part of the user address + * space. + * ENOBUFS or ENOMEM + * Not enough free memory. + * EPROTO + * Protocol error. + * EPERM + * Firewall rules forbid connection. + * + ****************************************************************************/ + +int psock_accept(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen, FAR struct socket *newsock); + /**************************************************************************** * Name: psock_connect * diff --git a/net/socket/accept.c b/net/socket/accept.c index ea1e887bf9a..11c2301ba8b 100644 --- a/net/socket/accept.c +++ b/net/socket/accept.c @@ -59,17 +59,17 @@ ****************************************************************************/ /**************************************************************************** - * Function: accept + * Function: psock_accept * * Description: - * The accept function is used with connection-based socket types + * The psock_accept function is used with connection-based socket types * (SOCK_STREAM, SOCK_SEQPACKET and SOCK_RDM). It extracts the first * connection request on the queue of pending connections, creates a new * connected socket with mostly the same properties as 'sockfd', and * allocates a new socket descriptor for the socket, which is returned. The * newly created socket is no longer in the listening state. The original * socket 'sockfd' is unaffected by this call. Per file descriptor flags - * are not inherited across an accept. + * are not inherited across an psock_accept. * * The 'sockfd' argument is a socket descriptor that has been created with * socket(), bound to a local address with bind(), and is listening for @@ -81,26 +81,24 @@ * actual length of the address returned. * * If no pending connections are present on the queue, and the socket is - * not marked as non-blocking, accept blocks the caller until a connection - * is present. If the socket is marked non-blocking and no pending - * connections are present on the queue, accept returns EAGAIN. + * not marked as non-blocking, psock_accept blocks the caller until a + * connection is present. If the socket is marked non-blocking and no + * pending connections are present on the queue, psock_accept returns + * EAGAIN. * * Parameters: - * sockfd The listening socket descriptor + * psock Reference to the listening socket structure * addr Receives the address of the connecting client * addrlen Input: allocated size of 'addr', Return: returned size of 'addr' + * newsock Location to return the accepted socket information. * * Returned Value: - * Returns -1 on error. If it succeeds, it returns a non-negative integer - * that is a descriptor for the accepted socket. + * Returns 0 (OK) on success. On failure, it returns -1 (ERROR) with the + * errno variable set to indicate the nature of the error. * * EAGAIN or EWOULDBLOCK * The socket is marked non-blocking and no connections are present to * be accepted. - * EBADF - * The descriptor is invalid. - * ENOTSOCK - * The descriptor references a file, not a socket. * EOPNOTSUPP * The referenced socket is not of type SOCK_STREAM. * EINTR @@ -124,42 +122,17 @@ * EPERM * Firewall rules forbid connection. * - * Assumptions: - * ****************************************************************************/ -int accept(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) +int psock_accept(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen, FAR struct socket *newsock) { - FAR struct socket *psock = sockfd_socket(sockfd); - FAR struct socket *pnewsock; - int newfd; int err; int ret; - /* Verify that the sockfd corresponds to valid, allocated socket */ + DEBUGASSERT(psock != NULL); - if (!psock || psock->s_crefs <= 0) - { - /* It is not a valid socket description. Distinguish between the cases - * where sockfd is a just valid and when it is a valid file descriptor used - * in the wrong context. - */ - -#if CONFIG_NFILE_DESCRIPTORS > 0 - if ((unsigned int)sockfd < CONFIG_NFILE_DESCRIPTORS) - { - err = ENOTSOCK; - } - else -#endif - { - err = EBADF; - } - - goto errout; - } - - /* We have a socket descriptor, but it is a stream? */ + /* Is the socket a stream? */ if (psock->s_type != SOCK_STREAM) { @@ -232,28 +205,10 @@ int accept(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) } } - /* Allocate a socket descriptor for the new connection now (so that it - * cannot fail later) - */ - - newfd = sockfd_allocate(0); - if (newfd < 0) - { - err = ENFILE; - goto errout; - } - - pnewsock = sockfd_socket(newfd); - if (!pnewsock) - { - err = ENFILE; - goto errout_with_socket; - } - /* Initialize the socket structure. */ - pnewsock->s_domain = psock->s_domain; - pnewsock->s_type = SOCK_STREAM; + newsock->s_domain = psock->s_domain; + newsock->s_type = SOCK_STREAM; /* Perform the correct accept operation for this address domain */ @@ -264,11 +219,11 @@ int accept(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) { /* Perform the local accept operation (with the network unlocked) */ - ret = psock_local_accept(psock, addr, addrlen, &pnewsock->s_conn); + ret = psock_local_accept(psock, addr, addrlen, &newsock->s_conn); if (ret < 0) { err = -ret; - goto errout_with_socket; + goto errout; } } #endif /* CONFIG_NET_LOCAL_STREAM */ @@ -283,19 +238,19 @@ int accept(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) /* Perform the local accept operation (with the network locked) */ state = net_lock(); - ret = psock_tcp_accept(psock, addr, addrlen, &pnewsock->s_conn); + ret = psock_tcp_accept(psock, addr, addrlen, &newsock->s_conn); if (ret < 0) { net_unlock(state); err = -ret; - goto errout_with_socket; + goto errout; } /* Begin monitoring for TCP connection events on the newly connected * socket */ - ret = net_startmonitor(pnewsock); + ret = net_startmonitor(newsock); if (ret < 0) { /* net_startmonitor() can only fail on certain race conditions @@ -314,12 +269,145 @@ int accept(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) /* Mark the new socket as connected. */ - pnewsock->s_flags |= _SF_CONNECTED; - pnewsock->s_flags &= ~_SF_CLOSED; - return newfd; + newsock->s_flags |= _SF_CONNECTED; + newsock->s_flags &= ~_SF_CLOSED; + return OK; errout_after_accept: - psock_close(pnewsock); + psock_close(newsock); + +errout: + set_errno(err); + return ERROR; +} + +/**************************************************************************** + * Function: accept + * + * Description: + * The accept function is used with connection-based socket types + * (SOCK_STREAM, SOCK_SEQPACKET and SOCK_RDM). It extracts the first + * connection request on the queue of pending connections, creates a new + * connected socket with mostly the same properties as 'sockfd', and + * allocates a new socket descriptor for the socket, which is returned. The + * newly created socket is no longer in the listening state. The original + * socket 'sockfd' is unaffected by this call. Per file descriptor flags + * are not inherited across an accept. + * + * The 'sockfd' argument is a socket descriptor that has been created with + * socket(), bound to a local address with bind(), and is listening for + * connections after a call to listen(). + * + * On return, the 'addr' structure is filled in with the address of the + * connecting entity. The 'addrlen' argument initially contains the size + * of the structure pointed to by 'addr'; on return it will contain the + * actual length of the address returned. + * + * If no pending connections are present on the queue, and the socket is + * not marked as non-blocking, accept blocks the caller until a connection + * is present. If the socket is marked non-blocking and no pending + * connections are present on the queue, accept returns EAGAIN. + * + * Parameters: + * sockfd The listening socket descriptor + * addr Receives the address of the connecting client + * addrlen Input: allocated size of 'addr', Return: returned size of 'addr' + * + * Returned Value: + * Returns -1 on error. If it succeeds, it returns a non-negative integer + * that is a descriptor for the accepted socket. + * + * EAGAIN or EWOULDBLOCK + * The socket is marked non-blocking and no connections are present to + * be accepted. + * EBADF + * The descriptor is invalid. + * ENOTSOCK + * The descriptor references a file, not a socket. + * EOPNOTSUPP + * The referenced socket is not of type SOCK_STREAM. + * EINTR + * The system call was interrupted by a signal that was caught before + * a valid connection arrived. + * ECONNABORTED + * A connection has been aborted. + * EINVAL + * Socket is not listening for connections. + * EMFILE + * The per-process limit of open file descriptors has been reached. + * ENFILE + * The system maximum for file descriptors has been reached. + * EFAULT + * The addr parameter is not in a writable part of the user address + * space. + * ENOBUFS or ENOMEM + * Not enough free memory. + * EPROTO + * Protocol error. + * EPERM + * Firewall rules forbid connection. + * + ****************************************************************************/ + +int accept(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) +{ + FAR struct socket *psock = sockfd_socket(sockfd); + FAR struct socket *newsock; + int newfd; + int err; + int ret; + + /* Verify that the sockfd corresponds to valid, allocated socket */ + + if (psock == NULL || psock->s_crefs <= 0) + { + /* It is not a valid socket description. Distinguish between the cases + * where sockfd is a just valid and when it is a valid file descriptor used + * in the wrong context. + */ + +#if CONFIG_NFILE_DESCRIPTORS > 0 + if ((unsigned int)sockfd < CONFIG_NFILE_DESCRIPTORS) + { + err = ENOTSOCK; + } + else +#endif + { + err = EBADF; + } + + goto errout; + } + + /* Allocate a socket descriptor for the new connection now (so that it + * cannot fail later) + */ + + newfd = sockfd_allocate(0); + if (newfd < 0) + { + err = ENFILE; + goto errout; + } + + newsock = sockfd_socket(newfd); + if (newsock == NULL) + { + err = ENFILE; + goto errout_with_socket; + } + + ret = psock_accept(psock, addr, addrlen, newsock); + if (ret < 0) + { + /* The errno value has already been set */ + + sockfd_release(newfd); + return ERROR; + } + + return newfd; errout_with_socket: sockfd_release(newfd); diff --git a/net/socket/listen.c b/net/socket/listen.c index cdfc4d9d877..c552d794023 100644 --- a/net/socket/listen.c +++ b/net/socket/listen.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/socket/listen.c * - * Copyright (C) 2007-2009, 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 201-2016 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -42,6 +42,7 @@ #include #include +#include #include #include "tcp/tcp.h" @@ -53,17 +54,17 @@ ****************************************************************************/ /**************************************************************************** - * Function: listen + * Function: psock_listen * * Description: - * To accept connections, a socket is first created with socket(), a - * willingness to accept incoming connections and a queue limit for incoming - * connections are specified with listen(), and then the connections are - * accepted with accept(). The listen() call applies only to sockets of - * type SOCK_STREAM or SOCK_SEQPACKET. + * To accept connections, a socket is first created with psock_socket(), a + * willingness to accept incoming connections and a queue limit for + * incoming connections are specified with psock_listen(), and then the + * connections are accepted with psock_accept(). The psock_listen() call + * applies only to sockets of type SOCK_STREAM or SOCK_SEQPACKET. * * Parameters: - * sockfd Socket descriptor of the bound socket + * psock Reference to an internal, boound socket structure. * backlog The maximum length the queue of pending connections may grow. * If a connection request arrives with the queue full, the client * may receive an error with an indication of ECONNREFUSED or, @@ -76,44 +77,16 @@ * * EADDRINUSE * Another socket is already listening on the same port. - * EBADF - * The argument 'sockfd' is not a valid descriptor. - * ENOTSOCK - * The argument 'sockfd' is not a socket. * EOPNOTSUPP * The socket is not of a type that supports the listen operation. * - * Assumptions: - * ****************************************************************************/ -int listen(int sockfd, int backlog) +int psock_listen(FAR struct socket *psock, int backlog) { - FAR struct socket *psock = sockfd_socket(sockfd); int err; - /* Verify that the sockfd corresponds to valid, allocated socket */ - - if (!psock || psock->s_crefs <= 0) - { - /* It is not a valid socket description. Distinguish between the cases - * where sockfd is a just invalid and when it is a valid file descriptor used - * in the wrong context. - */ - -#if CONFIG_NFILE_DESCRIPTORS > 0 - if ((unsigned int)sockfd < CONFIG_NFILE_DESCRIPTORS) - { - err = ENOTSOCK; - } - else -#endif - { - err = EBADF; - } - - goto errout; - } + DEBUGASSERT(psock != NULL); /* Verify that the sockfd corresponds to a connected SOCK_STREAM */ @@ -181,4 +154,73 @@ errout: return ERROR; } +/**************************************************************************** + * Function: listen + * + * Description: + * To accept connections, a socket is first created with socket(), a + * willingness to accept incoming connections and a queue limit for incoming + * connections are specified with listen(), and then the connections are + * accepted with accept(). The listen() call applies only to sockets of + * type SOCK_STREAM or SOCK_SEQPACKET. + * + * Parameters: + * sockfd Socket descriptor of the bound socket + * backlog The maximum length the queue of pending connections may grow. + * If a connection request arrives with the queue full, the client + * may receive an error with an indication of ECONNREFUSED or, + * if the underlying protocol supports retransmission, the request + * may be ignored so that retries succeed. + * + * Returned Value: + * On success, zero is returned. On error, -1 is returned, and errno is set + * appropriately. + * + * EADDRINUSE + * Another socket is already listening on the same port. + * EBADF + * The argument 'sockfd' is not a valid descriptor. + * ENOTSOCK + * The argument 'sockfd' is not a socket. + * EOPNOTSUPP + * The socket is not of a type that supports the listen operation. + * + ****************************************************************************/ + +int listen(int sockfd, int backlog) +{ + FAR struct socket *psock = sockfd_socket(sockfd); + int err; + + /* Verify that the sockfd corresponds to valid, allocated socket */ + + if (psock == NULL || psock->s_crefs <= 0) + { + /* It is not a valid socket description. Distinguish between the + * cases where sockfd is a just invalid and when it is a valid file + * descriptor used in the wrong context. + */ + +#if CONFIG_NFILE_DESCRIPTORS > 0 + if ((unsigned int)sockfd < CONFIG_NFILE_DESCRIPTORS) + { + err = ENOTSOCK; + } + else +#endif + { + err = EBADF; + } + + set_errno(err); + return ERROR; + } + + /* The let psock_listen to the work. If psock_listen() fails, it will have + * set the errno variable. + */ + + return psock_listen(psock, backlog); +} + #endif /* CONFIG_NET && CONFIG_NSOCKET_DESCRIPTORS */