Check return from nxsem_wait_initialize()

Resolution of Issue 619 will require multiple steps, this part of the first step in that resolution:  Every call to nxsem_wait_uninterruptible() must handle the return value from nxsem_wait_uninterruptible properly.  This commit is only for those files under drivers/audio, drivers/net, and drivers/lcd.
This commit is contained in:
Gregory Nutt 2020-03-31 08:05:48 -06:00 committed by Abdelatif Guettouche
parent 7f510a61b4
commit 5b74974919
9 changed files with 821 additions and 442 deletions

View file

@ -76,17 +76,20 @@ static
uint8_t cs43l22_readreg(FAR struct cs43l22_dev_s *priv, uint8_t regaddr);
static void cs43l22_writereg(FAR struct cs43l22_dev_s *priv, uint8_t regaddr,
uint8_t regval);
static void cs43l22_takesem(sem_t * sem);
static int cs43l22_takesem(FAR sem_t *sem);
static int cs43l22_forcetake(FAR sem_t *sem);
#define cs43l22_givesem(s) nxsem_post(s)
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
static inline uint16_t cs43l22_scalevolume(uint16_t volume, b16_t scale);
static void cs43l22_setvolume(FAR struct cs43l22_dev_s *priv, uint16_t volume,
bool mute);
static void cs43l22_setvolume(FAR struct cs43l22_dev_s *priv,
uint16_t volume, bool mute);
#endif
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
static void cs43l22_setbass(FAR struct cs43l22_dev_s *priv, uint8_t bass);
static void cs43l22_settreble(FAR struct cs43l22_dev_s *priv, uint8_t treble);
static void cs43l22_setbass(FAR struct cs43l22_dev_s *priv,
uint8_t bass);
static void cs43l22_settreble(FAR struct cs43l22_dev_s *priv,
uint8_t treble);
#endif
static void cs43l22_setdatawidth(FAR struct cs43l22_dev_s *priv);
@ -112,21 +115,25 @@ static void cs43l22_returnbuffers(FAR struct cs43l22_dev_s *priv);
static int cs43l22_sendbuffer(FAR struct cs43l22_dev_s *priv);
#ifdef CONFIG_AUDIO_MULTI_SESSION
static int cs43l22_start(FAR struct audio_lowerhalf_s *dev, FAR void *session);
static int cs43l22_start(FAR struct audio_lowerhalf_s *dev,
FAR void *session);
#else
static int cs43l22_start(FAR struct audio_lowerhalf_s *dev);
#endif
#ifndef CONFIG_AUDIO_EXCLUDE_STOP
#ifdef CONFIG_AUDIO_MULTI_SESSION
static int cs43l22_stop(FAR struct audio_lowerhalf_s *dev, FAR void *session);
static int cs43l22_stop(FAR struct audio_lowerhalf_s *dev,
FAR void *session);
#else
static int cs43l22_stop(FAR struct audio_lowerhalf_s *dev);
#endif
#endif
#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
#ifdef CONFIG_AUDIO_MULTI_SESSION
static int cs43l22_pause(FAR struct audio_lowerhalf_s *dev, FAR void *session);
static int cs43l22_resume(FAR struct audio_lowerhalf_s *dev, FAR void *session);
static int cs43l22_pause(FAR struct audio_lowerhalf_s *dev,
FAR void *session);
static int cs43l22_resume(FAR struct audio_lowerhalf_s *dev,
FAR void *session);
#else
static int cs43l22_pause(FAR struct audio_lowerhalf_s *dev);
static int cs43l22_resume(FAR struct audio_lowerhalf_s *dev);
@ -269,7 +276,6 @@ uint8_t cs43l22_readreg(FAR struct cs43l22_dev_s *priv, uint8_t regaddr)
}
else
{
/* The I2C transfer was successful... break out of the loop and
* return the value read.
*/
@ -286,13 +292,13 @@ uint8_t cs43l22_readreg(FAR struct cs43l22_dev_s *priv, uint8_t regaddr)
return 0;
}
/************************************************************************************
/****************************************************************************
* Name: cs43l22_writereg
*
* Description:
* Write the specified 16-bit register to the CS43L22 device.
*
************************************************************************************/
****************************************************************************/
static void
cs43l22_writereg(FAR struct cs43l22_dev_s *priv, uint8_t regaddr,
@ -355,28 +361,65 @@ cs43l22_writereg(FAR struct cs43l22_dev_s *priv, uint8_t regaddr,
}
}
/************************************************************************************
/****************************************************************************
* Name: cs43l22_takesem
*
* Description:
* Take a semaphore count, handling the nasty EINTR return if we are interrupted
* by a signal.
* Take a semaphore count, handling the nasty EINTR return if we are
* interrupted by a signal.
*
************************************************************************************/
****************************************************************************/
static void cs43l22_takesem(sem_t * sem)
static int cs43l22_takesem(FAR sem_t *sem)
{
nxsem_wait_uninterruptible(sem);
return nxsem_wait_uninterruptible(sem);
}
/************************************************************************************
/****************************************************************************
* Name: cs43l22_forcetake
*
* Description:
* This is just another wrapper but this one continues even if the thread
* is canceled. This must be done in certain conditions where were must
* continue in order to clean-up resources.
*
****************************************************************************/
static int cs43l22_forcetake(FAR sem_t *sem)
{
int result;
int ret = OK;
do
{
result = nxsem_wait_uninterruptible(sem);
/* The only expected error would -ECANCELED meaning that the
* parent thread has been canceled. We have to continue and
* terminate the poll in this case.
*/
DEBUGASSERT(result == OK || result == -ECANCELED);
if (ret == OK && result < 0)
{
/* Remember the first failure */
ret = result;
}
}
while (result < 0);
return ret;
}
/****************************************************************************
* Name: cs43l22_scalevolume
*
* Description:
* Set the right and left volume values in the CS43L22 device based on the current
* volume and balance settings.
* Set the right and left volume values in the CS43L22 device based on the
* current volume and balance settings.
*
************************************************************************************/
****************************************************************************/
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
static inline uint16_t cs43l22_scalevolume(uint16_t volume, b16_t scale)
@ -385,14 +428,14 @@ static inline uint16_t cs43l22_scalevolume(uint16_t volume, b16_t scale)
}
#endif
/************************************************************************************
/****************************************************************************
* Name: cs43l22_setvolume
*
* Description:
* Set the right and left volume values in the CS43L22 device based on the current
* volume and balance settings.
* Set the right and left volume values in the CS43L22 device based on the
* current volume and balance settings.
*
************************************************************************************/
****************************************************************************/
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
static void
@ -420,7 +463,7 @@ cs43l22_setvolume(FAR struct cs43l22_dev_s *priv, uint16_t volume, bool mute)
leftlevel = ((((1000 - priv->balance) * 100) / 500) * volume) / 100;
}
/* Calculate the right channel volume level {0..1000} */
/* Calculate the right channel volume level {0..1000} */
if (priv->balance >= 500)
{
@ -442,10 +485,10 @@ cs43l22_setvolume(FAR struct cs43l22_dev_s *priv, uint16_t volume, bool mute)
/* Set the volume */
regval = (rightlevel + 0x19) & 0xff;
cs43l22_writereg(priv, CS43L22_MS_VOL_CTRL_A, regval);
regval = ((leftlevel + 0x19) & 0xff);
cs43l22_writereg(priv, CS43L22_MS_VOL_CTRL_B, regval);
regval = (rightlevel + 0x19) & 0xff;
cs43l22_writereg(priv, CS43L22_MS_VOL_CTRL_A, regval);
regval = ((leftlevel + 0x19) & 0xff);
cs43l22_writereg(priv, CS43L22_MS_VOL_CTRL_B, regval);
#if 0
regval = (rightlevel + 0x01) & 0xff;
@ -474,7 +517,7 @@ cs43l22_setvolume(FAR struct cs43l22_dev_s *priv, uint16_t volume, bool mute)
}
#endif /* CONFIG_AUDIO_EXCLUDE_VOLUME */
/************************************************************************************
/****************************************************************************
* Name: cs43l22_setbass
*
* Description:
@ -482,7 +525,7 @@ cs43l22_setvolume(FAR struct cs43l22_dev_s *priv, uint16_t volume, bool mute)
*
* The level and range are in whole percentage levels (0-100).
*
************************************************************************************/
****************************************************************************/
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
static void cs43l22_setbass(FAR struct cs43l22_dev_s *priv, uint8_t bass)
@ -492,7 +535,7 @@ static void cs43l22_setbass(FAR struct cs43l22_dev_s *priv, uint8_t bass)
}
#endif /* CONFIG_AUDIO_EXCLUDE_TONE */
/************************************************************************************
/****************************************************************************
* Name: cs43l22_settreble
*
* Description:
@ -500,7 +543,7 @@ static void cs43l22_setbass(FAR struct cs43l22_dev_s *priv, uint8_t bass)
*
* The level and range are in whole percentage levels (0-100).
*
************************************************************************************/
****************************************************************************/
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
static void cs43l22_settreble(FAR struct cs43l22_dev_s *priv, uint8_t treble)
@ -523,11 +566,13 @@ static void cs43l22_setdatawidth(FAR struct cs43l22_dev_s *priv)
if (priv->bpsamp == 16)
{
/* Reset default default setting */
priv->i2s->ops->i2s_txdatawidth(priv->i2s, 16);
}
else
{
/* This should select 8-bit with no companding */
priv->i2s->ops->i2s_txdatawidth(priv->i2s, 8);
}
}
@ -583,17 +628,20 @@ static int cs43l22_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
switch (caps->ac_subtype)
{
case AUDIO_TYPE_QUERY:
/* We don't decode any formats! Only something above us in
* the audio stream can perform decoding on our behalf.
*/
/* The types of audio units we implement */
caps->ac_controls.b[0] = AUDIO_TYPE_OUTPUT | AUDIO_TYPE_FEATURE |
AUDIO_TYPE_PROCESSING;
caps->ac_controls.b[0] =
AUDIO_TYPE_OUTPUT | AUDIO_TYPE_FEATURE |
AUDIO_TYPE_PROCESSING;
break;
case AUDIO_FMT_MIDI:
/* We only support Format 0 */
caps->ac_controls.b[0] = AUDIO_SUBFMT_END;
@ -618,10 +666,11 @@ static int cs43l22_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
/* Report the Sample rates we support */
caps->ac_controls.b[0] = AUDIO_SAMP_RATE_8K | AUDIO_SAMP_RATE_11K |
AUDIO_SAMP_RATE_16K | AUDIO_SAMP_RATE_22K |
AUDIO_SAMP_RATE_32K | AUDIO_SAMP_RATE_44K |
AUDIO_SAMP_RATE_48K;
caps->ac_controls.b[0] =
AUDIO_SAMP_RATE_8K | AUDIO_SAMP_RATE_11K |
AUDIO_SAMP_RATE_16K | AUDIO_SAMP_RATE_22K |
AUDIO_SAMP_RATE_32K | AUDIO_SAMP_RATE_44K |
AUDIO_SAMP_RATE_48K;
break;
case AUDIO_FMT_MP3:
@ -639,19 +688,24 @@ static int cs43l22_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
case AUDIO_TYPE_FEATURE:
/* If the sub-type is UNDEF, then report the Feature Units we support */
/* If the sub-type is UNDEF, then report the Feature Units we
* support.
*/
if (caps->ac_subtype == AUDIO_FU_UNDEF)
{
/* Fill in the ac_controls section with the Feature Units we have */
/* Fill in the ac_controls section with the Feature Units we
* have.
*/
caps->ac_controls.b[0] = AUDIO_FU_VOLUME | AUDIO_FU_BASS | AUDIO_FU_TREBLE;
caps->ac_controls.b[0] = AUDIO_FU_VOLUME | AUDIO_FU_BASS |
AUDIO_FU_TREBLE;
caps->ac_controls.b[1] = AUDIO_FU_BALANCE >> 8;
}
else
{
/* TODO: Do we need to provide specific info for the Feature Units,
* such as volume setting ranges, etc.?
/* TODO: Do we need to provide specific info for the Feature
* Units, such as volume setting ranges, etc.?
*/
}
@ -664,18 +718,22 @@ static int cs43l22_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
switch (caps->ac_subtype)
{
case AUDIO_PU_UNDEF:
/* Provide the type of Processing Units we support */
caps->ac_controls.b[0] = AUDIO_PU_STEREO_EXTENDER;
break;
case AUDIO_PU_STEREO_EXTENDER:
/* Provide capabilities of our Stereo Extender */
caps->ac_controls.b[0] = AUDIO_STEXT_ENABLE | AUDIO_STEXT_WIDTH;
caps->ac_controls.b[0] =
AUDIO_STEXT_ENABLE | AUDIO_STEXT_WIDTH;
break;
default:
/* Other types of processing uint we don't support */
break;
@ -748,7 +806,8 @@ cs43l22_configure(FAR struct audio_lowerhalf_s *dev,
{
/* Scale the volume setting to the range {76..255} */
cs43l22_setvolume(priv, (179 * volume / 1000) + 76, priv->mute);
cs43l22_setvolume(priv, (179 * volume / 1000) + 76,
priv->mute);
}
else
{
@ -945,6 +1004,7 @@ cs43l22_senddone(FAR struct i2s_dev_s *i2s,
priv->inflight--;
/* Save the result of the transfer */
/* REVISIT: This can be overwritten */
priv->result = result;
@ -1047,7 +1107,7 @@ static int cs43l22_sendbuffer(FAR struct cs43l22_dev_s *priv)
irqstate_t flags;
uint32_t timeout;
int shift;
int ret = OK;
int ret;
/* Loop while there are audio buffers to be sent and we have few than
* CONFIG_CS43L22_INFLIGHT then "in-flight"
@ -1061,7 +1121,12 @@ static int cs43l22_sendbuffer(FAR struct cs43l22_dev_s *priv)
* only while accessing 'inflight'.
*/
cs43l22_takesem(&priv->pendsem);
ret = cs43l22_takesem(&priv->pendsem);
if (ret < 0)
{
return ret;
}
while (priv->inflight < CONFIG_CS43L22_INFLIGHT &&
dq_peek(&priv->pendq) != NULL && !priv->paused)
{
@ -1128,7 +1193,8 @@ static int cs43l22_sendbuffer(FAR struct cs43l22_dev_s *priv)
****************************************************************************/
#ifdef CONFIG_AUDIO_MULTI_SESSION
static int cs43l22_start(FAR struct audio_lowerhalf_s *dev, FAR void *session)
static int cs43l22_start(FAR struct audio_lowerhalf_s *dev,
FAR void *session)
#else
static int cs43l22_start(FAR struct audio_lowerhalf_s *dev)
#endif
@ -1143,6 +1209,7 @@ static int cs43l22_start(FAR struct audio_lowerhalf_s *dev)
audinfo("Entry\n");
/* Exit reduced power modes of operation */
/* REVISIT */
/* Create a message queue for the worker thread */
@ -1226,6 +1293,7 @@ static int cs43l22_stop(FAR struct audio_lowerhalf_s *dev)
priv->threadid = 0;
/* Enter into a reduced power usage mode */
/* REVISIT: */
return OK;
@ -1242,7 +1310,8 @@ static int cs43l22_stop(FAR struct audio_lowerhalf_s *dev)
#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
# ifdef CONFIG_AUDIO_MULTI_SESSION
static int cs43l22_pause(FAR struct audio_lowerhalf_s *dev, FAR void *session)
static int cs43l22_pause(FAR struct audio_lowerhalf_s *dev,
FAR void *session)
# else
static int cs43l22_pause(FAR struct audio_lowerhalf_s *dev)
# endif
@ -1272,7 +1341,8 @@ static int cs43l22_pause(FAR struct audio_lowerhalf_s *dev)
#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
# ifdef CONFIG_AUDIO_MULTI_SESSION
static int cs43l22_resume(FAR struct audio_lowerhalf_s *dev, FAR void *session)
static int cs43l22_resume(FAR struct audio_lowerhalf_s *dev,
FAR void *session)
# else
static int cs43l22_resume(FAR struct audio_lowerhalf_s *dev)
# endif
@ -1314,20 +1384,26 @@ static int cs43l22_enqueuebuffer(FAR struct audio_lowerhalf_s *dev,
audinfo("Enqueueing: apb=%p curbyte=%d nbytes=%d flags=%04x\n",
apb, apb->curbyte, apb->nbytes, apb->flags);
ret = cs43l22_takesem(&priv->pendsem);
if (ret < 0)
{
return ret;
}
/* Take a reference on the new audio buffer */
apb_reference(apb);
/* Add the new buffer to the tail of pending audio buffers */
cs43l22_takesem(&priv->pendsem);
apb->flags |= AUDIO_APB_OUTPUT_ENQUEUED;
dq_addlast(&apb->dq_entry, &priv->pendq);
cs43l22_givesem(&priv->pendsem);
/* Send a message to the worker thread indicating that a new buffer has been
* enqueued. If mq is NULL, then the playing has not yet started. In that
* case we are just "priming the pump" and we don't need to send any message.
/* Send a message to the worker thread indicating that a new buffer has
* been enqueued. If mq is NULL, then the playing has not yet started.
* In that case we are just "priming the pump" and we don't need to send
* any message.
*/
ret = OK;
@ -1437,7 +1513,12 @@ static int cs43l22_reserve(FAR struct audio_lowerhalf_s *dev)
/* Borrow the APBQ semaphore for thread sync */
cs43l22_takesem(&priv->pendsem);
ret = cs43l22_takesem(&priv->pendsem);
if (ret < 0)
{
return ret;
}
if (priv->reserved)
{
ret = -EBUSY;
@ -1472,13 +1553,15 @@ static int cs43l22_reserve(FAR struct audio_lowerhalf_s *dev)
****************************************************************************/
#ifdef CONFIG_AUDIO_MULTI_SESSION
static int cs43l22_release(FAR struct audio_lowerhalf_s *dev, FAR void *session)
static int cs43l22_release(FAR struct audio_lowerhalf_s *dev,
FAR void *session)
#else
static int cs43l22_release(FAR struct audio_lowerhalf_s *dev)
#endif
{
FAR struct cs43l22_dev_s *priv = (FAR struct cs43l22_dev_s *)dev;
void *value;
FAR void *value;
int ret;
/* Join any old worker thread we had created to prevent a memory leak */
@ -1490,14 +1573,14 @@ static int cs43l22_release(FAR struct audio_lowerhalf_s *dev)
/* Borrow the APBQ semaphore for thread sync */
cs43l22_takesem(&priv->pendsem);
ret = cs43l22_forcetake(&priv->pendsem);
/* Really we should free any queued buffers here */
priv->reserved = false;
cs43l22_givesem(&priv->pendsem);
return OK;
return ret;
}
/****************************************************************************
@ -1623,6 +1706,7 @@ static void *cs43l22_workerthread(pthread_addr_t pvarg)
#ifndef CONFIG_AUDIO_EXCLUDE_STOP
case AUDIO_MSG_STOP:
/* Indicate that we are terminating */
audinfo("AUDIO_MSG_STOP: Terminating\n");
@ -1657,7 +1741,7 @@ static void *cs43l22_workerthread(pthread_addr_t pvarg)
/* Return any pending buffers in our pending queue */
cs43l22_takesem(&priv->pendsem);
cs43l22_forcetake(&priv->pendsem);
while ((apb = (FAR struct ap_buffer_s *)dq_remfirst(&priv->pendq)) != NULL)
{
/* Release our reference to the buffer */
@ -1722,7 +1806,8 @@ static void cs43l22_audio_output(FAR struct cs43l22_dev_s *priv)
/* SPK always off and HP always on */
regval = CS43L22_PDN_HPB_ON | CS43L22_PDN_HPA_ON | CS43L22_PDN_SPKB_OFF | CS43L22_PDN_SPKA_OFF;
regval = CS43L22_PDN_HPB_ON | CS43L22_PDN_HPA_ON | CS43L22_PDN_SPKB_OFF |
CS43L22_PDN_SPKA_OFF;
cs43l22_writereg(priv, CS43L22_POWER_CTRL2, regval);
/* Clock configuration: Auto detection */
@ -1841,7 +1926,7 @@ static void cs43l22_reset(FAR struct cs43l22_dev_s *priv)
priv->nchannels = CS43L22_DEFAULT_NCHANNELS;
priv->bpsamp = CS43L22_DEFAULT_BPSAMP;
#if !defined(CONFIG_AUDIO_EXCLUDE_VOLUME) && !defined(CONFIG_AUDIO_EXCLUDE_BALANCE)
priv->balance = 500; // b16HALF; /* Center balance */
priv->balance = 500; /* b16HALF = Center balance */
#endif
/* Software reset. This puts all CS43L22 registers back in their
@ -1889,10 +1974,9 @@ static void cs43l22_reset(FAR struct cs43l22_dev_s *priv)
*
****************************************************************************/
FAR struct audio_lowerhalf_s *cs43l22_initialize(FAR struct i2c_master_s *i2c,
FAR struct i2s_dev_s *i2s,
FAR const struct
cs43l22_lower_s *lower)
FAR struct audio_lowerhalf_s *
cs43l22_initialize(FAR struct i2c_master_s *i2c, FAR struct i2s_dev_s *i2s,
FAR const struct cs43l22_lower_s *lower)
{
FAR struct cs43l22_dev_s *priv;
uint16_t regval;
@ -1903,7 +1987,8 @@ FAR struct audio_lowerhalf_s *cs43l22_initialize(FAR struct i2c_master_s *i2c,
/* Allocate a CS43L22 device structure */
priv = (FAR struct cs43l22_dev_s *)kmm_zalloc(sizeof(struct cs43l22_dev_s));
priv = (FAR struct cs43l22_dev_s *)
kmm_zalloc(sizeof(struct cs43l22_dev_s));
if (priv)
{
/* Initialize the CS43L22 device structure. Since we used kmm_zalloc,
@ -1921,10 +2006,12 @@ FAR struct audio_lowerhalf_s *cs43l22_initialize(FAR struct i2c_master_s *i2c,
/* Initialize I2C */
audinfo("address=%02x frequency=%d\n", lower->address, lower->frequency);
audinfo("address=%02x frequency=%d\n",
lower->address, lower->frequency);
/* Software reset. This puts all CS43L22 registers back in their default
* state. */
/* Software reset. This puts all CS43L22 registers back in their
* default state.
*/
CS43L22_HW_RESET(priv->lower);

View file

@ -74,7 +74,8 @@
static void wm8776_writereg(FAR struct wm8776_dev_s *priv,
uint8_t regaddr, uint16_t regval);
static void wm8776_takesem(sem_t *sem);
static int wm8776_takesem(FAR sem_t *sem);
static int wm8776_forcetake(FAR sem_t *sem);
#define wm8776_givesem(s) nxsem_post(s)
static int wm8776_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
@ -174,13 +175,13 @@ static const struct audio_ops_s g_audioops =
wm8776_release /* release */
};
/************************************************************************************
/****************************************************************************
* Name: wm8776_writereg
*
* Description:
* Write the specified 16-bit register to the WM8776 device.
*
************************************************************************************/
****************************************************************************/
static void wm8776_writereg(FAR struct wm8776_dev_s *priv,
uint8_t regaddr,
@ -208,28 +209,65 @@ static void wm8776_writereg(FAR struct wm8776_dev_s *priv,
}
}
/************************************************************************************
/****************************************************************************
* Name: wm8776_takesem
*
* Description:
* Take a semaphore count, handling the nasty EINTR return if we are interrupted
* by a signal.
* Take a semaphore count, handling the nasty EINTR return if we are
* interrupted by a signal.
*
************************************************************************************/
****************************************************************************/
static void wm8776_takesem(sem_t *sem)
static int wm8776_takesem(sem_t *sem)
{
nxsem_wait_uninterruptible(sem);
return nxsem_wait_uninterruptible(sem);
}
/************************************************************************************
/****************************************************************************
* Name: wm8776_forcetake
*
* Description:
* This is just another wrapper but this one continues even if the thread
* is canceled. This must be done in certain conditions where were must
* continue in order to clean-up resources.
*
****************************************************************************/
static int wm8776_forcetake(FAR sem_t *sem)
{
int result;
int ret = OK;
do
{
result = nxsem_wait_uninterruptible(sem);
/* The only expected error would -ECANCELED meaning that the
* parent thread has been canceled. We have to continue and
* terminate the poll in this case.
*/
DEBUGASSERT(result == OK || result == -ECANCELED);
if (ret == OK && result < 0)
{
/* Remember the first failure */
ret = result;
}
}
while (result < 0);
return ret;
}
/****************************************************************************
* Name: wm8776_setvolume
*
* Description:
* Set the right and left volume values in the WM8776 device based on the current
* volume and balance settings.
* Set the right and left volume values in the WM8776 device based on the
* current volume and balance settings.
*
************************************************************************************/
****************************************************************************/
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
static void wm8776_setvolume(FAR struct wm8776_dev_s *priv, uint16_t volume,
@ -312,8 +350,9 @@ static int wm8776_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
/* The types of audio units we implement */
caps->ac_controls.b[0] = AUDIO_TYPE_OUTPUT | AUDIO_TYPE_FEATURE |
AUDIO_TYPE_PROCESSING;
caps->ac_controls.b[0] =
AUDIO_TYPE_OUTPUT | AUDIO_TYPE_FEATURE |
AUDIO_TYPE_PROCESSING;
break;
@ -413,13 +452,14 @@ static int wm8776_configure(FAR struct audio_lowerhalf_s *dev,
{
/* Scale the volume setting to the range {0x2f .. 0x79} */
wm8776_setvolume(priv, (0x4a * volume / 1000) + 0x2f, priv->mute);
wm8776_setvolume(priv, (0x4a * volume / 1000) + 0x2f,
priv->mute);
}
else
{
ret = -EDOM;
}
}
}
break;
#endif /* CONFIG_AUDIO_EXCLUDE_VOLUME */
@ -537,6 +577,7 @@ static void wm8776_senddone(FAR struct i2s_dev_s *i2s,
priv->inflight--;
/* Save the result of the transfer */
/* REVISIT: This can be overwritten */
priv->result = result;
@ -639,7 +680,7 @@ static int wm8776_sendbuffer(FAR struct wm8776_dev_s *priv)
irqstate_t flags;
uint32_t timeout;
int shift;
int ret = OK;
int ret;
/* Loop while there are audio buffers to be sent and we have few than
* CONFIG_WM8776_INFLIGHT then "in-flight"
@ -653,7 +694,12 @@ static int wm8776_sendbuffer(FAR struct wm8776_dev_s *priv)
* only while accessing 'inflight'.
*/
wm8776_takesem(&priv->pendsem);
ret = wm8776_takesem(&priv->pendsem);
if (ret < 0)
{
return ret;
}
while (priv->inflight < CONFIG_WM8776_INFLIGHT &&
dq_peek(&priv->pendq) != NULL && !priv->paused)
{
@ -713,6 +759,7 @@ static int wm8776_start(FAR struct audio_lowerhalf_s *dev)
audinfo("Entry\n");
/* Exit reduced power modes of operation */
/* REVISIT */
/* Create a message queue for the worker thread */
@ -796,6 +843,7 @@ static int wm8776_stop(FAR struct audio_lowerhalf_s *dev)
priv->threadid = 0;
/* Enter into a reduced power usage mode */
/* REVISIT: */
return OK;
@ -837,7 +885,8 @@ static int wm8776_pause(FAR struct audio_lowerhalf_s *dev)
#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
#ifdef CONFIG_AUDIO_MULTI_SESSION
static int wm8776_resume(FAR struct audio_lowerhalf_s *dev, FAR void *session)
static int wm8776_resume(FAR struct audio_lowerhalf_s *dev,
FAR void *session)
#else
static int wm8776_resume(FAR struct audio_lowerhalf_s *dev)
#endif
@ -878,14 +927,20 @@ static int wm8776_enqueuebuffer(FAR struct audio_lowerhalf_s *dev,
/* Add the new buffer to the tail of pending audio buffers */
wm8776_takesem(&priv->pendsem);
ret = wm8776_takesem(&priv->pendsem);
if (ret < 0)
{
return ret;
}
apb->flags |= AUDIO_APB_OUTPUT_ENQUEUED;
dq_addlast(&apb->dq_entry, &priv->pendq);
wm8776_givesem(&priv->pendsem);
/* Send a message to the worker thread indicating that a new buffer has been
* enqueued. If mq is NULL, then the playing has not yet started. In that
* case we are just "priming the pump" and we don't need to send any message.
/* Send a message to the worker thread indicating that a new buffer has
* been enqueued. If mq is NULL, then the playing has not yet started.
* In that case we are just "priming the pump" and we don't need to send
* any message.
*/
ret = OK;
@ -996,7 +1051,12 @@ static int wm8776_reserve(FAR struct audio_lowerhalf_s *dev)
/* Borrow the APBQ semaphore for thread sync */
wm8776_takesem(&priv->pendsem);
ret = wm8776_takesem(&priv->pendsem);
if (ret < 0)
{
return ret;
}
if (priv->reserved)
{
ret = -EBUSY;
@ -1037,7 +1097,8 @@ static int wm8776_release(FAR struct audio_lowerhalf_s *dev)
#endif
{
FAR struct wm8776_dev_s *priv = (FAR struct wm8776_dev_s *)dev;
void *value;
FAR void *value;
int ret;
/* Join any old worker thread we had created to prevent a memory leak */
@ -1049,14 +1110,14 @@ static int wm8776_release(FAR struct audio_lowerhalf_s *dev)
/* Borrow the APBQ semaphore for thread sync */
wm8776_takesem(&priv->pendsem);
ret = wm8776_forcetake(&priv->pendsem);
/* Really we should free any queued buffers here */
priv->reserved = false;
wm8776_givesem(&priv->pendsem);
return OK;
return ret;
}
/****************************************************************************
@ -1075,11 +1136,12 @@ static int wm8776_release(FAR struct audio_lowerhalf_s *dev)
static void wm8776_audio_output(FAR struct wm8776_dev_s *priv)
{
wm8776_writereg(priv, WM8776_MASTER_ATT, WM8776_UPDATE | 0x58); /* -33db */
wm8776_writereg(priv, WM8776_DAC_IF, 0x32); /* 32bit, I2S, standard pol */
wm8776_writereg(priv, WM8776_MASTER_ATT,
WM8776_UPDATE | 0x58); /* -33db */
wm8776_writereg(priv, WM8776_DAC_IF, 0x32); /* 32bit, I2S, standard pol */
#ifdef CONFIG_WM8776_SWAP_HPOUT
wm8776_writereg(priv, WM8776_DAC_CC, 0x62); /* Swap HPOUT L/R */
wm8776_writereg(priv, WM8776_DAC_CC, 0x62); /* Swap HPOUT L/R */
#endif
wm8776_writereg(priv, WM8776_MASTER_MODE, 0x00); /* slave mode, 128fs */
@ -1120,7 +1182,6 @@ static void wm8776_hw_reset(FAR struct wm8776_dev_s *priv)
/* Configure the WM8776 hardware as an audio input device */
wm8776_audio_output(priv);
}
/****************************************************************************
@ -1203,6 +1264,7 @@ repeat:
#ifndef CONFIG_AUDIO_EXCLUDE_STOP
case AUDIO_MSG_STOP:
/* Indicate that we are terminating */
audinfo("AUDIO_MSG_STOP: Terminating\n");
@ -1238,7 +1300,6 @@ repeat:
{
goto repeat;
}
}
/* Reset the WM8776 hardware */
@ -1247,7 +1308,7 @@ repeat:
/* Return any pending buffers in our pending queue */
wm8776_takesem(&priv->pendsem);
wm8776_forcetake(&priv->pendsem);
while ((apb = (FAR struct ap_buffer_s *)dq_remfirst(&priv->pendq)) != NULL)
{
/* Release our reference to the buffer */
@ -1287,7 +1348,6 @@ repeat:
return NULL;
}
/****************************************************************************
* Public Functions
****************************************************************************/

View file

@ -94,7 +94,8 @@ static
uint8_t regaddr);
static void wm8904_writereg(FAR struct wm8904_dev_s *priv,
uint8_t regaddr, uint16_t regval);
static void wm8904_takesem(sem_t *sem);
static int wm8904_takesem(FAR sem_t *sem);
static int wm8904_forcetake(FAR sem_t *sem);
#define wm8904_givesem(s) nxsem_post(s)
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
@ -104,7 +105,8 @@ static void wm8904_setvolume(FAR struct wm8904_dev_s *priv,
#endif
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
static void wm8904_setbass(FAR struct wm8904_dev_s *priv, uint8_t bass);
static void wm8904_settreble(FAR struct wm8904_dev_s *priv, uint8_t treble);
static void wm8904_settreble(FAR struct wm8904_dev_s *priv,
uint8_t treble);
#endif
static void wm8904_setdatawidth(FAR struct wm8904_dev_s *priv);
@ -225,9 +227,9 @@ static const struct audio_ops_s g_audioops =
#ifndef CONFIG_WM8904_CLKDEBUG
static
#endif
const uint8_t g_sysclk_scaleb1[WM8904_BCLK_MAXDIV+1] =
const uint8_t g_sysclk_scaleb1[WM8904_BCLK_MAXDIV + 1] =
{
2, 3, 4, 6, 8, 10, 11, /* 1, 1.5, 2, 3, 4, 5, 5.5 */
2, 3, 4, 6, 8, 10, 11, /* 1, 1.5, 2, 3, 4, 5, 5.5 */
12, 16, 20, 22, 24, 32, 40, /* 6, 8, 10, 11, 12, 16, 20 */
44, 48, 50, 60, 64, 88, 96 /* 22, 24, 25, 30, 32, 44, 48 */
};
@ -297,7 +299,8 @@ uint16_t wm8904_readreg(FAR struct wm8904_dev_s *priv, uint8_t regaddr)
if (retries < MAX_RETRIES)
{
audwarn("WARNING: I2C_TRANSFER failed: %d ... Resetting\n", ret);
audwarn("WARNING: I2C_TRANSFER failed: %d ... Resetting\n",
ret);
ret = I2C_RESET(priv->i2c);
if (ret < 0)
@ -331,13 +334,13 @@ uint16_t wm8904_readreg(FAR struct wm8904_dev_s *priv, uint8_t regaddr)
return 0;
}
/************************************************************************************
/****************************************************************************
* Name: wm8904_writereg
*
* Description:
* Write the specified 16-bit register to the WM8904 device.
*
************************************************************************************/
****************************************************************************/
static void wm8904_writereg(FAR struct wm8904_dev_s *priv, uint8_t regaddr,
uint16_t regval)
@ -405,28 +408,65 @@ static void wm8904_writereg(FAR struct wm8904_dev_s *priv, uint8_t regaddr,
}
}
/************************************************************************************
/****************************************************************************
* Name: wm8904_takesem
*
* Description:
* Take a semaphore count, handling the nasty EINTR return if we are interrupted
* by a signal.
* Take a semaphore count, handling the nasty EINTR return if we are
* interrupted by a signal.
*
************************************************************************************/
****************************************************************************/
static void wm8904_takesem(sem_t *sem)
static int wm8904_takesem(sem_t *sem)
{
nxsem_wait_uninterruptible(sem);
return nxsem_wait_uninterruptible(sem);
}
/************************************************************************************
/****************************************************************************
* Name: wm8904_forcetake
*
* Description:
* This is just another wrapper but this one continues even if the thread
* is canceled. This must be done in certain conditions where were must
* continue in order to clean-up resources.
*
****************************************************************************/
static int wm8904_forcetake(FAR sem_t *sem)
{
int result;
int ret = OK;
do
{
result = nxsem_wait_uninterruptible(sem);
/* The only expected error would -ECANCELED meaning that the
* parent thread has been canceled. We have to continue and
* terminate the poll in this case.
*/
DEBUGASSERT(result == OK || result == -ECANCELED);
if (ret == OK && result < 0)
{
/* Remember the first failure */
ret = result;
}
}
while (result < 0);
return ret;
}
/****************************************************************************
* Name: wm8904_scalevolume
*
* Description:
* Set the right and left volume values in the WM8904 device based on the current
* volume and balance settings.
* Set the right and left volume values in the WM8904 device based on the
* current volume and balance settings.
*
************************************************************************************/
****************************************************************************/
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
static inline uint16_t wm8904_scalevolume(uint16_t volume, b16_t scale)
@ -435,14 +475,14 @@ static inline uint16_t wm8904_scalevolume(uint16_t volume, b16_t scale)
}
#endif
/************************************************************************************
/****************************************************************************
* Name: wm8904_setvolume
*
* Description:
* Set the right and left volume values in the WM8904 device based on the current
* volume and balance settings.
* Set the right and left volume values in the WM8904 device based on the
* current volume and balance settings.
*
************************************************************************************/
****************************************************************************/
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
static void wm8904_setvolume(FAR struct wm8904_dev_s *priv, uint16_t volume,
@ -514,7 +554,7 @@ static void wm8904_setvolume(FAR struct wm8904_dev_s *priv, uint16_t volume,
}
#endif /* CONFIG_AUDIO_EXCLUDE_VOLUME */
/************************************************************************************
/****************************************************************************
* Name: wm8904_setbass
*
* Description:
@ -522,7 +562,7 @@ static void wm8904_setvolume(FAR struct wm8904_dev_s *priv, uint16_t volume,
*
* The level and range are in whole percentage levels (0-100).
*
************************************************************************************/
****************************************************************************/
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
static void wm8904_setbass(FAR struct wm8904_dev_s *priv, uint8_t bass)
@ -532,7 +572,7 @@ static void wm8904_setbass(FAR struct wm8904_dev_s *priv, uint8_t bass)
}
#endif /* CONFIG_AUDIO_EXCLUDE_TONE */
/************************************************************************************
/****************************************************************************
* Name: wm8904_settreble
*
* Description:
@ -540,7 +580,7 @@ static void wm8904_setbass(FAR struct wm8904_dev_s *priv, uint8_t bass)
*
* The level and range are in whole percentage levels (0-100).
*
************************************************************************************/
****************************************************************************/
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
static void wm8904_settreble(FAR struct wm8904_dev_s *priv, uint8_t treble)
@ -710,12 +750,12 @@ static void wm8904_setbitrate(FAR struct wm8904_dev_s *priv)
/* MCLK must be divided down so that fref <=13.5MHz */
if (fref > 4*13500000)
if (fref > 4 * 13500000)
{
fref >>= 3;
regval = (WM8904_FLL_CLK_REF_SRC_MCLK | WM8904_FLL_CLK_REF_DIV8);
}
else if (fref > 2*13500000)
else if (fref > 2 * 13500000)
{
fref >>= 2;
regval = (WM8904_FLL_CLK_REF_SRC_MCLK | WM8904_FLL_CLK_REF_DIV4);
@ -841,6 +881,7 @@ static void wm8904_setbitrate(FAR struct wm8904_dev_s *priv)
priv->bitrate = fout;
/* Now, Configure the FLL */
/* FLL Control 1
*
* FLL_FRACN_ENA=1 : Enables fractional mode
@ -918,7 +959,7 @@ static void wm8904_setbitrate(FAR struct wm8904_dev_s *priv)
retries = 5;
do
{
nxsig_usleep(5*5000);
nxsig_usleep(5 * 5000);
}
while (priv->locked == false && --retries > 0);
@ -941,10 +982,11 @@ static void wm8904_setbitrate(FAR struct wm8904_dev_s *priv)
retries = 5;
do
{
nxsig_usleep(5*5000);
nxsig_usleep(5 * 5000);
}
while ((wm8904_readreg(priv, WM8904_INT_STATUS) & WM8904_FLL_LOCK_INT) != 0 ||
--retries > 0);
while ((wm8904_readreg(priv, WM8904_INT_STATUS) &
WM8904_FLL_LOCK_INT) != 0 ||
--retries > 0);
/* Clear all pending status bits by writing 1's into the interrupt status
* register.
@ -996,18 +1038,21 @@ static int wm8904_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
switch (caps->ac_subtype)
{
case AUDIO_TYPE_QUERY:
/* We don't decode any formats! Only something above us in
* the audio stream can perform decoding on our behalf.
*/
/* The types of audio units we implement */
caps->ac_controls.b[0] = AUDIO_TYPE_OUTPUT | AUDIO_TYPE_FEATURE |
AUDIO_TYPE_PROCESSING;
caps->ac_controls.b[0] =
AUDIO_TYPE_OUTPUT | AUDIO_TYPE_FEATURE |
AUDIO_TYPE_PROCESSING;
break;
case AUDIO_FMT_MIDI:
/* We only support Format 0 */
caps->ac_controls.b[0] = AUDIO_SUBFMT_END;
@ -1032,10 +1077,11 @@ static int wm8904_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
/* Report the Sample rates we support */
caps->ac_controls.b[0] = AUDIO_SAMP_RATE_8K | AUDIO_SAMP_RATE_11K |
AUDIO_SAMP_RATE_16K | AUDIO_SAMP_RATE_22K |
AUDIO_SAMP_RATE_32K | AUDIO_SAMP_RATE_44K |
AUDIO_SAMP_RATE_48K;
caps->ac_controls.b[0] =
AUDIO_SAMP_RATE_8K | AUDIO_SAMP_RATE_11K |
AUDIO_SAMP_RATE_16K | AUDIO_SAMP_RATE_22K |
AUDIO_SAMP_RATE_32K | AUDIO_SAMP_RATE_44K |
AUDIO_SAMP_RATE_48K;
break;
case AUDIO_FMT_MP3:
@ -1059,13 +1105,14 @@ static int wm8904_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
{
/* Fill in the ac_controls section with the Feature Units we have */
caps->ac_controls.b[0] = AUDIO_FU_VOLUME | AUDIO_FU_BASS | AUDIO_FU_TREBLE;
caps->ac_controls.b[0] = AUDIO_FU_VOLUME | AUDIO_FU_BASS |
AUDIO_FU_TREBLE;
caps->ac_controls.b[1] = AUDIO_FU_BALANCE >> 8;
}
else
{
/* TODO: Do we need to provide specific info for the Feature Units,
* such as volume setting ranges, etc.?
/* TODO: Do we need to provide specific info for the Feature
* Units, such as volume setting ranges, etc.?
*/
}
@ -1088,7 +1135,8 @@ static int wm8904_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
/* Provide capabilities of our Stereo Extender */
caps->ac_controls.b[0] = AUDIO_STEXT_ENABLE | AUDIO_STEXT_WIDTH;
caps->ac_controls.b[0] =
AUDIO_STEXT_ENABLE | AUDIO_STEXT_WIDTH;
break;
default:
@ -1342,6 +1390,7 @@ static void wm8904_senddone(FAR struct i2s_dev_s *i2s,
priv->inflight--;
/* Save the result of the transfer */
/* REVISIT: This can be overwritten */
priv->result = result;
@ -1444,7 +1493,7 @@ static int wm8904_sendbuffer(FAR struct wm8904_dev_s *priv)
irqstate_t flags;
uint32_t timeout;
int shift;
int ret = OK;
int ret;
/* Loop while there are audio buffers to be sent and we have few than
* CONFIG_WM8904_INFLIGHT then "in-flight"
@ -1458,7 +1507,12 @@ static int wm8904_sendbuffer(FAR struct wm8904_dev_s *priv)
* only while accessing 'inflight'.
*/
wm8904_takesem(&priv->pendsem);
ret = wm8904_takesem(&priv->pendsem);
if (ret < 0)
{
return ret;
}
while (priv->inflight < CONFIG_WM8904_INFLIGHT &&
dq_peek(&priv->pendq) != NULL && !priv->paused)
{
@ -1540,6 +1594,7 @@ static int wm8904_start(FAR struct audio_lowerhalf_s *dev)
audinfo("Entry\n");
/* Exit reduced power modes of operation */
/* REVISIT */
/* Create a message queue for the worker thread */
@ -1623,6 +1678,7 @@ static int wm8904_stop(FAR struct audio_lowerhalf_s *dev)
priv->threadid = 0;
/* Enter into a reduced power usage mode */
/* REVISIT: */
return OK;
@ -1667,7 +1723,8 @@ static int wm8904_pause(FAR struct audio_lowerhalf_s *dev)
#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
#ifdef CONFIG_AUDIO_MULTI_SESSION
static int wm8904_resume(FAR struct audio_lowerhalf_s *dev, FAR void *session)
static int wm8904_resume(FAR struct audio_lowerhalf_s *dev,
FAR void *session)
#else
static int wm8904_resume(FAR struct audio_lowerhalf_s *dev)
#endif
@ -1714,14 +1771,20 @@ static int wm8904_enqueuebuffer(FAR struct audio_lowerhalf_s *dev,
/* Add the new buffer to the tail of pending audio buffers */
wm8904_takesem(&priv->pendsem);
ret = wm8904_takesem(&priv->pendsem);
if (ret < 0)
{
return ret;
}
apb->flags |= AUDIO_APB_OUTPUT_ENQUEUED;
dq_addlast(&apb->dq_entry, &priv->pendq);
wm8904_givesem(&priv->pendsem);
/* Send a message to the worker thread indicating that a new buffer has been
* enqueued. If mq is NULL, then the playing has not yet started. In that
* case we are just "priming the pump" and we don't need to send any message.
/* Send a message to the worker thread indicating that a new buffer has
* been enqueued. If mq is NULL, then the playing has not yet started.
* In that case we are just "priming the pump" and we don't need to send
* any message.
*/
ret = OK;
@ -1824,11 +1887,16 @@ static int wm8904_reserve(FAR struct audio_lowerhalf_s *dev)
#endif
{
FAR struct wm8904_dev_s *priv = (FAR struct wm8904_dev_s *) dev;
int ret = OK;
int ret;
/* Borrow the APBQ semaphore for thread sync */
wm8904_takesem(&priv->pendsem);
ret = wm8904_takesem(&priv->pendsem);
if (ret < 0)
{
return ret;
}
if (priv->reserved)
{
ret = -EBUSY;
@ -1869,7 +1937,8 @@ static int wm8904_release(FAR struct audio_lowerhalf_s *dev)
#endif
{
FAR struct wm8904_dev_s *priv = (FAR struct wm8904_dev_s *)dev;
void *value;
FAR void *value;
int ret;
/* Join any old worker thread we had created to prevent a memory leak */
@ -1881,14 +1950,14 @@ static int wm8904_release(FAR struct audio_lowerhalf_s *dev)
/* Borrow the APBQ semaphore for thread sync */
wm8904_takesem(&priv->pendsem);
ret = wm8904_forcetake(&priv->pendsem);
/* Really we should free any queued buffers here */
priv->reserved = false;
wm8904_givesem(&priv->pendsem);
return OK;
return ret;
}
/****************************************************************************
@ -2069,6 +2138,7 @@ static void *wm8904_workerthread(pthread_addr_t pvarg)
#ifndef CONFIG_AUDIO_EXCLUDE_STOP
case AUDIO_MSG_STOP:
/* Indicate that we are terminating */
audinfo("AUDIO_MSG_STOP: Terminating\n");
@ -2103,7 +2173,7 @@ static void *wm8904_workerthread(pthread_addr_t pvarg)
/* Return any pending buffers in our pending queue */
wm8904_takesem(&priv->pendsem);
wm8904_forcetake(&priv->pendsem);
while ((apb = (FAR struct ap_buffer_s *)dq_remfirst(&priv->pendq)) != NULL)
{
/* Release our reference to the buffer */
@ -2174,6 +2244,7 @@ static void wm8904_audio_output(FAR struct wm8904_dev_s *priv)
wm8904_writereg(priv, WM8904_VMID_CTRL, regval);
/* Mic Bias Control 0 */
/* MICDET_ENA=1, MICBIAS_ENA=1 */
regval = WM8904_MICDET_ENA | WM8904_MICBIAS_ENA;
@ -2194,15 +2265,17 @@ static void wm8904_audio_output(FAR struct wm8904_dev_s *priv)
wm8904_writereg(priv, WM8904_PM2, regval);
/* Power Management 6 */
/* DACL_ENA=1, DACR_ENA=1, ADCL_ENA=1, ADCR_ENA=1 */
regval = WM8904_DACL_ENA | WM8904_DACR_ENA | WM8904_ADCL_ENA | WM8904_ADCR_ENA;
regval = WM8904_DACL_ENA | WM8904_DACR_ENA | WM8904_ADCL_ENA |
WM8904_ADCR_ENA;
wm8904_writereg(priv, WM8904_PM6, regval);
/* Clock Rates 0.
*
* This value sets TOCLK_RATE_DIV16=0, TOCLK_RATE_X4=0, and MCLK_DIV=0 while
* preserving the state of some undocumented bits (see wm8904.h).
* This value sets TOCLK_RATE_DIV16=0, TOCLK_RATE_X4=0, and MCLK_DIV=0
* while preserving the state of some undocumented bits (see wm8904.h).
*
* MCLK_DIV=0 : MCLK is is not divided by 2.
*/
@ -2244,13 +2317,14 @@ static void wm8904_audio_output(FAR struct wm8904_dev_s *priv)
/* Audio Interface 1.
*
* This value sets AIFADC_TDM=0, AIFADC_TDM_CHAN=0, BCLK_DIR=1 while preserving
* the state of some undocumented bits (see wm8904.h).
* This value sets AIFADC_TDM=0, AIFADC_TDM_CHAN=0, BCLK_DIR=1 while
* preserving the state of some undocumented bits (see wm8904.h).
*
* Digital audio interface format : I2S
* Digital audio interface word length : 24
* AIF_LRCLK_INV=0 : LRCLK not inverted
* BCLK_DIR=1 : BCLK is an output (will clock I2S).
* BCLK_DIR=1 : BCLK is an output (will clock
* I2S).
* AIF_BCLK_INV=0 : BCLK not inverted
* AIF_TRIS=0 : Outputs not tri-stated
* AIFADC_TDM_CHAN=0 : ADCDAT outputs data on slot 0
@ -2260,7 +2334,8 @@ static void wm8904_audio_output(FAR struct wm8904_dev_s *priv)
* Bit 14: : Undocumented
*/
regval = WM8904_AIF_FMT_I2S | WM8904_AIF_WL_24BITS | WM8904_BCLK_DIR | 0x4000;
regval = WM8904_AIF_FMT_I2S | WM8904_AIF_WL_24BITS | WM8904_BCLK_DIR |
0x4000;
wm8904_writereg(priv, WM8904_AIF1, regval);
/* Audio Interface 2.
@ -2271,10 +2346,10 @@ static void wm8904_audio_output(FAR struct wm8904_dev_s *priv)
/* Audio Interface 3
*
* Set LRCLK as an output with rate = BCLK / (2*WM8904_FRAMELENn). This is
* a value that varies with bits per sample, n=8 or 16. Since I2S will send
* a word on each edge of LRCLK (after a delay), this essentially means that
* each audio frame is WM8904_FRAMELENn bits in length.
* Set LRCLK as an output with rate = BCLK / (2*WM8904_FRAMELENn). This
* is a value that varies with bits per sample, n=8 or 16. Since I2S will
* send a word on each edge of LRCLK (after a delay), this essentially
* means that each audio frame is WM8904_FRAMELENn bits in length.
*/
regval = WM8904_LRCLK_DIR | WM8904_LRCLK_RATE(2*WM8904_FRAMELEN16);
@ -2285,6 +2360,7 @@ static void wm8904_audio_output(FAR struct wm8904_dev_s *priv)
wm8904_writereg(priv, WM8904_DAC_DIGI1, 0);
/* Analogue Left Input 0 */
/* Analogue Right Input 0 */
regval = WM8904_IN_VOL(5);
@ -2297,6 +2373,7 @@ static void wm8904_audio_output(FAR struct wm8904_dev_s *priv)
wm8904_writereg(priv, WM8904_ANA_RIGHT_IN1, 0);
/* Analogue OUT1 Left */
/* Analogue OUT1 Right */
wm8904_setvolume(priv, CONFIG_WM8904_INITVOLUME, true);
@ -2308,8 +2385,9 @@ static void wm8904_audio_output(FAR struct wm8904_dev_s *priv)
/* Analogue HP 0 */
regval = WM8904_HPL_RMV_SHORT | WM8904_HPL_ENA_OUTP | WM8904_HPL_ENA_DLY | WM8904_HPL_ENA |
WM8904_HPR_RMV_SHORT | WM8904_HPR_ENA_OUTP | WM8904_HPR_ENA_DLY | WM8904_HPR_ENA;
regval = WM8904_HPL_RMV_SHORT | WM8904_HPL_ENA_OUTP | WM8904_HPL_ENA_DLY |
WM8904_HPL_ENA | WM8904_HPR_RMV_SHORT | WM8904_HPR_ENA_OUTP |
WM8904_HPR_ENA_DLY | WM8904_HPR_ENA;
wm8904_writereg(priv, WM8904_ANA_HP0, regval);
/* Charge Pump 0 */

View file

@ -1,51 +1,40 @@
/**************************************************************************************
/****************************************************************************
* drivers/lcd/ft80x.c
*
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* References:
* - Document No.: FT_000792, "FT800 Embedded Video Engine", Datasheet Version 1.1,
* Clearance No.: FTDI# 334, Future Technology Devices International Ltd.
* - Document No.: FT_000986, "FT801 Embedded Video Engine Datasheet", Version 1.0,
* Clearance No.: FTDI#376, Future Technology Devices International Ltd.
* - Application Note AN_240AN_240, "FT800 From the Ground Up", Version 1.1,
* Issue Date: 2014-06-09, Future Technology Devices International Ltd.
* - "FT800 Series Programmer Guide Guide", Version 2.1, Issue Date: 2016-09-19,
* Future Technology Devices International Ltd.
* http://www.apache.org/licenses/LICENSE-2.0
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* 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.
*
**************************************************************************************/
****************************************************************************/
/**************************************************************************************
/* References:
* - Document No.: FT_000792, "FT800 Embedded Video Engine", Datasheet
* Version 1.1, Clearance No.: FTDI# 334, Future Technology Devices
* International Ltd.
* - Document No.: FT_000986, "FT801 Embedded Video Engine Datasheet",
* Version 1.0, Clearance No.: FTDI#376, Future Technology Devices
* International Ltd.
* - Application Note AN_240AN_240, "FT800 From the Ground Up", Version
* 1.1, Issue Date: 2014-06-09, Future Technology Devices International
* Ltd.
* - "FT800 Series Programmer Guide Guide", Version 2.1, Issue Date:
* 2016-09-19, Future Technology Devices International Ltd.
*/
/****************************************************************************
* Included Files
**************************************************************************************/
****************************************************************************/
#include <nuttx/config.h>
@ -154,6 +143,35 @@ static const struct file_operations g_ft80x_fops =
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: ft80x_forcetake
*
* Description:
* This is a wrapper around but nxsem_wait_uninterruptible(). The wrapper
* continues to wait even if the thread is canceled. This must be done in
* certain conditions where were must continue in order to clean-up
* resources.
*
****************************************************************************/
static void ft80x_forcetake(FAR sem_t *sem)
{
int ret;
do
{
ret = nxsem_wait_uninterruptible(sem);
/* The only expected error would -ECANCELED meaning that the
* parent thread has been canceled. We have to continue and
* terminate the poll in this case.
*/
DEBUGASSERT(ret == OK || ret == -ECANCELED);
}
while (ret < 0);
}
/****************************************************************************
* Name: ft80x_fade
*
@ -295,7 +313,7 @@ static void ft80x_interrupt_work(FAR void *arg)
/* Get exclusive access to the device structures */
nxsem_wait_uninterruptible(&priv->exclsem);
ft80x_forcetake(&priv->exclsem);
/* Get the set of pending interrupts. Note that simply reading this
* register is sufficient to clear all pending interrupts.
@ -309,74 +327,74 @@ static void ft80x_interrupt_work(FAR void *arg)
* implementation.
*/
if ((intflags & FT80X_INT_SWAP) != 0)
{
/* Display swap occurred */
if ((intflags & FT80X_INT_SWAP) != 0)
{
/* Display swap occurred */
lcdinfo("Display swap occurred\n");
ft80x_notify(priv, FT80X_NOTIFY_SWAP, 0);
}
lcdinfo("Display swap occurred\n");
ft80x_notify(priv, FT80X_NOTIFY_SWAP, 0);
}
if ((intflags & FT80X_INT_TOUCH) != 0)
{
/* Touch-screen touch detected */
if ((intflags & FT80X_INT_TOUCH) != 0)
{
/* Touch-screen touch detected */
lcdinfo("Touch-screen touch detected\n");
ft80x_notify(priv, FT80X_NOTIFY_TOUCH, 0);
}
lcdinfo("Touch-screen touch detected\n");
ft80x_notify(priv, FT80X_NOTIFY_TOUCH, 0);
}
if ((intflags & FT80X_INT_TAG) != 0)
{
/* Touch-screen tag value change */
if ((intflags & FT80X_INT_TAG) != 0)
{
/* Touch-screen tag value change */
lcdinfo("Touch-screen tag value change\n");
lcdinfo("Touch-screen tag value change\n");
#ifdef CONFIG_LCD_FT800
regval = ft80x_read_word(priv, FT80X_REG_TOUCH_TAG);
regval = ft80x_read_word(priv, FT80X_REG_TOUCH_TAG);
#else
regval = ft80x_read_word(priv, FT80X_REG_CTOUCH_TAG);
regval = ft80x_read_word(priv, FT80X_REG_CTOUCH_TAG);
#endif
ft80x_notify(priv, FT80X_NOTIFY_TAG, (int)(regval & TOUCH_TAG_MASK));
}
ft80x_notify(priv, FT80X_NOTIFY_TAG, (int)(regval & TOUCH_TAG_MASK));
}
if ((intflags & FT80X_INT_SOUND) != 0)
{
/* Sound effect ended */
if ((intflags & FT80X_INT_SOUND) != 0)
{
/* Sound effect ended */
lcdinfo(" Sound effect ended\n");
ft80x_notify(priv, FT80X_NOTIFY_SOUND, 0);
}
lcdinfo(" Sound effect ended\n");
ft80x_notify(priv, FT80X_NOTIFY_SOUND, 0);
}
if ((intflags & FT80X_INT_PLAYBACK) != 0)
{
/* Audio playback ended */
if ((intflags & FT80X_INT_PLAYBACK) != 0)
{
/* Audio playback ended */
lcdinfo("Audio playback ended\n");
ft80x_notify(priv, FT80X_NOTIFY_PLAYBACK, 0);
}
lcdinfo("Audio playback ended\n");
ft80x_notify(priv, FT80X_NOTIFY_PLAYBACK, 0);
}
if ((intflags & FT80X_INT_CMDEMPTY) != 0)
{
/* Command FIFO empty */
if ((intflags & FT80X_INT_CMDEMPTY) != 0)
{
/* Command FIFO empty */
lcdinfo("Command FIFO empty\n");
ft80x_notify(priv, FT80X_NOTIFY_CMDEMPTY, 0);
}
lcdinfo("Command FIFO empty\n");
ft80x_notify(priv, FT80X_NOTIFY_CMDEMPTY, 0);
}
if ((intflags & FT80X_INT_CMDFLAG) != 0)
{
/* Command FIFO flag */
if ((intflags & FT80X_INT_CMDFLAG) != 0)
{
/* Command FIFO flag */
lcdinfo("Command FIFO flag\n");
ft80x_notify(priv, FT80X_NOTIFY_CMDFLAG, 0);
}
lcdinfo("Command FIFO flag\n");
ft80x_notify(priv, FT80X_NOTIFY_CMDFLAG, 0);
}
if ((intflags & FT80X_INT_CONVCOMPLETE) != 0)
{
/* Touch-screen conversions completed */
if ((intflags & FT80X_INT_CONVCOMPLETE) != 0)
{
/* Touch-screen conversions completed */
lcdinfo(" Touch-screen conversions completed\n");
ft80x_notify(priv, FT80X_NOTIFY_CONVCOMPLETE, 0);
}
lcdinfo(" Touch-screen conversions completed\n");
ft80x_notify(priv, FT80X_NOTIFY_CONVCOMPLETE, 0);
}
/* Re-enable interrupts */
@ -598,7 +616,7 @@ static ssize_t ft80x_write(FAR struct file *filep, FAR const char *buffer,
if (buffer == NULL || ((uintptr_t)buffer & 3) != 0 ||
len == 0 || (len & 3) != 0 || (len + filep->f_pos) > FT80X_RAM_DL_SIZE)
{
return -EINVAL;
return -EINVAL;
}
/* Get exclusive access to the device structures */
@ -659,12 +677,14 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
switch (cmd)
{
/* FT80X_IOC_CREATEDL:
* Description: Write a display list to the FT80x display list memory
* Description: Write a display list to the FT80x display list memory
* starting at offset zero. This may or may not be the
* entire display list. Display lists may be created
* incrementally, starting with FT80X_IOC_CREATEDL and
* finishing the display list using FT80XIO_APPENDDL
* Description: Write a display list to the FT80x display list
* memory
* Description: Write a display list to the FT80x display list
* memory starting at offset zero. This may or may
* not be the entire display list. Display lists may
* be created incrementally, starting with
* FT80X_IOC_CREATEDL and finishing the display list
* using FT80XIO_APPENDDL
* Argument: A reference to a display list structure instance.
* See struct ft80x_displaylist_s.
* Returns: None
@ -682,12 +702,13 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
/* FT80X_IOC_APPENDDL:
* Description: Write additional display list entries to the FT80x
* display list memory at the current display list offset.
* This IOCTL command permits display lists to be completed
* incrementally, starting with FT80X_IOC_CREATEDL and
* finishing the display list using FT80XIO_APPENDDL.
* Argument: A reference to a display list structure instance. See
* struct ft80x_displaylist_s.
* display list memory at the current display list
* offset. This IOCTL command permits display lists
* to be completed incrementally, starting with
* FT80X_IOC_CREATEDL and finishing the display list
* using FT80XIO_APPENDDL.
* Argument: A reference to a display list structure instance.
* See struct ft80x_displaylist_s.
* Returns: None
*/
@ -778,7 +799,7 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
/* FT80X_IOC_PUTRAMCMD
* Description: Write 32-bit aligned data to FT80x FIFO (RAM_CMD)
* Argument: A reference to an instance of struct ft80x_relmem_s below.
* Argument: A reference to an instance of struct ft80x_relmem_s.
* Returns: None.
*/
@ -787,8 +808,7 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
FAR struct ft80x_relmem_s *ramcmd =
(FAR struct ft80x_relmem_s *)((uintptr_t)arg);
if (ramcmd == NULL || ((uintptr_t)ramcmd->offset & 3) != 0 /* ||
ramcmd->offset >= FT80X_CMDFIFO_SIZE */ )
if (ramcmd == NULL || ((uintptr_t)ramcmd->offset & 3) != 0)
{
ret = -EINVAL;
}
@ -803,7 +823,8 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
/* FT80X_IOC_GETREG8:
* Description: Read an 8-bit register value from the FT80x.
* Argument: A reference to an instance of struct ft80x_register_s.
* Argument: A reference to an instance of struct
* ft80x_register_s.
* Returns: The 8-bit value read from the register.
*/
@ -826,7 +847,8 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
/* FT80X_IOC_GETREG16:
* Description: Read a 16-bit register value from the FT80x.
* Argument: A reference to an instance of struct ft80x_register_s.
* Argument: A reference to an instance of struct
* ft80x_register_s.
* Returns: The 16-bit value read from the register.
*/
@ -849,7 +871,8 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
/* FT80X_IOC_GETREG32:
* Description: Read a 32-bit register value from the FT80x.
* Argument: A reference to an instance of struct ft80x_register_s.
* Argument: A reference to an instance of struct
* ft80x_register_s.
* Returns: The 32-bit value read from the register.
*/
@ -872,8 +895,10 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
/* FT80X_IOC_GETREGS:
* Description: Read multiple 32-bit register values from the FT80x.
* Argument: A reference to an instance of struct ft80x_registers_s.
* Returns: The 32-bit values read from the consecutive registers .
* Argument: A reference to an instance of struct
* ft80x_registers_s.
* Returns: The 32-bit values read from the consecutive
* registers .
*/
case FT80X_IOC_GETREGS:
@ -896,7 +921,8 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
/* FT80X_IOC_PUTREG8:
* Description: Write an 8-bit register value to the FT80x.
* Argument: A reference to an instance of struct ft80x_register_s.
* Argument: A reference to an instance of struct
* ft80x_register_s.
* Returns: None.
*/
@ -919,7 +945,8 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
/* FT80X_IOC_PUTREG16:
* Description: Write a 16-bit register value to the FT80x.
* Argument: A reference to an instance of struct ft80x_register_s.
* Argument: A reference to an instance of struct
* ft80x_register_s.
* Returns: None.
*/
@ -942,7 +969,8 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
/* FT80X_IOC_PUTREG32:
* Description: Write a 32-bit register value to the FT80x.
* Argument: A reference to an instance of struct ft80x_register_s.
* Argument: A reference to an instance of struct
* ft80x_register_s.
* Returns: None.
*/
@ -965,7 +993,8 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
/* FT80X_IOC_PUTREGS:
* Description: Write multiple 32-bit register values to the FT80x.
* Argument: A reference to an instance of struct ft80x_registers_s.
* Argument: A reference to an instance of struct
* ft80x_registers_s.
* Returns: None.
*/
@ -1091,7 +1120,8 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
#if defined(CONFIG_LCD_FT80X_AUDIO_MCUSHUTDOWN)
/* Amplifier is controlled by an MCU GPIO pin */
DEBUGASSERT(priv->lower->attach != NULL && priv->lower->audio != NULL);
DEBUGASSERT(priv->lower->attach != NULL &&
priv->lower->audio != NULL);
DEBUGASSERT(arg == 0 || arg == 1);
priv->lower->audio(priv->lower, (arg != 0));
@ -1207,8 +1237,8 @@ static int ft80x_initialize(FAR struct ft80x_dev_s *priv)
* - FT80X_REG_VSYNC0
* - FT80X_REG_VSYNC1
*
* And the FT80X_REG_CSPREAD register changes color clock timing to reduce system
* noise.
* And the FT80X_REG_CSPREAD register changes color clock timing to reduce
* system noise.
*
* GPIO bit 7 is used for the display enable pin of the LCD module. By
* setting the direction of the GPIO bit to out direction, the display can
@ -1221,7 +1251,8 @@ static int ft80x_initialize(FAR struct ft80x_dev_s *priv)
*
* 1. Drive the PD_N pin high
* 2. Wait for at least 20ms
* 3. Execute "Initialization Sequence during the Boot up" from steps 1 to 9
* 3. Execute "Initialization Sequence during the Boot up" from steps 1
* to 9
*
* Initialization Sequence from Sleep Mode:
*
@ -1235,9 +1266,9 @@ static int ft80x_initialize(FAR struct ft80x_dev_s *priv)
* Mode" except waiting for at least 20ms in step 2.
*/
DEBUGASSERT(priv->lower != NULL && priv->lower->pwrdown != NULL);
priv->lower->pwrdown(priv->lower, false);
up_mdelay(20);
DEBUGASSERT(priv->lower != NULL && priv->lower->pwrdown != NULL);
priv->lower->pwrdown(priv->lower, false);
up_mdelay(20);
/* Initialization Sequence during the boot up:
*
@ -1320,8 +1351,8 @@ static int ft80x_initialize(FAR struct ft80x_dev_s *priv)
* checked, the next task is to configure the LCD display parameters for
* the chosen display with the values determined in Section 2.3.3 above.
*
* a. Set FT80X_REG_PCLK to zero - This disables the pixel clock output while
* the LCD and other system parameters are configured
* a. Set FT80X_REG_PCLK to zero - This disables the pixel clock output
* while the LCD and other system parameters are configured
* b. Set the following registers with values for the chosen display.
* Typical WQVGA and QVGA values are shown:
*
@ -1388,8 +1419,8 @@ static int ft80x_initialize(FAR struct ft80x_dev_s *priv)
/* 5. Write first display list */
ft80x_write_word(priv, FT80X_RAM_DL + 0, FT80X_CLEAR_COLOR_RGB(0,0,0));
ft80x_write_word(priv, FT80X_RAM_DL + 4, FT80X_CLEAR(1,1,1));
ft80x_write_word(priv, FT80X_RAM_DL + 0, FT80X_CLEAR_COLOR_RGB(0, 0, 0));
ft80x_write_word(priv, FT80X_RAM_DL + 4, FT80X_CLEAR(1, 1, 1));
ft80x_write_word(priv, FT80X_RAM_DL + 8, FT80X_DISPLAY());
/* 6. Write FT80X_REG_DLSWAP, FT800 swaps display list immediately */

View file

@ -101,7 +101,7 @@ struct phy_notify_s
* Private Function Prototypes
****************************************************************************/
static void phy_semtake(void);
static int phy_semtake(void);
static FAR struct phy_notify_s *phy_find_unassigned(void);
static FAR struct phy_notify_s *phy_find_assigned(FAR const char *intf,
pid_t pid);
@ -128,9 +128,9 @@ static struct phy_notify_s
* Name: phy_semtake
****************************************************************************/
static void phy_semtake(void)
static int phy_semtake(void)
{
nxsem_wait_uninterruptible(&g_notify_clients_sem);
return nxsem_wait_uninterruptible(&g_notify_clients_sem);
}
#define phy_semgive() nxsem_post(&g_notify_clients_sem);
@ -142,9 +142,16 @@ static void phy_semtake(void)
static FAR struct phy_notify_s *phy_find_unassigned(void)
{
FAR struct phy_notify_s *client;
int ret;
int i;
phy_semtake();
ret = phy_semtake();
if (ret < 0)
{
phyerr("ERROR: phy_semtake failed: %d\n", ret);
return NULL;
}
for (i = 0; i < CONFIG_PHY_NOTIFICATION_NCLIENTS; i++)
{
client = &g_notify_clients[i];
@ -180,9 +187,16 @@ static FAR struct phy_notify_s *phy_find_assigned(FAR const char *intf,
pid_t pid)
{
FAR struct phy_notify_s *client;
int ret;
int i;
phy_semtake();
ret = phy_semtake();
if (ret < 0)
{
phyerr("ERROR: phy_semtake failed: %d\n", ret);
return NULL;
}
for (i = 0; i < CONFIG_PHY_NOTIFICATION_NCLIENTS; i++)
{
client = &g_notify_clients[i];
@ -286,7 +300,7 @@ int phy_notify_subscribe(FAR const char *intf, pid_t pid,
/* Check if this client already exists */
client = phy_find_assigned(intf, pid);
if (client)
if (client != NULL)
{
/* Yes.. update the signal number and argument */
@ -297,7 +311,7 @@ int phy_notify_subscribe(FAR const char *intf, pid_t pid,
/* No, allocate a new slot in the client notification table */
client = phy_find_unassigned();
if (!client)
if (client == NULL)
{
phyerr("ERROR: Failed to allocate a client entry\n");
return -ENOMEM;
@ -345,13 +359,14 @@ int phy_notify_subscribe(FAR const char *intf, pid_t pid,
int phy_notify_unsubscribe(FAR const char *intf, pid_t pid)
{
FAR struct phy_notify_s *client;
int ret;
phyinfo("%s: PID=%d\n", intf, pid);
/* Find the client entry for this interface */
client = phy_find_assigned(intf, pid);
if (!client)
if (client == NULL)
{
phyerr("ERROR: No such client\n");
return -ENOENT;
@ -359,20 +374,24 @@ int phy_notify_unsubscribe(FAR const char *intf, pid_t pid)
/* Detach and disable the PHY interrupt */
phy_semtake();
arch_phy_irq(intf, NULL, NULL, NULL);
ret = phy_semtake();
if (ret >= 0)
{
arch_phy_irq(intf, NULL, NULL, NULL);
/* Cancel any pending notification */
/* Cancel any pending notification */
nxsig_cancel_notification(&client->work);
nxsig_cancel_notification(&client->work);
/* Un-initialize the client entry */
/* Un-initialize the client entry */
client->assigned = false;
client->intf[0] = '\0';
client->pid = -1;
client->assigned = false;
client->intf[0] = '\0';
client->pid = -1;
phy_semgive();
}
phy_semgive();
return OK;
}

View file

@ -1,40 +1,25 @@
/****************************************************************************
* drivers/net/slip.c
*
* Copyright (C) 2011-2012, 2015-2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* Reference: RFC 1055
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/* Reference: RFC 1055 */
/****************************************************************************
* Included Files
****************************************************************************/
@ -110,14 +95,14 @@
# define CONFIG_NET_SLIP_NINTERFACES 1
#endif
/* SLIP special character codes *******************************************/
/* SLIP special character codes ********************************************/
#define SLIP_END 0300 /* Indicates end of packet */
#define SLIP_ESC 0333 /* Indicates byte stuffing */
#define SLIP_ESC_END 0334 /* ESC ESC_END means SLIP_END data byte */
#define SLIP_ESC_ESC 0335 /* ESC ESC_ESC means ESC data byte */
/* General driver definitions **********************************************/
/* General driver definitions ***********************************************/
/* TX poll delay = 1 second = 1000000 microseconds. */
@ -167,7 +152,8 @@ static struct slip_driver_s g_slip[CONFIG_NET_SLIP_NINTERFACES];
* Private Function Prototypes
****************************************************************************/
static void slip_semtake(FAR struct slip_driver_s *priv);
static int slip_semtake(FAR struct slip_driver_s *priv);
static void slip_forcetake(FAR struct slip_driver_s *priv);
/* Common TX logic */
@ -202,13 +188,41 @@ static int slip_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac);
* Name: slip_semtake
****************************************************************************/
static void slip_semtake(FAR struct slip_driver_s *priv)
static int slip_semtake(FAR struct slip_driver_s *priv)
{
nxsem_wait_uninterruptible(&priv->waitsem);
return nxsem_wait_uninterruptible(&priv->waitsem);
}
#define slip_semgive(p) nxsem_post(&(p)->waitsem);
/****************************************************************************
* Name: slip_forcetake
*
* Description:
* This is just another wrapper but this one continues even if the thread
* is canceled. This must be done in certain conditions where were must
* continue in order to clean-up resources.
*
****************************************************************************/
static void slip_forcetake(FAR struct slip_driver_s *priv)
{
int ret;
do
{
ret = nxsem_wait_uninterruptible(&priv->waitsem);
/* The only expected error would -ECANCELED meaning that the
* parent thread has been canceled. We have to continue and
* terminate the poll in this case.
*/
DEBUGASSERT(ret == OK || ret == -ECANCELED);
}
while (ret < 0);
}
/****************************************************************************
* Name: slip_write
*
@ -384,7 +398,8 @@ static void slip_transmit(FAR struct slip_driver_s *priv)
static int slip_txpoll(FAR struct net_driver_s *dev)
{
FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private;
FAR struct slip_driver_s *priv =
(FAR struct slip_driver_s *)dev->d_private;
/* If the polling resulted in data that should be sent out on the network,
* the field d_len is set to a value > 0.
@ -398,8 +413,8 @@ static int slip_txpoll(FAR struct net_driver_s *dev)
}
}
/* If zero is returned, the polling will continue until all connections have
* been examined.
/* If zero is returned, the polling will continue until all connections
* have been examined.
*/
return 0;
@ -426,6 +441,7 @@ static int slip_txtask(int argc, FAR char *argv[])
clock_t start_ticks;
clock_t now_ticks;
unsigned int hsec;
int ret;
nerr("index: %d\n", index);
DEBUGASSERT(index < CONFIG_NET_SLIP_NINTERFACES);
@ -440,11 +456,17 @@ static int slip_txtask(int argc, FAR char *argv[])
/* Loop forever */
start_ticks = clock_systimer();
for (; ; )
for (; ; )
{
/* Wait for the timeout to expire (or until we are signaled by */
slip_semtake(priv);
ret = slip_semtake(priv);
if (ret < 0)
{
DEBUGASSERT(ret == -ECANCELED);
break;
}
if (!priv->txnodelay)
{
slip_semgive(priv);
@ -777,7 +799,8 @@ static int slip_rxtask(int argc, FAR char *argv[])
static int slip_ifup(FAR struct net_driver_s *dev)
{
FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private;
FAR struct slip_driver_s *priv =
(FAR struct slip_driver_s *)dev->d_private;
#ifdef CONFIG_NET_IPv4
nerr("Bringing up: %d.%d.%d.%d\n",
@ -815,7 +838,8 @@ static int slip_ifup(FAR struct net_driver_s *dev)
static int slip_ifdown(FAR struct net_driver_s *dev)
{
FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private;
FAR struct slip_driver_s *priv =
(FAR struct slip_driver_s *)dev->d_private;
/* Mark the device "down" */
@ -841,7 +865,8 @@ static int slip_ifdown(FAR struct net_driver_s *dev)
static int slip_txavail(FAR struct net_driver_s *dev)
{
FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private;
FAR struct slip_driver_s *priv =
(FAR struct slip_driver_s *)dev->d_private;
/* Ignore the notification if the interface is not yet up */
@ -877,7 +902,8 @@ static int slip_txavail(FAR struct net_driver_s *dev)
#ifdef CONFIG_NET_MCASTGROUP
static int slip_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac)
{
FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private;
FAR struct slip_driver_s *priv =
(FAR struct slip_driver_s *)dev->d_private;
/* Add the MAC address to the hardware multicast routing table */
@ -906,7 +932,8 @@ static int slip_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac)
#ifdef CONFIG_NET_MCASTGROUP
static int slip_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac)
{
FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private;
FAR struct slip_driver_s *priv =
(FAR struct slip_driver_s *)dev->d_private;
/* Add the MAC address to the hardware multicast routing table */
@ -993,7 +1020,7 @@ int slip_initialize(int intf, FAR const char *devname)
/* Wait and make sure that the receive task is started. */
slip_semtake(priv);
slip_forcetake(priv);
/* Start the SLIP transmitter kernel thread */
@ -1008,7 +1035,7 @@ int slip_initialize(int intf, FAR const char *devname)
/* Wait and make sure that the transmit task is started. */
slip_semtake(priv);
slip_forcetake(priv);
/* Bump the semaphore count so that it can now be used as a mutex */

View file

@ -819,7 +819,8 @@ static ssize_t telnet_read(FAR struct file *filep, FAR char *buffer,
{
FAR struct inode *inode = filep->f_inode;
FAR struct telnet_dev_s *priv = inode->i_private;
ssize_t ret = 0;
ssize_t nread = 0;
int ret;
ninfo("len: %d\n", len);
@ -848,33 +849,44 @@ static ssize_t telnet_read(FAR struct file *filep, FAR char *buffer,
return -EAGAIN;
}
/* Wait for new data (or error) */
/* Wait for new data, interrupt, or thread cancellation */
ret = nxsem_wait(&priv->td_iosem);
if (ret < 0)
{
nerr("ERROR: nxsem_wait failed: %d\n", ret);
return (ssize_t)ret;
}
nxsem_wait_uninterruptible(&priv->td_iosem);
continue;
}
/* Take exclusive access to data buffer */
nxsem_wait(&priv->td_exclsem);
ret = nxsem_wait(&priv->td_exclsem);
if (ret < 0)
{
nerr("ERROR: nxsem_wait failed: %d\n", ret);
return (ssize_t)ret;
}
/* Process the buffered telnet data */
src = &priv->td_rxbuffer[priv->td_offset];
ret = telnet_receive(priv, src, priv->td_pending, buffer, len);
nread = telnet_receive(priv, src, priv->td_pending, buffer, len);
nxsem_post(&priv->td_exclsem);
}
while (ret == 0);
while (nread == 0);
/* Returned Value:
*
* ret > 0: The number of characters copied into the user buffer by
* telnet_receive().
* ret <= 0: Loss of connection or error events reported by recv().
* nread > 0: The number of characters copied into the user buffer by
* telnet_receive().
* nread <= 0: Loss of connection or error events reported by recv().
*/
return ret;
return nread;
}
/****************************************************************************

View file

@ -166,7 +166,7 @@ struct tun_driver_s
* Private Function Prototypes
****************************************************************************/
static void tun_lock(FAR struct tun_device_s *priv);
static int tun_lock(FAR struct tun_device_s *priv);
static void tun_unlock(FAR struct tun_device_s *priv);
/* Common TX logic */
@ -249,9 +249,9 @@ static const struct file_operations g_tun_file_ops =
* Name: tundev_lock
****************************************************************************/
static void tundev_lock(FAR struct tun_driver_s *tun)
static int tundev_lock(FAR struct tun_driver_s *tun)
{
nxsem_wait_uninterruptible(&tun->waitsem);
return nxsem_wait_uninterruptible(&tun->waitsem);
}
/****************************************************************************
@ -267,9 +267,9 @@ static void tundev_unlock(FAR struct tun_driver_s *tun)
* Name: tun_lock
****************************************************************************/
static void tun_lock(FAR struct tun_device_s *priv)
static int tun_lock(FAR struct tun_device_s *priv)
{
nxsem_wait_uninterruptible(&priv->waitsem);
return nxsem_wait_uninterruptible(&priv->waitsem);
}
/****************************************************************************
@ -778,10 +778,21 @@ static void tun_txdone(FAR struct tun_device_s *priv)
static void tun_poll_work(FAR void *arg)
{
FAR struct tun_device_s *priv = (FAR struct tun_device_s *)arg;
int ret;
/* Perform the poll */
tun_lock(priv);
ret = tun_lock(priv);
if (ret < 0)
{
/* This would indicate that the worker thread was canceled.. not a
* likely event.
*/
DEBUGASSERT(ret == -ECANCELED);
return;
}
net_lock();
/* Check if there is room in the send another TX packet. We cannot perform
@ -930,8 +941,15 @@ static int tun_ifdown(FAR struct net_driver_s *dev)
static void tun_txavail_work(FAR void *arg)
{
FAR struct tun_device_s *priv = (FAR struct tun_device_s *)arg;
int ret;
tun_lock(priv);
ret = tun_lock(priv);
if (ret < 0)
{
/* Thread has been canceled, skip poll-related work */
return;
}
/* Check if there is room to hold another network packet. */
@ -1152,6 +1170,7 @@ static int tun_close(FAR struct file *filep)
FAR struct tun_driver_s *tun = inode->i_private;
FAR struct tun_device_s *priv = filep->f_priv;
int intf;
int ret;
if (priv == NULL)
{
@ -1159,13 +1178,16 @@ static int tun_close(FAR struct file *filep)
}
intf = priv - g_tun_devices;
tundev_lock(tun);
ret = tundev_lock(tun);
if (ret >= 0)
{
tun->free_tuns |= (1 << intf);
tun_dev_uninit(priv);
tun->free_tuns |= (1 << intf);
tun_dev_uninit(priv);
tundev_unlock(tun);
}
tundev_unlock(tun);
return OK;
return ret;
}
/****************************************************************************
@ -1176,17 +1198,26 @@ static ssize_t tun_write(FAR struct file *filep, FAR const char *buffer,
size_t buflen)
{
FAR struct tun_device_s *priv = filep->f_priv;
ssize_t ret;
ssize_t nwritten = 0;
int ret;
if (priv == NULL || buflen > CONFIG_NET_TUN_PKTSIZE)
{
return -EINVAL;
}
tun_lock(priv);
for (; ; )
{
/* Write must return immediately if interrupted by a signal (or if the
* thread is canceled) and no data has yet been written.
*/
ret = nxsem_wait(&priv->waitsem);
if (ret < 0)
{
return nwritten == 0 ? (ssize_t)ret : nwritten;
}
/* Check if there are free space to write */
if (priv->write_d_len == 0)
@ -1200,7 +1231,7 @@ static ssize_t tun_write(FAR struct file *filep, FAR const char *buffer,
tun_net_receive(priv);
net_unlock();
ret = buflen;
nwritten = buflen;
break;
}
@ -1208,18 +1239,17 @@ static ssize_t tun_write(FAR struct file *filep, FAR const char *buffer,
if ((filep->f_oflags & O_NONBLOCK) != 0)
{
ret = -EAGAIN;
nwritten = -EAGAIN;
break;
}
priv->write_wait = true;
tun_unlock(priv);
nxsem_wait(&priv->write_wait_sem);
tun_lock(priv);
}
tun_unlock(priv);
return ret;
return nwritten;
}
/****************************************************************************
@ -1230,29 +1260,38 @@ static ssize_t tun_read(FAR struct file *filep, FAR char *buffer,
size_t buflen)
{
FAR struct tun_device_s *priv = filep->f_priv;
ssize_t ret;
ssize_t nread;
int ret;
if (priv == NULL)
{
return -EINVAL;
}
tun_lock(priv);
for (; ; )
{
/* Read must return immediately if interrupted by a signal (or if the
* thread is canceled) and no data has yet been read.
*/
ret = nxsem_wait(&priv->waitsem);
if (ret < 0)
{
return nread == 0 ? (ssize_t)ret : nread;
}
/* Check if there are data to read in write buffer */
if (priv->write_d_len > 0)
{
if (buflen < priv->write_d_len)
{
ret = -EINVAL;
nread = -EINVAL;
break;
}
memcpy(buffer, priv->write_buf, priv->write_d_len);
ret = priv->write_d_len;
nread = priv->write_d_len;
priv->write_d_len = 0;
NETDEV_TXDONE(&priv->dev);
@ -1266,12 +1305,12 @@ static ssize_t tun_read(FAR struct file *filep, FAR char *buffer,
{
if (buflen < priv->read_d_len)
{
ret = -EINVAL;
nread = -EINVAL;
break;
}
memcpy(buffer, priv->read_buf, priv->read_d_len);
ret = priv->read_d_len;
nread = priv->read_d_len;
priv->read_d_len = 0;
net_lock();
@ -1284,18 +1323,17 @@ static ssize_t tun_read(FAR struct file *filep, FAR char *buffer,
if ((filep->f_oflags & O_NONBLOCK) != 0)
{
ret = -EAGAIN;
nread = -EAGAIN;
break;
}
priv->read_wait = true;
tun_unlock(priv);
nxsem_wait(&priv->read_wait_sem);
tun_lock(priv);
}
tun_unlock(priv);
return ret;
return nread;
}
/****************************************************************************
@ -1306,7 +1344,7 @@ int tun_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup)
{
FAR struct tun_device_s *priv = filep->f_priv;
pollevent_t eventset;
int ret = OK;
int ret;
/* Some sanity checking */
@ -1315,7 +1353,11 @@ int tun_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup)
return -EINVAL;
}
tun_lock(priv);
ret = tun_lock(priv);
if (ret < 0)
{
return ret;
}
if (setup)
{
@ -1384,7 +1426,11 @@ static int tun_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
return -EINVAL;
}
tundev_lock(tun);
ret = tundev_lock(tun);
if (ret < 0)
{
return ret;
}
free_tuns = tun->free_tuns;

View file

@ -1,36 +1,20 @@
/****************************************************************************
* drivers/rwbuffer.c
*
* Copyright (C) 2009, 2011, 2013-2014, 2017, 2020 Gregory Nutt. All
* rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
@ -79,9 +63,9 @@
* Name: rwb_semtake
****************************************************************************/
static void rwb_semtake(FAR sem_t *sem)
static int rwb_semtake(FAR sem_t *sem)
{
nxsem_wait_uninterruptible(sem);
return nxsem_wait_uninterruptible(sem);
}
/****************************************************************************
@ -90,6 +74,34 @@ static void rwb_semtake(FAR sem_t *sem)
#define rwb_semgive(s) nxsem_post(s)
/****************************************************************************
* Name: rwb_forcetake
*
* Description:
* This is just another wrapper but this one continues even if the thread
* is canceled. This must be done in certain conditions where were must
* continue in order to clean-up resources.
*
****************************************************************************/
static void rwb_forcetake(FAR sem_t *sem)
{
int ret;
do
{
ret = nxsem_wait_uninterruptible(sem);
/* The only expected error would -ECANCELED meaning that the
* parent thread has been canceled. We have to continue and
* terminate the poll in this case.
*/
DEBUGASSERT(ret == OK || ret == -ECANCELED);
}
while (ret < 0);
}
/****************************************************************************
* Name: rwb_overlap
****************************************************************************/
@ -182,7 +194,7 @@ static void rwb_wrtimeout(FAR void *arg)
* worker thread.
*/
rwb_semtake(&rwb->wrsem);
rwb_forcetake(&rwb->wrsem);
rwb_wrflush(rwb);
rwb_semgive(&rwb->wrsem);
}
@ -410,7 +422,7 @@ int rwb_invalidate_writebuffer(FAR struct rwbuffer_s *rwb,
finfo("startblock=%d blockcount=%p\n", startblock, blockcount);
rwb_semtake(&rwb->wrsem);
rwb_forcetake(&rwb->wrsem);
/* Now there are five cases:
*
@ -547,7 +559,7 @@ int rwb_invalidate_readahead(FAR struct rwbuffer_s *rwb,
finfo("startblock=%d blockcount=%p\n", startblock, blockcount);
rwb_semtake(&rwb->rhsem);
rwb_forcetake(&rwb->rhsem);
/* Now there are five cases:
*
@ -781,7 +793,14 @@ static ssize_t rwb_read_(FAR struct rwbuffer_s *rwb, off_t startblock,
/* Loop until we have read all of the requested blocks */
rwb_semtake(&rwb->rhsem);
ret = nxsem_wait(&rwb->rhsem);
if (ret < 0)
{
/* Return EINTR or ECANCELED */
return ret;
}
for (remaining = nblocks; remaining > 0; )
{
/* Is there anything in the read-ahead buffer? */