[PATCH 04/12] misc: xilinx_sdfec: Add open, close and ioctl

From: Dragan Cvetic
Date: Tue Mar 19 2019 - 08:04:47 EST


Add char device interface per DT node present and support
file operations:
- open(), which keeps only one open per device at a time,
- close(), which release the open for this device,
- ioctl(), which provides infrastructure for a specific driver
control.

Reviewed-by: Michal Simek <michal.simek@xxxxxxxxxx>
Tested-by: Dragan Cvetic <dragan.cvetic@xxxxxxxxxx>
Signed-off-by: Derek Kiernan <derek.kiernan@xxxxxxxxxx>
Signed-off-by: Dragan Cvetic <dragan.cvetic@xxxxxxxxxx>
---
drivers/misc/xilinx_sdfec.c | 79 ++++++++++++++++++++++++++++++++++++++++
include/uapi/misc/xilinx_sdfec.h | 4 ++
2 files changed, 83 insertions(+)

diff --git a/drivers/misc/xilinx_sdfec.c b/drivers/misc/xilinx_sdfec.c
index a52a5c6..3407de4 100644
--- a/drivers/misc/xilinx_sdfec.c
+++ b/drivers/misc/xilinx_sdfec.c
@@ -81,8 +81,87 @@ struct xsdfec_dev {
struct xsdfec_clks clks;
};

+static int xsdfec_dev_open(struct inode *iptr, struct file *fptr)
+{
+ struct xsdfec_dev *xsdfec;
+
+ xsdfec = container_of(iptr->i_cdev, struct xsdfec_dev, xsdfec_cdev);
+ if (!xsdfec)
+ return -EAGAIN;
+
+ /* Only one open per device at a time */
+ if (!atomic_dec_and_test(&xsdfec->open_count)) {
+ atomic_inc(&xsdfec->open_count);
+ return -EBUSY;
+ }
+
+ fptr->private_data = xsdfec;
+ return 0;
+}
+
+static int xsdfec_dev_release(struct inode *iptr, struct file *fptr)
+{
+ struct xsdfec_dev *xsdfec;
+
+ xsdfec = container_of(iptr->i_cdev, struct xsdfec_dev, xsdfec_cdev);
+ if (!xsdfec)
+ return -EAGAIN;
+
+ atomic_inc(&xsdfec->open_count);
+ return 0;
+}
+
+static long xsdfec_dev_ioctl(struct file *fptr, unsigned int cmd,
+ unsigned long data)
+{
+ struct xsdfec_dev *xsdfec = fptr->private_data;
+ void __user *arg = NULL;
+ int rval = -EINVAL;
+ int err = 0;
+
+ if (!xsdfec)
+ return rval;
+
+ if (_IOC_TYPE(cmd) != XSDFEC_MAGIC) {
+ dev_err(xsdfec->dev, "Not a xilinx sdfec ioctl");
+ return -ENOTTY;
+ }
+
+ /* check if ioctl argument is present and valid */
+ if (_IOC_DIR(cmd) != _IOC_NONE) {
+ arg = (void __user *)data;
+ if (!arg) {
+ dev_err(xsdfec->dev,
+ "xilinx sdfec ioctl argument is NULL Pointer");
+ return rval;
+ }
+ }
+
+ /* Access check of the argument if present */
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ err = !access_ok((void *)arg, _IOC_SIZE(cmd));
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ err = !access_ok((void *)arg, _IOC_SIZE(cmd));
+
+ if (err) {
+ dev_err(xsdfec->dev, "Invalid xilinx sdfec ioctl argument");
+ return -EFAULT;
+ }
+
+ switch (cmd) {
+ default:
+ /* Should not get here */
+ dev_err(xsdfec->dev, "Undefined SDFEC IOCTL");
+ break;
+ }
+ return rval;
+}
+
static const struct file_operations xsdfec_fops = {
.owner = THIS_MODULE,
+ .open = xsdfec_dev_open,
+ .release = xsdfec_dev_release,
+ .unlocked_ioctl = xsdfec_dev_ioctl,
};

static int xsdfec_clk_init(struct platform_device *pdev,
diff --git a/include/uapi/misc/xilinx_sdfec.h b/include/uapi/misc/xilinx_sdfec.h
index 5543163..5de0add 100644
--- a/include/uapi/misc/xilinx_sdfec.h
+++ b/include/uapi/misc/xilinx_sdfec.h
@@ -39,4 +39,8 @@ struct xsdfec_config {
s32 fec_id;
};

+/*
+ * XSDFEC IOCTL List
+ */
+#define XSDFEC_MAGIC 'f'
#endif /* __XILINX_SDFEC_H__ */
--
2.7.4

This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.