一、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