Linux設備驅動之I2C架構分析

一:前言
I2c是philips提出的外設總線.I2C只有兩條線,一條串行數據線:SDA,一條是時鐘線SCL.正因爲這樣,它方便了工程人員的佈線.另外,I2C是一種多主機控制總線.它和USB總線不同,USB是基於master-slave機制,任何設備的通信必須由主機發起纔可以.而I2C 是基於multi master機制.一同總線上可允許多個master.關於I2C協議的知識,這裏不再贅述.可自行下載spec閱讀即可.
二:I2C架構概述
在linux中,I2C驅動架構如下所示:




如上圖所示,每一條I2C對應一個adapter.在kernel中,每一個adapter提供了一個描述的結構(structi2c_adapter),也定義了adapter支持的操作(struct i2c_adapter).再通過i2ccore層將i2c設備與i2c adapter關聯起來.
這個圖只是提供了一個大概的框架.在下面的代碼分析中,從下至上的來分析這個框架圖.以下的代碼分析是基於linux 2.6.26.分析的代碼基本位於: linux-2.6.26.3/drivers/i2c/位置.

三:adapter註冊
在kernel中提供了兩個adapter註冊接口,分別爲i2c_add_adapter()和i2c_add_numbered_adapter().由於在系統中可能存在多個adapter,因爲將每一條I2C總線對應一個編號,下文中稱爲I2C總線號.這個總線號的PCI中的總線號不同.它和硬件無關,只是軟件上便於區分而已.
對於i2c_add_adapter()而言,它使用的是動態總線號,即由系統給其分析一個總線號,而i2c_add_numbered_adapter()則是自己指定總線號,如果這個總線號非法或者是被佔用,就會註冊失敗.
分別來看一下這兩個函數的代碼:
int i2c_add_adapter(struct i2c_adapter *adapter)
{
    int id, res = 0;

retry:
    if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
        return -ENOMEM;

    mutex_lock(&core_lock);
    /* "above" here means "above or equal to", sigh */
    res = idr_get_new_above(&i2c_adapter_idr, adapter,
                __i2c_first_dynamic_bus_num, &id);
    mutex_unlock(&core_lock);

    if (res < 0) {
        if (res == -EAGAIN)
            goto retry;
        return res;
    }

    adapter->nr = id;
    return i2c_register_adapter(adapter);
}
在這裏涉及到一個idr結構.idr結構本來是爲了配合page cache中的radixtree而設計的.在這裏我們只需要知道,它是一種高效的搜索樹,且這個樹預先存放了一些內存.避免在內存不夠的時候出現問題.所在,在往idr中插入結構的時候,首先要調用idr_pre_get()爲它預留足夠的空閒內存,然後再調用idr_get_new_above()將結構插入idr中,該函數以參數的形式返回一個id.以後憑這個id就可以在idr中找到相對應的結構了.對這個數據結構操作不太理解的可以查閱本站<<linux文件系統之文件的讀寫>>中有關radix tree的分析.
注意一下idr_get_new_above(&i2c_adapter_idr,adapter,__i2c_first_dynamic_bus_num,&id)的參數的含義,它是將adapter結構插入到i2c_adapter_idr中,存放位置的id必須要大於或者等於__i2c_first_dynamic_bus_num,
然後將對應的id號存放在adapter->nr中.調用i2c_register_adapter(adapter)對這個adapter進行進一步註冊.

看一下另外一人註冊函數: i2c_add_numbered_adapter( ),如下所示:
int i2c_add_numbered_adapter(struct i2c_adapter *adap)
{
    int id;
    int status;

    if (adap->nr & ~MAX_ID_MASK)
        return -EINVAL;

retry:
    if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
        return -ENOMEM;

    mutex_lock(&core_lock);
    /* "above" here means "above or equal to", sigh;
    * we need the "equal to" result to force the result
    */
    status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id);
    if (status == 0 && id != adap->nr) {
        status = -EBUSY;
        idr_remove(&i2c_adapter_idr, id);
    }
    mutex_unlock(&core_lock);
    if (status == -EAGAIN)
        goto retry;

    if (status == 0)
        status = i2c_register_adapter(adap);
    return status;
}
對比一下就知道差別了,在這裏它已經指定好了adapter->nr了.如果分配的id不和指定的相等,便返回錯誤.

過一步跟蹤i2c_register_adapter().代碼如下:
static int i2c_register_adapter(struct i2c_adapter *adap)
{
    int res = 0, dummy;

    mutex_init(&adap->bus_lock);
    mutex_init(&adap->clist_lock);
    INIT_LIST_HEAD(&adap->clients);

    mutex_lock(&core_lock);

    /* Add the adapter to the driver core.
    * If the parent pointer is not set up,
    * we add this adapter to the host bus.
    */
    if (adap->dev.parent == NULL) {
        adap->dev.parent = &platform_bus;
        pr_debug("I2C adapter driver [%s] forgot to specify "
            "physical device/n", adap->name);
    }
    sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);
    adap->dev.release = &i2c_adapter_dev_release;
    adap->dev.class = &i2c_adapter_class;
    res = device_register(&adap->dev);
    if (res)
        goto out_list;

    dev_dbg(&adap->dev, "adapter [%s] registered/n", adap->name);

    /* create pre-declared device nodes for new-style drivers */
    if (adap->nr < __i2c_first_dynamic_bus_num)
        i2c_scan_static_board_info(adap);

    /* let legacy drivers scan this bus for matching devices */
    dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
                i2c_do_add_adapter);

out_unlock:
    mutex_unlock(&core_lock);
    return res;

out_list:
    idr_remove(&i2c_adapter_idr, adap->nr);
    goto out_unlock;
}
首先對adapter和adapter中內嵌的struct device結構進行必須的初始化.之後將adapter內嵌的struct device註冊.
在這裏注意一下adapter->dev的初始化.它的類別爲i2c_adapter_class,如果沒有父結點,則將其父結點設爲platform_bus.adapter->dev的名字爲i2c + 總線號.
測試一下:
[eric@mochow i2c]$ cd /sys/class/i2c-adapter/
[eric@mochow i2c-adapter]$ ls
i2c-0
可以看到,在我的PC上,有一個I2C adapter,看下詳細信息:
[eric@mochow i2c-adapter]$ tree
.
`-- i2c-0
    |-- device -> ../../../devices/pci0000:00/0000:00:1f.3/i2c-0
    |-- name
    |-- subsystem -> ../../../class/i2c-adapter
    `-- uevent

3 directories, 2 files
可以看到,該adapter是一個PCI設備.
繼續往下看:
之後,在註釋中看到,有兩種類型的driver,一種是new-style drivers,另外一種是legacy drivers
New-style drivers是在2.6近版的kernel加入的.它們最主要的區別是在adapter和i2c driver的匹配上.

3.1: new-style 形式的adapter註冊
對於第一種,也就是new-style drivers,將相關代碼再次列出如下:
    if (adap->nr < __i2c_first_dynamic_bus_num)
        i2c_scan_static_board_info(adap);
如果adap->nr 小於__i2c_first_dynamic_bus_num的話,就會進入到i2c_scan_static_board_info().
結合我們之前分析的adapter的兩種註冊分式: i2c_add_adapter()所分得的總線號肯會不會小於__i2c_first_dynamic_bus_num.只有i2c_add_numbered_adapter()纔有可能滿足:
(adap->nr < __i2c_first_dynamic_bus_num)
而且必須要調用i2c_register_board_info()將板子上的I2C設備信息預先註冊時纔會更改__i2c_first_dynamic_bus_num的值.在x86上只沒有使用i2c_register_board_info()的.因此,x86平臺上的分析可以忽略掉new-style driver的方式.不過,還是詳細分析這種情況下.
首先看一下i2c_register_board_info(),如下:
int __init
i2c_register_board_info(int busnum,
    struct i2c_board_info const *info, unsigned len)
{
    int status;

    mutex_lock(&__i2c_board_lock);

    /* dynamic bus numbers will be assigned after the last static one */
    if (busnum >= __i2c_first_dynamic_bus_num)
        __i2c_first_dynamic_bus_num = busnum + 1;

    for (status = 0; len; len--, info++) {
        struct i2c_devinfo  *devinfo;

        devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
        if (!devinfo) {
            pr_debug("i2c-core: can't register boardinfo!/n");
            status = -ENOMEM;
            break;
        }

        devinfo->busnum = busnum;
        devinfo->board_info = *info;
        list_add_tail(&devinfo->list, &__i2c_board_list);
    }

    mutex_unlock(&__i2c_board_lock);

    return status;
}
這個函數比較簡單, struct i2c_board_info用來表示I2C設備的一些情況,比如所在的總線.名稱,地址,中斷號等.最後,這些信息會被存放到__i2c_board_list鏈表.

跟蹤i2c_scan_static_board_info():代碼如下:
static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
{
    struct i2c_devinfo  *devinfo;

    mutex_lock(&__i2c_board_lock);
    list_for_each_entry(devinfo, &__i2c_board_list, list) {
        if (devinfo->busnum == adapter->nr
                && !i2c_new_device(adapter,
                        &devinfo->board_info))
            printk(KERN_ERR "i2c-core: can't create i2c%d-%04x/n",
                i2c_adapter_id(adapter),
                devinfo->board_info.addr);
    }
    mutex_unlock(&__i2c_board_lock);
}
該函數遍歷掛在__i2c_board_list鏈表上面的i2c設備的信息,也就是我們在啓動的時候指出的i2c設備的信息.
如果指定設備是位於adapter所在的I2C總線上,那麼,就調用i2c_new_device().代碼如下:
struct i2c_client *
i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
{
    struct i2c_client  *client;
    int        status;

    client = kzalloc(sizeof *client, GFP_KERNEL);
    if (!client)
        return NULL;

    client->adapter = adap;

    client->dev.platform_data = info->platform_data;
    device_init_wakeup(&client->dev, info->flags & I2C_CLIENT_WAKE);

    client->flags = info->flags & ~I2C_CLIENT_WAKE;
    client->addr = info->addr;
    client->irq = info->irq;

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

    /* a new style driver may be bound to this device when we
    * return from this function, or any later moment (e.g. maybe
    * hotplugging will load the driver module).  and the device
    * refcount model is the standard driver model one.
    */
    status = i2c_attach_client(client);
    if (status < 0) {
        kfree(client);
        client = NULL;
    }
    return client;
}
我們又遇到了一個新的結構:struct i2c_client,不要被這個結構嚇倒了,其實它就是一個嵌入struct device的I2C設備的封裝.它和我們之前遇到的struct usb_device結構的作用是一樣的.
首先,在clinet裏保存該設備的相關消息.特別的, client->adapter指向了它所在的adapter.
特別的,clinet->name爲info->name.也是指定好了的.
一切初始化完成之後,便會調用i2c_attach_client( ).看這個函數的字面意思,是將clinet關聯起來.到底怎麼樣關聯呢?繼續往下看:
int i2c_attach_client(struct i2c_client *client)
{
    struct i2c_adapter *adapter = client->adapter;
    int res = 0;

    //初始化client內嵌的dev結構
    //父結點爲所在的adapter,所在bus爲i2c_bus_type
    client->dev.parent = &client->adapter->dev;
    client->dev.bus = &i2c_bus_type;

    //如果client已經指定了driver,將driver和內嵌的dev關聯起來 
    if (client->driver)
        client->dev.driver = &client->driver->driver;
    //指定了driver, 但不是newstyle的
    if (client->driver && !is_newstyle_driver(client->driver)) {
        client->dev.release = i2c_client_release;
        client->dev.uevent_suppress = 1;
    } else
        client->dev.release = i2c_client_dev_release;

    //clinet->dev的名稱
    snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id),
        "%d-%04x", i2c_adapter_id(adapter), client->addr);
    //將內嵌的dev註冊
    res = device_register(&client->dev);
    if (res)
        goto out_err;

    //將clinet鏈到adapter->clients中
    mutex_lock(&adapter->clist_lock);
    list_add_tail(&client->list, &adapter->clients);
    mutex_unlock(&adapter->clist_lock);

    dev_dbg(&adapter->dev, "client [%s] registered with bus id %s/n",
        client->name, client->dev.bus_id);
    //如果adapter->cleinet_reqister存在,就調用它
    if (adapter->client_register)  {
        if (adapter->client_register(client)) {
            dev_dbg(&adapter->dev, "client_register "
                "failed for client [%s] at 0x%02x/n",
                client->name, client->addr);
        }
    }

    return 0;

