Contributors: 1
Author Tokens Token Proportion Commits Commit Proportion
Greg Kroah-Hartman 87 100.00% 1 100.00%
Total 87 1


// 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