娇小w搡bbbb搡bbb,《第一次の人妻》,中国成熟妇女毛茸茸,边啃奶头边躁狠狠躁视频免费观看

Linux驅(qū)動:I2C驅(qū)動編寫要點

發(fā)布者:leader4最新更新時間:2025-01-09 來源: cnblogs關(guān)鍵字:Linux驅(qū)動  I2C驅(qū)動 手機看文章 掃描二維碼
隨時隨地手機看文章

繼續(xù)上一篇博文沒講完的內(nèi)容“針對 RepStart 型i2c設(shè)備的驅(qū)動模型”,其中涉及的內(nèi)容有:i2c_client 的注冊、i2c_driver 的注冊、驅(qū)動程序的編寫。


一、i2c 設(shè)備的注冊分析:在新版本內(nèi)核的i2c驅(qū)動模型中,支持多種方式來注冊 i2c 設(shè)備,在Documentation/i2c/instantiating-devices文件中有講到,在內(nèi)核中對應的抽象數(shù)據(jù)結(jié)構(gòu)就是 struct i2c_client。


(1)Declare the I2C devices by bus number 以i2c總線號來聲明設(shè)備:主要適用于嵌入式系統(tǒng)設(shè)備,系統(tǒng)外的設(shè)備比較固定。


通過 struct i2c_board_info 結(jié)構(gòu)來聲明,使用 i2c_register_board_info() 函數(shù)來注冊。


 1 //在include/linux/i2c.h中

 2 struct i2c_board_info {

 3     char              type[I2C_NAME_SIZE]; //設(shè)備名稱

 4     unsigned short    flags;

 5     unsigned short    addr;  //設(shè)備地址

 6     void              *platform_data;

 7     struct dev_archdata     *archdata;

 8     struct device_node      *of_node;

 9     struct acpi_dev_node acpi_node;

10     int       irq;

11 };

12 

13 //在drivers/i2c/i2c-boardinfo.c中

14 LIST_HEAD(__i2c_board_list);

15 EXPORT_SYMBOL_GPL(__i2c_board_list);

16 

17 int __init i2c_register_board_info(int busnum,struct i2c_board_info const *info, unsigned len)

18 {

19     int status;

20 

21     /* dynamic bus numbers will be assigned after the last static one */

22     if (busnum >= __i2c_first_dynamic_bus_num)

23         __i2c_first_dynamic_bus_num = busnum + 1;

24         //__i2c_first_dynamic_bus_num是個全局變量,初始值為0,因此,他的值始終比busnum大1!這一點可以解決上一篇博文中提出的一個問題。

25 

26     for (status = 0; len; len--, info++) {

27         struct i2c_devinfo    *devinfo;

28 

29         devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);

30         if (!devinfo) {

31             pr_debug('i2c-core: can't register boardinfo!n');

32             status = -ENOMEM;

33             break;

34         }

35 

36         devinfo->busnum = busnum;

37         devinfo->board_info = *info;

38         list_add_tail(&devinfo->list, &__i2c_board_list);//將這個 i2c_board_info 添加到該總線的 __i2c_board_list i2c設(shè)備鏈表中

39     }

40     return status;

41 }


問題思考:board_list 鏈表結(jié)構(gòu)是怎樣的?是一條 i2c總線一條鏈表還是類似于哈希鏈表?

尋找答案:答案是一條i2c設(shè)備鏈表,里邊鏈著的是所有i2c總線上的設(shè)備,分析i2c-core.c中的函數(shù):


1 i2c_scan_static_board_info(struct i2c_adapter *adapter)

