Nouveau源码分析(一)
-
- 1089 module_init(nouveau_drm_init);
- 1090 module_exit(nouveau_drm_exit);
相信只要看过linux源码的都会知道这意味着什么,Nouveau被加载后第一个执行的函数和Nouveau被卸载前最后一个执行的函数.
显然,我们需要查看nouveau_drm_init
-
- 1062 static int __init
- 1063 nouveau_drm_init(void)
- 1064 {
- 1065 if (nouveau_modeset == -1) {
- 1066 #ifdef CONFIG_VGA_CONSOLE
- 1067 if (vgacon_text_force())
- 1068 nouveau_modeset = 0;
- 1069 #endif
- 1070 }
- 1071
- 1072 if (!nouveau_modeset)
- 1073 return 0;
- 1074
- 1075 nouveau_register_dsm_handler();
- 1076 return drm_pci_init(&driver, &nouveau_drm_pci_driver);
- 1077 }
1065行,nouveau_modset,这是什么东西? 虽然我们完全可以跳过这段代码不看,但还是多了解一下吧.
-
- 67 MODULE_PARM_DESC(modeset, "enable driver (default: auto, "
- 68 "0 = disabled, 1 = enabled, 2 = headless)");
- 69 int nouveau_modeset = -1;
- 70 module_param_named(modeset, nouveau_modeset, int, 0400);
嗯,一个指示Nouveau禁用或启用的变量,如果被设置成0[disabled]就会直接在1073行返回
1075行,nouveau_register_dsm_handler()
这个函数貌似是关于电源管理以及双显卡切换的,暂且忽略,以后再来看
1076行,最关键的一行代码出现了,通过drm_pci_init接口注册Nouveau驱动,所有的东西全都是由传入的两个结构体中的函数指针引发的
先看nouveau_drm_pci_driver吧:
-
- 1017 static struct pci_driver
- 1018 nouveau_drm_pci_driver = {
- 1019 .name = "nouveau",
- 1020 .id_table = nouveau_drm_pci_table,
- 1021 .probe = nouveau_drm_probe,
- 1022 .remove = nouveau_drm_remove,
- 1023 .driver.pm = &nouveau_pm_ops,
- 1024 };
这个的主要功能就是匹配pci中的Nvidia设备,先匹配id_table,符合id_table中的规则的调用probe,成功则Nouveau正式管理了这个Nvidia设备.
当然这里还有移除时调用的remove函数,和电源管理的pm部分.
-
- 893 static struct pci_device_id
- 894 nouveau_drm_pci_table[] = {
- 895 {
- 896 PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID),
- 897 .class = PCI_BASE_CLASS_DISPLAY << 16,
- 898 .class_mask = 0xff << 16,
- 899 },
- 900 {
- 901 PCI_DEVICE(PCI_VENDOR_ID_NVIDIA_SGS, PCI_ANY_ID),
- 902 .class = PCI_BASE_CLASS_DISPLAY << 16,
- 903 .class_mask = 0xff << 16,
- 904 },
- 905 {}
- 906 };
pci设备的匹配规则,相信大部分人都能看懂.
然后我们来看driver:
-
- 833 static struct drm_driver
- 834 driver = {
- 835 .driver_features =
- 836 DRIVER_USE_AGP |
- 837 DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_RENDER,
- 838
- 839 .load = nouveau_drm_load,
- 840 .unload = nouveau_drm_unload,
- 841 .open = nouveau_drm_open,
- 842 .preclose = nouveau_drm_preclose,
- 843 .postclose = nouveau_drm_postclose,
- 844 .lastclose = nouveau_vga_lastclose,
- 845
- 846 #if defined(CONFIG_DEBUG_FS)
- 847 .debugfs_init = nouveau_debugfs_init,
- 848 .debugfs_cleanup = nouveau_debugfs_takedown,
- 849 #endif
- 850
- 851 .get_vblank_counter = drm_vblank_count,
- 852 .enable_vblank = nouveau_display_vblank_enable,
- 853 .disable_vblank = nouveau_display_vblank_disable,
- 854 .get_scanout_position = nouveau_display_scanoutpos,
- 855 .get_vblank_timestamp = nouveau_display_vblstamp,
- 856
- 857 .ioctls = nouveau_ioctls,
- 858 .num_ioctls = ARRAY_SIZE(nouveau_ioctls),
- 859 .fops = &nouveau_driver_fops,
- 860
- 861 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
- 862 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
- 863 .gem_prime_export = drm_gem_prime_export,
- 864 .gem_prime_import = drm_gem_prime_import,
- 865 .gem_prime_pin = nouveau_gem_prime_pin,
- 866 .gem_prime_res_obj = nouveau_gem_prime_res_obj,
- 867 .gem_prime_unpin = nouveau_gem_prime_unpin,
- 868 .gem_prime_get_sg_table = nouveau_gem_prime_get_sg_table,
- 869 .gem_prime_import_sg_table = nouveau_gem_prime_import_sg_table,
- 870 .gem_prime_vmap = nouveau_gem_prime_vmap,
- 871 .gem_prime_vunmap = nouveau_gem_prime_vunmap,
- 872
- 873 .gem_free_object = nouveau_gem_object_del,
- 874 .gem_open_object = nouveau_gem_object_open,
- 875 .gem_close_object = nouveau_gem_object_close,
- 876
- 877 .dumb_create = nouveau_display_dumb_create,
- 878 .dumb_map_offset = nouveau_display_dumb_map_offset,
- 879 .dumb_destroy = drm_gem_dumb_destroy,
- 880
- 881 .name = DRIVER_NAME,
- 882 .desc = DRIVER_DESC,
- 883 #ifdef GIT_REVISION
- 884 .date = GIT_REVISION,
- 885 #else
- 886 .date = DRIVER_DATE,
- 887 #endif
- 888 .major = DRIVER_MAJOR,
- 889 .minor = DRIVER_MINOR,
- 890 .patchlevel = DRIVER_PATCHLEVEL,
- 891 };
看起来相当复杂,这就是Nouveau和外界的接口,注意一下初始化部分: ".load = nouveau_drm_load,"
至此nouveau_drm_init完成了它的任务------注册Nouveau驱动,下面就进入到了Nouveau针对具体Nvidia设备的初始化阶段------nouveau_drm_probe和nouveau_drm_load.