这篇文章主要以友善的实验板为例介绍一下,他们所说的IIC下的EEPROM驱动吧。因为我个人觉得不是很好,可能会给初学者带来一下迷惑,纯属个人观点!
#include <stdio.h>
#include <fcntl.h>
#include <getopt.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "24cXX.h"
#define usage_if(a) do { do_usage_if( a , __LINE__); } while(0);
void do_usage_if(int b, int line)
{
const static char *eeprog_usage =
"I2C-24C08(256 bytes) Read/Write Program, ONLY FOR TEST!\n"
"FriendlyARM Computer Tech. 2009\n";
if(!b)
return;
fprintf(stderr, "%s\n[line %d]\n", eeprog_usage, line);
exit(1);
}
#define die_if(a, msg) do { do_die_if( a , msg, __LINE__); } while(0);
void do_die_if(int b, char* msg, int line)
{
if(!b)
return;
fprintf(stderr, "Error at line %d: %s\n", line, msg);
fprintf(stderr, " sysmsg: %s\n", strerror(errno));
exit(1);
}
static int read_from_eeprom(struct eeprom *e, int addr, int size)
{
int ch, i;
for(i = 0; i < size; ++i, ++addr)
{
die_if((ch = eeprom_read_byte(e, addr)) < 0, "read error");
if( (i % 16) == 0 )
printf("\n %.4x| ", addr);
else if( (i % 8) == 0 )
printf(" ");
printf("%.2x ", ch);
fflush(stdout);
}
fprintf(stderr, "\n\n");
return 0;
}
static int write_to_eeprom(struct eeprom *e, int addr)
{
int i;
for(i=0, addr=0; i<256; i++, addr++)
{
if( (i % 16) == 0 )
printf("\n %.4x| ", addr);
else if( (i % 8) == 0 )
printf(" ");
printf("%.2x ", i);
fflush(stdout);
die_if(eeprom_write_byte(e, addr, i), "write error");
}
fprintf(stderr, "\n\n");
return 0;
}
int main(int argc, char** argv)
{
struct eeprom e;
int op;
op = 0;
usage_if(argc != 2 || argv[1][0] != '-' || argv[1][2] != '\0');
op = argv[1][1];
fprintf(stderr, "Open /dev/i2c/0 with 8bit mode\n");
die_if(eeprom_open("/dev/i2c/0", 0x50, EEPROM_TYPE_8BIT_ADDR, &e) < 0,
"unable to open eeprom device file "
"(check that the file exists and that it's readable)");
switch(op)
{
case 'r':
fprintf(stderr, " Reading 256 bytes from 0x0\n");
read_from_eeprom(&e, 0, 256);
break;
case 'w':
fprintf(stderr, " Writing 0x00-0xff into 24C08 \n");
write_to_eeprom(&e, 0);
break;
default:
usage_if(1);
exit(1);
}
eeprom_close(&e);
return 0;
}
上面的程序,是友善提供的eeprom的测试程序,而且只是里面的包括主函数的程序,完整的程序我给个链接吧,因为可能有人手上没有友善开发板的程序。链接:http://download.csdn.net/detail/xie0812/5862347,你可以这里下载,哈哈,因为要完全理解还得下载下来看看的。要是你完全看不懂,请先阅读《Unix环境高级编程》这本书了,这里就假设都能看懂了!
看应用程序嘛,当然要从main函数开始了,首先是打开设备了,这里的eeprom_open函数就是了,设备的名字就是/dev/i2c/0了,然后紧接着就是0x50,这是eeprom的地址,真真的地址是0xa0,当然跟你对eeprom的外部电路的接法有关了。那为什么这里是0x50呢,啊,原来在驱动里边会把地址向左移动一位,所以真真的地址还是0xa0了。这里就有例外的一个问题了,不是说设备是唯一的,怎么还要地址了?是啊,这个问题我也困惑了好久,我追寻这个测试程序对应的驱动程序,发现根本不是友善提供的文档上说的地方,它所说的那个驱动是适配器的驱动程序,也就是说是IIC总线的驱动程序,可能是说错了吧。既然不是,再找,发现原来真真的驱动程序是i2c-dev.c,这个文件在linux源文件的driver目录下的iic目录下。下面就简单地介绍一下i2c-dev.c。
i2c-dev.c实现的一个i2c_client(就是IIC的设备驱动)是虚拟的、临时的,随着设备文件的打开而产生,并随设备文件的关闭而撤销,并没有被添加到i2c_adapter的client链表中。i2c-dev.c针对每个I2C适配器生产一个主设备号为89的设备文件,linux中一切都是文件的思想嘛。实现了i2c-driver的成员函数以及文件操作接口。
static int i2cdev_open(struct inode *inode, struct file *file)
{
unsigned int minor = iminor(inode);
struct i2c_client *client;
struct i2c_adapter *adap;
struct i2c_dev *i2c_dev;
int ret = 0;
lock_kernel();
i2c_dev = i2c_dev_get_by_minor(minor);
if (!i2c_dev) {
ret = -ENODEV;
goto out;
}
adap = i2c_get_adapter(i2c_dev->adap->nr);
if (!adap) {
ret = -ENODEV;
goto out;
}
/* This creates an anonymous i2c_client, which may later be
* pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE.
*
* This client is ** NEVER REGISTERED ** with the driver model
* or I2C core code!! It just holds private copies of addressing
* information and maybe a PEC flag.
*/
client = kzalloc(sizeof(*client), GFP_KERNEL);
if (!client) {
i2c_put_adapter(adap);
ret = -ENOMEM;
goto out;
}
snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
client->driver = &i2cdev_driver;
client->adapter = adap;
file->private_data = client;
out:
unlock_kernel();
return ret;
}
这是i2c-dev.c中的open函数,也就是测试程序中对应的open系统调用了。分析这个函数可以知道,当调用这个函数时,它首先创建一个i2c-client结构,注册了一下
i2c-client结构中的i2c_driver以及适配器,通过注释可以看到真真的设备的地址是在icotl调用中完成的。要是你仔细查看了测试程序中的eeprom_open函数,会发现其实它是封装了open和icotl系统调用的。这也说明了它的确是虚拟的设备文件。当然这里提到的两个结构体,你可能不了解,没关系,我们下面的内容会讲到。谈到这里,大家应该明白了一件事,友善的实验板上根本没实现eeprom的驱动,只是利用一个虚拟的设备文件做了硬件的测试。那我们要真真写一个iic设备的驱动程序应该怎么写了,是啊,我们要学习iic驱动,这样肯定是不能算是明白了,所以我们需要进一步的探索,既然上了路,就应该勇敢的走下去!