1. 程式人生 > >驅動載入到I2C匯流排,如何執行到probe

驅動載入到I2C匯流排,如何執行到probe

為了簡短文章長度,一些檢查和除錯資訊被刪除

1. 在xxx_init()中會呼叫i2c_add_driver()函式   

static int __init ltr559_init(void)
{
    return i2c_add_driver(&ltr_ps_driver);//ltr_ps_driver是一個struct i2c_driver
} 

static void __exit ltr559_exit(void)
{
    i2c_del_driver(&ltr_ps_driver);    
}

module_init(ltr559_init);
module_exit(ltr559_exit);

2. i2c_add_driver

        是一個巨集命令,呼叫 i2c_register_driver

/*************************  include/linux/i2c.h  *******************************/
#define i2c_add_driver(driver) \
         i2c_register_driver(THIS_MODULE, driver)

3.  i2c_register_driver

     在一些 i2c_adapter 相關匯流排例項, 一個 i2c_driver 可以被一個或多個 i2c_client 裝置節點使用去訪問 i2c_slave_chip

     該函式

/**********************  kernel/drivers/i2c/i2c_core.c   ************************/
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
	int res;

	/*在驅動模組初始化完成後才可以註冊 */
	if (unlikely(WARN_ON(!i2c_bus_type.p)))
		return -EAGAIN;

	/* 新增該驅動到i2c驅動連結串列上 */
	driver->driver.owner = owner;
 	driver->driver.bus = &i2c_bus_type;

	/* 當註冊完成,驅動程式碼將呼叫probe()去匹配裝置 */
	res = driver_register(&driver->driver);

	INIT_LIST_HEAD(&driver->clients);

	i2c_for_each_dev(driver, __process_new_driver);

	return 0;
}

4. driver_register

    主要的工作還是由 bus_add_driver 來操作

/***************************    kernel/driver/base/driver.c  **************************/
int driver_register(struct device_driver *drv)
{
	int ret;
	struct device_driver *other;

	BUG_ON(!drv->bus->p);
	
	other = driver_find(drv->name, drv->bus);//通過driver_name在bus上查詢該driver,正常返回0
	
	ret = bus_add_driver(drv); //主要
	
	ret = driver_add_groups(drv, drv->groups);
	if (ret) {
		bus_remove_driver(drv);
		return ret;
	}
	kobject_uevent(&drv->p->kobj, KOBJ_ADD);

	return ret;
}

5. bus_add_driver

/****************  kernel/driver/base/bus.c **********************************/
int bus_add_driver(struct device_driver *drv)
{
    struct bus_type *bus;
    struct driver_private *priv;
    int error = 0;

    bus = bus_get(drv->bus);   

    priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 
    klist_init(&priv->klist_devices, NULL, NULL);

    priv->driver = drv;
    drv->p = priv;
    priv->kobj.kset = bus->p->drivers_kset;

    error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
                     "%s", drv->name);
   
    klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
    if (drv->bus->p->drivers_autoprobe) {
        error = driver_attach(drv);  //嘗試繫結
        
    }
    module_add_driver(drv->owner, drv);

    error = driver_create_file(drv, &driver_attr_uevent); //為驅動建立檔案,繼續呼叫sysfs_create_file()
    
    error = driver_add_attrs(bus, drv);
    
    if (!drv->suppress_bind_attrs) {
        error = add_bind_files(drv);
        
    }

    return 0;
}

6. driver_attach

/**
 * driver_attach - try to bind driver to devices.
 * @drv: driver.
 *
 * Walk the list of devices that the bus has on it and try to
 * match the driver with each one.  If driver_probe_device()
 * returns 0 and the @dev->driver is set, we've found a
 * compatible pair.
 */
int driver_attach(struct device_driver *drv)
{
	return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}

7. bus_for_each_dev

     引數 fn 就是__driver_attach()函式

/**
 * bus_for_each_dev - device iterator.
 * @bus: bus type.
 * @start: device to start iterating from.
 * @data: data for the callback.
 * @fn: function to be called for each device. 
 */
int bus_for_each_dev(struct bus_type *bus, struct device *start,
		     void *data, int (*fn)(struct device *, void *))
{
	struct klist_iter i;
	struct device *dev;
	int error = 0;

	if (!bus || !bus->p)
		return -EINVAL;

	klist_iter_init_node(&bus->p->klist_devices, &i,
			     (start ? &start->p->knode_bus : NULL));
	while ((dev = next_device(&i)) && !error)
		error = fn(dev, data);
	klist_iter_exit(&i);
	return error;
}

8. __driver_attach
static int __driver_attach(struct device *dev, void *data)
{
	struct device_driver *drv = data;

	if (!driver_match_device(drv, dev))
		return 0;

	if (dev->parent)	/* 如果是被usb介面呼叫,父裝置也要上鎖*/
		device_lock(dev->parent);
	device_lock(dev);
	if (!dev->driver)
		driver_probe_device(drv, dev); //
	device_unlock(dev);
	if (dev->parent)
		device_unlock(dev->parent);

	return 0;
}

