This is an automated email from the ASF dual-hosted git repository. jerpelea pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit f0cae6cdf351d6842def9aee1c7ac19f40daf76c Author: SPRESENSE <41312067+sprese...@users.noreply.github.com> AuthorDate: Wed May 19 17:04:24 2021 +0900 arch: cxd56xx: Fix multiple open and close ADC driver ADC driver does not support multiple open and close. It causes the memory corruption by multiple free. This commit fixes this problem by introducing the reference counter. --- arch/arm/src/cxd56xx/cxd56_adc.c | 50 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/arch/arm/src/cxd56xx/cxd56_adc.c b/arch/arm/src/cxd56xx/cxd56_adc.c index 728a01b..9f3ecda 100644 --- a/arch/arm/src/cxd56xx/cxd56_adc.c +++ b/arch/arm/src/cxd56xx/cxd56_adc.c @@ -35,6 +35,7 @@ #include <nuttx/kmalloc.h> #include <nuttx/fs/fs.h> #include <nuttx/irq.h> +#include <nuttx/semaphore.h> #include <arch/chip/scu.h> #include <arch/chip/adc.h> @@ -172,6 +173,8 @@ struct cxd56adc_dev_s struct scufifo_wm_s *wm; /* water mark */ struct math_filter_s *filter; /* math filter */ struct scuev_notify_s * notify; /* notify */ + sem_t exclsem; /* exclusive semaphore */ + int crefs; /* reference count */ }; /**************************************************************************** @@ -218,6 +221,7 @@ static struct cxd56adc_dev_s g_lpadc0priv = .wm = NULL, .filter = NULL, .notify = NULL, + .crefs = 0, }; #endif @@ -233,6 +237,7 @@ static struct cxd56adc_dev_s g_lpadc1priv = .wm = NULL, .filter = NULL, .notify = NULL, + .crefs = 0, }; #endif @@ -248,6 +253,7 @@ static struct cxd56adc_dev_s g_lpadc2priv = .wm = NULL, .filter = NULL, .notify = NULL, + .crefs = 0, }; #endif @@ -263,6 +269,7 @@ static struct cxd56adc_dev_s g_lpadc3priv = .wm = NULL, .filter = NULL, .notify = NULL, + .crefs = 0, }; #endif @@ -278,6 +285,7 @@ static struct cxd56adc_dev_s g_hpadc0priv = .wm = NULL, .filter = NULL, .notify = NULL, + .crefs = 0, }; #endif @@ -293,6 +301,7 @@ static struct cxd56adc_dev_s g_hpadc1priv = .wm = NULL, .filter = NULL, .notify = NULL, + .crefs = 0, }; #endif @@ -703,9 +712,23 @@ static int cxd56_adc_open(FAR struct file *filep) int type; DEBUGASSERT(priv != NULL); - DEBUGASSERT(priv->seq == NULL); DEBUGASSERT(priv->ch < CH_MAX); + /* Increment reference counter */ + + nxsem_wait_uninterruptible(&priv->exclsem); + + priv->crefs++; + DEBUGASSERT(priv->crefs > 0); + + if (priv->crefs > 1) + { + nxsem_post(&priv->exclsem); + return OK; + } + + DEBUGASSERT(priv->seq == NULL); + type = SCU_BUS_LPADC0 + priv->ch; /* Open sequencer */ @@ -713,6 +736,7 @@ static int cxd56_adc_open(FAR struct file *filep) priv->seq = seq_open(SEQ_TYPE_NORMAL, type); if (!priv->seq) { + nxsem_post(&priv->exclsem); return -ENOENT; } @@ -725,11 +749,14 @@ static int cxd56_adc_open(FAR struct file *filep) ret = set_ofstgain(priv); if (ret < 0) { + nxsem_post(&priv->exclsem); return ret; } ainfo("open ch%d freq%d scufifo%d\n", priv->ch, priv->freq, priv->fsize); + nxsem_post(&priv->exclsem); + return OK; } @@ -750,6 +777,19 @@ static int cxd56_adc_close(FAR struct file *filep) DEBUGASSERT(priv->seq != NULL); DEBUGASSERT(priv->ch < CH_MAX); + /* Decrement reference counter */ + + nxsem_wait_uninterruptible(&priv->exclsem); + + DEBUGASSERT(priv->crefs > 0); + priv->crefs--; + + if (priv->crefs > 0) + { + nxsem_post(&priv->exclsem); + return OK; + } + /* Close sequencer */ seq_close(priv->seq); @@ -773,6 +813,8 @@ static int cxd56_adc_close(FAR struct file *filep) priv->notify = NULL; } + nxsem_post(&priv->exclsem); + return OK; } @@ -1058,6 +1100,7 @@ int cxd56_adcinitialize(void) return ret; } + nxsem_init(&g_lpadc0priv.exclsem, 0, 1); #endif #if defined (CONFIG_CXD56_LPADC1) || defined (CONFIG_CXD56_LPADC0_1) || defined (CONFIG_CXD56_LPADC_ALL) ret = register_driver("/dev/lpadc1", &g_adcops, 0666, &g_lpadc1priv); @@ -1067,6 +1110,7 @@ int cxd56_adcinitialize(void) return ret; } + nxsem_init(&g_lpadc1priv.exclsem, 0, 1); #endif #if defined (CONFIG_CXD56_LPADC2) || defined (CONFIG_CXD56_LPADC_ALL) ret = register_driver("/dev/lpadc2", &g_adcops, 0666, &g_lpadc2priv); @@ -1076,6 +1120,7 @@ int cxd56_adcinitialize(void) return ret; } + nxsem_init(&g_lpadc2priv.exclsem, 0, 1); #endif #if defined (CONFIG_CXD56_LPADC3) || defined (CONFIG_CXD56_LPADC_ALL) ret = register_driver("/dev/lpadc3", &g_adcops, 0666, &g_lpadc3priv); @@ -1085,6 +1130,7 @@ int cxd56_adcinitialize(void) return ret; } + nxsem_init(&g_lpadc3priv.exclsem, 0, 1); #endif #ifdef CONFIG_CXD56_HPADC0 ret = register_driver("/dev/hpadc0", &g_adcops, 0666, &g_hpadc0priv); @@ -1094,6 +1140,7 @@ int cxd56_adcinitialize(void) return ret; } + nxsem_init(&g_hpadc0priv.exclsem, 0, 1); #endif #ifdef CONFIG_CXD56_HPADC1 ret = register_driver("/dev/hpadc1", &g_adcops, 0666, &g_hpadc1priv); @@ -1103,6 +1150,7 @@ int cxd56_adcinitialize(void) return ret; } + nxsem_init(&g_hpadc1priv.exclsem, 0, 1); #endif return ret;