+ -
当前位置:首页 → 问答吧 → rs5c372驱动加载问题,klist_next返回NULL的问题

rs5c372驱动加载问题,klist_next返回NULL的问题

时间:2010-07-24

来源:互联网

本帖最后由 joey_chow 于 2010-07-24 17:28 编辑

在使用内核提供的rs5c372的驱动时,驱动了麻烦,不能加载,在rs5c372执行init函数后,并没有执行probe函数,
追踪后发现,在匹配设备时,klist_next查找时返回了NULL,详细的追踪过程如下:

我的追踪过程如下:

//in rtc-rs5c372.c
static __init int rs5c372_init(void)
{
printk("Chow:rs5c372_init\n");
        return i2c_add_driver(&rs5c372_driver);
}
//in i2c.h
static inline int i2c_add_driver(struct i2c_driver *driver)
{
        return i2c_register_driver(THIS_MODULE, driver);
}

//in i2c-core.c
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
        int res;

        /* new style driver methods can't mix with legacy ones */
        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 */
        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.
         */
        res = driver_register(&driver->driver); //继续追踪driver_register
        if (res)
                return res;
        pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
        printk("chow:i2c-core: driver [%s] registered\n", driver->driver.name);

        INIT_LIST_HEAD(&driver->list);
        /* Walk the adapters that are already present */
        mutex_lock(&core_lists);
        printk("chow: bus for each dev\n");
        bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver);
        //bus_for_each_dev(&i2c_bus_type, NULL, driver, NULL);
        mutex_unlock(&core_lists);

printk("chow:leav for i2c register driver\n");
        return 0;
}
//in driver.c
int driver_register(struct device_driver * drv)
{
        if ((drv->bus->probe && drv->probe) ||
            (drv->bus->remove && drv->remove) ||
            (drv->bus->shutdown && drv->shutdown)) {
                printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);
        }
        printk("chow : Driver '%s' is register\n", drv->name);
        klist_init(&drv->klist_devices, NULL, NULL);
        return bus_add_driver(drv);//由此处追踪}
//in bus.c
int bus_add_driver(struct device_driver *drv)
{
        struct bus_type * bus = bus_get(drv->bus);
        int error = 0;

        if (!bus)
                return -EINVAL;

        pr_debug("bus %s: add driver %s\n", bus->name, drv->name);
        error = kobject_set_name(&drv->kobj, "%s", drv->name);
        if (error)
                goto out_put_bus;
printk("chow: 1\n");               
        drv->kobj.kset = &bus->drivers;
        error = kobject_register(&drv->kobj);
        if (error)
                goto out_put_bus;
printk("chow: 2\n");
printk("chow: drv->bus->drivers_autoprobe[%s]=%d \n", drv->name, drv->bus->drivers_autoprobe);
        if (drv->bus->drivers_autoprobe) {
                error = driver_attach(drv);// 探测驱动,由此处追踪
                if (error)
                        goto out_unregister;
printk("chow: 3\n");                       
        }
        klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
        module_add_driver(drv->owner, drv);

        error = driver_create_file(drv, &driver_attr_uevent);
        if (error) {
                printk(KERN_ERR "%s: uevent attr (%s) failed\n",
                        __FUNCTION__, drv->name);
        }
        error = driver_add_attrs(bus, drv);
        if (error) {
                /* How the hell do we get out of this pickle? Give up */
                printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
                        __FUNCTION__, drv->name);
        }
        error = add_bind_files(drv);
        if (error) {
                /* Ditto */
                printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
                        __FUNCTION__, drv->name);
        }

printk("chow:error=%d\n", error);
        return error;
out_unregister:
printk("chow: out_unregister\n");
        kobject_unregister(&drv->kobj);
out_put_bus:
printk("chow: out_put_bus\n");
        bus_put(bus);
        return error;
}

//in dd.c
int driver_attach(struct device_driver * drv)
{

printk("chow: drv[%s]\n", drv->name);
        return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}

//in bus.c
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;

printk("chow:bus_for_each_dev[] bus[%s]  \n", bus->name);
        if (!bus)
                return -EINVAL;

printk("chow next device\n");
        klist_iter_init_node(&bus->klist_devices, &i,
                             (start ? &start->knode_bus : NULL));


                             
        while ((dev = next_device(&i)) && !error)//追踪 next_device
                error = fn(dev, data);
        klist_iter_exit(&i);

