这篇文章主要以友善的实验板为例介绍一下,他们所说的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驱动,这样肯定是不能算是明白了,所以我们需要进一步的探索,既然上了路,就应该勇敢的走下去!