diff --git a/drivers/audio/cs43l22.c b/drivers/audio/cs43l22.c index a2e0f6bc47..de73b7afd6 100644 --- a/drivers/audio/cs43l22.c +++ b/drivers/audio/cs43l22.c @@ -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); diff --git a/drivers/audio/wm8776.c b/drivers/audio/wm8776.c index c786ff1709..0b47a93d24 100644 --- a/drivers/audio/wm8776.c +++ b/drivers/audio/wm8776.c @@ -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 ****************************************************************************/ diff --git a/drivers/audio/wm8904.c b/drivers/audio/wm8904.c index d2e1fc1d7f..975be11f46 100644 --- a/drivers/audio/wm8904.c +++ b/drivers/audio/wm8904.c @@ -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 */ diff --git a/drivers/lcd/ft80x.c b/drivers/lcd/ft80x.c index 0978fd8b19..9482548759 100644 --- a/drivers/lcd/ft80x.c +++ b/drivers/lcd/ft80x.c @@ -1,51 +1,40 @@ -/************************************************************************************** +/**************************************************************************** * drivers/lcd/ft80x.c * - * Copyright (C) 2018 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * 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 @@ -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 */ diff --git a/drivers/net/phy_notify.c b/drivers/net/phy_notify.c index ec3bc210db..2e29c26605 100644 --- a/drivers/net/phy_notify.c +++ b/drivers/net/phy_notify.c @@ -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; } diff --git a/drivers/net/slip.c b/drivers/net/slip.c index bdd2481bbf..5fc640cfc2 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -1,40 +1,25 @@ /**************************************************************************** * drivers/net/slip.c * - * Copyright (C) 2011-2012, 2015-2018 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * 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 */ diff --git a/drivers/net/telnet.c b/drivers/net/telnet.c index a1c998eed9..5346065aea 100644 --- a/drivers/net/telnet.c +++ b/drivers/net/telnet.c @@ -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; } /**************************************************************************** diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 005c35853b..05c97628d6 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -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; diff --git a/drivers/rwbuffer.c b/drivers/rwbuffer.c index 889683f9b9..59e2104ff3 100644 --- a/drivers/rwbuffer.c +++ b/drivers/rwbuffer.c @@ -1,36 +1,20 @@ /**************************************************************************** * drivers/rwbuffer.c * - * Copyright (C) 2009, 2011, 2013-2014, 2017, 2020 Gregory Nutt. All - * rights reserved. - * Author: Gregory Nutt + * 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? */