out_err:
    dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x "
        "(%d)/n", client->name, client->addr, res);
    return res;
}
參考上面添加的註釋,應該很容易理解這段代碼了,就不加詳細分析了.這個函數的名字不是i2c_attach_client()麼?怎麼沒看到它的關係過程呢?
這是因爲:在代碼中設置了client->dev所在的bus爲i2c_bus_type .以爲只需要有bus爲i2c_bus_type的driver註冊,就會產生probe了.這個過程呆後面分析i2c driver的時候再來詳細分析.

3.2: legacy形式的adapter註冊
Legacy形式的adapter註冊代碼片段如下:
    dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
                i2c_do_add_adapter);
這段代碼遍歷掛在i2c_bus_type上的驅動,然後對每一個驅動和adapter調用i2c_do_add_adapter().
代碼如下:
static int i2c_do_add_adapter(struct device_driver *d, void *data)
{
    struct i2c_driver *driver = to_i2c_driver(d);
    struct i2c_adapter *adap = data;

    if (driver->attach_adapter) {
        /* We ignore the return code; if it fails, too bad */
        driver->attach_adapter(adap);
    }
    return 0;
}
該函數很簡單,就是調用driver的attach_adapter()接口.
到此爲止,adapter的註冊已經分析完了.

四:i2c driver註冊
在分析i2c driver的時候,有必要先分析一下i2c架構的初始化
代碼如下:
static int __init i2c_init(void)
{
    int retval;

    retval = bus_register(&i2c_bus_type);
    if (retval)
        return retval;
    retval = class_register(&i2c_adapter_class);
    if (retval)
        goto bus_err;
    retval = i2c_add_driver(&dummy_driver);
    if (retval)
        goto class_err;
    return 0;

class_err:
    class_unregister(&i2c_adapter_class);
bus_err:
    bus_unregister(&i2c_bus_type);
    return retval;
}
subsys_initcall(i2c_init);
很明顯,i2c_init()會在系統初始化的時候被調用.
在i2c_init中,先註冊了i2c_bus_type的bus,i2c_adapter_class的class.然後再調用i2c_add_driver()註冊了一個i2c driver.

I2c_bus_type結構如下:
static struct bus_type i2c_bus_type = {
    .name      = "i2c",
    .dev_attrs  = i2c_dev_attrs,
    .match      = i2c_device_match,
    .uevent    = i2c_device_uevent,
    .probe      = i2c_device_probe,
    .remove    = i2c_device_remove,
    .shutdown  = i2c_device_shutdown,
    .suspend    = i2c_device_suspend,
    .resume    = i2c_device_resume,
};

這個結構先放在這裏吧,以後還會用到裏面的信息的.
從上面的初始化函數裏也看到了,註冊i2c driver的接口爲i2c_add_driver().代碼如下:
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;

    /* new style driver methods can't mix with legacy ones */
    //如果是一個newstyle的driver.但又定義了attach_adapter/detach_adapter.非法
    if (is_newstyle_driver(driver)) {
        if (driver->attach_adapter || driver->detach_adapter
                || driver->detach_client) {
            printk(KERN_WARNING
                    "i2c-core: driver [%s] is confused/n",
                    driver->driver.name);
            return -EINVAL;
        }
    }

    /* add the driver to the list of i2c drivers in the driver core */
    //關聯到i2c_bus_types
    driver->driver.owner = owner;
    driver->driver.bus = &i2c_bus_type;

    /* for new style drivers, when registration returns the driver core
    * will have called probe() for all matching-but-unbound devices.
    */
    //註冊內嵌的driver
    res = driver_register(&driver->driver);
    if (res)
        return res;

    mutex_lock(&core_lock);

    pr_debug("i2c-core: driver [%s] registered/n", driver->driver.name);

    /* legacy drivers scan i2c busses directly */
    //遍歷所有的adapter,對其都調用driver->attach_adapter
    if (driver->attach_adapter) {
        struct i2c_adapter *adapter;

        down(&i2c_adapter_class.sem);
        list_for_each_entry(adapter, &i2c_adapter_class.devices,
                    dev.node) {
            driver->attach_adapter(adapter);
        }
        up(&i2c_adapter_class.sem);
    }

    mutex_unlock(&core_lock);
    return 0;
}
這裏也有兩種形式的區分,對於第一種,只需要將內嵌的driver註冊就可以了,對於legacy的情況,對每一個adapter都調用driver->attach_adapter().
現在,我們可以將adapter和i2c driver關聯起來考慮一下了:
1:如果是news style形式的,在註冊adapter的時候,將它上面的i2c 設備轉換成了struct client.struct client->dev->bus又指定了和i2c driver同一個bus.因爲,它們可以發生probe.
2:如果是legacy形式,就直接找到對應的對象,調用driver->attach_adapter().

五: i2c_bus_type的相關操作
I2c_bus_type的操作主要存在於new-style形式的驅動中.接下來分析一下對應的probe過程:
5.1:match過程分析
Match對應的操作函數爲i2c_device_match().代碼如下
static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
    struct i2c_client  *client = to_i2c_client(dev);
    struct i2c_driver  *driver = to_i2c_driver(drv);

    /* make legacy i2c drivers bypass driver model probing entirely;
    * such drivers scan each i2c adapter/bus themselves.
    */
    if (!is_newstyle_driver(driver))
        return 0;

    /* match on an id table if there is one */
    if (driver->id_table)
        return i2c_match_id(driver->id_table, client) != NULL;

    return 0;
}
如果該驅動不是一個new-style形式的.或者driver沒有定義匹配的id_table.都會匹配失敗.
繼續跟蹤進i2c_match_id():
static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
                        const struct i2c_client *client)
{
    while (id->name[0]) {
        if (strcmp(client->name, id->name) == 0)
            return id;
        id++;
    }
    return NULL;
}
由此可見.如果client的名字和driver->id_table[]中的名稱匹配即爲成功.

