在那茫茫人海中,我找到了这两行,
1886 module_init(init_sd);
1887 module_exit(exit_sd);
不要问我它们来自哪里,咱们整个故事就是围绕着drivers/sd.c这么一个文件展开,所以除非特别声明的之外,都是来自这个文件.
1831 /**
1832 * init_sd - entry point for this driver (both when built in or when
1833 * a module).
1834 *
1835 * Note: this function registers this driver with the scsi mid-level.
1836 **/
1837 static int __init init_sd(void)
1838 {
1839 int majors = 0, i, err;
1840
1841 SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point/n"));
1842
1843 for (i = 0; i < SD_MAJORS; i++)
1844 if (register_blkdev(sd_major(i), "sd") == 0)
1845 majors++;
1846
1847 if (!majors)
1848 return -ENODEV;
1849
1850 err = class_register(&sd_disk_class);
1851 if (err)
1852 goto err_out;
1853
1854 err = scsi_register_driver(&sd_template.gendrv);
1855 if (err)
1856 goto err_out_class;
1857
1858 return 0;
1859
1860 err_out_class:
1861 class_unregister(&sd_disk_class);
1862 err_out:
1863 for (i = 0; i < SD_MAJORS; i++)
1864 unregister_blkdev(sd_major(i), "sd");
1865 return err;
1866 }
1867
1868 /**
1869 * exit_sd - exit point for this driver (when it is a module).
1870 *
1871 * Note: this function unregisters this driver from the scsi mid-level.
1872 **/
1873 static void __exit exit_sd(void)
1874 {
1875 int i;
1876
1877 SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver/n"));
1878
1879 scsi_unregister_driver(&sd_template.gendrv);
1880 class_unregister(&sd_disk_class);
1881
1882 for (i = 0; i < SD_MAJORS; i++)
1883 unregister_blkdev(sd_major(i), "sd");
1884 }
没什么特别的,一串的注册注销函数.
首先,register_blkdev,注册一个块设备.这个函数也算是骨灰级的了,N年前就有这个函数了.那时候我曾天真的以为这个世界上只有三种设备,块设备,字符设备,网络设备.后来发现世界并非那么简单,生活也并非那么简单,尽管,生,很简单,活,很简单,但生活却不简单.
我们来看一下这个函数的效果,加载sd_mod之前,
localhost:~ # cat /proc/devices
Character devices:
1 mem
2 pty
3 ttyp
4 /dev/vc/0
4 tty
4 ttyS
5 /dev/tty
5 /dev/console
5 /dev/ptmx
7 vcs
10 misc
13 input
29 fb
128 ptm
136 pts
Block devices:
1 ramdisk
3 ide0
7 loop
9 md
253 device-mapper
254 mdp
而通过下面两条命令加载了scsi_mod和sd_mod之后,
localhost:~ # modprobe scsi_mod
localhost:~ # modprobe sd_mod
localhost:~ # cat /proc/devices
Character devices:
1 mem
2 pty
3 ttyp
4 /dev/vc/0
4 tty
4 ttyS
5 /dev/tty
5 /dev/console
5 /dev/ptmx
7 vcs
10 misc
13 input
29 fb
128 ptm
136 pts
Block devices:
1 ramdisk
3 ide0
7 loop
8 sd
9 md
65 sd
66 sd
67 sd
68 sd
69 sd
70 sd
71 sd
128 sd
129 sd
130 sd
131 sd
132 sd
133 sd
134 sd
135 sd
253 device-mapper
254 mdp
可以看到,多了一个叫做sd的家伙.
这里出现的宏SD_MAJORS实际上被定义为16.所以经过16次循环之后,我们看到这里叫sd的有16个.
至于你说这些号码是怎么来的,就像八国联军在中国瓜分势力范围一样,每个国家分一片地,而Linux中所有的主设备号也是被各种各样的设备所瓜分.其中,8,65-71,136-143这么个16个号码就被scsi disk所霸占了.sd_major()函数的返回值就是这16个数字.每个主设备号可以带256个次设备号.
1850行, class_register,这行的效果就是,
localhost:~ # ls /sys/class/
backlight dma graphics input mem misc net pci_bus scsi_device scsi_disk scsi_host spi_master tty vc vtconsole
看到其中那项scsi_disk了么?这就是class_register这句干的好事.
而1854行,scsi_register_driver则是赤裸裸的注册一个scsi设备驱动.伟大的设备模型告诉我们对于每个设备驱动,有一个与之对应的struct device_driver结构体,而为了体现各类设备驱动自身的特点,各个子系统可以定义自己的结构体,然后把struct device_driver包含进来如C++中基类和扩展类一样.对于scsi子系统,这个基类就是struct scsi_driver,这个结构体本身定义于include/scsi/scsi_driver.h:
10 struct scsi_driver {
11 struct module *owner;
12 struct device_driver gendrv;
13
14 int (*init_command)(struct scsi_cmnd *);
15 void (*rescan)(struct device *);
16 int (*issue_flush)(struct device *, sector_t *);
17 int (*prepare_flush)(struct request_queue *, struct request *);
18 };
而咱们也自然定义了一个scsi_driver的结构体实例.它的名字叫做sd_template.
232 static struct scsi_driver sd_template = {
233 .owner = THIS_MODULE,
234 .gendrv = {
235 .name = "sd",
236 .probe = sd_probe,
237 .remove = sd_remove,
238 .suspend = sd_suspend,
239 .resume = sd_resume,
240 .shutdown = sd_shutdown,
241 },
242 .rescan = sd_rescan,
243 .init_command = sd_init_command,
244 .issue_flush = sd_issue_flush,
245 };
这其中,gendrv就是struct device_driver的结构体变量.咱们这么一注册,其直观效果就是:
localhost:~ # ls /sys/bus/scsi/drivers/
sd
而与以上三个函数相反的就是exit_sd()中的另外仨函数,scsi_unregister_driver,class_unregister,unregister_blkdev.这点我想不用我多说,阜成门外华联商厦门口卖盗版光盘那几位哥们儿也能明白怎么回事.
Okay了,这个初始化就这么简单,就这么结束了.相比uhci-hcd的那个初始化,这里的确简单的不得了.实话实说,SCSI硬盘驱动确实是挺简单的.下一步我们就从sd_probe函数看起,某种意义来说,读sd_mod的代码就算是对scsi子系统的入门.