eeprom驅動實例(35內核下)

#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/smp_lock.h>
#include <linux/jiffies.h>
#include <linux/slab.h>  /* kzalloc() */
#include <linux/sysfs.h> /* sysfs_create_group() */
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/string.h>

struct e2prom_priv_t {
 u8 dev_addr;
 u8 reg;
 u8 data;
};
struct e2prom_priv_t *e2prom_priv=NULL;
#define E2PROM_ADDR 0x50
#define EEPROM_RDWR 0X4401

static  struct i2c_client *this_client = NULL;

static struct cdev *e2prom_dev ;

static const struct i2c_device_id e2prom_i2c_id[] = {
 { "e2prom", 0 }
};

#define DEV_MAJOR 254
static int major=DEV_MAJOR;
static int e2prom_open(struct inode *inode,struct file *filp )
{
 struct e2prom_priv_t *data=&e2prom_priv;
 
 filp->private_data = data ;
 
 try_module_get(THIS_MODULE);
 return 0;
}
static int e2prom_release(struct inode *inode,struct file *filp)
{

 filp->private_data = NULL;
 module_put(THIS_MODULE);
 
 return 0;
}
static int e2prom_write_read(struct i2c_client client,u8 reg, u8 *value,int mode)
{
 u8 data[2];
    BUG_ON(client);
 struct i2c_msg msg[] = {
  {
   .addr = client->addr,
   //.flags = 0;//I2C_M_RD,
   .len = 2,
   .buf[0] = reg,
   .buf[1] = *value,
  },
 };

 
 if(mode==0){
  msg[0].flags = I2C_M_WR;;
  ret = i2c_transfer(client->adapter, msg, 1);
  if (ret < 0)
   printk("%s i2c read error: %d\n", __func__, ret);

  return (ret == 1) ? length : ret;
 }
 else
  {
            msg[0].flags = I2C_M_RD;;
   ret = i2c_transfer(client->adapter, msg, 1);
  if (ret < 0)
   printk("%s i2c read error: %d\n", __func__, ret);

  return (ret == 1) ? length : ret;
  }
  //  return 0;
  
}

static int e2prom_wr(struct file * filp, const char * buffer, size_t count, loff_t * ppos)
{
 //struct e2prom_priv_t *wm8731=(struct e2prom_priv_t *)filp->private_data;
 char *tmp;
 int ret;
 u16 val;
 
 tmp = kzalloc(count,GFP_KERNEL);

 if (tmp==NULL)
  return -ENOMEM;

 if (copy_from_user(tmp,buffer,count)) {
  kfree(tmp);
  return -EFAULT;
 }
 
 ret = e2prom_write_read(this_client,tmp[0],&val,0);
   
    kfree(tmp);
    return ret;
}
static int e2prom_rd(struct file * filp, const char * buffer, size_t count, loff_t * ppos)
{
// struct e2prom_priv_t *wm8731=(struct e2prom_priv_t *)filp->private_data;
 char *tmp;
 int ret;
 u16 val;
 
 tmp = kzalloc(count,GFP_KERNEL);

 if (tmp==NULL)
  return -ENOMEM;

 
 
 ret = e2prom_write_read(this_client,tmp[0],&val,1);
    tmp[0]= val;
    if (copy_to_user(buffer,tmp,count)) {
  kfree(tmp);
  return -EFAULT;
 }
    kfree(tmp);
    return ret;   
}
static int e2prom_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long ioctl_param)
{
    int ret=-1;
    struct i2c_rdwr_ioctl_data rdwr_arg;
 struct i2c_smbus_ioctl_data data_arg;
 struct i2c_msg *rdwr_pa;
 u8 __user **data_ptrs;
    switch(cmd){
        case EEPROM_RDWR:
        // do it yourself
            if (copy_from_user(&rdwr_arg,
       (struct i2c_rdwr_ioctl_data __user *)arg,
       sizeof(rdwr_arg)))
   return -EFAULT;

  /* Put an arbitrary limit on the number of messages that can
   * be sent at once */
  if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
   return -EINVAL;
  
  rdwr_pa = (struct i2c_msg *)
   kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg),
   GFP_KERNEL);

  if (rdwr_pa == NULL) return -ENOMEM;

  if (copy_from_user(rdwr_pa, rdwr_arg.msgs,
       rdwr_arg.nmsgs * sizeof(struct i2c_msg))) {
   kfree(rdwr_pa);
   return -EFAULT;
  }

  data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL);
  if (data_ptrs == NULL) {
   kfree(rdwr_pa);
   return -ENOMEM;
  }

  ret = 0;
  for( i=0; i<rdwr_arg.nmsgs; i++ ) {
   /* Limit the size of the message to a sane amount */
   if (rdwr_pa[i].len > 8192) {
    ret = -EINVAL;
    break;
   }
   data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf;
   rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL);
   if(rdwr_pa[i].buf == NULL) {
    ret = -ENOMEM;
    break;
   }
   if(copy_from_user(rdwr_pa[i].buf,
    data_ptrs[i],
    rdwr_pa[i].len)) {
     ++i; /* Needs to be kfreed too */
     ret = -EFAULT;
    break;
   }
  }
  if (ret < 0) {
   int j;
   for (j = 0; j < i; ++j)
    kfree(rdwr_pa[j].buf);
   kfree(data_ptrs);
   kfree(rdwr_pa);
   return ret;
  }

  ret = i2c_transfer(client->adapter,
   rdwr_pa,
   rdwr_arg.nmsgs);
  while(i-- > 0) {
   if( ret>=0 && (rdwr_pa[i].flags & I2C_M_RD)) {
    if(copy_to_user(
     data_ptrs[i],
     rdwr_pa[i].buf,
     rdwr_pa[i].len)) {
     ret = -EFAULT;
    }
   }
   kfree(rdwr_pa[i].buf);
  }
  kfree(data_ptrs);
  kfree(rdwr_pa);
  return ret;
            break;
        default:
        break;
    }
    return ret;
}

