i2c--test

硬件
http://www.i2c-bus.org/how-i2c-hardware-works/
http://www.xinqi.cn/pdf/cun/at24cxx.pdf
http://download.csdn.net/detail/songqqnew/4438714
http://download.csdn.net/detail/songqqnew/4438746
测试
***********************************************************************************************使用ioctl( ,I2C_SMBUS, )操作iic
板子的文件系统里已经有一个/usr/bin/i2c的程序,用于测试i2c,比如
i2c -r
i2c -w
源码如下
//24cxx.h

#ifndef _24CXX_H_
#define _24CXX_H_
#include <linux/i2c-dev.h>
#include <linux/i2c.h>

#define EEPROM_TYPE_UNKNOWN	0
#define EEPROM_TYPE_8BIT_ADDR	1
#define EEPROM_TYPE_16BIT_ADDR 	2

struct eeprom
{
	char *dev; 	// device file i.e. /dev/i2c-N
	int addr;	// i2c address
	int fd;		// file descriptor
	int type; 	// eeprom type
};

int eeprom_open(char *dev_fqn, int addr, int type, struct eeprom*);
int eeprom_close(struct eeprom *e);
int eeprom_read_byte(struct eeprom* e, __u16 mem_addr);
int eeprom_read_current_byte(struct eeprom *e);
int eeprom_write_byte(struct eeprom *e, __u16 mem_addr, __u8 data);
#endif

//eeprog.c

#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;
}
1.定义结构体变量struct eeprom e;
2.打开设备文件/dev/i2c/0,读取数据
read_from_eeprom(&e, 0, 256);----->eeprom_read_byte
write_to_eeprom(&e, 0);--------->eeprom_write_byte
而读和写最终都是通过ioctl(file,I2C_SMBUS,&args);方法实现的。如下
static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command, 
                                     int size, union i2c_smbus_data *data)
{
	struct i2c_smbus_ioctl_data args;

	args.read_write = read_write;
	args.command = command;
	args.size = size;
	args.data = data;
	return ioctl(file,I2C_SMBUS,&args);
}

***********************************************************************************************使用ioctl( ,I2C_RDWR, )操作iic
2015年5月26日 11:54:35

#include <stdio.h>
#include <linux/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>


char ToDec(char* sHex)
{

<span style="white-space:pre">	</span>int iValue =0;
<span style="white-space:pre">	</span>char buf[32]={0};

<span style="white-space:pre">	</span>sscanf(sHex,"%x",&iValue);
<span style="white-space:pre">	</span>//printf("%d\n",iValue);

<span style="white-space:pre">	</span>return (char)iValue;
}



int main(int argc,char *argv[])
{


<span style="white-space:pre">	</span>if(argc != 6)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>printf("usage: \n%s /dev/i2cx devaddr regaddr -r count \nOR \n%s /dev/i2cx devaddr regaddr -w value\n",argv[0],argv[0]);
<span style="white-space:pre">		</span>return 0;
<span style="white-space:pre">	</span>}




//./iic /dev/iic-2 0x60 0x79 -r 5
//./iic /dev/iic-2 0x60 0x79 -w 90




<span style="white-space:pre">	</span>char *device = argv[1];
<span style="white-space:pre">	</span>unsigned int devaddr = ToDec(argv[2]);
<span style="white-space:pre">	</span>unsigned int regaddr = ToDec(argv[3]);
<span style="white-space:pre">	</span>char *rw =  argv[4];
<span style="white-space:pre">	</span>unsigned int value =  ToDec(argv[5]);
<span style="white-space:pre">	</span>unsigned int count = value;


/*
printf("device = %s\n",device);
printf("devaddr = 0x%x\n",devaddr);
printf("regaddr = 0x%x\n",regaddr);
printf("rw = %s\n",rw);
printf("value = 0x%x\n",value);


*/


<span style="white-space:pre">	</span>
<span style="white-space:pre">	</span>int fd, ret;
<span style="white-space:pre">	</span>struct i2c_rdwr_ioctl_data e2prom_data;
<span style="white-space:pre">	</span>memset(&e2prom_data,0 ,sizeof(e2prom_data));


<span style="white-space:pre">	</span>fd= open(device, O_RDWR);
<span style="white-space:pre">	</span>if(fd < 0) {
<span style="white-space:pre">		</span>perror("openerror");
<span style="white-space:pre">		</span>exit(1);
<span style="white-space:pre">	</span>}

<span style="white-space:pre">	</span>ioctl(fd,I2C_TIMEOUT, 1); /* 设置超时 */
<span style="white-space:pre">	</span>ioctl(fd,I2C_RETRIES, 2); /* 设置重试次数 */

