Nouveau源码分析(一):从module_init开始
2014-11-01 17:00
274 查看
Nouveau源码分析(一)
// /drivers/gpu/drm/nouveau/nouveau_drm.c 1089 module_init(nouveau_drm_init); 1090 module_exit(nouveau_drm_exit);
相信只要看过linux源码的都会知道这意味着什么,Nouveau被加载后第一个执行的函数和Nouveau被卸载前最后一个执行的函数.
显然,我们需要查看nouveau_drm_init
// /drivers/gpu/drm/nouveau/nouveau_drm.c 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,这是什么东西? 虽然我们完全可以跳过这段代码不看,但还是多了解一下吧.
// /drivers/gpu/drm/nouveau/nouveau_drm.c 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吧:
// /drivers/gpu/drm/nouveau/nouveau_drm.c 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部分.
// /drivers/gpu/drm/nouveau/nouveau_drm.c 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:
// /drivers/gpu/drm/nouveau/nouveau_drm.c 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.
相关文章推荐
- Nouveau源码分析(一):从module_init开始
- .NET / Rotor源码分析5 - 开始使用WinDbg+SOS调试,sscoree.dll,加载SOS并设置JIT断点
- .NET / Rotor源码分析5 - 开始使用WinDbg+SOS调试,sscoree.dll,加载SOS并设置JIT断点
- Asp.net MVC源码分析--UrlRoutingModule与Service location的亲密接触
- 最新版ffmpeg源码分析三:transcode_init()函数
- 最新版ffmpeg源码分析三:transcode_init()函数
- 最新版ffmpeg源码分析三:transcode_init()函数
- .NET / Rotor源码分析5 - 开始使用WinDbg+SOS调试,sscoree.dll,加载SOS并设置JIT断点
- s3c6410uboot源码分析之cup_init.S(一)
- sys_init_module & sys_delete_module 简要分析
- u-boot源码----lowlevel_init.S分析
- .NET / Rotor源码分析5 - 开始使用WinDbg+SOS调试,sscoree.dll,加载SOS并设置JIT断点
- jQuery1.3.2 源码学习-3 init 函数分析 - 1
- .NET / Rotor源码分析5 - 开始使用WinDbg+SOS调试,sscoree.dll,加载SOS并设置JIT断点
- ArgoUML源码分析-新手开始
- .NET / Rotor源码分析5 - 开始使用WinDbg+SOS调试,sscoree.dll,加载SOS并设置JIT断点
- ECSHOP 源码分析(includes/init.php)
- jQuery 源码剖析-3 init 函数分析
- 最新版ffmpeg源码分析三:transcode_init()函数
- 最新版ffmpeg源码分析三:transcode_init()函数