static struct file_operations e2prom_fops = {
 owner:          THIS_MODULE,
 read:           e2prom_rd,
 write:   e2prom_wr,
 ioctl:          e2prom_ioctl,
 open:      e2prom_open,
 release:     e2prom_release,
};
static int e2prom_register()
{
    int ret;
   static dev_t dev= MKDEV(DEV_MAJOR,0);
  
    if(major)
    {
       ret= register_chrdev_region(dev,1,"eeprom");
       if(ret){
         return -EFAULT;
       }
    }
    else{
        ret= alloc_chrdev_region(dev, 0, 1,"eeprom");
        if(ret){
            return -EFAULT;
        }
    }
       
    e2prom_dev =cdev_alloc();
   
    cdev_init(e2prom_dev,e2prom_fops);
    e2prom_dev->owner= THIS_MODULE;
    ret= cdev_add(e2prom_dev,dev,1);
        
    return ret;
}
static int e2prom_unregister()
{
    static dev_t dev= MKDEV(DEV_MAJOR,0);
   if( e2prom_dev)
        cdev_del(e2prom_dev);
   unregister_chrdev_region(dev,1);
    return 0;
}
#define E2PROM_ADDR 0x50
static  struct i2c_client *this_client = NULL;
static int e2prom_i2c_probe(struct i2c_client *client,
          const struct i2c_device_id *id)
{

 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
  return -ENODEV;
 e2prom_priv = kzalloc(sizeof(struct e2prom_priv_t), GFP_KERNEL);
 if (e2prom_priv == NULL)
  return -ENOMEM;
 e2prom_priv->addr =  E2PROM_ADDR;

 if(client->addr != e2prom_priv->addr)
  client->addr = e2prom_priv->addr;
 this_client = client;
 i2c_set_clientdata(client, e2prom_priv);
 return 0;
}
static int e2prom_i2c_remove(struct i2c_client *client)
{
  struct e2prom_priv_t *e2prom_priv = i2c_get_clientdata(client);

 i2c_set_clientdata(client, NULL);

 if(e2prom_priv) kfree(e2prom_priv);
 
 return 0; 

}
static struct i2c_driver e2prom_i2c_driver = { 
 .probe =    e2prom_i2c_probe,
 .remove =   e2prom_i2c_remove,
 .id_table = e2prom_i2c_id,
 .driver = {
  .name = "EEPROM",
  .owner = THIS_MODULE,
 },
};
static int __init e2prom_drv_init(void)
{
 int ret;
 e2prom_register();
 ret = i2c_add_driver(&e2prom_i2c_driver);
 if (ret != 0) {
  printk(KERN_ERR "Failed to register WM8731 I2C driver: %d\n", ret);
 }
 return 0;
}
static void __exit e2prom_drv_exit(void)
{
 i2c_del_driver(&e2prom_i2c_driver);
 e2prom_unregister();
}
MODULE_LICENSE("GPL");
module_init(e2prom_drv_init);
module_exit(e2prom_drv_exit);

 


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章