<span style="white-space:pre">	</span>if(strcmp(rw,"-r") == 0)
<span style="white-space:pre">	</span>{


<span style="white-space:pre">		</span>e2prom_data.nmsgs = 2;
<span style="white-space:pre">		</span>e2prom_data.msgs= (struct i2c_msg *)malloc(e2prom_data.nmsgs *sizeof(struct i2c_msg));
<span style="white-space:pre">		</span>if(e2prom_data.msgs == NULL) {
<span style="white-space:pre">			</span>perror("mallocerror");
<span style="white-space:pre">			</span>exit(1);
<span style="white-space:pre">		</span>}




<span style="white-space:pre">		</span>unsigned char data= 0;/* be zero*/
<span style="white-space:pre">		</span>//从指定地址读 
<span style="white-space:pre">		</span>#if 1
<span style="white-space:pre">		</span>/*从e2prom的regaddr地址读取数据存入buf*/
<span style="white-space:pre">		</span>e2prom_data.nmsgs= 2;
<span style="white-space:pre">		</span>e2prom_data.msgs[0].len= 1;
<span style="white-space:pre">		</span>e2prom_data.msgs[0].addr= devaddr;
<span style="white-space:pre">		</span>e2prom_data.msgs[0].flags= 0;/* write */
<span style="white-space:pre">		</span>e2prom_data.msgs[0].buf= &regaddr;


<span style="white-space:pre">		</span>e2prom_data.msgs[1].len= count;
<span style="white-space:pre">		</span>e2prom_data.msgs[1].addr= devaddr;
<span style="white-space:pre">		</span>e2prom_data.msgs[1].flags= 1;/* read */
<span style="white-space:pre">		</span>e2prom_data.msgs[1].buf= (unsigned char *)malloc(count);
<span style="white-space:pre">		</span>#endif 


<span style="white-space:pre">		</span>//从指定地址读 
<span style="white-space:pre">		</span>#if 0
<span style="white-space:pre">		</span>/*从e2prom的regaddr地址读取数据存入buf*/
<span style="white-space:pre">		</span>e2prom_data.nmsgs= 2;
<span style="white-space:pre">		</span>e2prom_data.msgs[0].len= 1;
<span style="white-space:pre">		</span>e2prom_data.msgs[0].addr= devaddr;
<span style="white-space:pre">		</span>e2prom_data.msgs[0].flags= 0;/* write */
<span style="white-space:pre">		</span>e2prom_data.msgs[0].buf= &regaddr;


<span style="white-space:pre">		</span>e2prom_data.msgs[1].len= 1;
<span style="white-space:pre">		</span>e2prom_data.msgs[1].addr= devaddr;
<span style="white-space:pre">		</span>e2prom_data.msgs[1].flags= 1;/* read */
<span style="white-space:pre">		</span>e2prom_data.msgs[1].buf= &value;
<span style="white-space:pre">		</span>#endif 




<span style="white-space:pre">		</span>//从当前地址读
<span style="white-space:pre">		</span>#if 0
<span style="white-space:pre">		</span>/*从e2prom的当前地址读取数据存入buf*/
<span style="white-space:pre">		</span>e2prom_data.nmsgs= 1;
<span style="white-space:pre">		</span>e2prom_data.msgs[0].len= 5;
<span style="white-space:pre">		</span>e2prom_data.msgs[0].addr= devaddr;
<span style="white-space:pre">		</span>e2prom_data.msgs[0].flags= 1;/* read */ 
<span style="white-space:pre">		</span>e2prom_data.msgs[0].buf=(unsigned char *)malloc(5);
<span style="white-space:pre">		</span>#endif




<span style="white-space:pre">		</span>ret= ioctl(fd, I2C_RDWR, (unsigned long)&e2prom_data);
<span style="white-space:pre">		</span>if(ret < 0) {
<span style="white-space:pre">			</span>perror("readerror");
<span style="white-space:pre">			</span>exit(1);
<span style="white-space:pre">		</span>}


<span style="white-space:pre">		</span>int i=0;
<span style="white-space:pre">		</span>for( i=0;i<count;i++)
<span style="white-space:pre">		</span>{
<span style="white-space:pre">			</span>printf("read data: %d from regaddr: 0x%x\n",e2prom_data.msgs[1].buf[i],regaddr+i);
<span style="white-space:pre">		</span>}
<span style="white-space:pre">	</span>


<span style="white-space:pre">		</span>free(e2prom_data.msgs[1].buf);
<span style="white-space:pre">		</span>free(e2prom_data.msgs);


<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>else if(strcmp(rw,"-w") == 0)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>e2prom_data.nmsgs = 1;
<span style="white-space:pre">		</span>e2prom_data.msgs= (struct i2c_msg *)malloc(e2prom_data.nmsgs *sizeof(struct i2c_msg));
<span style="white-space:pre">		</span>if(e2prom_data.msgs == NULL) {
<span style="white-space:pre">			</span>perror("mallocerror");
<span style="white-space:pre">			</span>exit(1);
<span style="white-space:pre">		</span>}


<span style="white-space:pre">		</span>//向指定地址写入1字节数据  
<span style="white-space:pre">		</span>/*向e2prom的regaddr地址写入数据data*/
<span style="white-space:pre">		</span>
<span style="white-space:pre">		</span>e2prom_data.msgs[0].len= 2;
<span style="white-space:pre">		</span>e2prom_data.msgs[0].addr= devaddr;
<span style="white-space:pre">		</span>e2prom_data.msgs[0].flags= 0;/* write */


<span style="white-space:pre">		</span>e2prom_data.msgs[0].buf= (unsigned char *)malloc(2);
<span style="white-space:pre">		</span>e2prom_data.msgs[0].buf[0]= regaddr;/* write address */
<span style="white-space:pre">		</span>e2prom_data.msgs[0].buf[1]= value;/* write data */


<span style="white-space:pre">		</span>ret= ioctl(fd, I2C_RDWR, (unsigned long)&e2prom_data);
<span style="white-space:pre">		</span>if(ret < 0) {
<span style="white-space:pre">			</span>perror("writedata error");
<span style="white-space:pre">			</span>exit(1);
<span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>printf("write data: 0x%x to regaddr: 0x%x\n", value, regaddr);


<span style="white-space:pre">		</span>free(e2prom_data.msgs);
<span style="white-space:pre">	</span>}


<span style="white-space:pre">	</span>
<span style="white-space:pre">	</span>close(fd);
<span style="white-space:pre">	</span>return 0;
}


./iic /dev/i2c-2 0x60 0x0 -r 0x6
read data: 238 from regaddr: 0x0
read data: 0 from regaddr: 0x1
read data: 28 from regaddr: 0x2
read data: 96 from regaddr: 0x3
read data: 28 from regaddr: 0x4
read data: 176 from regaddr: 0x5

./iic /dev/i2c-2 0x60 0x26 -w 0xb9
write data: 0xb9 to regaddr: 0x26


地址格式如下,忽略掉最后一位读写标志,为0x60 
 1  1  0  0    0  0  0  x


