一、X系統基本概念:
XServer 是一個集中信息處理系統,它負責從 XClient 進程接收繪圖指令(原始數據),並將本地的輸入設備產生的數據轉換爲消息發送到 XClient 進程。這個過程看似簡單,但實際上流程比較複雜,極端情況下,當 XServer 獲得輸入設備產生的數據後,它先要發送給窗口管理器(窗口管理器很可能還在另一臺主機上,需要通過網絡傳輸),再接收窗口管理器發出的請求,再將輸入數據發送到真正的 XClient(又有可能通過網絡),XClient 處理完消息後向 XServer 發送繪圖請求(又有可能是網絡),再由 XServer 執行繪圖渲染工作,這其中如果使用到的字體不在本地,還要通過訪問字體服務器(又有可能是網絡)獲取字體數據後再行渲染。而花哨到極點的 compize 之類的聚合窗口管理器因爲需要在多個XClient產生的窗口上進行復合渲染,造成XClient遞交的繪圖指令被多次重複運行,更是讓XServer在效率上雪上加霜。
GTK—–>windowmanager—>xserver—>驅動適配層庫——>kernel
二、體系結構:
xserver目錄下包含多個X服務器的源碼,包括Xorg, Xnest和基於kdrive的多個服務器。
X服務器的代碼分爲四個部分組織:
設備無關層(DIX), 這一部分的代碼被所有Xserver的實現共享。
操作系統層(OS), 這一部分的代碼隨着操作系統的不同而不同,但是被這個操作系統上的圖形設備共享。
設備相關層(DDX), 這一部分隨着操作系統和圖形設備的組合的不同而不同。
擴展接口,這一部分爲用統一的方式向X server加入新的功能提供支持。
服務器相關部分的代碼放置在hw/目錄下。其中,hw/xfree86/目錄下包含了Xorg的代碼; hw/kdrive下 保 括 了 基 於kdrive的 多 個 服 務 器
三、main函數進入一個大循環,這個循環的第一步是完成初始化工作,第二部是進入Dispatch() 事
件處理循環,第三步是釋放所有的資源。這個大循環的退出即意味着main函數的退出。下面我們
一步步的分析初始化過程。
本人用的xserver版本是xserver_xorg-server-1.15.1,
跟蹤源碼從main函數開始吧,
路徑在 dix/main.c
131 int main(int argc, char *argv[], char *envp[])
132 #endif
133 {
134 int i;
135 HWEventQueueType alwaysCheckForInput[2];
136
137 display = "0";
138
139 InitRegions();
140
141 pixman_disable_out_of_bounds_workaround();
142
143 CheckUserParameters(argc, argv, envp);
144
145 CheckUserAuthorization();
146
147 InitConnectionLimits();
148
149 ProcessCommandLine(argc, argv);
main函數前面主要是一些初始化工作
while(1)
{
........
205 InitOutput(&screenInfo, argc, argv);
..........
}
接下來進入到了一個while循環,咱們找的解析xorg.xonf文件在initoutput裏做的,跟進去路徑在hw/xfree86/common/xf86Init.c
...............
361 /* Read and parse the config file */
362 if (!xf86DoConfigure && !xf86DoShowOptions) {
363 switch (xf86HandleConfigFile(FALSE)) {
364 case CONFIG_OK:
365 break;
..........
繼續看xf86HandleConfigFile(FALSE)函數實現
路徑hw/xfree86/common/xf86Config.c +2383
2379 xf86initConfigFiles();
2380 sysdirname = xf86openConfigDirFiles(SYS_CONFIGDIRPATH, NULL,
2381 PROJECTROOT);
2382 dirname = xf86openConfigDirFiles(dirsearch, xf86ConfigDir, PROJECTROOT);
2383 filename = xf86openConfigFile(filesearch, xf86ConfigFile, PROJECTROOT);
跟進函數xf86openConfigFile()
906 #ifndef DEFAULT_CONF_PATH
907 #define DEFAULT_CONF_PATH "/etc/X11/%S," \ "%P/etc/X11/%S," \ "/etc/X11/%G," \ "%P/etc/X11/%G," \ "/etc/X11/%X-%M," \ "/etc/X11/%X," \ "/etc/%X," \ "%P/etc/X11/%X.%H," \ "%P/etc/X11/%X-%M," \ "%P/etc/X11/%X," \ "%P/lib/X11/%X.%H," \ "%P/lib/X11/%X-%M," \ "%P/lib/X11/%X"
920 #endif
921
922 const char *
923 xf86openConfigFile(const char *path, const char *cmdline, const char *projroot)
924 {
925 if (!path || !path[0])
926 path = DEFAULT_CONF_PATH;
927 if (!projroot || !projroot[0])
928 projroot = PROJECTROOT;
929
930 /* Search for a config file */
931 configPath = OpenConfigFile(path, cmdline, projroot, XCONFIGFILE);
932 return configPath;
933 }
在這可以看到xorg.conf默認在/etc的一些路徑下,看configPath = OpenConfigFile(path, cmdline, projroot, XCONFIGFILE);的實現
路徑在hw/xfree86/parser/scan.c
730 * Given some searching parameters, locate and open the xorg config file.
731 */
732 static char *
733 OpenConfigFile(const char *path, const char *cmdline, const char *projroot,
734 const char *confname)
735 {
736 char *filepath = NULL;
737 char *pathcopy;
738 const char *template;
739 int cmdlineUsed = 0;
740 FILE *file = NULL;
741
742 pathcopy = strdup(path);
743 for (template = strtok(pathcopy, ","); template && !file;
744 template = strtok(NULL, ",")) {
745 filepath = DoSubstitution(template, cmdline, projroot,
746 &cmdlineUsed, NULL, confname);
747 if (!filepath)
748 continue;
749 if (cmdline && !cmdlineUsed) {
750 free(filepath);
751 filepath = NULL;
752 continue;
753 }
754 file = fopen(filepath, "r");
755 if (!file) {
756 free(filepath);
757 filepath = NULL;
758 }
到此結束,這個流程都是在判斷xorg文件是否存在。
四、接下來看代碼分析如何解析xorg.conf文件的
路徑在hw/xfree86/common/xf86Init.c
393 if (xf86DoConfigure)
394 DoConfigure();
跟進 DoConfigure()在hw/xfree86/common/xf86Configure.c
635 if (xf86writeConfigFile(filename, xf86config) == 0) {
636 xf86Msg(X_ERROR, "Unable to write config file: \"%s\": %s\n",
637 filename, strerror(errno));
638 goto bail;
639 }
跟進xf86writeConfigFile()路徑在hw/xfree86/parser/write.c
212 return doWriteConfigFile(filename, cptr);
繼續跟
114 xf86printVendorSection (cf, cptr->conf_vendor_lst);
115
116 xf86printServerFlagsSection (cf, cptr->conf_flags);
117
118 xf86printInputSection (cf, cptr->conf_input_lst);
119
120 xf86printInputClassSection (cf, cptr->conf_inputclass_lst);
121
122 xf86printVideoAdaptorSection (cf, cptr->conf_videoadaptor_lst);
123
124 xf86printModesSection (cf, cptr->conf_modes_lst);
125
126 xf86printMonitorSection (cf, cptr->conf_monitor_lst);
127
128 xf86printDeviceSection (cf, cptr->conf_device_lst);
129
130 xf86printScreenSection (cf, cptr->conf_screen_lst);
131
132 xf86printDRISection (cf, cptr->conf_dri);
133
134 xf86printExtensionsSection (cf, cptr->conf_extensions);
到這裏我們可以看到不同功能的解析函數
進入xf86printInputSection()
140 while (ptr)
141 {
142 fprintf (cf, "Section \"InputDevice\"\n");
143 if (ptr->inp_comment)
144 fprintf (cf, "%s", ptr->inp_comment);
145 if (ptr->inp_identifier)
146 fprintf (cf, "\tIdentifier \"%s\"\n", ptr->inp_identifier);
147 if (ptr->inp_driver)
148 fprintf (cf, "\tDriver \"%s\"\n", ptr->inp_driver);
149 xf86printOptionList(cf, ptr->inp_option_lst, 1);
150 fprintf (cf, "EndSection\n\n");
151 ptr = ptr->list.next;
152 }
在這我們終於明白爲什麼xorg.conf文件爲什麼按
Section \”InputDevice
Identifier
Driver
EndSection 格式寫了
五、如何找到驅動適配層庫
代碼路徑hw/xfree86/common/xf86Init.c
407 /* Load all modules specified explicitly in the config file */
408 if ((modulelist = xf86ModulelistFromConfig(&optionlist))) {
409 xf86LoadModules(modulelist, optionlist);
410 free(modulelist);
411 free(optionlist);
412 }
跟進 xf86LoadModules(modulelist, optionlist);函數
1430 if (!LoadModule(name, NULL, NULL, NULL, opt, NULL, &errmaj, &errmin)) {
1431 LoaderErrorMsg(NULL, name, errmaj, errmin);
1432 failed = TRUE;
跟進函數LoadModule()路徑在hw/xfree86/loader/loadmod.c
1058 return doLoadModule(module, path, subdirlist, patternlist, options,modreq, errmaj, errmin);
繼續跟 doLoadModule()
892 * if the module name is not a full pathname, we need to
893 * check the elements in the path
894 */
895 if (PathIsAbsolute(module))
896 found = xstrdup(module);
897 path_elem = pathlist;
898 while (!found && *path_elem != NULL) {
899 found = FindModule(m, *path_elem, subdirlist, patterns);
900 path_elem++;
901 /*
跟進FindModule()函數
452 for (s = subdirs; *s; s++) {
453 if ((dirlen = strlen(dirpath) + strlen(*s)) > PATH_MAX)
454 continue;
455 strcpy(buf, dirpath);
456 strcat(buf, *s);
457 if ((name = FindModuleInSubdir(buf, module)))
458 break;
跟進 FindModuleInSubdir()
398 /* the stat with the appended / fails for normal files,
399 and works for sub dirs fine, looks a bit strange in strace
400 but does seem to work */
401 if ((stat(tmpBuf, &stat_buf) == 0) && S_ISDIR(stat_buf.st_mode)) {
402 if ((ret = FindModuleInSubdir(tmpBuf, module)))
403 break;
404 continue;
405 }
406
407 snprintf(tmpBuf, PATH_MAX, "lib%s.so", module);
408 if (strcmp(direntry->d_name, tmpBuf) == 0) {
409 if (asprintf(&ret, "%s%s", dirpath, tmpBuf) == -1)
410 ret = NULL;
411 break;
412 }
413
414 snprintf(tmpBuf, PATH_MAX, "%s_drv.so", module);
415 if (strcmp(direntry->d_name, tmpBuf) == 0) {
416 if (asprintf(&ret, "%s%s", dirpath, tmpBuf) == -1)
417 ret = NULL;
418 break;
419 }
420
421 snprintf(tmpBuf, PATH_MAX, "%s.so", module);
422 if (strcmp(direntry->d_name, tmpBuf) == 0) {
423 if (asprintf(&ret, "%s%s", dirpath, tmpBuf) == -1)
424 ret = NULL;
425 break;
到這裏結束,會發現xserver在啓動時,會根據xorg.xonf去load相應的驅動適配層庫,庫的名字是組合的例如觸屏的庫叫tslib_drv.so