任小强们说房价高涨从现在开始,股评家们说牛市从5000点开始。他们的开始需要我们的钱袋,我的开始只需要一台电脑,最好再有一杯茶,伴着几支小曲儿,不盯着钱总是会比较惬意的。生容易,活容易,生活不容易,因为要盯着钱。
USB core从USB子系统的初始化开始,我们也需要从那里开始,它们在文件drivers/usb/core/usb.c 938subsys_initcall(usb_init); 939module_exit(usb_exit);
我们看到一个subsys_initcall,复旦人甲说它也是一个宏,我们可以把它理解为module_init,只不过因为这部分代码比较核心,开发者们把它看作一个子系统,而不仅仅是一个模块,这也很好理解,usbcore这个模块它代表的不是某一个设备,而是所有usb设备赖以生存的模块,Linux中,像这样一个类别的设备驱动被归结为一个子系统。比如pci子系统,比如scsi子系统,基本上,drivers/目录下面第一层的每个目录都算一个子系统,因为它们代表了一类设备。subsys_initcall(usb_init)的意思就是告诉我们usb_init是我们真正的初始化函数,而usb_exit()将是整个usb子系统的结束时的清理函数,于是我们就从usb_init开始看起。
既然复旦人甲都这么说了,那咱们就从usb_init开始看起吧。至于子系统在内核里具体的描述,牵涉到linux设备模型了,可以去看ldd3,或者更详细的。目前来说,我们只需要知道子系统通常显示在sysfs分层结构中的顶层,比如块设备子系统对应/sys/block,当然也不一定,usb子系统对应的就是/sys/bus/usb。 860 /* 861 * Init 862 */ 863 static int __initusb_init(void) 864 { 865 int retval; 866 if (nousb) { 867pr_info("%s: USB support disabled/n", usbcore_name); 868 return 0; 869 } 870 871 retval = ksuspend_usb_init(); 872 if (retval) 873 goto out; 874 retval = bus_register(&usb_bus_type); 875 if (retval) 876 goto bus_register_failed; 877 retval = usb_host_init(); 878 if (retval) 879 goto host_init_failed; 880 retval = usb_major_init(); 881 if (retval) 882 goto major_init_failed; 883 retval = usb_register(&usbfs_driver); 884 if (retval) 885 goto driver_register_failed; 886 retval = usb_devio_init(); 887 if (retval) 888 goto usb_devio_init_failed; 889 retval = usbfs_init(); 890 if (retval) 891 goto fs_init_failed; 892 retval = usb_hub_init(); 893 if (retval) 894 goto hub_init_failed; 895 retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE); 896 if (!retval) 897 goto out; 898 899usb_hub_cleanup(); 900 hub_init_failed: 901usbfs_cleanup(); 902 fs_init_failed: 903usb_devio_cleanup(); 904 usb_devio_init_failed: 905usb_deregister(&usbfs_driver); 906 driver_register_failed: 907usb_major_cleanup(); 908 major_init_failed: 909usb_host_cleanup(); 910 host_init_failed: 911bus_unregister(&usb_bus_type); 912 bus_register_failed: 913ksuspend_usb_cleanup(); 914out: 915 return retval; 916 }
看到上面定义里的__init标记没,写过驱动的应该不会陌生,它对内核来说就是一种暗示,表明这个函数仅在初始化期间使用,在模块被装载之后,它占用的资源就会释放掉用作它处。它的暗示你懂,可你的暗示,她却不懂或者懂装不懂,多么让人感伤。它在自己短暂的一生中一直从事繁重的工作,吃的是草吐出的是牛奶,留下的是整个USB子系统的繁荣。
受这种精神所感染,我觉得还是有必要为它说的更多些,21世纪多的是任小强,缺的是知恩图报的人。对__init的定义在include/linux/init.h里 43 #define __init__attribute__ ((__section__ (".init.text")))好像这里的疑问要更多,不过与__init相比,这点辛苦算什么,我会在它强大的精神支持下尽量说清楚的。那么__attribute__是什么?Linux内核代码使用了大量的GNU C扩展,以至于GNU C成为能够编译内核的唯一编译器,GNU C的这些扩展对代码优化、目标代码布局、安全检查等方面也提供了很强的支持。而__attribute__就是这些扩展中的一个,它主要被用来声明一些特殊的属性,这些属性主要被用来指示编译器进行特定方面的优化和更仔细的代码检查。GNU C支持十几个属性,section是其中的一个,我们查看gcc的手册可以看到下面的描述
‘section ("section-name")' Normally, the compiler places the code it generates in the `text' section. Sometimes, however, you need additional sections, or you
need certain particular functions to appear in special sections.
The `section' attribute specifies that a function lives in a
particular section. For example, the declaration:
extern void foobar (void) __attribute__ ((section ("bar")));
puts the function ‘foobar' in the ‘bar' section.
Some file formats do not support arbitrary sections so the
‘section' attribute is not available on all platforms. If you
need to map the entire contents of a module to a particular
section, consider using the facilities of the linker instead.