diff --git a/drivers/timers/timer.c b/drivers/timers/timer.c index ebe58dcd2f..16c85fa5d7 100644 --- a/drivers/timers/timer.c +++ b/drivers/timers/timer.c @@ -65,8 +65,13 @@ struct timer_upperhalf_s { - uint8_t crefs; /* The number of times the device has been opened */ - FAR char *path; /* Registration path */ + uint8_t crefs; /* The number of times the device has been opened */ +#ifdef HAVE_NOTIFICATION + uint8_t signal; /* The signal number to use in the notification */ + pid_t pid; /* The ID of the task/thread to receive the signal */ + FAR void *arg; /* An argument to pass with the signal */ +#endif + FAR char *path; /* Registration path */ /* The contained lower-half driver */ @@ -77,6 +82,12 @@ struct timer_upperhalf_s * Private Function Prototypes ****************************************************************************/ +#ifdef HAVE_NOTIFICATION + /* REVISIT: This function prototype is insufficient to support signaling */ + +static bool timer_notifier(FAR uint32_t *next_interval_us); +#endif + static int timer_open(FAR struct file *filep); static int timer_close(FAR struct file *filep); static ssize_t timer_read(FAR struct file *filep, FAR char *buffer, @@ -110,6 +121,36 @@ static const struct file_operations g_timerops = * Private Functions ****************************************************************************/ +/************************************************************************************ + * Name: timer_notifier + * + * Description: + * Notify the application via a signal when the timer interrupt occurs + * + * REVISIT: This function prototype is insufficient to support signaling + * + ************************************************************************************/ + +#ifdef HAVE_NOTIFICATION +static bool timer_notifier(FAR uint32_t *next_interval_us) +{ + FAR struct timer_upperhalf_s *upper = HOW?; +#ifdef CONFIG_CAN_PASS_STRUCTS + union sigval value; +#endif + int ret; + +#ifdef CONFIG_CAN_PASS_STRUCTS + value.sival_ptr = upper->arg; + ret = sigqueue(upper->pid, upper->signo, value); +#else + ret = sigqueue(upper->pid, upper->signo, upper->arg); +#endif + + return ret == OK; +} +#endif + /************************************************************************************ * Name: timer_open * @@ -120,10 +161,10 @@ static const struct file_operations g_timerops = static int timer_open(FAR struct file *filep) { - FAR struct inode *inode = filep->f_inode; + FAR struct inode *inode = filep->f_inode; FAR struct timer_upperhalf_s *upper = inode->i_private; - uint8_t tmp; - int ret; + uint8_t tmp; + int ret; tmrinfo("crefs: %d\n", upper->crefs); @@ -322,6 +363,36 @@ static int timer_ioctl(FAR struct file *filep, int cmd, unsigned long arg) } break; +#ifdef HAVE_NOTIFICATION + /* cmd: TCIOC_NOTIFICATION + * Description: Notify application via a signal when the timer expires. + * Argument: signal number + * + * NOTE: This ioctl cannot be support in the kernel build mode. In that + * case direct callbacks from kernel space into user space is forbidden. + */ + + case TCIOC_NOTIFICATION: + { + FAR struct timer_notify_s *notify = + (FAR struct timer_notify_s *)((uintptr_t)arg) + + if (notify != NULL) + { + upper->signo = notify->signal; + upper->get = notify->signal; + upper->arg = noify->arg; + + ret = timer_sethandler((FAR void *handle)upper, timer_notifier, NULL); + } + else + { + ret = -EINVAL; + } + } + break; +#endif + /* Any unrecognized IOCTL commands might be platform-specific ioctl commands */ default: @@ -500,7 +571,7 @@ int timer_sethandler(FAR void *handle, tccb_t newhandler, FAR struct timer_upperhalf_s *upper; FAR struct timer_lowerhalf_s *lower; tccb_t tmphandler; - + /* Recover the pointer to the upper-half driver state */ upper = (FAR struct timer_upperhalf_s *)handle; diff --git a/include/nuttx/timers/timer.h b/include/nuttx/timers/timer.h index 77946327fc..eb2830bd56 100644 --- a/include/nuttx/timers/timer.h +++ b/include/nuttx/timers/timer.h @@ -52,6 +52,12 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ +/* It would require some interface modifcations in order to support + * notifications. + */ + +#undef HAVE_NOTIFICATION + /* IOCTL Commands ***********************************************************/ /* The timer driver uses a standard character driver framework. However, * since the timer driver is a device control interface and not a data @@ -60,14 +66,18 @@ * * These are detected and handled by the "upper half" timer driver. * - * TCIOC_START - Start the timer - * Argument: Ignored - * TCIOC_STOP - Stop the timer - * Argument: Ignored - * TCIOC_GETSTATUS - Get the status of the timer. - * Argument: A writeable pointer to struct timer_status_s. - * TCIOC_SETTIMEOUT - Reset the timer timeout to this value - * Argument: A 32-bit timeout value in microseconds. + * TCIOC_START - Start the timer + * Argument: Ignored + * TCIOC_STOP - Stop the timer + * Argument: Ignored + * TCIOC_GETSTATUS - Get the status of the timer. + * Argument: A writeable pointer to struct timer_status_s. + * TCIOC_SETTIMEOUT - Reset the timer timeout to this value + * Argument: A 32-bit timeout value in microseconds. + * TCIOC_NOTIFICATION - Set up to notify an application via a signal when + * the timer expires. + * Argument: A read-only pointer to an instance of + * stuct timer_notify_s. * * WARNING: May change TCIOC_SETTIMEOUT to pass pointer to 64bit nanoseconds * or timespec structure. @@ -82,18 +92,20 @@ * range. */ -#define TCIOC_START _TCIOC(0x0001) -#define TCIOC_STOP _TCIOC(0x0002) -#define TCIOC_GETSTATUS _TCIOC(0x0003) -#define TCIOC_SETTIMEOUT _TCIOC(0x0004) -#define TCIOC_SETHANDLER _TCIOC(0x0005) +#define TCIOC_START _TCIOC(0x0001) +#define TCIOC_STOP _TCIOC(0x0002) +#define TCIOC_GETSTATUS _TCIOC(0x0003) +#define TCIOC_SETTIMEOUT _TCIOC(0x0004) +#ifdef HAVE_NOTIFICATION +#define TCIOC_NOTIFICATION _TCIOC(0x0005) +#endif /* Bit Settings *************************************************************/ /* Bit settings for the struct timer_status_s flags field */ -#define TCFLAGS_ACTIVE (1 << 0) /* 1=The timer is running */ -#define TCFLAGS_HANDLER (1 << 1) /* 1=Call the user function when the - * timer expires */ +#define TCFLAGS_ACTIVE (1 << 0) /* 1=The timer is running */ +#define TCFLAGS_HANDLER (1 << 1) /* 1=Call the user function when the + * timer expires */ /**************************************************************************** * Public Types @@ -117,6 +129,17 @@ struct timer_status_s * (in microseconds) */ }; +#ifdef HAVE_NOTIFICATION +/* This is the type of the argument passed to the TCIOC_NOTIFICATION ioctl */ + +struct timer_notify_s +{ + FAR void *arg; /* An argument to pass with the signal */ + pid_t pid; /* The ID of the task/thread to receive the signal */ + uint8_t signal; /* The signal number to use in the notification */ +}; +#endif + /* This structure provides the "lower-half" driver operations available to * the "upper-half" driver. */