从指定地址读,驱动执行如下动作
[root@FORLINX6410]#  DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 338): 
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 339): rdwr_arg.nmsgs=1
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 343): rdwr_pa[0].addr=0x50//设备地址
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 344): rdwr_pa[0].len=2
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 347): rdwr_pa[0].buf[0]=0x66//要写的内存地址
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 347): rdwr_pa[0].buf[1]=0x7//要写的数据
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 338): 
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 339): rdwr_arg.nmsgs=2
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 343): rdwr_pa[0].addr=0x50//设备地址
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 344): rdwr_pa[0].len=1
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 347): rdwr_pa[0].buf[0]=0x66//要读的内存地址
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 343): rdwr_pa[1].addr=0x50//设备地址
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 344): rdwr_pa[1].len=1
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 347): rdwr_pa[1].buf[0]=0x7//读到的数据
从当前地址读,驱动执行如下动作
[root@FORLINX6410]#  DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 338): 
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 339): rdwr_arg.nmsgs=1
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 343): rdwr_pa[0].addr=0x50
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 344): rdwr_pa[0].len=2
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 347): rdwr_pa[0].buf[0]=0x66
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 347): rdwr_pa[0].buf[1]=0x7
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 338): 
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 339): rdwr_arg.nmsgs=1
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 343): rdwr_pa[0].addr=0x50//设备地址
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 344): rdwr_pa[0].len=5//要读的数据个数
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 347): rdwr_pa[0].buf[0]=0x67//读到的数据,以下均是
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 347): rdwr_pa[0].buf[1]=0x68
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 347): rdwr_pa[0].buf[2]=0x69
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 347): rdwr_pa[0].buf[3]=0x6a
 DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 347): rdwr_pa[0].buf[4]=0x6b

分析:
根据24cxx手册,
写字节操作如下


即步骤为
start---设备地址(7位)+写标志0(1位)---要写入的内存地址----要写入的数据
注意:设备地址是0x50=101 0000,这个地址的确定见下图,由于a0a1a2接地了,所以设备地址是0x50(只算前7位,不算最后一位的r/w位,所以一条总线最多可以辨别127个设 备)。在驱动中会根据读写要求自动将地址左移一位然后加上读写标志位组成一个字节发送到sda引脚。
i2c-s3c2410.c

static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
                      struct i2c_msg *msg)
{
    unsigned int addr = (msg->addr & 0x7f) << 1;

...}



从指定地址读操作如下:

即步骤为:
start---设备地址(7位)+写标志0(1位)---要读的内存地址---start---设备地址(7位)+读标志1(1位)---读出的数据

注意:这个操作有允许多个start信号,所以程序中使用了两个msg---每个msg都会发送一个start信号

从当前地址读操作如下:


即步骤为:
start---设备地址(7位)+读标志1(1位)---读出的数据
注意:此处可以读一个字节,也可以读多个字节,只要arm在读到第一个字节之后接着去读IICDS寄存器,24cx就会满足arm把下一个地址的数据也发出

************************************************************************************************使用read,write操作iic
如果使用read write操作i2c比如下
ioctl(fd,I2C_SLAVE,0x33);//设置从机地址
write(fd,buf,num1);//向iic从机写入数据
memset(buf, 0, sizeof(buf));
read(fd,buf,num2);//从iic从机接收数据  

则上面的驱动会打印类似如下
DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 203): 发送 1 条写msg,写入的数据如下:
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 208): msg.flags=0x0
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 209): msg.addr=0x33
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 210): msg.len=7
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[0]=0x1
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[1]=0x38
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[2]=0x0
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[3]=0x0
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[4]=0xc7
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[5]=0xff
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[6]=0x17
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 165): 发送 1 条读msg,读到的数据如下:
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 170): msg.flags=0x0
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 171): msg.addr=0x33
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 172): msg.len=15
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[0]=0x1
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[1]=0x0
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[2]=0x8
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[3]=0x0
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[4]=0x69
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[5]=0x80
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[6]=0x2
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[7]=0x1e
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[8]=0x3
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[9]=0x15
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[10]=0x2
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[11]=0x1
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[12]=0xd3
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[13]=0xfe
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[14]=0x17
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 203): 发送 1 条写msg,写入的数据如下:
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 208): msg.flags=0x0
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 209): msg.addr=0x33
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 210): msg.len=8
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[0]=0x1
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[1]=0x32
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[2]=0x1
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[3]=0x0
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[4]=0x0
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[5]=0xcc
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[6]=0xff
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[7]=0x17
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 165): 发送 1 条读msg,读到的数据如下:
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 170): msg.flags=0x0
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 171): msg.addr=0x33
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 172): msg.len=11
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[0]=0x1
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[1]=0x0
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[2]=0x4
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[3]=0x0
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[4]=0x26
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[5]=0x0
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[6]=0xff
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[7]=0x0
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[8]=0xd6
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[9]=0xfe
 DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[10]=0x17
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 203): 发送 1 条写msg,写入的数据如下:
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 208): msg.flags=0x0
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 209): msg.addr=0x33
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 210): msg.len=60
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[0]=0x1
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[1]=0x37
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[2]=0x35
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[3]=0x0
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[4]=0x2
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[5]=0x66
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[6]=0x70
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[7]=0x0
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[8]=0x8f
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[9]=0x82
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[10]=0x8e
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[11]=0x83
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[12]=0xe0
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[13]=0x54
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[14]=0x1
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[15]=0x0
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[16]=0x0
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[17]=0x0
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[18]=0x70
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[19]=0xf8
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[20]=0x22
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[21]=0x78
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[22]=0xff
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[23]=0xe4
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[24]=0xf6
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[25]=0xd8
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[26]=0xfd
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[27]=0x2
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[28]=0x67
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[29]=0x1
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[30]=0x41
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[31]=0x13
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[32]=0x9
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[33]=0xff
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[34]=0x63
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[35]=0x9c
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[36]=0xe
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[37]=0xf6
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[38]=0x75
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[39]=0x30
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[40]=0x47
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[41]=0x35
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[42]=0x39
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[43]=0xa5
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[44]=0x32
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[45]=0x1
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[46]=0x2c
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[47]=0xe3
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[48]=0x29
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[49]=0x21
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[50]=0x26
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[51]=0x38
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[52]=0x23
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[53]=0xdf
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[54]=0x21
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[55]=0xed
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[56]=0x20
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[57]=0xd2
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[58]=0xea
 DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[59]=0x17
