您的位置:首页 > 运维架构 > Linux

linux设备模型,bus,device,driver,实验遇到的问题

2011-11-07 22:03 435 查看
这个问题困扰了我好久,对于内核的不熟悉,一开始是出现了使用空指针的问题,部分错误提示如下

Unable to handle kernel NULL pointer dereference at virtual address 00000000

pgd = c3ab4000

[00000000] *pgd=33b11031, *pte=00000000, *ppte=00000000

Internal error: Oops: 17 [#1]

last sysfs file: /sys/devices/virtual/vc/vcsa4/dev

Modules linked in: usb_driver(+) usb_device usb_bus

CPU: 0 Not tainted (2.6.32.2-FriendlyARM #1)

PC is at strcmp+0x10/0x40

LR is at usb_bus_match+0x2c/0x60 [usb_bus]

后面我几经周转发现是原来match函数中设备名为空,这个我是照着其他人写的博客上面弄的,只知道照着弄,其他的就不清楚了,后面上网搜的下面这篇文章,本想自己总结一下,不过发现他们总结的很好了,而且我完全保留原作者的文章,没有改动。

原文地址 http://hi.baidu.com/tracyangrad/blog/item/88437f5b188d74302934f042.html

实验环境:

linux2.6.32.2

在做bus驱动实验的时候,出现了一个问题:

提示bus_id找不到。于是到内核源代码找了一番,果然没有看见。直接到device结构体中看,找到的最像的也就

const char *init_name; /* initial name of the device */

想到这个也可以作为标识,并且BUS_ID_SIZE也找不到,于是将strncpy(my_dev.init_name, "my_dev", BUS_ID_SIZE);注释掉,直接在mydev中添

加.init_name="my_dev"。

但是在注册驱动时又出现了段错误,根据console打印,知道在strncmp时,也就是总线在比较驱动和设备的名字的时候出问题了。

于是在比较函数里加入

printk("dev->init_name:%s\tdriver->name:%s\n", dev->init_name, driver->name);

想看看到底是怎么比较的。结果console上打印出来的是

dev->init_name:<NULL> driver->name:my_dev (与下面亮点关联)

Unable to handle kernel NULL pointer dereference at virtual address 00000000

dev->init_name不存在?

于是baidu了一下,发现了了下面网友的那段,我用对了init_name,却没直接在内核里搜到dev_name(dev),于是又在内核搜索一番。可以找到下面一段总线上的比较函数:

static int bttv_sub_bus_match(struct device *dev, struct device_driver *drv)

{

struct bttv_sub_driver *sub = to_bttv_sub_drv(drv);

int len = strlen(sub->wanted);

if (0 == strncmp(dev_name(dev), sub->wanted, len))

return 1;

return 0;

}

它用的是dev_name(dev)而不是dev->init_name。还是在match函数里加入输出语句,打印如下:

dev_name(dev):my_dev driver->name:my_dev

成功了!

那我们深究下,dev_name()是什么东东呢?

static inline const char *dev_name(const struct device *dev)

{

return kobject_name(&dev->kobj);

}

├───static inline const char *kobject_name(const struct kobject *kobj)

{

return kobj->name;

}

其实就是kobj->name;

dev_name(dev)怎么和dev->kobj-name联系上的呢?找遍“可见”代码找不到,猜测很可能是在device_register里面。

从源码里顺蔓摸瓜:

└─device_register

└─device_add

└─if (dev->init_name)

{

dev_set_name(dev, "%s", dev->init_name);

dev->init_name = NULL; (亮点!)

}

dev_set_name

└─kobject_set_name_vargs (看到希望了!)

└─kobj->name= kvasprintf(GFP_KERNEL, fmt, vargs);(找到了,这个就是的了!)

找到了!就是在注册设备的时候将init_name成员赋给了kobj->name,发现那个"亮点"没,不是说说写得有多漂亮(也不是说写得不漂亮,纠结了。。),“亮

点”的意思是发现了新大陆那种感觉,越说越远。。看到前面我为了查错误从控制台打出来的信息,dev->init_name:<NULL> driver->name:my_dev中,dev-

>init_name等于NULL就是在这个dev->init_name = NULL;“亮点”的地方被置空了。这也是为什么用strncmp比较会出错的原因。

要感谢下面这个网友,才想到要到内核去搜一下dev_name。内核版本号不同,必然有一些改动,当我们发现不同后,要善于从中去找到不同,找到解决问题的方

法。

以下是转载自

网友ying_seven的博客(看到其也是转载的,但是并没有注明来处)

--------------------------------------------------------------------------------------------------------------------------

按照国嵌的代码(LDD那本书上的代码也一样):

struct device my_bus = {

.bus_id = "my_bus0",

.release = my_bus_release,

};

static int my_match(struct device *dev, struct device_driver *driver)

{

return !strncmp(dev->bus_id, driver->name, strlen(driver->name));

}

编译时,提示 struct device 中没有bus_id 这样的错误。打开/lib/modules/2.6.35-28-generic/build/include/linux/device.h

找到struct device 的定义,里面没有bus_id,但有:

const char *init_name; /* initial name of the device */ 这句。

可见,要把上面结构中的.bus_id = "my_bus0", 改为 .init_name = "my_bus0",

同时上网搜到,return !strncmp(dev->bus_id, driver->name, strlen(driver->name));这句也要改成:

return !strncmp(dev_name(dev), driver->name, strlen(driver->name));

这样编译即可成功!

另注:

如果要设置设备的名字,也不再使用strncpy(my_dev.bus_id, "my_dev", BUS_ID_SIZE); 而改用:

dev_set_name(&dev, "name");

--------------------------------------------------------------------------------------------------------------------------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: