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.
This commit is contained in:
SPRESENSE 2021-05-19 17:04:24 +09:00 committed by Alin Jerpelea
parent 98871e58af
commit f0cae6cdf3

View File

@ -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;