很明显,read和write每次只能发送一个msg,对应一个start信号。完全可以用ioctl( ,I2C_RDWR,1)代替。
************************************************************************************************
总之,如下

使用write,read之前,需要使用ioctl(fd,I2C_SLAVE,addr)设置地址,然后直接write或read真正的数据即可
使用ioctl(fd, I2C_RDWR, (unsigned long)&e2prom_data);
时,不必事先使用ioctl设置从机地址,因为 e2prom_data结构中包括地址了,如下
struct i2c_msg {
    __u16 addr;    /* slave address            */
    __u16 flags;
    __u16 len;        /* msg length                */
    __u8 *buf;        /* pointer to msg data            */
};


************************************************************************************************消息第一个字节的发送

master_xfer最终调用i2c-s3c2410.c的s3c24xx_i2c_message_start发送消息,具体发送的仅是消息的地址如下
static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
				      struct i2c_msg *msg)
{
	unsigned int addr = (msg->addr & 0x7f) << 1;
	unsigned long stat;
	unsigned long iiccon;

	stat = 0;
	stat |=  S3C2410_IICSTAT_TXRXEN;

	if (msg->flags & I2C_M_RD) {
		stat |= S3C2410_IICSTAT_MASTER_RX;
		addr |= 1;
	} else
		stat |= S3C2410_IICSTAT_MASTER_TX;

	if (msg->flags & I2C_M_REV_DIR_ADDR)
		addr ^= 1;

	/* todo - check for wether ack wanted or not */
	s3c24xx_i2c_enable_ack(i2c);//使能ack

	iiccon = readl(i2c->regs + S3C2410_IICCON);
	writel(stat, i2c->regs + S3C2410_IICSTAT);

	dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS\n", stat, addr);
	writeb(addr, i2c->regs + S3C2410_IICDS);//写从机地址到IICDS移位寄存器,包含一个读写标志位----第一个发送的字节总是地址

	/* delay here to ensure the data byte has gotten onto the bus
	 * before the transaction is started */

	ndelay(i2c->tx_setup);

	dev_dbg(i2c->dev, "iiccon, %08lx\n", iiccon);
	writel(iiccon, i2c->regs + S3C2410_IICCON);

	stat |= S3C2410_IICSTAT_START;
	writel(stat, i2c->regs + S3C2410_IICSTAT);//开始发送
#if 0
	int i;
	printk("msg->addr=0x%x\n",msg->addr);
	printk("msg->flags=0x%x\n",msg->flags);
	printk("msg->len=%d\n",msg->len);

	for(i=0;i<msg->len;i++)
	{
	printk("msg->buf[%d]=0x%x\n",i,msg->buf[i]);
	}

	printk("--\n");
#endif
}

根据6410手册,不同操作模式下的读写顺序为
主机发送

主机接收

下面的从机发送或接收暂时没用到,但也贴出来吧
从机发送


从机接收

其中IICSTAT寄存器

************************************************************************************************消息其他字节的发送或接收

函数s3c24xx_i2c_message_start是作为iic主机读或写时,用于发送消息的第一个字节(即要寻址的从机地址)-----那么消息的其他字节什么时候发送呢??在读消息时,就是其他字节什么时候读呢---在中断函数里面去读或继续发送。
static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
{
	struct s3c24xx_i2c *i2c = dev_id;
	unsigned long status;
	unsigned long tmp;

	status = readl(i2c->regs + S3C2410_IICSTAT);

	if (status & S3C2410_IICSTAT_ARBITR) {
		/* deal with arbitration loss */
		dev_err(i2c->dev, "deal with arbitration loss\n");
	}

	if (i2c->state == STATE_IDLE) {
		dev_dbg(i2c->dev, "IRQ: error i2c->state == IDLE\n");

		tmp = readl(i2c->regs + S3C2410_IICCON);
		tmp &= ~S3C2410_IICCON_IRQPEND;
		writel(tmp, i2c->regs +  S3C2410_IICCON);
		goto out;
	}

	/* pretty much this leaves us with the fact that we've
	 * transmitted or received whatever byte we last sent */

	i2s_s3c_irq_nextbyte(i2c, status);//见下面

 out:
	return IRQ_HANDLED;
}

/* i2s_s3c_irq_nextbyte
 *
 * process an interrupt and work out what to do
 */