2     list_for_each_entry(devinfo, &__i2c_board_list, list) {

3             if (devinfo->busnum == adapter->nr && !i2c_new_device(adapter,&devinfo->board_info))

4                     dev_err(&adapter->dev,'Can't create device at 0x%02xn',devinfo->board_info.addr);

5     }

6 //遍歷__i2c_board_list這整個鏈表,比較其中每一個結(jié)點的 busnum 與 adapter->nr是否相等


看看這種方法的具體應用:以 at24cxx 為例來分析。


 1 //在arch/arm/mach-s5pv210/mach-smdkv210.c中

 2 static struct i2c_board_info smdkv210_i2c_devs0[] __initdata = {

 3     { I2C_BOARD_INFO('tq210-at24cxx', 0x50), }, /* 目標i2c外設(shè) */

 4     { I2C_BOARD_INFO('wm8580', 0x1b), },

 5 };

 6 smdkv210_machine_init()

 7 {

 8     ...

 9     i2c_register_board_info(0, smdkv210_i2c_devs0,ARRAY_SIZE(smdkv210_i2c_devs0));//注冊i2c-0總線上的i2c設(shè)備到設(shè)備鏈表

10     i2c_register_board_info(1, smdkv210_i2c_devs1,ARRAY_SIZE(smdkv210_i2c_devs1));//注冊i2c-1總線上的i2c設(shè)備到設(shè)備鏈表

11     i2c_register_board_info(2, smdkv210_i2c_devs2,ARRAY_SIZE(smdkv210_i2c_devs2));//注冊i2c-2總線上的i2c設(shè)備到設(shè)備鏈表

12     ...

13 }


我們在前一篇博文中分析platform_driver.probe函數(shù)(s3c24xx_i2c_probe)的時候得知函數(shù)的調(diào)用關(guān)系是:


i2c_add_numbered_adapter -> i2c_register_adapter -> i2c_scan_static_board_info -> i2c_new_device,即在i2c_adapter注冊好之后內(nèi)核會去嘗試從__i2c_board_list鏈表中搜索匹配的i2c設(shè)備。這種方法有個缺陷就是:必須在調(diào)用 i2c_register_adapter 來注冊 i2c_adapter 之前就把i2c設(shè)備鏈表注冊好,因此,不適合使用 insmod 來動態(tài)注冊i2c設(shè)備。


(2)Instantiate the devices explicitly 立即檢測 i2c設(shè)備:


這種方法就是“認為i2c設(shè)備一定肯定存在”后直接使用 i2c_new_device函數(shù)來注冊i2c_client??纯丛鯓幼?,再來詳細跟進這個函數(shù):


 1 struct i2c_client *i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)

 2 {

 3     struct i2c_client    *client;

 4     int            status;

 5 

 6     client = kzalloc(sizeof *client, GFP_KERNEL);

 7     

 8     // 設(shè)置這個client

 9     client->adapter = adap;

10     client->dev.platform_data = info->platform_data;

11     ......

12     client->flags = info->flags;

13     client->addr = info->addr;

14     client->irq = info->irq;

15     strlcpy(client->name, info->type, sizeof(client->name));

16     /* Check for address validity */

17     status = i2c_check_client_addr_validity(client); // 地址合法性

18     ......

19     /* Check for address business */

20     status = i2c_check_addr_busy(adap, client->addr);// 地址是否被復用

21     .....

22     client->dev.bus = &i2c_bus_type;

23     client->dev.type = &i2c_client_type;

24     .....

25     status = device_register(&client->dev); //注冊i2c_client設(shè)備

26     ......

27     return client; //返回i2c_client結(jié)構(gòu),方便在字符設(shè)備編程中的使用!!!

28     ......

29 }


但是使用這個函數(shù)前從其參數(shù)可以發(fā)現(xiàn)需要準備一些材料:i2c_adapter 和 i2c_board_list ,i2c_adapter 需要用核心層的 i2c_get_adapter() 函數(shù)來獲得, i2c_board_list 的話自己現(xiàn)場構(gòu)造一個。


其實到這里就可以看穿其真實面目:把之前放在注冊 i2c_adapter之后的任務(wù):遍歷 i2c_board_list 鏈表來注冊 i2c_client 版移到這里來實現(xiàn),這樣就可以使用 “insmod” 來動態(tài)裝載i2c設(shè)備了。


(3)Probe an I2C bus for certain devices 通過probe來探測確定在i2c總線上的設(shè)備:


使用核心層的 i2c_new_probed_device函數(shù)來實現(xiàn):


 1 i2c_new_probed_device(struct i2c_adapter *adap,struct i2c_board_info *info,unsigned short const *addr_list,int (*probe)(struct i2c_adapter *, unsigned short addr))

 2 {

 3     if (!probe)

 4         probe = i2c_default_probe;

 5     ......

 6     /* Test address responsiveness */

 7     for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) {

 8         ......

 9         if (probe(adap, addr_list[i])) //真實的發(fā)地址去探測

10             break; //成功就跳出for循環(huán)往后進行注冊i2c設(shè)備

11     }

12     if (addr_list[i] == I2C_CLIENT_END) { //看看是不是探測地址用完了,用完了函數(shù)就返回,不往下注冊設(shè)備。

13         dev_dbg(&adap->dev, 'Probing failed, no device foundn');

14         return NULL;

15     }

16     info->addr = addr_list[i];

17     return i2c_new_device(adap, info);//注冊設(shè)備:創(chuàng)建 i2c_client 并注冊

18 }


其實這種方法是2.6或之前的內(nèi)核做法,傳聞?wù)f這種探測機制會有副作用不建議使用,具體什么副作用就不知道了。


(4)Instantiate from user-space 從用戶空間來創(chuàng)建i2c設(shè)備:


