diff --git a/arch/arm/src/stm32/stm32_rng.c b/arch/arm/src/stm32/stm32_rng.c index ccbbd96dd72..6588814d6c3 100644 --- a/arch/arm/src/stm32/stm32_rng.c +++ b/arch/arm/src/stm32/stm32_rng.c @@ -46,6 +46,7 @@ #include #include +#include #include #include @@ -97,13 +98,20 @@ static const struct file_operations g_rngops = #ifndef CONFIG_DISABLE_POLL , 0 /* poll */ #endif +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS + , 0 /* unlink */ +#endif }; /**************************************************************************** * Private functions ****************************************************************************/ -static int stm32_rng_initialize() +/**************************************************************************** + * Name: stm32_rng_initialize + ****************************************************************************/ + +static int stm32_rng_initialize(void) { uint32_t regval; @@ -133,7 +141,11 @@ static int stm32_rng_initialize() return OK; } -static void stm32_enable() +/**************************************************************************** + * Name: stm32_enable + ****************************************************************************/ + +static void stm32_enable(void) { uint32_t regval; @@ -144,7 +156,11 @@ static void stm32_enable() putreg32(regval, STM32_RNG_CR); } -static void stm32_disable() +/**************************************************************************** + * Name: stm32_disable + ****************************************************************************/ + +static void stm32_disable(void) { uint32_t regval; regval = getreg32(STM32_RNG_CR); @@ -152,6 +168,10 @@ static void stm32_disable() putreg32(regval, STM32_RNG_CR); } +/**************************************************************************** + * Name: stm32_interrupt + ****************************************************************************/ + static int stm32_interrupt(int irq, void *context, FAR void *arg) { uint32_t rngsr; @@ -234,11 +254,14 @@ static ssize_t stm32_read(struct file *filep, char *buffer, size_t buflen) { /* We've got the semaphore. */ - /* Initialize semaphore with 0 for blocking until the buffer is filled from - * interrupts. + /* Initialize the operation semaphore with 0 for blocking until the + * buffer is filled from interrupts. The readsem semaphore is used + * for signaling and, hence, should not have priority inheritance + * enabled. */ - sem_init(&g_rngdev.rd_readsem, 0, 1); + sem_init(&g_rngdev.rd_readsem, 0, 0); + sem_setprotocol(&g_rngdev.rd_readsem, SEM_PRIO_NONE); g_rngdev.rd_buflen = buflen; g_rngdev.rd_buf = buffer; diff --git a/arch/arm/src/stm32f7/Make.defs b/arch/arm/src/stm32f7/Make.defs index d25b702d67d..8baa4fbf135 100644 --- a/arch/arm/src/stm32f7/Make.defs +++ b/arch/arm/src/stm32f7/Make.defs @@ -194,3 +194,7 @@ endif ifeq ($(CONFIG_STM32F7_BBSRAM),y) CHIP_CSRCS += stm32_bbsram.c endif + +ifeq ($(CONFIG_STM32F7_RNG),y) +CHIP_CSRCS += stm32_rng.c +endif diff --git a/arch/arm/src/stm32f7/chip/stm32_rng.h b/arch/arm/src/stm32f7/chip/stm32_rng.h new file mode 100644 index 00000000000..3f5351a074b --- /dev/null +++ b/arch/arm/src/stm32f7/chip/stm32_rng.h @@ -0,0 +1,77 @@ +/************************************************************************************ + * arch/arm/src/stm32f7/chip/stm32_rng.h + * + * Copyright (C) 2012 Max Holtzberg. All rights reserved. + * Author: Max Holtzberg + * + * 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_STC_STM32F7_CHIP_STM32_RNG_H +#define __ARCH_ARM_STC_STM32F7_CHIP_STM32_RNG_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include +#include "chip.h" + +/************************************************************************************ + * Pre-processor Definitions + ************************************************************************************/ + +/* Register Offsets *****************************************************************/ + +#define STM32_RNG_CR_OFFSET 0x0000 /* RNG Control Register */ +#define STM32_RNG_SR_OFFSET 0x0004 /* RNG Status Register */ +#define STM32_RNG_DR_OFFSET 0x0008 /* RNG Data Register */ + +/* Register Addresses ***************************************************************/ + +#define STM32_RNG_CR (STM32_RNG_BASE+STM32_RNG_CR_OFFSET) +#define STM32_RNG_SR (STM32_RNG_BASE+STM32_RNG_SR_OFFSET) +#define STM32_RNG_DR (STM32_RNG_BASE+STM32_RNG_DR_OFFSET) + +/* Register Bitfield Definitions ****************************************************/ + +/* RNG Control Register */ + +#define RNG_CR_RNGEN (1 << 2) /* Bit 2: RNG enable */ +#define RNG_CR_IE (1 << 3) /* Bit 3: Interrupt enable */ + +/* RNG Status Register */ + +#define RNG_SR_DRDY (1 << 0) /* Bit 0: Data ready */ +#define RNG_SR_CECS (1 << 1) /* Bit 1: Clock error current status */ +#define RNG_SR_SECS (1 << 2) /* Bit 2: Seed error current status */ +#define RNG_SR_CEIS (1 << 5) /* Bit 5: Clock error interrupt status */ +#define RNG_SR_SEIS (1 << 6) /* Bit 6: Seed error interrupt status */ + +#endif /* __ARCH_ARM_STC_STM32F7_CHIP_STM32_RNG_H */ diff --git a/arch/arm/src/stm32f7/stm32_rng.c b/arch/arm/src/stm32f7/stm32_rng.c new file mode 100644 index 00000000000..8fb0f466859 --- /dev/null +++ b/arch/arm/src/stm32f7/stm32_rng.c @@ -0,0 +1,362 @@ +/**************************************************************************** + * arch/arm/src/stm32f7/stm32_rng.c + * + * Copyright (C) 2012 Max Holtzberg. All rights reserved. + * Author: Max Holtzberg + * mods for STL32L4 port by dev@ziggurat29.com + * + * 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 +#include +#include + +#include +#include +#include +#include +#include + +#include "up_arch.h" +#include "chip/stm32_rng.h" +#include "up_internal.h" + +#if defined(CONFIG_STM32F7_RNG) +#if defined(CONFIG_DEV_RANDOM) || defined(CONFIG_DEV_URANDOM_ARCH) + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int stm32_rng_initialize(void); +static int stm32_rnginterrupt(int irq, void *context, FAR void *arg); +static void stm32_rngenable(void); +static void stm32_rngdisable(void); +static ssize_t stm32_rngread(struct file *filep, char *buffer, size_t); + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct rng_dev_s +{ + sem_t rd_devsem; /* Threads can only exclusively access the RNG */ + sem_t rd_readsem; /* To block until the buffer is filled */ + char *rd_buf; + size_t rd_buflen; + uint32_t rd_lastval; + bool rd_first; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct rng_dev_s g_rngdev; + +static const struct file_operations g_rngops = +{ + 0, /* open */ + 0, /* close */ + stm32_rngread, /* read */ + 0, /* write */ + 0, /* seek */ + 0 /* ioctl */ +#ifndef CONFIG_DISABLE_POLL + , 0 /* poll */ +#endif +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS + , 0 /* unlink */ +#endif +}; + +/**************************************************************************** + * Private functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_rng_initialize + ****************************************************************************/ + +static int stm32_rng_initialize(void) +{ + _info("Initializing RNG\n"); + + memset(&g_rngdev, 0, sizeof(struct rng_dev_s)); + + sem_init(&g_rngdev.rd_devsem, 0, 1); + + if (irq_attach(STM32_IRQ_RNG, stm32_rnginterrupt, NULL)) + { + /* We could not attach the ISR to the interrupt */ + + _info("Could not attach IRQ.\n"); + + return -EAGAIN; + } + + return OK; +} + +/**************************************************************************** + * Name: stm32_rngenable + ****************************************************************************/ + +static void stm32_rngenable(void) +{ + uint32_t regval; + + g_rngdev.rd_first = true; + + /* Enable generation and interrupts */ + + regval = getreg32(STM32_RNG_CR); + regval |= RNG_CR_RNGEN; + regval |= RNG_CR_IE; + putreg32(regval, STM32_RNG_CR); + + up_enable_irq(STM32_IRQ_RNG); +} + +/**************************************************************************** + * Name: stm32_rngdisable + ****************************************************************************/ + +static void stm32_rngdisable(void) +{ + uint32_t regval; + + up_disable_irq(STM32_IRQ_RNG); + + regval = getreg32(STM32_RNG_CR); + regval &= ~RNG_CR_IE; + regval &= ~RNG_CR_RNGEN; + putreg32(regval, STM32_RNG_CR); +} + +/**************************************************************************** + * Name: stm32_rnginterrupt + ****************************************************************************/ + +static int stm32_rnginterrupt(int irq, void *context, FAR void *arg) +{ + uint32_t rngsr; + uint32_t data; + + rngsr = getreg32(STM32_RNG_SR); + if (rngsr & RNG_SR_CEIS) /* Check for clock error int stat */ + { + /* Clear it, we will try again. */ + + putreg32(rngsr & ~RNG_SR_CEIS, STM32_RNG_SR); + return OK; + } + + if (rngsr & RNG_SR_SEIS) /* Check for seed error in int stat */ + { + uint32_t crval; + + /* Clear seed error, then disable/enable the rng and try again. */ + + putreg32(rngsr & ~RNG_SR_SEIS, STM32_RNG_SR); + crval = getreg32(STM32_RNG_CR); + crval &= ~RNG_CR_RNGEN; + putreg32(crval, STM32_RNG_CR); + crval |= RNG_CR_RNGEN; + putreg32(crval, STM32_RNG_CR); + return OK; + } + + if (!(rngsr & RNG_SR_DRDY)) /* Data ready must be set */ + { + /* This random value is not valid, we will try again. */ + + return OK; + } + + data = getreg32(STM32_RNG_DR); + + /* As required by the FIPS PUB (Federal Information Processing Standard + * Publication) 140-2, the first random number generated after setting the + * RNGEN bit should not be used, but saved for comparison with the next + * generated random number. Each subsequent generated random number has to be + * compared with the previously generated number. The test fails if any two + * compared numbers are equal (continuous random number generator test). + */ + + if (g_rngdev.rd_first) + { + g_rngdev.rd_first = false; + g_rngdev.rd_lastval = data; + return OK; + } + + if (g_rngdev.rd_lastval == data) + { + /* Two subsequent same numbers, we will try again. */ + + return OK; + } + + /* If we get here, the random number is valid. */ + + g_rngdev.rd_lastval = data; + + if (g_rngdev.rd_buflen >= 4) + { + g_rngdev.rd_buflen -= 4; + *(uint32_t *)&g_rngdev.rd_buf[g_rngdev.rd_buflen] = data; + } + else + { + while (g_rngdev.rd_buflen > 0) + { + g_rngdev.rd_buf[--g_rngdev.rd_buflen] = (char)data; + data >>= 8; + } + } + + if (g_rngdev.rd_buflen == 0) + { + /* Buffer filled, stop further interrupts. */ + + stm32_rngdisable(); + sem_post(&g_rngdev.rd_readsem); + } + + return OK; +} + +/**************************************************************************** + * Name: stm32_rngread + ****************************************************************************/ + +static ssize_t stm32_rngread(struct file *filep, char *buffer, size_t buflen) +{ + if (sem_wait(&g_rngdev.rd_devsem) != OK) + { + return -errno; + } + else + { + /* We've got the device semaphore, proceed with reading */ + + /* Initialize the operation semaphore with 0 for blocking until the + * buffer is filled from interrupts. The readsem semaphore is used + * for signaling and, hence, should not have priority inheritance + * enabled. + */ + + sem_init(&g_rngdev.rd_readsem, 0, 0); + sem_setprotocol(&g_rngdev.rd_readsem, SEM_PRIO_NONE); + + g_rngdev.rd_buflen = buflen; + g_rngdev.rd_buf = buffer; + + /* Enable RNG with interrupts */ + + stm32_rngenable(); + + /* Wait until the buffer is filled */ + + sem_wait(&g_rngdev.rd_readsem); + + /* Done with the operation semaphore */ + + sem_destroy(&g_rngdev.rd_readsem); + + /* Free RNG via the device semaphore for next use */ + + sem_post(&g_rngdev.rd_devsem); + + return buflen; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: devrandom_register + * + * Description: + * Initialize the RNG hardware and register the /dev/random driver. + * Must be called BEFORE devurandom_register. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_DEV_RANDOM +void devrandom_register(void) +{ + stm32_rng_initialize(); + (void)register_driver("/dev/random", &g_rngops, 0444, NULL); +} +#endif + +/**************************************************************************** + * Name: devurandom_register + * + * Description: + * Register /dev/urandom + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_DEV_URANDOM_ARCH +void devurandom_register(void) +{ +#ifndef CONFIG_DEV_RANDOM + stm32_rng_initialize(); +#endif + (void)register_driver("/dev/urandom", &g_rngops, 0444, NULL); +} +#endif + +#endif /* CONFIG_DEV_RANDOM || CONFIG_DEV_URANDOM_ARCH */ +#endif /* CONFIG_STM32F7_RNG */ diff --git a/arch/arm/src/stm32l4/stm32l4_rng.c b/arch/arm/src/stm32l4/stm32l4_rng.c index dd0f782f2d0..3334d86ec0a 100644 --- a/arch/arm/src/stm32l4/stm32l4_rng.c +++ b/arch/arm/src/stm32l4/stm32l4_rng.c @@ -145,7 +145,7 @@ static void stm32l4_rngenable(void) up_enable_irq(STM32L4_IRQ_RNG); } -static void stm32l4_rngdisable() +static void stm32l4_rngdisable(void) { uint32_t regval; @@ -261,7 +261,7 @@ static ssize_t stm32l4_rngread(struct file *filep, char *buffer, size_t buflen) /* We've got the device semaphore, proceed with reading */ /* Initialize the operation semaphore with 0 for blocking until the - * buffer is filled from interrupts. The waitsem semaphore is used + * buffer is filled from interrupts. The readsem semaphore is used * for signaling and, hence, should not have priority inheritance * enabled. */ diff --git a/configs/nucleo-l476rg/src/nucleo-l476rg.h b/configs/nucleo-l476rg/src/nucleo-l476rg.h index e82283b177c..a6f676da547 100644 --- a/configs/nucleo-l476rg/src/nucleo-l476rg.h +++ b/configs/nucleo-l476rg/src/nucleo-l476rg.h @@ -71,7 +71,7 @@ # undef HAVE_RTC_DRIVER #endif -#if !defined(CONFIG_STM32_SDIO) || !defined(CONFIG_MMCSD) || \ +#if !defined(CONFIG_STM32L4_SDIO) || !defined(CONFIG_MMCSD) || \ !defined(CONFIG_MMCSD_SDIO) # undef HAVE_MMCSD #endif @@ -293,10 +293,10 @@ /* Global driver instances */ -#ifdef CONFIG_STM32_SPI1 +#ifdef CONFIG_STM32L4_SPI1 extern struct spi_dev_s *g_spi1; #endif -#ifdef CONFIG_STM32_SPI2 +#ifdef CONFIG_STM32L4_SPI2 extern struct spi_dev_s *g_spi2; #endif #ifdef HAVE_MMCSD @@ -308,27 +308,27 @@ extern struct sdio_dev_s *g_sdio; ************************************************************************************/ /************************************************************************************ - * Name: stm32_spiinitialize + * Name: stm32l4_spiinitialize * * Description: * Called to configure SPI chip select GPIO pins. * ************************************************************************************/ -void stm32_spiinitialize(void); +void stm32l4_spiinitialize(void); /************************************************************************************ - * Name: stm32_usbinitialize + * Name: stm32l4_usbinitialize * * Description: * Called to setup USB-related GPIO pins. * ************************************************************************************/ -void stm32_usbinitialize(void); +void stm32l4_usbinitialize(void); /************************************************************************************ - * Name: stm32_pwm_setup + * Name: stm32l4_pwm_setup * * Description: * Initialize PWM and register the PWM device. @@ -336,11 +336,11 @@ void stm32_usbinitialize(void); ************************************************************************************/ #ifdef CONFIG_PWM -int stm32_pwm_setup(void); +int stm32l4_pwm_setup(void); #endif /************************************************************************************ - * Name: stm32_adc_setup + * Name: stm32l4_adc_setup * * Description: * Initialize ADC and register the ADC driver. @@ -348,7 +348,7 @@ int stm32_pwm_setup(void); ************************************************************************************/ #ifdef CONFIG_ADC -int stm32_adc_setup(void); +int stm32l4_adc_setup(void); #endif /**************************************************************************** diff --git a/configs/nucleo-l476rg/src/stm32_appinit.c b/configs/nucleo-l476rg/src/stm32_appinit.c index 41b54976ae4..ceaa3a76f52 100644 --- a/configs/nucleo-l476rg/src/stm32_appinit.c +++ b/configs/nucleo-l476rg/src/stm32_appinit.c @@ -1,5 +1,5 @@ /**************************************************************************** - * configs/nucleo-l476rg/src/stm32_appinit.c + * configs/nucleo-l476rg/src/stm32l4_appinit.c * * Copyright (C) 2016 Gregory Nutt. All rights reserved. * Author: Gregory Nutt @@ -199,20 +199,20 @@ int board_app_initialize(uintptr_t arg) #ifdef CONFIG_PWM /* Initialize PWM and register the PWM device. */ - ret = stm32_pwm_setup(); + ret = stm32l4_pwm_setup(); if (ret < 0) { - syslog(LOG_ERR, "ERROR: stm32_pwm_setup() failed: %d\n", ret); + syslog(LOG_ERR, "ERROR: stm32l4_pwm_setup() failed: %d\n", ret); } #endif #ifdef CONFIG_ADC /* Initialize ADC and register the ADC driver. */ - ret = stm32_adc_setup(); + ret = stm32l4_adc_setup(); if (ret < 0) { - syslog(LOG_ERR, "ERROR: stm32_adc_setup failed: %d\n", ret); + syslog(LOG_ERR, "ERROR: stm32l4_adc_setup failed: %d\n", ret); } #endif diff --git a/configs/nucleo-l476rg/src/stm32_boot.c b/configs/nucleo-l476rg/src/stm32_boot.c index 0389d18cf11..2acb52ee62e 100644 --- a/configs/nucleo-l476rg/src/stm32_boot.c +++ b/configs/nucleo-l476rg/src/stm32_boot.c @@ -1,5 +1,5 @@ /************************************************************************************ - * configs/nucleo-l476rg/src/stm32_boot.c + * configs/nucleo-l476rg/src/stm32l4_boot.c * * Copyright (C) 2014-2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt @@ -82,19 +82,19 @@ void stm32l4_boardinitialize(void) #endif /* Configure SPI chip selects if 1) SP2 is not disabled, and 2) the weak function - * stm32_spiinitialize() has been brought into the link. + * stm32l4_spiinitialize() has been brought into the link. */ -#if defined(CONFIG_STM32_SPI1) || defined(CONFIG_STM32_SPI2) || defined(CONFIG_STM32_SPI3) +#if defined(CONFIG_STM32L4_SPI1) || defined(CONFIG_STM32L4_SPI2) || defined(CONFIG_STM32L4_SPI3) stm32l4_spiinitialize(); #endif /* Initialize USB is 1) USBDEV is selected, 2) the USB controller is not - * disabled, and 3) the weak function stm32_usbinitialize() has been brought + * disabled, and 3) the weak function stm32l4_usbinitialize() has been brought * into the build. */ -#if defined(CONFIG_USBDEV) && defined(CONFIG_STM32_USB) +#if defined(CONFIG_USBDEV) && defined(CONFIG_STM32L4_USB) stm32l4_usbinitialize(); #endif } diff --git a/configs/samv71-xult/netnsh/defconfig b/configs/samv71-xult/netnsh/defconfig index b6512741955..395fe4df825 100644 --- a/configs/samv71-xult/netnsh/defconfig +++ b/configs/samv71-xult/netnsh/defconfig @@ -96,6 +96,7 @@ CONFIG_ARCH="arm" # CONFIG_ARCH_CHIP_LPC2378 is not set # CONFIG_ARCH_CHIP_LPC31XX is not set # CONFIG_ARCH_CHIP_LPC43XX is not set +# CONFIG_ARCH_CHIP_MOXART is not set # CONFIG_ARCH_CHIP_NUC1XX is not set # CONFIG_ARCH_CHIP_SAMA5 is not set # CONFIG_ARCH_CHIP_SAMD is not set @@ -107,7 +108,7 @@ CONFIG_ARCH_CHIP_SAMV7=y # 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 +# CONFIG_ARCH_CHIP_XMC4 is not set # CONFIG_ARCH_ARM7TDMI is not set # CONFIG_ARCH_ARM926EJS is not set # CONFIG_ARCH_ARM920T is not set @@ -457,6 +458,8 @@ CONFIG_SCHED_WAITPID=y # # CONFIG_PTHREAD_MUTEX_TYPES is not set CONFIG_PTHREAD_MUTEX_ROBUST=y +# CONFIG_PTHREAD_MUTEX_UNSAFE is not set +# CONFIG_PTHREAD_MUTEX_BOTH is not set CONFIG_NPTHREAD_KEYS=4 # CONFIG_PTHREAD_CLEANUP is not set # CONFIG_CANCELLATION_POINTS is not set @@ -1160,6 +1163,7 @@ CONFIG_EXAMPLES_NSH=y # CONFIG_EXAMPLES_USBSERIAL is not set # CONFIG_EXAMPLES_WATCHDOG is not set # CONFIG_EXAMPLES_WEBSERVER is not set +# CONFIG_EXAMPLES_XBC_TEST is not set # # File System Utilities diff --git a/include/nuttx/net/sixlowpan.h b/include/nuttx/net/sixlowpan.h index 4887d255f0a..be7f9f1e366 100644 --- a/include/nuttx/net/sixlowpan.h +++ b/include/nuttx/net/sixlowpan.h @@ -50,8 +50,11 @@ ****************************************************************************/ #include + #include +#include + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -223,51 +226,66 @@ (((a)->u16[6]) == 0) && \ (((a)->u8[14]) == 0)) -/* Maximum size of an IEEE802.15.4 frame */ +/* This maximum size of an IEEE802.15.4 frame. Certain, non-standard + * devices may exceed this value, however. + */ -#define SIXLOWPAN_MAC_MAXFRAME 127 +#define SIXLOWPAN_MAC_STDFRAME 127 /**************************************************************************** * Public Types ****************************************************************************/ -/* The header for fragments +/* The device structure for IEEE802.15.4 MAC network device differs from the + * standard Ethernet MAC device structure. The main reason for this + * difference is that fragmentation must be supported. * - * NOTE: We do not define different structures for FRAG1 and FRAGN headers, - * which are different. For FRAG1, the offset field is just not used + * The IEEE802.15.4 MAC does not use the d_buf packet buffer directly. + * Rather, it uses a smaller frame buffer. The packet data is provided to + * the frame buffer each time that the IEEE802.15.4 MAC needs to send + * more data. + * + * This is accomplished by "inheriting" the standard 'struct net_driver_s' + * and appending the frame buffer as well as other metadata needed to + * manage the fragmentation. 'struct ieee802154_driver_s' is cast + * compatible with 'struct net_driver_s' when CONFIG_NET_MULTINIC is not + * defined or when dev->d_lltype == NET_LL_IEEE802154. */ -struct sixlowpan_frag_hdr +struct ieee802154_driver_s { - uint16_t dispatch_size; - uint16_t tag; - uint8_t offset; -}; + /* This definitiona must appear first in the structure definition to + * assure cast compatibility. + */ -/* The HC1 header when HC_UDP is not used - * - * When all fields are compressed and HC_UDP is not used, we use this - * structure. If HC_UDP is used, the ttl is in another spot, and we use the - * sixlowpan_hc1_hc_udp structure - */ + struct net_driver_s i_dev; -struct sixlowpan_hc1hdr_s -{ - uint8_t dispatch; - uint8_t encoding; - uint8_t ttl; -}; + /* IEEE802.15.4 MAC-specific definitions follow. */ -/* HC1 followed by HC_UDP */ + /* The i_frame array is used to hold outgoing frame. When the + * IEEE802.15.4 device polls for new data, the outgoing frame containing + * the next fragment is placed in i_frame. + * + * The network will handle only a single outgong frame at a time. The + * IEEE802.15.4 MAC driver design may be concurrently sending and + * requesting new framesusing break-off fram buffers. That frame buffer + * management must be controlled by the IEEE802.15.4 MAC driver. + * + * Driver provied frame buffers should be 16-bit aligned. + */ -struct sixlowpan_hc1_hcudp_hdr_s -{ - uint8_t dispatch; - uint8_t hc1_encoding; - uint8_t hc_udp_encoding; - uint8_t ttl; - uint8_t ports; - uint16_t udpchksum; + FAR uint8_t *i_frame; + + /* The length of valid data in the i_frame buffer. + * + * When the network device driver calls the network input function, + * i_framelen should be set to zero. If there is frame to be sent + * by the network, i_framelen will be set to indicate the size of + * frame to be sent. The value zero means that there is no frame + * to be sent. + */ + + uint16_t i_framelen; }; /* The structure of a next header compressor. This compressor is provided diff --git a/net/netdev/netdev_register.c b/net/netdev/netdev_register.c index 9a3a01c66d2..4dda608c1ac 100644 --- a/net/netdev/netdev_register.c +++ b/net/netdev/netdev_register.c @@ -230,7 +230,7 @@ int netdev_register(FAR struct net_driver_s *dev, enum net_lltype_e lltype) #ifdef CONFIG_NET_6LOWPAN case NET_LL_IEEE802154: /* IEEE 802.15.4 MAC */ dev->d_llhdrlen = 0; /* REVISIT */ - dev->d_mtu = SIXLOWPAN_MAC_MAXFRAME; + dev->d_mtu = CONFIG_NET_6LOWPAN_FRAMELEN; #ifdef CONFIG_NET_TCP dev->d_recvwndo = CONFIG_NET_6LOWPAN_TCP_RECVWNDO; #endif diff --git a/net/sixlowpan/Kconfig b/net/sixlowpan/Kconfig index 4505a7ee880..84cb1c6652e 100644 --- a/net/sixlowpan/Kconfig +++ b/net/sixlowpan/Kconfig @@ -20,6 +20,14 @@ config NET_6LOWPAN_FRAG CONFIG_NET_6LOWPAN_FRAG specifies if 6lowpan fragmentation should be used or not. Fragmentation is on by default. +config NET_6LOWPAN_FRAMELEN + int "IEEE802.15.4 MAC Frame Length" + default 127 + range 127 999999 + ---help--- + Some wireless devices may use non-standard frame lengths. This + setting should never be smaller than 127. + choice prompt "6loWPAN Compression" default NET_6LOWPAN_COMPRESSION_HC06 @@ -124,6 +132,9 @@ endif # NET_6LOWPAN_COMPRESSION_HC06 config NET_6LOWPAN_RIMEADDR_SIZE int "Rime address size" default 2 + range 2 8 + ---help--- + Only the values 2 and 8 are supported config NET_SIXLOWPAN_MAXAGE int "Packet reassembly timeout" diff --git a/net/sixlowpan/sixlowpan.h b/net/sixlowpan/sixlowpan.h index 46a282b41da..3acd0f48042 100644 --- a/net/sixlowpan/sixlowpan.h +++ b/net/sixlowpan/sixlowpan.h @@ -45,10 +45,24 @@ #ifdef CONFIG_NET_6LOWPAN +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Rime addres macros */ + +#define rimeaddr_copy(dest,src) \ + memcpy(dest, src, CONFIG_NET_6LOWPAN_RIMEADDR_SIZE) + +#define rimeaddr_cmp(addr1,addr2) \ + (memcmp(addr1, addr2, CONFIG_NET_6LOWPAN_RIMEADDR_SIZE) == 0) + /**************************************************************************** * Public Types ****************************************************************************/ +/* Rime address representation */ + struct rimeaddr_s { uint8_t u8[CONFIG_NET_6LOWPAN_RIMEADDR_SIZE]; diff --git a/net/sixlowpan/sixlowpan_send.c b/net/sixlowpan/sixlowpan_send.c index de338945975..b85c685f420 100644 --- a/net/sixlowpan/sixlowpan_send.c +++ b/net/sixlowpan/sixlowpan_send.c @@ -54,6 +54,7 @@ #ifdef CONFIG_NET_6LOWPAN + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -62,11 +63,20 @@ * Name: sixlowpan_send * * Description: - * Process an outgoing UDP or TCP packet. Called from UDP/TCP logic to - * determine if the the packet should be formatted for 6loWPAN output. + * Process an outgoing UDP or TCP packet. Takes an IP packet and formats + * it to be sent on an 802.15.4 network using 6lowpan. Called from common + * UDP/TCP send logic. + * + * The payload data is in the caller 'buf' and is of length 'len'. + * Compressed headers will be added and if necessary the packet is + * fragmented. The resulting packet/fragments are put in dev->d_buf and + * the first frame will be delivered to the 802.15.4 MAC. via ieee->i_frame. + * + * Input Parmeters: * * Input Parameters: - * dev - The IEEE802.15.4 MAC network driver interface. + * dev - The IEEE802.15.4 MAC network driver interface. + * raddr - The MAC address of the destination * * Returned Value: * Ok is returned on success; Othewise a negated errno value is returned. @@ -79,8 +89,10 @@ * ****************************************************************************/ -int sixlowpan_send(FAR struct net_driver_s *dev) +int sixlowpan_send(FAR struct net_driver_s *dev, net_ipv6addr_t raddr) { + FAR struct ieee802154_driver_s *ieee = (FAR struct ieee802154_driver_s *)dev; + net_lock(); /* REVISIT: To be provided */ net_unlock(); @@ -143,6 +155,7 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf, conn = (FAR struct tcp_conn_s *)psock->s_conn; DEBUGASSERT(conn != NULL); +#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6) /* Ignore if not IPv6 domain */ if (conn->domain != PF_INET6) @@ -150,6 +163,7 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf, nwarn("WARNING: Not IPv6\n"); return (ssize_t)-EPROTOTYPE; } +#endif /* Route outgoing message to the correct device */ @@ -188,7 +202,7 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf, * packet. */ - ret = sixlowpan_send(dev); + ret = sixlowpan_send(dev, conn->u.ipv6.raddr); if (ret < 0) { nerr("ERROR: sixlowpan_send() failed: %d\n", ret); @@ -251,6 +265,7 @@ ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf, conn = (FAR struct udp_conn_s *)psock->s_conn; DEBUGASSERT(conn != NULL); +#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6) /* Ignore if not IPv6 domain */ if (conn->domain != PF_INET6) @@ -258,6 +273,7 @@ ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf, nwarn("WARNING: Not IPv6\n"); return (ssize_t)-EPROTOTYPE; } +#endif /* Route outgoing message to the correct device */ @@ -296,7 +312,7 @@ ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf, * packet. */ - ret = sixlowpan_send(dev); + ret = sixlowpan_send(dev, conn->u.ipv6.raddr); if (ret < 0) { nerr("ERROR: sixlowpan_send() failed: %d\n", ret); diff --git a/net/socket/send.c b/net/socket/send.c index 20252fcdaeb..fd37860a1a1 100644 --- a/net/socket/send.c +++ b/net/socket/send.c @@ -164,13 +164,22 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len, /* Try 6loWPAN TCP packet send */ ret = psock_6lowpan_tcp_send(psock, buf, len); + +#ifdef CONFIG_NETDEV_MULTINIC if (ret < 0) -#endif { - /* Try TCP/IP packet send */ + /* UDP/IP packet send */ ret = psock_tcp_send(psock, buf, len); } + +#endif /* CONFIG_NETDEV_MULTINIC */ +#else /* CONFIG_NET_6LOWPAN */ + + /* Only TCP/IP packet send */ + + ret = psock_tcp_send(psock, buf, len); +#endif /* CONFIG_NET_6LOWPAN */ } #endif /* CONFIG_NET_TCP */ } @@ -200,13 +209,22 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len, /* Try 6loWPAN UDP packet send */ ret = psock_6lowpan_udp_send(psock, buf, len); + +#ifdef CONFIG_NETDEV_MULTINIC if (ret < 0) -#endif { /* UDP/IP packet send */ ret = psock_udp_send(psock, buf, len); } + +#endif /* CONFIG_NETDEV_MULTINIC */ +#else /* CONFIG_NET_6LOWPAN */ + + /* Only UDP/IP packet send */ + + ret = psock_udp_send(psock, buf, len); +#endif /* CONFIG_NET_6LOWPAN */ } #endif /* CONFIG_NET_UDP */ } diff --git a/sched/pthread/pthread.h b/sched/pthread/pthread.h index bc0238c9039..b4e87d95339 100644 --- a/sched/pthread/pthread.h +++ b/sched/pthread/pthread.h @@ -112,11 +112,13 @@ int pthread_givesemaphore(sem_t *sem); #ifndef CONFIG_PTHREAD_MUTEX_UNSAFE int pthread_mutex_take(FAR struct pthread_mutex_s *mutex, bool intr); +int pthread_mutex_trytake(FAR struct pthread_mutex_s *mutex); int pthread_mutex_give(FAR struct pthread_mutex_s *mutex); void pthread_mutex_inconsistent(FAR struct pthread_tcb_s *tcb); #else -# define pthread_mutex_take(m,i) pthread_takesemaphore(&(m)->sem,(i)) -# define pthread_mutex_give(m) pthread_givesemaphore(&(m)->sem) +# define pthread_mutex_take(m,i) pthread_takesemaphore(&(m)->sem,(i)) +# define pthread_mutex_trytake(m) sem_trywait(&(m)->sem) +# define pthread_mutex_give(m) pthread_givesemaphore(&(m)->sem) #endif #ifdef CONFIG_PTHREAD_MUTEX_TYPES diff --git a/sched/pthread/pthread_mutex.c b/sched/pthread/pthread_mutex.c index 03bf35ea49e..f11a5b01f6f 100644 --- a/sched/pthread/pthread_mutex.c +++ b/sched/pthread/pthread_mutex.c @@ -50,6 +50,39 @@ #include "sched/sched.h" #include "pthread/pthread.h" +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pthread_mutex_add + * + * Description: + * Add the mutex to the list of mutexes held by this thread. + * + * Parameters: + * mutex - The mux to be locked + * + * Return Value: + * None + * + ****************************************************************************/ + +static void pthread_mutex_add(FAR struct pthread_mutex_s *mutex) +{ + FAR struct pthread_tcb_s *rtcb = (FAR struct pthread_tcb_s *)this_task(); + irqstate_t flags; + + DEBUGASSERT(mutex->flink == NULL); + + /* Add the mutex to the list of mutexes held by this task */ + + flags = enter_critical_section(); + mutex->flink = rtcb->mhead; + rtcb->mhead = mutex; + leave_critical_section(flags); +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -58,8 +91,8 @@ * Name: pthread_mutex_take * * Description: - * Take the pthread_mutex and, if successful, add the mutex to the ist of - * mutexes held by this thread. + * Take the pthread_mutex, waiting if necessary. If successful, add the + * mutex to the list of mutexes held by this thread. * * Parameters: * mutex - The mux to be locked @@ -84,38 +117,104 @@ int pthread_mutex_take(FAR struct pthread_mutex_s *mutex, bool intr) sched_lock(); - /* Take semaphore underlying the mutex */ + /* Error out if the mutex is already in an inconsistent state. */ - ret = pthread_takesemaphore(&mutex->sem, intr); - if (ret == OK) + if ((mutex->flags & _PTHREAD_MFLAGS_INCONSISTENT) != 0) { - DEBUGASSERT(mutex->flink == NULL); + ret = EOWNERDEAD; + } + else + { + /* Take semaphore underlying the mutex */ - /* Check if the holder of the mutex has terminated. In that case, - * the state of the mutex is inconsistent and we return EOWNERDEAD. - */ - - if ((mutex->flags & _PTHREAD_MFLAGS_INCONSISTENT) != 0) + ret = pthread_takesemaphore(&mutex->sem, intr); + if (ret < OK) { - ret = EOWNERDEAD; + ret = get_errno(); } - - /* Add the mutex to the list of mutexes held by this task */ - else { - FAR struct pthread_tcb_s *rtcb = (FAR struct pthread_tcb_s *)this_task(); - irqstate_t flags; + /* Check if the holder of the mutex has terminated without + * releasing. In that case, the state of the mutex is + * inconsistent and we return EOWNERDEAD. + */ - flags = enter_critical_section(); - mutex->flink = rtcb->mhead; - rtcb->mhead = mutex; - leave_critical_section(flags); + if ((mutex->flags & _PTHREAD_MFLAGS_INCONSISTENT) != 0) + { + ret = EOWNERDEAD; + } + + /* Add the mutex to the list of mutexes held by this task */ + + else + { + pthread_mutex_add(mutex); + } } } + + sched_unlock(); + } + + return ret; +} + +/**************************************************************************** + * Name: pthread_mutex_trytake + * + * Description: + * Try to take the pthread_mutex without waiting. If successful, add the + * mutex to the list of mutexes held by this thread. + * + * Parameters: + * mutex - The mux to be locked + * intr - false: ignore EINTR errors when locking; true tread EINTR as + * other errors by returning the errno value + * + * Return Value: + * 0 on success or an errno value on failure. + * + ****************************************************************************/ + +int pthread_mutex_trytake(FAR struct pthread_mutex_s *mutex) +{ + int ret = EINVAL; + + /* Verify input parameters */ + + DEBUGASSERT(mutex != NULL); + if (mutex != NULL) + { + /* Make sure that no unexpected context switches occur */ + + sched_lock(); + + /* Error out if the mutex is already in an inconsistent state. */ + + if ((mutex->flags & _PTHREAD_MFLAGS_INCONSISTENT) != 0) + { + ret = EOWNERDEAD; + } + else + { + /* Try to take the semaphore underlying the mutex */ + + ret = sem_trywait(&mutex->sem); + if (ret < OK) + { + ret = get_errno(); + } + else + { + /* Add the mutex to the list of mutexes held by this task */ + + pthread_mutex_add(mutex); + } + } + + sched_unlock(); } - sched_unlock(); return ret; } @@ -173,7 +272,7 @@ int pthread_mutex_give(FAR struct pthread_mutex_s *mutex) mutex->flink = NULL; leave_critical_section(flags); - + /* Now release the underlying semaphore */ ret = pthread_givesemaphore(&mutex->sem); diff --git a/sched/pthread/pthread_mutextrylock.c b/sched/pthread/pthread_mutextrylock.c index 9083fd465aa..f4cda697b78 100644 --- a/sched/pthread/pthread_mutextrylock.c +++ b/sched/pthread/pthread_mutextrylock.c @@ -102,7 +102,7 @@ int pthread_mutex_trylock(FAR pthread_mutex_t *mutex) /* Try to get the semaphore. */ - status = sem_trywait((FAR sem_t *)&mutex->sem); + status = pthread_mutex_trytake(mutex); if (status == OK) { /* If we successfully obtained the semaphore, then indicate @@ -120,96 +120,91 @@ int pthread_mutex_trylock(FAR pthread_mutex_t *mutex) ret = OK; } - /* sem_trywait failed */ + /* pthread_mutex_trytake failed. Did it fail because the semaphore + * was not avaialable? + */ - else + else if (status == EAGAIN) { - /* Did it fail because the semaphore was not avaialable? */ - - int errcode = get_errno(); - if (errcode == EAGAIN) - { #ifdef CONFIG_PTHREAD_MUTEX_TYPES - /* Check if recursive mutex was locked by the calling thread. */ + /* Check if recursive mutex was locked by the calling thread. */ - if (mutex->type == PTHREAD_MUTEX_RECURSIVE && mutex->pid == mypid) + if (mutex->type == PTHREAD_MUTEX_RECURSIVE && mutex->pid == mypid) + { + /* Increment the number of locks held and return successfully. */ + + if (mutex->nlocks < INT16_MAX) { - /* Increment the number of locks held and return successfully. */ - - if (mutex->nlocks < INT16_MAX) - { - mutex->nlocks++; - ret = OK; - } - else - { - ret = EOVERFLOW; - } + mutex->nlocks++; + ret = OK; } else + { + ret = EOVERFLOW; + } + } + else #endif #ifndef CONFIG_PTHREAD_MUTEX_UNSAFE - /* The calling thread does not hold the semaphore. The correct - * behavior for the 'robust' mutex is to verify that the holder of - * the mutex is still valid. This is protection from the case - * where the holder of the mutex has exitted without unlocking it. - */ + /* The calling thread does not hold the semaphore. The correct + * behavior for the 'robust' mutex is to verify that the holder of + * the mutex is still valid. This is protection from the case + * where the holder of the mutex has exitted without unlocking it. + */ #ifdef CONFIG_PTHREAD_MUTEX_BOTH #ifdef CONFIG_PTHREAD_MUTEX_TYPES - /* Check if this NORMAL mutex is robust */ + /* Check if this NORMAL mutex is robust */ - if (mutex->pid > 0 && - ((mutex->flags & _PTHREAD_MFLAGS_ROBUST) != 0 || - mutex->type != PTHREAD_MUTEX_NORMAL) && - sched_gettcb(mutex->pid) == NULL) + if (mutex->pid > 0 && + ((mutex->flags & _PTHREAD_MFLAGS_ROBUST) != 0 || + mutex->type != PTHREAD_MUTEX_NORMAL) && + sched_gettcb(mutex->pid) == NULL) #else /* CONFIG_PTHREAD_MUTEX_TYPES */ - /* Check if this NORMAL mutex is robust */ + /* Check if this NORMAL mutex is robust */ - if (mutex->pid > 0 && - (mutex->flags & _PTHREAD_MFLAGS_ROBUST) != 0 && - sched_gettcb(mutex->pid) == NULL) + if (mutex->pid > 0 && + (mutex->flags & _PTHREAD_MFLAGS_ROBUST) != 0 && + sched_gettcb(mutex->pid) == NULL) #endif /* CONFIG_PTHREAD_MUTEX_TYPES */ #else /* CONFIG_PTHREAD_MUTEX_ROBUST */ - /* This mutex is always robust, whatever type it is. */ + /* This mutex is always robust, whatever type it is. */ - if (mutex->pid > 0 && sched_gettcb(mutex->pid) == NULL) + if (mutex->pid > 0 && sched_gettcb(mutex->pid) == NULL) #endif - { - DEBUGASSERT(mutex->pid != 0); /* < 0: available, >0 owned, ==0 error */ - DEBUGASSERT((mutex->flags & _PTHREAD_MFLAGS_INCONSISTENT) != 0); + { + DEBUGASSERT(mutex->pid != 0); /* < 0: available, >0 owned, ==0 error */ + DEBUGASSERT((mutex->flags & _PTHREAD_MFLAGS_INCONSISTENT) != 0); - /* A thread holds the mutex, but there is no such thread. - * POSIX requires that the 'robust' mutex return EOWNERDEAD - * in this case. It is then the caller's responsibility to - * call pthread_mutx_consistent() fo fix the mutex. - */ + /* A thread holds the mutex, but there is no such thread. + * POSIX requires that the 'robust' mutex return EOWNERDEAD + * in this case. It is then the caller's responsibility to + * call pthread_mutx_consistent() fo fix the mutex. + */ - mutex->flags |= _PTHREAD_MFLAGS_INCONSISTENT; - ret = EOWNERDEAD; - } - - /* The mutex is locked by another, active thread */ - - else -#endif /* CONFIG_PTHREAD_MUTEX_UNSAFE */ - - { - ret = EBUSY; - } + mutex->flags |= _PTHREAD_MFLAGS_INCONSISTENT; + ret = EOWNERDEAD; } - /* Some other, unhandled error occurred */ + /* The mutex is locked by another, active thread */ else +#endif /* CONFIG_PTHREAD_MUTEX_UNSAFE */ { - ret = errcode; + ret = EBUSY; } } + /* Some other, unhandled error occurred */ + + else + { + ret = status; + } + sched_unlock(); }