static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
{
	unsigned long tmp;
	unsigned char byte;
	int ret = 0;

	switch (i2c->state) {

	case STATE_IDLE:
		dev_err(i2c->dev, "%s: called in STATE_IDLE\n", __func__);
		goto out;
		break;

	case STATE_STOP:
		dev_err(i2c->dev, "%s: called in STATE_STOP\n", __func__);
		s3c24xx_i2c_disable_irq(i2c);
		goto out_ack;

	case STATE_START:
		/* last thing we did was send a start condition on the
		 * bus, or started a new i2c message
		 */

		if (iicstat & S3C2410_IICSTAT_LASTBIT &&
		    !(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
			/* ack was not received... */

			dev_dbg(i2c->dev, "ack was not received\n");
			s3c24xx_i2c_stop(i2c, -ENXIO);
			goto out_ack;
		}

		if (i2c->msg->flags & I2C_M_RD)
			i2c->state = STATE_READ;
		else
			i2c->state = STATE_WRITE;

		/* terminate the transfer if there is nothing to do
		 * as this is used by the i2c probe to find devices. */

		if (is_lastmsg(i2c) && i2c->msg->len == 0) {
			s3c24xx_i2c_stop(i2c, 0);
			goto out_ack;
		}

		if (i2c->state == STATE_READ)
			goto prepare_read;

		/* fall through to the write state, as we will need to
		 * send a byte as well */

	case STATE_WRITE://如果此消息是写标志
		/* we are writing data to the device... check for the
		 * end of the message, and if so, work out what to do
		 */

		if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
			if (iicstat & S3C2410_IICSTAT_LASTBIT) {
				dev_dbg(i2c->dev, "WRITE: No Ack\n");

				s3c24xx_i2c_stop(i2c, -ECONNREFUSED);
				goto out_ack;
			}
		}

 retry_write:

		if (!is_msgend(i2c)) {//如果不是此消息的buf没有发完
			byte = i2c->msg->buf[i2c->msg_ptr++];
			writeb(byte, i2c->regs + S3C2410_IICDS);//写消息的其他字节依次写入IICDS寄存器

			/* delay after writing the byte to allow the
			 * data setup time on the bus, as writing the
			 * data to the register causes the first bit
			 * to appear on SDA, and SCL will change as
			 * soon as the interrupt is acknowledged */

			ndelay(i2c->tx_setup);

		} else if (!is_lastmsg(i2c)) {//如果是消息的最后一个字节
			/* we need to go to the next i2c message */

			dev_dbg(i2c->dev, "WRITE: Next Message\n");

			i2c->msg_ptr = 0;
			i2c->msg_idx++;
			i2c->msg++;

			/* check to see if we need to do another message */
			if (i2c->msg->flags & I2C_M_NOSTART) {

				if (i2c->msg->flags & I2C_M_RD) {
					/* cannot do this, the controller
					 * forces us to send a new START
					 * when we change direction */

					s3c24xx_i2c_stop(i2c, -EINVAL);
				}

				goto retry_write;
			} else {
				/* send the new start */
				s3c24xx_i2c_message_start(i2c, i2c->msg);
				i2c->state = STATE_START;
			}

		} else {
			/* send stop */

			s3c24xx_i2c_stop(i2c, 0);
		}
		break;

	case STATE_READ://如果此消息为读标志
		/* we have a byte of data in the data register, do
		 * something with it, and then work out wether we are
		 * going to do any more read/write
		 */

		byte = readb(i2c->regs + S3C2410_IICDS);//从IICDS移位寄存器中读出数据
		i2c->msg->buf[i2c->msg_ptr++] = byte;//数据依次写入消息的buf

 prepare_read:
		if (is_msglast(i2c)) {
			/* last byte of buffer */

			if (is_lastmsg(i2c))
				s3c24xx_i2c_disable_ack(i2c);

		} else if (is_msgend(i2c)) {
			/* ok, we've read the entire buffer, see if there
			 * is anything else we need to do */

			if (is_lastmsg(i2c)) {
				/* last message, send stop and complete */
				dev_dbg(i2c->dev, "READ: Send Stop\n");

				s3c24xx_i2c_stop(i2c, 0);
			} else {
				/* go to the next transfer */
				dev_dbg(i2c->dev, "READ: Next Transfer\n");

				i2c->msg_ptr = 0;
				i2c->msg_idx++;
				i2c->msg++;
			}
		}

		break;
	}

	/* acknowlegde the IRQ and get back on with the work */

 out_ack:
	tmp = readl(i2c->regs + S3C2410_IICCON);
	tmp &= ~S3C2410_IICCON_IRQPEND;
	writel(tmp, i2c->regs + S3C2410_IICCON);
 out:
	return ret;
}
************************************************************************************************
附i2c-dev.c源码
/*
    i2c-dev.c - i2c-bus driver, char device interface

    Copyright (C) 1995-97 Simon G. Vogl
    Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
    Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/* Note that this is a complete rewrite of Simon Vogl's i2c-dev module.
   But I have used so much of his original code and ideas that it seems
   only fair to recognize him as co-author -- Frodo */

/* The I2C_RDWR ioctl code is written by Kolja Waschk <waschk@telos.de> */

#define DEBUG
#ifdef DEBUG    
#define DBG(...) printk(" DBG(%s, %s(), %d): ", __FILE__, __FUNCTION__, __LINE__); printk(__VA_ARGS__)    
#else    
#define DBG(...)    
#endif    

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/jiffies.h>
#include <linux/uaccess.h>

static struct i2c_driver i2cdev_driver;

/*
 * An i2c_dev represents an i2c_adapter ... an I2C or SMBus master, not a
 * slave (i2c_client) with which messages will be exchanged.  It's coupled
 * with a character special file which is accessed by user mode drivers.
 *
 * The list of i2c_dev structures is parallel to the i2c_adapter lists
 * maintained by the driver model, and is updated using notifications
 * delivered to the i2cdev_driver.
 */
struct i2c_dev {
	struct list_head list;
	struct i2c_adapter *adap;
	struct device *dev;
};

#define I2C_MINORS	256
static LIST_HEAD(i2c_dev_list);
static DEFINE_SPINLOCK(i2c_dev_list_lock);

static struct i2c_dev *i2c_dev_get_by_minor(unsigned index)
{
	struct i2c_dev *i2c_dev;

	spin_lock(&i2c_dev_list_lock);
	list_for_each_entry(i2c_dev, &i2c_dev_list, list) {
		if (i2c_dev->adap->nr == index)
			goto found;
	}
	i2c_dev = NULL;
found:
	spin_unlock(&i2c_dev_list_lock);
	return i2c_dev;
}

static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap)
{
	struct i2c_dev *i2c_dev;

	if (adap->nr >= I2C_MINORS) {
		printk(KERN_ERR "i2c-dev: Out of device minors (%d)\n",
		       adap->nr);
		return ERR_PTR(-ENODEV);
	}

	i2c_dev = kzalloc(sizeof(*i2c_dev), GFP_KERNEL);
	if (!i2c_dev)
		return ERR_PTR(-ENOMEM);
	i2c_dev->adap = adap;

	spin_lock(&i2c_dev_list_lock);
	list_add_tail(&i2c_dev->list, &i2c_dev_list);
	spin_unlock(&i2c_dev_list_lock);
	return i2c_dev;
}

