diff options
Diffstat (limited to 'drivers/staging/kpc2000/kpc_i2c/fileops.c')
-rw-r--r-- | drivers/staging/kpc2000/kpc_i2c/fileops.c | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/drivers/staging/kpc2000/kpc_i2c/fileops.c b/drivers/staging/kpc2000/kpc_i2c/fileops.c new file mode 100644 index 000000000000..e749c0994491 --- /dev/null +++ b/drivers/staging/kpc2000/kpc_i2c/fileops.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: GPL-2.0+ +#if 0 +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kernel.h> /* printk() */ +#include <linux/slab.h> /* kmalloc() */ +#include <linux/fs.h> /* everything... */ +#include <linux/errno.h> /* error codes */ +#include <linux/types.h> /* size_t */ +#include <linux/cdev.h> +#include <asm/uaccess.h> /* copy_*_user */ + +#include "i2c_driver.h" + +int i2c_cdev_open(struct inode *inode, struct file *filp) +{ + struct i2c_device *lddev; + + if(NULL == inode) { + //printk(KERN_WARNING "<pl_i2c> i2c_cdev_open: inode is a NULL pointer\n"); + DBG_PRINT(KERN_WARNING, "i2c_cdev_open: inode is a NULL pointer\n"); + return -EINVAL; + } + if(NULL == filp) { + //printk(KERN_WARNING "<pl_i2c> i2c_cdev_open: filp is a NULL pointer\n"); + DBG_PRINT(KERN_WARNING, "i2c_cdev_open: filp is a NULL pointer\n"); + return -EINVAL; + } + + lddev = container_of(inode->i_cdev, struct i2c_device, cdev); + //printk(KERN_DEBUG "<pl_i2c> i2c_cdev_open(filp = [%p], lddev = [%p])\n", filp, lddev); + DBG_PRINT(KERN_DEBUG, "i2c_cdev_open(filp = [%p], lddev = [%p])\n", filp, lddev); + + filp->private_data = lddev; /* so other methods can access it */ + + return 0; /* success */ +} + +int i2c_cdev_close(struct inode *inode, struct file *filp) +{ + struct i2c_device *lddev; + + if(NULL == inode) { + //printk(KERN_WARNING "<pl_i2c> i2c_cdev_close: inode is a NULL pointer\n"); + DBG_PRINT(KERN_WARNING, "i2c_cdev_close: inode is a NULL pointer\n"); + return -EINVAL; + } + if(NULL == filp) { + //printk(KERN_WARNING "<pl_i2c> i2c_cdev_close: filp is a NULL pointer\n"); + DBG_PRINT(KERN_WARNING, "i2c_cdev_close: filp is a NULL pointer\n"); + return -EINVAL; + } + + lddev = filp->private_data; + //printk(KERN_DEBUG "<pl_i2c> i2c_cdev_close(filp = [%p], lddev = [%p])\n", filp, lddev); + DBG_PRINT(KERN_DEBUG, "i2c_cdev_close(filp = [%p], lddev = [%p])\n", filp, lddev); + + return 0; +} + +ssize_t i2c_cdev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + size_t copy; + ssize_t ret = 0; + int err = 0; + u64 read_val; + char tmp_buf[48] = { 0 }; + struct i2c_device *lddev = filp->private_data; + + if(NULL == filp) { + //printk(KERN_WARNING "<pl_i2c> i2c_cdev_read: filp is a NULL pointer\n"); + DBG_PRINT(KERN_WARNING, "i2c_cdev_read: filp is a NULL pointer\n"); + return -EINVAL; + } + if(NULL == buf) { + //printk(KERN_WARNING "<pl_i2c> i2c_cdev_read: buf is a NULL pointer\n"); + DBG_PRINT(KERN_WARNING, "i2c_cdev_read: buf is a NULL pointer\n"); + return -EINVAL; + } + if(NULL == f_pos) { + //printk(KERN_WARNING "<pl_i2c> i2c_cdev_read: f_pos is a NULL pointer\n"); + DBG_PRINT(KERN_WARNING, "i2c_cdev_read: f_pos is a NULL pointer\n"); + return -EINVAL; + } + + if(count < sizeof(tmp_buf)) { + //printk(KERN_INFO "<pl_i2c> i2c_cdev_read: buffer is too small (count = %d, should be at least %d bytes)\n", (int)count, (int)sizeof(tmp_buf)); + DBG_PRINT(KERN_INFO, "i2c_cdev_read: buffer is too small (count = %d, should be at least %d bytes)\n", (int)count, (int)sizeof(tmp_buf)); + return -EINVAL; + } + if(((*f_pos * 8) + lddev->pldev->resource[0].start) > lddev->pldev->resource[0].end) { + //printk(KERN_INFO "<pl_i2c> i2c_cdev_read: bad read addr %016llx\n", (*f_pos * 8) + lddev->pldev->resource[0].start); + DBG_PRINT(KERN_INFO, "i2c_cdev_read: bad read addr %016llx\n", (*f_pos * 8) + lddev->pldev->resource[0].start); + //printk(KERN_INFO "<pl_i2c> i2c_cdev_read: addr end %016llx\n", lddev->pldev->resource[0].end); + DBG_PRINT(KERN_INFO, "i2c_cdev_read: addr end %016llx\n", lddev->pldev->resource[0].end); + //printk(KERN_INFO "<pl_i2c> i2c_cdev_read: EOF reached\n"); + DBG_PRINT(KERN_INFO, "i2c_cdev_read: EOF reached\n"); + return 0; + } + + down_read(&lddev->rw_sem); + + read_val = *(lddev->regs + *f_pos); + copy = clamp_t(size_t, count, 1, sizeof(tmp_buf)); + copy = scnprintf(tmp_buf, copy, "reg: 0x%x val: 0x%llx\n", (unsigned int)*f_pos, read_val); + err = copy_to_user(buf, tmp_buf, copy); + if(err) { + //printk(KERN_INFO "<pl_i2c> i2c_cdev_read: could not copy to user (err = %d)\n", err); + DBG_PRINT(KERN_INFO, "i2c_cdev_read: could not copy to user (err = %d)\n", err); + return -EINVAL; + } + + ret = (ssize_t)copy; + (*f_pos)++; + + up_read(&lddev->rw_sem); + + return ret; +} + +ssize_t i2c_cdev_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) +{ + u8 reg; + u8 val; + char tmp[8] = { 0 }; + struct i2c_device *lddev = filp->private_data; + + if(NULL == filp) { + //printk(KERN_WARNING "<pl_i2c> i2c_cdev_write: filp is a NULL pointer\n"); + DBG_PRINT(KERN_WARNING, "i2c_cdev_write: filp is a NULL pointer\n"); + return -EINVAL; + } + if(NULL == buf) { + //printk(KERN_WARNING "<pl_i2c> i2c_cdev_write: buf is a NULL pointer\n"); + DBG_PRINT(KERN_WARNING, "i2c_cdev_write: buf is a NULL pointer\n"); + return -EINVAL; + } + if(NULL == f_pos) { + //printk(KERN_WARNING "<pl_i2c> i2c_cdev_write: f_pos is a NULL pointer\n"); + DBG_PRINT(KERN_WARNING, "i2c_cdev_write: f_pos is a NULL pointer\n"); + return -EINVAL; + } + + //printk(KERN_DEBUG "<pl_i2c> i2c_cdev_write(filp = [%p], lddev = [%p])\n", filp, lddev); + DBG_PRINT(KERN_DEBUG, "i2c_cdev_write(filp = [%p], lddev = [%p])\n", filp, lddev); + + down_write(&lddev->rw_sem); + + if(count >= 2) { + if(copy_from_user(tmp, buf, 2)) { + return -EFAULT; + } + + reg = tmp[0] - '0'; + val = tmp[1] - '0'; + + //printk(KERN_DEBUG " reg = %d val = %d\n", reg, val); + DBG_PRINT(KERN_DEBUG, " reg = %d val = %d\n", reg, val); + + if(reg >= 0 && reg < 16) { + //printk(KERN_DEBUG " Writing 0x%x to %p\n", val, lddev->regs + reg); + DBG_PRINT(KERN_DEBUG, " Writing 0x%x to %p\n", val, lddev->regs + reg); + *(lddev->regs + reg) = val; + } + } + + (*f_pos)++; + + up_write(&lddev->rw_sem); + + return count; +} + +struct file_operations i2c_fops = { + .owner = THIS_MODULE, + .open = i2c_cdev_open, + .release = i2c_cdev_close, + .read = i2c_cdev_read, + .write = i2c_cdev_write, +}; +#endif |