xorg和linux input system初探
时间:2009-05-06 来源:hylpro
2009.4.14 在 /proc内有进程打开的文件信息, 比如简单看看Xorg打开了什么文件, 可以这样: $ps -A | grep Xorg 6245 tty7 00:56:59 Xorg sudo ls /proc/6245/fd -l [sudo] password for yhe: total 0 l-wx------ 1 root root 64 2009-04-14 14:10 0 -> /var/log/Xorg.0.log lrwx------ 1 root root 64 2009-04-14 14:10 1 -> socket:[16061] lrwx------ 1 root root 64 2009-04-14 14:10 10 -> /dev/nvidia0 lrwx------ 1 root root 64 2009-04-14 14:10 11 -> /dev/nvidia0 lrwx------ 1 root root 64 2009-04-14 14:10 12 -> /dev/nvidia0 lrwx------ 1 root root 64 2009-04-14 14:10 13 -> socket:[16387] lrwx------ 1 root root 64 2009-04-14 14:10 14 -> /dev/nvidiactl lrwx------ 1 root root 64 2009-04-14 14:10 15 -> /dev/nvidia0 lr-x------ 1 root root 64 2009-04-14 14:10 16 -> /proc/acpi/video/VID1/LCD/state lr-x------ 1 root root 64 2009-04-14 14:10 17 -> /proc/acpi/video/VID1/LCD/info lr-x------ 1 root root 64 2009-04-14 14:10 18 -> /proc/acpi/video/VID1/CRT/state lr-x------ 1 root root 64 2009-04-14 14:10 19 -> /proc/acpi/video/VID1/CRT/info l-wx------ 1 root root 64 2009-04-14 14:10 2 -> /var/log/gdm/:0.log lr-x------ 1 root root 64 2009-04-14 14:10 20 -> /proc/acpi/video/VID1/TV/state lr-x------ 1 root root 64 2009-04-14 14:10 21 -> /proc/acpi/video/VID1/TV/info lr-x------ 1 root root 64 2009-04-14 14:10 22 -> /proc/acpi/video/VID/DVI/state lr-x------ 1 root root 64 2009-04-14 14:10 23 -> /proc/acpi/video/VID/DVI/info lr-x------ 1 root root 64 2009-04-14 14:10 24 -> /proc/acpi/video/VID/LCD/state lr-x------ 1 root root 64 2009-04-14 14:10 25 -> /proc/acpi/video/VID/LCD/info lr-x------ 1 root root 64 2009-04-14 14:10 26 -> /proc/acpi/video/VID/CRT/state lr-x------ 1 root root 64 2009-04-14 14:10 27 -> /proc/acpi/video/VID/CRT/info lr-x------ 1 root root 64 2009-04-14 14:10 28 -> /proc/acpi/video/VID/TV/state lr-x------ 1 root root 64 2009-04-14 14:10 29 -> /proc/acpi/video/VID/TV/info lrwx------ 1 root root 64 2009-04-14 14:10 3 -> socket:[16082] lrwx------ 1 root root 64 2009-04-14 14:10 30 -> /dev/nvidia0 lrwx------ 1 root root 64 2009-04-14 14:10 31 -> /dev/nvidia0 lrwx------ 1 root root 64 2009-04-14 14:10 32 -> /dev/psaux lrwx------ 1 root root 64 2009-04-14 14:10 33 -> /dev/nvidiactl lrwx------ 1 root root 64 2009-04-14 14:10 34 -> /dev/nvidia0 lrwx------ 1 root root 64 2009-04-14 14:10 35 -> /dev/nvidia0 lrwx------ 1 root root 64 2009-04-14 14:10 36 -> socket:[16545] lrwx------ 1 root root 64 2009-04-14 14:10 37 -> socket:[16547] lrwx------ 1 root root 64 2009-04-14 14:10 38 -> socket:[17674] lrwx------ 1 root root 64 2009-04-14 14:10 39 -> socket:[17679] lrwx------ 1 root root 64 2009-04-14 14:10 4 -> /dev/tty7 ..... lrwx------ 1 root root 64 2009-04-14 14:10 5 -> /proc/bus/pci/01/00.0 .... lrwx------ 1 root root 64 2009-04-14 14:10 6 -> /dev/nvidiactl 非 常值得注意的是, /dev/nvidia0, /dev/nvidiactl是NV 官方驱动引入的两个设备文件, 而/dev/tty7的含义也很明显, 为什么ctrl+alt+f7 可以切换到X系统就很明显拉. 同时Xorg这个进程还打开了acpi的CRT以及LCD相关文件, 可以获取电源管理的一些信息. /dev/psaux 则 是一个虚拟设备, 由mousedev.c创建, 他获取系统的鼠标设备事件, 以PS2协议提供设备/dev/psaux给use space使用, 这个mousedev可以产生三种PS2协议: PS/2, ImPS2(Microsoft ItelliMouse, 支持滚轮), ExplorerPS/2( 支持多个鼠标button). mousedev和linux新的input系统共存, 是一个临时的hack 行为。 /proc/bus/pci/01/00.0, 对应pci bus 1, 设备00.0, 从可以看到这设备正是nvida显卡. $ls /sys/bus/pci/devices/0000\:01\:00.0/ -l total 0 -rw-r--r-- 1 root root 4096 2009-04-15 09:58 broken_parity_status -r--r--r-- 1 root root 4096 2009-04-15 09:58 class -rw-r--r-- 1 root root 256 2009-04-15 09:58 config -r--r--r-- 1 root root 4096 2009-04-15 09:58 device lrwxrwxrwx 1 root root 0 2009-04-15 09:58 driver -> ../../../../bus/pci/drivers/nvidia -rw------- 1 root root 4096 2009-04-15 09:58 enable drwxr-xr-x 5 root root 0 2009-04-15 09:58 i2c-adapter -r--r--r-- 1 root root 4096 2009-04-15 09:58 irq -r--r--r-- 1 root root 4096 2009-04-15 09:58 local_cpus -r--r--r-- 1 root root 4096 2009-04-15 09:58 modalias -rw-r--r-- 1 root root 4096 2009-04-15 09:58 msi_bus drwxr-xr-x 2 root root 0 2009-04-15 09:58 power -r--r--r-- 1 root root 4096 2009-04-15 09:58 resource -rw------- 1 root root 16777216 2009-04-15 09:58 resource0 -rw------- 1 root root 268435456 2009-04-15 09:58 resource1 -rw------- 1 root root 33554432 2009-04-15 09:58 resource3 -rw------- 1 root root 128 2009-04-15 09:58 resource5 -r-------- 1 root root 131072 2009-04-15 09:58 rom lrwxrwxrwx 1 root root 0 2009-04-15 09:58 subsystem -> ../../../../bus/pci -r--r--r-- 1 root root 4096 2009-04-15 09:58 subsystem_device -r--r--r-- 1 root root 4096 2009-04-15 09:58 subsystem_vendor -rw-r--r-- 1 root root 4096 2009-04-15 09:58 uevent -r--r--r-- 1 root root 4096 2009-04-15 09:58 vendor 然后可以获得verndor 和device 的名字. $cat /usr/share/misc/pci.ids | grep 10de 10de nVidia Corporation $cat /sys/bus/pci/devices/0000\:01\:00.0/device 0x042b $ cat /usr/share/misc/pci.ids | grep 042b 042b Quadro NVS 135M 但是这些过程不用这么麻烦, 有现成的工具, 做得更好. $ ps -A | grep Xorg 6134 tty7 00:05:02 Xorg $ sudo lsof -p 6134 然后查看硬件信息如nvidia, 可以 lspci -d 10de: -vvv -xxx -b 01:00.0 VGA compatible controller: nVidia Corporation Quadro NVS 135M (rev a1) (prog-if 00 [VGA controller]) Subsystem: Dell Unknown device 01f9 Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- Latency: 0 Interrupt: pin A routed to IRQ 5 Region 0: Memory at f5000000 (32-bit, non-prefetchable) Region 1: Memory at 00000000e0000000 (64-bit, prefetchable) Region 3: Memory at 00000000f2000000 (64-bit, non-prefetchable) Region 5: I/O ports at ef00 Capabilities: <access denied> 00: de 10 2b 04 07 00 10 00 a1 00 00 03 00 00 00 00 10: 00 00 00 f5 0c 00 00 e0 00 00 00 00 04 00 00 f2 20: 00 00 00 00 01 ef 00 00 00 00 00 00 28 10 f9 01 30: 00 00 00 00 60 00 00 00 00 00 00 00 05 01 00 00 稍微深入看Xorg如何处理鼠标键盘初始化,需要看看xorg的代码。从本文分析的具体环境如下, 从/var/log/Xorg.0.log获取: X.Org X Server 1.4.0.90 Release Date: 5 September 2007 X Protocol Version 11, Revision 0 Build Operating System: Linux Ubuntu (xorg-server 2:1.4.1~git20080131-1ubuntu9.2) Current Operating System: Linux yhe-laptop 2.6.24-23-generic #1 SMP Thu Feb 5 15:00:25 UTC 2009 i686 首 先安装source code:sudo apt-get source xorg-server, 就能得到源代码xorg-server-1.4.1~git20080131. 不深入看xorg代码,从config 解析看看鼠标键盘的初始化吧.先看看log记录: Markers: (--) probed, (**) from config file, (==) default setting, (++) from command line, (!!) notice, (II) informational, (WW) warning, (EE) error, (NI) not implemented, (??) unknown. (==) Log file: "/var/log/Xorg.0.log", Time: Mon May 4 10:40:15 2009 (==) Using config file: "/etc/X11/xorg.conf" ---> xf86HandleConfigFile (==) ServerLayout "Layout0" ----->xf86parseLayoutSection (**) |-->Screen "Screen0" (0) (**) | |-->Monitor "Monitor0" (**) | |-->Device "Device0" (**) |-->Input Device "Keyboard0" (**) |-->Input Device "Mouse0" (==) Automatically adding devices (==) Automatically enabling devices 对应代码是hw/xfree86/parser/scan.c , xf86openConfigFile, 通过两个宏来搜索配置文件: #define DEFAULT_CONF_PATH "/etc/X11/%S," \ ..................... #define XCONFIGFILE "xorg.conf" 继续深入前,看看这个环境的xorg.conf 对应输入部分的内容: Section "ServerLayout" Identifier "Layout0" Screen 0 "Screen0" InputDevice "Keyboard0" "CoreKeyboard" InputDevice "Mouse0" "CorePointer" EndSection Section "InputDevice" # generated from default Identifier "Mouse0" Driver "mouse" Option "Protocol" "auto" Option "Device" "/dev/psaux" Option "Emulate3Buttons" "no" Option "ZAxisMapping" "4 5" EndSection Section "InputDevice" # generated from default Identifier "Keyboard0" Driver "kbd" EndSection 从上面提到的函数可以追踪到键盘配置的解析过程xf86parseInputSection,将鼠标键盘的配置记录下来,接着看log: (II) Module ABI versions: X.Org ANSI C Emulation: 0.3 X.Org Video Driver: 2.0 X.Org XInput driver : 2.0 X.Org Server Extension : 0.3 X.Org Font Renderer : 0.5 (II) Loader running on linux --->xfree86/common/xf86init.c->InitOutput->LoaderInit .... (++) using VT number 7 ---> xf86OpenConsole(); (II) LoadModule: "kbd" (II) Loading /usr/lib/xorg/modules/input//kbd_drv.so (II) Module kbd: vendor="X.Org Foundation" compiled for 1.4.0, module version = 1.2.2 Module class: X.Org XInput Driver ABI class: X.Org XInput driver, version 2.0 (II) LoadModule: "mouse" (II) Loading /usr/lib/xorg/modules/input//mouse_drv.so (II) Module mouse: vendor="X.Org Foundation" compiled for 1.4.0, module version = 1.2.3 Module class: X.Org XInput Driver ABI class: X.Org XInput driver, version 2.0 ...... (II) Initializing built-in extension XInputExtension (II) Initializing built-in extension XTEST 从log可以看到, kbd是加载的kbd_drv.so, 这个driver在另外一个包中, 需要单独获取源代码:sudo apt-get source xserver-xorg-input-kbd. 编译以下就知道是哪几个C文件构成这个xserver 的drv了: gcc -shared .libs/kbd.o .libs/lnx_KbdMap.o .libs/lnx_kbd.o .libs/at_scancode.o -Wl,-soname -Wl,kbd_drv.so -o .libs/kbd_drv.so 也可以参考 man 4 kbd. 我们的配置文件如下, 选择的就是这个驱动, 在man的信息里提到,默认(没有指定device参数的)情况下, 使用tty7来作为输入设备. Section "InputDevice" # generated from default Identifier "Keyboard0" Driver "kbd" EndSection 打开设备的代码如下, 可以看到在么有指定device的情况下,就用tty7作为键盘输入源. static Bool OpenKeyboard(InputInfoPtr pInfo) { KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; int i; KbdProtocolId prot = PROT_UNKNOWN_KBD; char *s; s = xf86SetStrOption(pInfo->options, "Protocol", NULL); for (i = 0; protocols[i].name; i++) { if (xf86NameCmp(s, protocols[i].name) == 0) { prot = protocols[i].id; break; } } switch (prot) { case PROT_STD: pInfo->read_input = stdReadInput; break; default: xf86Msg(X_ERROR,"\"%s\" is not a valid keyboard protocol name\n", s); xfree(s); return FALSE; } xf86Msg(X_CONFIG, "%s: Protocol: %s\n", pInfo->name, s); xfree(s); s = xf86SetStrOption(pInfo->options, "Device", NULL); if (s == NULL) { pInfo->fd = xf86Info.consoleFd; pKbd->isConsole = TRUE; } else { pInfo->fd = open(s, O_RDONLY | O_NONBLOCK | O_EXCL); if (pInfo->fd == -1) { xf86Msg(X_ERROR, "%s: cannot open \"%s\"\n", pInfo->name, s); xfree(s); return FALSE; } pKbd->isConsole = FALSE; xfree(s); } if (pKbd->isConsole) pKbd->vtSwitchSupported = TRUE; return TRUE; } .......... (**) Option "CoreKeyboard" (**) Keyboard0: always reports core events (**) Option "Protocol" "standard" (**) Keyboard0: Protocol: standard xserver-xorg-input-kbd/src/lnx_kbd.c ->OpenKeyboard (**) Option "AutoRepeat" "500 30" (**) Option "XkbRules" "xorg" (**) Keyboard0: XkbRules: "xorg" (**) Option "XkbModel" "pc105" (**) Keyboard0: XkbModel: "pc105" (**) Option "XkbLayout" "us" (**) Keyboard0: XkbLayout: "us" (**) Option "CustomKeycodes" "off" (**) Keyboard0: CustomKeycodes disabled 鼠标类似,也是单独下载驱动的源码:sudo apt-get source xserver-xorg-input-mouse, make 然后知道其组成: gcc -shared .libs/mouse.o .libs/pnp.o -Wl,-soname -Wl,mouse_drv.so -o .libs/mouse_drv.so Section "InputDevice" # generated from default Identifier "Mouse0" Driver "mouse" Option "Protocol" "auto" Option "Device" "/dev/psaux" Option "Emulate3Buttons" "no" Option "ZAxisMapping" "4 5" EndSection (**) Option "Protocol" "auto" (**) Mouse0: Device: "/dev/psaux" xserver-xorg-input-mouse/src/mouse.c:MousePreInit (**) Mouse0: Protocol: "auto" (**) Option "CorePointer" (**) Mouse0: always reports core events (**) Option "Device" "/dev/psaux" (**) Option "Emulate3Buttons" "no" (**) Option "ZAxisMapping" "4 5" (**) Mouse0: ZAxisMapping: buttons 4 and 5 (**) Mouse0: Buttons: 9 (**) Mouse0: Sensitivity: 1 (II) evaluating device (Mouse0) (II) XINPUT: Adding extended input device "Mouse0" (type: MOUSE) (II) XINPUT: Adding extended input device "Mouse0" (type: MOUSE) (II) evaluating device (Keyboard0) (II) XINPUT: Adding extended input device "Keyboard0" (type: KEYBOARD) (--) Mouse0: PnP-detected protocol: "ExplorerPS/2" (II) Mouse0: ps2EnableDataReporting: succeeded Xorg 键盘鼠标输入处理流程 先 总结后分析: xorg 处理两种输入, 一种是鼠标键盘这种设备的输入, 另一种是client的socket传入的请求. socket当然采用的是select, 来进行异步处理. 本环境下鼠标键盘的x驱动是通过tty的fd进行select. 有的系统, 鼠标输入采用异步IO, 采用的信号是SIGIO, 比如BSD. 采用SIGIO的还有些DRI设备(Direct Rendering Infrastructure 参考:http://en.wikipedia.org/wiki/Direct_Rendering_Infrastructure ) 这 里采用的xorg环境上面已经有所提及, 这里提及一点历史: xfree86 原来专用于x86,后来发展成极为通用的X系统, 但是XFree86从2004年发布的版本4.4起不再遵从GPL许可证发行, 同年Xorg发布了基于4.4版本的Xorg X系统. 所以你看到xorg代码中有多个相同定义时, 对我们的环境, 它是xfree86所定义的那个函数. 此外预先介绍下xorg Xserver的几个相关组成部分(google即得): *xserver/dix: Device Independent 1) 资源管理(字体,位图,光标之类 2. dispatch, 处理client请求(events.c) 3.处理input事件 * xserver/mi ... machine independent X. Mouse cursor rendering stuff. * xserver/hw/xfree86/common ... some additional stuff, especially for X Input. * xserver/Xi ... X Input Extension protocol stuff. 文章推荐: http://wearables.unisa.edu.au/mpx/?q=eventprocessing MP X server 项目文档 此文档有个如何处理鼠标输入的图, 非常直观, 先奉上. 这个例子里鼠标采用的是在SIGIO信号内处理鼠标事件,和这里讨论的具体环境有差异,仅供参考. (单击看大图了) 先看对client的服务是如何分发的, 前面提到是select模式, 非常有意义的一个变量是定义在 xserver/os/connection.c中, fd_set AllSockets; /* select on this */ 新建立的链接会吧自己的fd加入这个set, 而Dispatch会直接select on 这个set. 在同一个文件还有另外一个重要的变量: fd_set EnabledDevices; /* mask for input devices that are on */ 用于记录打开的输入设备, 比如我们所讨论的鼠标和键盘. 还是先从main开始吧, 在server/dix/main.c中 int main(int argc, char *argv[], char *envp[]) { ........ while(1) { OsInit(); config_init(); if(serverGeneration == 1) { CreateWellKnownSockets(); /*打开server端口并加入AllSockets*/ ..... } .......... InitOutput(&screenInfo, argc, argv); /*读取配置文件, 打开console等,载入input设备驱动和各种模块 (xfree86/common/xf86init.c), 注册xf86Wakeup 到wakup handlers*/ #ifdef XPRINT PrinterInitOutput(&screenInfo, argc, argv); #endif if (screenInfo.numScreens < 1) FatalError("no screens found"); if (screenInfo.numVideoScreens < 0) screenInfo.numVideoScreens = screenInfo.numScreens; InitExtensions(argc, argv); if (!InitClientPrivates(serverClient)) FatalError("failed to allocate serverClient devprivates"); for (i = 0; i < screenInfo.numScreens; i++) { ScreenPtr pScreen = screenInfo.screens[i]; if (!CreateScratchPixmapsForScreen(i)) FatalError("failed to create scratch pixmaps"); if (pScreen->CreateScreenResources && !(*pScreen->CreateScreenResources)(pScreen)) FatalError("failed to create screen resources"); if (!CreateGCperDepth(i)) FatalError("failed to create scratch GCs"); if (!CreateDefaultStipple(i)) FatalError("failed to create default stipple"); if (!CreateRootWindow(pScreen)) FatalError("failed to create root window"); } InitCoreDevices(); InitInput(argc, argv); /*调用每个输入设备的PreInit函数, mieqInit*/ if (InitAndStartDevices() != Success) /*向鼠标键盘发送DEVICE_ON命令, 注册到全局输入处理表:handlers*/ FatalError("failed to initialize core devices"); InitFonts(); Dispatch(); /*WaitForSomething select on AllSockets, 有键盘鼠标输入也会被信号唤醒,并处理*/ /* Now free up whatever must be freed */ .......... } 键盘鼠标的输入函数注册 InitAndStartDevices -> KbdProc(xserver-xorg-input-kbd-1.22/src/kbc.c)(鼠标的亦同) -> AddEnabledDevice(pInfo->fd) : 把fd同时加入EnabledDevices, 和AllSockets 全局fdset中, 并在全局 读取数据: InitOutput -> RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, xf86Wakeup,NULL); 注册xf86Wakup到全局表handlers 中,在任务被唤醒后得到调用. os/WaitFor.c :WaitForSomething -> WakeupHandler ->(*handlers[i].WakeupHandler) (handlers[i].blockData,..) -> xf86Wakeup 根据select结果, 在全局输入设备表xf86InputDevs 中找到此设备调用其read_input函数. 唤醒: 内核根据select 结果,唤醒Xorg. xclient传递的消息在Dispatch函数中处理. 至于鼠标键盘的read_input读取键盘/鼠标输入然后分发给xclient的过程就不做研究了. 参考: xserver/os/connection.c : AllocNewConnection, 新链接加入AllSockets. xserver/os/WaitFor.c : WaitForSomething, http://lists.freedesktop.org/archives/xorg/2006-August/017253.html http://wearables.unisa.edu.au/mpx/downloads/deprecated/ |
相关阅读 更多 +