5.2:probe過程分析
Probe對應的函數爲: i2c_device_probe()
static int i2c_device_probe(struct device *dev)
{
    struct i2c_client  *client = to_i2c_client(dev);
    struct i2c_driver  *driver = to_i2c_driver(dev->driver);
    const struct i2c_device_id *id;
    int status;

    if (!driver->probe)
        return -ENODEV;
    client->driver = driver;
    dev_dbg(dev, "probe/n");

    if (driver->id_table)
        id = i2c_match_id(driver->id_table, client);
    else
        id = NULL;
    status = driver->probe(client, id);
    if (status)
        client->driver = NULL;
    return status;
}
這個函數也很簡單,就是將probe流程回溯到i2c driver的probe()

六:其它的擴展
分析完adapter和i2c driver的註冊之後,好像整個架構也差不多了,其它,擴展的東西還有很多.
我們舉一個legacy形式的例子,這個例子是在kernel中隨便搜索出來的:
在linux-2.6.26.3/drivers/hwmon/ad7418.c中,初始化函數爲:
static int __init ad7418_init(void)
{
    return i2c_add_driver(&ad7418_driver);
}
i2c_driver ad7418_driver結構如下:
static struct i2c_driver ad7418_driver = {
    .driver = {
        .name  = "ad7418",
    },
    .attach_adapter = ad7418_attach_adapter,
    .detach_client  = ad7418_detach_client,
};
該結構中沒有probe()函數,可以斷定是一個legacy形式的驅動.這類驅動註冊的時候,會調用driver的attach_adapter函數.在這裏也就是ad7418_attach_adapter.
這個函數代碼如下:
static int ad7418_attach_adapter(struct i2c_adapter *adapter)
{
    if (!(adapter->class & I2C_CLASS_HWMON))
        return 0;
    return i2c_probe(adapter, &addr_data, ad7418_detect);
}
在這裏我們又遇到了一個i2c-core中的函數,i2c_probe().在分析這個函數之前,先來看下addr_data是什麼?
#define I2C_CLIENT_MODULE_PARM(var,desc) /
  static unsigned short var[I2C_CLIENT_MAX_OPTS] = I2C_CLIENT_DEFAULTS; /
  static unsigned int var##_num; /
  module_param_array(var, short, &var##_num, 0); /
  MODULE_PARM_DESC(var,desc)

#define I2C_CLIENT_MODULE_PARM_FORCE(name)              /
I2C_CLIENT_MODULE_PARM(force_##name,                    /
              "List of adapter,address pairs which are "    /
              "unquestionably assumed to contain a `"      /
              # name "' chip")


#define I2C_CLIENT_INSMOD_COMMON                    /
I2C_CLIENT_MODULE_PARM(probe, "List of adapter,address pairs to scan "  /
              "additionally");                  /
I2C_CLIENT_MODULE_PARM(ignore, "List of adapter,address pairs not to "  /
              "scan");                      /
static const struct i2c_client_address_data addr_data = {      /
    .normal_i2c = normal_i2c,                  /
    .probe      = probe,                    /
    .ignore    = ignore,                  /
    .forces    = forces,                  /
}

#define I2C_CLIENT_FORCE_TEXT /
    "List of adapter,address pairs to boldly assume to be present"
由此可知道,addr_data中的三個成員都是模塊參數.在加載模塊的時候可以用參數的方式對其賦值.三個模塊參數爲別爲probe,ignore,force.另外需要指出的是normal_i2c不能以模塊參數的方式對其賦值,只能在驅動內部靜態指定.
從模塊參數的模述看來, probe是指"List of adapter,address pairs to scan additionally"
Ignore是指"List of adapter,address pairs not to scan "
Force是指"List of adapter,address pairs to boldly assume to be present"
事實上,它們裏面的數據都是成對出現的.前面一部份表示所在的總線號,ANY_I2C_BUS表示任一總線.後一部份表示設備的地址.
現在可以來跟蹤i2c_probe()的代碼了.如下:
int i2c_probe(struct i2c_adapter *adapter,
          const struct i2c_client_address_data *address_data,
          int (*found_proc) (struct i2c_adapter *, int, int))
{
    int i, err;
    int adap_id = i2c_adapter_id(adapter);

    /* Force entries are done first, and are not affected by ignore
      entries */
      //先掃描force裏面的信息,注意它是一個二級指針.ignore裏的信息對它是無效的
    if (address_data->forces) {
        const unsigned short * const *forces = address_data->forces;
        int kind;

        for (kind = 0; forces[kind]; kind++) {
            for (i = 0; forces[kind] != I2C_CLIENT_END;
                i += 2) {
                if (forces[kind] == adap_id
                || forces[kind] == ANY_I2C_BUS) {
                    dev_dbg(&adapter->dev, "found force "
                        "parameter for adapter %d, "
                        "addr 0x%02x, kind %d/n",
                        adap_id, forces[kind][i + 1],
                        kind);
                    err = i2c_probe_address(adapter,
                        forces[kind][i + 1],
                        kind, found_proc);
                    if (err)
                        return err;
                }
            }
        }
    }

    /* Stop here if we can't use SMBUS_QUICK */
    //如果adapter不支持quick.不能夠遍歷這個adapter上面的設備
    if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) {
        if (address_data->probe[0] == I2C_CLIENT_END
        && address_data->normal_i2c[0] == I2C_CLIENT_END)
            return 0;

        dev_warn(&adapter->dev, "SMBus Quick command not supported, "
            "can't probe for chips/n");
        return -1;
    }

    /* Probe entries are done second, and are not affected by ignore
      entries either */
      //遍歷probe上面的信息.ignore上的信息也對它是沒有影響的
    for (i = 0; address_data->probe != I2C_CLIENT_END; i += 2) {
        if (address_data->probe == adap_id
        || address_data->probe == ANY_I2C_BUS) {
            dev_dbg(&adapter->dev, "found probe parameter for "
                "adapter %d, addr 0x%02x/n", adap_id,
                address_data->probe[i + 1]);
            err = i2c_probe_address(adapter,
                        address_data->probe[i + 1],
                        -1, found_proc);
            if (err)
                return err;
        }
    }

    /* Normal entries are done last, unless shadowed by an ignore entry */
    //最後遍歷normal_i2c上面的信息.它上面的信息不能在ignore中.
    for (i = 0; address_data->normal_i2c != I2C_CLIENT_END; i += 1) {
        int j, ignore;

        ignore = 0;
        for (j = 0; address_data->ignore[j] != I2C_CLIENT_END;
            j += 2) {
            if ((address_data->ignore[j] == adap_id ||
                address_data->ignore[j] == ANY_I2C_BUS)
            && address_data->ignore[j + 1]
                == address_data->normal_i2c) {
                dev_dbg(&adapter->dev, "found ignore "
                    "parameter for adapter %d, "
                    "addr 0x%02x/n", adap_id,
                    address_data->ignore[j + 1]);
                ignore = 1;
                break;
            }
        }
        if (ignore)
            continue;

        dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
            "addr 0x%02x/n", adap_id,
            address_data->normal_i2c);
        err = i2c_probe_address(adapter, address_data->normal_i2c,
                    -1, found_proc);
        if (err)
            return err;
    }

    return 0;
}
這段代碼很簡單,結合代碼上面添加的註釋應該很好理解.如果匹配成功,則會調用i2c_probe_address ().這個函數代碼如下:
static int i2c_probe_address(struct i2c_adapter *adapter, int addr, int kind,
                int (*found_proc) (struct i2c_adapter *, int, int))
{
    int err;

    /* Make sure the address is valid */
    //地址小於0x03或者大於0x77都是不合法的
    if (addr < 0x03 || addr > 0x77) {
        dev_warn(&adapter->dev, "Invalid probe address 0x%02x/n",
            addr);
        return -EINVAL;
    }

    /* Skip if already in use */
    //adapter上已經有這個設備了
    if (i2c_check_addr(adapter, addr))
        return 0;

    /* Make sure there is something at this address, unless forced */
    //如果kind小於0.檢查adapter上是否有這個設備
    if (kind < 0) {
        if (i2c_smbus_xfer(adapter, addr, 0, 0, 0,
                  I2C_SMBUS_QUICK, NULL) < 0)
            return 0;

        /* prevent 24RF08 corruption */
        if ((addr & ~0x0f) == 0x50)
            i2c_smbus_xfer(adapter, addr, 0, 0, 0,
                      I2C_SMBUS_QUICK, NULL);
    }

    /* Finally call the custom detection function */
    //調用回調函數
    err = found_proc(adapter, addr, kind);
    /* -ENODEV can be returned if there is a chip at the given address
      but it isn't supported by this chip driver. We catch it here as
      this isn't an error. */
    if (err == -ENODEV)
        err = 0;

    if (err)
        dev_warn(&adapter->dev, "Client creation failed at 0x%x (%d)/n",
            addr, err);
    return err;
}
首先,對傳入的參數進行一系列的合法性檢查.另外,如果該adapter上已經有了這個地址的設備了.也會返回失敗.所有adapter下面的設備都是以adapter->dev爲父結點的.因此只需要遍歷adapter->dev下面的子設備就可以得到當前地址是不是被佔用了.
如果kind < 0.還得要adapter檢查該總線是否有這個地址的設備.方法是向這個地址發送一個Read的Quick請求.如果該地址有應答,則說明這個地址上有這個設備.另外還有一種情況是在24RF08設備的特例.
如果adapter上確實有這個設備,就會調用驅動調用時的回調函數.

