[02/10] watchdog: Add read capability

Message ID 20200620174907.20229-3-minyard@acm.org
State New
Headers show
Series
  • Convert the IPMI watchdog to use the watchdog
Related show

Commit Message

Corey Minyard June 20, 2020, 5:48 p.m.
From: Corey Minyard <cminyard@mvista.com>

Allow read, poll, and fasync calls on the watchdog device to be passed
to the driver.  This is so the IPMI driver can be moved over to the
watchdog framework, as it has the ability to have a read return when
data comes in on the watchdog.

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
 drivers/watchdog/watchdog_dev.c | 45 +++++++++++++++++++++++++++++++++
 include/linux/watchdog.h        |  8 ++++++
 2 files changed, 53 insertions(+)

Patch

diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index 7e4cd34a8c20..45a0a4fe731d 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -698,6 +698,48 @@  static ssize_t watchdog_write(struct file *file, const char __user *data,
 	return len;
 }
 
+/*
+ *	watchdog_read: Pass a read on to the device if it accepts it
+ *	@file: file handle to the device
+ *	@buf: the buffer to read into
+ *	@count: the size of buf in bytes
+ *      @ppos: pointer to the file offset
+ *
+ *	The watchdog API defines a common set of functions for all watchdogs
+ *	according to their available features.
+ */
+
+static ssize_t watchdog_read(struct file *file, char __user *buf,
+			     size_t count, loff_t *ppos)
+{
+	struct watchdog_core_data *wd_data = file->private_data;
+	struct watchdog_device *wdd = wd_data->wdd;
+
+	if (!wdd->ops->read)
+		return -EINVAL;
+	return wdd->ops->read(wdd, file, buf, count, ppos);
+}
+
+static __poll_t watchdog_poll(struct file *file, poll_table *wait)
+{
+	struct watchdog_core_data *wd_data = file->private_data;
+	struct watchdog_device *wdd = wd_data->wdd;
+
+	if (!wdd->ops->poll)
+		return DEFAULT_POLLMASK;
+	return wdd->ops->poll(wdd, file, wait);
+}
+
+static int watchdog_fasync(int fd, struct file *file, int on)
+{
+	struct watchdog_core_data *wd_data = file->private_data;
+	struct watchdog_device *wdd = wd_data->wdd;
+
+	if (!wdd->ops->fasync)
+		return 0;
+	return wdd->ops->fasync(wdd, fd, file, on);
+}
+
 /*
  *	watchdog_ioctl: handle the different ioctl's for the watchdog device.
  *	@file: file handle to the device
@@ -951,6 +993,9 @@  static int watchdog_release(struct inode *inode, struct file *file)
 static const struct file_operations watchdog_fops = {
 	.owner		= THIS_MODULE,
 	.write		= watchdog_write,
+	.read		= watchdog_read,
+	.poll		= watchdog_poll,
+	.fasync		= watchdog_fasync,
 	.unlocked_ioctl	= watchdog_ioctl,
 	.compat_ioctl	= compat_ptr_ioctl,
 	.open		= watchdog_open,
diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h
index 1464ce6ffa31..36f99c8c973e 100644
--- a/include/linux/watchdog.h
+++ b/include/linux/watchdog.h
@@ -15,6 +15,7 @@ 
 #include <linux/device.h>
 #include <linux/kernel.h>
 #include <linux/notifier.h>
+#include <linux/poll.h>
 #include <uapi/linux/watchdog.h>
 
 struct watchdog_ops;
@@ -34,6 +35,9 @@  struct watchdog_governor;
  * @get_timeleft:The routine that gets the time left before a reset (in seconds).
  * @restart:	The routine for restarting the machine.
  * @ioctl:	The routines that handles extra ioctl calls.
+ * @read:	Call this is not NULL and a read comes in on the watchdog dev.
+ * @poll:	Call this is not NULL and a poll comes in on the watchdog dev.
+ * @fasync:	Call this is not NULL and a fasync comes in on the watchdog dev.
  *
  * The watchdog_ops structure contains a list of low-level operations
  * that control a watchdog device. It also contains the module that owns
@@ -53,6 +57,10 @@  struct watchdog_ops {
 	unsigned int (*get_timeleft)(struct watchdog_device *);
 	int (*restart)(struct watchdog_device *, unsigned long, void *);
 	long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
+	ssize_t (*read)(struct watchdog_device *, struct file *, char __user *,
+			size_t, loff_t *);
+	__poll_t (*poll)(struct watchdog_device *, struct file *, poll_table *);
+	int (*fasync)(struct watchdog_device *, int, struct file *, int);
 };
 
 /** struct watchdog_device - The structure that defines a watchdog device