Chinaunix首页 | 论坛 | 博客
  • 博客访问: 506000
  • 博文数量: 176
  • 博客积分: 4045
  • 博客等级: 上校
  • 技术积分: 2491
  • 用 户 组: 普通用户
  • 注册时间: 2008-03-19 11:23
文章分类

全部博文(176)

文章存档

2011年(7)

2009年(12)

2008年(157)

我的朋友

分类:

2008-06-22 10:29:26

在设置udev的规则的时候从其语法中我们得知有一项KERNEL="",此处是我们通常见到的如sda,hda

eth0......等等设备,我们通过学习udev可以知道/dev/下的设备是可以让我们在用户空间建立的,那么这个

那么这个KERNEL在内核初始化时已经确立,也就是说udev从sysfs中得到的信息。那么这个名字究竟是从

何而来的了呢?这也是此篇文章要讨论的。

先略过sysfs,虽然udev是从sysfs直接得到的关于设备的所有信息,但是sysfs从哪里得到的了呢?

所以sysfs暂时不提,这是个很复杂的领域,如果你tree /sys看到的链接数,将使你头晕!你从来也不

曾想过,是谁这么变态能做这么多的链接?呵呵,这要用到kobject数据结构(可理解为面向对象中的类)

这个东西,请参考作者在2005年作的报告:Patrick MochelThe sysfs Filesystem。当然有可

能的话还是看看其源码:linux/kobject.h,fs/sysfs/*......


继续回到题目:

kernel在初始化时会扫描所有硬件,内核根据某些条件,加载其对应的驱动,或是直接编译在内核中的

(也就说当系统运行是直接加载到RAM中的);或是通过用户空间的modprobe加载模块。在设备驱动

程序在内核中注册后,相应的设备文件才开始建立,sysfs/proc可见,用户才可以操作。

那么我们就讨论下这个注册的过程。

我以我们的经典的loop.c为例分析一番,其它的也类似。

cd /usr/src/linux-source/driver/block/

查看loop.c,

定义loop的数据结构

static struct loop_device *loop_alloc(int i)

{

......

disk->queue             = lo->lo_queue;
        sprintf(disk->disk_name, "loop%d", i);
        return lo;

.......

}

驱动程序向内核注册的函数:

static int __init loop_init(void)
{

.....

        if (register_blkdev(LOOP_MAJOR, "loop"))
                return -EIO;
......

 blk_register_region(MKDEV(LOOP_MAJOR, 0), range,
                                  THIS_MODULE, loop_probe, NULL, NULL);

        printk(KERN_INFO "loop: module loaded\n");
        return 0;
.......


}

看到LOOP_MAJOR,我们再去../include/linux/major.h里找到如下一句:

(注:内核中还有一个重要的文件include/linux/major.h,其文档是如此描述的:

This file has definitions for major device numbers. For the device number

assignments, see Documentation/devices.txt.)

#define LOOP_MAJOR              7


这就是如题所示的答案,也就说在/dev/下看到的,或是 /proc/device,或是/sys/block下的设备都是从这里开始的。

详细情形,请参阅:Linux设备驱动程序(第三版)关于设备注册的那节。

以下是我查看其它设备的实践过程。然后谈到hotplug的设备发现、寻找模块、加载模块的过程。

下面我们看几个设备驱动的例子,因为linux将设备文件区分为三类,network,block,char。我们分别对待。


driver/net/tg3.c


tg3:(其实理解网络设备驱动做好的入门代码是loopback.c,就是linux中用指令ifconfig的那个lo设备

#define DRV_MODULE_NAME "tg3"

.......略去大部分

static struct pci_driver tg3_driver = {

.name = DRV_MODULE_NAME,

.id_table = tg3_pci_tbl,

.probe = tg3_init_one,

.remove = __devexit_p(tg3_remove_one),

.suspend = tg3_suspend,

.resume = tg3_resume

};

driver/block/cciss.c


cciss:

sprintf(disk->disk_name, "cciss/c%dd%d", i, j);

......(忽略很多)

static struct pci_driver cciss_pci_driver = {

.name = "cciss",

.probe = cciss_init_one,

.remove = __devexit_p(cciss_remove_one),

.id_table = cciss_pci_device_id, /* id_table */

};

driver/char/tty.c


struct console vt_console_driver = {

.name = "tty",

.write = vt_console_print,

.device = vt_console_device,

.unblank = unblank_screen,

.flags = CON_PRINTBUFFER,

.index = -1,

};

....... 略去

console_driver->devfs_name = "vc/";//使用devfs时使用的驱动名称(archlinux

console_driver->name = "tty"; //devfs使用的名称,常见的终端


根据以上引用的代码,有心人也看出来了,每个驱动程序的数据结构定义的驱动名称,id_table

或设备名称.他们之间是如何关联起来的呢?


在此,还需要说明一些个文件,/lib/modules/`uname -r`/module.*map文件。下面我以

tg3.ctg3.h/lib/modules/`uname -r`/modules.pcimap顺藤摸瓜来示范一次:

1struct pci_dirver tg3_driver定义的.id_table = tg3_pci_tbl结构定义了所有tg3设备

ID,可查看static struct pci_device_id tg3_pci_tbl[] = ...

{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5720,

PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },

.....

2、我们再到tg3.h中,找到 PCI_DEVICE_ID_TIGON3_5720所对应的实际16进制数:

#if !defined(PCI_DEVICE_ID_TIGON3_5720)

#define PCI_DEVICE_ID_TIGON3_5720 0x1658

#endif

3、然后用1658/lib/modules/`uname -r`/modules.pcimap中查找

# pci module vendor device subvendor subdevice class class_mask driver_data

......

bcm5700 0x000014e4 0x00001658 0xffffffff 0xffffffff 0x00000000 0x00000000 0x0

......

tg3 0x000014e4 0x00001658 0xffffffff 0xffffffff 0x00000000 0x00000000 0x0


当然,在系统运行是这是一个逆向的过程,将上面的步骤倒过来,就是kernel从如何识别硬件、匹配名称和

模块、到正确加载为用户空间提供可使用的一切条件。这就是hotplug的一整个过程


阅读(1642) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~