Chinaunix首页 | 论坛 | 博客
  • 博客访问: 493211
  • 博文数量: 118
  • 博客积分: 5003
  • 博客等级: 大校
  • 技术积分: 1213
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-07 20:29
文章存档

2011年(8)

2010年(4)

2009年(12)

2008年(85)

2007年(9)

我的朋友

分类: LINUX

2008-05-29 11:29:25

    这两天挺累的,频繁的应酬,都有点受不了了,下了班也不敢加班,赶紧跑回家,结果发现,跑回家也没有作用。。。
    放出一个atmel24c512的设备驱动框架。可以使用,但是使用这要对read和write进行一些修改,需要能指定地址的访问。。。
    感谢网上的某位兄弟放出的部分源码,linux开源的力量无穷!!!
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

static unsigned short normal_i2c[] = { 0x50,I2C_CLIENT_END };


#define EEPROM_SIZE    65536

#define    DEVICE_NAME     "at24c512"
#define    AT24C512_EEPROM_MAJOR 251



#define    SEEK_END    2

#define    SEEK_CUR    1

#define    SEEK_SET    0


static DECLARE_MUTEX(at24c512_eeprom_read_sem);
static DECLARE_MUTEX(at24c512_eeprom_write_sem);

struct i2c_client *new_client;


/* possible types of eeprom devices */
enum eeprom_nature {
    UNKNOWN,
    VAIO,
};
/* Module parameters */
/*这一句很重要得,不然的addr_data会找不到,因为i2c.h文件只是定义了几种宏,这里才真正定义这个变量,今天才真正理解了这个addr_data如何产生的,
每个i2c设备都有一个addr_data结构,这样就好理解i2c的框架(i2c_probe)驱动为何这样写,*/
I2C_CLIENT_INSMOD;


static ssize_t eeprom_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
{
memset(buf,0x88,10);
return 10;
}

static ssize_t eeprom_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
{
return 10;
}

static struct i2c_driver eeprom_driver;


static struct bin_attribute eeprom_attr = {
    .attr = {
        .name = "at24c512",
        .mode = S_IRUGO,
        .owner = THIS_MODULE,
    },
    .size = EEPROM_SIZE,
    .read = eeprom_read,
    .write=eeprom_write,
};



struct eeprom_data {
    struct i2c_client client;
    struct mutex update_lock;
    unsigned char valid;            /* bitfield, bit!=0 if slice is valid */
    unsigned long last_updated[8];    /* In jiffies, 8 slices */
    unsigned char data[EEPROM_SIZE];        /* Register values */
    enum eeprom_nature nature;
};



/* This function is called by i2c_probe */
static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind)
{
    struct eeprom_data *data;
    int err = 0;

    printk("eeprom_detect!\n");   

    if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
        err = -ENODEV;
        goto exit;
    }

    if (!(data = kzalloc(sizeof(struct eeprom_data), GFP_KERNEL))) {
        err = -ENOMEM;
        goto exit;
    }

    new_client = &data->client;
    memset(data->data, 0xff, EEPROM_SIZE);
    i2c_set_clientdata(new_client, data);
    new_client->addr = address;
    printk("address==%x\n",new_client->addr);
    new_client->adapter = adapter;
    new_client->driver = &eeprom_driver;
    new_client->flags = 0;

    /* Fill in the remaining client fields */
    strlcpy(new_client->name, eeprom_driver.driver.name, I2C_NAME_SIZE);
    data->valid = 0;
    mutex_init(&data->update_lock);
    data->nature = UNKNOWN;


    /* Tell the I2C layer a new client has arrived */
    if ((err = i2c_attach_client(new_client)))
        goto exit_kfree;

    /* Detect the Vaio nature of EEPROMs.
       We use the "PCG-" prefix as the signature. */
    /*
    if (address == 0x57) {
        if (i2c_smbus_read_byte_data(new_client, 0x80) == 'P'
         && i2c_smbus_read_byte(new_client) == 'C'
         && i2c_smbus_read_byte(new_client) == 'G'
         && i2c_smbus_read_byte(new_client) == '-') {
            dev_info(&new_client->dev, "Vaio EEPROM detected, "
                "enabling password protection\n");
            data->nature = VAIO;
        }
    }
    */

    /* create the sysfs eeprom file */
    err = sysfs_create_bin_file(&new_client->dev.kobj, &eeprom_attr);
    if (err)
        goto exit_detach;
   
    printk("eeprom_detect ok!\n");       

    return 0;

exit_detach:
    i2c_detach_client(new_client);
exit_kfree:
    kfree(data);
exit:
    return err;
}



static int eeprom_attach_adapter(struct i2c_adapter *adapter)
{
    return i2c_probe(adapter, &addr_data, eeprom_detect);
}


static int eeprom_detach_client(struct i2c_client *client)
{
    int err;

    sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr);

    err = i2c_detach_client(client);
    if (err)
        return err;

    kfree(i2c_get_clientdata(client));

    return 0;
}


/* This is the driver that will be inserted */
static struct i2c_driver eeprom_driver = {
    .driver = {
        .name    = "at24c512",
    },
    .id        = I2C_DRIVERID_EEPROM,
    .attach_adapter    = eeprom_attach_adapter,
    .detach_client    = eeprom_detach_client,
};




static int  at24c512_eeprom_open(struct inode * inode, struct file * filp)
{
    filp->private_data = new_client;
    printk("at24c512 open success!\n");
    return 0;
}

