From 03f3d956103dd6149a3c62ab67ec323386e32862 Mon Sep 17 00:00:00 2001 From: stamrakar Date: Mon, 4 Nov 2024 16:54:57 -0700 Subject: [PATCH] Supporting llseek() and unlocked_ioctl() --- aesd-char-driver/main.c | 104 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 1 deletion(-) diff --git a/aesd-char-driver/main.c b/aesd-char-driver/main.c index 6bbb86b..1413277 100644 --- a/aesd-char-driver/main.c +++ b/aesd-char-driver/main.c @@ -28,7 +28,7 @@ #include #include // file_operations - +#include "aesd_ioctl.h" #include "aesdchar.h" @@ -71,6 +71,106 @@ int aesd_release(struct inode *inode, struct file *filp) return 0; } +/** + * "The llseek method is used to change the current read/write position + * in a file, and the new position is returne as a (positive) return value. + * The loff_t parameter is a "long offset" and is at least 64 bits wide + * even on 32-bit platforms. Errors are signaled by a negative return value. + * If this function pointer is NULL, seek calls will modify the position + * counter in the file structure in potentially unpredictable ways." + * Linux Device Drivers Chapter 3, J. Corbet, A Rubini, G. Kroah-Hartman + */ +loff_t aesd_llseek(struct file *filp, loff_t offset, int whence) +{ + ssize_t retval; + loff_t fsl; + loff_t circbuffsize=0; + struct aesd_dev *dev = NULL; + struct aesd_buffer_entry *entry = NULL; + uint8_t stread; + if (filp == NULL) + { + retval = -EINVAL; + PDEBUG("file pointer filp NULL, returning %zu", retval); + goto errout; + } + + dev = filp->private_data; + + if (mutex_lock_interruptible(&dev->bufferlock)) + { + retval = -ERESTARTSYS; + PDEBUG("mutex lock interruptible, returning %zu", retval); + goto errout; + } + + AESD_CIRCULAR_BUFFER_FOREACH(entry, &(aesd_device.circular), stread) + { + if(entry->buffptr != NULL) + circbuffsize += entry->size; + } + + //need to get the total size of all content of the circular buffer + fsl = fixed_size_llseek(filp, offset, whence, circbuffsize); + if (fsl == -EINVAL) + { + retval = fsl; + PDEBUG("fixed_size_llseek() returned -EINVAL. %zu", retval); + goto unlockout; + } + retval = fsl; + //filp->f_pos += fsl; + return retval; + + unlockout: + mutex_unlock(&dev->bufferlock); + errout: + return retval; +} + + +/** + * Adjust the file offset (f_pos) parameter of @param filp based on the location specified by + * @param write_cmd (the zero referenced command to locate) and @param write_cmd_offset + * (the zero referenced offset into the command) + * @return 0 if successful, negative if error occurred: + * -ERESTARTSYS if mutex could not be obtained + * -EINVAL if write command or write_cmd_offset was out of range. + */ +static long aesd_adjust_file_offset(struct file *filp, unsigned int write_cmd, unsigned int write_cmd_offset) +{ + +} + +int aesd_unlocked_ioctl(struct inode *node, struct file *filp, unsigned int vala, unsigned long valb) +{ + ssize_t retval; + if (filp == NULL) + { + retval = -EINVAL; + PDEBUG("file pointer filp NULL, returning %zu", retval); + goto errout; + } + + case AESDCHAR_IOCSEEKTO + { + struct aesd_seekto seekto; + if (copy_from_user(&seekto, (const void __user *)arg, sizeof(seekto)) != 0) { + retval = EFAULT; + } else { + retval = aesd_adjust_file_offset(filp, seekto.write_cmd, seekto.write_cmd_offset); + } + break; + } + + default: + break; + + + errout: + return retval; +} + ssize_t aesd_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { @@ -243,6 +343,8 @@ struct file_operations aesd_fops = { .write = aesd_write, .open = aesd_open, .release = aesd_release, + .llseek = aesd_llseek, + .unlocked_ioctl = aesd_unlocked_ioctl, }; static int aesd_setup_cdev(struct aesd_dev *dev)