在上面涉及到了IIC的傳輸方式,有疑問的可以參考intel ICH5手冊的有關smbus部份.
跟蹤i2c_smbus_xfer().代碼如下:
s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags,
                  char read_write, u8 command, int size,
                  union i2c_smbus_data * data)
{
    s32 res;

    flags &= I2C_M_TEN | I2C_CLIENT_PEC;

    if (adapter->algo->smbus_xfer) {
        mutex_lock(&adapter->bus_lock);
        res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write,
                                        command,size,data);
        mutex_unlock(&adapter->bus_lock);
    } else
        res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
                                          command,size,data);

    return res;
}
如果adapter有smbus_xfer()函數,則直接調用它發送,否則,也就是在adapter不支持smbus協議的情況下,調用i2c_smbus_xfer_emulated()繼續處理.
跟進i2c_smbus_xfer_emulated().代碼如下:
static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
                                  unsigned short flags,
                                  char read_write, u8 command, int size,
                                  union i2c_smbus_data * data)
{
    /* So we need to generate a series of msgs. In the case of writing, we
      need to use only one message; when reading, we need two. We initialize
      most things with sane defaults, to keep the code below somewhat
      simpler. */
    //寫操作只會進行一次交互,而讀操作,有時會有兩次操作.
    //因爲有時候讀操作要先寫command,再從總線上讀數據
    //在這裏爲了代碼的簡潔.使用了兩個緩存區,將兩種情況統一起來.
    unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3];
    unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2];
    //一般來說,讀操作要交互兩次.例外的情況我們在下面會接着分析
    int num = read_write == I2C_SMBUS_READ?2:1;
    //與設備交互的數據,一般在msg[0]存放寫入設備的信息,在msb[1]裏存放接收到的
    //信息.不過也有例外的
    //msg[2]的初始化,默認發送緩存區佔一個字節,無接收緩存
    struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 },
                              { addr, flags | I2C_M_RD, 0, msgbuf1 }
                            };
    int i;
    u8 partial_pec = 0;

    //將要發送的信息copy到發送緩存區的第一字節
    msgbuf0[0] = command;
    switch(size) {
        //quick類型的,其它並不傳輸有效數據,只是將地址寫到總線上,等待應答即可
        //所以將發送緩存區長度置爲0 .再根據讀/寫操作,調整msg[0]的標誌位
        //這類傳輸只需要一次總線交互
    case I2C_SMBUS_QUICK:
        msg[0].len = 0;
        /* Special case: The read/write field is used as data */
        msg[0].flags = flags | (read_write==I2C_SMBUS_READ)?I2C_M_RD:0;
        num = 1;
        break;
    case I2C_SMBUS_BYTE:
        //BYTE類型指一次寫和讀只有一個字節.這種情況下,讀和寫都只會交互一次
        //這種類型的讀有例外,它讀取出來的數據不是放在msg[1]中的,而是存放在msg[0]
        if (read_write == I2C_SMBUS_READ) {
            /* Special case: only a read! */
            msg[0].flags = I2C_M_RD | flags;
            num = 1;
        }
        break;
    case I2C_SMBUS_BYTE_DATA:
        //Byte_Data是指命令+數據的傳輸形式.在這種情況下,寫只需要一次交互,讀卻要兩次
        //第一次將command寫到總線上,第二次要轉換方向.要將設備地址和read標誌寫入總線.
        //應回答之後再進行read操作
        //寫操作佔兩字節,分別是command+data.讀操作的有效數據只有一個字節
        //交互次數用初始化值就可以了
        if (read_write == I2C_SMBUS_READ)
            msg[1].len = 1;
        else {
            msg[0].len = 2;
            msgbuf0[1] = data->byte;
        }
        break;
    case I2C_SMBUS_WORD_DATA:
        //Word_Data是指命令+雙字節的形式.這種情況跟Byte_Data的情況類似
        //兩者相比只是交互的數據大小不同
        if (read_write == I2C_SMBUS_READ)
            msg[1].len = 2;
        else {
            msg[0].len=3;
            msgbuf0[1] = data->word & 0xff;
            msgbuf0[2] = data->word >> 8;
        }
        break;
    case I2C_SMBUS_PROC_CALL:
        //Proc_Call的方式與write 的Word_Data相似,只不過寫完Word_Data之後,要等待它的應答
        //應該它需要交互兩次,一次寫一次讀
        num = 2; /* Special case */
        read_write = I2C_SMBUS_READ;
        msg[0].len = 3;
        msg[1].len = 2;
        msgbuf0[1] = data->word & 0xff;
        msgbuf0[2] = data->word >> 8;
        break;
    case I2C_SMBUS_BLOCK_DATA:
        //Block_Data:指command+N段數據的情況.
        //如果是讀操作,它首先要寫command到總線,然後再讀N段數據.要寫的command已經
        //放在msg[0]了.現在只需要將msg[1]的標誌置I2C_M_RECV_LEN位,msg[1]有效長度爲1字節.因爲
        //adapter驅動會處理好的.現在現在還不知道要傳多少段數據.

        //對於寫的情況:msg[1]照例不需要.將要寫的數據全部都放到msb[0]中.相應的也要更新
        //msg[0]中的緩存區長度
        if (read_write == I2C_SMBUS_READ) {
            msg[1].flags |= I2C_M_RECV_LEN;
            msg[1].len = 1; /* block length will be added by
                      the underlying bus driver */
        } else {
            //data->block[0]表示後面有多少段數據.總長度要加2是因爲command+count+N段數據
            msg[0].len = data->block[0] + 2;
            if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {
                dev_err(&adapter->dev, "smbus_access called with "
                      "invalid block write size (%d)/n",
                      data->block[0]);
                return -1;
            }
            for (i = 1; i < msg[0].len; i++)
                msgbuf0 = data->block[i-1];
        }
        break;
    case I2C_SMBUS_BLOCK_PROC_CALL:
        //Proc_Call:表示寫完Block_Data之後,要等它的應答消息它和Block_Data相比,只是多了一部份應答而已
        num = 2; /* Another special case */
        read_write = I2C_SMBUS_READ;
        if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
            dev_err(&adapter->dev, "%s called with invalid "
                "block proc call size (%d)/n", __func__,
                data->block[0]);
            return -1;
        }
        msg[0].len = data->block[0] + 2;
        for (i = 1; i < msg[0].len; i++)
            msgbuf0 = data->block[i-1];
        msg[1].flags |= I2C_M_RECV_LEN;
        msg[1].len = 1; /* block length will be added by
                  the underlying bus driver */
        break;
    case I2C_SMBUS_I2C_BLOCK_DATA:
        //I2c Block_Data與Block_Data相似,只不過read的時候,數據長度是預先定義好了的.另外
        //與Block_Data相比,中間不需要傳輸Count字段.(Count表示數據段數目)
        if (read_write == I2C_SMBUS_READ) {
            msg[1].len = data->block[0];
        } else {
            msg[0].len = data->block[0] + 1;
            if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) {
                dev_err(&adapter->dev, "i2c_smbus_xfer_emulated called with "
                      "invalid block write size (%d)/n",
                      data->block[0]);
                return -1;
            }
            for (i = 1; i <= data->block[0]; i++)
                msgbuf0 = data->block;
        }
        break;
    default:
        dev_err(&adapter->dev, "smbus_access called with invalid size (%d)/n",
              size);
        return -1;
    }

    //如果啓用了PEC.Quick和I2c Block_Data是不支持PEC的
    i = ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK
                      && size != I2C_SMBUS_I2C_BLOCK_DATA);
    if (i) {
        /* Compute PEC if first message is a write */
        //如果第一個操作是寫操作
        if (!(msg[0].flags & I2C_M_RD)) {
            //如果只是寫操作
            if (num == 1) /* Write only */
                //如果只有寫操作,寫緩存區要擴充一個字節,用來存放計算出來的PEC
                i2c_smbus_add_pec(&msg[0]);
            else /* Write followed by read */
                //如果後面還有讀操作,先計算前面寫部份的PEC(注意這種情況下不需要
                //擴充寫緩存區,因爲不需要發送PEC.只會接收到PEC)
                partial_pec = i2c_smbus_msg_pec(0, &msg[0]);
        }
        /* Ask for PEC if last message is a read */
        //如果最後一次是讀消息.還要接收到來自slave的PEC.所以接收緩存區要擴充一個字節
        if (msg[num-1].flags & I2C_M_RD)
            msg[num-1].len++;
    }

    if (i2c_transfer(adapter, msg, num) < 0)
        return -1;

    /* Check PEC if last message is a read */
    //操作完了之後,如果最後一個操作是PEC的讀操作.檢驗後面的PEC是否正確
    if (i && (msg[num-1].flags & I2C_M_RD)) {
        if (i2c_smbus_check_pec(partial_pec, &msg[num-1]) < 0)
            return -1;
    }

    //操作完了,現在可以將數據放到data部份返回了.
    if (read_write == I2C_SMBUS_READ)
        switch(size) {
            case I2C_SMBUS_BYTE:
                data->byte = msgbuf0[0];
                break;
            case I2C_SMBUS_BYTE_DATA:
                data->byte = msgbuf1[0];
                break;
            case I2C_SMBUS_WORD_DATA:
            case I2C_SMBUS_PROC_CALL:
                data->word = msgbuf1[0] | (msgbuf1[1] << 8);
                break;
            case I2C_SMBUS_I2C_BLOCK_DATA:
                for (i = 0; i < data->block[0]; i++)
                    data->block[i+1] = msgbuf1;
                break;
            case I2C_SMBUS_BLOCK_DATA:
            case I2C_SMBUS_BLOCK_PROC_CALL:
                for (i = 0; i < msgbuf1[0] + 1; i++)
                    data->block = msgbuf1;
                break;
        }
    return 0;
}
在這個函數添上了很詳細的註釋,配和intel的datasheet,應該很容易看懂.在上面的交互過程中,調用了子函數i2c_transfer().它的代碼如下所示:
int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
{
    int ret;

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

        ret = adap->algo->master_xfer(adap,msgs,num);
        mutex_unlock(&adap->bus_lock);

        return ret;
    } else {
        dev_dbg(&adap->dev, "I2C level transfers not supported/n");
        return -ENOSYS;
    }
}
因爲在這裏的同步用的是mutex.首先判斷判斷是否充許睡眠,如果不允許,嘗試獲鎖.如果獲鎖失敗,則返回,這樣的操作是避免進入睡眠,我們在後面也可以看到,實際的傳輸工作交給了adap->algo->master_xfer()完成.

