分类:
2008-06-22 10:29:26
eth0......等等设备,我们通过学习udev可以知道/dev/下的设备是可以让我们在用户空间建立的,那么这个
那么这个KERNEL在内核初始化时已经确立,也就是说udev从sysfs中得到的信息。那么这个名字究竟是从
何而来的了呢?这也是此篇文章要讨论的。
先略过sysfs,虽然udev是从sysfs直接得到的关于设备的所有信息,但是sysfs从哪里得到的了呢?
所以sysfs暂时不提,这是个很复杂的领域,如果你tree /sys看到的链接数,将使你头晕!你从来也不
曾想过,是谁这么变态能做这么多的链接?呵呵,这要用到kobject数据结构(可理解为面向对象中的类)
这个东西,请参考作者在2005年作的报告:Patrick Mochel:The 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.c、tg3.h、/lib/modules/`uname -r`/modules.pcimap顺藤摸瓜来示范一次:
1、struct 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的一整个过程。