static void return_i2c_dev(struct i2c_dev *i2c_dev)
{
	spin_lock(&i2c_dev_list_lock);
	list_del(&i2c_dev->list);
	spin_unlock(&i2c_dev_list_lock);
	kfree(i2c_dev);
}

static ssize_t show_adapter_name(struct device *dev,
				 struct device_attribute *attr, char *buf)
{
	struct i2c_dev *i2c_dev = i2c_dev_get_by_minor(MINOR(dev->devt));

	if (!i2c_dev)
		return -ENODEV;
	return sprintf(buf, "%s\n", i2c_dev->adap->name);
}
static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL);

/* ------------------------------------------------------------------------- */

/*
 * After opening an instance of this character special file, a file
 * descriptor starts out associated only with an i2c_adapter (and bus).
 *
 * Using the I2C_RDWR ioctl(), you can then *immediately* issue i2c_msg
 * traffic to any devices on the bus used by that adapter.  That's because
 * the i2c_msg vectors embed all the addressing information they need, and
 * are submitted directly to an i2c_adapter.  However, SMBus-only adapters
 * don't support that interface.
 *
 * To use read()/write() system calls on that file descriptor, or to use
 * SMBus interfaces (and work with SMBus-only hosts!), you must first issue
 * an I2C_SLAVE (or I2C_SLAVE_FORCE) ioctl.  That configures an anonymous
 * (never registered) i2c_client so it holds the addressing information
 * needed by those system calls and by this SMBus interface.
 */

static ssize_t i2cdev_read(struct file *file, char __user *buf, size_t count,
		loff_t *offset)
{
	char *tmp;
	int ret;

	struct i2c_client *client = file->private_data;

	if (count > 8192)
		count = 8192;

	tmp = kmalloc(count, GFP_KERNEL);
	if (tmp == NULL)
		return -ENOMEM;

	pr_debug("i2c-dev: i2c-%d reading %zu bytes.\n",
		iminor(file->f_path.dentry->d_inode), count);

	ret = i2c_master_recv(client, tmp, count);

	if (ret >= 0)
	{
	#if 1
		DBG("发送 1 条读msg,读到的数据如下:\n");
		struct i2c_msg msg;
		msg.addr = client->addr;
		msg.len = count;
		msg.buf = tmp;
		DBG("msg.flags=0x%x\n",msg.flags);	
		DBG("msg.addr=0x%x\n",msg.addr);
		DBG("msg.len=%d\n",msg.len);
		int i;
		for(i=0;i<msg.len;i++){
		DBG("msg.buf[%d]=0x%x\n",i,msg.buf[i]);
		}
	#endif
		ret = copy_to_user(buf, tmp, count) ? -EFAULT : ret;
	}
		
	kfree(tmp);
	return ret;
}

static ssize_t i2cdev_write(struct file *file, const char __user *buf,
		size_t count, loff_t *offset)
{
	int ret;
	char *tmp;
	struct i2c_client *client = file->private_data;

	if (count > 8192)
		count = 8192;

	tmp = memdup_user(buf, count);
	if (IS_ERR(tmp))
		return PTR_ERR(tmp);

	pr_debug("i2c-dev: i2c-%d writing %zu bytes.\n",
		iminor(file->f_path.dentry->d_inode), count);

#if 1
	DBG("发送 1 条写msg,写入的数据如下:\n");
	struct i2c_msg msg;
	msg.addr = client->addr;
	msg.len = count;
	msg.buf = (char *)buf;
	DBG("msg.flags=0x%x\n",msg.flags);	
	DBG("msg.addr=0x%x\n",msg.addr);
	DBG("msg.len=%d\n",msg.len);
	int i;
	for(i=0;i<msg.len;i++){
	DBG("msg.buf[%d]=0x%x\n",i,msg.buf[i]);
	}
#endif
	ret = i2c_master_send(client, tmp, count);
	kfree(tmp);
	return ret;
}

static int i2cdev_check(struct device *dev, void *addrp)
{
	struct i2c_client *client = i2c_verify_client(dev);

	if (!client || client->addr != *(unsigned int *)addrp)
		return 0;

	return dev->driver ? -EBUSY : 0;
}

/* walk up mux tree */
static int i2cdev_check_mux_parents(struct i2c_adapter *adapter, int addr)
{
	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
	int result;

	result = device_for_each_child(&adapter->dev, &addr, i2cdev_check);
	if (!result && parent)
		result = i2cdev_check_mux_parents(parent, addr);

	return result;
}

/* recurse down mux tree */
static int i2cdev_check_mux_children(struct device *dev, void *addrp)
{
	int result;

	if (dev->type == &i2c_adapter_type)
		result = device_for_each_child(dev, addrp,
						i2cdev_check_mux_children);
	else
		result = i2cdev_check(dev, addrp);

	return result;
}

/* This address checking function differs from the one in i2c-core
   in that it considers an address with a registered device, but no
   driver bound to it, as NOT busy. */
static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
{
	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
	int result = 0;

	if (parent)
		result = i2cdev_check_mux_parents(parent, addr);

	if (!result)
		result = device_for_each_child(&adapter->dev, &addr,
						i2cdev_check_mux_children);

	return result;
}

