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:
parent
7f510a61b4
commit
5b74974919
@ -76,17 +76,20 @@ static
|
|||||||
uint8_t cs43l22_readreg(FAR struct cs43l22_dev_s *priv, uint8_t regaddr);
|
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,
|
static void cs43l22_writereg(FAR struct cs43l22_dev_s *priv, uint8_t regaddr,
|
||||||
uint8_t regval);
|
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)
|
#define cs43l22_givesem(s) nxsem_post(s)
|
||||||
|
|
||||||
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
|
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
|
||||||
static inline uint16_t cs43l22_scalevolume(uint16_t volume, b16_t scale);
|
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,
|
static void cs43l22_setvolume(FAR struct cs43l22_dev_s *priv,
|
||||||
bool mute);
|
uint16_t volume, bool mute);
|
||||||
#endif
|
#endif
|
||||||
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
|
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
|
||||||
static void cs43l22_setbass(FAR struct cs43l22_dev_s *priv, uint8_t bass);
|
static void cs43l22_setbass(FAR struct cs43l22_dev_s *priv,
|
||||||
static void cs43l22_settreble(FAR struct cs43l22_dev_s *priv, uint8_t treble);
|
uint8_t bass);
|
||||||
|
static void cs43l22_settreble(FAR struct cs43l22_dev_s *priv,
|
||||||
|
uint8_t treble);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void cs43l22_setdatawidth(FAR struct cs43l22_dev_s *priv);
|
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);
|
static int cs43l22_sendbuffer(FAR struct cs43l22_dev_s *priv);
|
||||||
|
|
||||||
#ifdef CONFIG_AUDIO_MULTI_SESSION
|
#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
|
#else
|
||||||
static int cs43l22_start(FAR struct audio_lowerhalf_s *dev);
|
static int cs43l22_start(FAR struct audio_lowerhalf_s *dev);
|
||||||
#endif
|
#endif
|
||||||
#ifndef CONFIG_AUDIO_EXCLUDE_STOP
|
#ifndef CONFIG_AUDIO_EXCLUDE_STOP
|
||||||
#ifdef CONFIG_AUDIO_MULTI_SESSION
|
#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
|
#else
|
||||||
static int cs43l22_stop(FAR struct audio_lowerhalf_s *dev);
|
static int cs43l22_stop(FAR struct audio_lowerhalf_s *dev);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
|
#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
|
||||||
#ifdef CONFIG_AUDIO_MULTI_SESSION
|
#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,
|
||||||
static int cs43l22_resume(FAR struct audio_lowerhalf_s *dev, FAR void *session);
|
FAR void *session);
|
||||||
|
static int cs43l22_resume(FAR struct audio_lowerhalf_s *dev,
|
||||||
|
FAR void *session);
|
||||||
#else
|
#else
|
||||||
static int cs43l22_pause(FAR struct audio_lowerhalf_s *dev);
|
static int cs43l22_pause(FAR struct audio_lowerhalf_s *dev);
|
||||||
static int cs43l22_resume(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
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
/* The I2C transfer was successful... break out of the loop and
|
/* The I2C transfer was successful... break out of the loop and
|
||||||
* return the value read.
|
* return the value read.
|
||||||
*/
|
*/
|
||||||
@ -286,13 +292,13 @@ uint8_t cs43l22_readreg(FAR struct cs43l22_dev_s *priv, uint8_t regaddr)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************************
|
/****************************************************************************
|
||||||
* Name: cs43l22_writereg
|
* Name: cs43l22_writereg
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Write the specified 16-bit register to the CS43L22 device.
|
* Write the specified 16-bit register to the CS43L22 device.
|
||||||
*
|
*
|
||||||
************************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cs43l22_writereg(FAR struct cs43l22_dev_s *priv, uint8_t regaddr,
|
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
|
* Name: cs43l22_takesem
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Take a semaphore count, handling the nasty EINTR return if we are interrupted
|
* Take a semaphore count, handling the nasty EINTR return if we are
|
||||||
* by a signal.
|
* 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
|
* Name: cs43l22_scalevolume
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Set the right and left volume values in the CS43L22 device based on the current
|
* Set the right and left volume values in the CS43L22 device based on the
|
||||||
* volume and balance settings.
|
* current volume and balance settings.
|
||||||
*
|
*
|
||||||
************************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
|
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
|
||||||
static inline uint16_t cs43l22_scalevolume(uint16_t volume, b16_t scale)
|
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
|
#endif
|
||||||
|
|
||||||
/************************************************************************************
|
/****************************************************************************
|
||||||
* Name: cs43l22_setvolume
|
* Name: cs43l22_setvolume
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Set the right and left volume values in the CS43L22 device based on the current
|
* Set the right and left volume values in the CS43L22 device based on the
|
||||||
* volume and balance settings.
|
* current volume and balance settings.
|
||||||
*
|
*
|
||||||
************************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
|
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
|
||||||
static void
|
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;
|
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)
|
if (priv->balance >= 500)
|
||||||
{
|
{
|
||||||
@ -442,10 +485,10 @@ cs43l22_setvolume(FAR struct cs43l22_dev_s *priv, uint16_t volume, bool mute)
|
|||||||
|
|
||||||
/* Set the volume */
|
/* Set the volume */
|
||||||
|
|
||||||
regval = (rightlevel + 0x19) & 0xff;
|
regval = (rightlevel + 0x19) & 0xff;
|
||||||
cs43l22_writereg(priv, CS43L22_MS_VOL_CTRL_A, regval);
|
cs43l22_writereg(priv, CS43L22_MS_VOL_CTRL_A, regval);
|
||||||
regval = ((leftlevel + 0x19) & 0xff);
|
regval = ((leftlevel + 0x19) & 0xff);
|
||||||
cs43l22_writereg(priv, CS43L22_MS_VOL_CTRL_B, regval);
|
cs43l22_writereg(priv, CS43L22_MS_VOL_CTRL_B, regval);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
regval = (rightlevel + 0x01) & 0xff;
|
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 */
|
#endif /* CONFIG_AUDIO_EXCLUDE_VOLUME */
|
||||||
|
|
||||||
/************************************************************************************
|
/****************************************************************************
|
||||||
* Name: cs43l22_setbass
|
* Name: cs43l22_setbass
|
||||||
*
|
*
|
||||||
* Description:
|
* 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).
|
* The level and range are in whole percentage levels (0-100).
|
||||||
*
|
*
|
||||||
************************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
|
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
|
||||||
static void cs43l22_setbass(FAR struct cs43l22_dev_s *priv, uint8_t bass)
|
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 */
|
#endif /* CONFIG_AUDIO_EXCLUDE_TONE */
|
||||||
|
|
||||||
/************************************************************************************
|
/****************************************************************************
|
||||||
* Name: cs43l22_settreble
|
* Name: cs43l22_settreble
|
||||||
*
|
*
|
||||||
* Description:
|
* 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).
|
* The level and range are in whole percentage levels (0-100).
|
||||||
*
|
*
|
||||||
************************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
|
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
|
||||||
static void cs43l22_settreble(FAR struct cs43l22_dev_s *priv, uint8_t treble)
|
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)
|
if (priv->bpsamp == 16)
|
||||||
{
|
{
|
||||||
/* Reset default default setting */
|
/* Reset default default setting */
|
||||||
|
|
||||||
priv->i2s->ops->i2s_txdatawidth(priv->i2s, 16);
|
priv->i2s->ops->i2s_txdatawidth(priv->i2s, 16);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* This should select 8-bit with no companding */
|
/* This should select 8-bit with no companding */
|
||||||
|
|
||||||
priv->i2s->ops->i2s_txdatawidth(priv->i2s, 8);
|
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)
|
switch (caps->ac_subtype)
|
||||||
{
|
{
|
||||||
case AUDIO_TYPE_QUERY:
|
case AUDIO_TYPE_QUERY:
|
||||||
|
|
||||||
/* We don't decode any formats! Only something above us in
|
/* We don't decode any formats! Only something above us in
|
||||||
* the audio stream can perform decoding on our behalf.
|
* the audio stream can perform decoding on our behalf.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* The types of audio units we implement */
|
/* The types of audio units we implement */
|
||||||
|
|
||||||
caps->ac_controls.b[0] = AUDIO_TYPE_OUTPUT | AUDIO_TYPE_FEATURE |
|
caps->ac_controls.b[0] =
|
||||||
AUDIO_TYPE_PROCESSING;
|
AUDIO_TYPE_OUTPUT | AUDIO_TYPE_FEATURE |
|
||||||
|
AUDIO_TYPE_PROCESSING;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AUDIO_FMT_MIDI:
|
case AUDIO_FMT_MIDI:
|
||||||
|
|
||||||
/* We only support Format 0 */
|
/* We only support Format 0 */
|
||||||
|
|
||||||
caps->ac_controls.b[0] = AUDIO_SUBFMT_END;
|
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 */
|
/* Report the Sample rates we support */
|
||||||
|
|
||||||
caps->ac_controls.b[0] = AUDIO_SAMP_RATE_8K | AUDIO_SAMP_RATE_11K |
|
caps->ac_controls.b[0] =
|
||||||
AUDIO_SAMP_RATE_16K | AUDIO_SAMP_RATE_22K |
|
AUDIO_SAMP_RATE_8K | AUDIO_SAMP_RATE_11K |
|
||||||
AUDIO_SAMP_RATE_32K | AUDIO_SAMP_RATE_44K |
|
AUDIO_SAMP_RATE_16K | AUDIO_SAMP_RATE_22K |
|
||||||
AUDIO_SAMP_RATE_48K;
|
AUDIO_SAMP_RATE_32K | AUDIO_SAMP_RATE_44K |
|
||||||
|
AUDIO_SAMP_RATE_48K;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AUDIO_FMT_MP3:
|
case AUDIO_FMT_MP3:
|
||||||
@ -639,19 +688,24 @@ static int cs43l22_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
|
|||||||
|
|
||||||
case AUDIO_TYPE_FEATURE:
|
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)
|
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;
|
caps->ac_controls.b[1] = AUDIO_FU_BALANCE >> 8;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* TODO: Do we need to provide specific info for the Feature Units,
|
/* TODO: Do we need to provide specific info for the Feature
|
||||||
* such as volume setting ranges, etc.?
|
* 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)
|
switch (caps->ac_subtype)
|
||||||
{
|
{
|
||||||
case AUDIO_PU_UNDEF:
|
case AUDIO_PU_UNDEF:
|
||||||
|
|
||||||
/* Provide the type of Processing Units we support */
|
/* Provide the type of Processing Units we support */
|
||||||
|
|
||||||
caps->ac_controls.b[0] = AUDIO_PU_STEREO_EXTENDER;
|
caps->ac_controls.b[0] = AUDIO_PU_STEREO_EXTENDER;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AUDIO_PU_STEREO_EXTENDER:
|
case AUDIO_PU_STEREO_EXTENDER:
|
||||||
|
|
||||||
/* Provide capabilities of our 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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
/* Other types of processing uint we don't support */
|
/* Other types of processing uint we don't support */
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -748,7 +806,8 @@ cs43l22_configure(FAR struct audio_lowerhalf_s *dev,
|
|||||||
{
|
{
|
||||||
/* Scale the volume setting to the range {76..255} */
|
/* 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
|
else
|
||||||
{
|
{
|
||||||
@ -945,6 +1004,7 @@ cs43l22_senddone(FAR struct i2s_dev_s *i2s,
|
|||||||
priv->inflight--;
|
priv->inflight--;
|
||||||
|
|
||||||
/* Save the result of the transfer */
|
/* Save the result of the transfer */
|
||||||
|
|
||||||
/* REVISIT: This can be overwritten */
|
/* REVISIT: This can be overwritten */
|
||||||
|
|
||||||
priv->result = result;
|
priv->result = result;
|
||||||
@ -1047,7 +1107,7 @@ static int cs43l22_sendbuffer(FAR struct cs43l22_dev_s *priv)
|
|||||||
irqstate_t flags;
|
irqstate_t flags;
|
||||||
uint32_t timeout;
|
uint32_t timeout;
|
||||||
int shift;
|
int shift;
|
||||||
int ret = OK;
|
int ret;
|
||||||
|
|
||||||
/* Loop while there are audio buffers to be sent and we have few than
|
/* Loop while there are audio buffers to be sent and we have few than
|
||||||
* CONFIG_CS43L22_INFLIGHT then "in-flight"
|
* CONFIG_CS43L22_INFLIGHT then "in-flight"
|
||||||
@ -1061,7 +1121,12 @@ static int cs43l22_sendbuffer(FAR struct cs43l22_dev_s *priv)
|
|||||||
* only while accessing 'inflight'.
|
* only while accessing 'inflight'.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
cs43l22_takesem(&priv->pendsem);
|
ret = cs43l22_takesem(&priv->pendsem);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
while (priv->inflight < CONFIG_CS43L22_INFLIGHT &&
|
while (priv->inflight < CONFIG_CS43L22_INFLIGHT &&
|
||||||
dq_peek(&priv->pendq) != NULL && !priv->paused)
|
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
|
#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
|
#else
|
||||||
static int cs43l22_start(FAR struct audio_lowerhalf_s *dev)
|
static int cs43l22_start(FAR struct audio_lowerhalf_s *dev)
|
||||||
#endif
|
#endif
|
||||||
@ -1143,6 +1209,7 @@ static int cs43l22_start(FAR struct audio_lowerhalf_s *dev)
|
|||||||
audinfo("Entry\n");
|
audinfo("Entry\n");
|
||||||
|
|
||||||
/* Exit reduced power modes of operation */
|
/* Exit reduced power modes of operation */
|
||||||
|
|
||||||
/* REVISIT */
|
/* REVISIT */
|
||||||
|
|
||||||
/* Create a message queue for the worker thread */
|
/* 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;
|
priv->threadid = 0;
|
||||||
|
|
||||||
/* Enter into a reduced power usage mode */
|
/* Enter into a reduced power usage mode */
|
||||||
|
|
||||||
/* REVISIT: */
|
/* REVISIT: */
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
@ -1242,7 +1310,8 @@ static int cs43l22_stop(FAR struct audio_lowerhalf_s *dev)
|
|||||||
|
|
||||||
#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
|
#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
|
||||||
# ifdef CONFIG_AUDIO_MULTI_SESSION
|
# 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
|
# else
|
||||||
static int cs43l22_pause(FAR struct audio_lowerhalf_s *dev)
|
static int cs43l22_pause(FAR struct audio_lowerhalf_s *dev)
|
||||||
# endif
|
# endif
|
||||||
@ -1272,7 +1341,8 @@ static int cs43l22_pause(FAR struct audio_lowerhalf_s *dev)
|
|||||||
|
|
||||||
#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
|
#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
|
||||||
# ifdef CONFIG_AUDIO_MULTI_SESSION
|
# 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
|
# else
|
||||||
static int cs43l22_resume(FAR struct audio_lowerhalf_s *dev)
|
static int cs43l22_resume(FAR struct audio_lowerhalf_s *dev)
|
||||||
# endif
|
# 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",
|
audinfo("Enqueueing: apb=%p curbyte=%d nbytes=%d flags=%04x\n",
|
||||||
apb, apb->curbyte, apb->nbytes, apb->flags);
|
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 */
|
/* Take a reference on the new audio buffer */
|
||||||
|
|
||||||
apb_reference(apb);
|
apb_reference(apb);
|
||||||
|
|
||||||
/* Add the new buffer to the tail of pending audio buffers */
|
/* Add the new buffer to the tail of pending audio buffers */
|
||||||
|
|
||||||
cs43l22_takesem(&priv->pendsem);
|
|
||||||
apb->flags |= AUDIO_APB_OUTPUT_ENQUEUED;
|
apb->flags |= AUDIO_APB_OUTPUT_ENQUEUED;
|
||||||
dq_addlast(&apb->dq_entry, &priv->pendq);
|
dq_addlast(&apb->dq_entry, &priv->pendq);
|
||||||
cs43l22_givesem(&priv->pendsem);
|
cs43l22_givesem(&priv->pendsem);
|
||||||
|
|
||||||
/* Send a message to the worker thread indicating that a new buffer has been
|
/* Send a message to the worker thread indicating that a new buffer has
|
||||||
* enqueued. If mq is NULL, then the playing has not yet started. In that
|
* been enqueued. If mq is NULL, then the playing has not yet started.
|
||||||
* case we are just "priming the pump" and we don't need to send any message.
|
* In that case we are just "priming the pump" and we don't need to send
|
||||||
|
* any message.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ret = OK;
|
ret = OK;
|
||||||
@ -1437,7 +1513,12 @@ static int cs43l22_reserve(FAR struct audio_lowerhalf_s *dev)
|
|||||||
|
|
||||||
/* Borrow the APBQ semaphore for thread sync */
|
/* Borrow the APBQ semaphore for thread sync */
|
||||||
|
|
||||||
cs43l22_takesem(&priv->pendsem);
|
ret = cs43l22_takesem(&priv->pendsem);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (priv->reserved)
|
if (priv->reserved)
|
||||||
{
|
{
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
@ -1472,13 +1553,15 @@ static int cs43l22_reserve(FAR struct audio_lowerhalf_s *dev)
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifdef CONFIG_AUDIO_MULTI_SESSION
|
#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
|
#else
|
||||||
static int cs43l22_release(FAR struct audio_lowerhalf_s *dev)
|
static int cs43l22_release(FAR struct audio_lowerhalf_s *dev)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
FAR struct cs43l22_dev_s *priv = (FAR struct cs43l22_dev_s *)dev;
|
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 */
|
/* 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 */
|
/* Borrow the APBQ semaphore for thread sync */
|
||||||
|
|
||||||
cs43l22_takesem(&priv->pendsem);
|
ret = cs43l22_forcetake(&priv->pendsem);
|
||||||
|
|
||||||
/* Really we should free any queued buffers here */
|
/* Really we should free any queued buffers here */
|
||||||
|
|
||||||
priv->reserved = false;
|
priv->reserved = false;
|
||||||
cs43l22_givesem(&priv->pendsem);
|
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
|
#ifndef CONFIG_AUDIO_EXCLUDE_STOP
|
||||||
case AUDIO_MSG_STOP:
|
case AUDIO_MSG_STOP:
|
||||||
|
|
||||||
/* Indicate that we are terminating */
|
/* Indicate that we are terminating */
|
||||||
|
|
||||||
audinfo("AUDIO_MSG_STOP: Terminating\n");
|
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 */
|
/* 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)
|
while ((apb = (FAR struct ap_buffer_s *)dq_remfirst(&priv->pendq)) != NULL)
|
||||||
{
|
{
|
||||||
/* Release our reference to the buffer */
|
/* 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 */
|
/* 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);
|
cs43l22_writereg(priv, CS43L22_POWER_CTRL2, regval);
|
||||||
|
|
||||||
/* Clock configuration: Auto detection */
|
/* Clock configuration: Auto detection */
|
||||||
@ -1841,7 +1926,7 @@ static void cs43l22_reset(FAR struct cs43l22_dev_s *priv)
|
|||||||
priv->nchannels = CS43L22_DEFAULT_NCHANNELS;
|
priv->nchannels = CS43L22_DEFAULT_NCHANNELS;
|
||||||
priv->bpsamp = CS43L22_DEFAULT_BPSAMP;
|
priv->bpsamp = CS43L22_DEFAULT_BPSAMP;
|
||||||
#if !defined(CONFIG_AUDIO_EXCLUDE_VOLUME) && !defined(CONFIG_AUDIO_EXCLUDE_BALANCE)
|
#if !defined(CONFIG_AUDIO_EXCLUDE_VOLUME) && !defined(CONFIG_AUDIO_EXCLUDE_BALANCE)
|
||||||
priv->balance = 500; // b16HALF; /* Center balance */
|
priv->balance = 500; /* b16HALF = Center balance */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Software reset. This puts all CS43L22 registers back in their
|
/* 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 audio_lowerhalf_s *
|
||||||
FAR struct i2s_dev_s *i2s,
|
cs43l22_initialize(FAR struct i2c_master_s *i2c, FAR struct i2s_dev_s *i2s,
|
||||||
FAR const struct
|
FAR const struct cs43l22_lower_s *lower)
|
||||||
cs43l22_lower_s *lower)
|
|
||||||
{
|
{
|
||||||
FAR struct cs43l22_dev_s *priv;
|
FAR struct cs43l22_dev_s *priv;
|
||||||
uint16_t regval;
|
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 */
|
/* 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)
|
if (priv)
|
||||||
{
|
{
|
||||||
/* Initialize the CS43L22 device structure. Since we used kmm_zalloc,
|
/* 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 */
|
/* 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
|
/* Software reset. This puts all CS43L22 registers back in their
|
||||||
* state. */
|
* default state.
|
||||||
|
*/
|
||||||
|
|
||||||
CS43L22_HW_RESET(priv->lower);
|
CS43L22_HW_RESET(priv->lower);
|
||||||
|
|
||||||
|
@ -74,7 +74,8 @@
|
|||||||
static void wm8776_writereg(FAR struct wm8776_dev_s *priv,
|
static void wm8776_writereg(FAR struct wm8776_dev_s *priv,
|
||||||
uint8_t regaddr, uint16_t regval);
|
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)
|
#define wm8776_givesem(s) nxsem_post(s)
|
||||||
|
|
||||||
static int wm8776_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
|
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 */
|
wm8776_release /* release */
|
||||||
};
|
};
|
||||||
|
|
||||||
/************************************************************************************
|
/****************************************************************************
|
||||||
* Name: wm8776_writereg
|
* Name: wm8776_writereg
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Write the specified 16-bit register to the WM8776 device.
|
* Write the specified 16-bit register to the WM8776 device.
|
||||||
*
|
*
|
||||||
************************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static void wm8776_writereg(FAR struct wm8776_dev_s *priv,
|
static void wm8776_writereg(FAR struct wm8776_dev_s *priv,
|
||||||
uint8_t regaddr,
|
uint8_t regaddr,
|
||||||
@ -208,28 +209,65 @@ static void wm8776_writereg(FAR struct wm8776_dev_s *priv,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************************
|
/****************************************************************************
|
||||||
* Name: wm8776_takesem
|
* Name: wm8776_takesem
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Take a semaphore count, handling the nasty EINTR return if we are interrupted
|
* Take a semaphore count, handling the nasty EINTR return if we are
|
||||||
* by a signal.
|
* 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
|
* Name: wm8776_setvolume
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Set the right and left volume values in the WM8776 device based on the current
|
* Set the right and left volume values in the WM8776 device based on the
|
||||||
* volume and balance settings.
|
* current volume and balance settings.
|
||||||
*
|
*
|
||||||
************************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
|
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
|
||||||
static void wm8776_setvolume(FAR struct wm8776_dev_s *priv, uint16_t 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 */
|
/* The types of audio units we implement */
|
||||||
|
|
||||||
caps->ac_controls.b[0] = AUDIO_TYPE_OUTPUT | AUDIO_TYPE_FEATURE |
|
caps->ac_controls.b[0] =
|
||||||
AUDIO_TYPE_PROCESSING;
|
AUDIO_TYPE_OUTPUT | AUDIO_TYPE_FEATURE |
|
||||||
|
AUDIO_TYPE_PROCESSING;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -413,13 +452,14 @@ static int wm8776_configure(FAR struct audio_lowerhalf_s *dev,
|
|||||||
{
|
{
|
||||||
/* Scale the volume setting to the range {0x2f .. 0x79} */
|
/* 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
|
else
|
||||||
{
|
{
|
||||||
ret = -EDOM;
|
ret = -EDOM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif /* CONFIG_AUDIO_EXCLUDE_VOLUME */
|
#endif /* CONFIG_AUDIO_EXCLUDE_VOLUME */
|
||||||
|
|
||||||
@ -537,6 +577,7 @@ static void wm8776_senddone(FAR struct i2s_dev_s *i2s,
|
|||||||
priv->inflight--;
|
priv->inflight--;
|
||||||
|
|
||||||
/* Save the result of the transfer */
|
/* Save the result of the transfer */
|
||||||
|
|
||||||
/* REVISIT: This can be overwritten */
|
/* REVISIT: This can be overwritten */
|
||||||
|
|
||||||
priv->result = result;
|
priv->result = result;
|
||||||
@ -639,7 +680,7 @@ static int wm8776_sendbuffer(FAR struct wm8776_dev_s *priv)
|
|||||||
irqstate_t flags;
|
irqstate_t flags;
|
||||||
uint32_t timeout;
|
uint32_t timeout;
|
||||||
int shift;
|
int shift;
|
||||||
int ret = OK;
|
int ret;
|
||||||
|
|
||||||
/* Loop while there are audio buffers to be sent and we have few than
|
/* Loop while there are audio buffers to be sent and we have few than
|
||||||
* CONFIG_WM8776_INFLIGHT then "in-flight"
|
* CONFIG_WM8776_INFLIGHT then "in-flight"
|
||||||
@ -653,7 +694,12 @@ static int wm8776_sendbuffer(FAR struct wm8776_dev_s *priv)
|
|||||||
* only while accessing 'inflight'.
|
* only while accessing 'inflight'.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
wm8776_takesem(&priv->pendsem);
|
ret = wm8776_takesem(&priv->pendsem);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
while (priv->inflight < CONFIG_WM8776_INFLIGHT &&
|
while (priv->inflight < CONFIG_WM8776_INFLIGHT &&
|
||||||
dq_peek(&priv->pendq) != NULL && !priv->paused)
|
dq_peek(&priv->pendq) != NULL && !priv->paused)
|
||||||
{
|
{
|
||||||
@ -713,6 +759,7 @@ static int wm8776_start(FAR struct audio_lowerhalf_s *dev)
|
|||||||
audinfo("Entry\n");
|
audinfo("Entry\n");
|
||||||
|
|
||||||
/* Exit reduced power modes of operation */
|
/* Exit reduced power modes of operation */
|
||||||
|
|
||||||
/* REVISIT */
|
/* REVISIT */
|
||||||
|
|
||||||
/* Create a message queue for the worker thread */
|
/* 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;
|
priv->threadid = 0;
|
||||||
|
|
||||||
/* Enter into a reduced power usage mode */
|
/* Enter into a reduced power usage mode */
|
||||||
|
|
||||||
/* REVISIT: */
|
/* REVISIT: */
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
@ -837,7 +885,8 @@ static int wm8776_pause(FAR struct audio_lowerhalf_s *dev)
|
|||||||
|
|
||||||
#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
|
#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
|
||||||
#ifdef CONFIG_AUDIO_MULTI_SESSION
|
#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
|
#else
|
||||||
static int wm8776_resume(FAR struct audio_lowerhalf_s *dev)
|
static int wm8776_resume(FAR struct audio_lowerhalf_s *dev)
|
||||||
#endif
|
#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 */
|
/* 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;
|
apb->flags |= AUDIO_APB_OUTPUT_ENQUEUED;
|
||||||
dq_addlast(&apb->dq_entry, &priv->pendq);
|
dq_addlast(&apb->dq_entry, &priv->pendq);
|
||||||
wm8776_givesem(&priv->pendsem);
|
wm8776_givesem(&priv->pendsem);
|
||||||
|
|
||||||
/* Send a message to the worker thread indicating that a new buffer has been
|
/* Send a message to the worker thread indicating that a new buffer has
|
||||||
* enqueued. If mq is NULL, then the playing has not yet started. In that
|
* been enqueued. If mq is NULL, then the playing has not yet started.
|
||||||
* case we are just "priming the pump" and we don't need to send any message.
|
* In that case we are just "priming the pump" and we don't need to send
|
||||||
|
* any message.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ret = OK;
|
ret = OK;
|
||||||
@ -996,7 +1051,12 @@ static int wm8776_reserve(FAR struct audio_lowerhalf_s *dev)
|
|||||||
|
|
||||||
/* Borrow the APBQ semaphore for thread sync */
|
/* Borrow the APBQ semaphore for thread sync */
|
||||||
|
|
||||||
wm8776_takesem(&priv->pendsem);
|
ret = wm8776_takesem(&priv->pendsem);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (priv->reserved)
|
if (priv->reserved)
|
||||||
{
|
{
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
@ -1037,7 +1097,8 @@ static int wm8776_release(FAR struct audio_lowerhalf_s *dev)
|
|||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
FAR struct wm8776_dev_s *priv = (FAR struct wm8776_dev_s *)dev;
|
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 */
|
/* 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 */
|
/* Borrow the APBQ semaphore for thread sync */
|
||||||
|
|
||||||
wm8776_takesem(&priv->pendsem);
|
ret = wm8776_forcetake(&priv->pendsem);
|
||||||
|
|
||||||
/* Really we should free any queued buffers here */
|
/* Really we should free any queued buffers here */
|
||||||
|
|
||||||
priv->reserved = false;
|
priv->reserved = false;
|
||||||
wm8776_givesem(&priv->pendsem);
|
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)
|
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_MASTER_ATT,
|
||||||
wm8776_writereg(priv, WM8776_DAC_IF, 0x32); /* 32bit, I2S, standard pol */
|
WM8776_UPDATE | 0x58); /* -33db */
|
||||||
|
wm8776_writereg(priv, WM8776_DAC_IF, 0x32); /* 32bit, I2S, standard pol */
|
||||||
|
|
||||||
#ifdef CONFIG_WM8776_SWAP_HPOUT
|
#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
|
#endif
|
||||||
|
|
||||||
wm8776_writereg(priv, WM8776_MASTER_MODE, 0x00); /* slave mode, 128fs */
|
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 */
|
/* Configure the WM8776 hardware as an audio input device */
|
||||||
|
|
||||||
wm8776_audio_output(priv);
|
wm8776_audio_output(priv);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@ -1203,6 +1264,7 @@ repeat:
|
|||||||
|
|
||||||
#ifndef CONFIG_AUDIO_EXCLUDE_STOP
|
#ifndef CONFIG_AUDIO_EXCLUDE_STOP
|
||||||
case AUDIO_MSG_STOP:
|
case AUDIO_MSG_STOP:
|
||||||
|
|
||||||
/* Indicate that we are terminating */
|
/* Indicate that we are terminating */
|
||||||
|
|
||||||
audinfo("AUDIO_MSG_STOP: Terminating\n");
|
audinfo("AUDIO_MSG_STOP: Terminating\n");
|
||||||
@ -1238,7 +1300,6 @@ repeat:
|
|||||||
{
|
{
|
||||||
goto repeat;
|
goto repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset the WM8776 hardware */
|
/* Reset the WM8776 hardware */
|
||||||
@ -1247,7 +1308,7 @@ repeat:
|
|||||||
|
|
||||||
/* Return any pending buffers in our pending queue */
|
/* 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)
|
while ((apb = (FAR struct ap_buffer_s *)dq_remfirst(&priv->pendq)) != NULL)
|
||||||
{
|
{
|
||||||
/* Release our reference to the buffer */
|
/* Release our reference to the buffer */
|
||||||
@ -1287,7 +1348,6 @@ repeat:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
@ -94,7 +94,8 @@ static
|
|||||||
uint8_t regaddr);
|
uint8_t regaddr);
|
||||||
static void wm8904_writereg(FAR struct wm8904_dev_s *priv,
|
static void wm8904_writereg(FAR struct wm8904_dev_s *priv,
|
||||||
uint8_t regaddr, uint16_t regval);
|
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)
|
#define wm8904_givesem(s) nxsem_post(s)
|
||||||
|
|
||||||
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
|
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
|
||||||
@ -104,7 +105,8 @@ static void wm8904_setvolume(FAR struct wm8904_dev_s *priv,
|
|||||||
#endif
|
#endif
|
||||||
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
|
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
|
||||||
static void wm8904_setbass(FAR struct wm8904_dev_s *priv, uint8_t bass);
|
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
|
#endif
|
||||||
|
|
||||||
static void wm8904_setdatawidth(FAR struct wm8904_dev_s *priv);
|
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
|
#ifndef CONFIG_WM8904_CLKDEBUG
|
||||||
static
|
static
|
||||||
#endif
|
#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 */
|
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 */
|
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)
|
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);
|
ret = I2C_RESET(priv->i2c);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
@ -331,13 +334,13 @@ uint16_t wm8904_readreg(FAR struct wm8904_dev_s *priv, uint8_t regaddr)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************************
|
/****************************************************************************
|
||||||
* Name: wm8904_writereg
|
* Name: wm8904_writereg
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Write the specified 16-bit register to the WM8904 device.
|
* Write the specified 16-bit register to the WM8904 device.
|
||||||
*
|
*
|
||||||
************************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static void wm8904_writereg(FAR struct wm8904_dev_s *priv, uint8_t regaddr,
|
static void wm8904_writereg(FAR struct wm8904_dev_s *priv, uint8_t regaddr,
|
||||||
uint16_t regval)
|
uint16_t regval)
|
||||||
@ -405,28 +408,65 @@ static void wm8904_writereg(FAR struct wm8904_dev_s *priv, uint8_t regaddr,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************************
|
/****************************************************************************
|
||||||
* Name: wm8904_takesem
|
* Name: wm8904_takesem
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Take a semaphore count, handling the nasty EINTR return if we are interrupted
|
* Take a semaphore count, handling the nasty EINTR return if we are
|
||||||
* by a signal.
|
* 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
|
* Name: wm8904_scalevolume
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Set the right and left volume values in the WM8904 device based on the current
|
* Set the right and left volume values in the WM8904 device based on the
|
||||||
* volume and balance settings.
|
* current volume and balance settings.
|
||||||
*
|
*
|
||||||
************************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
|
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
|
||||||
static inline uint16_t wm8904_scalevolume(uint16_t volume, b16_t scale)
|
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
|
#endif
|
||||||
|
|
||||||
/************************************************************************************
|
/****************************************************************************
|
||||||
* Name: wm8904_setvolume
|
* Name: wm8904_setvolume
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Set the right and left volume values in the WM8904 device based on the current
|
* Set the right and left volume values in the WM8904 device based on the
|
||||||
* volume and balance settings.
|
* current volume and balance settings.
|
||||||
*
|
*
|
||||||
************************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
|
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
|
||||||
static void wm8904_setvolume(FAR struct wm8904_dev_s *priv, uint16_t 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 */
|
#endif /* CONFIG_AUDIO_EXCLUDE_VOLUME */
|
||||||
|
|
||||||
/************************************************************************************
|
/****************************************************************************
|
||||||
* Name: wm8904_setbass
|
* Name: wm8904_setbass
|
||||||
*
|
*
|
||||||
* Description:
|
* 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).
|
* The level and range are in whole percentage levels (0-100).
|
||||||
*
|
*
|
||||||
************************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
|
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
|
||||||
static void wm8904_setbass(FAR struct wm8904_dev_s *priv, uint8_t bass)
|
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 */
|
#endif /* CONFIG_AUDIO_EXCLUDE_TONE */
|
||||||
|
|
||||||
/************************************************************************************
|
/****************************************************************************
|
||||||
* Name: wm8904_settreble
|
* Name: wm8904_settreble
|
||||||
*
|
*
|
||||||
* Description:
|
* 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).
|
* The level and range are in whole percentage levels (0-100).
|
||||||
*
|
*
|
||||||
************************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
|
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
|
||||||
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)
|
||||||
@ -710,12 +750,12 @@ static void wm8904_setbitrate(FAR struct wm8904_dev_s *priv)
|
|||||||
|
|
||||||
/* MCLK must be divided down so that fref <=13.5MHz */
|
/* MCLK must be divided down so that fref <=13.5MHz */
|
||||||
|
|
||||||
if (fref > 4*13500000)
|
if (fref > 4 * 13500000)
|
||||||
{
|
{
|
||||||
fref >>= 3;
|
fref >>= 3;
|
||||||
regval = (WM8904_FLL_CLK_REF_SRC_MCLK | WM8904_FLL_CLK_REF_DIV8);
|
regval = (WM8904_FLL_CLK_REF_SRC_MCLK | WM8904_FLL_CLK_REF_DIV8);
|
||||||
}
|
}
|
||||||
else if (fref > 2*13500000)
|
else if (fref > 2 * 13500000)
|
||||||
{
|
{
|
||||||
fref >>= 2;
|
fref >>= 2;
|
||||||
regval = (WM8904_FLL_CLK_REF_SRC_MCLK | WM8904_FLL_CLK_REF_DIV4);
|
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;
|
priv->bitrate = fout;
|
||||||
|
|
||||||
/* Now, Configure the FLL */
|
/* Now, Configure the FLL */
|
||||||
|
|
||||||
/* FLL Control 1
|
/* FLL Control 1
|
||||||
*
|
*
|
||||||
* FLL_FRACN_ENA=1 : Enables fractional mode
|
* FLL_FRACN_ENA=1 : Enables fractional mode
|
||||||
@ -918,7 +959,7 @@ static void wm8904_setbitrate(FAR struct wm8904_dev_s *priv)
|
|||||||
retries = 5;
|
retries = 5;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
nxsig_usleep(5*5000);
|
nxsig_usleep(5 * 5000);
|
||||||
}
|
}
|
||||||
while (priv->locked == false && --retries > 0);
|
while (priv->locked == false && --retries > 0);
|
||||||
|
|
||||||
@ -941,10 +982,11 @@ static void wm8904_setbitrate(FAR struct wm8904_dev_s *priv)
|
|||||||
retries = 5;
|
retries = 5;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
nxsig_usleep(5*5000);
|
nxsig_usleep(5 * 5000);
|
||||||
}
|
}
|
||||||
while ((wm8904_readreg(priv, WM8904_INT_STATUS) & WM8904_FLL_LOCK_INT) != 0 ||
|
while ((wm8904_readreg(priv, WM8904_INT_STATUS) &
|
||||||
--retries > 0);
|
WM8904_FLL_LOCK_INT) != 0 ||
|
||||||
|
--retries > 0);
|
||||||
|
|
||||||
/* Clear all pending status bits by writing 1's into the interrupt status
|
/* Clear all pending status bits by writing 1's into the interrupt status
|
||||||
* register.
|
* register.
|
||||||
@ -996,18 +1038,21 @@ static int wm8904_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
|
|||||||
switch (caps->ac_subtype)
|
switch (caps->ac_subtype)
|
||||||
{
|
{
|
||||||
case AUDIO_TYPE_QUERY:
|
case AUDIO_TYPE_QUERY:
|
||||||
|
|
||||||
/* We don't decode any formats! Only something above us in
|
/* We don't decode any formats! Only something above us in
|
||||||
* the audio stream can perform decoding on our behalf.
|
* the audio stream can perform decoding on our behalf.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* The types of audio units we implement */
|
/* The types of audio units we implement */
|
||||||
|
|
||||||
caps->ac_controls.b[0] = AUDIO_TYPE_OUTPUT | AUDIO_TYPE_FEATURE |
|
caps->ac_controls.b[0] =
|
||||||
AUDIO_TYPE_PROCESSING;
|
AUDIO_TYPE_OUTPUT | AUDIO_TYPE_FEATURE |
|
||||||
|
AUDIO_TYPE_PROCESSING;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AUDIO_FMT_MIDI:
|
case AUDIO_FMT_MIDI:
|
||||||
|
|
||||||
/* We only support Format 0 */
|
/* We only support Format 0 */
|
||||||
|
|
||||||
caps->ac_controls.b[0] = AUDIO_SUBFMT_END;
|
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 */
|
/* Report the Sample rates we support */
|
||||||
|
|
||||||
caps->ac_controls.b[0] = AUDIO_SAMP_RATE_8K | AUDIO_SAMP_RATE_11K |
|
caps->ac_controls.b[0] =
|
||||||
AUDIO_SAMP_RATE_16K | AUDIO_SAMP_RATE_22K |
|
AUDIO_SAMP_RATE_8K | AUDIO_SAMP_RATE_11K |
|
||||||
AUDIO_SAMP_RATE_32K | AUDIO_SAMP_RATE_44K |
|
AUDIO_SAMP_RATE_16K | AUDIO_SAMP_RATE_22K |
|
||||||
AUDIO_SAMP_RATE_48K;
|
AUDIO_SAMP_RATE_32K | AUDIO_SAMP_RATE_44K |
|
||||||
|
AUDIO_SAMP_RATE_48K;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AUDIO_FMT_MP3:
|
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 */
|
/* 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;
|
caps->ac_controls.b[1] = AUDIO_FU_BALANCE >> 8;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* TODO: Do we need to provide specific info for the Feature Units,
|
/* TODO: Do we need to provide specific info for the Feature
|
||||||
* such as volume setting ranges, etc.?
|
* 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 */
|
/* 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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -1342,6 +1390,7 @@ static void wm8904_senddone(FAR struct i2s_dev_s *i2s,
|
|||||||
priv->inflight--;
|
priv->inflight--;
|
||||||
|
|
||||||
/* Save the result of the transfer */
|
/* Save the result of the transfer */
|
||||||
|
|
||||||
/* REVISIT: This can be overwritten */
|
/* REVISIT: This can be overwritten */
|
||||||
|
|
||||||
priv->result = result;
|
priv->result = result;
|
||||||
@ -1444,7 +1493,7 @@ static int wm8904_sendbuffer(FAR struct wm8904_dev_s *priv)
|
|||||||
irqstate_t flags;
|
irqstate_t flags;
|
||||||
uint32_t timeout;
|
uint32_t timeout;
|
||||||
int shift;
|
int shift;
|
||||||
int ret = OK;
|
int ret;
|
||||||
|
|
||||||
/* Loop while there are audio buffers to be sent and we have few than
|
/* Loop while there are audio buffers to be sent and we have few than
|
||||||
* CONFIG_WM8904_INFLIGHT then "in-flight"
|
* CONFIG_WM8904_INFLIGHT then "in-flight"
|
||||||
@ -1458,7 +1507,12 @@ static int wm8904_sendbuffer(FAR struct wm8904_dev_s *priv)
|
|||||||
* only while accessing 'inflight'.
|
* only while accessing 'inflight'.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
wm8904_takesem(&priv->pendsem);
|
ret = wm8904_takesem(&priv->pendsem);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
while (priv->inflight < CONFIG_WM8904_INFLIGHT &&
|
while (priv->inflight < CONFIG_WM8904_INFLIGHT &&
|
||||||
dq_peek(&priv->pendq) != NULL && !priv->paused)
|
dq_peek(&priv->pendq) != NULL && !priv->paused)
|
||||||
{
|
{
|
||||||
@ -1540,6 +1594,7 @@ static int wm8904_start(FAR struct audio_lowerhalf_s *dev)
|
|||||||
audinfo("Entry\n");
|
audinfo("Entry\n");
|
||||||
|
|
||||||
/* Exit reduced power modes of operation */
|
/* Exit reduced power modes of operation */
|
||||||
|
|
||||||
/* REVISIT */
|
/* REVISIT */
|
||||||
|
|
||||||
/* Create a message queue for the worker thread */
|
/* 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;
|
priv->threadid = 0;
|
||||||
|
|
||||||
/* Enter into a reduced power usage mode */
|
/* Enter into a reduced power usage mode */
|
||||||
|
|
||||||
/* REVISIT: */
|
/* REVISIT: */
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
@ -1667,7 +1723,8 @@ static int wm8904_pause(FAR struct audio_lowerhalf_s *dev)
|
|||||||
|
|
||||||
#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
|
#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
|
||||||
#ifdef CONFIG_AUDIO_MULTI_SESSION
|
#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
|
#else
|
||||||
static int wm8904_resume(FAR struct audio_lowerhalf_s *dev)
|
static int wm8904_resume(FAR struct audio_lowerhalf_s *dev)
|
||||||
#endif
|
#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 */
|
/* 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;
|
apb->flags |= AUDIO_APB_OUTPUT_ENQUEUED;
|
||||||
dq_addlast(&apb->dq_entry, &priv->pendq);
|
dq_addlast(&apb->dq_entry, &priv->pendq);
|
||||||
wm8904_givesem(&priv->pendsem);
|
wm8904_givesem(&priv->pendsem);
|
||||||
|
|
||||||
/* Send a message to the worker thread indicating that a new buffer has been
|
/* Send a message to the worker thread indicating that a new buffer has
|
||||||
* enqueued. If mq is NULL, then the playing has not yet started. In that
|
* been enqueued. If mq is NULL, then the playing has not yet started.
|
||||||
* case we are just "priming the pump" and we don't need to send any message.
|
* In that case we are just "priming the pump" and we don't need to send
|
||||||
|
* any message.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ret = OK;
|
ret = OK;
|
||||||
@ -1824,11 +1887,16 @@ static int wm8904_reserve(FAR struct audio_lowerhalf_s *dev)
|
|||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
FAR struct wm8904_dev_s *priv = (FAR struct wm8904_dev_s *) dev;
|
FAR struct wm8904_dev_s *priv = (FAR struct wm8904_dev_s *) dev;
|
||||||
int ret = OK;
|
int ret;
|
||||||
|
|
||||||
/* Borrow the APBQ semaphore for thread sync */
|
/* Borrow the APBQ semaphore for thread sync */
|
||||||
|
|
||||||
wm8904_takesem(&priv->pendsem);
|
ret = wm8904_takesem(&priv->pendsem);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (priv->reserved)
|
if (priv->reserved)
|
||||||
{
|
{
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
@ -1869,7 +1937,8 @@ static int wm8904_release(FAR struct audio_lowerhalf_s *dev)
|
|||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
FAR struct wm8904_dev_s *priv = (FAR struct wm8904_dev_s *)dev;
|
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 */
|
/* 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 */
|
/* Borrow the APBQ semaphore for thread sync */
|
||||||
|
|
||||||
wm8904_takesem(&priv->pendsem);
|
ret = wm8904_forcetake(&priv->pendsem);
|
||||||
|
|
||||||
/* Really we should free any queued buffers here */
|
/* Really we should free any queued buffers here */
|
||||||
|
|
||||||
priv->reserved = false;
|
priv->reserved = false;
|
||||||
wm8904_givesem(&priv->pendsem);
|
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
|
#ifndef CONFIG_AUDIO_EXCLUDE_STOP
|
||||||
case AUDIO_MSG_STOP:
|
case AUDIO_MSG_STOP:
|
||||||
|
|
||||||
/* Indicate that we are terminating */
|
/* Indicate that we are terminating */
|
||||||
|
|
||||||
audinfo("AUDIO_MSG_STOP: Terminating\n");
|
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 */
|
/* 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)
|
while ((apb = (FAR struct ap_buffer_s *)dq_remfirst(&priv->pendq)) != NULL)
|
||||||
{
|
{
|
||||||
/* Release our reference to the buffer */
|
/* 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);
|
wm8904_writereg(priv, WM8904_VMID_CTRL, regval);
|
||||||
|
|
||||||
/* Mic Bias Control 0 */
|
/* Mic Bias Control 0 */
|
||||||
|
|
||||||
/* MICDET_ENA=1, MICBIAS_ENA=1 */
|
/* MICDET_ENA=1, MICBIAS_ENA=1 */
|
||||||
|
|
||||||
regval = WM8904_MICDET_ENA | WM8904_MICBIAS_ENA;
|
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);
|
wm8904_writereg(priv, WM8904_PM2, regval);
|
||||||
|
|
||||||
/* Power Management 6 */
|
/* Power Management 6 */
|
||||||
|
|
||||||
/* DACL_ENA=1, DACR_ENA=1, ADCL_ENA=1, ADCR_ENA=1 */
|
/* 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);
|
wm8904_writereg(priv, WM8904_PM6, regval);
|
||||||
|
|
||||||
/* Clock Rates 0.
|
/* Clock Rates 0.
|
||||||
*
|
*
|
||||||
* This value sets TOCLK_RATE_DIV16=0, TOCLK_RATE_X4=0, and MCLK_DIV=0 while
|
* This value sets TOCLK_RATE_DIV16=0, TOCLK_RATE_X4=0, and MCLK_DIV=0
|
||||||
* preserving the state of some undocumented bits (see wm8904.h).
|
* while preserving the state of some undocumented bits (see wm8904.h).
|
||||||
*
|
*
|
||||||
* MCLK_DIV=0 : MCLK is is not divided by 2.
|
* 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.
|
/* Audio Interface 1.
|
||||||
*
|
*
|
||||||
* This value sets AIFADC_TDM=0, AIFADC_TDM_CHAN=0, BCLK_DIR=1 while preserving
|
* This value sets AIFADC_TDM=0, AIFADC_TDM_CHAN=0, BCLK_DIR=1 while
|
||||||
* the state of some undocumented bits (see wm8904.h).
|
* preserving the state of some undocumented bits (see wm8904.h).
|
||||||
*
|
*
|
||||||
* Digital audio interface format : I2S
|
* Digital audio interface format : I2S
|
||||||
* Digital audio interface word length : 24
|
* Digital audio interface word length : 24
|
||||||
* AIF_LRCLK_INV=0 : LRCLK not inverted
|
* 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_BCLK_INV=0 : BCLK not inverted
|
||||||
* AIF_TRIS=0 : Outputs not tri-stated
|
* AIF_TRIS=0 : Outputs not tri-stated
|
||||||
* AIFADC_TDM_CHAN=0 : ADCDAT outputs data on slot 0
|
* 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
|
* 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);
|
wm8904_writereg(priv, WM8904_AIF1, regval);
|
||||||
|
|
||||||
/* Audio Interface 2.
|
/* Audio Interface 2.
|
||||||
@ -2271,10 +2346,10 @@ static void wm8904_audio_output(FAR struct wm8904_dev_s *priv)
|
|||||||
|
|
||||||
/* Audio Interface 3
|
/* Audio Interface 3
|
||||||
*
|
*
|
||||||
* Set LRCLK as an output with rate = BCLK / (2*WM8904_FRAMELENn). This is
|
* Set LRCLK as an output with rate = BCLK / (2*WM8904_FRAMELENn). This
|
||||||
* a value that varies with bits per sample, n=8 or 16. Since I2S will send
|
* is a value that varies with bits per sample, n=8 or 16. Since I2S will
|
||||||
* a word on each edge of LRCLK (after a delay), this essentially means that
|
* send a word on each edge of LRCLK (after a delay), this essentially
|
||||||
* each audio frame is WM8904_FRAMELENn bits in length.
|
* means that each audio frame is WM8904_FRAMELENn bits in length.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
regval = WM8904_LRCLK_DIR | WM8904_LRCLK_RATE(2*WM8904_FRAMELEN16);
|
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);
|
wm8904_writereg(priv, WM8904_DAC_DIGI1, 0);
|
||||||
|
|
||||||
/* Analogue Left Input 0 */
|
/* Analogue Left Input 0 */
|
||||||
|
|
||||||
/* Analogue Right Input 0 */
|
/* Analogue Right Input 0 */
|
||||||
|
|
||||||
regval = WM8904_IN_VOL(5);
|
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);
|
wm8904_writereg(priv, WM8904_ANA_RIGHT_IN1, 0);
|
||||||
|
|
||||||
/* Analogue OUT1 Left */
|
/* Analogue OUT1 Left */
|
||||||
|
|
||||||
/* Analogue OUT1 Right */
|
/* Analogue OUT1 Right */
|
||||||
|
|
||||||
wm8904_setvolume(priv, CONFIG_WM8904_INITVOLUME, true);
|
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 */
|
/* Analogue HP 0 */
|
||||||
|
|
||||||
regval = WM8904_HPL_RMV_SHORT | WM8904_HPL_ENA_OUTP | WM8904_HPL_ENA_DLY | WM8904_HPL_ENA |
|
regval = WM8904_HPL_RMV_SHORT | WM8904_HPL_ENA_OUTP | WM8904_HPL_ENA_DLY |
|
||||||
WM8904_HPR_RMV_SHORT | WM8904_HPR_ENA_OUTP | WM8904_HPR_ENA_DLY | WM8904_HPR_ENA;
|
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);
|
wm8904_writereg(priv, WM8904_ANA_HP0, regval);
|
||||||
|
|
||||||
/* Charge Pump 0 */
|
/* Charge Pump 0 */
|
||||||
|
@ -1,51 +1,40 @@
|
|||||||
/**************************************************************************************
|
/****************************************************************************
|
||||||
* drivers/lcd/ft80x.c
|
* drivers/lcd/ft80x.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
* 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:
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
* - 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.
|
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* modification, are permitted provided that the following conditions
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
* are met:
|
* 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
|
* Included Files
|
||||||
**************************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include <nuttx/config.h>
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
@ -154,6 +143,35 @@ static const struct file_operations g_ft80x_fops =
|
|||||||
* Private Functions
|
* 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
|
* Name: ft80x_fade
|
||||||
*
|
*
|
||||||
@ -295,7 +313,7 @@ static void ft80x_interrupt_work(FAR void *arg)
|
|||||||
|
|
||||||
/* Get exclusive access to the device structures */
|
/* 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
|
/* Get the set of pending interrupts. Note that simply reading this
|
||||||
* register is sufficient to clear all pending interrupts.
|
* register is sufficient to clear all pending interrupts.
|
||||||
@ -309,74 +327,74 @@ static void ft80x_interrupt_work(FAR void *arg)
|
|||||||
* implementation.
|
* implementation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((intflags & FT80X_INT_SWAP) != 0)
|
if ((intflags & FT80X_INT_SWAP) != 0)
|
||||||
{
|
{
|
||||||
/* Display swap occurred */
|
/* Display swap occurred */
|
||||||
|
|
||||||
lcdinfo("Display swap occurred\n");
|
lcdinfo("Display swap occurred\n");
|
||||||
ft80x_notify(priv, FT80X_NOTIFY_SWAP, 0);
|
ft80x_notify(priv, FT80X_NOTIFY_SWAP, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((intflags & FT80X_INT_TOUCH) != 0)
|
if ((intflags & FT80X_INT_TOUCH) != 0)
|
||||||
{
|
{
|
||||||
/* Touch-screen touch detected */
|
/* Touch-screen touch detected */
|
||||||
|
|
||||||
lcdinfo("Touch-screen touch detected\n");
|
lcdinfo("Touch-screen touch detected\n");
|
||||||
ft80x_notify(priv, FT80X_NOTIFY_TOUCH, 0);
|
ft80x_notify(priv, FT80X_NOTIFY_TOUCH, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((intflags & FT80X_INT_TAG) != 0)
|
if ((intflags & FT80X_INT_TAG) != 0)
|
||||||
{
|
{
|
||||||
/* Touch-screen tag value change */
|
/* Touch-screen tag value change */
|
||||||
|
|
||||||
lcdinfo("Touch-screen tag value change\n");
|
lcdinfo("Touch-screen tag value change\n");
|
||||||
#ifdef CONFIG_LCD_FT800
|
#ifdef CONFIG_LCD_FT800
|
||||||
regval = ft80x_read_word(priv, FT80X_REG_TOUCH_TAG);
|
regval = ft80x_read_word(priv, FT80X_REG_TOUCH_TAG);
|
||||||
#else
|
#else
|
||||||
regval = ft80x_read_word(priv, FT80X_REG_CTOUCH_TAG);
|
regval = ft80x_read_word(priv, FT80X_REG_CTOUCH_TAG);
|
||||||
#endif
|
#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)
|
if ((intflags & FT80X_INT_SOUND) != 0)
|
||||||
{
|
{
|
||||||
/* Sound effect ended */
|
/* Sound effect ended */
|
||||||
|
|
||||||
lcdinfo(" Sound effect ended\n");
|
lcdinfo(" Sound effect ended\n");
|
||||||
ft80x_notify(priv, FT80X_NOTIFY_SOUND, 0);
|
ft80x_notify(priv, FT80X_NOTIFY_SOUND, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((intflags & FT80X_INT_PLAYBACK) != 0)
|
if ((intflags & FT80X_INT_PLAYBACK) != 0)
|
||||||
{
|
{
|
||||||
/* Audio playback ended */
|
/* Audio playback ended */
|
||||||
|
|
||||||
lcdinfo("Audio playback ended\n");
|
lcdinfo("Audio playback ended\n");
|
||||||
ft80x_notify(priv, FT80X_NOTIFY_PLAYBACK, 0);
|
ft80x_notify(priv, FT80X_NOTIFY_PLAYBACK, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((intflags & FT80X_INT_CMDEMPTY) != 0)
|
if ((intflags & FT80X_INT_CMDEMPTY) != 0)
|
||||||
{
|
{
|
||||||
/* Command FIFO empty */
|
/* Command FIFO empty */
|
||||||
|
|
||||||
lcdinfo("Command FIFO empty\n");
|
lcdinfo("Command FIFO empty\n");
|
||||||
ft80x_notify(priv, FT80X_NOTIFY_CMDEMPTY, 0);
|
ft80x_notify(priv, FT80X_NOTIFY_CMDEMPTY, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((intflags & FT80X_INT_CMDFLAG) != 0)
|
if ((intflags & FT80X_INT_CMDFLAG) != 0)
|
||||||
{
|
{
|
||||||
/* Command FIFO flag */
|
/* Command FIFO flag */
|
||||||
|
|
||||||
lcdinfo("Command FIFO flag\n");
|
lcdinfo("Command FIFO flag\n");
|
||||||
ft80x_notify(priv, FT80X_NOTIFY_CMDFLAG, 0);
|
ft80x_notify(priv, FT80X_NOTIFY_CMDFLAG, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((intflags & FT80X_INT_CONVCOMPLETE) != 0)
|
if ((intflags & FT80X_INT_CONVCOMPLETE) != 0)
|
||||||
{
|
{
|
||||||
/* Touch-screen conversions completed */
|
/* Touch-screen conversions completed */
|
||||||
|
|
||||||
lcdinfo(" Touch-screen conversions completed\n");
|
lcdinfo(" Touch-screen conversions completed\n");
|
||||||
ft80x_notify(priv, FT80X_NOTIFY_CONVCOMPLETE, 0);
|
ft80x_notify(priv, FT80X_NOTIFY_CONVCOMPLETE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Re-enable interrupts */
|
/* 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 ||
|
if (buffer == NULL || ((uintptr_t)buffer & 3) != 0 ||
|
||||||
len == 0 || (len & 3) != 0 || (len + filep->f_pos) > FT80X_RAM_DL_SIZE)
|
len == 0 || (len & 3) != 0 || (len + filep->f_pos) > FT80X_RAM_DL_SIZE)
|
||||||
{
|
{
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get exclusive access to the device structures */
|
/* 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)
|
switch (cmd)
|
||||||
{
|
{
|
||||||
/* FT80X_IOC_CREATEDL:
|
/* FT80X_IOC_CREATEDL:
|
||||||
* Description: Write a display list to the FT80x display list memory
|
* Description: Write a display list to the FT80x display list
|
||||||
* Description: Write a display list to the FT80x display list memory
|
* memory
|
||||||
* starting at offset zero. This may or may not be the
|
* Description: Write a display list to the FT80x display list
|
||||||
* entire display list. Display lists may be created
|
* memory starting at offset zero. This may or may
|
||||||
* incrementally, starting with FT80X_IOC_CREATEDL and
|
* not be the entire display list. Display lists may
|
||||||
* finishing the display list using FT80XIO_APPENDDL
|
* 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.
|
* Argument: A reference to a display list structure instance.
|
||||||
* See struct ft80x_displaylist_s.
|
* See struct ft80x_displaylist_s.
|
||||||
* Returns: None
|
* Returns: None
|
||||||
@ -682,12 +702,13 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
|
|
||||||
/* FT80X_IOC_APPENDDL:
|
/* FT80X_IOC_APPENDDL:
|
||||||
* Description: Write additional display list entries to the FT80x
|
* Description: Write additional display list entries to the FT80x
|
||||||
* display list memory at the current display list offset.
|
* display list memory at the current display list
|
||||||
* This IOCTL command permits display lists to be completed
|
* offset. This IOCTL command permits display lists
|
||||||
* incrementally, starting with FT80X_IOC_CREATEDL and
|
* to be completed incrementally, starting with
|
||||||
* finishing the display list using FT80XIO_APPENDDL.
|
* FT80X_IOC_CREATEDL and finishing the display list
|
||||||
* Argument: A reference to a display list structure instance. See
|
* using FT80XIO_APPENDDL.
|
||||||
* struct ft80x_displaylist_s.
|
* Argument: A reference to a display list structure instance.
|
||||||
|
* See struct ft80x_displaylist_s.
|
||||||
* Returns: None
|
* Returns: None
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -778,7 +799,7 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
|
|
||||||
/* FT80X_IOC_PUTRAMCMD
|
/* FT80X_IOC_PUTRAMCMD
|
||||||
* Description: Write 32-bit aligned data to FT80x FIFO (RAM_CMD)
|
* 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.
|
* 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 *ramcmd =
|
||||||
(FAR struct ft80x_relmem_s *)((uintptr_t)arg);
|
(FAR struct ft80x_relmem_s *)((uintptr_t)arg);
|
||||||
|
|
||||||
if (ramcmd == NULL || ((uintptr_t)ramcmd->offset & 3) != 0 /* ||
|
if (ramcmd == NULL || ((uintptr_t)ramcmd->offset & 3) != 0)
|
||||||
ramcmd->offset >= FT80X_CMDFIFO_SIZE */ )
|
|
||||||
{
|
{
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
@ -803,7 +823,8 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
|
|
||||||
/* FT80X_IOC_GETREG8:
|
/* FT80X_IOC_GETREG8:
|
||||||
* Description: Read an 8-bit register value from the FT80x.
|
* 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.
|
* 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:
|
/* FT80X_IOC_GETREG16:
|
||||||
* Description: Read a 16-bit register value from the FT80x.
|
* 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.
|
* 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:
|
/* FT80X_IOC_GETREG32:
|
||||||
* Description: Read a 32-bit register value from the FT80x.
|
* 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.
|
* 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:
|
/* FT80X_IOC_GETREGS:
|
||||||
* Description: Read multiple 32-bit register values from the FT80x.
|
* Description: Read multiple 32-bit register values from the FT80x.
|
||||||
* Argument: A reference to an instance of struct ft80x_registers_s.
|
* Argument: A reference to an instance of struct
|
||||||
* Returns: The 32-bit values read from the consecutive registers .
|
* ft80x_registers_s.
|
||||||
|
* Returns: The 32-bit values read from the consecutive
|
||||||
|
* registers .
|
||||||
*/
|
*/
|
||||||
|
|
||||||
case FT80X_IOC_GETREGS:
|
case FT80X_IOC_GETREGS:
|
||||||
@ -896,7 +921,8 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
|
|
||||||
/* FT80X_IOC_PUTREG8:
|
/* FT80X_IOC_PUTREG8:
|
||||||
* Description: Write an 8-bit register value to the FT80x.
|
* 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.
|
* Returns: None.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -919,7 +945,8 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
|
|
||||||
/* FT80X_IOC_PUTREG16:
|
/* FT80X_IOC_PUTREG16:
|
||||||
* Description: Write a 16-bit register value to the FT80x.
|
* 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.
|
* Returns: None.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -942,7 +969,8 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
|
|
||||||
/* FT80X_IOC_PUTREG32:
|
/* FT80X_IOC_PUTREG32:
|
||||||
* Description: Write a 32-bit register value to the FT80x.
|
* 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.
|
* Returns: None.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -965,7 +993,8 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
|
|
||||||
/* FT80X_IOC_PUTREGS:
|
/* FT80X_IOC_PUTREGS:
|
||||||
* Description: Write multiple 32-bit register values to the FT80x.
|
* 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.
|
* 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)
|
#if defined(CONFIG_LCD_FT80X_AUDIO_MCUSHUTDOWN)
|
||||||
/* Amplifier is controlled by an MCU GPIO pin */
|
/* 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);
|
DEBUGASSERT(arg == 0 || arg == 1);
|
||||||
|
|
||||||
priv->lower->audio(priv->lower, (arg != 0));
|
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_VSYNC0
|
||||||
* - FT80X_REG_VSYNC1
|
* - FT80X_REG_VSYNC1
|
||||||
*
|
*
|
||||||
* And the FT80X_REG_CSPREAD register changes color clock timing to reduce system
|
* And the FT80X_REG_CSPREAD register changes color clock timing to reduce
|
||||||
* noise.
|
* system noise.
|
||||||
*
|
*
|
||||||
* GPIO bit 7 is used for the display enable pin of the LCD module. By
|
* 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
|
* 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
|
* 1. Drive the PD_N pin high
|
||||||
* 2. Wait for at least 20ms
|
* 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:
|
* 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.
|
* Mode" except waiting for at least 20ms in step 2.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
DEBUGASSERT(priv->lower != NULL && priv->lower->pwrdown != NULL);
|
DEBUGASSERT(priv->lower != NULL && priv->lower->pwrdown != NULL);
|
||||||
priv->lower->pwrdown(priv->lower, false);
|
priv->lower->pwrdown(priv->lower, false);
|
||||||
up_mdelay(20);
|
up_mdelay(20);
|
||||||
|
|
||||||
/* Initialization Sequence during the boot up:
|
/* 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
|
* 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.
|
* 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
|
* a. Set FT80X_REG_PCLK to zero - This disables the pixel clock output
|
||||||
* the LCD and other system parameters are configured
|
* while the LCD and other system parameters are configured
|
||||||
* b. Set the following registers with values for the chosen display.
|
* b. Set the following registers with values for the chosen display.
|
||||||
* Typical WQVGA and QVGA values are shown:
|
* 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 */
|
/* 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 + 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 + 4, FT80X_CLEAR(1, 1, 1));
|
||||||
ft80x_write_word(priv, FT80X_RAM_DL + 8, FT80X_DISPLAY());
|
ft80x_write_word(priv, FT80X_RAM_DL + 8, FT80X_DISPLAY());
|
||||||
|
|
||||||
/* 6. Write FT80X_REG_DLSWAP, FT800 swaps display list immediately */
|
/* 6. Write FT80X_REG_DLSWAP, FT800 swaps display list immediately */
|
||||||
|
@ -101,7 +101,7 @@ struct phy_notify_s
|
|||||||
* Private Function Prototypes
|
* 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_unassigned(void);
|
||||||
static FAR struct phy_notify_s *phy_find_assigned(FAR const char *intf,
|
static FAR struct phy_notify_s *phy_find_assigned(FAR const char *intf,
|
||||||
pid_t pid);
|
pid_t pid);
|
||||||
@ -128,9 +128,9 @@ static struct phy_notify_s
|
|||||||
* Name: phy_semtake
|
* 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);
|
#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)
|
static FAR struct phy_notify_s *phy_find_unassigned(void)
|
||||||
{
|
{
|
||||||
FAR struct phy_notify_s *client;
|
FAR struct phy_notify_s *client;
|
||||||
|
int ret;
|
||||||
int i;
|
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++)
|
for (i = 0; i < CONFIG_PHY_NOTIFICATION_NCLIENTS; i++)
|
||||||
{
|
{
|
||||||
client = &g_notify_clients[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)
|
pid_t pid)
|
||||||
{
|
{
|
||||||
FAR struct phy_notify_s *client;
|
FAR struct phy_notify_s *client;
|
||||||
|
int ret;
|
||||||
int i;
|
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++)
|
for (i = 0; i < CONFIG_PHY_NOTIFICATION_NCLIENTS; i++)
|
||||||
{
|
{
|
||||||
client = &g_notify_clients[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 */
|
/* Check if this client already exists */
|
||||||
|
|
||||||
client = phy_find_assigned(intf, pid);
|
client = phy_find_assigned(intf, pid);
|
||||||
if (client)
|
if (client != NULL)
|
||||||
{
|
{
|
||||||
/* Yes.. update the signal number and argument */
|
/* 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 */
|
/* No, allocate a new slot in the client notification table */
|
||||||
|
|
||||||
client = phy_find_unassigned();
|
client = phy_find_unassigned();
|
||||||
if (!client)
|
if (client == NULL)
|
||||||
{
|
{
|
||||||
phyerr("ERROR: Failed to allocate a client entry\n");
|
phyerr("ERROR: Failed to allocate a client entry\n");
|
||||||
return -ENOMEM;
|
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)
|
int phy_notify_unsubscribe(FAR const char *intf, pid_t pid)
|
||||||
{
|
{
|
||||||
FAR struct phy_notify_s *client;
|
FAR struct phy_notify_s *client;
|
||||||
|
int ret;
|
||||||
|
|
||||||
phyinfo("%s: PID=%d\n", intf, pid);
|
phyinfo("%s: PID=%d\n", intf, pid);
|
||||||
|
|
||||||
/* Find the client entry for this interface */
|
/* Find the client entry for this interface */
|
||||||
|
|
||||||
client = phy_find_assigned(intf, pid);
|
client = phy_find_assigned(intf, pid);
|
||||||
if (!client)
|
if (client == NULL)
|
||||||
{
|
{
|
||||||
phyerr("ERROR: No such client\n");
|
phyerr("ERROR: No such client\n");
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
@ -359,20 +374,24 @@ int phy_notify_unsubscribe(FAR const char *intf, pid_t pid)
|
|||||||
|
|
||||||
/* Detach and disable the PHY interrupt */
|
/* Detach and disable the PHY interrupt */
|
||||||
|
|
||||||
phy_semtake();
|
ret = phy_semtake();
|
||||||
arch_phy_irq(intf, NULL, NULL, NULL);
|
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->assigned = false;
|
||||||
client->intf[0] = '\0';
|
client->intf[0] = '\0';
|
||||||
client->pid = -1;
|
client->pid = -1;
|
||||||
|
|
||||||
|
phy_semgive();
|
||||||
|
}
|
||||||
|
|
||||||
phy_semgive();
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,40 +1,25 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* drivers/net/slip.c
|
* drivers/net/slip.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2011-2012, 2015-2018 Gregory Nutt. All rights reserved.
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
* 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
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* modification, are permitted provided that the following conditions
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
* are met:
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
*
|
* License for the specific language governing permissions and limitations
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
* under the License.
|
||||||
* 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.
|
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* Reference: RFC 1055 */
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Included Files
|
* Included Files
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@ -110,14 +95,14 @@
|
|||||||
# define CONFIG_NET_SLIP_NINTERFACES 1
|
# define CONFIG_NET_SLIP_NINTERFACES 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* SLIP special character codes *******************************************/
|
/* SLIP special character codes ********************************************/
|
||||||
|
|
||||||
#define SLIP_END 0300 /* Indicates end of packet */
|
#define SLIP_END 0300 /* Indicates end of packet */
|
||||||
#define SLIP_ESC 0333 /* Indicates byte stuffing */
|
#define SLIP_ESC 0333 /* Indicates byte stuffing */
|
||||||
#define SLIP_ESC_END 0334 /* ESC ESC_END means SLIP_END data byte */
|
#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 */
|
#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. */
|
/* 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
|
* 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 */
|
/* 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
|
* 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);
|
#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
|
* 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)
|
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,
|
/* If the polling resulted in data that should be sent out on the network,
|
||||||
* the field d_len is set to a value > 0.
|
* 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
|
/* If zero is returned, the polling will continue until all connections
|
||||||
* been examined.
|
* have been examined.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -426,6 +441,7 @@ static int slip_txtask(int argc, FAR char *argv[])
|
|||||||
clock_t start_ticks;
|
clock_t start_ticks;
|
||||||
clock_t now_ticks;
|
clock_t now_ticks;
|
||||||
unsigned int hsec;
|
unsigned int hsec;
|
||||||
|
int ret;
|
||||||
|
|
||||||
nerr("index: %d\n", index);
|
nerr("index: %d\n", index);
|
||||||
DEBUGASSERT(index < CONFIG_NET_SLIP_NINTERFACES);
|
DEBUGASSERT(index < CONFIG_NET_SLIP_NINTERFACES);
|
||||||
@ -440,11 +456,17 @@ static int slip_txtask(int argc, FAR char *argv[])
|
|||||||
/* Loop forever */
|
/* Loop forever */
|
||||||
|
|
||||||
start_ticks = clock_systimer();
|
start_ticks = clock_systimer();
|
||||||
for (; ; )
|
for (; ; )
|
||||||
{
|
{
|
||||||
/* Wait for the timeout to expire (or until we are signaled by */
|
/* 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)
|
if (!priv->txnodelay)
|
||||||
{
|
{
|
||||||
slip_semgive(priv);
|
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)
|
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
|
#ifdef CONFIG_NET_IPv4
|
||||||
nerr("Bringing up: %d.%d.%d.%d\n",
|
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)
|
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" */
|
/* 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)
|
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 */
|
/* 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
|
#ifdef CONFIG_NET_MCASTGROUP
|
||||||
static int slip_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac)
|
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 */
|
/* 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
|
#ifdef CONFIG_NET_MCASTGROUP
|
||||||
static int slip_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac)
|
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 */
|
/* 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. */
|
/* Wait and make sure that the receive task is started. */
|
||||||
|
|
||||||
slip_semtake(priv);
|
slip_forcetake(priv);
|
||||||
|
|
||||||
/* Start the SLIP transmitter kernel thread */
|
/* 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. */
|
/* 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 */
|
/* Bump the semaphore count so that it can now be used as a mutex */
|
||||||
|
|
||||||
|
@ -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 inode *inode = filep->f_inode;
|
||||||
FAR struct telnet_dev_s *priv = inode->i_private;
|
FAR struct telnet_dev_s *priv = inode->i_private;
|
||||||
ssize_t ret = 0;
|
ssize_t nread = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
ninfo("len: %d\n", len);
|
ninfo("len: %d\n", len);
|
||||||
|
|
||||||
@ -848,33 +849,44 @@ static ssize_t telnet_read(FAR struct file *filep, FAR char *buffer,
|
|||||||
return -EAGAIN;
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Take exclusive access to data buffer */
|
/* 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 */
|
/* Process the buffered telnet data */
|
||||||
|
|
||||||
src = &priv->td_rxbuffer[priv->td_offset];
|
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);
|
nxsem_post(&priv->td_exclsem);
|
||||||
}
|
}
|
||||||
while (ret == 0);
|
while (nread == 0);
|
||||||
|
|
||||||
/* Returned Value:
|
/* Returned Value:
|
||||||
*
|
*
|
||||||
* ret > 0: The number of characters copied into the user buffer by
|
* nread > 0: The number of characters copied into the user buffer by
|
||||||
* telnet_receive().
|
* telnet_receive().
|
||||||
* ret <= 0: Loss of connection or error events reported by recv().
|
* nread <= 0: Loss of connection or error events reported by recv().
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return ret;
|
return nread;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
@ -166,7 +166,7 @@ struct tun_driver_s
|
|||||||
* Private Function Prototypes
|
* 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);
|
static void tun_unlock(FAR struct tun_device_s *priv);
|
||||||
|
|
||||||
/* Common TX logic */
|
/* Common TX logic */
|
||||||
@ -249,9 +249,9 @@ static const struct file_operations g_tun_file_ops =
|
|||||||
* Name: tundev_lock
|
* 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
|
* 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)
|
static void tun_poll_work(FAR void *arg)
|
||||||
{
|
{
|
||||||
FAR struct tun_device_s *priv = (FAR struct tun_device_s *)arg;
|
FAR struct tun_device_s *priv = (FAR struct tun_device_s *)arg;
|
||||||
|
int ret;
|
||||||
|
|
||||||
/* Perform the poll */
|
/* 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();
|
net_lock();
|
||||||
|
|
||||||
/* Check if there is room in the send another TX packet. We cannot perform
|
/* 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)
|
static void tun_txavail_work(FAR void *arg)
|
||||||
{
|
{
|
||||||
FAR struct tun_device_s *priv = (FAR struct tun_device_s *)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. */
|
/* 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_driver_s *tun = inode->i_private;
|
||||||
FAR struct tun_device_s *priv = filep->f_priv;
|
FAR struct tun_device_s *priv = filep->f_priv;
|
||||||
int intf;
|
int intf;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (priv == NULL)
|
if (priv == NULL)
|
||||||
{
|
{
|
||||||
@ -1159,13 +1178,16 @@ static int tun_close(FAR struct file *filep)
|
|||||||
}
|
}
|
||||||
|
|
||||||
intf = priv - g_tun_devices;
|
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);
|
tundev_unlock(tun);
|
||||||
tun_dev_uninit(priv);
|
}
|
||||||
|
|
||||||
tundev_unlock(tun);
|
return ret;
|
||||||
return OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@ -1176,17 +1198,26 @@ static ssize_t tun_write(FAR struct file *filep, FAR const char *buffer,
|
|||||||
size_t buflen)
|
size_t buflen)
|
||||||
{
|
{
|
||||||
FAR struct tun_device_s *priv = filep->f_priv;
|
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)
|
if (priv == NULL || buflen > CONFIG_NET_TUN_PKTSIZE)
|
||||||
{
|
{
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
tun_lock(priv);
|
|
||||||
|
|
||||||
for (; ; )
|
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 */
|
/* Check if there are free space to write */
|
||||||
|
|
||||||
if (priv->write_d_len == 0)
|
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);
|
tun_net_receive(priv);
|
||||||
net_unlock();
|
net_unlock();
|
||||||
|
|
||||||
ret = buflen;
|
nwritten = buflen;
|
||||||
break;
|
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)
|
if ((filep->f_oflags & O_NONBLOCK) != 0)
|
||||||
{
|
{
|
||||||
ret = -EAGAIN;
|
nwritten = -EAGAIN;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->write_wait = true;
|
priv->write_wait = true;
|
||||||
tun_unlock(priv);
|
tun_unlock(priv);
|
||||||
nxsem_wait(&priv->write_wait_sem);
|
nxsem_wait(&priv->write_wait_sem);
|
||||||
tun_lock(priv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tun_unlock(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)
|
size_t buflen)
|
||||||
{
|
{
|
||||||
FAR struct tun_device_s *priv = filep->f_priv;
|
FAR struct tun_device_s *priv = filep->f_priv;
|
||||||
ssize_t ret;
|
ssize_t nread;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (priv == NULL)
|
if (priv == NULL)
|
||||||
{
|
{
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
tun_lock(priv);
|
|
||||||
|
|
||||||
for (; ; )
|
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 */
|
/* Check if there are data to read in write buffer */
|
||||||
|
|
||||||
if (priv->write_d_len > 0)
|
if (priv->write_d_len > 0)
|
||||||
{
|
{
|
||||||
if (buflen < priv->write_d_len)
|
if (buflen < priv->write_d_len)
|
||||||
{
|
{
|
||||||
ret = -EINVAL;
|
nread = -EINVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(buffer, priv->write_buf, priv->write_d_len);
|
memcpy(buffer, priv->write_buf, priv->write_d_len);
|
||||||
ret = priv->write_d_len;
|
nread = priv->write_d_len;
|
||||||
priv->write_d_len = 0;
|
priv->write_d_len = 0;
|
||||||
|
|
||||||
NETDEV_TXDONE(&priv->dev);
|
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)
|
if (buflen < priv->read_d_len)
|
||||||
{
|
{
|
||||||
ret = -EINVAL;
|
nread = -EINVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(buffer, priv->read_buf, priv->read_d_len);
|
memcpy(buffer, priv->read_buf, priv->read_d_len);
|
||||||
ret = priv->read_d_len;
|
nread = priv->read_d_len;
|
||||||
priv->read_d_len = 0;
|
priv->read_d_len = 0;
|
||||||
|
|
||||||
net_lock();
|
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)
|
if ((filep->f_oflags & O_NONBLOCK) != 0)
|
||||||
{
|
{
|
||||||
ret = -EAGAIN;
|
nread = -EAGAIN;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->read_wait = true;
|
priv->read_wait = true;
|
||||||
tun_unlock(priv);
|
tun_unlock(priv);
|
||||||
nxsem_wait(&priv->read_wait_sem);
|
nxsem_wait(&priv->read_wait_sem);
|
||||||
tun_lock(priv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tun_unlock(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;
|
FAR struct tun_device_s *priv = filep->f_priv;
|
||||||
pollevent_t eventset;
|
pollevent_t eventset;
|
||||||
int ret = OK;
|
int ret;
|
||||||
|
|
||||||
/* Some sanity checking */
|
/* Some sanity checking */
|
||||||
|
|
||||||
@ -1315,7 +1353,11 @@ int tun_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
tun_lock(priv);
|
ret = tun_lock(priv);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (setup)
|
if (setup)
|
||||||
{
|
{
|
||||||
@ -1384,7 +1426,11 @@ static int tun_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
tundev_lock(tun);
|
ret = tundev_lock(tun);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
free_tuns = tun->free_tuns;
|
free_tuns = tun->free_tuns;
|
||||||
|
|
||||||
|
@ -1,36 +1,20 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* drivers/rwbuffer.c
|
* drivers/rwbuffer.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009, 2011, 2013-2014, 2017, 2020 Gregory Nutt. All
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
* rights reserved.
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
* 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
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
*
|
*
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
* notice, this list of conditions and the following disclaimer in
|
* License for the specific language governing permissions and limitations
|
||||||
* the documentation and/or other materials provided with the
|
* under the License.
|
||||||
* 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.
|
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
@ -79,9 +63,9 @@
|
|||||||
* Name: rwb_semtake
|
* 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)
|
#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
|
* Name: rwb_overlap
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@ -182,7 +194,7 @@ static void rwb_wrtimeout(FAR void *arg)
|
|||||||
* worker thread.
|
* worker thread.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
rwb_semtake(&rwb->wrsem);
|
rwb_forcetake(&rwb->wrsem);
|
||||||
rwb_wrflush(rwb);
|
rwb_wrflush(rwb);
|
||||||
rwb_semgive(&rwb->wrsem);
|
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);
|
finfo("startblock=%d blockcount=%p\n", startblock, blockcount);
|
||||||
|
|
||||||
rwb_semtake(&rwb->wrsem);
|
rwb_forcetake(&rwb->wrsem);
|
||||||
|
|
||||||
/* Now there are five cases:
|
/* 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);
|
finfo("startblock=%d blockcount=%p\n", startblock, blockcount);
|
||||||
|
|
||||||
rwb_semtake(&rwb->rhsem);
|
rwb_forcetake(&rwb->rhsem);
|
||||||
|
|
||||||
/* Now there are five cases:
|
/* 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 */
|
/* 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; )
|
for (remaining = nblocks; remaining > 0; )
|
||||||
{
|
{
|
||||||
/* Is there anything in the read-ahead buffer? */
|
/* Is there anything in the read-ahead buffer? */
|
||||||
|
Loading…
Reference in New Issue
Block a user