mirror of
https://github.com/apache/nuttx.git
synced 2025-01-13 09:49:21 +08:00
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
9 changed files with 821 additions and 442 deletions
|
@ -76,17 +76,20 @@ static
|
|||
uint8_t cs43l22_readreg(FAR struct cs43l22_dev_s *priv, uint8_t regaddr);
|
||||
static void cs43l22_writereg(FAR struct cs43l22_dev_s *priv, uint8_t regaddr,
|
||||
uint8_t regval);
|
||||
static void cs43l22_takesem(sem_t * sem);
|
||||
static int cs43l22_takesem(FAR sem_t *sem);
|
||||
static int cs43l22_forcetake(FAR sem_t *sem);
|
||||
#define cs43l22_givesem(s) nxsem_post(s)
|
||||
|
||||
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
|
||||
static inline uint16_t cs43l22_scalevolume(uint16_t volume, b16_t scale);
|
||||
static void cs43l22_setvolume(FAR struct cs43l22_dev_s *priv, uint16_t volume,
|
||||
bool mute);
|
||||
static void cs43l22_setvolume(FAR struct cs43l22_dev_s *priv,
|
||||
uint16_t volume, bool mute);
|
||||
#endif
|
||||
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
|
||||
static void cs43l22_setbass(FAR struct cs43l22_dev_s *priv, uint8_t bass);
|
||||
static void cs43l22_settreble(FAR struct cs43l22_dev_s *priv, uint8_t treble);
|
||||
static void cs43l22_setbass(FAR struct cs43l22_dev_s *priv,
|
||||
uint8_t bass);
|
||||
static void cs43l22_settreble(FAR struct cs43l22_dev_s *priv,
|
||||
uint8_t treble);
|
||||
#endif
|
||||
|
||||
static void cs43l22_setdatawidth(FAR struct cs43l22_dev_s *priv);
|
||||
|
@ -112,21 +115,25 @@ static void cs43l22_returnbuffers(FAR struct cs43l22_dev_s *priv);
|
|||
static int cs43l22_sendbuffer(FAR struct cs43l22_dev_s *priv);
|
||||
|
||||
#ifdef CONFIG_AUDIO_MULTI_SESSION
|
||||
static int cs43l22_start(FAR struct audio_lowerhalf_s *dev, FAR void *session);
|
||||
static int cs43l22_start(FAR struct audio_lowerhalf_s *dev,
|
||||
FAR void *session);
|
||||
#else
|
||||
static int cs43l22_start(FAR struct audio_lowerhalf_s *dev);
|
||||
#endif
|
||||
#ifndef CONFIG_AUDIO_EXCLUDE_STOP
|
||||
#ifdef CONFIG_AUDIO_MULTI_SESSION
|
||||
static int cs43l22_stop(FAR struct audio_lowerhalf_s *dev, FAR void *session);
|
||||
static int cs43l22_stop(FAR struct audio_lowerhalf_s *dev,
|
||||
FAR void *session);
|
||||
#else
|
||||
static int cs43l22_stop(FAR struct audio_lowerhalf_s *dev);
|
||||
#endif
|
||||
#endif
|
||||
#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
|
||||
#ifdef CONFIG_AUDIO_MULTI_SESSION
|
||||
static int cs43l22_pause(FAR struct audio_lowerhalf_s *dev, FAR void *session);
|
||||
static int cs43l22_resume(FAR struct audio_lowerhalf_s *dev, FAR void *session);
|
||||
static int cs43l22_pause(FAR struct audio_lowerhalf_s *dev,
|
||||
FAR void *session);
|
||||
static int cs43l22_resume(FAR struct audio_lowerhalf_s *dev,
|
||||
FAR void *session);
|
||||
#else
|
||||
static int cs43l22_pause(FAR struct audio_lowerhalf_s *dev);
|
||||
static int cs43l22_resume(FAR struct audio_lowerhalf_s *dev);
|
||||
|
@ -269,7 +276,6 @@ uint8_t cs43l22_readreg(FAR struct cs43l22_dev_s *priv, uint8_t regaddr)
|
|||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* The I2C transfer was successful... break out of the loop and
|
||||
* return the value read.
|
||||
*/
|
||||
|
@ -286,13 +292,13 @@ uint8_t cs43l22_readreg(FAR struct cs43l22_dev_s *priv, uint8_t regaddr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: cs43l22_writereg
|
||||
*
|
||||
* Description:
|
||||
* Write the specified 16-bit register to the CS43L22 device.
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
static void
|
||||
cs43l22_writereg(FAR struct cs43l22_dev_s *priv, uint8_t regaddr,
|
||||
|
@ -355,28 +361,65 @@ cs43l22_writereg(FAR struct cs43l22_dev_s *priv, uint8_t regaddr,
|
|||
}
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: cs43l22_takesem
|
||||
*
|
||||
* Description:
|
||||
* Take a semaphore count, handling the nasty EINTR return if we are interrupted
|
||||
* by a signal.
|
||||
* Take a semaphore count, handling the nasty EINTR return if we are
|
||||
* interrupted by a signal.
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
static void cs43l22_takesem(sem_t * sem)
|
||||
static int cs43l22_takesem(FAR sem_t *sem)
|
||||
{
|
||||
nxsem_wait_uninterruptible(sem);
|
||||
return nxsem_wait_uninterruptible(sem);
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: cs43l22_forcetake
|
||||
*
|
||||
* Description:
|
||||
* This is just another wrapper but this one continues even if the thread
|
||||
* is canceled. This must be done in certain conditions where were must
|
||||
* continue in order to clean-up resources.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int cs43l22_forcetake(FAR sem_t *sem)
|
||||
{
|
||||
int result;
|
||||
int ret = OK;
|
||||
|
||||
do
|
||||
{
|
||||
result = nxsem_wait_uninterruptible(sem);
|
||||
|
||||
/* The only expected error would -ECANCELED meaning that the
|
||||
* parent thread has been canceled. We have to continue and
|
||||
* terminate the poll in this case.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(result == OK || result == -ECANCELED);
|
||||
if (ret == OK && result < 0)
|
||||
{
|
||||
/* Remember the first failure */
|
||||
|
||||
ret = result;
|
||||
}
|
||||
}
|
||||
while (result < 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: cs43l22_scalevolume
|
||||
*
|
||||
* Description:
|
||||
* Set the right and left volume values in the CS43L22 device based on the current
|
||||
* volume and balance settings.
|
||||
* Set the right and left volume values in the CS43L22 device based on the
|
||||
* current volume and balance settings.
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
|
||||
static inline uint16_t cs43l22_scalevolume(uint16_t volume, b16_t scale)
|
||||
|
@ -385,14 +428,14 @@ static inline uint16_t cs43l22_scalevolume(uint16_t volume, b16_t scale)
|
|||
}
|
||||
#endif
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: cs43l22_setvolume
|
||||
*
|
||||
* Description:
|
||||
* Set the right and left volume values in the CS43L22 device based on the current
|
||||
* volume and balance settings.
|
||||
* Set the right and left volume values in the CS43L22 device based on the
|
||||
* current volume and balance settings.
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
|
||||
static void
|
||||
|
@ -420,7 +463,7 @@ cs43l22_setvolume(FAR struct cs43l22_dev_s *priv, uint16_t volume, bool mute)
|
|||
leftlevel = ((((1000 - priv->balance) * 100) / 500) * volume) / 100;
|
||||
}
|
||||
|
||||
/* Calculate the right channel volume level {0..1000} */
|
||||
/* Calculate the right channel volume level {0..1000} */
|
||||
|
||||
if (priv->balance >= 500)
|
||||
{
|
||||
|
@ -442,10 +485,10 @@ cs43l22_setvolume(FAR struct cs43l22_dev_s *priv, uint16_t volume, bool mute)
|
|||
|
||||
/* Set the volume */
|
||||
|
||||
regval = (rightlevel + 0x19) & 0xff;
|
||||
cs43l22_writereg(priv, CS43L22_MS_VOL_CTRL_A, regval);
|
||||
regval = ((leftlevel + 0x19) & 0xff);
|
||||
cs43l22_writereg(priv, CS43L22_MS_VOL_CTRL_B, regval);
|
||||
regval = (rightlevel + 0x19) & 0xff;
|
||||
cs43l22_writereg(priv, CS43L22_MS_VOL_CTRL_A, regval);
|
||||
regval = ((leftlevel + 0x19) & 0xff);
|
||||
cs43l22_writereg(priv, CS43L22_MS_VOL_CTRL_B, regval);
|
||||
|
||||
#if 0
|
||||
regval = (rightlevel + 0x01) & 0xff;
|
||||
|
@ -474,7 +517,7 @@ cs43l22_setvolume(FAR struct cs43l22_dev_s *priv, uint16_t volume, bool mute)
|
|||
}
|
||||
#endif /* CONFIG_AUDIO_EXCLUDE_VOLUME */
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: cs43l22_setbass
|
||||
*
|
||||
* Description:
|
||||
|
@ -482,7 +525,7 @@ cs43l22_setvolume(FAR struct cs43l22_dev_s *priv, uint16_t volume, bool mute)
|
|||
*
|
||||
* The level and range are in whole percentage levels (0-100).
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
|
||||
static void cs43l22_setbass(FAR struct cs43l22_dev_s *priv, uint8_t bass)
|
||||
|
@ -492,7 +535,7 @@ static void cs43l22_setbass(FAR struct cs43l22_dev_s *priv, uint8_t bass)
|
|||
}
|
||||
#endif /* CONFIG_AUDIO_EXCLUDE_TONE */
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: cs43l22_settreble
|
||||
*
|
||||
* Description:
|
||||
|
@ -500,7 +543,7 @@ static void cs43l22_setbass(FAR struct cs43l22_dev_s *priv, uint8_t bass)
|
|||
*
|
||||
* The level and range are in whole percentage levels (0-100).
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
|
||||
static void cs43l22_settreble(FAR struct cs43l22_dev_s *priv, uint8_t treble)
|
||||
|
@ -523,11 +566,13 @@ static void cs43l22_setdatawidth(FAR struct cs43l22_dev_s *priv)
|
|||
if (priv->bpsamp == 16)
|
||||
{
|
||||
/* Reset default default setting */
|
||||
|
||||
priv->i2s->ops->i2s_txdatawidth(priv->i2s, 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This should select 8-bit with no companding */
|
||||
|
||||
priv->i2s->ops->i2s_txdatawidth(priv->i2s, 8);
|
||||
}
|
||||
}
|
||||
|
@ -583,17 +628,20 @@ static int cs43l22_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
|
|||
switch (caps->ac_subtype)
|
||||
{
|
||||
case AUDIO_TYPE_QUERY:
|
||||
|
||||
/* We don't decode any formats! Only something above us in
|
||||
* the audio stream can perform decoding on our behalf.
|
||||
*/
|
||||
|
||||
/* The types of audio units we implement */
|
||||
|
||||
caps->ac_controls.b[0] = AUDIO_TYPE_OUTPUT | AUDIO_TYPE_FEATURE |
|
||||
AUDIO_TYPE_PROCESSING;
|
||||
caps->ac_controls.b[0] =
|
||||
AUDIO_TYPE_OUTPUT | AUDIO_TYPE_FEATURE |
|
||||
AUDIO_TYPE_PROCESSING;
|
||||
break;
|
||||
|
||||
case AUDIO_FMT_MIDI:
|
||||
|
||||
/* We only support Format 0 */
|
||||
|
||||
caps->ac_controls.b[0] = AUDIO_SUBFMT_END;
|
||||
|
@ -618,10 +666,11 @@ static int cs43l22_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
|
|||
|
||||
/* Report the Sample rates we support */
|
||||
|
||||
caps->ac_controls.b[0] = AUDIO_SAMP_RATE_8K | AUDIO_SAMP_RATE_11K |
|
||||
AUDIO_SAMP_RATE_16K | AUDIO_SAMP_RATE_22K |
|
||||
AUDIO_SAMP_RATE_32K | AUDIO_SAMP_RATE_44K |
|
||||
AUDIO_SAMP_RATE_48K;
|
||||
caps->ac_controls.b[0] =
|
||||
AUDIO_SAMP_RATE_8K | AUDIO_SAMP_RATE_11K |
|
||||
AUDIO_SAMP_RATE_16K | AUDIO_SAMP_RATE_22K |
|
||||
AUDIO_SAMP_RATE_32K | AUDIO_SAMP_RATE_44K |
|
||||
AUDIO_SAMP_RATE_48K;
|
||||
break;
|
||||
|
||||
case AUDIO_FMT_MP3:
|
||||
|
@ -639,19 +688,24 @@ static int cs43l22_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
|
|||
|
||||
case AUDIO_TYPE_FEATURE:
|
||||
|
||||
/* If the sub-type is UNDEF, then report the Feature Units we support */
|
||||
/* If the sub-type is UNDEF, then report the Feature Units we
|
||||
* support.
|
||||
*/
|
||||
|
||||
if (caps->ac_subtype == AUDIO_FU_UNDEF)
|
||||
{
|
||||
/* Fill in the ac_controls section with the Feature Units we have */
|
||||
/* Fill in the ac_controls section with the Feature Units we
|
||||
* have.
|
||||
*/
|
||||
|
||||
caps->ac_controls.b[0] = AUDIO_FU_VOLUME | AUDIO_FU_BASS | AUDIO_FU_TREBLE;
|
||||
caps->ac_controls.b[0] = AUDIO_FU_VOLUME | AUDIO_FU_BASS |
|
||||
AUDIO_FU_TREBLE;
|
||||
caps->ac_controls.b[1] = AUDIO_FU_BALANCE >> 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO: Do we need to provide specific info for the Feature Units,
|
||||
* such as volume setting ranges, etc.?
|
||||
/* TODO: Do we need to provide specific info for the Feature
|
||||
* Units, such as volume setting ranges, etc.?
|
||||
*/
|
||||
}
|
||||
|
||||
|
@ -664,18 +718,22 @@ static int cs43l22_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
|
|||
switch (caps->ac_subtype)
|
||||
{
|
||||
case AUDIO_PU_UNDEF:
|
||||
|
||||
/* Provide the type of Processing Units we support */
|
||||
|
||||
caps->ac_controls.b[0] = AUDIO_PU_STEREO_EXTENDER;
|
||||
break;
|
||||
|
||||
case AUDIO_PU_STEREO_EXTENDER:
|
||||
|
||||
/* Provide capabilities of our Stereo Extender */
|
||||
|
||||
caps->ac_controls.b[0] = AUDIO_STEXT_ENABLE | AUDIO_STEXT_WIDTH;
|
||||
caps->ac_controls.b[0] =
|
||||
AUDIO_STEXT_ENABLE | AUDIO_STEXT_WIDTH;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
/* Other types of processing uint we don't support */
|
||||
|
||||
break;
|
||||
|
@ -748,7 +806,8 @@ cs43l22_configure(FAR struct audio_lowerhalf_s *dev,
|
|||
{
|
||||
/* Scale the volume setting to the range {76..255} */
|
||||
|
||||
cs43l22_setvolume(priv, (179 * volume / 1000) + 76, priv->mute);
|
||||
cs43l22_setvolume(priv, (179 * volume / 1000) + 76,
|
||||
priv->mute);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -945,6 +1004,7 @@ cs43l22_senddone(FAR struct i2s_dev_s *i2s,
|
|||
priv->inflight--;
|
||||
|
||||
/* Save the result of the transfer */
|
||||
|
||||
/* REVISIT: This can be overwritten */
|
||||
|
||||
priv->result = result;
|
||||
|
@ -1047,7 +1107,7 @@ static int cs43l22_sendbuffer(FAR struct cs43l22_dev_s *priv)
|
|||
irqstate_t flags;
|
||||
uint32_t timeout;
|
||||
int shift;
|
||||
int ret = OK;
|
||||
int ret;
|
||||
|
||||
/* Loop while there are audio buffers to be sent and we have few than
|
||||
* CONFIG_CS43L22_INFLIGHT then "in-flight"
|
||||
|
@ -1061,7 +1121,12 @@ static int cs43l22_sendbuffer(FAR struct cs43l22_dev_s *priv)
|
|||
* only while accessing 'inflight'.
|
||||
*/
|
||||
|
||||
cs43l22_takesem(&priv->pendsem);
|
||||
ret = cs43l22_takesem(&priv->pendsem);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (priv->inflight < CONFIG_CS43L22_INFLIGHT &&
|
||||
dq_peek(&priv->pendq) != NULL && !priv->paused)
|
||||
{
|
||||
|
@ -1128,7 +1193,8 @@ static int cs43l22_sendbuffer(FAR struct cs43l22_dev_s *priv)
|
|||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_AUDIO_MULTI_SESSION
|
||||
static int cs43l22_start(FAR struct audio_lowerhalf_s *dev, FAR void *session)
|
||||
static int cs43l22_start(FAR struct audio_lowerhalf_s *dev,
|
||||
FAR void *session)
|
||||
#else
|
||||
static int cs43l22_start(FAR struct audio_lowerhalf_s *dev)
|
||||
#endif
|
||||
|
@ -1143,6 +1209,7 @@ static int cs43l22_start(FAR struct audio_lowerhalf_s *dev)
|
|||
audinfo("Entry\n");
|
||||
|
||||
/* Exit reduced power modes of operation */
|
||||
|
||||
/* REVISIT */
|
||||
|
||||
/* Create a message queue for the worker thread */
|
||||
|
@ -1226,6 +1293,7 @@ static int cs43l22_stop(FAR struct audio_lowerhalf_s *dev)
|
|||
priv->threadid = 0;
|
||||
|
||||
/* Enter into a reduced power usage mode */
|
||||
|
||||
/* REVISIT: */
|
||||
|
||||
return OK;
|
||||
|
@ -1242,7 +1310,8 @@ static int cs43l22_stop(FAR struct audio_lowerhalf_s *dev)
|
|||
|
||||
#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
|
||||
# ifdef CONFIG_AUDIO_MULTI_SESSION
|
||||
static int cs43l22_pause(FAR struct audio_lowerhalf_s *dev, FAR void *session)
|
||||
static int cs43l22_pause(FAR struct audio_lowerhalf_s *dev,
|
||||
FAR void *session)
|
||||
# else
|
||||
static int cs43l22_pause(FAR struct audio_lowerhalf_s *dev)
|
||||
# endif
|
||||
|
@ -1272,7 +1341,8 @@ static int cs43l22_pause(FAR struct audio_lowerhalf_s *dev)
|
|||
|
||||
#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
|
||||
# ifdef CONFIG_AUDIO_MULTI_SESSION
|
||||
static int cs43l22_resume(FAR struct audio_lowerhalf_s *dev, FAR void *session)
|
||||
static int cs43l22_resume(FAR struct audio_lowerhalf_s *dev,
|
||||
FAR void *session)
|
||||
# else
|
||||
static int cs43l22_resume(FAR struct audio_lowerhalf_s *dev)
|
||||
# endif
|
||||
|
@ -1314,20 +1384,26 @@ static int cs43l22_enqueuebuffer(FAR struct audio_lowerhalf_s *dev,
|
|||
audinfo("Enqueueing: apb=%p curbyte=%d nbytes=%d flags=%04x\n",
|
||||
apb, apb->curbyte, apb->nbytes, apb->flags);
|
||||
|
||||
ret = cs43l22_takesem(&priv->pendsem);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Take a reference on the new audio buffer */
|
||||
|
||||
apb_reference(apb);
|
||||
|
||||
/* Add the new buffer to the tail of pending audio buffers */
|
||||
|
||||
cs43l22_takesem(&priv->pendsem);
|
||||
apb->flags |= AUDIO_APB_OUTPUT_ENQUEUED;
|
||||
dq_addlast(&apb->dq_entry, &priv->pendq);
|
||||
cs43l22_givesem(&priv->pendsem);
|
||||
|
||||
/* Send a message to the worker thread indicating that a new buffer has been
|
||||
* enqueued. If mq is NULL, then the playing has not yet started. In that
|
||||
* case we are just "priming the pump" and we don't need to send any message.
|
||||
/* Send a message to the worker thread indicating that a new buffer has
|
||||
* been enqueued. If mq is NULL, then the playing has not yet started.
|
||||
* In that case we are just "priming the pump" and we don't need to send
|
||||
* any message.
|
||||
*/
|
||||
|
||||
ret = OK;
|
||||
|
@ -1437,7 +1513,12 @@ static int cs43l22_reserve(FAR struct audio_lowerhalf_s *dev)
|
|||
|
||||
/* Borrow the APBQ semaphore for thread sync */
|
||||
|
||||
cs43l22_takesem(&priv->pendsem);
|
||||
ret = cs43l22_takesem(&priv->pendsem);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (priv->reserved)
|
||||
{
|
||||
ret = -EBUSY;
|
||||
|
@ -1472,13 +1553,15 @@ static int cs43l22_reserve(FAR struct audio_lowerhalf_s *dev)
|
|||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_AUDIO_MULTI_SESSION
|
||||
static int cs43l22_release(FAR struct audio_lowerhalf_s *dev, FAR void *session)
|
||||
static int cs43l22_release(FAR struct audio_lowerhalf_s *dev,
|
||||
FAR void *session)
|
||||
#else
|
||||
static int cs43l22_release(FAR struct audio_lowerhalf_s *dev)
|
||||
#endif
|
||||
{
|
||||
FAR struct cs43l22_dev_s *priv = (FAR struct cs43l22_dev_s *)dev;
|
||||
void *value;
|
||||
FAR void *value;
|
||||
int ret;
|
||||
|
||||
/* Join any old worker thread we had created to prevent a memory leak */
|
||||
|
||||
|
@ -1490,14 +1573,14 @@ static int cs43l22_release(FAR struct audio_lowerhalf_s *dev)
|
|||
|
||||
/* Borrow the APBQ semaphore for thread sync */
|
||||
|
||||
cs43l22_takesem(&priv->pendsem);
|
||||
ret = cs43l22_forcetake(&priv->pendsem);
|
||||
|
||||
/* Really we should free any queued buffers here */
|
||||
|
||||
priv->reserved = false;
|
||||
cs43l22_givesem(&priv->pendsem);
|
||||
|
||||
return OK;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -1623,6 +1706,7 @@ static void *cs43l22_workerthread(pthread_addr_t pvarg)
|
|||
|
||||
#ifndef CONFIG_AUDIO_EXCLUDE_STOP
|
||||
case AUDIO_MSG_STOP:
|
||||
|
||||
/* Indicate that we are terminating */
|
||||
|
||||
audinfo("AUDIO_MSG_STOP: Terminating\n");
|
||||
|
@ -1657,7 +1741,7 @@ static void *cs43l22_workerthread(pthread_addr_t pvarg)
|
|||
|
||||
/* Return any pending buffers in our pending queue */
|
||||
|
||||
cs43l22_takesem(&priv->pendsem);
|
||||
cs43l22_forcetake(&priv->pendsem);
|
||||
while ((apb = (FAR struct ap_buffer_s *)dq_remfirst(&priv->pendq)) != NULL)
|
||||
{
|
||||
/* Release our reference to the buffer */
|
||||
|
@ -1722,7 +1806,8 @@ static void cs43l22_audio_output(FAR struct cs43l22_dev_s *priv)
|
|||
|
||||
/* SPK always off and HP always on */
|
||||
|
||||
regval = CS43L22_PDN_HPB_ON | CS43L22_PDN_HPA_ON | CS43L22_PDN_SPKB_OFF | CS43L22_PDN_SPKA_OFF;
|
||||
regval = CS43L22_PDN_HPB_ON | CS43L22_PDN_HPA_ON | CS43L22_PDN_SPKB_OFF |
|
||||
CS43L22_PDN_SPKA_OFF;
|
||||
cs43l22_writereg(priv, CS43L22_POWER_CTRL2, regval);
|
||||
|
||||
/* Clock configuration: Auto detection */
|
||||
|
@ -1841,7 +1926,7 @@ static void cs43l22_reset(FAR struct cs43l22_dev_s *priv)
|
|||
priv->nchannels = CS43L22_DEFAULT_NCHANNELS;
|
||||
priv->bpsamp = CS43L22_DEFAULT_BPSAMP;
|
||||
#if !defined(CONFIG_AUDIO_EXCLUDE_VOLUME) && !defined(CONFIG_AUDIO_EXCLUDE_BALANCE)
|
||||
priv->balance = 500; // b16HALF; /* Center balance */
|
||||
priv->balance = 500; /* b16HALF = Center balance */
|
||||
#endif
|
||||
|
||||
/* Software reset. This puts all CS43L22 registers back in their
|
||||
|
@ -1889,10 +1974,9 @@ static void cs43l22_reset(FAR struct cs43l22_dev_s *priv)
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct audio_lowerhalf_s *cs43l22_initialize(FAR struct i2c_master_s *i2c,
|
||||
FAR struct i2s_dev_s *i2s,
|
||||
FAR const struct
|
||||
cs43l22_lower_s *lower)
|
||||
FAR struct audio_lowerhalf_s *
|
||||
cs43l22_initialize(FAR struct i2c_master_s *i2c, FAR struct i2s_dev_s *i2s,
|
||||
FAR const struct cs43l22_lower_s *lower)
|
||||
{
|
||||
FAR struct cs43l22_dev_s *priv;
|
||||
uint16_t regval;
|
||||
|
@ -1903,7 +1987,8 @@ FAR struct audio_lowerhalf_s *cs43l22_initialize(FAR struct i2c_master_s *i2c,
|
|||
|
||||
/* Allocate a CS43L22 device structure */
|
||||
|
||||
priv = (FAR struct cs43l22_dev_s *)kmm_zalloc(sizeof(struct cs43l22_dev_s));
|
||||
priv = (FAR struct cs43l22_dev_s *)
|
||||
kmm_zalloc(sizeof(struct cs43l22_dev_s));
|
||||
if (priv)
|
||||
{
|
||||
/* Initialize the CS43L22 device structure. Since we used kmm_zalloc,
|
||||
|
@ -1921,10 +2006,12 @@ FAR struct audio_lowerhalf_s *cs43l22_initialize(FAR struct i2c_master_s *i2c,
|
|||
|
||||
/* Initialize I2C */
|
||||
|
||||
audinfo("address=%02x frequency=%d\n", lower->address, lower->frequency);
|
||||
audinfo("address=%02x frequency=%d\n",
|
||||
lower->address, lower->frequency);
|
||||
|
||||
/* Software reset. This puts all CS43L22 registers back in their default
|
||||
* state. */
|
||||
/* Software reset. This puts all CS43L22 registers back in their
|
||||
* default state.
|
||||
*/
|
||||
|
||||
CS43L22_HW_RESET(priv->lower);
|
||||
|
||||
|
|
|
@ -74,7 +74,8 @@
|
|||
static void wm8776_writereg(FAR struct wm8776_dev_s *priv,
|
||||
uint8_t regaddr, uint16_t regval);
|
||||
|
||||
static void wm8776_takesem(sem_t *sem);
|
||||
static int wm8776_takesem(FAR sem_t *sem);
|
||||
static int wm8776_forcetake(FAR sem_t *sem);
|
||||
#define wm8776_givesem(s) nxsem_post(s)
|
||||
|
||||
static int wm8776_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
|
||||
|
@ -174,13 +175,13 @@ static const struct audio_ops_s g_audioops =
|
|||
wm8776_release /* release */
|
||||
};
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: wm8776_writereg
|
||||
*
|
||||
* Description:
|
||||
* Write the specified 16-bit register to the WM8776 device.
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
static void wm8776_writereg(FAR struct wm8776_dev_s *priv,
|
||||
uint8_t regaddr,
|
||||
|
@ -208,28 +209,65 @@ static void wm8776_writereg(FAR struct wm8776_dev_s *priv,
|
|||
}
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: wm8776_takesem
|
||||
*
|
||||
* Description:
|
||||
* Take a semaphore count, handling the nasty EINTR return if we are interrupted
|
||||
* by a signal.
|
||||
* Take a semaphore count, handling the nasty EINTR return if we are
|
||||
* interrupted by a signal.
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
static void wm8776_takesem(sem_t *sem)
|
||||
static int wm8776_takesem(sem_t *sem)
|
||||
{
|
||||
nxsem_wait_uninterruptible(sem);
|
||||
return nxsem_wait_uninterruptible(sem);
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: wm8776_forcetake
|
||||
*
|
||||
* Description:
|
||||
* This is just another wrapper but this one continues even if the thread
|
||||
* is canceled. This must be done in certain conditions where were must
|
||||
* continue in order to clean-up resources.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int wm8776_forcetake(FAR sem_t *sem)
|
||||
{
|
||||
int result;
|
||||
int ret = OK;
|
||||
|
||||
do
|
||||
{
|
||||
result = nxsem_wait_uninterruptible(sem);
|
||||
|
||||
/* The only expected error would -ECANCELED meaning that the
|
||||
* parent thread has been canceled. We have to continue and
|
||||
* terminate the poll in this case.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(result == OK || result == -ECANCELED);
|
||||
if (ret == OK && result < 0)
|
||||
{
|
||||
/* Remember the first failure */
|
||||
|
||||
ret = result;
|
||||
}
|
||||
}
|
||||
while (result < 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: wm8776_setvolume
|
||||
*
|
||||
* Description:
|
||||
* Set the right and left volume values in the WM8776 device based on the current
|
||||
* volume and balance settings.
|
||||
* Set the right and left volume values in the WM8776 device based on the
|
||||
* current volume and balance settings.
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
|
||||
static void wm8776_setvolume(FAR struct wm8776_dev_s *priv, uint16_t volume,
|
||||
|
@ -312,8 +350,9 @@ static int wm8776_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
|
|||
|
||||
/* The types of audio units we implement */
|
||||
|
||||
caps->ac_controls.b[0] = AUDIO_TYPE_OUTPUT | AUDIO_TYPE_FEATURE |
|
||||
AUDIO_TYPE_PROCESSING;
|
||||
caps->ac_controls.b[0] =
|
||||
AUDIO_TYPE_OUTPUT | AUDIO_TYPE_FEATURE |
|
||||
AUDIO_TYPE_PROCESSING;
|
||||
|
||||
break;
|
||||
|
||||
|
@ -413,13 +452,14 @@ static int wm8776_configure(FAR struct audio_lowerhalf_s *dev,
|
|||
{
|
||||
/* Scale the volume setting to the range {0x2f .. 0x79} */
|
||||
|
||||
wm8776_setvolume(priv, (0x4a * volume / 1000) + 0x2f, priv->mute);
|
||||
wm8776_setvolume(priv, (0x4a * volume / 1000) + 0x2f,
|
||||
priv->mute);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -EDOM;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_AUDIO_EXCLUDE_VOLUME */
|
||||
|
||||
|
@ -537,6 +577,7 @@ static void wm8776_senddone(FAR struct i2s_dev_s *i2s,
|
|||
priv->inflight--;
|
||||
|
||||
/* Save the result of the transfer */
|
||||
|
||||
/* REVISIT: This can be overwritten */
|
||||
|
||||
priv->result = result;
|
||||
|
@ -639,7 +680,7 @@ static int wm8776_sendbuffer(FAR struct wm8776_dev_s *priv)
|
|||
irqstate_t flags;
|
||||
uint32_t timeout;
|
||||
int shift;
|
||||
int ret = OK;
|
||||
int ret;
|
||||
|
||||
/* Loop while there are audio buffers to be sent and we have few than
|
||||
* CONFIG_WM8776_INFLIGHT then "in-flight"
|
||||
|
@ -653,7 +694,12 @@ static int wm8776_sendbuffer(FAR struct wm8776_dev_s *priv)
|
|||
* only while accessing 'inflight'.
|
||||
*/
|
||||
|
||||
wm8776_takesem(&priv->pendsem);
|
||||
ret = wm8776_takesem(&priv->pendsem);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (priv->inflight < CONFIG_WM8776_INFLIGHT &&
|
||||
dq_peek(&priv->pendq) != NULL && !priv->paused)
|
||||
{
|
||||
|
@ -713,6 +759,7 @@ static int wm8776_start(FAR struct audio_lowerhalf_s *dev)
|
|||
audinfo("Entry\n");
|
||||
|
||||
/* Exit reduced power modes of operation */
|
||||
|
||||
/* REVISIT */
|
||||
|
||||
/* Create a message queue for the worker thread */
|
||||
|
@ -796,6 +843,7 @@ static int wm8776_stop(FAR struct audio_lowerhalf_s *dev)
|
|||
priv->threadid = 0;
|
||||
|
||||
/* Enter into a reduced power usage mode */
|
||||
|
||||
/* REVISIT: */
|
||||
|
||||
return OK;
|
||||
|
@ -837,7 +885,8 @@ static int wm8776_pause(FAR struct audio_lowerhalf_s *dev)
|
|||
|
||||
#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
|
||||
#ifdef CONFIG_AUDIO_MULTI_SESSION
|
||||
static int wm8776_resume(FAR struct audio_lowerhalf_s *dev, FAR void *session)
|
||||
static int wm8776_resume(FAR struct audio_lowerhalf_s *dev,
|
||||
FAR void *session)
|
||||
#else
|
||||
static int wm8776_resume(FAR struct audio_lowerhalf_s *dev)
|
||||
#endif
|
||||
|
@ -878,14 +927,20 @@ static int wm8776_enqueuebuffer(FAR struct audio_lowerhalf_s *dev,
|
|||
|
||||
/* Add the new buffer to the tail of pending audio buffers */
|
||||
|
||||
wm8776_takesem(&priv->pendsem);
|
||||
ret = wm8776_takesem(&priv->pendsem);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
apb->flags |= AUDIO_APB_OUTPUT_ENQUEUED;
|
||||
dq_addlast(&apb->dq_entry, &priv->pendq);
|
||||
wm8776_givesem(&priv->pendsem);
|
||||
|
||||
/* Send a message to the worker thread indicating that a new buffer has been
|
||||
* enqueued. If mq is NULL, then the playing has not yet started. In that
|
||||
* case we are just "priming the pump" and we don't need to send any message.
|
||||
/* Send a message to the worker thread indicating that a new buffer has
|
||||
* been enqueued. If mq is NULL, then the playing has not yet started.
|
||||
* In that case we are just "priming the pump" and we don't need to send
|
||||
* any message.
|
||||
*/
|
||||
|
||||
ret = OK;
|
||||
|
@ -996,7 +1051,12 @@ static int wm8776_reserve(FAR struct audio_lowerhalf_s *dev)
|
|||
|
||||
/* Borrow the APBQ semaphore for thread sync */
|
||||
|
||||
wm8776_takesem(&priv->pendsem);
|
||||
ret = wm8776_takesem(&priv->pendsem);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (priv->reserved)
|
||||
{
|
||||
ret = -EBUSY;
|
||||
|
@ -1037,7 +1097,8 @@ static int wm8776_release(FAR struct audio_lowerhalf_s *dev)
|
|||
#endif
|
||||
{
|
||||
FAR struct wm8776_dev_s *priv = (FAR struct wm8776_dev_s *)dev;
|
||||
void *value;
|
||||
FAR void *value;
|
||||
int ret;
|
||||
|
||||
/* Join any old worker thread we had created to prevent a memory leak */
|
||||
|
||||
|
@ -1049,14 +1110,14 @@ static int wm8776_release(FAR struct audio_lowerhalf_s *dev)
|
|||
|
||||
/* Borrow the APBQ semaphore for thread sync */
|
||||
|
||||
wm8776_takesem(&priv->pendsem);
|
||||
ret = wm8776_forcetake(&priv->pendsem);
|
||||
|
||||
/* Really we should free any queued buffers here */
|
||||
|
||||
priv->reserved = false;
|
||||
wm8776_givesem(&priv->pendsem);
|
||||
|
||||
return OK;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -1075,11 +1136,12 @@ static int wm8776_release(FAR struct audio_lowerhalf_s *dev)
|
|||
|
||||
static void wm8776_audio_output(FAR struct wm8776_dev_s *priv)
|
||||
{
|
||||
wm8776_writereg(priv, WM8776_MASTER_ATT, WM8776_UPDATE | 0x58); /* -33db */
|
||||
wm8776_writereg(priv, WM8776_DAC_IF, 0x32); /* 32bit, I2S, standard pol */
|
||||
wm8776_writereg(priv, WM8776_MASTER_ATT,
|
||||
WM8776_UPDATE | 0x58); /* -33db */
|
||||
wm8776_writereg(priv, WM8776_DAC_IF, 0x32); /* 32bit, I2S, standard pol */
|
||||
|
||||
#ifdef CONFIG_WM8776_SWAP_HPOUT
|
||||
wm8776_writereg(priv, WM8776_DAC_CC, 0x62); /* Swap HPOUT L/R */
|
||||
wm8776_writereg(priv, WM8776_DAC_CC, 0x62); /* Swap HPOUT L/R */
|
||||
#endif
|
||||
|
||||
wm8776_writereg(priv, WM8776_MASTER_MODE, 0x00); /* slave mode, 128fs */
|
||||
|
@ -1120,7 +1182,6 @@ static void wm8776_hw_reset(FAR struct wm8776_dev_s *priv)
|
|||
/* Configure the WM8776 hardware as an audio input device */
|
||||
|
||||
wm8776_audio_output(priv);
|
||||
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -1203,6 +1264,7 @@ repeat:
|
|||
|
||||
#ifndef CONFIG_AUDIO_EXCLUDE_STOP
|
||||
case AUDIO_MSG_STOP:
|
||||
|
||||
/* Indicate that we are terminating */
|
||||
|
||||
audinfo("AUDIO_MSG_STOP: Terminating\n");
|
||||
|
@ -1238,7 +1300,6 @@ repeat:
|
|||
{
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Reset the WM8776 hardware */
|
||||
|
@ -1247,7 +1308,7 @@ repeat:
|
|||
|
||||
/* Return any pending buffers in our pending queue */
|
||||
|
||||
wm8776_takesem(&priv->pendsem);
|
||||
wm8776_forcetake(&priv->pendsem);
|
||||
while ((apb = (FAR struct ap_buffer_s *)dq_remfirst(&priv->pendq)) != NULL)
|
||||
{
|
||||
/* Release our reference to the buffer */
|
||||
|
@ -1287,7 +1348,6 @@ repeat:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
|
|
@ -94,7 +94,8 @@ static
|
|||
uint8_t regaddr);
|
||||
static void wm8904_writereg(FAR struct wm8904_dev_s *priv,
|
||||
uint8_t regaddr, uint16_t regval);
|
||||
static void wm8904_takesem(sem_t *sem);
|
||||
static int wm8904_takesem(FAR sem_t *sem);
|
||||
static int wm8904_forcetake(FAR sem_t *sem);
|
||||
#define wm8904_givesem(s) nxsem_post(s)
|
||||
|
||||
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
|
||||
|
@ -104,7 +105,8 @@ static void wm8904_setvolume(FAR struct wm8904_dev_s *priv,
|
|||
#endif
|
||||
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
|
||||
static void wm8904_setbass(FAR struct wm8904_dev_s *priv, uint8_t bass);
|
||||
static void wm8904_settreble(FAR struct wm8904_dev_s *priv, uint8_t treble);
|
||||
static void wm8904_settreble(FAR struct wm8904_dev_s *priv,
|
||||
uint8_t treble);
|
||||
#endif
|
||||
|
||||
static void wm8904_setdatawidth(FAR struct wm8904_dev_s *priv);
|
||||
|
@ -225,9 +227,9 @@ static const struct audio_ops_s g_audioops =
|
|||
#ifndef CONFIG_WM8904_CLKDEBUG
|
||||
static
|
||||
#endif
|
||||
const uint8_t g_sysclk_scaleb1[WM8904_BCLK_MAXDIV+1] =
|
||||
const uint8_t g_sysclk_scaleb1[WM8904_BCLK_MAXDIV + 1] =
|
||||
{
|
||||
2, 3, 4, 6, 8, 10, 11, /* 1, 1.5, 2, 3, 4, 5, 5.5 */
|
||||
2, 3, 4, 6, 8, 10, 11, /* 1, 1.5, 2, 3, 4, 5, 5.5 */
|
||||
12, 16, 20, 22, 24, 32, 40, /* 6, 8, 10, 11, 12, 16, 20 */
|
||||
44, 48, 50, 60, 64, 88, 96 /* 22, 24, 25, 30, 32, 44, 48 */
|
||||
};
|
||||
|
@ -297,7 +299,8 @@ uint16_t wm8904_readreg(FAR struct wm8904_dev_s *priv, uint8_t regaddr)
|
|||
|
||||
if (retries < MAX_RETRIES)
|
||||
{
|
||||
audwarn("WARNING: I2C_TRANSFER failed: %d ... Resetting\n", ret);
|
||||
audwarn("WARNING: I2C_TRANSFER failed: %d ... Resetting\n",
|
||||
ret);
|
||||
|
||||
ret = I2C_RESET(priv->i2c);
|
||||
if (ret < 0)
|
||||
|
@ -331,13 +334,13 @@ uint16_t wm8904_readreg(FAR struct wm8904_dev_s *priv, uint8_t regaddr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: wm8904_writereg
|
||||
*
|
||||
* Description:
|
||||
* Write the specified 16-bit register to the WM8904 device.
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
static void wm8904_writereg(FAR struct wm8904_dev_s *priv, uint8_t regaddr,
|
||||
uint16_t regval)
|
||||
|
@ -405,28 +408,65 @@ static void wm8904_writereg(FAR struct wm8904_dev_s *priv, uint8_t regaddr,
|
|||
}
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: wm8904_takesem
|
||||
*
|
||||
* Description:
|
||||
* Take a semaphore count, handling the nasty EINTR return if we are interrupted
|
||||
* by a signal.
|
||||
* Take a semaphore count, handling the nasty EINTR return if we are
|
||||
* interrupted by a signal.
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
static void wm8904_takesem(sem_t *sem)
|
||||
static int wm8904_takesem(sem_t *sem)
|
||||
{
|
||||
nxsem_wait_uninterruptible(sem);
|
||||
return nxsem_wait_uninterruptible(sem);
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: wm8904_forcetake
|
||||
*
|
||||
* Description:
|
||||
* This is just another wrapper but this one continues even if the thread
|
||||
* is canceled. This must be done in certain conditions where were must
|
||||
* continue in order to clean-up resources.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int wm8904_forcetake(FAR sem_t *sem)
|
||||
{
|
||||
int result;
|
||||
int ret = OK;
|
||||
|
||||
do
|
||||
{
|
||||
result = nxsem_wait_uninterruptible(sem);
|
||||
|
||||
/* The only expected error would -ECANCELED meaning that the
|
||||
* parent thread has been canceled. We have to continue and
|
||||
* terminate the poll in this case.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(result == OK || result == -ECANCELED);
|
||||
if (ret == OK && result < 0)
|
||||
{
|
||||
/* Remember the first failure */
|
||||
|
||||
ret = result;
|
||||
}
|
||||
}
|
||||
while (result < 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: wm8904_scalevolume
|
||||
*
|
||||
* Description:
|
||||
* Set the right and left volume values in the WM8904 device based on the current
|
||||
* volume and balance settings.
|
||||
* Set the right and left volume values in the WM8904 device based on the
|
||||
* current volume and balance settings.
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
|
||||
static inline uint16_t wm8904_scalevolume(uint16_t volume, b16_t scale)
|
||||
|
@ -435,14 +475,14 @@ static inline uint16_t wm8904_scalevolume(uint16_t volume, b16_t scale)
|
|||
}
|
||||
#endif
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: wm8904_setvolume
|
||||
*
|
||||
* Description:
|
||||
* Set the right and left volume values in the WM8904 device based on the current
|
||||
* volume and balance settings.
|
||||
* Set the right and left volume values in the WM8904 device based on the
|
||||
* current volume and balance settings.
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
|
||||
static void wm8904_setvolume(FAR struct wm8904_dev_s *priv, uint16_t volume,
|
||||
|
@ -514,7 +554,7 @@ static void wm8904_setvolume(FAR struct wm8904_dev_s *priv, uint16_t volume,
|
|||
}
|
||||
#endif /* CONFIG_AUDIO_EXCLUDE_VOLUME */
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: wm8904_setbass
|
||||
*
|
||||
* Description:
|
||||
|
@ -522,7 +562,7 @@ static void wm8904_setvolume(FAR struct wm8904_dev_s *priv, uint16_t volume,
|
|||
*
|
||||
* The level and range are in whole percentage levels (0-100).
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
|
||||
static void wm8904_setbass(FAR struct wm8904_dev_s *priv, uint8_t bass)
|
||||
|
@ -532,7 +572,7 @@ static void wm8904_setbass(FAR struct wm8904_dev_s *priv, uint8_t bass)
|
|||
}
|
||||
#endif /* CONFIG_AUDIO_EXCLUDE_TONE */
|
||||
|
||||
/************************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: wm8904_settreble
|
||||
*
|
||||
* Description:
|
||||
|
@ -540,7 +580,7 @@ static void wm8904_setbass(FAR struct wm8904_dev_s *priv, uint8_t bass)
|
|||
*
|
||||
* The level and range are in whole percentage levels (0-100).
|
||||
*
|
||||
************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
|
||||
static void wm8904_settreble(FAR struct wm8904_dev_s *priv, uint8_t treble)
|
||||
|
@ -710,12 +750,12 @@ static void wm8904_setbitrate(FAR struct wm8904_dev_s *priv)
|
|||
|
||||
/* MCLK must be divided down so that fref <=13.5MHz */
|
||||
|
||||
if (fref > 4*13500000)
|
||||
if (fref > 4 * 13500000)
|
||||
{
|
||||
fref >>= 3;
|
||||
regval = (WM8904_FLL_CLK_REF_SRC_MCLK | WM8904_FLL_CLK_REF_DIV8);
|
||||
}
|
||||
else if (fref > 2*13500000)
|
||||
else if (fref > 2 * 13500000)
|
||||
{
|
||||
fref >>= 2;
|
||||
regval = (WM8904_FLL_CLK_REF_SRC_MCLK | WM8904_FLL_CLK_REF_DIV4);
|
||||
|
@ -841,6 +881,7 @@ static void wm8904_setbitrate(FAR struct wm8904_dev_s *priv)
|
|||
priv->bitrate = fout;
|
||||
|
||||
/* Now, Configure the FLL */
|
||||
|
||||
/* FLL Control 1
|
||||
*
|
||||
* FLL_FRACN_ENA=1 : Enables fractional mode
|
||||
|
@ -918,7 +959,7 @@ static void wm8904_setbitrate(FAR struct wm8904_dev_s *priv)
|
|||
retries = 5;
|
||||
do
|
||||
{
|
||||
nxsig_usleep(5*5000);
|
||||
nxsig_usleep(5 * 5000);
|
||||
}
|
||||
while (priv->locked == false && --retries > 0);
|
||||
|
||||
|
@ -941,10 +982,11 @@ static void wm8904_setbitrate(FAR struct wm8904_dev_s *priv)
|
|||
retries = 5;
|
||||
do
|
||||
{
|
||||
nxsig_usleep(5*5000);
|
||||
nxsig_usleep(5 * 5000);
|
||||
}
|
||||
while ((wm8904_readreg(priv, WM8904_INT_STATUS) & WM8904_FLL_LOCK_INT) != 0 ||
|
||||
--retries > 0);
|
||||
while ((wm8904_readreg(priv, WM8904_INT_STATUS) &
|
||||
WM8904_FLL_LOCK_INT) != 0 ||
|
||||
--retries > 0);
|
||||
|
||||
/* Clear all pending status bits by writing 1's into the interrupt status
|
||||
* register.
|
||||
|
@ -996,18 +1038,21 @@ static int wm8904_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
|
|||
switch (caps->ac_subtype)
|
||||
{
|
||||
case AUDIO_TYPE_QUERY:
|
||||
|
||||
/* We don't decode any formats! Only something above us in
|
||||
* the audio stream can perform decoding on our behalf.
|
||||
*/
|
||||
|
||||
/* The types of audio units we implement */
|
||||
|
||||
caps->ac_controls.b[0] = AUDIO_TYPE_OUTPUT | AUDIO_TYPE_FEATURE |
|
||||
AUDIO_TYPE_PROCESSING;
|
||||
caps->ac_controls.b[0] =
|
||||
AUDIO_TYPE_OUTPUT | AUDIO_TYPE_FEATURE |
|
||||
AUDIO_TYPE_PROCESSING;
|
||||
|
||||
break;
|
||||
|
||||
case AUDIO_FMT_MIDI:
|
||||
|
||||
/* We only support Format 0 */
|
||||
|
||||
caps->ac_controls.b[0] = AUDIO_SUBFMT_END;
|
||||
|
@ -1032,10 +1077,11 @@ static int wm8904_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
|
|||
|
||||
/* Report the Sample rates we support */
|
||||
|
||||
caps->ac_controls.b[0] = AUDIO_SAMP_RATE_8K | AUDIO_SAMP_RATE_11K |
|
||||
AUDIO_SAMP_RATE_16K | AUDIO_SAMP_RATE_22K |
|
||||
AUDIO_SAMP_RATE_32K | AUDIO_SAMP_RATE_44K |
|
||||
AUDIO_SAMP_RATE_48K;
|
||||
caps->ac_controls.b[0] =
|
||||
AUDIO_SAMP_RATE_8K | AUDIO_SAMP_RATE_11K |
|
||||
AUDIO_SAMP_RATE_16K | AUDIO_SAMP_RATE_22K |
|
||||
AUDIO_SAMP_RATE_32K | AUDIO_SAMP_RATE_44K |
|
||||
AUDIO_SAMP_RATE_48K;
|
||||
break;
|
||||
|
||||
case AUDIO_FMT_MP3:
|
||||
|
@ -1059,13 +1105,14 @@ static int wm8904_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
|
|||
{
|
||||
/* Fill in the ac_controls section with the Feature Units we have */
|
||||
|
||||
caps->ac_controls.b[0] = AUDIO_FU_VOLUME | AUDIO_FU_BASS | AUDIO_FU_TREBLE;
|
||||
caps->ac_controls.b[0] = AUDIO_FU_VOLUME | AUDIO_FU_BASS |
|
||||
AUDIO_FU_TREBLE;
|
||||
caps->ac_controls.b[1] = AUDIO_FU_BALANCE >> 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO: Do we need to provide specific info for the Feature Units,
|
||||
* such as volume setting ranges, etc.?
|
||||
/* TODO: Do we need to provide specific info for the Feature
|
||||
* Units, such as volume setting ranges, etc.?
|
||||
*/
|
||||
}
|
||||
|
||||
|
@ -1088,7 +1135,8 @@ static int wm8904_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
|
|||
|
||||
/* Provide capabilities of our Stereo Extender */
|
||||
|
||||
caps->ac_controls.b[0] = AUDIO_STEXT_ENABLE | AUDIO_STEXT_WIDTH;
|
||||
caps->ac_controls.b[0] =
|
||||
AUDIO_STEXT_ENABLE | AUDIO_STEXT_WIDTH;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1342,6 +1390,7 @@ static void wm8904_senddone(FAR struct i2s_dev_s *i2s,
|
|||
priv->inflight--;
|
||||
|
||||
/* Save the result of the transfer */
|
||||
|
||||
/* REVISIT: This can be overwritten */
|
||||
|
||||
priv->result = result;
|
||||
|
@ -1444,7 +1493,7 @@ static int wm8904_sendbuffer(FAR struct wm8904_dev_s *priv)
|
|||
irqstate_t flags;
|
||||
uint32_t timeout;
|
||||
int shift;
|
||||
int ret = OK;
|
||||
int ret;
|
||||
|
||||
/* Loop while there are audio buffers to be sent and we have few than
|
||||
* CONFIG_WM8904_INFLIGHT then "in-flight"
|
||||
|
@ -1458,7 +1507,12 @@ static int wm8904_sendbuffer(FAR struct wm8904_dev_s *priv)
|
|||
* only while accessing 'inflight'.
|
||||
*/
|
||||
|
||||
wm8904_takesem(&priv->pendsem);
|
||||
ret = wm8904_takesem(&priv->pendsem);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (priv->inflight < CONFIG_WM8904_INFLIGHT &&
|
||||
dq_peek(&priv->pendq) != NULL && !priv->paused)
|
||||
{
|
||||
|
@ -1540,6 +1594,7 @@ static int wm8904_start(FAR struct audio_lowerhalf_s *dev)
|
|||
audinfo("Entry\n");
|
||||
|
||||
/* Exit reduced power modes of operation */
|
||||
|
||||
/* REVISIT */
|
||||
|
||||
/* Create a message queue for the worker thread */
|
||||
|
@ -1623,6 +1678,7 @@ static int wm8904_stop(FAR struct audio_lowerhalf_s *dev)
|
|||
priv->threadid = 0;
|
||||
|
||||
/* Enter into a reduced power usage mode */
|
||||
|
||||
/* REVISIT: */
|
||||
|
||||
return OK;
|
||||
|
@ -1667,7 +1723,8 @@ static int wm8904_pause(FAR struct audio_lowerhalf_s *dev)
|
|||
|
||||
#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
|
||||
#ifdef CONFIG_AUDIO_MULTI_SESSION
|
||||
static int wm8904_resume(FAR struct audio_lowerhalf_s *dev, FAR void *session)
|
||||
static int wm8904_resume(FAR struct audio_lowerhalf_s *dev,
|
||||
FAR void *session)
|
||||
#else
|
||||
static int wm8904_resume(FAR struct audio_lowerhalf_s *dev)
|
||||
#endif
|
||||
|
@ -1714,14 +1771,20 @@ static int wm8904_enqueuebuffer(FAR struct audio_lowerhalf_s *dev,
|
|||
|
||||
/* Add the new buffer to the tail of pending audio buffers */
|
||||
|
||||
wm8904_takesem(&priv->pendsem);
|
||||
ret = wm8904_takesem(&priv->pendsem);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
apb->flags |= AUDIO_APB_OUTPUT_ENQUEUED;
|
||||
dq_addlast(&apb->dq_entry, &priv->pendq);
|
||||
wm8904_givesem(&priv->pendsem);
|
||||
|
||||
/* Send a message to the worker thread indicating that a new buffer has been
|
||||
* enqueued. If mq is NULL, then the playing has not yet started. In that
|
||||
* case we are just "priming the pump" and we don't need to send any message.
|
||||
/* Send a message to the worker thread indicating that a new buffer has
|
||||
* been enqueued. If mq is NULL, then the playing has not yet started.
|
||||
* In that case we are just "priming the pump" and we don't need to send
|
||||
* any message.
|
||||
*/
|
||||
|
||||
ret = OK;
|
||||
|
@ -1824,11 +1887,16 @@ static int wm8904_reserve(FAR struct audio_lowerhalf_s *dev)
|
|||
#endif
|
||||
{
|
||||
FAR struct wm8904_dev_s *priv = (FAR struct wm8904_dev_s *) dev;
|
||||
int ret = OK;
|
||||
int ret;
|
||||
|
||||
/* Borrow the APBQ semaphore for thread sync */
|
||||
|
||||
wm8904_takesem(&priv->pendsem);
|
||||
ret = wm8904_takesem(&priv->pendsem);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (priv->reserved)
|
||||
{
|
||||
ret = -EBUSY;
|
||||
|
@ -1869,7 +1937,8 @@ static int wm8904_release(FAR struct audio_lowerhalf_s *dev)
|
|||
#endif
|
||||
{
|
||||
FAR struct wm8904_dev_s *priv = (FAR struct wm8904_dev_s *)dev;
|
||||
void *value;
|
||||
FAR void *value;
|
||||
int ret;
|
||||
|
||||
/* Join any old worker thread we had created to prevent a memory leak */
|
||||
|
||||
|
@ -1881,14 +1950,14 @@ static int wm8904_release(FAR struct audio_lowerhalf_s *dev)
|
|||
|
||||
/* Borrow the APBQ semaphore for thread sync */
|
||||
|
||||
wm8904_takesem(&priv->pendsem);
|
||||
ret = wm8904_forcetake(&priv->pendsem);
|
||||
|
||||
/* Really we should free any queued buffers here */
|
||||
|
||||
priv->reserved = false;
|
||||
wm8904_givesem(&priv->pendsem);
|
||||
|
||||
return OK;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -2069,6 +2138,7 @@ static void *wm8904_workerthread(pthread_addr_t pvarg)
|
|||
|
||||
#ifndef CONFIG_AUDIO_EXCLUDE_STOP
|
||||
case AUDIO_MSG_STOP:
|
||||
|
||||
/* Indicate that we are terminating */
|
||||
|
||||
audinfo("AUDIO_MSG_STOP: Terminating\n");
|
||||
|
@ -2103,7 +2173,7 @@ static void *wm8904_workerthread(pthread_addr_t pvarg)
|
|||
|
||||
/* Return any pending buffers in our pending queue */
|
||||
|
||||
wm8904_takesem(&priv->pendsem);
|
||||
wm8904_forcetake(&priv->pendsem);
|
||||
while ((apb = (FAR struct ap_buffer_s *)dq_remfirst(&priv->pendq)) != NULL)
|
||||
{
|
||||
/* Release our reference to the buffer */
|
||||
|
@ -2174,6 +2244,7 @@ static void wm8904_audio_output(FAR struct wm8904_dev_s *priv)
|
|||
wm8904_writereg(priv, WM8904_VMID_CTRL, regval);
|
||||
|
||||
/* Mic Bias Control 0 */
|
||||
|
||||
/* MICDET_ENA=1, MICBIAS_ENA=1 */
|
||||
|
||||
regval = WM8904_MICDET_ENA | WM8904_MICBIAS_ENA;
|
||||
|
@ -2194,15 +2265,17 @@ static void wm8904_audio_output(FAR struct wm8904_dev_s *priv)
|
|||
wm8904_writereg(priv, WM8904_PM2, regval);
|
||||
|
||||
/* Power Management 6 */
|
||||
|
||||
/* DACL_ENA=1, DACR_ENA=1, ADCL_ENA=1, ADCR_ENA=1 */
|
||||
|
||||
regval = WM8904_DACL_ENA | WM8904_DACR_ENA | WM8904_ADCL_ENA | WM8904_ADCR_ENA;
|
||||
regval = WM8904_DACL_ENA | WM8904_DACR_ENA | WM8904_ADCL_ENA |
|
||||
WM8904_ADCR_ENA;
|
||||
wm8904_writereg(priv, WM8904_PM6, regval);
|
||||
|
||||
/* Clock Rates 0.
|
||||
*
|
||||
* This value sets TOCLK_RATE_DIV16=0, TOCLK_RATE_X4=0, and MCLK_DIV=0 while
|
||||
* preserving the state of some undocumented bits (see wm8904.h).
|
||||
* This value sets TOCLK_RATE_DIV16=0, TOCLK_RATE_X4=0, and MCLK_DIV=0
|
||||
* while preserving the state of some undocumented bits (see wm8904.h).
|
||||
*
|
||||
* MCLK_DIV=0 : MCLK is is not divided by 2.
|
||||
*/
|
||||
|
@ -2244,13 +2317,14 @@ static void wm8904_audio_output(FAR struct wm8904_dev_s *priv)
|
|||
|
||||
/* Audio Interface 1.
|
||||
*
|
||||
* This value sets AIFADC_TDM=0, AIFADC_TDM_CHAN=0, BCLK_DIR=1 while preserving
|
||||
* the state of some undocumented bits (see wm8904.h).
|
||||
* This value sets AIFADC_TDM=0, AIFADC_TDM_CHAN=0, BCLK_DIR=1 while
|
||||
* preserving the state of some undocumented bits (see wm8904.h).
|
||||
*
|
||||
* Digital audio interface format : I2S
|
||||
* Digital audio interface word length : 24
|
||||
* AIF_LRCLK_INV=0 : LRCLK not inverted
|
||||
* BCLK_DIR=1 : BCLK is an output (will clock I2S).
|
||||
* BCLK_DIR=1 : BCLK is an output (will clock
|
||||
* I2S).
|
||||
* AIF_BCLK_INV=0 : BCLK not inverted
|
||||
* AIF_TRIS=0 : Outputs not tri-stated
|
||||
* AIFADC_TDM_CHAN=0 : ADCDAT outputs data on slot 0
|
||||
|
@ -2260,7 +2334,8 @@ static void wm8904_audio_output(FAR struct wm8904_dev_s *priv)
|
|||
* Bit 14: : Undocumented
|
||||
*/
|
||||
|
||||
regval = WM8904_AIF_FMT_I2S | WM8904_AIF_WL_24BITS | WM8904_BCLK_DIR | 0x4000;
|
||||
regval = WM8904_AIF_FMT_I2S | WM8904_AIF_WL_24BITS | WM8904_BCLK_DIR |
|
||||
0x4000;
|
||||
wm8904_writereg(priv, WM8904_AIF1, regval);
|
||||
|
||||
/* Audio Interface 2.
|
||||
|
@ -2271,10 +2346,10 @@ static void wm8904_audio_output(FAR struct wm8904_dev_s *priv)
|
|||
|
||||
/* Audio Interface 3
|
||||
*
|
||||
* Set LRCLK as an output with rate = BCLK / (2*WM8904_FRAMELENn). This is
|
||||
* a value that varies with bits per sample, n=8 or 16. Since I2S will send
|
||||
* a word on each edge of LRCLK (after a delay), this essentially means that
|
||||
* each audio frame is WM8904_FRAMELENn bits in length.
|
||||
* Set LRCLK as an output with rate = BCLK / (2*WM8904_FRAMELENn). This
|
||||
* is a value that varies with bits per sample, n=8 or 16. Since I2S will
|
||||
* send a word on each edge of LRCLK (after a delay), this essentially
|
||||
* means that each audio frame is WM8904_FRAMELENn bits in length.
|
||||
*/
|
||||
|
||||
regval = WM8904_LRCLK_DIR | WM8904_LRCLK_RATE(2*WM8904_FRAMELEN16);
|
||||
|
@ -2285,6 +2360,7 @@ static void wm8904_audio_output(FAR struct wm8904_dev_s *priv)
|
|||
wm8904_writereg(priv, WM8904_DAC_DIGI1, 0);
|
||||
|
||||
/* Analogue Left Input 0 */
|
||||
|
||||
/* Analogue Right Input 0 */
|
||||
|
||||
regval = WM8904_IN_VOL(5);
|
||||
|
@ -2297,6 +2373,7 @@ static void wm8904_audio_output(FAR struct wm8904_dev_s *priv)
|
|||
wm8904_writereg(priv, WM8904_ANA_RIGHT_IN1, 0);
|
||||
|
||||
/* Analogue OUT1 Left */
|
||||
|
||||
/* Analogue OUT1 Right */
|
||||
|
||||
wm8904_setvolume(priv, CONFIG_WM8904_INITVOLUME, true);
|
||||
|
@ -2308,8 +2385,9 @@ static void wm8904_audio_output(FAR struct wm8904_dev_s *priv)
|
|||
|
||||
/* Analogue HP 0 */
|
||||
|
||||
regval = WM8904_HPL_RMV_SHORT | WM8904_HPL_ENA_OUTP | WM8904_HPL_ENA_DLY | WM8904_HPL_ENA |
|
||||
WM8904_HPR_RMV_SHORT | WM8904_HPR_ENA_OUTP | WM8904_HPR_ENA_DLY | WM8904_HPR_ENA;
|
||||
regval = WM8904_HPL_RMV_SHORT | WM8904_HPL_ENA_OUTP | WM8904_HPL_ENA_DLY |
|
||||
WM8904_HPL_ENA | WM8904_HPR_RMV_SHORT | WM8904_HPR_ENA_OUTP |
|
||||
WM8904_HPR_ENA_DLY | WM8904_HPR_ENA;
|
||||
wm8904_writereg(priv, WM8904_ANA_HP0, regval);
|
||||
|
||||
/* Charge Pump 0 */
|
||||
|
|
|
@ -1,51 +1,40 @@
|
|||
/**************************************************************************************
|
||||
/****************************************************************************
|
||||
* drivers/lcd/ft80x.c
|
||||
*
|
||||
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* References:
|
||||
* - Document No.: FT_000792, "FT800 Embedded Video Engine", Datasheet Version 1.1,
|
||||
* Clearance No.: FTDI# 334, Future Technology Devices International Ltd.
|
||||
* - Document No.: FT_000986, "FT801 Embedded Video Engine Datasheet", Version 1.0,
|
||||
* Clearance No.: FTDI#376, Future Technology Devices International Ltd.
|
||||
* - Application Note AN_240AN_240, "FT800 From the Ground Up", Version 1.1,
|
||||
* Issue Date: 2014-06-09, Future Technology Devices International Ltd.
|
||||
* - "FT800 Series Programmer Guide Guide", Version 2.1, Issue Date: 2016-09-19,
|
||||
* Future Technology Devices International Ltd.
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
/**************************************************************************************
|
||||
/* References:
|
||||
* - Document No.: FT_000792, "FT800 Embedded Video Engine", Datasheet
|
||||
* Version 1.1, Clearance No.: FTDI# 334, Future Technology Devices
|
||||
* International Ltd.
|
||||
* - Document No.: FT_000986, "FT801 Embedded Video Engine Datasheet",
|
||||
* Version 1.0, Clearance No.: FTDI#376, Future Technology Devices
|
||||
* International Ltd.
|
||||
* - Application Note AN_240AN_240, "FT800 From the Ground Up", Version
|
||||
* 1.1, Issue Date: 2014-06-09, Future Technology Devices International
|
||||
* Ltd.
|
||||
* - "FT800 Series Programmer Guide Guide", Version 2.1, Issue Date:
|
||||
* 2016-09-19, Future Technology Devices International Ltd.
|
||||
*/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
**************************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
|
@ -154,6 +143,35 @@ static const struct file_operations g_ft80x_fops =
|
|||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ft80x_forcetake
|
||||
*
|
||||
* Description:
|
||||
* This is a wrapper around but nxsem_wait_uninterruptible(). The wrapper
|
||||
* continues to wait even if the thread is canceled. This must be done in
|
||||
* certain conditions where were must continue in order to clean-up
|
||||
* resources.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void ft80x_forcetake(FAR sem_t *sem)
|
||||
{
|
||||
int ret;
|
||||
|
||||
do
|
||||
{
|
||||
ret = nxsem_wait_uninterruptible(sem);
|
||||
|
||||
/* The only expected error would -ECANCELED meaning that the
|
||||
* parent thread has been canceled. We have to continue and
|
||||
* terminate the poll in this case.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(ret == OK || ret == -ECANCELED);
|
||||
}
|
||||
while (ret < 0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ft80x_fade
|
||||
*
|
||||
|
@ -295,7 +313,7 @@ static void ft80x_interrupt_work(FAR void *arg)
|
|||
|
||||
/* Get exclusive access to the device structures */
|
||||
|
||||
nxsem_wait_uninterruptible(&priv->exclsem);
|
||||
ft80x_forcetake(&priv->exclsem);
|
||||
|
||||
/* Get the set of pending interrupts. Note that simply reading this
|
||||
* register is sufficient to clear all pending interrupts.
|
||||
|
@ -309,74 +327,74 @@ static void ft80x_interrupt_work(FAR void *arg)
|
|||
* implementation.
|
||||
*/
|
||||
|
||||
if ((intflags & FT80X_INT_SWAP) != 0)
|
||||
{
|
||||
/* Display swap occurred */
|
||||
if ((intflags & FT80X_INT_SWAP) != 0)
|
||||
{
|
||||
/* Display swap occurred */
|
||||
|
||||
lcdinfo("Display swap occurred\n");
|
||||
ft80x_notify(priv, FT80X_NOTIFY_SWAP, 0);
|
||||
}
|
||||
lcdinfo("Display swap occurred\n");
|
||||
ft80x_notify(priv, FT80X_NOTIFY_SWAP, 0);
|
||||
}
|
||||
|
||||
if ((intflags & FT80X_INT_TOUCH) != 0)
|
||||
{
|
||||
/* Touch-screen touch detected */
|
||||
if ((intflags & FT80X_INT_TOUCH) != 0)
|
||||
{
|
||||
/* Touch-screen touch detected */
|
||||
|
||||
lcdinfo("Touch-screen touch detected\n");
|
||||
ft80x_notify(priv, FT80X_NOTIFY_TOUCH, 0);
|
||||
}
|
||||
lcdinfo("Touch-screen touch detected\n");
|
||||
ft80x_notify(priv, FT80X_NOTIFY_TOUCH, 0);
|
||||
}
|
||||
|
||||
if ((intflags & FT80X_INT_TAG) != 0)
|
||||
{
|
||||
/* Touch-screen tag value change */
|
||||
if ((intflags & FT80X_INT_TAG) != 0)
|
||||
{
|
||||
/* Touch-screen tag value change */
|
||||
|
||||
lcdinfo("Touch-screen tag value change\n");
|
||||
lcdinfo("Touch-screen tag value change\n");
|
||||
#ifdef CONFIG_LCD_FT800
|
||||
regval = ft80x_read_word(priv, FT80X_REG_TOUCH_TAG);
|
||||
regval = ft80x_read_word(priv, FT80X_REG_TOUCH_TAG);
|
||||
#else
|
||||
regval = ft80x_read_word(priv, FT80X_REG_CTOUCH_TAG);
|
||||
regval = ft80x_read_word(priv, FT80X_REG_CTOUCH_TAG);
|
||||
#endif
|
||||
ft80x_notify(priv, FT80X_NOTIFY_TAG, (int)(regval & TOUCH_TAG_MASK));
|
||||
}
|
||||
ft80x_notify(priv, FT80X_NOTIFY_TAG, (int)(regval & TOUCH_TAG_MASK));
|
||||
}
|
||||
|
||||
if ((intflags & FT80X_INT_SOUND) != 0)
|
||||
{
|
||||
/* Sound effect ended */
|
||||
if ((intflags & FT80X_INT_SOUND) != 0)
|
||||
{
|
||||
/* Sound effect ended */
|
||||
|
||||
lcdinfo(" Sound effect ended\n");
|
||||
ft80x_notify(priv, FT80X_NOTIFY_SOUND, 0);
|
||||
}
|
||||
lcdinfo(" Sound effect ended\n");
|
||||
ft80x_notify(priv, FT80X_NOTIFY_SOUND, 0);
|
||||
}
|
||||
|
||||
if ((intflags & FT80X_INT_PLAYBACK) != 0)
|
||||
{
|
||||
/* Audio playback ended */
|
||||
if ((intflags & FT80X_INT_PLAYBACK) != 0)
|
||||
{
|
||||
/* Audio playback ended */
|
||||
|
||||
lcdinfo("Audio playback ended\n");
|
||||
ft80x_notify(priv, FT80X_NOTIFY_PLAYBACK, 0);
|
||||
}
|
||||
lcdinfo("Audio playback ended\n");
|
||||
ft80x_notify(priv, FT80X_NOTIFY_PLAYBACK, 0);
|
||||
}
|
||||
|
||||
if ((intflags & FT80X_INT_CMDEMPTY) != 0)
|
||||
{
|
||||
/* Command FIFO empty */
|
||||
if ((intflags & FT80X_INT_CMDEMPTY) != 0)
|
||||
{
|
||||
/* Command FIFO empty */
|
||||
|
||||
lcdinfo("Command FIFO empty\n");
|
||||
ft80x_notify(priv, FT80X_NOTIFY_CMDEMPTY, 0);
|
||||
}
|
||||
lcdinfo("Command FIFO empty\n");
|
||||
ft80x_notify(priv, FT80X_NOTIFY_CMDEMPTY, 0);
|
||||
}
|
||||
|
||||
if ((intflags & FT80X_INT_CMDFLAG) != 0)
|
||||
{
|
||||
/* Command FIFO flag */
|
||||
if ((intflags & FT80X_INT_CMDFLAG) != 0)
|
||||
{
|
||||
/* Command FIFO flag */
|
||||
|
||||
lcdinfo("Command FIFO flag\n");
|
||||
ft80x_notify(priv, FT80X_NOTIFY_CMDFLAG, 0);
|
||||
}
|
||||
lcdinfo("Command FIFO flag\n");
|
||||
ft80x_notify(priv, FT80X_NOTIFY_CMDFLAG, 0);
|
||||
}
|
||||
|
||||
if ((intflags & FT80X_INT_CONVCOMPLETE) != 0)
|
||||
{
|
||||
/* Touch-screen conversions completed */
|
||||
if ((intflags & FT80X_INT_CONVCOMPLETE) != 0)
|
||||
{
|
||||
/* Touch-screen conversions completed */
|
||||
|
||||
lcdinfo(" Touch-screen conversions completed\n");
|
||||
ft80x_notify(priv, FT80X_NOTIFY_CONVCOMPLETE, 0);
|
||||
}
|
||||
lcdinfo(" Touch-screen conversions completed\n");
|
||||
ft80x_notify(priv, FT80X_NOTIFY_CONVCOMPLETE, 0);
|
||||
}
|
||||
|
||||
/* Re-enable interrupts */
|
||||
|
||||
|
@ -598,7 +616,7 @@ static ssize_t ft80x_write(FAR struct file *filep, FAR const char *buffer,
|
|||
if (buffer == NULL || ((uintptr_t)buffer & 3) != 0 ||
|
||||
len == 0 || (len & 3) != 0 || (len + filep->f_pos) > FT80X_RAM_DL_SIZE)
|
||||
{
|
||||
return -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Get exclusive access to the device structures */
|
||||
|
@ -659,12 +677,14 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
switch (cmd)
|
||||
{
|
||||
/* FT80X_IOC_CREATEDL:
|
||||
* Description: Write a display list to the FT80x display list memory
|
||||
* Description: Write a display list to the FT80x display list memory
|
||||
* starting at offset zero. This may or may not be the
|
||||
* entire display list. Display lists may be created
|
||||
* incrementally, starting with FT80X_IOC_CREATEDL and
|
||||
* finishing the display list using FT80XIO_APPENDDL
|
||||
* Description: Write a display list to the FT80x display list
|
||||
* memory
|
||||
* Description: Write a display list to the FT80x display list
|
||||
* memory starting at offset zero. This may or may
|
||||
* not be the entire display list. Display lists may
|
||||
* be created incrementally, starting with
|
||||
* FT80X_IOC_CREATEDL and finishing the display list
|
||||
* using FT80XIO_APPENDDL
|
||||
* Argument: A reference to a display list structure instance.
|
||||
* See struct ft80x_displaylist_s.
|
||||
* Returns: None
|
||||
|
@ -682,12 +702,13 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
|
||||
/* FT80X_IOC_APPENDDL:
|
||||
* Description: Write additional display list entries to the FT80x
|
||||
* display list memory at the current display list offset.
|
||||
* This IOCTL command permits display lists to be completed
|
||||
* incrementally, starting with FT80X_IOC_CREATEDL and
|
||||
* finishing the display list using FT80XIO_APPENDDL.
|
||||
* Argument: A reference to a display list structure instance. See
|
||||
* struct ft80x_displaylist_s.
|
||||
* display list memory at the current display list
|
||||
* offset. This IOCTL command permits display lists
|
||||
* to be completed incrementally, starting with
|
||||
* FT80X_IOC_CREATEDL and finishing the display list
|
||||
* using FT80XIO_APPENDDL.
|
||||
* Argument: A reference to a display list structure instance.
|
||||
* See struct ft80x_displaylist_s.
|
||||
* Returns: None
|
||||
*/
|
||||
|
||||
|
@ -778,7 +799,7 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
|
||||
/* FT80X_IOC_PUTRAMCMD
|
||||
* Description: Write 32-bit aligned data to FT80x FIFO (RAM_CMD)
|
||||
* Argument: A reference to an instance of struct ft80x_relmem_s below.
|
||||
* Argument: A reference to an instance of struct ft80x_relmem_s.
|
||||
* Returns: None.
|
||||
*/
|
||||
|
||||
|
@ -787,8 +808,7 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
FAR struct ft80x_relmem_s *ramcmd =
|
||||
(FAR struct ft80x_relmem_s *)((uintptr_t)arg);
|
||||
|
||||
if (ramcmd == NULL || ((uintptr_t)ramcmd->offset & 3) != 0 /* ||
|
||||
ramcmd->offset >= FT80X_CMDFIFO_SIZE */ )
|
||||
if (ramcmd == NULL || ((uintptr_t)ramcmd->offset & 3) != 0)
|
||||
{
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
@ -803,7 +823,8 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
|
||||
/* FT80X_IOC_GETREG8:
|
||||
* Description: Read an 8-bit register value from the FT80x.
|
||||
* Argument: A reference to an instance of struct ft80x_register_s.
|
||||
* Argument: A reference to an instance of struct
|
||||
* ft80x_register_s.
|
||||
* Returns: The 8-bit value read from the register.
|
||||
*/
|
||||
|
||||
|
@ -826,7 +847,8 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
|
||||
/* FT80X_IOC_GETREG16:
|
||||
* Description: Read a 16-bit register value from the FT80x.
|
||||
* Argument: A reference to an instance of struct ft80x_register_s.
|
||||
* Argument: A reference to an instance of struct
|
||||
* ft80x_register_s.
|
||||
* Returns: The 16-bit value read from the register.
|
||||
*/
|
||||
|
||||
|
@ -849,7 +871,8 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
|
||||
/* FT80X_IOC_GETREG32:
|
||||
* Description: Read a 32-bit register value from the FT80x.
|
||||
* Argument: A reference to an instance of struct ft80x_register_s.
|
||||
* Argument: A reference to an instance of struct
|
||||
* ft80x_register_s.
|
||||
* Returns: The 32-bit value read from the register.
|
||||
*/
|
||||
|
||||
|
@ -872,8 +895,10 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
|
||||
/* FT80X_IOC_GETREGS:
|
||||
* Description: Read multiple 32-bit register values from the FT80x.
|
||||
* Argument: A reference to an instance of struct ft80x_registers_s.
|
||||
* Returns: The 32-bit values read from the consecutive registers .
|
||||
* Argument: A reference to an instance of struct
|
||||
* ft80x_registers_s.
|
||||
* Returns: The 32-bit values read from the consecutive
|
||||
* registers .
|
||||
*/
|
||||
|
||||
case FT80X_IOC_GETREGS:
|
||||
|
@ -896,7 +921,8 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
|
||||
/* FT80X_IOC_PUTREG8:
|
||||
* Description: Write an 8-bit register value to the FT80x.
|
||||
* Argument: A reference to an instance of struct ft80x_register_s.
|
||||
* Argument: A reference to an instance of struct
|
||||
* ft80x_register_s.
|
||||
* Returns: None.
|
||||
*/
|
||||
|
||||
|
@ -919,7 +945,8 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
|
||||
/* FT80X_IOC_PUTREG16:
|
||||
* Description: Write a 16-bit register value to the FT80x.
|
||||
* Argument: A reference to an instance of struct ft80x_register_s.
|
||||
* Argument: A reference to an instance of struct
|
||||
* ft80x_register_s.
|
||||
* Returns: None.
|
||||
*/
|
||||
|
||||
|
@ -942,7 +969,8 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
|
||||
/* FT80X_IOC_PUTREG32:
|
||||
* Description: Write a 32-bit register value to the FT80x.
|
||||
* Argument: A reference to an instance of struct ft80x_register_s.
|
||||
* Argument: A reference to an instance of struct
|
||||
* ft80x_register_s.
|
||||
* Returns: None.
|
||||
*/
|
||||
|
||||
|
@ -965,7 +993,8 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
|
||||
/* FT80X_IOC_PUTREGS:
|
||||
* Description: Write multiple 32-bit register values to the FT80x.
|
||||
* Argument: A reference to an instance of struct ft80x_registers_s.
|
||||
* Argument: A reference to an instance of struct
|
||||
* ft80x_registers_s.
|
||||
* Returns: None.
|
||||
*/
|
||||
|
||||
|
@ -1091,7 +1120,8 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
#if defined(CONFIG_LCD_FT80X_AUDIO_MCUSHUTDOWN)
|
||||
/* Amplifier is controlled by an MCU GPIO pin */
|
||||
|
||||
DEBUGASSERT(priv->lower->attach != NULL && priv->lower->audio != NULL);
|
||||
DEBUGASSERT(priv->lower->attach != NULL &&
|
||||
priv->lower->audio != NULL);
|
||||
DEBUGASSERT(arg == 0 || arg == 1);
|
||||
|
||||
priv->lower->audio(priv->lower, (arg != 0));
|
||||
|
@ -1207,8 +1237,8 @@ static int ft80x_initialize(FAR struct ft80x_dev_s *priv)
|
|||
* - FT80X_REG_VSYNC0
|
||||
* - FT80X_REG_VSYNC1
|
||||
*
|
||||
* And the FT80X_REG_CSPREAD register changes color clock timing to reduce system
|
||||
* noise.
|
||||
* And the FT80X_REG_CSPREAD register changes color clock timing to reduce
|
||||
* system noise.
|
||||
*
|
||||
* GPIO bit 7 is used for the display enable pin of the LCD module. By
|
||||
* setting the direction of the GPIO bit to out direction, the display can
|
||||
|
@ -1221,7 +1251,8 @@ static int ft80x_initialize(FAR struct ft80x_dev_s *priv)
|
|||
*
|
||||
* 1. Drive the PD_N pin high
|
||||
* 2. Wait for at least 20ms
|
||||
* 3. Execute "Initialization Sequence during the Boot up" from steps 1 to 9
|
||||
* 3. Execute "Initialization Sequence during the Boot up" from steps 1
|
||||
* to 9
|
||||
*
|
||||
* Initialization Sequence from Sleep Mode:
|
||||
*
|
||||
|
@ -1235,9 +1266,9 @@ static int ft80x_initialize(FAR struct ft80x_dev_s *priv)
|
|||
* Mode" except waiting for at least 20ms in step 2.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(priv->lower != NULL && priv->lower->pwrdown != NULL);
|
||||
priv->lower->pwrdown(priv->lower, false);
|
||||
up_mdelay(20);
|
||||
DEBUGASSERT(priv->lower != NULL && priv->lower->pwrdown != NULL);
|
||||
priv->lower->pwrdown(priv->lower, false);
|
||||
up_mdelay(20);
|
||||
|
||||
/* Initialization Sequence during the boot up:
|
||||
*
|
||||
|
@ -1320,8 +1351,8 @@ static int ft80x_initialize(FAR struct ft80x_dev_s *priv)
|
|||
* checked, the next task is to configure the LCD display parameters for
|
||||
* the chosen display with the values determined in Section 2.3.3 above.
|
||||
*
|
||||
* a. Set FT80X_REG_PCLK to zero - This disables the pixel clock output while
|
||||
* the LCD and other system parameters are configured
|
||||
* a. Set FT80X_REG_PCLK to zero - This disables the pixel clock output
|
||||
* while the LCD and other system parameters are configured
|
||||
* b. Set the following registers with values for the chosen display.
|
||||
* Typical WQVGA and QVGA values are shown:
|
||||
*
|
||||
|
@ -1388,8 +1419,8 @@ static int ft80x_initialize(FAR struct ft80x_dev_s *priv)
|
|||
|
||||
/* 5. Write first display list */
|
||||
|
||||
ft80x_write_word(priv, FT80X_RAM_DL + 0, FT80X_CLEAR_COLOR_RGB(0,0,0));
|
||||
ft80x_write_word(priv, FT80X_RAM_DL + 4, FT80X_CLEAR(1,1,1));
|
||||
ft80x_write_word(priv, FT80X_RAM_DL + 0, FT80X_CLEAR_COLOR_RGB(0, 0, 0));
|
||||
ft80x_write_word(priv, FT80X_RAM_DL + 4, FT80X_CLEAR(1, 1, 1));
|
||||
ft80x_write_word(priv, FT80X_RAM_DL + 8, FT80X_DISPLAY());
|
||||
|
||||
/* 6. Write FT80X_REG_DLSWAP, FT800 swaps display list immediately */
|
||||
|
|
|
@ -101,7 +101,7 @@ struct phy_notify_s
|
|||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static void phy_semtake(void);
|
||||
static int phy_semtake(void);
|
||||
static FAR struct phy_notify_s *phy_find_unassigned(void);
|
||||
static FAR struct phy_notify_s *phy_find_assigned(FAR const char *intf,
|
||||
pid_t pid);
|
||||
|
@ -128,9 +128,9 @@ static struct phy_notify_s
|
|||
* Name: phy_semtake
|
||||
****************************************************************************/
|
||||
|
||||
static void phy_semtake(void)
|
||||
static int phy_semtake(void)
|
||||
{
|
||||
nxsem_wait_uninterruptible(&g_notify_clients_sem);
|
||||
return nxsem_wait_uninterruptible(&g_notify_clients_sem);
|
||||
}
|
||||
|
||||
#define phy_semgive() nxsem_post(&g_notify_clients_sem);
|
||||
|
@ -142,9 +142,16 @@ static void phy_semtake(void)
|
|||
static FAR struct phy_notify_s *phy_find_unassigned(void)
|
||||
{
|
||||
FAR struct phy_notify_s *client;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
phy_semtake();
|
||||
ret = phy_semtake();
|
||||
if (ret < 0)
|
||||
{
|
||||
phyerr("ERROR: phy_semtake failed: %d\n", ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < CONFIG_PHY_NOTIFICATION_NCLIENTS; i++)
|
||||
{
|
||||
client = &g_notify_clients[i];
|
||||
|
@ -180,9 +187,16 @@ static FAR struct phy_notify_s *phy_find_assigned(FAR const char *intf,
|
|||
pid_t pid)
|
||||
{
|
||||
FAR struct phy_notify_s *client;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
phy_semtake();
|
||||
ret = phy_semtake();
|
||||
if (ret < 0)
|
||||
{
|
||||
phyerr("ERROR: phy_semtake failed: %d\n", ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < CONFIG_PHY_NOTIFICATION_NCLIENTS; i++)
|
||||
{
|
||||
client = &g_notify_clients[i];
|
||||
|
@ -286,7 +300,7 @@ int phy_notify_subscribe(FAR const char *intf, pid_t pid,
|
|||
/* Check if this client already exists */
|
||||
|
||||
client = phy_find_assigned(intf, pid);
|
||||
if (client)
|
||||
if (client != NULL)
|
||||
{
|
||||
/* Yes.. update the signal number and argument */
|
||||
|
||||
|
@ -297,7 +311,7 @@ int phy_notify_subscribe(FAR const char *intf, pid_t pid,
|
|||
/* No, allocate a new slot in the client notification table */
|
||||
|
||||
client = phy_find_unassigned();
|
||||
if (!client)
|
||||
if (client == NULL)
|
||||
{
|
||||
phyerr("ERROR: Failed to allocate a client entry\n");
|
||||
return -ENOMEM;
|
||||
|
@ -345,13 +359,14 @@ int phy_notify_subscribe(FAR const char *intf, pid_t pid,
|
|||
int phy_notify_unsubscribe(FAR const char *intf, pid_t pid)
|
||||
{
|
||||
FAR struct phy_notify_s *client;
|
||||
int ret;
|
||||
|
||||
phyinfo("%s: PID=%d\n", intf, pid);
|
||||
|
||||
/* Find the client entry for this interface */
|
||||
|
||||
client = phy_find_assigned(intf, pid);
|
||||
if (!client)
|
||||
if (client == NULL)
|
||||
{
|
||||
phyerr("ERROR: No such client\n");
|
||||
return -ENOENT;
|
||||
|
@ -359,20 +374,24 @@ int phy_notify_unsubscribe(FAR const char *intf, pid_t pid)
|
|||
|
||||
/* Detach and disable the PHY interrupt */
|
||||
|
||||
phy_semtake();
|
||||
arch_phy_irq(intf, NULL, NULL, NULL);
|
||||
ret = phy_semtake();
|
||||
if (ret >= 0)
|
||||
{
|
||||
arch_phy_irq(intf, NULL, NULL, NULL);
|
||||
|
||||
/* Cancel any pending notification */
|
||||
/* Cancel any pending notification */
|
||||
|
||||
nxsig_cancel_notification(&client->work);
|
||||
nxsig_cancel_notification(&client->work);
|
||||
|
||||
/* Un-initialize the client entry */
|
||||
/* Un-initialize the client entry */
|
||||
|
||||
client->assigned = false;
|
||||
client->intf[0] = '\0';
|
||||
client->pid = -1;
|
||||
client->assigned = false;
|
||||
client->intf[0] = '\0';
|
||||
client->pid = -1;
|
||||
|
||||
phy_semgive();
|
||||
}
|
||||
|
||||
phy_semgive();
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,40 +1,25 @@
|
|||
/****************************************************************************
|
||||
* drivers/net/slip.c
|
||||
*
|
||||
* Copyright (C) 2011-2012, 2015-2018 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* Reference: RFC 1055
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* Reference: RFC 1055 */
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
@ -110,14 +95,14 @@
|
|||
# define CONFIG_NET_SLIP_NINTERFACES 1
|
||||
#endif
|
||||
|
||||
/* SLIP special character codes *******************************************/
|
||||
/* SLIP special character codes ********************************************/
|
||||
|
||||
#define SLIP_END 0300 /* Indicates end of packet */
|
||||
#define SLIP_ESC 0333 /* Indicates byte stuffing */
|
||||
#define SLIP_ESC_END 0334 /* ESC ESC_END means SLIP_END data byte */
|
||||
#define SLIP_ESC_ESC 0335 /* ESC ESC_ESC means ESC data byte */
|
||||
|
||||
/* General driver definitions **********************************************/
|
||||
/* General driver definitions ***********************************************/
|
||||
|
||||
/* TX poll delay = 1 second = 1000000 microseconds. */
|
||||
|
||||
|
@ -167,7 +152,8 @@ static struct slip_driver_s g_slip[CONFIG_NET_SLIP_NINTERFACES];
|
|||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static void slip_semtake(FAR struct slip_driver_s *priv);
|
||||
static int slip_semtake(FAR struct slip_driver_s *priv);
|
||||
static void slip_forcetake(FAR struct slip_driver_s *priv);
|
||||
|
||||
/* Common TX logic */
|
||||
|
||||
|
@ -202,13 +188,41 @@ static int slip_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac);
|
|||
* Name: slip_semtake
|
||||
****************************************************************************/
|
||||
|
||||
static void slip_semtake(FAR struct slip_driver_s *priv)
|
||||
static int slip_semtake(FAR struct slip_driver_s *priv)
|
||||
{
|
||||
nxsem_wait_uninterruptible(&priv->waitsem);
|
||||
return nxsem_wait_uninterruptible(&priv->waitsem);
|
||||
}
|
||||
|
||||
#define slip_semgive(p) nxsem_post(&(p)->waitsem);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: slip_forcetake
|
||||
*
|
||||
* Description:
|
||||
* This is just another wrapper but this one continues even if the thread
|
||||
* is canceled. This must be done in certain conditions where were must
|
||||
* continue in order to clean-up resources.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void slip_forcetake(FAR struct slip_driver_s *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
do
|
||||
{
|
||||
ret = nxsem_wait_uninterruptible(&priv->waitsem);
|
||||
|
||||
/* The only expected error would -ECANCELED meaning that the
|
||||
* parent thread has been canceled. We have to continue and
|
||||
* terminate the poll in this case.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(ret == OK || ret == -ECANCELED);
|
||||
}
|
||||
while (ret < 0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: slip_write
|
||||
*
|
||||
|
@ -384,7 +398,8 @@ static void slip_transmit(FAR struct slip_driver_s *priv)
|
|||
|
||||
static int slip_txpoll(FAR struct net_driver_s *dev)
|
||||
{
|
||||
FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private;
|
||||
FAR struct slip_driver_s *priv =
|
||||
(FAR struct slip_driver_s *)dev->d_private;
|
||||
|
||||
/* If the polling resulted in data that should be sent out on the network,
|
||||
* the field d_len is set to a value > 0.
|
||||
|
@ -398,8 +413,8 @@ static int slip_txpoll(FAR struct net_driver_s *dev)
|
|||
}
|
||||
}
|
||||
|
||||
/* If zero is returned, the polling will continue until all connections have
|
||||
* been examined.
|
||||
/* If zero is returned, the polling will continue until all connections
|
||||
* have been examined.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
|
@ -426,6 +441,7 @@ static int slip_txtask(int argc, FAR char *argv[])
|
|||
clock_t start_ticks;
|
||||
clock_t now_ticks;
|
||||
unsigned int hsec;
|
||||
int ret;
|
||||
|
||||
nerr("index: %d\n", index);
|
||||
DEBUGASSERT(index < CONFIG_NET_SLIP_NINTERFACES);
|
||||
|
@ -440,11 +456,17 @@ static int slip_txtask(int argc, FAR char *argv[])
|
|||
/* Loop forever */
|
||||
|
||||
start_ticks = clock_systimer();
|
||||
for (; ; )
|
||||
for (; ; )
|
||||
{
|
||||
/* Wait for the timeout to expire (or until we are signaled by */
|
||||
|
||||
slip_semtake(priv);
|
||||
ret = slip_semtake(priv);
|
||||
if (ret < 0)
|
||||
{
|
||||
DEBUGASSERT(ret == -ECANCELED);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!priv->txnodelay)
|
||||
{
|
||||
slip_semgive(priv);
|
||||
|
@ -777,7 +799,8 @@ static int slip_rxtask(int argc, FAR char *argv[])
|
|||
|
||||
static int slip_ifup(FAR struct net_driver_s *dev)
|
||||
{
|
||||
FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private;
|
||||
FAR struct slip_driver_s *priv =
|
||||
(FAR struct slip_driver_s *)dev->d_private;
|
||||
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
nerr("Bringing up: %d.%d.%d.%d\n",
|
||||
|
@ -815,7 +838,8 @@ static int slip_ifup(FAR struct net_driver_s *dev)
|
|||
|
||||
static int slip_ifdown(FAR struct net_driver_s *dev)
|
||||
{
|
||||
FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private;
|
||||
FAR struct slip_driver_s *priv =
|
||||
(FAR struct slip_driver_s *)dev->d_private;
|
||||
|
||||
/* Mark the device "down" */
|
||||
|
||||
|
@ -841,7 +865,8 @@ static int slip_ifdown(FAR struct net_driver_s *dev)
|
|||
|
||||
static int slip_txavail(FAR struct net_driver_s *dev)
|
||||
{
|
||||
FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private;
|
||||
FAR struct slip_driver_s *priv =
|
||||
(FAR struct slip_driver_s *)dev->d_private;
|
||||
|
||||
/* Ignore the notification if the interface is not yet up */
|
||||
|
||||
|
@ -877,7 +902,8 @@ static int slip_txavail(FAR struct net_driver_s *dev)
|
|||
#ifdef CONFIG_NET_MCASTGROUP
|
||||
static int slip_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac)
|
||||
{
|
||||
FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private;
|
||||
FAR struct slip_driver_s *priv =
|
||||
(FAR struct slip_driver_s *)dev->d_private;
|
||||
|
||||
/* Add the MAC address to the hardware multicast routing table */
|
||||
|
||||
|
@ -906,7 +932,8 @@ static int slip_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac)
|
|||
#ifdef CONFIG_NET_MCASTGROUP
|
||||
static int slip_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac)
|
||||
{
|
||||
FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private;
|
||||
FAR struct slip_driver_s *priv =
|
||||
(FAR struct slip_driver_s *)dev->d_private;
|
||||
|
||||
/* Add the MAC address to the hardware multicast routing table */
|
||||
|
||||
|
@ -993,7 +1020,7 @@ int slip_initialize(int intf, FAR const char *devname)
|
|||
|
||||
/* Wait and make sure that the receive task is started. */
|
||||
|
||||
slip_semtake(priv);
|
||||
slip_forcetake(priv);
|
||||
|
||||
/* Start the SLIP transmitter kernel thread */
|
||||
|
||||
|
@ -1008,7 +1035,7 @@ int slip_initialize(int intf, FAR const char *devname)
|
|||
|
||||
/* Wait and make sure that the transmit task is started. */
|
||||
|
||||
slip_semtake(priv);
|
||||
slip_forcetake(priv);
|
||||
|
||||
/* Bump the semaphore count so that it can now be used as a mutex */
|
||||
|
||||
|
|
|
@ -819,7 +819,8 @@ static ssize_t telnet_read(FAR struct file *filep, FAR char *buffer,
|
|||
{
|
||||
FAR struct inode *inode = filep->f_inode;
|
||||
FAR struct telnet_dev_s *priv = inode->i_private;
|
||||
ssize_t ret = 0;
|
||||
ssize_t nread = 0;
|
||||
int ret;
|
||||
|
||||
ninfo("len: %d\n", len);
|
||||
|
||||
|
@ -848,33 +849,44 @@ static ssize_t telnet_read(FAR struct file *filep, FAR char *buffer,
|
|||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/* Wait for new data (or error) */
|
||||
/* Wait for new data, interrupt, or thread cancellation */
|
||||
|
||||
ret = nxsem_wait(&priv->td_iosem);
|
||||
if (ret < 0)
|
||||
{
|
||||
nerr("ERROR: nxsem_wait failed: %d\n", ret);
|
||||
return (ssize_t)ret;
|
||||
}
|
||||
|
||||
nxsem_wait_uninterruptible(&priv->td_iosem);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Take exclusive access to data buffer */
|
||||
|
||||
nxsem_wait(&priv->td_exclsem);
|
||||
ret = nxsem_wait(&priv->td_exclsem);
|
||||
if (ret < 0)
|
||||
{
|
||||
nerr("ERROR: nxsem_wait failed: %d\n", ret);
|
||||
return (ssize_t)ret;
|
||||
}
|
||||
|
||||
/* Process the buffered telnet data */
|
||||
|
||||
src = &priv->td_rxbuffer[priv->td_offset];
|
||||
ret = telnet_receive(priv, src, priv->td_pending, buffer, len);
|
||||
nread = telnet_receive(priv, src, priv->td_pending, buffer, len);
|
||||
|
||||
nxsem_post(&priv->td_exclsem);
|
||||
}
|
||||
while (ret == 0);
|
||||
while (nread == 0);
|
||||
|
||||
/* Returned Value:
|
||||
*
|
||||
* ret > 0: The number of characters copied into the user buffer by
|
||||
* telnet_receive().
|
||||
* ret <= 0: Loss of connection or error events reported by recv().
|
||||
* nread > 0: The number of characters copied into the user buffer by
|
||||
* telnet_receive().
|
||||
* nread <= 0: Loss of connection or error events reported by recv().
|
||||
*/
|
||||
|
||||
return ret;
|
||||
return nread;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -166,7 +166,7 @@ struct tun_driver_s
|
|||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static void tun_lock(FAR struct tun_device_s *priv);
|
||||
static int tun_lock(FAR struct tun_device_s *priv);
|
||||
static void tun_unlock(FAR struct tun_device_s *priv);
|
||||
|
||||
/* Common TX logic */
|
||||
|
@ -249,9 +249,9 @@ static const struct file_operations g_tun_file_ops =
|
|||
* Name: tundev_lock
|
||||
****************************************************************************/
|
||||
|
||||
static void tundev_lock(FAR struct tun_driver_s *tun)
|
||||
static int tundev_lock(FAR struct tun_driver_s *tun)
|
||||
{
|
||||
nxsem_wait_uninterruptible(&tun->waitsem);
|
||||
return nxsem_wait_uninterruptible(&tun->waitsem);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -267,9 +267,9 @@ static void tundev_unlock(FAR struct tun_driver_s *tun)
|
|||
* Name: tun_lock
|
||||
****************************************************************************/
|
||||
|
||||
static void tun_lock(FAR struct tun_device_s *priv)
|
||||
static int tun_lock(FAR struct tun_device_s *priv)
|
||||
{
|
||||
nxsem_wait_uninterruptible(&priv->waitsem);
|
||||
return nxsem_wait_uninterruptible(&priv->waitsem);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -778,10 +778,21 @@ static void tun_txdone(FAR struct tun_device_s *priv)
|
|||
static void tun_poll_work(FAR void *arg)
|
||||
{
|
||||
FAR struct tun_device_s *priv = (FAR struct tun_device_s *)arg;
|
||||
int ret;
|
||||
|
||||
/* Perform the poll */
|
||||
|
||||
tun_lock(priv);
|
||||
ret = tun_lock(priv);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* This would indicate that the worker thread was canceled.. not a
|
||||
* likely event.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(ret == -ECANCELED);
|
||||
return;
|
||||
}
|
||||
|
||||
net_lock();
|
||||
|
||||
/* Check if there is room in the send another TX packet. We cannot perform
|
||||
|
@ -930,8 +941,15 @@ static int tun_ifdown(FAR struct net_driver_s *dev)
|
|||
static void tun_txavail_work(FAR void *arg)
|
||||
{
|
||||
FAR struct tun_device_s *priv = (FAR struct tun_device_s *)arg;
|
||||
int ret;
|
||||
|
||||
tun_lock(priv);
|
||||
ret = tun_lock(priv);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* Thread has been canceled, skip poll-related work */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if there is room to hold another network packet. */
|
||||
|
||||
|
@ -1152,6 +1170,7 @@ static int tun_close(FAR struct file *filep)
|
|||
FAR struct tun_driver_s *tun = inode->i_private;
|
||||
FAR struct tun_device_s *priv = filep->f_priv;
|
||||
int intf;
|
||||
int ret;
|
||||
|
||||
if (priv == NULL)
|
||||
{
|
||||
|
@ -1159,13 +1178,16 @@ static int tun_close(FAR struct file *filep)
|
|||
}
|
||||
|
||||
intf = priv - g_tun_devices;
|
||||
tundev_lock(tun);
|
||||
ret = tundev_lock(tun);
|
||||
if (ret >= 0)
|
||||
{
|
||||
tun->free_tuns |= (1 << intf);
|
||||
tun_dev_uninit(priv);
|
||||
|
||||
tun->free_tuns |= (1 << intf);
|
||||
tun_dev_uninit(priv);
|
||||
tundev_unlock(tun);
|
||||
}
|
||||
|
||||
tundev_unlock(tun);
|
||||
return OK;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -1176,17 +1198,26 @@ static ssize_t tun_write(FAR struct file *filep, FAR const char *buffer,
|
|||
size_t buflen)
|
||||
{
|
||||
FAR struct tun_device_s *priv = filep->f_priv;
|
||||
ssize_t ret;
|
||||
ssize_t nwritten = 0;
|
||||
int ret;
|
||||
|
||||
if (priv == NULL || buflen > CONFIG_NET_TUN_PKTSIZE)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tun_lock(priv);
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
/* Write must return immediately if interrupted by a signal (or if the
|
||||
* thread is canceled) and no data has yet been written.
|
||||
*/
|
||||
|
||||
ret = nxsem_wait(&priv->waitsem);
|
||||
if (ret < 0)
|
||||
{
|
||||
return nwritten == 0 ? (ssize_t)ret : nwritten;
|
||||
}
|
||||
|
||||
/* Check if there are free space to write */
|
||||
|
||||
if (priv->write_d_len == 0)
|
||||
|
@ -1200,7 +1231,7 @@ static ssize_t tun_write(FAR struct file *filep, FAR const char *buffer,
|
|||
tun_net_receive(priv);
|
||||
net_unlock();
|
||||
|
||||
ret = buflen;
|
||||
nwritten = buflen;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1208,18 +1239,17 @@ static ssize_t tun_write(FAR struct file *filep, FAR const char *buffer,
|
|||
|
||||
if ((filep->f_oflags & O_NONBLOCK) != 0)
|
||||
{
|
||||
ret = -EAGAIN;
|
||||
nwritten = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
|
||||
priv->write_wait = true;
|
||||
tun_unlock(priv);
|
||||
nxsem_wait(&priv->write_wait_sem);
|
||||
tun_lock(priv);
|
||||
}
|
||||
|
||||
tun_unlock(priv);
|
||||
return ret;
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -1230,29 +1260,38 @@ static ssize_t tun_read(FAR struct file *filep, FAR char *buffer,
|
|||
size_t buflen)
|
||||
{
|
||||
FAR struct tun_device_s *priv = filep->f_priv;
|
||||
ssize_t ret;
|
||||
ssize_t nread;
|
||||
int ret;
|
||||
|
||||
if (priv == NULL)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tun_lock(priv);
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
/* Read must return immediately if interrupted by a signal (or if the
|
||||
* thread is canceled) and no data has yet been read.
|
||||
*/
|
||||
|
||||
ret = nxsem_wait(&priv->waitsem);
|
||||
if (ret < 0)
|
||||
{
|
||||
return nread == 0 ? (ssize_t)ret : nread;
|
||||
}
|
||||
|
||||
/* Check if there are data to read in write buffer */
|
||||
|
||||
if (priv->write_d_len > 0)
|
||||
{
|
||||
if (buflen < priv->write_d_len)
|
||||
{
|
||||
ret = -EINVAL;
|
||||
nread = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(buffer, priv->write_buf, priv->write_d_len);
|
||||
ret = priv->write_d_len;
|
||||
nread = priv->write_d_len;
|
||||
priv->write_d_len = 0;
|
||||
|
||||
NETDEV_TXDONE(&priv->dev);
|
||||
|
@ -1266,12 +1305,12 @@ static ssize_t tun_read(FAR struct file *filep, FAR char *buffer,
|
|||
{
|
||||
if (buflen < priv->read_d_len)
|
||||
{
|
||||
ret = -EINVAL;
|
||||
nread = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(buffer, priv->read_buf, priv->read_d_len);
|
||||
ret = priv->read_d_len;
|
||||
nread = priv->read_d_len;
|
||||
priv->read_d_len = 0;
|
||||
|
||||
net_lock();
|
||||
|
@ -1284,18 +1323,17 @@ static ssize_t tun_read(FAR struct file *filep, FAR char *buffer,
|
|||
|
||||
if ((filep->f_oflags & O_NONBLOCK) != 0)
|
||||
{
|
||||
ret = -EAGAIN;
|
||||
nread = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
|
||||
priv->read_wait = true;
|
||||
tun_unlock(priv);
|
||||
nxsem_wait(&priv->read_wait_sem);
|
||||
tun_lock(priv);
|
||||
}
|
||||
|
||||
tun_unlock(priv);
|
||||
return ret;
|
||||
return nread;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -1306,7 +1344,7 @@ int tun_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup)
|
|||
{
|
||||
FAR struct tun_device_s *priv = filep->f_priv;
|
||||
pollevent_t eventset;
|
||||
int ret = OK;
|
||||
int ret;
|
||||
|
||||
/* Some sanity checking */
|
||||
|
||||
|
@ -1315,7 +1353,11 @@ int tun_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
tun_lock(priv);
|
||||
ret = tun_lock(priv);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (setup)
|
||||
{
|
||||
|
@ -1384,7 +1426,11 @@ static int tun_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
tundev_lock(tun);
|
||||
ret = tundev_lock(tun);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
free_tuns = tun->free_tuns;
|
||||
|
||||
|
|
|
@ -1,36 +1,20 @@
|
|||
/****************************************************************************
|
||||
* drivers/rwbuffer.c
|
||||
*
|
||||
* Copyright (C) 2009, 2011, 2013-2014, 2017, 2020 Gregory Nutt. All
|
||||
* rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
@ -79,9 +63,9 @@
|
|||
* Name: rwb_semtake
|
||||
****************************************************************************/
|
||||
|
||||
static void rwb_semtake(FAR sem_t *sem)
|
||||
static int rwb_semtake(FAR sem_t *sem)
|
||||
{
|
||||
nxsem_wait_uninterruptible(sem);
|
||||
return nxsem_wait_uninterruptible(sem);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -90,6 +74,34 @@ static void rwb_semtake(FAR sem_t *sem)
|
|||
|
||||
#define rwb_semgive(s) nxsem_post(s)
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rwb_forcetake
|
||||
*
|
||||
* Description:
|
||||
* This is just another wrapper but this one continues even if the thread
|
||||
* is canceled. This must be done in certain conditions where were must
|
||||
* continue in order to clean-up resources.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void rwb_forcetake(FAR sem_t *sem)
|
||||
{
|
||||
int ret;
|
||||
|
||||
do
|
||||
{
|
||||
ret = nxsem_wait_uninterruptible(sem);
|
||||
|
||||
/* The only expected error would -ECANCELED meaning that the
|
||||
* parent thread has been canceled. We have to continue and
|
||||
* terminate the poll in this case.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(ret == OK || ret == -ECANCELED);
|
||||
}
|
||||
while (ret < 0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rwb_overlap
|
||||
****************************************************************************/
|
||||
|
@ -182,7 +194,7 @@ static void rwb_wrtimeout(FAR void *arg)
|
|||
* worker thread.
|
||||
*/
|
||||
|
||||
rwb_semtake(&rwb->wrsem);
|
||||
rwb_forcetake(&rwb->wrsem);
|
||||
rwb_wrflush(rwb);
|
||||
rwb_semgive(&rwb->wrsem);
|
||||
}
|
||||
|
@ -410,7 +422,7 @@ int rwb_invalidate_writebuffer(FAR struct rwbuffer_s *rwb,
|
|||
|
||||
finfo("startblock=%d blockcount=%p\n", startblock, blockcount);
|
||||
|
||||
rwb_semtake(&rwb->wrsem);
|
||||
rwb_forcetake(&rwb->wrsem);
|
||||
|
||||
/* Now there are five cases:
|
||||
*
|
||||
|
@ -547,7 +559,7 @@ int rwb_invalidate_readahead(FAR struct rwbuffer_s *rwb,
|
|||
|
||||
finfo("startblock=%d blockcount=%p\n", startblock, blockcount);
|
||||
|
||||
rwb_semtake(&rwb->rhsem);
|
||||
rwb_forcetake(&rwb->rhsem);
|
||||
|
||||
/* Now there are five cases:
|
||||
*
|
||||
|
@ -781,7 +793,14 @@ static ssize_t rwb_read_(FAR struct rwbuffer_s *rwb, off_t startblock,
|
|||
|
||||
/* Loop until we have read all of the requested blocks */
|
||||
|
||||
rwb_semtake(&rwb->rhsem);
|
||||
ret = nxsem_wait(&rwb->rhsem);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* Return EINTR or ECANCELED */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (remaining = nblocks; remaining > 0; )
|
||||
{
|
||||
/* Is there anything in the read-ahead buffer? */
|
||||
|
|
Loading…
Reference in a new issue