日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

i2c--test

發布時間:2024/4/14 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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 2struct eeprom {char *dev; // device file i.e. /dev/i2c-Nint addr; // i2c addressint fd; // file descriptorint 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
如下的測試代碼很直觀,借來貼上了。
refer to? http://blog.csdn.net/cjok376240497/article/details/6982883
??? #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>?? ?int main()?? ?{?? ?int fd, ret;?? ?unsigned char rdwr_addr = 0x66;?? /* e2prom 讀寫地址 */?? ?unsigned char device_addr = 0x50; /* e2prom 設備地址 */?? ?unsigned char data = 0x7;? /* 向e2prom寫的數據 */?? ?struct i2c_rdwr_ioctl_data e2prom_data;?? ?fd= open("/dev/i2c/0", O_RDWR);?? ?if(fd < 0) {?? ?perror("openerror");?? ?exit(1);?? ?}?? ?e2prom_data.msgs= (struct i2c_msg *)malloc(e2prom_data.nmsgs * \?? ?sizeof(struct i2c_msg));?? ?if(e2prom_data.msgs == NULL) {?? ?perror("mallocerror");?? ?exit(1);?? ?}?? ?ioctl(fd,I2C_TIMEOUT, 1); /* 設置超時 */?? ?ioctl(fd,I2C_RETRIES, 2); /* 設置重試次數 */?? ?//向指定地址寫入1字節數據 ????????? ?/*向e2prom的rdwr_addr地址寫入數據data*/?? ?e2prom_data.nmsgs= 1;? //http://blog.csdn.net/hongtao_liu/article/details/4964244 ?e2prom_data.msgs[0].len= 2;?? ?e2prom_data.msgs[0].addr= device_addr;?? ?e2prom_data.msgs[0].flags= 0;???? /* write */?? ?e2prom_data.msgs[0].buf= (unsigned char *)malloc(2);?? ?e2prom_data.msgs[0].buf[0]= rdwr_addr;??? /* write address */?? ?e2prom_data.msgs[0].buf[1]= data;????? /* write data */?? ?ret= ioctl(fd, I2C_RDWR, (unsigned long)&e2prom_data);?? ?if(ret < 0) {?? ?perror("writedata error");?? ?exit(1);?? ?}?? ?//printf("writedata: %d to address: %#x\n", data, rdwr_addr);?? ?data= 0;? /* be zero*/?? ?//從指定地址讀 ?? ?#if 1 /*從e2prom的rdwr_addr地址讀取數據存入buf*/?? ?e2prom_data.nmsgs= 2;?? ?e2prom_data.msgs[0].len= 1;?? ?e2prom_data.msgs[0].addr= device_addr;?? ?e2prom_data.msgs[0].flags= 0;???? /* write */?? ?e2prom_data.msgs[0].buf= &rdwr_addr;?? ?e2prom_data.msgs[1].len= 1;?? ?e2prom_data.msgs[1].addr= device_addr;?? ?e2prom_data.msgs[1].flags= 1;???? /* read */?? ?e2prom_data.msgs[1].buf= &data;?? ?#endif //從當前地址讀#if 0/*從e2prom的當前地址讀取數據存入buf*/?? ?e2prom_data.nmsgs= 1;?? ?e2prom_data.msgs[0].len= 5;?? ?e2prom_data.msgs[0].addr= device_addr;?? ?e2prom_data.msgs[0].flags= 1;???? /* read */ e2prom_data.msgs[0].buf=(unsigned char *)malloc(5);? ?#endif ret= ioctl(fd, I2C_RDWR, (unsigned long)&e2prom_data);?? ?if(ret < 0) {?? ?perror("readerror");?? ?exit(1);?? ?}?? ?//printf("read? data: %d from address: %#x\n", e2prom_data.msgs[0].buf[0],rdwr_addr);?? ?free(e2prom_data.msgs);?? ?close(fd);?? ?return 0;?? ?} 從指定地址讀,驅動執行如下動作
[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=1DBG(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=2DBG(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=2DBG(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=1DBG(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=1DBG(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=1DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 343): rdwr_pa[0].addr=0x50DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 344): rdwr_pa[0].len=2DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 347): rdwr_pa[0].buf[0]=0x66DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 347): rdwr_pa[0].buf[1]=0x7DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 338): DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 339): rdwr_arg.nmsgs=1DBG(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]=0x68DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 347): rdwr_pa[0].buf[2]=0x69DBG(drivers/i2c/i2c-dev.c, i2cdev_ioctl_rdrw(), 347): rdwr_pa[0].buf[3]=0x6aDBG(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=0x0DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 209): msg.addr=0x33DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 210): msg.len=7DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[0]=0x1DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[1]=0x38DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[2]=0x0DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[3]=0x0DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[4]=0xc7DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[5]=0xffDBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[6]=0x17DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 165): 發送 1 條讀msg,讀到的數據如下:DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 170): msg.flags=0x0DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 171): msg.addr=0x33DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 172): msg.len=15DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[0]=0x1DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[1]=0x0DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[2]=0x8DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[3]=0x0DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[4]=0x69DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[5]=0x80DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[6]=0x2DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[7]=0x1eDBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[8]=0x3DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[9]=0x15DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[10]=0x2DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[11]=0x1DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[12]=0xd3DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[13]=0xfeDBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[14]=0x17DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 203): 發送 1 條寫msg,寫入的數據如下:DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 208): msg.flags=0x0DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 209): msg.addr=0x33DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 210): msg.len=8DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[0]=0x1DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[1]=0x32DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[2]=0x1DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[3]=0x0DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[4]=0x0DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[5]=0xccDBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[6]=0xffDBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[7]=0x17DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 165): 發送 1 條讀msg,讀到的數據如下:DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 170): msg.flags=0x0DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 171): msg.addr=0x33DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 172): msg.len=11DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[0]=0x1DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[1]=0x0DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[2]=0x4DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[3]=0x0DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[4]=0x26DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[5]=0x0DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[6]=0xffDBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[7]=0x0DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[8]=0xd6DBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[9]=0xfeDBG(drivers/i2c/i2c-dev.c, i2cdev_read(), 175): msg.buf[10]=0x17DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 203): 發送 1 條寫msg,寫入的數據如下:DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 208): msg.flags=0x0DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 209): msg.addr=0x33DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 210): msg.len=60DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[0]=0x1DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[1]=0x37DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[2]=0x35DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[3]=0x0DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[4]=0x2DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[5]=0x66DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[6]=0x70DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[7]=0x0DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[8]=0x8fDBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[9]=0x82DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[10]=0x8eDBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[11]=0x83DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[12]=0xe0DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[13]=0x54DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[14]=0x1DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[15]=0x0DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[16]=0x0DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[17]=0x0DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[18]=0x70DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[19]=0xf8DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[20]=0x22DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[21]=0x78DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[22]=0xffDBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[23]=0xe4DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[24]=0xf6DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[25]=0xd8DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[26]=0xfdDBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[27]=0x2DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[28]=0x67DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[29]=0x1DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[30]=0x41DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[31]=0x13DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[32]=0x9DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[33]=0xffDBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[34]=0x63DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[35]=0x9cDBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[36]=0xeDBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[37]=0xf6DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[38]=0x75DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[39]=0x30DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[40]=0x47DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[41]=0x35DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[42]=0x39DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[43]=0xa5DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[44]=0x32DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[45]=0x1DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[46]=0x2cDBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[47]=0xe3DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[48]=0x29DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[49]=0x21DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[50]=0x26DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[51]=0x38DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[52]=0x23DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[53]=0xdfDBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[54]=0x21DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[55]=0xedDBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[56]=0x20DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[57]=0xd2DBG(drivers/i2c/i2c-dev.c, i2cdev_write(), 213): msg.buf[58]=0xeaDBG(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;} elsestat |= 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);//使能ackiiccon = 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 0int 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;elsei2c->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;//數據依次寫入消息的bufprepare_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 interfaceCopyright (C) 1995-97 Simon G. VoglCopyright (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 modifyit under the terms of the GNU General Public License as published bythe 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, 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 seemsonly 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 1DBG("發送 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]);}#endifret = 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 1DBG("發送 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]);} #endifret = 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);elseresult = i2cdev_check(dev, addrp);return result; }/* This address checking function differs from the one in i2c-corein that it considers an address with a registered device, but nodriver 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 1DBG("\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]);}}#endifwhile (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 newconvention. 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;elseclient->flags &= ~I2C_M_TEN;return 0;case I2C_PEC:if (arg)client->flags |= I2C_CLIENT_PEC;elseclient->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

轉載于:https://www.cnblogs.com/-song/archive/2011/12/01/3331913.html

總結

以上是生活随笔為你收集整理的i2c--test的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。