static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
		unsigned long arg)
{
	struct i2c_rdwr_ioctl_data rdwr_arg;
	struct i2c_msg *rdwr_pa;
	u8 __user **data_ptrs;
	int i, res;

	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 = kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), GFP_KERNEL);
	if (!rdwr_pa)
		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;
	}

	res = 0;
	for (i = 0; i < rdwr_arg.nmsgs; i++) {
		/* Limit the size of the message to a sane amount;
		 * and don't let length change either. */
		if ((rdwr_pa[i].len > 8192) ||
		    (rdwr_pa[i].flags & I2C_M_RECV_LEN)) {
			res = -EINVAL;
			break;
		}
		data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf;
		rdwr_pa[i].buf = memdup_user(data_ptrs[i], rdwr_pa[i].len);
		if (IS_ERR(rdwr_pa[i].buf)) {
			res = PTR_ERR(rdwr_pa[i].buf);
			break;
		}
	}
	if (res < 0) {
		int j;
		for (j = 0; j < i; ++j)
			kfree(rdwr_pa[j].buf);
		kfree(data_ptrs);
		kfree(rdwr_pa);
		return res;
	}
	res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs);


	#if 1
	DBG("\n");
	DBG("rdwr_arg.nmsgs=%d\n",rdwr_arg.nmsgs);
	int k,ii;
	for(ii=0;ii<i;ii++)
	{
		DBG("rdwr_pa[%d].addr=0x%x\n",ii,rdwr_pa[ii].addr);
		DBG("rdwr_pa[%d].len=%d\n",ii,rdwr_pa[ii].len);
		for(k=0;k<rdwr_pa[ii].len;k++)
		{
		DBG("rdwr_pa[%d].buf[%d]=0x%x\n",ii,k,rdwr_pa[ii].buf[k]);
		}
	}
	#endif

	while (i-- > 0) {
		if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) {
			if (copy_to_user(data_ptrs[i], rdwr_pa[i].buf,
					 rdwr_pa[i].len))
				res = -EFAULT;
		}
		kfree(rdwr_pa[i].buf);
	}
	kfree(data_ptrs);
	kfree(rdwr_pa);
	return res;
}

static noinline int i2cdev_ioctl_smbus(struct i2c_client *client,
		unsigned long arg)
{
	struct i2c_smbus_ioctl_data data_arg;
	union i2c_smbus_data temp;
	int datasize, res;

	if (copy_from_user(&data_arg,
			   (struct i2c_smbus_ioctl_data __user *) arg,
			   sizeof(struct i2c_smbus_ioctl_data)))
		return -EFAULT;
	if ((data_arg.size != I2C_SMBUS_BYTE) &&
	    (data_arg.size != I2C_SMBUS_QUICK) &&
	    (data_arg.size != I2C_SMBUS_BYTE_DATA) &&
	    (data_arg.size != I2C_SMBUS_WORD_DATA) &&
	    (data_arg.size != I2C_SMBUS_PROC_CALL) &&
	    (data_arg.size != I2C_SMBUS_BLOCK_DATA) &&
	    (data_arg.size != I2C_SMBUS_I2C_BLOCK_BROKEN) &&
	    (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) &&
	    (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) {
		dev_dbg(&client->adapter->dev,
			"size out of range (%x) in ioctl I2C_SMBUS.\n",
			data_arg.size);
		return -EINVAL;
	}
	/* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1,
	   so the check is valid if size==I2C_SMBUS_QUICK too. */
	if ((data_arg.read_write != I2C_SMBUS_READ) &&
	    (data_arg.read_write != I2C_SMBUS_WRITE)) {
		dev_dbg(&client->adapter->dev,
			"read_write out of range (%x) in ioctl I2C_SMBUS.\n",
			data_arg.read_write);
		return -EINVAL;
	}

	/* Note that command values are always valid! */
	if ((data_arg.size == I2C_SMBUS_QUICK) ||
	    ((data_arg.size == I2C_SMBUS_BYTE) &&
	    (data_arg.read_write == I2C_SMBUS_WRITE)))
		/* These are special: we do not use data */
		return i2c_smbus_xfer(client->adapter, client->addr,
				      client->flags, data_arg.read_write,
				      data_arg.command, data_arg.size, NULL);

	if (data_arg.data == NULL) {
		dev_dbg(&client->adapter->dev,
			"data is NULL pointer in ioctl I2C_SMBUS.\n");
		return -EINVAL;
	}

	if ((data_arg.size == I2C_SMBUS_BYTE_DATA) ||
	    (data_arg.size == I2C_SMBUS_BYTE))
		datasize = sizeof(data_arg.data->byte);
	else if ((data_arg.size == I2C_SMBUS_WORD_DATA) ||
		 (data_arg.size == I2C_SMBUS_PROC_CALL))
		datasize = sizeof(data_arg.data->word);
	else /* size == smbus block, i2c block, or block proc. call */
		datasize = sizeof(data_arg.data->block);

	if ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
	    (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
	    (data_arg.size == I2C_SMBUS_I2C_BLOCK_DATA) ||
	    (data_arg.read_write == I2C_SMBUS_WRITE)) {
		if (copy_from_user(&temp, data_arg.data, datasize))
			return -EFAULT;
	}
	if (data_arg.size == I2C_SMBUS_I2C_BLOCK_BROKEN) {
		/* Convert old I2C block commands to the new
		   convention. This preserves binary compatibility. */
		data_arg.size = I2C_SMBUS_I2C_BLOCK_DATA;
		if (data_arg.read_write == I2C_SMBUS_READ)
			temp.block[0] = I2C_SMBUS_BLOCK_MAX;
	}
//DBG("\n");
	res = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
	      data_arg.read_write, data_arg.command, data_arg.size, &temp);
	if (!res && ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
		     (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
		     (data_arg.read_write == I2C_SMBUS_READ))) {
		if (copy_to_user(data_arg.data, &temp, datasize))
			return -EFAULT;
	}
//DBG("\n");
	return res;
}

