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

歡迎訪問(wèn) 生活随笔!

生活随笔

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

linux

Linux I2C核心、总线与设备驱动(二)

發(fā)布時(shí)間:2023/12/10 linux 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux I2C核心、总线与设备驱动(二) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

從上面的分析可知,雖然I2C硬件體系結(jié)構(gòu)比較簡(jiǎn)單,但是I2C體系結(jié)構(gòu)在Linux中的實(shí)現(xiàn)卻相當(dāng)復(fù)雜。當(dāng)工程師拿到實(shí)際的電路板,面對(duì)復(fù)雜的 Linux I2C子系統(tǒng),應(yīng)該如何下手寫驅(qū)動(dòng)呢?究竟有哪些是需要親自做的,哪些是內(nèi)核已經(jīng)提供的呢?理清這個(gè)問(wèn)題非常有意義,可以使我們面對(duì)具體問(wèn)題時(shí)迅速地抓住重點(diǎn)。
???
一方面,適配器驅(qū)動(dòng)可能是Linux內(nèi)核本身還不包含的。另一方面,掛接在適配器上的具體設(shè)備驅(qū)動(dòng)可能也是Linux不存在的。即便上述設(shè)備驅(qū)動(dòng)都存在于Linux內(nèi)核中,其基于的平臺(tái)也可能與我們的電路板不一樣。因此,工程師要實(shí)現(xiàn)的主要工作將包括:
??
提供I2C適配器的硬件驅(qū)動(dòng),探測(cè)、初始化I2C適配器(如申請(qǐng)I2CI/O地址和中斷號(hào))、驅(qū)動(dòng)CPU控制的I2C適配器從硬件上產(chǎn)生各種信號(hào)以及處理I2C中斷等。
??
提供I2C適配器的algorithm,用具體適配器的xxx_xfer()函數(shù)填充i2c_algorithmmaster_xfer指針,并把i2c_algorithm指針賦值給i2c_adapteralgo指針。
??
實(shí)現(xiàn)I2C設(shè)備驅(qū)動(dòng)與i2c_driver接口,用具體設(shè)備yyyyyy_attach_adapter()函數(shù)指針、 yyy_detach_client()函數(shù)指針和yyy_command()函數(shù)指針的賦值給i2c_driverattach_adapter detach_adapterdetach_client指針。
??
實(shí)現(xiàn)I2C設(shè)備驅(qū)動(dòng)的文件操作接口,即實(shí)現(xiàn)具體設(shè)備yyyyyy_read()yyy_write()yyy_ioctl()函數(shù)等。
上述工作中12屬于I2C總線驅(qū)動(dòng),34屬于I2C設(shè)備驅(qū)動(dòng),做完這些工作,系統(tǒng)會(huì)增加兩個(gè)內(nèi)核模塊。本章第34節(jié)將詳細(xì)分析這些工作的實(shí)施方法,給出設(shè)計(jì)模板,而5~6節(jié)將給出兩個(gè)具體的實(shí)例。
15.2 Linux I2C
核心
I2C
核心(drivers/i2c/i2c-core.c)中提供了一組不依賴于硬件平臺(tái)的接口函數(shù),這個(gè)文件一般不需要被工程師修改,但是理解其中的主要函數(shù)非常關(guān)鍵,因?yàn)?/span>I2C總線驅(qū)動(dòng)和設(shè)備驅(qū)動(dòng)之間依賴于I2C核心作為紐帶。I2C核心中的主要函數(shù)包括:
??
增加/刪除i2c_adapter
int i2c_add_adapter(struct i2c_adapter *adap);
int i2c_del_adapter(struct i2c_adapter *adap);
??
增加/刪除i2c_driver
int i2c_register_driver(struct module *owner, struct i2c_driver *driver);
int i2c_del_driver(struct i2c_driver *driver);
inline int i2c_add_driver(struct i2c_driver *driver);
?? i2c_client
依附/脫離
int i2c_attach_client(struct i2c_client *client);
int i2c_detach_client(struct i2c_client *client);
當(dāng)一個(gè)具體的client被偵測(cè)到并被關(guān)聯(lián)的時(shí)候,設(shè)備和sysfs文件將被注冊(cè)。相反地,在client被取消關(guān)聯(lián)的時(shí)候,sysfs文件和設(shè)備也被注銷,如代碼清單15.6
代碼清單15.6 I2C核心client attach/detach函數(shù)
1? int i2c_attach_client(struct i2c_client *client)
2? {
3??? ...
4? ?device_register(&client->dev);
5? ?device_create_file(&client->dev, &dev_attr_client_name);
6? ?
7? ?return 0;
8? }
9?
10 int i2c_detach_client(struct i2c_client *client)
11 {
12?? ...
13 ?device_remove_file(&client->dev, &dev_attr_client_name);
14 ?device_unregister(&client->dev);
15?? ...
16 }
4i2c傳輸、發(fā)送和接收
int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num);
int i2c_master_send(struct i2c_client *client,const char *buf ,int count);
int i2c_master_recv(struct i2c_client *client, char *buf ,int count);
i2c_transfer ()
函數(shù)用于進(jìn)行I2C適配器和I2C設(shè)備之間的一組消息交互,i2c_master_send()函數(shù)和i2c_master_recv()函數(shù)內(nèi)部會(huì)調(diào)用i2c_transfer()函數(shù)分別完成一條寫消息和一條讀消息,如代碼清單15.715.8
代碼清單15.7 I2C核心i2c_master_send函數(shù)
1? int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
2? {
3? ?int ret;
4? ?struct i2c_adapter *adap=client->adapter;
5? ?struct i2c_msg msg;
6??? /*
構(gòu)造一個(gè)寫消息*/
7? ?msg.addr = client->addr;
8? ?msg.flags = client->flags & I2C_M_TEN;
9? ?msg.len = count;
10 ?msg.buf = (char *)buf;
11 ?/*
傳輸消息*/
12 ?ret = i2c_transfer(adap, &msg, 1);
13
14 ?return (ret == 1) ? count : ret;
15 }
代碼清單15.8 I2C核心i 2c_master_recv函數(shù)
1? int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
2? {
3? ?struct i2c_adapter *adap=client->adapter;
4? ?struct i2c_msg msg;
5? ?int ret;
6?? /*
構(gòu)造一個(gè)讀消息*/
7? ?msg.addr = client->addr;
8? ?msg.flags = client->flags & I2C_M_TEN;
9? ?msg.flags |= I2C_M_RD;
10 ?msg.len = count;
11 ?msg.buf = buf;
12? /*
傳輸消息*/
13 ?ret = i2c_transfer(adap, &msg, 1);
14
15 ?/*
成功(1條消息被處理), 返回讀的字節(jié)數(shù) */
16 ?return (ret == 1) ? count : ret;
17 }
i2c_transfer()
函數(shù)本身不具備驅(qū)動(dòng)適配器物理硬件完成消息交互的能力,它只是尋找到i2c_adapter對(duì)應(yīng)的i2c_algorithm,并使用i2c_algorithmmaster_xfer()函數(shù)真正驅(qū)動(dòng)硬件流程,如代碼清單15.9
代碼清單15.9 I2C核心i 2c_transfer函數(shù)
1? int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
2? {
3? ?int ret;
4?
5? ?if (adap->algo->master_xfer) {
6? ??down(&adap->bus_lock);
7? ??ret = adap->algo->master_xfer(adap,msgs,num); /*
消息傳輸 */
8? ??up(&adap->bus_lock);
9? ??return ret;
10 ?} else {
11 ??dev_dbg(&adap->dev, "I2C level transfers not supported\n");
12 ??return -ENOSYS;
13 ?}
14 }
5I2C控制命令分派
下面函數(shù)有助于將發(fā)給I2C適配器設(shè)備文件ioctl的命令分派給對(duì)應(yīng)適配器的algorithmalgo_control()函數(shù)或i2c_drivercommand()函數(shù):
int i2c_control(struct i2c_client *client,?unsigned int cmd, unsigned long arg);
void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg);
15.3 Linux I2C
總線驅(qū)動(dòng)
15.3.1 I2C
適配器驅(qū)動(dòng)加載與卸載
I2C
總線驅(qū)動(dòng)模塊的加載函數(shù)要完成兩個(gè)工作:
??
初始化I2C適配器所使用的硬件資源,申請(qǐng)I/O地址、中斷號(hào)等。
??
通過(guò)i2c_add_adapter()添加i2c_adapter的數(shù)據(jù)結(jié)構(gòu),當(dāng)然這個(gè)i2c_adapter數(shù)據(jù)結(jié)構(gòu)的成員已經(jīng)被xxx適配器的相應(yīng)函數(shù)指針?biāo)跏蓟?/span>
I2C
總線驅(qū)動(dòng)模塊的卸載函數(shù)要完成的工作與加載函數(shù)的相反:
??
釋放I2C適配器所使用的硬件資源,釋放I/O地址、中斷號(hào)等。
??
通過(guò)i2c_del_adapter()刪除i2c_adapter的數(shù)據(jù)結(jié)構(gòu)。
代碼清單15.10給出了I2C適配器驅(qū)動(dòng)模塊加載和卸載函數(shù)的模板。
代碼清單15.10 I2C總線驅(qū)動(dòng)模塊加載和卸載函數(shù)模板
1? static int __init i2c_adapter_xxx_init(void)
2? {
3??? xxx_adpater_hw_init();
4??? i2c_add_adapter(&xxx_adapter);
5? }
6?
7? static void __exit i2c_adapter_xxx_exit(void)
8? {
9??? xxx_adpater_hw_free();
10?? i2c_del_adapter(&xxx_adapter);
11 }
上述代碼中xxx_adpater_hw_init()xxx_adpater_hw_free()函數(shù)的實(shí)現(xiàn)都與具體的CPUI2C設(shè)備硬件直接相關(guān)。
15.3.2 I2C
總線通信方法
我們需要為特定的I2C適配器實(shí)現(xiàn)其通信方法,主要實(shí)現(xiàn)i2c_algorithmmaster_xfer()函數(shù)和functionality()函數(shù)。
functionality ()
函數(shù)非常簡(jiǎn)單,用于返回algorithm所支持的通信協(xié)議,如I2C_FUNC_I2CI2C_FUNC_10BIT_ADDR I2C_FUNC_SMBUS_READ_BYTEI2C_FUNC_SMBUS_WRITE_BYTE等。
master_xfer()
函數(shù)在I2C適配器上完成傳遞給它的i2c_msg數(shù)組中的每個(gè)I2C消息,代碼清單15.11給出了xxx設(shè)備的master_xfer()函數(shù)模板。
代碼清單15.11 I2C總線驅(qū)動(dòng)master_xfer函數(shù)模板
1? static int i2c_adapter_xxx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
2??? int num)
3? {
4??? ...
5??? for (i = 0; i < num; i++)
6??? {
7????? i2c_adapter_xxx_start(); /*
產(chǎn)生開始位*/
8????? /*
是讀消息*/
9????? if (msgs[i]->flags &I2C_M_RD)
10???? {
11?????? i2c_adapter_xxx_setaddr((msg->addr << 1) | 1); /*
發(fā)送從設(shè)備讀地址*/
12?????? i2c_adapter_xxx_wait_ack(); /*
獲得從設(shè)備的ack*/
13?????? i2c_adapter_xxx_readbytes(msgs[i]->buf, msgs[i]->len); /*
讀取msgs[i]
14???????? ->len
長(zhǎng)的數(shù)據(jù)到msgs[i]->buf*/
15???? }
16???? else
17????? /*
是寫消息*/
18???? {
19?????? i2c_adapter_xxx_setaddr(msg->addr << 1); /*
發(fā)送從設(shè)備寫地址*/
20?????? i2c_adapter_xxx_wait_ack(); /*
獲得從設(shè)備的ack*/
21?????? i2c_adapter_xxx_writebytes(msgs[i]->buf, msgs[i]->len); /*
讀取msgs[i]
22???????? ->len
長(zhǎng)的數(shù)據(jù)到msgs[i]->buf*/
23???? }
24?? }
25?? i2c_adapter_xxx_stop(); /*
產(chǎn)生停止位*/
26 }
述代碼實(shí)際上給出了一個(gè)master_xfer()函數(shù)處理I2C消息數(shù)組的流程,對(duì)于數(shù)組中的每個(gè)消息,判斷消息類型,若為讀消息,則賦從設(shè)備地址為 (msg->addr << 1) | 1,否則為msg->addr << 1。對(duì)每個(gè)消息產(chǎn)生1個(gè)開始位,緊接著傳送從設(shè)備地址,然后開始數(shù)據(jù)的發(fā)送或接收,對(duì)最后的消息還需產(chǎn)生1個(gè)停止位。圖15.3描述了整個(gè) master_xfer()完成的時(shí)序。


