// SPDX-License-Identifier: GPL-2.0+ #if 0 #include #include #include /* printk() */ #include /* kmalloc() */ #include /* everything... */ #include /* error codes */ #include /* size_t */ #include #include /* 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 " 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 " 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 " 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 " 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 " 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 " 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 " 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 " 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 " 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 " 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 " 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 " 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 " 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 " 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 " 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 " 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 " 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 " 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