在這裏,我們終於把i2c_probe_address()的執行分析完了,經過這個分析,我們也知道了數據是怎麼樣傳輸的.我們接着i2c_probe()往下看.如果i2c_probe_address()成功.說明總線上確實有這樣的設備.那麼就會調用驅動中的回調函數.在ad7148的驅動中,如下所示:
return i2c_probe(adapter, &addr_data, ad7418_detect);
也就是說,要調用的回調函數是ad7418_detect().這個函數中我們只分析和i2c框架相關的部份.代碼片段如下所示:
static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind)
{
    struct i2c_client *client;
    ……
    ……
client->addr = address;
    client->adapter = adapter;
    client->driver = &ad7418_driver;

    i2c_set_clientdata(client, data);
    ……
    ……
if ((err = i2c_attach_client(client)))
        goto exit_free;
    ……
    ……
}
結合上面關於new-style形式的驅動分析.發現這裏走的是同一個套路,即初始化了client.然後調用i2c_attach_client().後面的流程就跟上面分析的一樣了.只不過,不相同的是,這裏clinet已經指定了驅動爲ad7418_driver.應該在註冊clinet->dev之後,就不會走bus->match和bus->probe的流程了.

七:i2c dev節點操作
現在來分析上面架構圖中的i2c-dev.c中的部份.這個部份爲用戶空間提供了操作adapter的接口.這部份代碼其實對應就晃一個模塊.它的初始化函數爲:
module_init(i2c_dev_init);
i2c_dev_init()代碼如下:
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))
        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;
}
首先爲主冊了一個主設備號爲I2C_MAJOR(89),操作集爲i2cdev_fops的字符設備.然後註冊了一個名爲”i2c-dev”的class.之後再註冊了一個i2c的driver.如下所示:[font=Times New Roman]
res = i2c_add_driver(&i2cdev_driver);
    if (res)
        goto out_unreg_class;
