zoukankan      html  css  js  c++  java
  • RTC设备驱动

    问题:pcf8563 RTC设备驱动不能被正常的加载!问题分析过程。
    
    问题在下午得到解决,虽然解决的办法比较笨,采用的是不断的使用printk来跟踪rtc-8563驱动的加载的过程,以及iic模块的工作过程。
    
    曾经想过将内核的DEBUG打开,打开的方法在/linux2.6.21/include/linux/device.h文件中搜索DEBUG,这样的话,设备的所有的操作的debug信息都会输出,你会受不了,因为输出的无用的信息会掩盖你需要的真正的信息。
    
    所以就改为在i2c-core.c和rtc-8563文件中加入printk调试信息来跟踪系统的信息输出。我们来分析一下rtc驱动的加载过程。
    
    Linux驱动的i2c文件夹下有algos,busses,chips三个文件夹,另外还有i2c-core.c和i2c-dev.c两个文件。其中 i2c-core.c文件实现了I2C core框架,是Linux内核用来维护和管理的I2C的核心部分,其中维护了两个静态的List,分别记录系统中的I2C driver结构和I2C adapter结构。I2C core提供接口函数,允许一个I2C adatper,I2C driver和I2C client初始化时在I2C core中进行注册,以及退出时进行注销。同时还提供了I2C总线读写访问的一般接口,主要应用在I2C设备驱动中。
    
    
    在rtc-8563文件中:
    static int __init pcf8563_init(void)
    {
        return i2c_add_driver(&pcf8563_driver);
    }
    
    static void __exit pcf8563_exit(void)
    {
        i2c_del_driver(&pcf8563_driver);
    }
    
    MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
    MODULE_DESCRIPTION("Philips PCF8563/Epson RTC8564 RTC driver");
    MODULE_LICENSE("GPL");
    MODULE_VERSION(DRV_VERSION);
    
    module_init(pcf8563_init);
    module_exit(pcf8563_exit);
    
    从这里我们可以知道模块加载的初始化函数和卸载函数都是使用的i2c的框架函数i2c_add_driver和i2c_del_driver。
    i2c_add_driver被定义在 include/linux/i2c.h文件中。其实质是i2c-core.c文件中的i2c_register_driver函数
    该函数的原型如下:
    int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
    {
        struct list_head   *item;
        struct i2c_adapter *adapter;
        int res;
    
        /* add the driver to the list of i2c drivers in the driver core */
        driver->driver.owner = owner;
        driver->driver.bus = &i2c_bus_type;
    
        res = driver_register(&driver->driver);
        if (res)
            return res;
    
        mutex_lock(&core_lists);
        //将该driver的list成员加入到全局的drivers链表尾部,linux中大量存在这种链表的结构体
        list_add_tail(&driver->list,&drivers);
        pr_debug("i2c-core: driver [%s] registered
    ", driver->driver.name);
    
        /* now look for instances of driver on our adapters */
        if (driver->attach_adapter) {
    //该函数搜索整个adapters链表,item指向每一个链表中的成员,这里实际是一个for循环。
    //      #define list_for_each(pos, head) 
    //        for (pos = (head)->next; prefetch(pos->next), pos //!=(head); pos = pos->next)
    
            list_for_each(item,&adapters) {
      //获得一个适配器结构体
                adapter = list_entry(item, struct i2c_adapter, list);
                driver->attach_adapter(adapter);
            }
        }
    
        mutex_unlock(&core_lists);
        return 0;
    }
    EXPORT_SYMBOL(i2c_register_driver);
    
    在这个函数中,首先向内核中注册你的驱动,然后锁信号量。。最关键的一步是:
    driver->attach_adapter(adapter);
    而attach_adapter就是在rtc-pcf8563.c文件中定义的重要的驱动结构体,定义如下。
    
    static struct i2c_driver pcf8563_driver = {
        .driver        = {
            .name    = "pcf8563",
        },
        .id        = I2C_DRIVERID_PCF8563,
        .attach_adapter = &pcf8563_attach,
        .detach_client    = &pcf8563_detach,
    };
    
    
    所以也就是说i2c框架函数会回调你写的适配器加载函数,我们的适配器加载函数是pcf8563_attach函数。该函数定义如下:
    static int pcf8563_attach(struct i2c_adapter *adapter)
    {
        return i2c_probe(adapter, &addr_data, pcf8563_probe);
    }
    调用i2c框架函数i2c_probe来进行适配器的加载。
    在下面这个函数中传递参数为
    适配器变量:adapter。
    i2c_client_address_data结构体原型
    static struct i2c_client_address_data addr_data = {            
        .normal_i2c    = normal_i2c,                    
        .probe        = probe,                    
        .ignore        = ignore,                    
        .forces        = forces,                    
    }
    
    注意,在我们的rtc-8563.c文件中只定义了normal_i2c数组。
    static unsigned short normal_i2c[] = { 0x51,I2C_CLIENT_END };
    而出错的地方就在这里,原来的定义没有0x51这个成员,所以根本不去加载pcf8563这个器件。
    
    
    
    int i2c_probe(struct i2c_adapter *adapter,
              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 */
    //为空,不执行
        if (address_data->forces) {
            unsigned short **forces = address_data->forces;
            int kind;
            for (kind = 0; forces[kind]; kind++) {
                for (i = 0; forces[kind][i] != I2C_CLIENT_END;
                     i += 2) {
                    if (forces[kind][i] == adap_id
                     || forces[kind][i] == ANY_I2C_BUS) {
                        dev_dbg(&adapter->dev, "found force "
                            "parameter for adapter %d, "
                            "addr 0x%02x, kind %d
    ",
                            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 */
        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
    ");
            return -1;
        }
    
        /* Probe entries are done second, and are not affected by ignore
           entries either */
        for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) {
            if (address_data->probe[i] == adap_id
             || address_data->probe[i] == ANY_I2C_BUS) {
                dev_dbg(&adapter->dev, "found probe parameter for "
                    "adapter %d, addr 0x%02x
    ", 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 */
    //执行这部!通过i2c_probe_address函数来回调你编写的pcf8563_probe加载函数。
        for (i = 0; address_data->normal_i2c[i] != 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[i]) {
                    dev_printk(KERN_ERR ,&adapter->dev, "found ignore "
                        "parameter for adapter %d, "
                        "addr 0x%02x
    ", 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
    ", adap_id,
                address_data->normal_i2c[i]);
            err = i2c_probe_address(adapter, address_data->normal_i2c[i],
                        -1, found_proc);
            if (err)
                return err;
        }
    
        return 0;
    }
    
    i2c_probe_address的原型存在于i2c-core.c文件中:
    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 */
        if (addr < 0x03 || addr > 0x77) {
            dev_warn(&adapter->dev, "Invalid probe address 0x%02x
    ",
                 addr);
            return -EINVAL;
        }
        /* Skip if already in use */
        if (i2c_check_addr(adapter, addr))
            return 0;
        /* Make sure there is something at this address, unless forced */
        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 */
    //这里回调你写的适配器加载函数pcf8563_probe,完成一个iic适配器的加载
        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)
    ",
                 addr, err);
        return err;
    }
  • 相关阅读:
    MFC中,什么是CALLBACK函数,什么是WINAPI函数,二者有什么区别和联系?
    浙江移动话费计算-js代码
    [转]C#网页自动登录和提交POST信息的多种方法
    JavaScript小数四舍五入toFixed
    C#.NET应用程序实现网页自动登录
    VC改变对话框按钮字体颜色和背景的解决方案(转)
    WPF窗口阴影
    用MVVM模式开发中遇到的零散问题总结(1)
    NPOI之Excel——合并单元格、设置样式、输入公式
    近距离接触RAC DRM
  • 原文地址:https://www.cnblogs.com/timssd/p/4086280.html
Copyright © 2011-2022 走看看