9. driver_probe_device

    如果裝置沒有註冊,則該函式返回 -ENODEV , probe 成功 返回 1 ,失敗 返回 0 。該函式被呼叫時,裝置一定要上鎖

/**********************  kernel/drivers/base/dd.c *********************************
 * driver_probe_device - attempt to bind device & driver together
 * @drv: driver to bind a device to
 * @dev: device to try to bind to the driver
 */
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
	int ret = 0;

	if (!device_is_registered(dev))  //判斷裝置是否註冊
		return -ENODEV;
	pm_runtime_barrier(dev);
 	ret = really_probe(dev, drv);
	pm_request_idle(dev);

	return ret;
}

10. really_probe
/**********************  kernel/drivers/base/dd.c *********************************/
static int really_probe(struct device *dev, struct device_driver *drv)
{
	int ret = 0;

	atomic_inc(&probe_count);

	WARN_ON(!list_empty(&dev->devres_head));

	dev->driver = drv;


	ret = pinctrl_bind_pins(dev);
	if (ret)
		goto probe_failed;

	if (driver_sysfs_add(dev)) {
		printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
			__func__, dev_name(dev));
		goto probe_failed;
	}

	if (dev->bus->probe) {
		ret = dev->bus->probe(dev);
		if (ret)
			goto probe_failed;
	} else if (drv->probe) {
		ret = drv->probe(dev); //這裡才是正在呼叫驅動中實現的probe函式
		if (ret)
			goto probe_failed;
	}

	driver_bound(dev);
	ret = 1;	
	goto done;

probe_failed:
	devres_release_all(dev);
	driver_sysfs_remove(dev);
	dev->driver = NULL;
	dev_set_drvdata(dev, NULL);

	if (ret == -EPROBE_DEFER) {
		/* Driver requested deferred probing */
		dev_info(dev, "Driver %s requests probe deferral\n", drv->name);
		driver_deferred_probe_add(dev);
	} else if (ret != -ENODEV && ret != -ENXIO) {
		/* driver matched but the probe failed */
		printk(KERN_WARNING
		       "%s: probe of %s failed with error %d\n",
		       drv->name, dev_name(dev), ret);
	} else {
		pr_debug("%s: probe of %s rejects match %d\n",
		       drv->name, dev_name(dev), ret);
	}
	/*
	 * Ignore errors returned by ->probe so that the next driver can try
	 * its luck.
	 */
	ret = 0;
done:
	atomic_dec(&probe_count);
	wake_up(&probe_waitqueue);
	return ret;
}


相關推薦

驅動載入I2C匯流排如何執行probe