i2cdev_driver定義如下:
static struct i2c_driver i2cdev_driver = {
    .driver = {
        .name  = "dev_driver",
    },
    .id    = I2C_DRIVERID_I2CDEV,
    .attach_adapter = i2cdev_attach_adapter,
    .detach_adapter = i2cdev_detach_adapter,
    .detach_client  = i2cdev_detach_client,
};
也就是說,當它註冊或者有新的adapter註冊後,就會它的attach_adapter()函數.該函數代碼如下:
static int i2cdev_attach_adapter(struct i2c_adapter *adap)
{
    struct i2c_dev *i2c_dev;
    int res;

    i2c_dev = get_free_i2c_dev(adap);
    if (IS_ERR(i2c_dev))
        return PTR_ERR(i2c_dev);

    /* register this i2c device with the driver core */
    i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,
                    MKDEV(I2C_MAJOR, adap->nr),
                    "i2c-%d", adap->nr);
    if (IS_ERR(i2c_dev->dev)) {
        res = PTR_ERR(i2c_dev->dev);
        goto error;
    }
    res = device_create_file(i2c_dev->dev, &dev_attr_name);
    if (res)
        goto error_destroy;

    pr_debug("i2c-dev: adapter [%s] registered as minor %d/n",
        adap->name, adap->nr);
    return 0;
error_destroy:
    device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
