\chapter{虚拟输入设备驱动}
\label{sec:vinput}
-输入设备驱动程序是提供通过事件与交互设备进行通信的方式的内核模块。例如,键盘可%
-以å\8f\91é\80\81æ\8c\89ä¸\8bæ\88\96é\87\8aæ\94¾äº\8bä»¶æ\9d¥å\91\8aè¯\89å\86\85æ ¸æ\88\91们æ\83³è¦\81å\81\9aä»\80ä¹\88ã\80\82è¾\93å\85¥è®¾å¤\87驱å\8a¨ä½¿ç\94¨ \cpp|input_allocate_device()| %
-å\88\86é\85\8dä¸\80个æ\96°ç\9a\84è¾\93å\85¥ç»\93æ\9e\84ï¼\8cå¹¶ä¸\94建ç«\8bè¾\93å\85¥æ¯\94ç\89¹ä½\8då\97段ï¼\8c设å¤\87 IDï¼\8cç\89\88æ\9c¬ç\89ã\80\82ä¹\8bå\90\8eé\80\9aè¿\87è°\83ç\94¨ %
-\cpp|input_register_device()| 来注册它。
+输入设备驱动程序是一个内核模块,它提供通过事件与交互设备进行通信的一种方法。%
+ä¾\8bå¦\82ï¼\8cé\94®ç\9b\98å\8f¯ä»¥å\8f\91é\80\81æ\8c\89å\8e\8bæ\88\96é\87\8aæ\94¾æ\8c\89é\94®ç\9a\84äº\8bä»¶ï¼\8cæ\9d¥å\91\8aè¯\89å\86\85æ ¸æ\88\91们æ\83³è¦\81å\81\9aä»\80ä¹\88ã\80\82è¾\93å\85¥è®¾å¤\87驱%
+å\8a¨ä½¿ç\94¨ \cpp|input_allocate_device()| å\88\86é\85\8dä¸\80个æ\96°ç\9a\84è¾\93å\85¥ç»\93æ\9e\84ï¼\8cå¹¶ä¸\94建ç«\8bè¾\93å\85¥æ¯\94ç\89¹ä½\8d%
+字段,设备 ID,版本等。之后通过调用 \cpp|input_register_device()| 来注册它。
这里有一个示例,vinput,它是一个 API,可以轻松开发虚拟输入驱动程序。驱动程序需%
-要输出一个 \cpp|vinput_device()|,其包含虚拟设备名与 \cpp|vinput_ops| 结构,该%
-结构说明如下:
+要输出一个 \cpp|vinput_device()|,其包含虚拟设备名称以及 \cpp|vinput_ops| 结%
+构,该结构说明如下:
\begin{itemize}
\item 初始化函数: \cpp|init()|
\item 输入事件注入函数: \cpp|send()|
- \item 回调函数: \cpp|read()|
+ \item 读出函数: \cpp|read()|
\end{itemize}
然后使用 \cpp|vinput_register_device()| 与 \cpp|vinput_unregister_device()| %
\begin{code}
int init(struct vinput *);
\end{code}
-此函数被传递有一个内存空间被分配为 \cpp|struct input_dev| 大小的,且初始化的 %
-\cpp|struct vinput|。\cpp|init()| 函数是负责初始化输入设备的能力,并注册它。
+这个函数被传递一个结构构 \cpp|struct vinput|,它已被一个在内存空间,被分配结构%
+体 \cpp|input_dev| 尺寸大小的结构体,进行了初始化操作。\cpp|init()| 函数是负责%
+初始化输入设备的能力,并注册它的函数。
\begin{code}
int send(struct vinput *, char *, int);
\end{code}
-此函数将接收用户字符串以使用 \cpp|input_report_XXXX| 或 \cpp|input_event| 来解%
-释和注入事件。该字符串已从用户处拷贝。
+此函数将接收一个用户字符串,以使用 \cpp|input_report_XXXX| 或调用 \cpp|input_event| %
+来解释和注入事件。该字符串已被从用户那里拷贝。
\begin{code}
int read(struct vinput *, char *, int);
};
\end{code}
-在 \verb|input.c| 中,用到的宏 \cpp|CLASS_ATTR_WO(export/unexport)| 是在文件 %
-\src{include/linux/device.h}(此时,\verb|device.h| 被包含于 \src{include/linux/input.h})%
-中被定义,它将产生 \cpp|class_attribute| 结构,%
+在 \verb|input.c| 中,被用到的宏 \cpp|CLASS_ATTR_WO(export/unexport)| 是在文件 %
+\src{include/linux/device.h}\,(\,此时,\verb|device.h| 被包含于 %
+\src{include/linux/input.h}\,) 中被定义,它将产生 \cpp|class_attribute| 结构,%
\verb|class_attr_export/unexport)| 是这些结构被命名的名称,然后,将它们放入 %
\cpp|vinput_class_attrs| 数组,此后宏 \cpp|ATTRIBUTE_GROUPS(vinput_class)| %
将产生结构 \cpp|struct attribute_group|, \verb|vinput_class_group| 它在 \cpp|vinput_class| %
这里的虚拟键盘是使用 vinput 的一个示例。它支持所有 \cpp|KEY_MAX| 键码。注入格式%
为如在 \src{include/linux/input.h}中被定义的 \cpp|KEY_CODE|。正整数值意味着按键%
-的 \cpp|KEY_PRESS| 状态,而负整数值代表 \cpp|KEY_RELEASE| 处理状态。当按键按下时%
-间长度过长时,键盘支持重复。下面演示了模拟是如何工作的。
+的 \cpp|KEY_PRESS| 按下状态,而负整数值代表按键的 \cpp|KEY_RELEASE| 释放状态。%
+当按键按下时间长度过长时,键盘支持重复输入功能。下面演示了模拟如何工作。
模拟在``g''(\cpp|KEY_G| = 34)被按下:
\chapter{标准化接口:设备模型}
\label{sec:device_model}
-å\88°ç\9b®å\89\8d为æ¢ï¼\8cæ\88\91们已ç»\8fç\9c\8bå\88°å\90\84ç§\8då\90\84æ ·ç\9a\84模å\9d\97å\9c¨å\81\9aä¸\8då\90\8cç\9a\84äº\8bæ\83\85ï¼\8cä½\86æ\98¯å®\83们ç\9a\84æ\8e¥å\8f£ä¸\8eå\86\85æ ¸ç\9a\84å\85¶%
-余部分没有一致性。为了提高一致性,这里开启了最小化标准化方法的工作,启动,暂停,%
-和恢复一个设备的模型被添加进来。下面是一个示例,你以此为模板,可以为模板添加自%
-己的挂起,恢复或其它接口函数。
+å\88°ç\9b®å\89\8d为æ¢ï¼\8cæ\88\91们已ç»\8fç\9c\8bå\88°å\90\84ç§\8då\90\84æ ·ç\9a\84模å\9d\97å\9c¨å\81\9aä¸\8då\90\8cç\9a\84äº\8bæ\83\85ï¼\8cä½\86æ\98¯å\89\8dé\9d¢æ¨¡å\9d\97ä¸\8eå\86\85æ ¸ç\9a\84å\85¶ä½\99%
+部分不具有一致性。为了提高一致性,这里开启了最小标准化路程,启动,暂停,和恢复%
+一个设备的模型被添加进来。下面是一个示例,你以此为模板,可以为模板添加自己的挂%
+起,恢复或其它接口函数。
\samplec{examples/devicemodel.c}
\section{静态键}
\label{sec:static_keys}
-静态键允许我们根据键的运行时状态来启用或禁止内核代码路径。它的 API 自2010年起(%
-大多数架构已经被支持)已经可用,使用自修改代码来消除缓存和分支预测的开销。静态键%
-æ\9c\80å\85¸å\9e\8bç\9a\84ç\94¨ä¾\8bæ\98¯æ\80§è\83½æ\95\8fæ\84\9fç\9a\84å\86\85æ ¸ä»£ç \81ï¼\8cä¾\8bå¦\82è·\9f踪ç\82¹ï¼\8cä¸\8aä¸\8bæ\96\87ä»¶å\88\87æ\8d¢ã\80\81ç½\91ç»\9cç\89ã\80\82å\86\85æ ¸ç\9a\84è¿\99äº\9b%
-热路径通常包含分支,并且可以使用此技术轻松优化。在我们可以在内核中使用静态键之%
-前,我们需要确保 gcc 支持内联汇编,并设置以下内核配置:
+静态键允许我们根据键的运行时状态来启用或禁止内核代码路径。它的 API 自2010年起\,(\,%
+大多数架构已经被支持\,)\,已经可用,使用自修改代码来消除缓存和分支预测的开销。静%
+æ\80\81é\94®æ\9c\80å\85¸å\9e\8bç\9a\84ç\94¨ä¾\8bæ\98¯æ\80§è\83½æ\95\8fæ\84\9fç\9a\84å\86\85æ ¸ä»£ç \81ï¼\8cä¾\8bå¦\82è·\9f踪ç\82¹ï¼\8cä¸\8aä¸\8bæ\96\87ä»¶å\88\87æ\8d¢ã\80\81ç½\91ç»\9cç\89ã\80\82å\86\85æ ¸ç\9a\84%
+这些热路径通常包含分支,并且可以使用此技术轻松优化。在我们可以在内核中使用静态%
+键之前,我们需要确保 gcc 支持内联汇编,并设置以下内核配置:
\begin{code}
CONFIG_JUMP_LABEL=y
\samplec{examples/static_key.c}
-在检查静态键的状态,我们可以使用 \verb|/dev/key_state| 接口。
+要检查静态键的状态,我们可以使用 \verb|/dev/key_state| 接口。
\begin{codebash}
cat /dev/key_state
这将启用静态键,引起代码路径从快速路径切换到慢速路径。
-有时,键在初始化阶段决定是开启或禁止,并且状态决不会改变,我们可以声明一静态键%
-作为只读,这意味着这个键只能在模块初始化函数中被触发。要声明一个只读静态键,我%
-们可以使用 \cpp|DEFINE_STATIC_KEY_FALSE_RO| 或 \cpp|DEFINE_STATIC_KEY_TRUE_RO| %
+有时,键在初始化阶段决定是开启或禁止,且维持状态决不改变,我们可以声明一个静态%
+键作为只读,这意味着这个键只能在模块初始化函数中被触发。要声明一个只读静态键,%
+我们可以使用 \cpp|DEFINE_STATIC_KEY_FALSE_RO| 或 \cpp|DEFINE_STATIC_KEY_TRUE_RO| %
宏作为替换。在运行时尝试修改键将引起一个代码页失效。如想了解更多信息,请参阅 %
\href{https://www.kernel.org/doc/Documentation/static-keys.txt}{Static keys}。