15.3 algorithmmaster_xfer的時(shí)序

master_xfer() 數(shù)模板中的i2c_adapter_xxx_start()i2c_adapter_xxx_setaddr() i2c_adapter_xxx_wait_ack()i2c_adapter_xxx_readbytes() i2c_adapter_xxx_writebytes()i2c_adapter_xxx_stop()函數(shù)用于完成適配器的底層硬件操作,與I2C 適配器和CPU的具體硬件直接相關(guān),需要由工程師根據(jù)芯片的數(shù)據(jù)手冊(cè)來(lái)實(shí)現(xiàn)。
i2c_adapter_xxx_readbytes()
用于從從設(shè)備上接收一串?dāng)?shù)據(jù),i2c_adapter_xxx_writebytes()用于向從設(shè)備寫入一串?dāng)?shù)據(jù),這兩個(gè)函數(shù)的內(nèi)部也會(huì)涉及到I2C總線協(xié)議中的ACK應(yīng)答。
master_xfer ()
函數(shù)的實(shí)現(xiàn)在形式上會(huì)很多樣,即便是Linux內(nèi)核源代碼中已經(jīng)給出的一些I2C總線驅(qū)動(dòng)的master_xfer()函數(shù),由于由不同的組織或個(gè)人 完成,風(fēng)格上的差別也非常大,不一定能與模板完全對(duì)應(yīng),如master_xfer()函數(shù)模板給出的消息處理是順序進(jìn)行的,而有的驅(qū)動(dòng)以中斷方式來(lái)完成這 個(gè)流程(第5節(jié)的實(shí)例即是如此)。不管具體怎么實(shí)施,流程的本質(zhì)都是不變的。因?yàn)檫@個(gè)流程不以驅(qū)動(dòng)工程師的意志為轉(zhuǎn)移,最終由I2C總線硬件上的通信協(xié)議 決定。
多數(shù)I2C總線驅(qū)動(dòng)會(huì)定義一個(gè)xxx_i2c結(jié)構(gòu)體,作為i2c_adapteralgo_data(類似私有數(shù)據(jù)),其中包含 I2C消息數(shù)組指針、數(shù)組索引及I2C適配器algorithm訪問(wèn)控制用的自旋鎖、等待隊(duì)列等,而master_xfer()函數(shù)完成消息數(shù)組中消息的 處理也可通過(guò)對(duì)xxx_i2c結(jié)構(gòu)體相關(guān)成員的訪問(wèn)來(lái)控制。代碼清單15.12給出了xxx_i2c結(jié)構(gòu)體的定義,與圖15.2中的xxx_i2c是對(duì)應(yīng) 的。
代碼清單15.12 xxx_i2c結(jié)構(gòu)體模板
1? struct xxx_i2c
2? {
3? ?spinlock_t??lock;
4? ?wait_queue_head_t?wait;?
5? ?struct i2c_msg??*msg;
6? ?unsigned int??msg_num;
7? ?unsigned int??msg_idx;
8? ?unsigned int??msg_ptr;
9?? ...
10 ?struct i2c_adapter?adap;
11 };
15.4 Linux I2C
設(shè)備驅(qū)動(dòng)
I2C
設(shè)備驅(qū)動(dòng)要使用i2c_driveri2c_client數(shù)據(jù)結(jié)構(gòu)并填充其中的成員函數(shù)。i2c_client一般被包含在設(shè)備的私有信息結(jié)構(gòu)體 yyy_data中,而i2c_driver則適宜被定義為全局變量并初始化,代碼清單15.13顯示了被初始化的i2c_driver
代碼清單15.13 初始化的i2c_driver
1? static struct i2c_driver yyy_driver =
2? {
3??? .driver =
4??? {
5????? .name = "yyy",
6??? } ,
7??? .attach_adapter = yyy_attach_adapter,
8??? .detach_client =? yyy_detach_client,
9??? .command = yyy_command,
10 };
15.4.1 Linux I2C
設(shè)備驅(qū)動(dòng)模塊加載與卸載
I2C
設(shè)備驅(qū)動(dòng)模塊加載函數(shù)通用的方法是在I2C設(shè)備驅(qū)動(dòng)模塊加載函數(shù)中完成兩件事:
??
通過(guò)register_chrdev()函數(shù)將I2C設(shè)備注冊(cè)為一個(gè)字符設(shè)備。
??
通過(guò)I2C核心的i2c_add_driver()函數(shù)添加i2c_driver
在模塊卸載函數(shù)中需要做相反的兩件事:
??
通過(guò)I2C核心的i2c_del_driver()函數(shù)刪除i2c_driver
??
通過(guò)unregister_chrdev()函數(shù)注銷字符設(shè)備。
代碼清單15.14給出了I2C設(shè)備驅(qū)動(dòng)加載與卸載函數(shù)的模板。
代碼清單15.14 I2C設(shè)備驅(qū)動(dòng)模塊加載與卸載函數(shù)模板
1? static int __init yyy_init(void)
2? {
3??? int res;
4??? /*
注冊(cè)字符設(shè)備*/
5??? res = register_chrdev(YYY_MAJOR, "yyy", &yyy_fops); //
老內(nèi)核接口
6??? if (res)
7????? goto out;
8??? /*
添加i2c_driver*/
9??? res = i2c_add_driver(&yyy_driver);
10?? if (res)
11???? goto out_unreg_class;
12?? return 0;
13
14?? out_unreg_chrdev: unregister_chrdev(I2C_MAJOR, "i2c");
15?? out: printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);
16?? return res;
17 }
18
19 static void __exit yyy_exit(void)
20 {
21?? i2c_del_driver(&i2cdev_driver);
22?? unregister_chrdev(YYY_MAJOR, "yyy");
23 }
5行代碼說(shuō)明注冊(cè)“yyy”這個(gè)字符設(shè)備時(shí),使用的file_operations結(jié)構(gòu)體為yyy_fops15.4.3節(jié)將講解這個(gè)結(jié)構(gòu)體中成員函數(shù)的實(shí)現(xiàn)。
15.4.2 Linux I2C
設(shè)備驅(qū)動(dòng)i2c_driver成員函數(shù)
i2c_add_driver (&yyy_driver)
的執(zhí)行會(huì)引發(fā)i2c_driver結(jié)構(gòu)體中yyy_attach_adapter()函數(shù)的執(zhí)行,我們可以在 yyy_attach_adapter()函數(shù)里探測(cè)物理設(shè)備。為了實(shí)現(xiàn)探測(cè),yyy_attach_adapter()函數(shù)里面也只需簡(jiǎn)單地調(diào)用I2C 核心的i2c_probe()函數(shù),如代碼清單15.15
代碼清單15.15 I2C設(shè)備驅(qū)動(dòng)i2c_attach_adapter函數(shù)模板
1 static int yyy_attach_adapter(struct i2c_adapter *adapter)
2 {
3 ?return i2c_probe(adapter, &addr_data, yyy_detect);
4 }
代碼第3行傳遞給i2c_probe()函數(shù)的第1個(gè)參數(shù)是i2c_adapter指針,第2個(gè)參數(shù)是要探測(cè)的地址數(shù)據(jù),第3個(gè)參數(shù)是具體的探測(cè)函數(shù)。要探測(cè)的地址實(shí)際列表在一個(gè)16位無(wú)符號(hào)整型數(shù)組中,這個(gè)數(shù)組以I2C_CLIENT_END為最后一個(gè)元素。
i2c_probe()
函數(shù)會(huì)引發(fā)yyy_detect()函數(shù)的調(diào)用,可以在yyy_detect()函數(shù)中初始化i2c_client,如代碼清單15.16
代碼清單15.16 I2C設(shè)備驅(qū)動(dòng)detect函數(shù)模板
1? static int yyy_detect(struct i2c_adapter *adapter, int address, int kind)
2? {
3?? struct i2c_client *new_client;
4?? struct yyy_data *data;
5?? int err = 0;
6
7?? if (!i2c_check_functionality(adapter, I2C_FUNC_XXX)
8???? goto exit;
9
10? if (!(data = kzalloc(sizeof(struct yyy_data), GFP_KERNEL)))
11? {
12??? err =? - ENOMEM;
13??? goto exit;
14? }
15
16? new_client = &data->client;
17? new_client->addr = address;
18? new_client->adapter = adapter;
19? new_client->driver = &yyy_driver;
20? new_client->flags = 0;
21
22? /*
新的client將依附于adapter */
23? if ((err = i2c_attach_client(new_client)))
24??? goto exit_kfree;
25?
26? yyy_init_client(new_client);
27? return 0;
28? exit_kfree: kfree(data);
29? exit: return err;
30}
碼第10行分配私有信息結(jié)構(gòu)體的內(nèi)存,i2c_client也被創(chuàng)建。第1620行對(duì)新創(chuàng)建的i2c_client進(jìn)行初始化。第23行調(diào)用內(nèi)核的 i2c_attach_client()知會(huì)I2C核心系統(tǒng)中包含了一個(gè)新的I2C設(shè)備。第26行代碼初始化i2c_client對(duì)應(yīng)的I2C設(shè)備,這個(gè) 函數(shù)是硬件相關(guān)的。
15.4描述了當(dāng)I2C設(shè)備驅(qū)動(dòng)的模塊加載函數(shù)被調(diào)用的時(shí)候引發(fā)的連鎖反應(yīng)的流程。


15.4 I2C設(shè)備驅(qū)動(dòng)模塊加載連鎖反應(yīng)

I2C 設(shè)備驅(qū)動(dòng)卸載函數(shù)進(jìn)行i2c_del_driver(&yyy_driver)調(diào)用后,會(huì)引發(fā)與yyy_driver關(guān)聯(lián)的每個(gè) i2c_client與之解除關(guān)聯(lián),即yyy_detach_client()函數(shù)將因此而被調(diào)用,代碼清單15.17給出了函數(shù) yyy_detach_client()的設(shè)計(jì)。
代碼清單15.17 I2C設(shè)備驅(qū)動(dòng)i2c_detach_client函數(shù)模板
1? static int yyy_detach_client(struct i2c_client *client)
2? {
3? ?int err;
4? ?struct yyy_data *data = i2c_get_clientdata(client);
5?
6? ?if ((err = i2c_detach_client(client)))
7? ??return err;
8?
9? ?kfree(data);
10 ?return 0;
11 }
述函數(shù)中第4行的i2c_get_clientdata()函數(shù)用于從yyy_data私有信息結(jié)構(gòu)中的i2c_client的指針獲取yyy_data 的指針。第6行調(diào)用I2C核心函數(shù)i2c_detach_client(),這個(gè)函數(shù)會(huì)引發(fā)i2c_adapterclient_unregister ()函數(shù)被調(diào)用。第9行代碼釋放yyy_data的內(nèi)存。
15.5描述了當(dāng)I2C設(shè)備驅(qū)動(dòng)的模塊卸載函數(shù)被調(diào)用的時(shí)候引發(fā)的連鎖反應(yīng)的流程。


15.5 I2C設(shè)備驅(qū)動(dòng)模塊卸載連鎖反應(yīng)

下面開始分析i2c_driver中重要函數(shù)yyy_command()的實(shí)現(xiàn),它實(shí)現(xiàn)了針對(duì)設(shè)備的控制命令。具體的控制命令是設(shè)備相關(guān)的,如對(duì)于實(shí)時(shí)鐘而言,命令將是設(shè)置時(shí)間和獲取時(shí)間,而對(duì)于視頻AD設(shè)備而言,命令會(huì)是設(shè)置采樣方式、選擇通道等。
假設(shè)yyy設(shè)備接受兩類命令YYY_CMD1YYY_CMD2,而處理這兩個(gè)命令的函數(shù)分別為yyy_cmd1()yyy_cmd2(),代碼清單15.18給出了yyy_command()函數(shù)的設(shè)計(jì)。
代碼清單15.18 I2C設(shè)備驅(qū)動(dòng)command函數(shù)模板
1? static int yyy_command(struct i2c_client *client, unsigned int cmd, void
2??? *arg)
3? {
4??? switch (cmd)
5??? {
6????? case YYY_CMD1:
7??????? return yyy_cmd1(client, arg);?
8????? case YYY_CMD2:
9??????? return yyy_cmd2(client, arg);
10???? default:
11?????? return? - EINVAL;
12?? }
13 }
具體命令的實(shí)現(xiàn)是通過(guò)組件i2c_msg消息數(shù)組,并調(diào)用I2C核心的傳輸、發(fā)送和接收函數(shù),由I2C核心的傳輸、發(fā)送和接收函數(shù)調(diào)用I2C適配器對(duì)應(yīng)的algorithm相關(guān)函數(shù)來(lái)完成的。代碼清單15.19給出了一個(gè)yyy_cmd1()的例子。
代碼清單15.19 I2C設(shè)備具體命令處理函數(shù)模板
1? static int yyy_cmd1(struct i2c_client *client, struct rtc_time *dt)
2? {
3? ?struct i2c_msg msg[2];
4?? /*
第一條消息是寫消息*/
5? ?msg[0].addr = client->addr;
6? ?msg[0].flags = 0;
7? ?msg[0].len = 1;
8? ?msg[0].buf = &offs;
9? ?/*
第二條消息是讀消息*/
10 ?msg[1].addr = client->addr;
11 ?msg[1].flags = I2C_M_RD;
12 ?msg[1].len = sizeof(buf);
13 ?msg[1].buf = &buf[0];
14 ?
15 ?i2c_transfer(client->adapter, msg, 2);
16?? ...
17 }
15.4.3 Linux I2C
設(shè)備驅(qū)動(dòng)文件操作接口
為一種字符類設(shè)備,Linux I2C設(shè)備驅(qū)動(dòng)文件操作接口與普通的設(shè)備驅(qū)動(dòng)是完全一致的,但是在其中要使用i2c_clienti2c_driveri2c_adapter i2c_algorithm結(jié)構(gòu)體和I2C核心,并且對(duì)設(shè)備的讀寫和控制需要借助體系結(jié)構(gòu)中各組成部分的協(xié)同合作。代碼清單15.20給出一個(gè)I2C設(shè)備 寫函數(shù)的例子。
代碼清單15.20 I2C設(shè)備文件接口寫函數(shù)范例
1? static ssize_t yyy_write(struct file *file, char *buf, size_t count, loff_t off)
2? {
3??? struct i2c_client *client = (struct i2c_client*)file->private_data;
4??? i2c_msg msg[1];
5??? char *tmp;
6??? int ret;
7?
8??? tmp = kmalloc(count, GFP_KERNEL);
9??? if (tmp == NULL)
10???? return? - ENOMEM;
11?? if (copy_from_user(tmp, buf, count))
12?? {
13???? kfree(tmp);
14???? return? - EFAULT;
15?? }
16
17?? msg[0].addr = client->addr;//
地址
18?? msg[0].flags = 0;?????? //0
為寫
19?? msg[0].len = count;???? //
要寫的字節(jié)數(shù)
20?? msg[0].buf = tmp;????? //
要寫的數(shù)據(jù)
21?? ret = i2c_transfer(client->adapter, msg, 1);? //
傳輸i2c消息
22?? return (ret == 1) ? count : ret;
23 }
上述程序給出的僅僅是一個(gè)寫函數(shù)的例子,具體的寫操作與設(shè)備密切相關(guān)。我們通過(guò)這個(gè)例來(lái)仔細(xì)分析I2C設(shè)備讀寫過(guò)程中數(shù)據(jù)的流向和函數(shù)的調(diào)用關(guān)系。I2C設(shè)備的寫操作經(jīng)歷了如下幾個(gè)步驟:
從用戶空間到字符設(shè)備驅(qū)動(dòng)寫函數(shù)接口,寫函數(shù)構(gòu)造I2C消息數(shù)組。
寫函數(shù)把構(gòu)造的I2C消息數(shù)組傳遞給I2C核心的傳輸函數(shù)i2c_transfer()
I2C核心的傳輸函數(shù)i2c_transfer()找到對(duì)應(yīng)適配器algorithm的通信方法函數(shù)master_xfer()去最終完成I2C消息的處理。
15.6描述了從用戶空間發(fā)起讀寫操作到algorithm進(jìn)行消息傳輸?shù)牧鞒獭?/span>

?
15.6 I2C設(shè)備讀寫完整流程

總結(jié)

以上是生活随笔為你收集整理的Linux I2C核心、总线与设备驱动(二)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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