error:
    return_i2c_dev(i2c_dev);
    return res;
}
這個函數也很簡單,首先調用get_free_i2c_dev()分配並初始化了一個structi2c_dev結構,使i2c_dev->adap指向操作的adapter.之後,該i2c_dev會被鏈入鏈表i2c_dev_list中.再分別以I2C_MAJOR,adap->nr爲主次設備號創建了一個device.如果此時系統配置了udev或者是hotplug,那麼就麼在/dev下自動創建相關的設備節點了.
剛纔我們說過,所有主設備號爲I2C_MAJOR的設備節點的操作函數是i2cdev_fops.它的定義如下所示:
static const struct file_operations i2cdev_fops = {
    .owner      = THIS_MODULE,
    .llseek    = no_llseek,
    .read      = i2cdev_read,
    .write      = i2cdev_write,
    .ioctl      = i2cdev_ioctl,
    .open      = i2cdev_open,
    .release    = i2cdev_release,
};

7.1:i2c dev的open操作
Open操作對應的函數爲i2cdev_open().代碼如下:

static int i2cdev_open(struct inode *inode, struct file *file)
{
    unsigned int minor = iminor(inode);
    struct i2c_client *client;
    struct i2c_adapter *adap;
    struct i2c_dev *i2c_dev;

    //以次設備號從i2c_dev_list鏈表中取得i2c_dev
    i2c_dev = i2c_dev_get_by_minor(minor);
    if (!i2c_dev)
        return -ENODEV;

    //以apapter的總線號從i2c_adapter_idr中找到adapter
    adap = i2c_get_adapter(i2c_dev->adap->nr);
    if (!adap)
        return -ENODEV;

    /* This creates an anonymous i2c_client, which may later be
    * pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE.
    *
    * This client is ** NEVER REGISTERED ** with the driver model
    * or I2C core code!!  It just holds private copies of addressing
    * information and maybe a PEC flag.
    */
    //分配並初始化一個i2c_client結構
    client = kzalloc(sizeof(*client), GFP_KERNEL);
    if (!client) {
        i2c_put_adapter(adap);
        return -ENOMEM;
    }
    snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
    client->driver = &i2cdev_driver;

    //clinet->adapter指向操作的adapter
    client->adapter = adap;
    //關聯到file
    file->private_data = client;

    return 0;
}
注意這裏分配並初始化了一個structi2c_client結構.但是沒有註冊這個clinet.此外,這個函數中還有一個比較奇怪的操作.不是在前面已經將i2c_dev->adap指向要操作的adapter麼?爲什麼還要以adapter->nr爲關鍵字從i2c_adapter_idr去找這個操作的adapter呢?注意了,調用i2c_get_adapter()從總線號nr找到操作的adapter的時候,還會增加module的引用計數.這樣可以防止模塊意外被釋放掉.也許有人會有這樣的疑問,那i2c_dev->adap->nr操作,如果i2c_dev->adap被釋放掉的話,不是一樣會引起系統崩潰麼?這裏因爲,在i2cdev_attach_adapter()間接的增加了一次adapter的一次引用計數.如下:
tatic int i2cdev_attach_adapter(struct i2c_adapter *adap)
{
......
i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,
                    MKDEV(I2C_MAJOR, adap->nr),
                    "i2c-%d", adap->nr);
......
}
看到了麼,i2c_dev內嵌的device是以adap->dev爲父結點,在device_create()中會增次adap->dev的一次引用計數.
好了,open()操作到此就完成了.

7.2:read操作
Read操作對應的操作函數如下示:
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 %zd 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;
}
首先從file結構中取得struct i2c_clinet.然後在kernel同分配相同長度的緩存區,隨之調用i2c_master_recv()從設備中讀取數據.再將讀取出來的數據copy到用戶空間中.
I2c_master_recv()代碼如下:
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_msg.然後調用i2c_tanster().代碼中的client->flags & I2C_M_TEN表示adapter是否採用10位尋址的方式.在這裏就不再詳細分析了.
另外,有人可能看出了一個問題.這裏clinet->addr是從哪來的呢?對,在read之前應該還要有一步操作來設置clinet->addr的值.這個過程是ioctl的操作.ioctl可以設置PEC標誌,重試次數,超時時間,和發送接收數據等,我們在這裏只看一下clinet->addr的設置.代碼片段如下示:
static int i2cdev_ioctl(struct inode *inode, struct file *file,
        unsigned int cmd, unsigned long arg)
{
    ......
    ......
    switch ( cmd ) {
    case I2C_SLAVE:
    case I2C_SLAVE_FORCE:
        /* NOTE:  devices set up to work with "new style" drivers
        * can't use I2C_SLAVE, even when the device node is not
        * bound to a driver.  Only I2C_SLAVE_FORCE will work.
        *
        * Setting the PEC flag here won't affect kernel drivers,
        * which will be using the i2c_client node registered with
        * the driver model core.  Likewise, when that client has
        * the PEC flag already set, the i2c-dev driver won't see
        * (or use) this setting.
        */
        if ((arg > 0x3ff) ||
            (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
            return -EINVAL;
        if (cmd == I2C_SLAVE && i2cdev_check_addr(client->adapter, arg))
            return -EBUSY;
        /* REVISIT: address could become busy later */
        client->addr = arg;
        return 0;
    ......
    ......
}
由此可見,調用I2C_SLAVE或者I2C_SLAVE_FORCE的Ioctl就會設置clinet->addr.另外,註釋中也說得很清楚了.如果是I2C_SLAVE的話,還會調用其所長i2cdev_check_addr().進行地址檢查,如果adapter已經關聯到這個地址的設備,就會檢查失敗.

7.2:write操作
Write操作如下所示:
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 %zd bytes./n",
        iminor(file->f_path.dentry->d_inode), count);

    ret = i2c_master_send(client,tmp,count);
    kfree(tmp);
    return ret;
}
該操作比較簡單,就是將用戶空間的數據發送到i2c 設備.

八:小結
在本節中,分析了i2c的框架設計.這個框架大體上沿用了Linux的設備驅動框架,不過之中又做了很多變通.在之後的分析中,會分別舉一個adapter和i2c device的例子來詳細描述一下有關i2c driver的設計.
發佈了1 篇原創文章 · 獲贊 2 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章