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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux iopen i2c dev,i2c-dev - Linux驱动子系统之I2C_Linux编程_Linux公社-Linux系统门户网站...

發(fā)布時間:2023/12/15 linux 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux iopen i2c dev,i2c-dev - Linux驱动子系统之I2C_Linux编程_Linux公社-Linux系统门户网站... 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

[概述]

之前在介紹I2C子系統(tǒng)時,提到過使用i2c-dev.c文件在應(yīng)用程序中實(shí)現(xiàn)我們的I2C從設(shè)備驅(qū)動。不過,它實(shí)現(xiàn)的是一個虛擬,臨時的i2c_client,隨著設(shè)備文件的打開而產(chǎn)生,并隨著設(shè)備文件的關(guān)閉而撤銷。I2c-dev.c針對每個I2C適配器生成一個主設(shè)備號為89的設(shè)備文件,實(shí)現(xiàn)了i2c_driver的成員函數(shù)以及文件操作接口,所以i2c-dev.c的主題是”i2c_driver成員函數(shù)+字符設(shè)備驅(qū)動”。

[i2c-dev.c源碼分析]

I2c-dev初始化函數(shù)主要做了注冊名為”i2c”的字符設(shè)備文件和”i2c-dev”的類。

I2c-dev.c中實(shí)現(xiàn)的i2cdev_read和i2cdev_write函數(shù)不具有太強(qiáng)的通用性,只適合下面這種單開始信號情況:

而不適合多開始信號的情況:

所以我們經(jīng)常會使用i2cdev_ioctl函數(shù)的I2C_RDWR,在分析i2cdev_ioctl函數(shù)之前,我們需要了解一個結(jié)構(gòu)體:

/*?This?is?the?structure?as?used?in?theI2C_RDWR?ioctl?call?*/

structi2c_rdwr_ioctl_data?{

structi2c_msg?__user?*msgs;/*?pointersto?i2c_msgs?*/

__u32nmsgs;/*?number?ofi2c_msgs?*/

};

Msgs?????表示單個開始信號傳遞的數(shù)據(jù);

Nmsgs???? 表示有多少個msgs,比如上圖,單開始信號時,nmsgs等于1;多開始信號時,nmsgs等于2

structi2c_msg?{

__u16addr;/*?slave?address?????????????????????????*/

__u16flags;/*?默認(rèn)為寫入?*/

#define?I2C_M_TEN??????????????????0x0010?????/*this?is?a?ten?bit?chip?address?*/

#define?I2C_M_RD???????????0x0001?????/*?readdata,?from?slave?to?master?*/

#define?I2C_M_NOSTART??????????????????0x4000?????/*?if?I2C_FUNC_PROTOCOL_MANGLING?*/

#define?I2C_M_REV_DIR_ADDR?????0x2000?????/*if?I2C_FUNC_PROTOCOL_MANGLING?*/

#define?I2C_M_IGNORE_NAK??????????0x1000?????/*if?I2C_FUNC_PROTOCOL_MANGLING?*/

#define?I2C_M_NO_RD_ACK???????????0x0800?????/*?if?I2C_FUNC_PROTOCOL_MANGLING?*/

#define?I2C_M_RECV_LEN???????????????0x0400?????/*?length?will?be?first?received?byte?*/

__u16len;/*?msg?length??????????????????????????????*/

__u8*buf;/*?pointer?to?msgdata???????????????????????*/

};

使用i2cdev_ioctl函數(shù)的I2C_RDWR指令會調(diào)用到i2cdev_ioctl_rdrw函數(shù):

staticnoinlineinti2cdev_ioctl_rdrw(structi2c_client?*client,

unsignedlong?arg)

{

structi2c_rdwr_ioctl_data?rdwr_arg;

structi2c_msg?*rdwr_pa;

u8__user?**data_ptrs;

inti,?res;

if(copy_from_user(&rdwr_arg,

(structi2c_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(structi2c_msg),?GFP_KERNEL);

if(!rdwr_pa)

return-ENOMEM;

if(copy_from_user(rdwr_pa,?rdwr_arg.msgs,

rdwr_arg.nmsgs?*sizeof(structi2c_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?

/*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?

intj;

for(j?=?0;?j?

kfree(rdwr_pa[j].buf);

kfree(data_ptrs);

kfree(rdwr_pa);

returnres;

}

res=?i2c_transfer(client->adapter,?rdwr_pa,?rdwr_arg.nmsgs);

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);

returnres;

}

咋一看,還挺復(fù)雜,其實(shí)主要做了一件事情:把用戶空間傳遞過來的i2c_rdwr_ioctl_data數(shù)據(jù)進(jìn)行錯誤檢查,www.linuxidc.com?然后調(diào)用i2c_transfer函數(shù)與適配器進(jìn)行通信,如果是接收數(shù)據(jù),代碼會將訪問到的數(shù)據(jù)傳回i2c_rdwr_ioctl_data的buf中。I2c_transfer最終會調(diào)用到I2C適配器具體實(shí)現(xiàn)的master_xfer函數(shù)來與硬件進(jìn)行通信。

[eeprom實(shí)例]

預(yù)備知識

使用的mini2440開發(fā)板,eeprom的地址為0x50,實(shí)驗完成一個數(shù)據(jù)的讀寫,先看下讀寫時序

AT24C08任意地址字節(jié)寫的時序:

AT24C08任意地址字節(jié)寫的時序:

下面的代碼可以按照上面的兩個圖來閱讀:

#include?

#include?

#include?

#include?

#include?

#include?

#include?

#include?

#include?

#include?

#include?

#include?

intmain()

{

intfd,?ret;

unsignedchar?rdwr_addr?=?0x42;/*?e2prom?讀寫地址?*/

unsignedchar?device_addr?=?0x50;/*?e2prom?設(shè)備地址?*/

unsignedchar?data?=?0x12;/*?向e2prom寫的數(shù)據(jù)?*/

structi2c_rdwr_ioctl_data?e2prom_data;

fd=?open("/dev/i2c/0",?O_RDWR);

if(fd?

perror("openerror");

exit(1);

}

e2prom_data.msgs=?(structi2c_msg?*)malloc(e2prom_data.nmsgs?*?\

sizeof(structi2c_msg));

if(e2prom_data.msgs?==?NULL)?{

perror("mallocerror");

exit(1);

}

ioctl(fd,I2C_TIMEOUT,?1);/*?設(shè)置超時?*/

ioctl(fd,I2C_RETRIES,?2);/*?設(shè)置重試次數(shù)?*/

/*向e2prom的rdwr_addr地址寫入數(shù)據(jù)data*/

e2prom_data.nmsgs=?1;

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=?(unsignedchar*)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,?(unsignedlong)&e2prom_data);

if(ret?

perror("writedata?error");

exit(1);

}

printf("writedata:?%d?to?address:?%#x\n",?data,?rdwr_addr);

data=?0;/*?be?zero*/

/*從e2prom的rdwr_addr地址讀取數(shù)據(jù)存入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;

ret=?ioctl(fd,?I2C_RDWR,?(unsignedlong)&e2prom_data);

if(ret?

perror("readerror");

exit(1);

}

printf("read??data:?%d?from?address:?%#x\n",?data,rdwr_addr);

free(e2prom_data.msgs);

close(fd);

return0;

}

在mini2440開發(fā)板上已經(jīng)實(shí)驗成功。

總結(jié)

以上是生活随笔為你收集整理的linux iopen i2c dev,i2c-dev - Linux驱动子系统之I2C_Linux编程_Linux公社-Linux系统门户网站...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。