printk("chow:bus for dev :%d\n", error);       
        return error;
}
//in bus.c
static struct device * next_device(struct klist_iter * i)
{

/*
        struct klist_node * n = klist_next(i);
        return n ? container_of(n, struct device, knode_bus) : NULL;
*/
        struct klist_node *n = klist_next(i); //追踪 klist_next
        struct device *dev = NULL;
        //struct device *dev_prv;

        if (n) { // 发现 n == 0,直接return了
        printk("chow: n\n");
                dev = to_device_private_bus(n);
                //dev = dev_prv->device;
        }
       
        return dev;

}
//in klist.c
struct klist_node * klist_next(struct klist_iter * i)
{
        struct list_head * next;
        struct klist_node * lnode = i->i_cur;
        struct klist_node * knode = NULL;
        void (*put)(struct klist_node *) = i->i_klist->put;


        spin_lock(&i->i_klist->k_lock);
printk("chow: inode=%d\n", lnode);               
       
        if (lnode) { //发现lnode==0
       
                next = lnode->n_node.next;
                if (!klist_dec_and_del(lnode))
                        put = NULL;
        } else
                next = i->i_head->next;

printk("chow: net=%d   i->i_head=%d\n\n", next, i->i_head);
/*此处的打印信息如下:
chow next device
chow: inode=0
chow: next=-1609140780   i->i_head=-1609140780 这两个值相等,其它正常的驱动,都不相等的,why???

chow: knode=0
*/


        if (next != i->i_head) { //问题可能出在此处,从打印信息中发现,这两个值相等,因此knode == null,
                knode = to_klist_node(next);
printk("chow: knode1=%d\n", knode);               
               
                kref_get(&knode->n_ref);
        }
        i->i_cur = knode;
        spin_unlock(&i->i_klist->k_lock);
        if (put && lnode)
                put(lnode);
printk("chow: knode=%d\n", knode);               
        return knode;
}


详细的打印信息如下:

Chow:rs5c372_init
chow : Driver 'rtc-rs5c372' is register
chow: 1
chow: 2
chow: drv->bus->drivers_autoprobe[rtc-rs5c372]=1
chow: drv[rtc-rs5c372]
chow:bus_for_each_dev[] bus[i2c]  
chow next device
chow: inode=0
chow: next=-1609140780   i->i_head=-1609140780

chow: knode=0
chow:bus for dev :0
chow: 3
chow:error=0
chow:i2c-core: driver [rtc-rs5c372] registered
chow: bus for each dev
chow:bus_for_each_dev[] bus[i2c]  
chow next device
chow: inode=0
chow: net=-1609140780   i->i_head=-1609140780

chow: knode=0
chow:bus for dev :0
chow:leav for i2c register driver
chow : Driver 'lpc22xx-i2c' is register
chow: 1
chow: 2
chow: drv->bus->drivers_autoprobe[lpc22xx-i2c]=1
chow: drv[lpc22xx-i2c]
chow:bus_for_each_dev[] bus[platform]  
chow next device
chow: inode=0
chow: net=-1609190084   i->i_head=-1609144760//正确加载的都不相等

chow: knode1=-1609190088
chow: knode=-1609190088
chow: n
chow:__driver_attach
chow: driver_probe_device
chow:platform: try du match  lpc22xx-global with Driver lpc22xx-i2c
chow: inode=-1609190088
chow: net=-1609189724   i->i_head=-1609144760

chow: knode1=-1609189728
chow: knode=-1609189728
chow: n
chow:__driver_attach
chow: driver_probe_device
chow:platform: try du match  lpc22xx-gpio with Driver lpc22xx-i2c
chow: inode=-1609189728
chow: net=-1609189392   i->i_head=-1609144760

chow: knode1=-1609189396
chow: knode=-1609189396
chow: n
chow:__driver_attach
chow: driver_probe_device
chow:platform: try du match  lpc22xx-timer with Driver lpc22xx-i2c
chow: inode=-1609189396
chow: net=-1609189088   i->i_head=-1609144760

chow: knode1=-1609189092
chow: knode=-1609189092
chow: n
chow:__driver_attach
chow: inode=-1609189092
chow: net=-1609188672   i->i_head=-1609144760

chow: knode1=-1609188676
chow: knode=-1609188676
chow: n
chow:__driver_attach
chow: driver_probe_device
chow:platform: try du match  nvram with Driver lpc22xx-i2c
chow: inode=-1609188676
chow: net=-1609188368   i->i_head=-1609144760