這種方法最最......好吧,竟然找不到一個詞匯來形容對它的這種感覺。


直接使用指令來完成:


echo eeprom 0x50 > /sys/bus/i2c/devices/i2c-0/new_device


大體原理可以意會到一些,具體的原理可以看看內(nèi)核文檔的介紹。


二、i2c 設(shè)備驅(qū)動的分析和實例編寫


不管上邊的哪一種方法注冊 i2c_client ,對我的i2c設(shè)備驅(qū)動的設(shè)計都沒有太大的出入。下邊給出是在第一種方式下注冊的 i2c_client 時的驅(qū)動編寫,分析的內(nèi)容已經(jīng)容納在程序的注釋中。


  1 #include   

  2 #include   

  3 #include   

  4 #include   

  5 #include   

  6 #include   

  7 #include  

  8 #include

  9 #include

 10 #include

 11 #include

 12 #include

 13 #include

 14 #include

 15 #include

 16 #include

 17 #include

 18 #include

 19 #include

 20 #include

 21 #include

 22 

 23 static int major;

 24 static struct class    *cls;

 25 static struct device *i2c_dev;

 26 struct i2c_client       *at24cxx_client ;

 27 

 28 static unsigned write_timeout = 25;

 29 

 30 

 31 int at24cxx_open(struct inode *inode, struct file *file)

 32 {

 33     printk('at24cxx_openn');

 34     return 0;

 35 }

 36 

 37 static ssize_t at24cxx_read(struct file *file, char __user *buf, size_t size, loff_t * offset)

 38 {

 39     unsigned char    address;

 40     unsigned char    data;

 41     int ret;

 42     struct i2c_msg msg[2];

 43 

 44     unsigned long timeout, read_time;

 45     

 46     /* address = buf[0] 

 47      * data    = buf[1]

 48      */

 49     if (size != 1)

 50         return -EINVAL;

 51     

 52     ret = copy_from_user(&address, buf, 1);

 53     printk('read addr:%dn',address);

 54     /* 數(shù)據(jù)傳輸三要素: 源,目的,長度 */

 55     /* 讀AT24CXX時,要先把要讀的存儲空間的地址發(fā)給它 */

[1] [2]
關(guān)鍵字:Linux驅(qū)動  I2C驅(qū)動 引用地址:Linux驅(qū)動:I2C驅(qū)動編寫要點

上一篇:Linux驅(qū)動:LCD驅(qū)動框架分析
下一篇:Linux驅(qū)動:內(nèi)核等待隊列

推薦閱讀最新更新時間:2025-04-17 17:57

S5pv210 HDMI 接口在 Linux 3.0.8 驅(qū)動框架解析
本文主要簡述S5pv210處理器的 HDMI 接口在 Linux 3.0.8 內(nèi)核下的驅(qū)動框架。 現(xiàn)在三星的主流處理器基本都支持HDMI,使用HDMI也有段時間了,卻一直不知道它是怎么工作的,只知道linux和android下都會有一個HDMI-service的用戶服務(wù)程序。然后底層會有HDMI驅(qū)動。知道HDMI 和framebuffer有點關(guān)系,卻不知道兩者是如何聯(lián)系在一起的。從知道HDMI以來就覺得它神秘,出于好奇,決定揭開它的面紗一探真容。按照我的思路從下面四個方面并依照源碼簡單剖析一下Samsung S5pv210 處理器HDMI 在linux3.0.8下的驅(qū)動框架。 ? 1.1 何為HDMI,HDMI總線協(xié)議
[單片機]
S5pv210 HDMI 接口在 <font color='red'>Linux</font> 3.0.8 <font color='red'>驅(qū)動</font>框架解析
Linux 內(nèi)核驅(qū)動自動創(chuàng)建設(shè)備節(jié)點并掛載設(shè)備
一、首先需要在最開始定義兩個數(shù)據(jù)結(jié)構(gòu): static struct class *firstdrv_class; static struct device *firstdrv_device; 二、在init函數(shù)里通過class_create和device_create函數(shù)創(chuàng)建相應的設(shè)備節(jié)點,示例代碼如下: static int first_drv_init(void) { /* 主設(shè)備號設(shè)置為0表示由系統(tǒng)自動分配主設(shè)備號 */ major = register_chrdev(0, first_drv , &first_drv_fops); /* 創(chuàng)建firstdrv類 */ firstdr
[單片機]
linux-2.6.32在mini2440開發(fā)板上移植-SD卡驅(qū)動移植
1 在內(nèi)核中注冊SD 設(shè)備驅(qū)動 Linux-2.6.32.2 已經(jīng)自帶了S3C2440 芯片的SD 卡驅(qū)動,我們只需在初始化代碼中加入SD 平臺設(shè)備結(jié)構(gòu)就可以,打開arch/arm/mach-s3c2440/mach-mini2440.c,在nand flash 平臺結(jié)構(gòu)后面添加如下紅色代碼: ;在mini2440.c 的頂部添加SD 卡設(shè)備結(jié)構(gòu)所需的頭文件 #include linux/mmc/host.h #include plat/mci.h static struct platform_device mini2440_device_eth = { .name = dm9000 , .id = -1, .num_resour
[單片機]
OK6410A 開發(fā)板 (八) 4 linux-5.11 OK6410A 外圍驅(qū)動
其他驅(qū)動 目前已經(jīng)弄完的,且正常能用的 boot uart mmc(sd) ddr lcd(WXCAT43-TG3#001,CON1外插) ethernet(dm9000a) usb(usb otg) 目前還剩下比較有意思的,過一階段再弄 觸摸屏 gpio(J8/J12/J13) led(led1/2/3/4) camera(FIT-CAM-OV9650,JP1外插) audio(ac97,wm9714,粉紅色插口J7mic,青色插口J6speaker,淡藍色插口J14) nand(K9G8G08U0A) jtag(CN2,外插) rtc(S3C6410內(nèi)部) sdiowifi(接sdcard1,CN4外插) TV out(黃
[單片機]
[Linux 底層]U-boot ksz8081網(wǎng)絡(luò)驅(qū)動調(diào)試
micrel公司一款優(yōu)秀的PHY芯片,關(guān)于芯片的介紹參考: ksz8081數(shù)據(jù)手冊解讀 系統(tǒng)版本:Ubuntu18.04-64 編譯器版本:gcc version 7.4.0 (Ubuntu/Linaro 7.4.0-1ubuntu1~18.04.1) uboot版本:2018.07 -linux4sam_6.0 板子型號:at91sama5d3x-xplained MCU型號:sama5d36 與ksz9031很相似,公眾部分可參考: 1、如何找到uboot官網(wǎng)開發(fā)板默認配置文件路徑 2、如何進行公共信息配置 3、如何核對開發(fā)板硬件的參數(shù) 4、如何對uboot功能進行裁剪 5、設(shè)
[單片機]
linux串口驅(qū)動——s3c6410平臺(一)
1、serial文件夾下Kconfig分析 config SERIAL_SAMSUNG tristate Samsung SoC serial support depends on ARM && PLAT_S3C select SERIAL_CORE help Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,為支持三星的片上UARTs控制器 providing /dev/ttySAC0, 1 and 2 (note, some machines may not provide all of these ports, depending
[單片機]
05-S3C2440學習之內(nèi)核(移植)linux3.4.2移植(4)支持LED驅(qū)動、按鍵驅(qū)動
一、前面的工作: (1)從頭移植3.4.2內(nèi)核,修改分區(qū),制作jffs2文件系統(tǒng) http://blog.csdn.net/fengyuwuzu0519/article/details/69802922 (2)修改內(nèi)核支持yffs2、制作yffs2文件系統(tǒng)、內(nèi)核裁剪、制作補丁 http://blog.csdn.net/fengyuwuzu0519/article/details/70162666 (3)移植內(nèi)核支持DM9000C網(wǎng)卡驅(qū)動(可以使用mount nfs)、支持三路串口 http://blog.csdn.net/fengyuwuzu0519/article/details/72846205 到此我
[單片機]
05-S3C2440學習之內(nèi)核(移植)<font color='red'>linux</font>3.4.2移植(4)支持LED<font color='red'>驅(qū)動</font>、按鍵<font color='red'>驅(qū)動</font>
小廣播
設(shè)計資源 培訓 開發(fā)板 精華推薦

最新單片機文章

 
EEWorld訂閱號

 
EEWorld服務(wù)號

 
汽車開發(fā)圈

 
機器人開發(fā)圈

電子工程世界版權(quán)所有 京ICP證060456號 京ICP備10001474號-1 電信業(yè)務(wù)審批[2006]字第258號函 京公網(wǎng)安備 11010802033920號 Copyright ? 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
主站蜘蛛池模板: 桐城市| 威海市| 长治市| 克山县| 察哈| 斗六市| 禹城市| 清河县| 修武县| 成安县| 南宁市| 通化市| 石棉县| 白山市| 泉州市| 绵竹市| 太仆寺旗| 高清| 内乡县| 马边| 翁牛特旗| 剑河县| 隆林| 丰镇市| 绥江县| 南和县| 台中市| 安新县| 平谷区| 新营市| 扶风县| 镇原县| 克拉玛依市| 五台县| 红桥区| 佛坪县| 宜宾县| 西林县| 卢氏县| 乾安县| 嫩江县|