為了簡短文章長度,一些檢查和除錯資訊被刪除 1. 在xxx_init()中會呼叫i2c_add_driver()函式    static int __init ltr559_init(void) {     return i2c_add_driver(&ltr_p

linux驅動開發:匯流排裝置驅動三要素

平臺匯流排和IIC,SPI,IIS都是匯流排型別,一般的,匯流排下,掛載對應的裝置。但實際上,裝置要正常運轉,是需要驅動程式來未知提供驅動的。所以linux核心也把驅動掛載在對應的匯流排下。匯流排,驅動,裝置三者缺一不可. 相應的,核心衍生出來的平臺匯流排,那

Linux驅動I2C匯流排裝置以及驅動

[ 導讀] 本文通過閱讀核心程式碼,來梳理一下I2C子系統的整體檢視。在開發I2C裝置驅動程式時,往往缺乏對於系統整體的認識,導致沒有一個清晰的思路。所以從高層級來分析一下I2C系統的設計思路,將有助於設計除錯具體的驅動程式。 ## I2C/SMBUS基礎 I2C是一種晶片間通訊匯流排技術,最早由Ph

spring boot 匯出jar 包執行報錯無法載入 orcl驅動的問題。

原因是因為orcl資料庫是收費的,所以在pom檔案中無法匯入所以需要手動新增jar包,但是打包的時候無法將手動的jar包打包,只打包maven中的jar。 解決的辦法: 需要自己本地建立一個maven本地倉庫,然後需要配置環境 。 將執行 mvn

(已解決)拷貝dll檔案到另一個專案編譯不報錯執行報錯“未能載入檔案或程式集...”

未能載入檔案或程式集“JUtility, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”或它的某一個依賴項。試圖載入格式不正確的程式。   需要注意該dll生成的目標平臺:右擊專案-生成-目標平臺, 引用這個dll的專案

java動態編譯class,動態載入執行載入類的方法,直接可執行測試

直接上圖上程式碼 public static void main(String[] args) { TestClass testClass=new TestClass(); try { //動態編譯程式碼 Java

開發必備知識點--django專案啟動時url載入之前執行某個.py檔案

django專案啟動時,自定義執行某個py檔案 在任意的app下的apps.py中的Config類下自定義ready()方法,並且呼叫autodiscover_modules。 app01/apps.py 1 from django.apps import AppConfig 2 from dj

記困擾很久的pytorch載入模型OOMpython import執行流程python“懶執行”,whindows控制ubuntu遠端桌面

前言 半路接手專案,閱讀程式碼,解決bug,優化速度。 part one 1050 Ti載入模型時OOM model.load_state_dict(torch.load(path)) Copie

I2C匯流排驅動框架詳解

一、I2C子系統總體架構 1、三大組成部分 (1)I2C核心(i2c-core):I2C核心提供了I2C匯流排驅動(介面卡)和裝置驅動的註冊、登出方法,I2C通訊方法(”algorithm”)上層的,與具體硬體無關的程式碼以及探測裝置     檢測裝置地址的上層程式

vs程式執行時報錯"未能載入 SqlServerSpatialxxx.dll找不到指定的模組(異常來自......)"的解決方法

報錯原因: 因為程式中引用了Microsoft.SqlServer.Types程式集,正常情況下程式會去c:\windows\system32或者c:\windows\syswow64目錄中尋找,所以找不到。 其實你引用時已經在bin\debug\SqlServerTypes資料夾下生成了報

在c#中引用Microsoft.SqlServer.Types後系統執行報"未能載入 SqlServerSpatial140.dll找不到指定的模組(異常來自......)的解決方法

1.在資源管理器中檢視C:\Windows\System32或者C:\Windows\SysWOW64下有沒有SqlServerSpatialXXX.dll的檔案,如果沒有,在網上下載後,把檔案重新命名為報錯的dll檔名,將其放入此目錄下 2.如果有,如下圖,我將原本的130改為140,程式便不

Linux--核心---I2C匯流排驅動分析 以linux3.10.0 RK3288為例

Linux 3.10.0 iic匯流排註冊過程 I2C匯流排驅動包括I2C介面卡驅動載入與解除安裝以及I2C匯流排通訊方法 I2C核心提供了i2c_adapter的增加和刪除函式、i2c_driver的增加和刪除函式、i2c_client的依附和脫離函式 以及i2c傳輸、傳送

第七章——Windows核心基礎-核心理論基礎(0環通訊核心函式驅動載入流程)

windowsR3與R0通訊         當我們呼叫某個API的時候,這個API是被封裝在某個DLL庫中,而DLL庫中的函式則是在更底層的ntdll.dll檔案中,而相對應的則是呼叫ntdll中的Native API函式ntdll中的

A31S android 手動載入攝像頭命令驅動編譯進核心

insmod /system/vendor/modules/videobuf2-core.ko insmod /system/vendor/modules/videobuf2-memops.ko ins

gendisk,request與bio結構體以及塊裝置驅動註冊與登出以及載入與解除安裝

struct bio *bio; bio是這個請求中包含的bio結構體的連結串列,驅動中不宜直接存取這個成員,而應該使用後文將介紹的rq_for_each_bio()。 char *buffer; 指向緩衝區的指標,資料應當被傳送到或者來自這個緩衝區,這個指標是一個核心虛擬地址,可被驅動直接引用。 uns

Java虛擬機器結構(記憶體載入執行引擎)

1. JVM背景知識 1995年,Java誕生於Sun公司。目標:Write Once, Run Anywhere。 2006年,Sun宣佈Java開源,並在隨後1年,陸續將JDK的各部分在GPL v2協議下公開原始碼,並建立OpenJDK組織,對原始

Linux+I2C匯流排分析(主要是probe的方式)

Linux I2C 匯流排淺析 ㈠ Overview Linux的I2C體系結構分為3個組成部分: ·I2C核心: I2C核心提供了I2C匯流排驅動和裝置驅動的註冊、登出方法,I2C通訊方法(即“algorithm”)上層的、與具體介面卡無關的程式碼以及探測裝置、檢測裝置地址的上層程式碼等。這部分是與平臺無

js中如何控制所有頁面載入完成後執行某些方法

做頁面時經常會遇到當前頁面載入完成後,執行某些初始化工作。這時候就要知道如何判斷頁面(包括IFRAME)已經載入完成,程式碼如下: <script language="javascript">       document.onreadystatechange

i2c驅動程式(2) i2c_driver probe被呼叫的流程分析

(本文為個人的筆記 難免有錯 望各位高人賜教指正 謝謝!) i2c驅動程式i2c_driver probe被呼叫的流程分析 step1 i2c_add_driver(&at24_driver); step2 i2c_register_driver(T

java動態載入jar包執行其中的類和方法

動態載入jar包,在實際開發中經常會需要用到,尤其涉及平臺和業務的關係的時候,業務邏輯部分可以獨立出去交給業務方管理,業務方只需要提供jar包,就能在平臺上執行。 下面通過一個例項來直觀演示: 第一:定義一個抽象類 AbstractAction (稍後換成介面的例項) pa