chow: knode1=-1609188372
chow: knode=-1609188372
chow: n
chow:__driver_attach
chow: driver_probe_device
chow:platform: try du match  lpc22xx-i2c.0 with Driver lpc22xx-i2c
chow:platform: Matched Device lpc22xx-i2c.0 with Driver lpc22xx-i2c
chow: really_probe
lpc22xx_i2c_probe base=e005c000 irq=19
Division by zero in kernel.
Function entered at [<a0020500>] from [<a0020d3c>]
Function entered at [<a0020d24>] from [<a00cbaa8>]
Function entered at [<a011e0f4>] from [<a0018f5c>]
r5:a015bba4 r4:a030f800
Function entered at [<a0018e54>] from [<a0103908>]
r7:00000000 r6:a015bc2c r5:a015bba4 r4:a01676d4
Function entered at [<a01038e8>] from [<a010198c>]
Function entered at [<a0101800>] from [<a0101bec>]
Function entered at [<a0101afc>] from [<a0100ab4>]
r6:a01676d4 r5:a01b7ee8 r4:00000000
Function entered at [<a0100a4c>] from [<a0101c24>]
r8:a01b6000 r7:a01676dc r6:a01665b0 r5:00000000 r4:a01676d4
Function entered at [<a0101bf4>] from [<a01010a8>]
r4:a01676d4
Function entered at [<a0100f40>] from [<a0102094>]
Function entered at [<a0102038>] from [<a0103a1c>]
r4:00000000
Function entered at [<a01039b0>] from [<a0019018>]
Function entered at [<a0019004>] from [<a0008ba4>]
Function entered at [<a0008b00>] from [<a0031c9c>]
=== lpc22xx_pca_init
Chow: i2c probe
chow: inode=-1609188372
chow: net=-1609188036   i->i_head=-1609144760

chow: knode1=-1609188040
chow: knode=-1609188040
chow: n
chow:__driver_attach
chow: driver_probe_device
chow:platform: try du match  lpc22xx-usb.0 with Driver lpc22xx-i2c
chow: inode=-1609188040
chow: net=-1609187704   i->i_head=-1609144760

chow: knode1=-1609187708
chow: knode=-1609187708
chow: n
chow:__driver_attach
chow: driver_probe_device
chow:platform: try du match  lpc22xx-can.0 with Driver lpc22xx-i2c
chow: inode=-1609187708
chow: net=-1609187316   i->i_head=-1609144760

chow: knode1=-1609187320
chow: knode=-1609187320
chow: n
chow:__driver_attach
chow: driver_probe_device
chow:platform: try du match  lpc2468-ea-flash with Driver lpc22xx-i2c
chow: inode=-1609187320
chow: net=-1608527788   i->i_head=-1609144760

chow: knode1=-1608527792
chow: knode=-1608527792
chow: n
chow:__driver_attach
chow: inode=-1608527792
chow: net=-1607466412   i->i_head=-1609144760

chow: knode1=-1607466416
chow: knode=-1607466416
chow: n
chow:__driver_attach
chow: inode=-1607466416
chow: net=-1609144760   i->i_head=-1609144760

chow: knode=0
chow:bus for dev :0
chow: 3
chow:error=0
Chow:rtc_class_open rtc0: rtc_class=1
drivers/rtc/hctosys.c: unable to open rtc device (rtc0)
VFS: Mounted root (jffs2 filesystem).
init started:  BusyBox v1.00 (2010.06.01-15:23+0000) multi-call binary
init started:  BusyBox v1.00 (2010.06.01-15:23+0000) multi-call binary
Starting pid 18, console : '/etc/rc'
Welcome to
          ____ _  _
         /  __| ||_|                 
    _   _| |  | | _ ____  _   _  _  _
   | | | | |  | || |  _ \| | | |\ \/ /
   | |_| | |__| || | | | | |_| |/    \
   |  ___\____|_||_|_| |_|\____|\_/\_/
   | |
   |_|

For further information check:
http://www.uclinux.org/
http://www.olimex.com/dev/
Starting pid 30, console : '/bin/sh'


BusyBox v1.00 (2010.06.01-16:26+0000) Built-in shell (msh)
Enter 'help' for a list of built-in commands.

#

作者: joey_chow   发布时间: 2010-07-24

回复 joey_chow


    大概看了一下这个RTC驱动,,,它是I2C接口的。
   你说的没有执行probe() ,可能是因为没有注册i2c adapter到内核....在注册adapter时就会注册一个device..
    LZ可以看看i2c bus的匹配规则:
  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,
};

跟踪一下上面红色的回调函数就可以清楚它的匹配规则了....

作者: wmmy2008   发布时间: 2010-07-24

这种驱动问题,LZ可以发到驱动版

作者: wmmy2008   发布时间: 2010-07-24