diff --git a/drivers/lcd/ft80x.h b/drivers/lcd/ft80x.h index c8de119a005..2880f3454f8 100644 --- a/drivers/lcd/ft80x.h +++ b/drivers/lcd/ft80x.h @@ -361,7 +361,10 @@ struct ft80x_dev_s FAR const struct ft80x_config_s *lower; /* Cached lower half instance */ uint32_t frequency; /* Effective frequency */ sem_t exclsem; /* Mutual exclusion semaphore */ - uint8_t crefs; /* Open count */ +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS + uint8_t crefs; /* Number of open references */ + bool unlinked; /* True if the driver has been unlinked */ +#endif }; /**************************************************************************** diff --git a/drivers/lcd/ft80x_base.c b/drivers/lcd/ft80x_base.c index 2a371a092a2..7a2238724e3 100644 --- a/drivers/lcd/ft80x_base.c +++ b/drivers/lcd/ft80x_base.c @@ -90,6 +90,10 @@ * Private Function Prototypes ****************************************************************************/ +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS +static void ft80x_destroy(FAR struct ft80x_dev_s *priv); +#endif + /* Character driver methods */ static int ft80x_open(FAR struct file *filep); @@ -104,6 +108,9 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg); static int ft80x_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup); #endif +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS +static int ft80x_unlink(FAR struct inode *inode); +#endif /* Initialization */ @@ -125,7 +132,7 @@ static const struct file_operations g_ft80x_fops = , ft80x_poll /* poll */ #endif #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS - , NULL /* unlink */ + , ft80x_unlink /* unlink */ #endif }; @@ -133,6 +140,35 @@ static const struct file_operations g_ft80x_fops = * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: ft80x_destroy + * + * Description: + * The driver has been unlinked... clean up as best we can. + * + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS +static void ft80x_destroy(FAR struct ft80x_dev_s *priv) +{ + /* If the lower half driver provided a destroy method, then call that + * method now in order order to clean up resources used by the lower-half + * driver. + */ + + DEBUGASSERT(priv != NULL && priv->lower != NULL); + if (priv->lower->destroy != NULL) + { + priv->lower->destroy(priv->lower); + } + + /* Then free our container */ + + sem_destroy(&priv->exclsem); + kmm_free(priv); +} +#endif + /**************************************************************************** * Name: ft80x_open * @@ -143,6 +179,7 @@ static const struct file_operations g_ft80x_fops = static int ft80x_open(FAR struct file *filep) { +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS FAR struct inode *inode; FAR struct ft80x_dev_s *priv; uint8_t tmp; @@ -184,6 +221,9 @@ errout_with_sem: errout: return ret; +#else + return OK; +#endif } /**************************************************************************** @@ -196,6 +236,7 @@ errout: static int ft80x_close(FAR struct file *filep) { +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS FAR struct inode *inode; FAR struct ft80x_dev_s *priv; int ret; @@ -215,10 +256,25 @@ static int ft80x_close(FAR struct file *filep) goto errout; } - /* Decrement the references to the driver. */ + /* Will the count decrement to zero? */ - if (priv->crefs > 1) + if (priv->crefs <= 1) { + /* Yes.. if the driver has been unlinked, then we need to destroy the + * driver instance. + */ + + priv->crefs = 0; + if (priv->unlinked) + { + ft80x_destroy(priv); + return OK; + } + } + else + { + /* NO.. decrement the number of references to the driver. */ + priv->crefs--; } @@ -227,6 +283,9 @@ static int ft80x_close(FAR struct file *filep) errout: return ret; +#else + return OK; +#endif } /**************************************************************************** @@ -276,6 +335,10 @@ static ssize_t ft80x_write(FAR struct file *filep, FAR const char *buffer, return ret; } + /* Note that there is no check if the driver was opened read-only. That + * would be a silly thing to do. + */ + /* The write method is functionally equivalent to the FT80XIOC_PUTDISPLAYLIST * IOCTL command: It simply copies the display list in the user buffer to * the FT80x display list memory. @@ -424,6 +487,39 @@ static int ft80x_poll(FAR struct file *filep, FAR struct pollfd *fds, } #endif +/**************************************************************************** + * Name: ft80x_unlink + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS +static int ft80x_unlink(FAR struct inode *inode) +{ + FAR struct ft80x_dev_s *priv; + + /* Get the reference to our internal state structure from the inode + * structure. + */ + + DEBUGASSERT(inode && inode->i_private); + priv = inode->i_private; + + /* Indicate that the driver has been unlinked */ + + priv->unlinked = true; + + /* If there are no further open references to the driver, then commit + * Hara-Kiri now. + */ + + if (priv->crefs == 0) + { + ft80x_destroy(priv); + } + + return OK; +} +#endif + /**************************************************************************** * Name: ft80x_initialize * diff --git a/include/nuttx/lcd/ft80x.h b/include/nuttx/lcd/ft80x.h index 973bb07ba94..92ae3d77761 100644 --- a/include/nuttx/lcd/ft80x.h +++ b/include/nuttx/lcd/ft80x.h @@ -470,13 +470,17 @@ struct ft80x_config_s * enable - Enable or disable the GPIO interrupt * clear - Acknowledge/clear any pending GPIO interrupt * pwrdown - Power down the FT80X + * destroy - The driver has been unlinked. Cleanup as necessary. */ - int (*attach)(FAR const struct ft80x_config_s *state, xcpt_t isr, - FAR void *arg); - void (*enable)(FAR const struct ft80x_config_s *state, bool enable); - void (*clear)(FAR const struct ft80x_config_s *state); - bool (*pwrdown)(FAR const struct ft80x_config_s *state, bool pwrdown); + CODE int (*attach)(FAR const struct ft80x_config_s *state, xcpt_t isr, + FAR void *arg); + CODE void (*enable)(FAR const struct ft80x_config_s *state, bool enable); + CODE void (*clear)(FAR const struct ft80x_config_s *state); + CODE bool (*pwrdown)(FAR const struct ft80x_config_s *state, bool pwrdown); +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS + CODE void (*destroy)(FAR const struct ft80x_config_s *state); +#endif }; /* This structure describes one generic display list command */