static int  at24c512_eeprom_release(struct inode * inode, struct file * filp)
{
    printk("at24c512 realse success!\n");
    return 0;
}

static loff_t  at24c512_eeprom_llseek (struct file *filp, loff_t off, int whence)
{

     //struct i2c_dev *dev = filp->private_data;
     loff_t newpos=-1;
 
     filp->private_data=new_client;
     switch(whence)
     { 
          case SEEK_SET:  
       newpos = off; 
       break; 
  
          case SEEK_CUR:  
       newpos = filp->f_pos + off; 
       break; 
  
          case SEEK_END:  
       //newpos = (filp->private_data)->size + off; 
       break; 
  
          default: /* can't happen */ 
       return -EINVAL;
    }
   
       
    if (newpos < 0)
   return -EINVAL;

    printk("at24c512 llseek success!\n");

    filp->f_pos = newpos;
    return newpos;
}



static ssize_t at24c512_eeprom_read(struct file * file, char * buffer, size_t count, loff_t *ppos)
{
    ssize_t ret;
 int result;
 struct i2c_client *client = new_client;
 struct i2c_msg msg[1];
 char *tmp;

 printk("this is in reading!\n");
 if(down_interruptible(&at24c512_eeprom_read_sem))
  goto out;
 
 if (!(tmp = kzalloc(count, GFP_KERNEL)))
        return  - ENOMEM;
    printk("the number is %d\n",count);
  result=i2c_master_recv(client, tmp ,count);
  printk("read result===%x\n",result);
        ret = copy_to_user(buffer, tmp, count);
  if(ret != 0)
  {
   kfree(tmp);
  return -EFAULT;
  }
 
 out:
 {
  up(&at24c512_eeprom_read_sem);
  return 0;
 }
 kfree(tmp);
 return ret;

}

static ssize_t at24c512_eeprom_write(struct file * file, char * buffer, size_t count, loff_t *ppos)
{
 ssize_t ret;
 int result,i;
 struct i2c_client *client=new_client;
     struct i2c_msg msg[1];
    char *tmp;

 if(down_interruptible(&at24c512_eeprom_write_sem))
  goto out;
 printk("this is in writting!\n");

 if (!(tmp = kzalloc(count, GFP_KERNEL)))
        return  - ENOMEM;

  ret = copy_from_user(tmp, buffer, count);

  if(ret != 0)
  {
   kfree(tmp);
  return -EFAULT;
  }
 
  result=i2c_master_send(client,tmp ,count);
  printk("write result===%x\n",result);
 out:
 {
  up(&at24c512_eeprom_write_sem);
  return 0;
 }
 kfree(tmp);
 return result;

}



/*to user*/
static struct file_operations at24c512_eeprom_fops = {
 .owner = THIS_MODULE,
 .open=at24c512_eeprom_open,
 //.poll = tsmb_eeprom_select,
 .read = at24c512_eeprom_read,
 .write = at24c512_eeprom_write,
 .llseek = at24c512_eeprom_llseek,
 .release=at24c512_eeprom_release,
};


static int __init eeprom_init(void)
{
    int ret,result;   
    result = register_chrdev(AT24C512_EEPROM_MAJOR, DEVICE_NAME,  &at24c512_eeprom_fops);
    if (result < 0)
     {
          printk(KERN_ERR DEVICE_NAME ": Unable to get major %d\n", AT24C512_EEPROM_MAJOR);
          return(result);
     }        
    ret=i2c_add_driver(&eeprom_driver);
      if (ret)
       goto out_unreg_class;

     printk(KERN_ERR DEVICE_NAME ": init OK\n");
     return 0;
     out_unreg_class:
          unregister_chrdev(AT24C512_EEPROM_MAJOR, DEVICE_NAME);
    return 1;
}

static void __exit eeprom_exit(void)
{
    i2c_del_driver(&eeprom_driver);
    unregister_chrdev(AT24C512_EEPROM_MAJOR, DEVICE_NAME);
}


MODULE_AUTHOR("tony(gwkm ltd) ty3247@163.com");
MODULE_DESCRIPTION("I2C EEPROM at24c512 driver");
MODULE_LICENSE("GPL");

module_init(eeprom_init);
module_exit(eeprom_exit);



有疑问大家可以提问!欢迎讨论。。。。

dmesg输出如下信息:

<4>eeprom_detect ok!
<3>at24c512: init OK
<4>at24c512 open success!
<4>this is in reading!
<4>the number is 8192
<7>i2c_adapter i2c-0: master_xfer[0] R, addr=0x50, len=8192
<7>i2c_adapter i2c-0: at91_xfer: processing 1 messages:
<7>i2c_adapter i2c-0:  #0: reading 8192 bytes from 0x50
<7>i2c_adapter i2c-0: transfer complete
<4>read result===2000
<4>at24c512 realse success!
说明通信成功。。。



阅读(3120) | 评论(1) | 转发(0) |
0

上一篇:spi总线设备驱动分析

下一篇:uptime的使用

给主人留下些什么吧!~~

chinaunix网友2008-10-07 15:02:22

你好。目前我也在使用这种型号的EEPROM(AT24C512B),但是对EEPROM的读写不成功,read result和write result都为0.看了一下AT24C512B的pdf文档,“ A write operation requires two 8-bit data word addresses following the device address word and acknowledgment.” 请问是不是要根据EEPROM的特点要组织一条消息格式,才能对应的读和写? PS:可以加qq聊吗,我的是562945624