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

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

生活随笔

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

linux

Linux I2C子系统分析-I2C设备驱动

發(fā)布時(shí)間:2025/4/16 linux 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux I2C子系统分析-I2C设备驱动 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

接下來(lái)以一個(gè)實(shí)際的例子來(lái)看I2C設(shè)備驅(qū)動(dòng),就以drivers/i2c/i2c-dev.c為例。

先看它的初始化和注銷函數(shù)

[cpp]?view plaincopy
  • 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");??
  • }??
  • 首先調(diào)用register_chrdev注冊(cè)了一個(gè)字符設(shè)備,這是老的字符驅(qū)動(dòng)注冊(cè)方式。然后到了接下來(lái)的主角,i2c_add_driver,在I2C子系統(tǒng)中,I2C設(shè)備驅(qū)動(dòng)就是采用這個(gè)函數(shù)注冊(cè),注銷一個(gè)I2C設(shè)備驅(qū)動(dòng)使用下面的i2c_del_driver函數(shù),那就具體看看這個(gè)I2C設(shè)備驅(qū)動(dòng)注冊(cè)函數(shù)。

    [cpp]?view plaincopy
  • static?inline?int?i2c_add_driver(struct?i2c_driver?*driver)??
  • {??
  • ????return?i2c_register_driver(THIS_MODULE,?driver);??
  • }??
  • int?i2c_register_driver(struct?module?*owner,?struct?i2c_driver?*driver)??
  • {??
  • ????int?res;??
  • ??
  • ????/*?Can't?register?until?after?driver?model?init?*/??
  • ????if?(unlikely(WARN_ON(!i2c_bus_type.p)))??
  • ????????return?-EAGAIN;??
  • ??
  • ????/*?add?the?driver?to?the?list?of?i2c?drivers?in?the?driver?core?*/??
  • ????driver->driver.owner?=?owner;??
  • ????driver->driver.bus?=?&i2c_bus_type;?/*指定驅(qū)動(dòng)的總線類型*/??
  • ??
  • ????/*?When?registration?returns,?the?driver?core?
  • ?????*?will?have?called?probe()?for?all?matching-but-unbound?devices.?
  • ?????*/??
  • ????res?=?driver_register(&driver->driver);?/*注冊(cè)驅(qū)動(dòng)*/??
  • ????if?(res)??
  • ????????return?res;??
  • ??
  • ????pr_debug("i2c-core:?driver?[%s]?registered\n",?driver->driver.name);??
  • ??
  • ????INIT_LIST_HEAD(&driver->clients);??
  • ????/*?Walk?the?adapters?that?are?already?present?*/??
  • ????mutex_lock(&core_lock);??
  • ????bus_for_each_dev(&i2c_bus_type,?NULL,?driver,?__attach_adapter);??
  • ????mutex_unlock(&core_lock);??
  • ??
  • ????return?0;??
  • }??
  • 再來(lái)看看i2c設(shè)備驅(qū)動(dòng)注銷函數(shù)

    [cpp]?view plaincopy
  • void?i2c_del_driver(struct?i2c_driver?*driver)??
  • {??
  • ????mutex_lock(&core_lock);??
  • ????bus_for_each_dev(&i2c_bus_type,?NULL,?driver,?__detach_adapter);??
  • ????mutex_unlock(&core_lock);??
  • ??
  • ????driver_unregister(&driver->driver);??
  • ????pr_debug("i2c-core:?driver?[%s]?unregistered\n",?driver->driver.name);??
  • }??
  • 也沒(méi)什么,最后調(diào)用的就是驅(qū)動(dòng)的注銷函數(shù)driver_unregister函數(shù)。

    來(lái)看傳遞給注冊(cè)和注銷i2c驅(qū)動(dòng)函數(shù)的參數(shù)什么,i2cdev_driver它是structi2c_driver結(jié)構(gòu)類型,i2c設(shè)備驅(qū)動(dòng)就是使用這個(gè)結(jié)構(gòu)類型描述,這個(gè)結(jié)構(gòu)類型定義在include/linux/i2c.h

    [cpp]?view plaincopy
  • struct?i2c_driver?{??
  • ????unsigned?int?class;??
  • ??
  • ????/*?Notifies?the?driver?that?a?new?bus?has?appeared?or?is?about?to?be?
  • ?????*?removed.?You?should?avoid?using?this?if?you?can,?it?will?probably?
  • ?????*?be?removed?in?a?near?future.?
  • ?????*/??
  • ????int?(*attach_adapter)(struct?i2c_adapter?*);??
  • ????int?(*detach_adapter)(struct?i2c_adapter?*);??
  • ??
  • ????/*?Standard?driver?model?interfaces?*/??
  • ????int?(*probe)(struct?i2c_client?*,?const?struct?i2c_device_id?*);??
  • ????int?(*remove)(struct?i2c_client?*);??
  • ??
  • ????/*?driver?model?interfaces?that?don't?relate?to?enumeration??*/??
  • ????void?(*shutdown)(struct?i2c_client?*);??
  • ????int?(*suspend)(struct?i2c_client?*,?pm_message_t?mesg);??
  • ????int?(*resume)(struct?i2c_client?*);??
  • ??
  • ????/*?a?ioctl?like?command?that?can?be?used?to?perform?specific?functions?
  • ?????*?with?the?device.?
  • ?????*/??
  • ????int?(*command)(struct?i2c_client?*client,?unsigned?int?cmd,?void?*arg);??
  • ??
  • ????struct?device_driver?driver;??
  • ????const?struct?i2c_device_id?*id_table;??
  • ??
  • ????/*?Device?detection?callback?for?automatic?device?creation?*/??
  • ????int?(*detect)(struct?i2c_client?*,?int?kind,?struct?i2c_board_info?*);??
  • ????const?struct?i2c_client_address_data?*address_data;??
  • ????struct?list_head?clients;??
  • };??
  • 來(lái)看i2c-dev.c中是怎么定義的

    [cpp]?view plaincopy
  • static?struct?i2c_driver?i2cdev_driver?=?{??
  • ????.driver?=?{??
  • ????????.name???=?"dev_driver",??
  • ????},??
  • ????.attach_adapter?=?i2cdev_attach_adapter,??
  • ????.detach_adapter?=?i2cdev_detach_adapter,??
  • };??
  • 這是老的方式,所以它只是給attach_adapterdetach_adapter賦了值,由于這里是老的方式,所以我們也就不去具體看這個(gè)函數(shù)了,我們直接去看它的數(shù)據(jù)傳輸部分吧。

    [cpp]?view plaincopy
  • 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?=?(struct?i2c_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)??
  • ????????ret?=?copy_to_user(buf,tmp,count)?-EFAULT:ret;??
  • ????kfree(tmp);??
  • ????return?ret;??
  • }??
  • 這是i2c設(shè)備讀函數(shù),我們看它是調(diào)用的i2c_master_recv函數(shù)去操作的,去看這個(gè)函數(shù)

    [cpp]?view plaincopy
  • int?i2c_master_recv(struct?i2c_client?*client,?char?*buf?,int?count)??
  • {??
  • ????struct?i2c_adapter?*adap=client->adapter;??
  • ????struct?i2c_msg?msg;??
  • ????int?ret;??
  • ??
  • ????msg.addr?=?client->addr;??
  • ????msg.flags?=?client->flags?&?I2C_M_TEN;??
  • ????msg.flags?|=?I2C_M_RD;??
  • ????msg.len?=?count;??
  • ????msg.buf?=?buf;??
  • ??
  • ????ret?=?i2c_transfer(adap,?&msg,?1);??
  • ??
  • ????/*?If?everything?went?ok?(i.e.?1?msg?transmitted),?return?#bytes?
  • ???????transmitted,?else?error?code.?*/??
  • ????return?(ret?==?1)???count?:?ret;??
  • }??
  • i2c設(shè)備寫函數(shù)

    [cpp]?view plaincopy
  • 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?=?(struct?i2c_client?*)file->private_data;??
  • ??
  • ????if?(count?>?8192)??
  • ????????count?=?8192;??
  • ??
  • ????tmp?=?kmalloc(count,GFP_KERNEL);??
  • ????if?(tmp==NULL)??
  • ????????return?-ENOMEM;??
  • ????if?(copy_from_user(tmp,buf,count))?{??
  • ????????kfree(tmp);??
  • ????????return?-EFAULT;??
  • ????}??
  • ??
  • ????pr_debug("i2c-dev:?i2c-%d?writing?%zu?bytes.\n",??
  • ????????iminor(file->f_path.dentry->d_inode),?count);??
  • ??
  • ????ret?=?i2c_master_send(client,tmp,count);??
  • ????kfree(tmp);??
  • ????return?ret;??
  • }??
  • int?i2c_master_send(struct?i2c_client?*client,const?char?*buf?,int?count)??
  • {??
  • ????int?ret;??
  • ????struct?i2c_adapter?*adap=client->adapter;??
  • ????struct?i2c_msg?msg;??
  • ??
  • ????msg.addr?=?client->addr;??
  • ????msg.flags?=?client->flags?&?I2C_M_TEN;??
  • ????msg.len?=?count;??
  • ????msg.buf?=?(char?*)buf;??
  • ??
  • ????ret?=?i2c_transfer(adap,?&msg,?1);??
  • ??
  • ????/*?If?everything?went?ok?(i.e.?1?msg?transmitted),?return?#bytes?
  • ???????transmitted,?else?error?code.?*/??
  • ????return?(ret?==?1)???count?:?ret;??
  • }??
  • 這兩個(gè)函數(shù)最終都是調(diào)用的i2c_transfer函數(shù)去完成數(shù)據(jù)的傳輸,只是他們的msgflags不一樣,讀操作的flags要加上I2C_M_RD這個(gè)標(biāo)志。

    再看它們兩個(gè)共同的i2c_transfer函數(shù)

    [cpp]?view plaincopy
  • int?i2c_transfer(struct?i2c_adapter?*adap,?struct?i2c_msg?*msgs,?int?num)??
  • {??
  • ????unsigned?long?orig_jiffies;??
  • ????int?ret,?try;??
  • ??
  • ????/*?REVISIT?the?fault?reporting?model?here?is?weak:?
  • ?????*?
  • ?????*??-?When?we?get?an?error?after?receiving?N?bytes?from?a?slave,?
  • ?????*????there?is?no?way?to?report?"N".?
  • ?????*?
  • ?????*??-?When?we?get?a?NAK?after?transmitting?N?bytes?to?a?slave,?
  • ?????*????there?is?no?way?to?report?"N"?...?or?to?let?the?master?
  • ?????*????continue?executing?the?rest?of?this?combined?message,?if?
  • ?????*????that's?the?appropriate?response.?
  • ?????*?
  • ?????*??-?When?for?example?"num"?is?two?and?we?successfully?complete?
  • ?????*????the?first?message?but?get?an?error?part?way?through?the?
  • ?????*????second,?it's?unclear?whether?that?should?be?reported?as?
  • ?????*????one?(discarding?status?on?the?second?message)?or?errno?
  • ?????*????(discarding?status?on?the?first?one).?
  • ?????*/??
  • ??
  • ????if?(adap->algo->master_xfer)?{??
  • #ifdef?DEBUG??
  • ????????for?(ret?=?0;?ret?<?num;?ret++)?{??
  • ????????????dev_dbg(&adap->dev,?"master_xfer[%d]?%c,?addr=0x%02x,?"??
  • ????????????????"len=%d%s\n",?ret,?(msgs[ret].flags?&?I2C_M_RD)??
  • ??????????????????'R'?:?'W',?msgs[ret].addr,?msgs[ret].len,??
  • ????????????????(msgs[ret].flags?&?I2C_M_RECV_LEN)???"+"?:?"");??
  • ????????}??
  • #endif??
  • ??
  • ????????if?(in_atomic()?||?irqs_disabled())?{??
  • ????????????ret?=?mutex_trylock(&adap->bus_lock);??
  • ????????????if?(!ret)??
  • ????????????????/*?I2C?activity?is?ongoing.?*/??
  • ????????????????return?-EAGAIN;??
  • ????????}?else?{??
  • ????????????mutex_lock_nested(&adap->bus_lock,?adap->level);??
  • ????????}??
  • ??
  • ????????/*?Retry?automatically?on?arbitration?loss?*/??
  • ????????orig_jiffies?=?jiffies;??
  • ????????for?(ret?=?0,?try?=?0;?try?<=?adap->retries;?try++)?{??
  • ????????????ret?=?adap->algo->master_xfer(adap,?msgs,?num);??
  • ????????????if?(ret?!=?-EAGAIN)??
  • ????????????????break;??
  • ????????????if?(time_after(jiffies,?orig_jiffies?+?adap->timeout))??
  • ????????????????break;??
  • ????????}??
  • ????????mutex_unlock(&adap->bus_lock);??
  • ??
  • ????????return?ret;??
  • ????}?else?{??
  • ????????dev_dbg(&adap->dev,?"I2C?level?transfers?not?supported\n");??
  • ????????return?-EOPNOTSUPP;??
  • ????}??
  • }??
  • 我們看就是調(diào)用總線的master_xfer方法,我們?cè)谇懊娣治鍪褂?span style="font-family:'DejaVu Serif',serif">gpio模擬i2c總線時(shí),看過(guò)這樣一句?.master_xfer =bit_xfer,?,所以最終調(diào)用的是這個(gè)函數(shù)來(lái)完成數(shù)據(jù)傳輸。使用i2c_master_recvi2c_master_send函數(shù)一次只能傳輸一個(gè)msg,由于它一次只能傳輸一個(gè)msg,所以它的傳輸方向不能改變,也就是一次只能完成讀或?qū)懖僮?#xff0c;并且讀操作時(shí)還不能傳遞設(shè)備的基地址,所以通常是不會(huì)用這兩個(gè)函數(shù)的,直接的做法時(shí),構(gòu)造兩個(gè)msg,一個(gè)msg的數(shù)據(jù)為操作設(shè)備基地址,另外一個(gè)msg才是我們真正要讀寫的數(shù)據(jù),最后調(diào)用i2c_transfer函數(shù)去完成數(shù)據(jù)的傳送。

    總結(jié)

    以上是生活随笔為你收集整理的Linux I2C子系统分析-I2C设备驱动的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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

    主站蜘蛛池模板: 国产女人水真多18毛片18精品 | 色欲久久久天天天精品综合网 | 亚洲综合一区中 | 国产在线二区 | 99婷婷 | 男女日批在线观看 | 欧美在线色 | 亚洲片国产一区一级在线观看 | 欧美性猛交乱大交 | 亚洲国产黄色 | 国产精品久久综合视频 | 18禁网站免费无遮挡无码中文 | 99热影院 | 欧美一区二区在线观看视频 | h在线播放 | 国产欧美日韩综合精品一区二区三区 | 国产亚洲女人久久久久毛片 | 久久久性色精品国产免费观看 | 亚洲av熟女一区 | 一色综合 | 999久久精品 | www.狠狠| 亚洲三级国产 | 国产精品视频看看 | 欧美粗大猛烈老熟妇 | 日韩国产在线一区 | 校园sm主奴调教1v1罚视频 | 伊人免费视频二 | 国产精品亚州 | 亚洲图片一区二区 | 成人看的毛片 | 国产精品一线天 | gai免费观看网站外网 | 国产乱子伦一区二区 | av一区二区三区在线观看 | 黄色福利视频 | 天天尻逼 | 日日摸日日碰夜夜爽无码 | 欧美极品少妇xxxxⅹ免费视频 | 在线视频精品免费 | 张柏芝亚洲一区二区三区 | 国产精品入口日韩视频大尺度 | 精品网站 | 精品人妻午夜一区二区三区四区 | 久久久久久久久福利 | 高清不卡av | 天堂网2018| 玩偶游戏在线观看免费 | 男人爱看的网站 | 午夜精品福利在线 | 久久久99精品免费观看 | 免费黄色入口 | 欧美日韩激情视频在线观看 | 日韩综合网| 亚洲av无码日韩精品影片 | av中文字幕在线免费观看 | 黄色片小视频 | 欧美18一20男同69gay | 亚洲精品人人 | 91精品国产aⅴ一区 黄色a网 | 伊人狼人影院 | 免费成人深夜在线观看 | 欧美在线色视频 | 四虎网址在线 | 国产麻豆xxxvideo实拍 | 国产中文字字幕乱码无限 | 国产黄色av网站 | 成人深夜电影 | www.xxx.日本 | 午夜视频色 | 日日噜噜夜夜狠狠久久波多野 | 国产伦子伦对白视频 | 91插视频| 日韩欧美有码 | 亚洲精品一区二区三区在线观看 | 亚洲乱熟女一区二区三区小说 | 亚洲国产精品天堂 | 97碰碰视频| 免费看国产黄色片 | 欧美激情欧美激情在线五月 | 成人一级黄色片 | 亚洲一级在线播放 | 丰满女人又爽又紧又丰满 | 青青青国产在线 | 强制高潮抽搐哭叫求饶h | 一区二区三区免费观看视频 | 99re视频这里只有精品 | 国产精品欧美性爱 | 性按摩玩人妻hd中文字幕 | 中日韩一级片 | 黄色av网站免费观看 | 狠狠操av| 在线观看不卡一区 | 日韩在线视频在线观看 | 精品中文字幕一区二区 | 色图在线观看 | 国产思思 | 亚洲色成人www永久在线观看 | 国产精品国产三级国产普通话蜜臀 |