static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	struct i2c_client *client = file->private_data;
	unsigned long funcs;

	dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n",
		cmd, arg);

	switch (cmd) {
	case I2C_SLAVE:
	case I2C_SLAVE_FORCE:
		/* NOTE:  devices set up to work with "new style" drivers
		 * can't use I2C_SLAVE, even when the device node is not
		 * bound to a driver.  Only I2C_SLAVE_FORCE will work.
		 *
		 * Setting the PEC flag here won't affect kernel drivers,
		 * which will be using the i2c_client node registered with
		 * the driver model core.  Likewise, when that client has
		 * the PEC flag already set, the i2c-dev driver won't see
		 * (or use) this setting.
		 */
		if ((arg > 0x3ff) ||
		    (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
			return -EINVAL;
		if (cmd == I2C_SLAVE && i2cdev_check_addr(client->adapter, arg))
			return -EBUSY;
		/* REVISIT: address could become busy later */
		client->addr = arg;
		return 0;
	case I2C_TENBIT:
		if (arg)
			client->flags |= I2C_M_TEN;
		else
			client->flags &= ~I2C_M_TEN;
		return 0;
	case I2C_PEC:
		if (arg)
			client->flags |= I2C_CLIENT_PEC;
		else
			client->flags &= ~I2C_CLIENT_PEC;
		return 0;
	case I2C_FUNCS:
		funcs = i2c_get_functionality(client->adapter);
		return put_user(funcs, (unsigned long __user *)arg);

	case I2C_RDWR:
		return i2cdev_ioctl_rdrw(client, arg);

	case I2C_SMBUS:
		return i2cdev_ioctl_smbus(client, arg);

	case I2C_RETRIES:
		client->adapter->retries = arg;
		break;
	case I2C_TIMEOUT:
		/* For historical reasons, user-space sets the timeout
		 * value in units of 10 ms.
		 */
		client->adapter->timeout = msecs_to_jiffies(arg * 10);
		break;
	default:
		/* NOTE:  returning a fault code here could cause trouble
		 * in buggy userspace code.  Some old kernel bugs returned
		 * zero in this case, and userspace code might accidentally
		 * have depended on that bug.
		 */
		return -ENOTTY;
	}
	return 0;
}

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;

	i2c_dev = i2c_dev_get_by_minor(minor);
	if (!i2c_dev)
		return -ENODEV;

	adap = i2c_get_adapter(i2c_dev->adap->nr);
	if (!adap)
		return -ENODEV;

	/* 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);
		return -ENOMEM;
	}
	snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
	client->driver = &i2cdev_driver;

	client->adapter = adap;
	file->private_data = client;

	return 0;
}

static int i2cdev_release(struct inode *inode, struct file *file)
{
	struct i2c_client *client = file->private_data;

	i2c_put_adapter(client->adapter);
	kfree(client);
	file->private_data = NULL;

	return 0;
}

static const struct file_operations i2cdev_fops = {
	.owner		= THIS_MODULE,
	.llseek		= no_llseek,
	.read		= i2cdev_read,
	.write		= i2cdev_write,
	.unlocked_ioctl	= i2cdev_ioctl,
	.open		= i2cdev_open,
	.release	= i2cdev_release,
};

/* ------------------------------------------------------------------------- */

/*
 * The legacy "i2cdev_driver" is used primarily to get notifications when
 * I2C adapters are added or removed, so that each one gets an i2c_dev
 * and is thus made available to userspace driver code.
 */

static struct class *i2c_dev_class;

static int i2cdev_attach_adapter(struct i2c_adapter *adap)
{
	struct i2c_dev *i2c_dev;
	int res;

	i2c_dev = get_free_i2c_dev(adap);
	if (IS_ERR(i2c_dev))
		return PTR_ERR(i2c_dev);

	/* register this i2c device with the driver core */
	i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,
				     MKDEV(I2C_MAJOR, adap->nr), NULL,
				     "i2c-%d", adap->nr);
	if (IS_ERR(i2c_dev->dev)) {
		res = PTR_ERR(i2c_dev->dev);
		goto error;
	}
	res = device_create_file(i2c_dev->dev, &dev_attr_name);
	if (res)
		goto error_destroy;

	pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
		 adap->name, adap->nr);
	return 0;
error_destroy:
	device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
error:
	return_i2c_dev(i2c_dev);
	return res;
}

static int i2cdev_detach_adapter(struct i2c_adapter *adap)
{
	struct i2c_dev *i2c_dev;

	i2c_dev = i2c_dev_get_by_minor(adap->nr);
	if (!i2c_dev) /* attach_adapter must have failed */
		return 0;

	device_remove_file(i2c_dev->dev, &dev_attr_name);
	return_i2c_dev(i2c_dev);
	device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));

	pr_debug("i2c-dev: adapter [%s] unregistered\n", adap->name);
	return 0;
}

static struct i2c_driver i2cdev_driver = {
	.driver = {
		.name	= "dev_driver",
	},
	.attach_adapter	= i2cdev_attach_adapter,
	.detach_adapter	= i2cdev_detach_adapter,
};

/* ------------------------------------------------------------------------- */

/*
 * module load/unload record keeping
 */

static int __init i2c_dev_init(void)
{
	int res;

	printk(KERN_INFO "i2c /dev entries driver\n");

	res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
	if (res)
		goto out;

	i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
	if (IS_ERR(i2c_dev_class)) {
		res = PTR_ERR(i2c_dev_class);
		goto out_unreg_chrdev;
	}

	res = i2c_add_driver(&i2cdev_driver);
	if (res)
		goto out_unreg_class;

	return 0;

out_unreg_class:
	class_destroy(i2c_dev_class);
out_unreg_chrdev:
	unregister_chrdev(I2C_MAJOR, "i2c");
out:
	printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);
	return res;
}

static void __exit i2c_dev_exit(void)
{
	i2c_del_driver(&i2cdev_driver);
	class_destroy(i2c_dev_class);
	unregister_chrdev(I2C_MAJOR, "i2c");
}

MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
		"Simon G. Vogl <simon@tk.uni-linz.ac.at>");
MODULE_DESCRIPTION("I2C /dev entries driver");
MODULE_LICENSE("GPL");

module_init


  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值