diff --git a/index.html b/index.html
index faf3de8..9ae954c 100644
--- a/index.html
+++ b/index.html
@@ -85,18 +85,15 @@
15.1 Interrupt Handlers
15.2 Detecting button presses
15.3 Bottom Half
-
16 Crypto
-
16.1 Hash functions
-
16.2 Symmetric key encryption
-
17 Virtual Input Device Driver
-
18 Standardizing the interfaces: The Device Model
-
19 Optimizations
-
19.1 Likely and Unlikely conditions
-
19.2 Static keys
-
20 Common Pitfalls
-
20.1 Using standard libraries
-
20.2 Disabling interrupts
-
21 Where To Go From Here?
+
16 Virtual Input Device Driver
+
17 Standardizing the interfaces: The Device Model
+
18 Optimizations
+
18.1 Likely and Unlikely conditions
+
18.2 Static keys
+
19 Common Pitfalls
+
19.1 Using standard libraries
+
19.2 Disabling interrupts
+
20 Where To Go From Here?
The Linux Kernel Module Programming Guide is a free book; you may reproduce @@ -111,14 +108,14 @@ the provisions of the Open Sof distribute this book free of charge or for a profit. No explicit permission is required from the author for reproduction of this book in any medium, physical or electronic. - - -
Derivative works and translations of this document must be placed under the Open Software License, and the original copyright notice must remain intact. If you have contributed new material to this book, you must make the material and source code available for your revisions. Please make revisions and updates available directly to the document maintainer, Jim Huang <jserv@ccns.ncku.edu.tw>. This will allow + + + for the merging of updates and provide consistent revisions to the Linux community.
If you publish or distribute this book commercially, donations, royalties, and/or @@ -153,13 +150,13 @@ Scarpazza, David Porter, demonsome, Dimo Velev, Ekang Monyet, Ethan Chan, fennecJ, Francois Audeon, Gilad Reti, heartofrain, Horst Schirmeier, Hsin-Hsiang Peng, Ignacio Martin, Iûnn Kiàn-îng, Jian-Xing Wu, Johan Calle, keytouch, Kohei Otsuka, Kuan-Wei Chiu, manbing, Marconi Jiang, - - - mengxinayan, Peter Lin, Roman Lakeev, Sam Erickson, Shao-Tse Hung, Shih-Sheng Yang, Stacy Prowell, Steven Lung, Tristan Lelong, Tse-Wei Lin, Tucker Polomik, Tyler Fanelli, VxTeemo, Wei-Lun Tsai, Xatierlike Lee, Yin-Chiuan Chen, Yi-Wei Lin, Ylowy, Yu-Hsiang Tseng.
+ + +
On Arch Linux:
1sudo pacman -S gcc kmod+
+
--
To discover what modules are already loaded within your current kernel use the command
At the dawn of the internet, everybody trusted everybody completely…but that did
-not work out so well. When this guide was originally written, it was a more innocent
-era in which almost nobody actually gave a damn about crypto - least of all kernel
-developers. That is certainly no longer the case now. To handle crypto stuff, the
-kernel has its own API enabling common methods of encryption, decryption and your
-favourite hash functions.
-
- Calculating and checking the hashes of things is a common operation.
-Here is a demonstration of how to calculate a sha256 hash within a
-kernel module. To provide the sha256 algorithm support, make sure
-
- Install the module:
-
- And you should see that the hash was calculated for the test string.
- Finally, remove the test module:
-
-
-
-
-
- Here is an example of symmetrically encrypting a string using the AES algorithm
-and a password.
-
-
- The input device driver is a module that provides a way to communicate
+ The input device driver is a module that provides a way to communicate
with the interaction device via the event. For example, the keyboard
can send the press or release event to tell the kernel what we want to
do. The input device driver will allocate a new input structure with
@@ -5718,7 +5409,7 @@ do. The input device driver will allocate a new input structure with
lsmod
@@ -5403,314 +5400,8 @@ when an interrupt is triggered.
168MODULE_DESCRIPTION("Interrupt with top and bottom half");
and sets up input bitfields, device id, version, etc. After that, registers it by calling
16 Crypto
-16.1 Hash functions
- CONFIG_CRYPTO_SHA256
-
is enabled in kernel.
-1/*
-2 * cryptosha256.c
-3 */
-4#include <crypto/internal/hash.h>
-5#include <linux/module.h>
-6
-7#define SHA256_LENGTH 32
-8
-9static void show_hash_result(char *plaintext, char *hash_sha256)
-10{
-11 int i;
-12 char str[SHA256_LENGTH * 2 + 1];
-13
-14 pr_info("sha256 test for string: \"%s\"\n", plaintext);
-15 for (i = 0; i < SHA256_LENGTH; i++)
-16 sprintf(&str[i * 2], "%02x", (unsigned char)hash_sha256[i]);
-17 str[i * 2] = 0;
-18 pr_info("%s\n", str);
-19}
-20
-21static int __init cryptosha256_init(void)
-22{
-23 char *plaintext = "This is a test";
-24 char hash_sha256[SHA256_LENGTH];
-25 struct crypto_shash *sha256;
-26 struct shash_desc *shash;
-27
-28 sha256 = crypto_alloc_shash("sha256", 0, 0);
-29 if (IS_ERR(sha256)) {
-30 pr_err(
-31 "%s(): Failed to allocate sha256 algorithm, enable CONFIG_CRYPTO_SHA256 and try again.\n",
-32 __func__);
-33 return -1;
-34 }
-35
-36 shash = kmalloc(sizeof(struct shash_desc) + crypto_shash_descsize(sha256),
-37 GFP_KERNEL);
-38 if (!shash)
-39 return -ENOMEM;
-40
-41 shash->tfm = sha256;
-42
-43 if (crypto_shash_init(shash))
-44 return -1;
-45
-46 if (crypto_shash_update(shash, plaintext, strlen(plaintext)))
-47 return -1;
-48
-49 if (crypto_shash_final(shash, hash_sha256))
-50 return -1;
-51
-52 kfree(shash);
-53 crypto_free_shash(sha256);
-54
-55 show_hash_result(plaintext, hash_sha256);
-56
-57 return 0;
-58}
-59
-60static void __exit cryptosha256_exit(void)
-61{
-62}
-63
-64module_init(cryptosha256_init);
-65module_exit(cryptosha256_exit);
-66
-67MODULE_DESCRIPTION("sha256 hash test");
-68MODULE_LICENSE("GPL");
-1sudo insmod cryptosha256.ko
-2sudo dmesg
-1sudo rmmod cryptosha256
-16.2 Symmetric key encryption
-1/*
-2 * cryptosk.c
-3 */
-4#include <crypto/internal/skcipher.h>
-5#include <linux/crypto.h>
-6#include <linux/module.h>
-7#include <linux/random.h>
-8#include <linux/scatterlist.h>
-9
-10#define SYMMETRIC_KEY_LENGTH 32
-11#define CIPHER_BLOCK_SIZE 16
-12
-13struct tcrypt_result {
-14 struct completion completion;
-15 int err;
-16};
-17
-18struct skcipher_def {
-19 struct scatterlist sg;
-20 struct crypto_skcipher *tfm;
-21 struct skcipher_request *req;
-22 struct tcrypt_result result;
-23 char *scratchpad;
-24 char *ciphertext;
-25 char *ivdata;
-26};
-27
-28static struct skcipher_def sk;
-29
-30static void test_skcipher_finish(struct skcipher_def *sk)
-31{
-32 if (sk->tfm)
-33 crypto_free_skcipher(sk->tfm);
-34 if (sk->req)
-35 skcipher_request_free(sk->req);
-36 if (sk->ivdata)
-37 kfree(sk->ivdata);
-38 if (sk->scratchpad)
-39 kfree(sk->scratchpad);
-40 if (sk->ciphertext)
-41 kfree(sk->ciphertext);
-42}
-43
-44static int test_skcipher_result(struct skcipher_def *sk, int rc)
-45{
-46 switch (rc) {
-47 case 0:
-48 break;
-49 case -EINPROGRESS:
-50 case -EBUSY:
-51 rc = wait_for_completion_interruptible(&sk->result.completion);
-52 if (!rc && !sk->result.err) {
-53 reinit_completion(&sk->result.completion);
-54 break;
-55 }
-56 pr_info("skcipher encrypt returned with %d result %d\n", rc,
-57 sk->result.err);
-58 break;
-59 default:
-60 pr_info("skcipher encrypt returned with %d result %d\n", rc,
-61 sk->result.err);
-62 break;
-63 }
-64
-65 init_completion(&sk->result.completion);
-66
-67 return rc;
-68}
-69
-70static void test_skcipher_callback(struct crypto_async_request *req, int error)
-71{
-72 struct tcrypt_result *result = req->data;
-73
-74 if (error == -EINPROGRESS)
-75 return;
-76
-77 result->err = error;
-78 complete(&result->completion);
-79 pr_info("Encryption finished successfully\n");
-80
-81 /* decrypt data */
-82#if 0
-83 memset((void*)sk.scratchpad, '-', CIPHER_BLOCK_SIZE);
-84 ret = crypto_skcipher_decrypt(sk.req);
-85 ret = test_skcipher_result(&sk, ret);
-86 if (ret)
-87 return;
-88
-89 sg_copy_from_buffer(&sk.sg, 1, sk.scratchpad, CIPHER_BLOCK_SIZE);
-90 sk.scratchpad[CIPHER_BLOCK_SIZE-1] = 0;
-91
-92 pr_info("Decryption request successful\n");
-93 pr_info("Decrypted: %s\n", sk.scratchpad);
-94#endif
-95}
-96
-97static int test_skcipher_encrypt(char *plaintext, char *password,
-98 struct skcipher_def *sk)
-99{
-100 int ret = -EFAULT;
-101 unsigned char key[SYMMETRIC_KEY_LENGTH];
-102
-103 if (!sk->tfm) {
-104 sk->tfm = crypto_alloc_skcipher("cbc-aes-aesni", 0, 0);
-105 if (IS_ERR(sk->tfm)) {
-106 pr_info("could not allocate skcipher handle\n");
-107 return PTR_ERR(sk->tfm);
-108 }
-109 }
-110
-111 if (!sk->req) {
-112 sk->req = skcipher_request_alloc(sk->tfm, GFP_KERNEL);
-113 if (!sk->req) {
-114 pr_info("could not allocate skcipher request\n");
-115 ret = -ENOMEM;
-116 goto out;
-117 }
-118 }
-119
-120 skcipher_request_set_callback(sk->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
-121 test_skcipher_callback, &sk->result);
-122
-123 /* clear the key */
-124 memset((void *)key, '\0', SYMMETRIC_KEY_LENGTH);
-125
-126 /* Use the world's favourite password */
-127 sprintf((char *)key, "%s", password);
-128
-129 /* AES 256 with given symmetric key */
-130 if (crypto_skcipher_setkey(sk->tfm, key, SYMMETRIC_KEY_LENGTH)) {
-131 pr_info("key could not be set\n");
-132 ret = -EAGAIN;
-133 goto out;
-134 }
-135 pr_info("Symmetric key: %s\n", key);
-136 pr_info("Plaintext: %s\n", plaintext);
-137
-138 if (!sk->ivdata) {
-139 /* see https://en.wikipedia.org/wiki/Initialization_vector */
-140 sk->ivdata = kmalloc(CIPHER_BLOCK_SIZE, GFP_KERNEL);
-141 if (!sk->ivdata) {
-142 pr_info("could not allocate ivdata\n");
-143 goto out;
-144 }
-145 get_random_bytes(sk->ivdata, CIPHER_BLOCK_SIZE);
-146 }
-147
-148 if (!sk->scratchpad) {
-149 /* The text to be encrypted */
-150 sk->scratchpad = kmalloc(CIPHER_BLOCK_SIZE, GFP_KERNEL);
-151 if (!sk->scratchpad) {
-152 pr_info("could not allocate scratchpad\n");
-153 goto out;
-154 }
-155 }
-156 sprintf((char *)sk->scratchpad, "%s", plaintext);
-157
-158 sg_init_one(&sk->sg, sk->scratchpad, CIPHER_BLOCK_SIZE);
-159 skcipher_request_set_crypt(sk->req, &sk->sg, &sk->sg, CIPHER_BLOCK_SIZE,
-160 sk->ivdata);
-161 init_completion(&sk->result.completion);
-162
-163 /* encrypt data */
-164 ret = crypto_skcipher_encrypt(sk->req);
-165 ret = test_skcipher_result(sk, ret);
-166 if (ret)
-167 goto out;
-168
-169 pr_info("Encryption request successful\n");
-170
-171out:
-172 return ret;
-173}
-174
-175static int __init cryptoapi_init(void)
-176{
-177 /* The world's favorite password */
-178 char *password = "password123";
-179
-180 sk.tfm = NULL;
-181 sk.req = NULL;
-182 sk.scratchpad = NULL;
-183 sk.ciphertext = NULL;
-184 sk.ivdata = NULL;
-185
-186 test_skcipher_encrypt("Testing", password, &sk);
-187 return 0;
-188}
-189
-190static void __exit cryptoapi_exit(void)
-191{
-192 test_skcipher_finish(&sk);
-193}
-194
-195module_init(cryptoapi_init);
-196module_exit(cryptoapi_exit);
-197
-198MODULE_DESCRIPTION("Symmetric key encryption example");
-199MODULE_LICENSE("GPL");
-17 Virtual Input Device Driver
-16 Virtual Input Device Driver
+ input_register_device()
.
-
Here is an example, vinput, It is an API to allow easy +
Here is an example, vinput, It is an API to allow easy
development of virtual input drivers. The drivers needs to export a
vinput_device()
that contains the virtual device name and
@@ -5731,527 +5422,530 @@ development of virtual input drivers. The drivers needs to export a
send()
+
+
+
read()
Then using Then using
This function is passed a This function is passed a
This function will receive a user string to interpret and inject the event using the
+ This function will receive a user string to interpret and inject the event using the
This function is used for debugging and should fill the buffer parameter with the
+ This function is used for debugging and should fill the buffer parameter with the
last event sent in the virtual input device format. The buffer will then be copied to
user.
- vinput devices are created and destroyed using sysfs. And, event injection is done
+ vinput devices are created and destroyed using sysfs. And, event injection is done
through a /dev node. The device name will be used by the userland to export a new
virtual input device.
- The The
In vinput.c, the macro In vinput.c, the macro To create a vinputX sysfs entry and /dev node.
+ To create a vinputX sysfs entry and /dev node.
To unexport the device, just echo its id in unexport:
+ To unexport the device, just echo its id in unexport:
Here the virtual keyboard is one of example to use vinput. It supports all
+ Here the virtual keyboard is one of example to use vinput. It supports all
Simulate a key press on "g" ( Simulate a key press on "g" (
Simulate a key release on "g" ( Simulate a key release on "g" (
+
+
Up to this point we have seen all kinds of modules doing all kinds of things, but there
+ Up to this point we have seen all kinds of modules doing all kinds of things, but there
was no consistency in their interfaces with the rest of the kernel. To impose some
consistency such that there is at minimum a standardized way to start, suspend and
resume a device model was added. An example is shown below, and you can
@@ -6396,111 +6090,111 @@ use this as a template to add your own suspend, resume or other interface
functions.
+
+
Sometimes you might want your code to run as quickly as possible,
+ Sometimes you might want your code to run as quickly as possible,
especially if it is handling an interrupt or doing something which might
cause noticeable latency. If your code contains boolean conditions and if
you know that the conditions are almost always likely to evaluate as either
@@ -6512,40 +6206,40 @@ you know that the conditions are almost always likely to evaluate as either
+ When the When the
+
Static keys allow us to enable or disable kernel code paths based on the runtime state
+ Static keys allow us to enable or disable kernel code paths based on the runtime state
of key. Its APIs have been available since 2010 (most architectures are already
supported), use self-modifying code to eliminate the overhead of cache and branch
prediction. The most typical use case of static keys is for performance-sensitive kernel
code, such as tracepoints, context switching, networking, etc. These hot paths of the
kernel often contain branches and can be optimized easily using this technique.
Before we can use static keys in the kernel, we need to make sure that gcc supports
-
To declare a static key, we need to define a global variable using the
+ To declare a static key, we need to define a global variable using the
Once the static key has been declared, we need to add branching code to the
+ Once the static key has been declared, we need to add branching code to the
module that uses the static key. For example, the code includes a fastpath, where a
no-op instruction will be generated at compile time as the key is initialized to false
and the branch is unlikely to be taken.
If the key is enabled at runtime by calling
+ If the key is enabled at runtime by calling
- The following kernel module derived from chardev.c, demonstrates how the
+ The following kernel module derived from chardev.c, demonstrates how the
static key works.
To check the state of the static key, we can use the /dev/key_state
+ To check the state of the static key, we can use the /dev/key_state
interface.
This will display the current state of the key, which is disabled by default.
- To change the state of the static key, we can perform a write operation on the
+ This will display the current state of the key, which is disabled by default.
+ To change the state of the static key, we can perform a write operation on the
file:
This will enable the static key, causing the code path to switch from the fastpath
+ This will enable the static key, causing the code path to switch from the fastpath
to the slowpath.
- In some cases, the key is enabled or disabled at initialization and never changed,
+ In some cases, the key is enabled or disabled at initialization and never changed,
we can declare a static key as read-only, which means that it can only be toggled in
the module init function. To declare a read-only static key, we can use the
+
+
You can not do that. In a kernel module, you can only use kernel functions which are
+the functions you can see in /proc/kallsyms.
- You can not do that. In a kernel module, you can only use kernel functions which are
-the functions you can see in /proc/kallsyms.
-
+
You might need to do this for a short time and that is OK, but if you do not enable
+ You might need to do this for a short time and that is OK, but if you do not enable
them afterwards, your system will be stuck and you will have to power it
off.
-
+
For those deeply interested in kernel programming, kernelnewbies.org and the
+ For those deeply interested in kernel programming, kernelnewbies.org and the
Documentation subdirectory within the kernel source code are highly recommended.
Although the latter may not always be straightforward, it serves as a valuable initial
step for further exploration. Echoing Linus Torvalds’ perspective, the most effective
method to understand the kernel is through personal examination of the source
code.
- Contributions to this guide are welcome, especially if there are any significant
+ Contributions to this guide are welcome, especially if there are any significant
inaccuracies identified. To contribute or report an issue, please initiate an
issue at https://github.com/sysprog21/lkmpg. Pull requests are greatly
appreciated.
- Happy hacking!
+ Happy hacking!
1The goal of threaded interrupts is to push more of the work to separate threads, so that the
minimum needed for acknowledging an interrupt is reduced, and therefore the time spent handling
diff --git a/lkmpg-for-ht.css b/lkmpg-for-ht.css
index 6b00ff7..956dc50 100644
--- a/lkmpg-for-ht.css
+++ b/lkmpg-for-ht.css
@@ -3409,784 +3409,761 @@ pre#fancyvrb82{ border-top: solid 0.4pt; }
pre#fancyvrb82{ border-left: solid 0.4pt; }
pre#fancyvrb82{ border-bottom: solid 0.4pt; }
pre#fancyvrb82{ border-right: solid 0.4pt; }
-span#textcolor2789{color:rgb(0,127,0)}
-span#textcolor2790{color:rgb(0,127,0)}
-span#textcolor2791{color:rgb(0,127,0)}
+span#textcolor2789{color:rgb(43,145,175)}
+span#textcolor2790{color:rgb(0,0,255)}
+span#textcolor2791{color:rgb(0,0,255)}
span#textcolor2792{color:rgb(0,0,255)}
-span#textcolor2793{color:rgb(0,127,0)}
-span#textcolor2794{color:rgb(0,0,255)}
-span#textcolor2795{color:rgb(0,127,0)}
-span#textcolor2796{color:rgb(0,0,255)}
-span#textcolor2797{color:rgb(0,0,255)}
-span#textcolor2798{color:rgb(43,145,175)}
-span#textcolor2799{color:rgb(43,145,175)}
-span#textcolor2800{color:rgb(43,145,175)}
-span#textcolor2801{color:rgb(43,145,175)}
-span#textcolor2802{color:rgb(43,145,175)}
-span#textcolor2803{color:rgb(163,20,20)}
-span#textcolor2804{color:rgb(163,20,20)}
-span#textcolor2805{color:rgb(163,20,20)}
-span#textcolor2806{color:rgb(163,20,20)}
-span#textcolor2807{color:rgb(163,20,20)}
-span#textcolor2808{color:rgb(0,0,255)}
-span#textcolor2809{color:rgb(163,20,20)}
-span#textcolor2810{color:rgb(43,145,175)}
-span#textcolor2811{color:rgb(43,145,175)}
-span#textcolor2812{color:rgb(163,20,20)}
-span#textcolor2813{color:rgb(163,20,20)}
-span#textcolor2814{color:rgb(163,20,20)}
-span#textcolor2815{color:rgb(0,0,255)}
-span#textcolor2816{color:rgb(43,145,175)}
-span#textcolor2817{color:rgb(43,145,175)}
-span#textcolor2818{color:rgb(43,145,175)}
-span#textcolor2819{color:rgb(163,20,20)}
-span#textcolor2820{color:rgb(43,145,175)}
-span#textcolor2821{color:rgb(0,0,255)}
-span#textcolor2822{color:rgb(0,0,255)}
-span#textcolor2823{color:rgb(163,20,20)}
-span#textcolor2824{color:rgb(0,0,255)}
-span#textcolor2825{color:rgb(163,20,20)}
-span#textcolor2826{color:rgb(163,20,20)}
-span#textcolor2827{color:rgb(163,20,20)}
-span#textcolor2828{color:rgb(0,0,255)}
-span#textcolor2829{color:rgb(0,0,255)}
-span#textcolor2830{color:rgb(0,0,255)}
-span#textcolor2831{color:rgb(0,0,255)}
-span#textcolor2832{color:rgb(0,0,255)}
-span#textcolor2833{color:rgb(0,0,255)}
-span#textcolor2834{color:rgb(0,0,255)}
-span#textcolor2835{color:rgb(0,0,255)}
-span#textcolor2836{color:rgb(0,0,255)}
-span#textcolor2837{color:rgb(0,0,255)}
-span#textcolor2838{color:rgb(0,0,255)}
-span#textcolor2839{color:rgb(0,0,255)}
-span#textcolor2840{color:rgb(0,0,255)}
-span#textcolor2841{color:rgb(43,145,175)}
-span#textcolor2842{color:rgb(43,145,175)}
-span#textcolor2843{color:rgb(163,20,20)}
-span#textcolor2844{color:rgb(163,20,20)}
pre#fancyvrb83{padding:5.69054pt;}
pre#fancyvrb83{ border-top: solid 0.4pt; }
pre#fancyvrb83{ border-left: solid 0.4pt; }
pre#fancyvrb83{ border-bottom: solid 0.4pt; }
pre#fancyvrb83{ border-right: solid 0.4pt; }
+span#textcolor2793{color:rgb(43,145,175)}
+span#textcolor2794{color:rgb(0,0,255)}
+span#textcolor2795{color:rgb(43,145,175)}
+span#textcolor2796{color:rgb(43,145,175)}
pre#fancyvrb84{padding:5.69054pt;}
pre#fancyvrb84{ border-top: solid 0.4pt; }
pre#fancyvrb84{ border-left: solid 0.4pt; }
pre#fancyvrb84{ border-bottom: solid 0.4pt; }
pre#fancyvrb84{ border-right: solid 0.4pt; }
+span#textcolor2797{color:rgb(43,145,175)}
+span#textcolor2798{color:rgb(0,0,255)}
+span#textcolor2799{color:rgb(43,145,175)}
+span#textcolor2800{color:rgb(43,145,175)}
pre#fancyvrb85{padding:5.69054pt;}
pre#fancyvrb85{ border-top: solid 0.4pt; }
pre#fancyvrb85{ border-left: solid 0.4pt; }
pre#fancyvrb85{ border-bottom: solid 0.4pt; }
pre#fancyvrb85{ border-right: solid 0.4pt; }
-span#textcolor2845{color:rgb(0,127,0)}
-span#textcolor2846{color:rgb(0,127,0)}
-span#textcolor2847{color:rgb(0,127,0)}
-span#textcolor2848{color:rgb(0,0,255)}
-span#textcolor2849{color:rgb(0,127,0)}
-span#textcolor2850{color:rgb(0,0,255)}
-span#textcolor2851{color:rgb(0,127,0)}
+span#textcolor2801{color:rgb(0,0,255)}
+span#textcolor2802{color:rgb(0,0,255)}
+span#textcolor2803{color:rgb(43,145,175)}
+span#textcolor2804{color:rgb(0,0,255)}
+span#textcolor2805{color:rgb(0,0,255)}
+span#textcolor2806{color:rgb(43,145,175)}
+span#textcolor2807{color:rgb(43,145,175)}
+span#textcolor2808{color:rgb(0,0,255)}
+span#textcolor2809{color:rgb(0,0,255)}
+span#textcolor2810{color:rgb(0,0,255)}
+span#textcolor2811{color:rgb(43,145,175)}
+span#textcolor2812{color:rgb(43,145,175)}
+span#textcolor2813{color:rgb(0,0,255)}
+pre#fancyvrb86{padding:5.69054pt;}
+pre#fancyvrb86{ border-top: solid 0.4pt; }
+pre#fancyvrb86{ border-left: solid 0.4pt; }
+pre#fancyvrb86{ border-bottom: solid 0.4pt; }
+pre#fancyvrb86{ border-right: solid 0.4pt; }
+span#textcolor2814{color:rgb(163,20,20)}
+pre#fancyvrb87{padding:5.69054pt;}
+pre#fancyvrb87{ border-top: solid 0.4pt; }
+pre#fancyvrb87{ border-left: solid 0.4pt; }
+pre#fancyvrb87{ border-bottom: solid 0.4pt; }
+pre#fancyvrb87{ border-right: solid 0.4pt; }
+span#textcolor2815{color:rgb(163,20,20)}
+pre#fancyvrb88{padding:5.69054pt;}
+pre#fancyvrb88{ border-top: solid 0.4pt; }
+pre#fancyvrb88{ border-left: solid 0.4pt; }
+pre#fancyvrb88{ border-bottom: solid 0.4pt; }
+pre#fancyvrb88{ border-right: solid 0.4pt; }
+span#textcolor2816{color:rgb(0,127,0)}
+span#textcolor2817{color:rgb(0,127,0)}
+span#textcolor2818{color:rgb(0,127,0)}
+span#textcolor2819{color:rgb(0,0,255)}
+span#textcolor2820{color:rgb(0,0,255)}
+span#textcolor2821{color:rgb(0,0,255)}
+span#textcolor2822{color:rgb(0,127,0)}
+span#textcolor2823{color:rgb(0,0,255)}
+span#textcolor2824{color:rgb(0,127,0)}
+span#textcolor2825{color:rgb(0,0,255)}
+span#textcolor2826{color:rgb(0,0,255)}
+span#textcolor2827{color:rgb(0,0,255)}
+span#textcolor2828{color:rgb(0,0,255)}
+span#textcolor2829{color:rgb(0,0,255)}
+span#textcolor2830{color:rgb(0,0,255)}
+span#textcolor2831{color:rgb(43,145,175)}
+span#textcolor2832{color:rgb(43,145,175)}
+span#textcolor2833{color:rgb(43,145,175)}
+span#textcolor2834{color:rgb(43,145,175)}
+span#textcolor2835{color:rgb(0,0,255)}
+span#textcolor2836{color:rgb(0,0,255)}
+span#textcolor2837{color:rgb(0,0,255)}
+span#textcolor2838{color:rgb(0,0,255)}
+span#textcolor2839{color:rgb(0,0,255)}
+span#textcolor2840{color:rgb(43,145,175)}
+span#textcolor2841{color:rgb(0,0,255)}
+span#textcolor2842{color:rgb(43,145,175)}
+span#textcolor2843{color:rgb(0,0,255)}
+span#textcolor2844{color:rgb(43,145,175)}
+span#textcolor2845{color:rgb(0,0,255)}
+span#textcolor2846{color:rgb(43,145,175)}
+span#textcolor2847{color:rgb(43,145,175)}
+span#textcolor2848{color:rgb(43,145,175)}
+span#textcolor2849{color:rgb(0,0,255)}
+span#textcolor2850{color:rgb(43,145,175)}
+span#textcolor2851{color:rgb(43,145,175)}
span#textcolor2852{color:rgb(0,0,255)}
-span#textcolor2853{color:rgb(0,127,0)}
+span#textcolor2853{color:rgb(43,145,175)}
span#textcolor2854{color:rgb(0,0,255)}
-span#textcolor2855{color:rgb(0,127,0)}
-span#textcolor2856{color:rgb(0,0,255)}
-span#textcolor2857{color:rgb(0,127,0)}
-span#textcolor2858{color:rgb(0,0,255)}
+span#textcolor2855{color:rgb(0,0,255)}
+span#textcolor2856{color:rgb(43,145,175)}
+span#textcolor2857{color:rgb(0,0,255)}
+span#textcolor2858{color:rgb(43,145,175)}
span#textcolor2859{color:rgb(0,0,255)}
span#textcolor2860{color:rgb(0,0,255)}
-span#textcolor2861{color:rgb(0,0,255)}
-span#textcolor2862{color:rgb(43,145,175)}
-span#textcolor2863{color:rgb(0,0,255)}
+pre#fancyvrb89{padding:5.69054pt;}
+pre#fancyvrb89{ border-top: solid 0.4pt; }
+pre#fancyvrb89{ border-left: solid 0.4pt; }
+pre#fancyvrb89{ border-bottom: solid 0.4pt; }
+pre#fancyvrb89{ border-right: solid 0.4pt; }
+span#textcolor2861{color:rgb(0,127,0)}
+span#textcolor2862{color:rgb(0,127,0)}
+span#textcolor2863{color:rgb(0,127,0)}
span#textcolor2864{color:rgb(0,0,255)}
-span#textcolor2865{color:rgb(0,0,255)}
+span#textcolor2865{color:rgb(0,127,0)}
span#textcolor2866{color:rgb(0,0,255)}
-span#textcolor2867{color:rgb(0,0,255)}
-span#textcolor2868{color:rgb(43,145,175)}
-span#textcolor2869{color:rgb(43,145,175)}
-span#textcolor2870{color:rgb(43,145,175)}
-span#textcolor2871{color:rgb(0,0,255)}
+span#textcolor2867{color:rgb(0,127,0)}
+span#textcolor2868{color:rgb(0,0,255)}
+span#textcolor2869{color:rgb(0,127,0)}
+span#textcolor2870{color:rgb(0,0,255)}
+span#textcolor2871{color:rgb(0,127,0)}
span#textcolor2872{color:rgb(0,0,255)}
-span#textcolor2873{color:rgb(0,0,255)}
-span#textcolor2874{color:rgb(43,145,175)}
-span#textcolor2875{color:rgb(0,0,255)}
+span#textcolor2873{color:rgb(0,127,0)}
+span#textcolor2874{color:rgb(0,0,255)}
+span#textcolor2875{color:rgb(0,127,0)}
span#textcolor2876{color:rgb(0,0,255)}
-span#textcolor2877{color:rgb(0,0,255)}
+span#textcolor2877{color:rgb(0,127,0)}
span#textcolor2878{color:rgb(0,0,255)}
span#textcolor2879{color:rgb(0,0,255)}
span#textcolor2880{color:rgb(0,0,255)}
span#textcolor2881{color:rgb(0,0,255)}
-span#textcolor2882{color:rgb(43,145,175)}
+span#textcolor2882{color:rgb(0,0,255)}
span#textcolor2883{color:rgb(0,0,255)}
span#textcolor2884{color:rgb(43,145,175)}
span#textcolor2885{color:rgb(0,0,255)}
span#textcolor2886{color:rgb(0,0,255)}
span#textcolor2887{color:rgb(0,0,255)}
span#textcolor2888{color:rgb(0,0,255)}
-span#textcolor2889{color:rgb(0,0,255)}
-span#textcolor2890{color:rgb(0,0,255)}
-span#textcolor2891{color:rgb(0,0,255)}
-span#textcolor2892{color:rgb(163,20,20)}
-span#textcolor2893{color:rgb(163,20,20)}
-span#textcolor2894{color:rgb(163,20,20)}
-span#textcolor2895{color:rgb(0,0,255)}
-span#textcolor2896{color:rgb(0,0,255)}
-span#textcolor2897{color:rgb(163,20,20)}
-span#textcolor2898{color:rgb(163,20,20)}
-span#textcolor2899{color:rgb(163,20,20)}
+span#textcolor2889{color:rgb(0,127,0)}
+span#textcolor2890{color:rgb(0,127,0)}
+span#textcolor2891{color:rgb(0,127,0)}
+span#textcolor2892{color:rgb(0,0,255)}
+span#textcolor2893{color:rgb(0,0,255)}
+span#textcolor2894{color:rgb(0,0,255)}
+span#textcolor2895{color:rgb(43,145,175)}
+span#textcolor2896{color:rgb(43,145,175)}
+span#textcolor2897{color:rgb(0,0,255)}
+span#textcolor2898{color:rgb(0,0,255)}
+span#textcolor2899{color:rgb(0,0,255)}
span#textcolor2900{color:rgb(0,0,255)}
span#textcolor2901{color:rgb(0,0,255)}
span#textcolor2902{color:rgb(0,0,255)}
-span#textcolor2903{color:rgb(43,145,175)}
+span#textcolor2903{color:rgb(0,0,255)}
span#textcolor2904{color:rgb(0,0,255)}
-span#textcolor2905{color:rgb(43,145,175)}
-span#textcolor2906{color:rgb(0,0,255)}
-span#textcolor2907{color:rgb(0,0,255)}
+span#textcolor2905{color:rgb(0,127,0)}
+span#textcolor2906{color:rgb(0,127,0)}
+span#textcolor2907{color:rgb(0,127,0)}
span#textcolor2908{color:rgb(0,0,255)}
-span#textcolor2909{color:rgb(163,20,20)}
-span#textcolor2910{color:rgb(163,20,20)}
-span#textcolor2911{color:rgb(163,20,20)}
-span#textcolor2912{color:rgb(0,127,0)}
+span#textcolor2909{color:rgb(0,0,255)}
+span#textcolor2910{color:rgb(43,145,175)}
+span#textcolor2911{color:rgb(0,0,255)}
+span#textcolor2912{color:rgb(0,0,255)}
span#textcolor2913{color:rgb(0,0,255)}
-span#textcolor2914{color:rgb(0,127,0)}
-span#textcolor2915{color:rgb(0,127,0)}
-span#textcolor2916{color:rgb(0,127,0)}
-span#textcolor2917{color:rgb(0,127,0)}
-span#textcolor2918{color:rgb(0,127,0)}
-span#textcolor2919{color:rgb(0,127,0)}
-span#textcolor2920{color:rgb(0,127,0)}
-span#textcolor2921{color:rgb(0,127,0)}
-span#textcolor2922{color:rgb(0,127,0)}
-span#textcolor2923{color:rgb(0,0,255)}
+span#textcolor2914{color:rgb(0,0,255)}
+span#textcolor2915{color:rgb(0,0,255)}
+span#textcolor2916{color:rgb(0,0,255)}
+span#textcolor2917{color:rgb(0,0,255)}
+span#textcolor2918{color:rgb(0,0,255)}
+span#textcolor2919{color:rgb(0,0,255)}
+span#textcolor2920{color:rgb(43,145,175)}
+span#textcolor2921{color:rgb(0,0,255)}
+span#textcolor2922{color:rgb(0,0,255)}
+span#textcolor2923{color:rgb(43,145,175)}
span#textcolor2924{color:rgb(0,0,255)}
-span#textcolor2925{color:rgb(43,145,175)}
-span#textcolor2926{color:rgb(43,145,175)}
-span#textcolor2927{color:rgb(43,145,175)}
+span#textcolor2925{color:rgb(0,0,255)}
+span#textcolor2926{color:rgb(0,0,255)}
+span#textcolor2927{color:rgb(0,0,255)}
span#textcolor2928{color:rgb(0,0,255)}
span#textcolor2929{color:rgb(43,145,175)}
-span#textcolor2930{color:rgb(43,145,175)}
-span#textcolor2931{color:rgb(43,145,175)}
+span#textcolor2930{color:rgb(0,0,255)}
+span#textcolor2931{color:rgb(0,0,255)}
span#textcolor2932{color:rgb(0,0,255)}
-span#textcolor2933{color:rgb(163,20,20)}
-span#textcolor2934{color:rgb(0,0,255)}
-span#textcolor2935{color:rgb(163,20,20)}
-span#textcolor2936{color:rgb(163,20,20)}
-span#textcolor2937{color:rgb(163,20,20)}
-span#textcolor2938{color:rgb(0,0,255)}
-span#textcolor2939{color:rgb(0,0,255)}
+span#textcolor2933{color:rgb(0,0,255)}
+span#textcolor2934{color:rgb(43,145,175)}
+span#textcolor2935{color:rgb(0,0,255)}
+span#textcolor2936{color:rgb(43,145,175)}
+span#textcolor2937{color:rgb(43,145,175)}
+span#textcolor2938{color:rgb(43,145,175)}
+span#textcolor2939{color:rgb(43,145,175)}
span#textcolor2940{color:rgb(0,0,255)}
-span#textcolor2941{color:rgb(163,20,20)}
-span#textcolor2942{color:rgb(163,20,20)}
-span#textcolor2943{color:rgb(163,20,20)}
+span#textcolor2941{color:rgb(0,0,255)}
+span#textcolor2942{color:rgb(0,0,255)}
+span#textcolor2943{color:rgb(0,0,255)}
span#textcolor2944{color:rgb(0,0,255)}
-span#textcolor2945{color:rgb(0,127,0)}
-span#textcolor2946{color:rgb(43,145,175)}
-span#textcolor2947{color:rgb(163,20,20)}
-span#textcolor2948{color:rgb(0,127,0)}
-span#textcolor2949{color:rgb(43,145,175)}
-span#textcolor2950{color:rgb(163,20,20)}
-span#textcolor2951{color:rgb(0,127,0)}
-span#textcolor2952{color:rgb(0,0,255)}
-span#textcolor2953{color:rgb(163,20,20)}
-span#textcolor2954{color:rgb(163,20,20)}
-span#textcolor2955{color:rgb(163,20,20)}
+span#textcolor2945{color:rgb(0,0,255)}
+span#textcolor2946{color:rgb(0,0,255)}
+span#textcolor2947{color:rgb(43,145,175)}
+span#textcolor2948{color:rgb(0,0,255)}
+span#textcolor2949{color:rgb(0,0,255)}
+span#textcolor2950{color:rgb(43,145,175)}
+span#textcolor2951{color:rgb(43,145,175)}
+span#textcolor2952{color:rgb(43,145,175)}
+span#textcolor2953{color:rgb(0,0,255)}
+span#textcolor2954{color:rgb(0,0,255)}
+span#textcolor2955{color:rgb(43,145,175)}
span#textcolor2956{color:rgb(0,0,255)}
span#textcolor2957{color:rgb(163,20,20)}
span#textcolor2958{color:rgb(163,20,20)}
span#textcolor2959{color:rgb(163,20,20)}
-span#textcolor2960{color:rgb(163,20,20)}
-span#textcolor2961{color:rgb(163,20,20)}
-span#textcolor2962{color:rgb(163,20,20)}
+span#textcolor2960{color:rgb(0,0,255)}
+span#textcolor2961{color:rgb(0,0,255)}
+span#textcolor2962{color:rgb(0,0,255)}
span#textcolor2963{color:rgb(0,0,255)}
-span#textcolor2964{color:rgb(0,127,0)}
+span#textcolor2964{color:rgb(0,0,255)}
span#textcolor2965{color:rgb(0,0,255)}
-span#textcolor2966{color:rgb(163,20,20)}
-span#textcolor2967{color:rgb(163,20,20)}
-span#textcolor2968{color:rgb(163,20,20)}
+span#textcolor2966{color:rgb(0,0,255)}
+span#textcolor2967{color:rgb(0,0,255)}
+span#textcolor2968{color:rgb(43,145,175)}
span#textcolor2969{color:rgb(0,0,255)}
span#textcolor2970{color:rgb(0,0,255)}
-span#textcolor2971{color:rgb(0,127,0)}
-span#textcolor2972{color:rgb(0,0,255)}
-span#textcolor2973{color:rgb(163,20,20)}
-span#textcolor2974{color:rgb(163,20,20)}
-span#textcolor2975{color:rgb(163,20,20)}
-span#textcolor2976{color:rgb(0,0,255)}
-span#textcolor2977{color:rgb(43,145,175)}
-span#textcolor2978{color:rgb(163,20,20)}
-span#textcolor2979{color:rgb(0,127,0)}
-span#textcolor2980{color:rgb(0,0,255)}
-span#textcolor2981{color:rgb(0,0,255)}
+span#textcolor2971{color:rgb(0,0,255)}
+span#textcolor2972{color:rgb(43,145,175)}
+span#textcolor2973{color:rgb(0,0,255)}
+span#textcolor2974{color:rgb(0,127,0)}
+span#textcolor2975{color:rgb(0,0,255)}
+span#textcolor2976{color:rgb(43,145,175)}
+span#textcolor2977{color:rgb(0,0,255)}
+span#textcolor2978{color:rgb(0,0,255)}
+span#textcolor2979{color:rgb(43,145,175)}
+span#textcolor2980{color:rgb(163,20,20)}
+span#textcolor2981{color:rgb(163,20,20)}
span#textcolor2982{color:rgb(163,20,20)}
-span#textcolor2983{color:rgb(163,20,20)}
-span#textcolor2984{color:rgb(163,20,20)}
-span#textcolor2985{color:rgb(0,0,255)}
-span#textcolor2986{color:rgb(0,0,255)}
-span#textcolor2987{color:rgb(43,145,175)}
-span#textcolor2988{color:rgb(43,145,175)}
-span#textcolor2989{color:rgb(0,127,0)}
-span#textcolor2990{color:rgb(43,145,175)}
-span#textcolor2991{color:rgb(163,20,20)}
-span#textcolor2992{color:rgb(163,20,20)}
+span#textcolor2983{color:rgb(0,0,255)}
+span#textcolor2984{color:rgb(0,0,255)}
+span#textcolor2985{color:rgb(43,145,175)}
+span#textcolor2986{color:rgb(43,145,175)}
+span#textcolor2987{color:rgb(0,0,255)}
+span#textcolor2988{color:rgb(0,0,255)}
+span#textcolor2989{color:rgb(0,0,255)}
+span#textcolor2990{color:rgb(0,0,255)}
+span#textcolor2991{color:rgb(0,0,255)}
+span#textcolor2992{color:rgb(0,0,255)}
span#textcolor2993{color:rgb(0,0,255)}
-span#textcolor2994{color:rgb(0,0,255)}
-span#textcolor2995{color:rgb(43,145,175)}
-span#textcolor2996{color:rgb(43,145,175)}
+span#textcolor2994{color:rgb(0,127,0)}
+span#textcolor2995{color:rgb(0,0,255)}
+span#textcolor2996{color:rgb(163,20,20)}
span#textcolor2997{color:rgb(163,20,20)}
span#textcolor2998{color:rgb(163,20,20)}
-pre#fancyvrb86{padding:5.69054pt;}
-pre#fancyvrb86{ border-top: solid 0.4pt; }
-pre#fancyvrb86{ border-left: solid 0.4pt; }
-pre#fancyvrb86{ border-bottom: solid 0.4pt; }
-pre#fancyvrb86{ border-right: solid 0.4pt; }
-span#textcolor2999{color:rgb(43,145,175)}
-span#textcolor3000{color:rgb(0,0,255)}
-span#textcolor3001{color:rgb(0,0,255)}
+span#textcolor2999{color:rgb(0,0,255)}
+span#textcolor3000{color:rgb(0,127,0)}
+span#textcolor3001{color:rgb(163,20,20)}
span#textcolor3002{color:rgb(0,0,255)}
-pre#fancyvrb87{padding:5.69054pt;}
-pre#fancyvrb87{ border-top: solid 0.4pt; }
-pre#fancyvrb87{ border-left: solid 0.4pt; }
-pre#fancyvrb87{ border-bottom: solid 0.4pt; }
-pre#fancyvrb87{ border-right: solid 0.4pt; }
-span#textcolor3003{color:rgb(43,145,175)}
+span#textcolor3003{color:rgb(0,0,255)}
span#textcolor3004{color:rgb(0,0,255)}
span#textcolor3005{color:rgb(43,145,175)}
-span#textcolor3006{color:rgb(43,145,175)}
-pre#fancyvrb88{padding:5.69054pt;}
-pre#fancyvrb88{ border-top: solid 0.4pt; }
-pre#fancyvrb88{ border-left: solid 0.4pt; }
-pre#fancyvrb88{ border-bottom: solid 0.4pt; }
-pre#fancyvrb88{ border-right: solid 0.4pt; }
+span#textcolor3006{color:rgb(0,0,255)}
span#textcolor3007{color:rgb(43,145,175)}
-span#textcolor3008{color:rgb(0,0,255)}
-span#textcolor3009{color:rgb(43,145,175)}
-span#textcolor3010{color:rgb(43,145,175)}
-pre#fancyvrb89{padding:5.69054pt;}
-pre#fancyvrb89{ border-top: solid 0.4pt; }
-pre#fancyvrb89{ border-left: solid 0.4pt; }
-pre#fancyvrb89{ border-bottom: solid 0.4pt; }
-pre#fancyvrb89{ border-right: solid 0.4pt; }
-span#textcolor3011{color:rgb(0,0,255)}
-span#textcolor3012{color:rgb(0,0,255)}
-span#textcolor3013{color:rgb(43,145,175)}
+span#textcolor3008{color:rgb(0,127,0)}
+span#textcolor3009{color:rgb(163,20,20)}
+span#textcolor3010{color:rgb(0,0,255)}
+span#textcolor3011{color:rgb(163,20,20)}
+span#textcolor3012{color:rgb(163,20,20)}
+span#textcolor3013{color:rgb(163,20,20)}
span#textcolor3014{color:rgb(0,0,255)}
span#textcolor3015{color:rgb(0,0,255)}
span#textcolor3016{color:rgb(43,145,175)}
-span#textcolor3017{color:rgb(43,145,175)}
+span#textcolor3017{color:rgb(0,0,255)}
span#textcolor3018{color:rgb(0,0,255)}
span#textcolor3019{color:rgb(0,0,255)}
-span#textcolor3020{color:rgb(0,0,255)}
+span#textcolor3020{color:rgb(43,145,175)}
span#textcolor3021{color:rgb(43,145,175)}
span#textcolor3022{color:rgb(43,145,175)}
span#textcolor3023{color:rgb(0,0,255)}
-pre#fancyvrb90{padding:5.69054pt;}
-pre#fancyvrb90{ border-top: solid 0.4pt; }
-pre#fancyvrb90{ border-left: solid 0.4pt; }
-pre#fancyvrb90{ border-bottom: solid 0.4pt; }
-pre#fancyvrb90{ border-right: solid 0.4pt; }
-span#textcolor3024{color:rgb(163,20,20)}
-pre#fancyvrb91{padding:5.69054pt;}
-pre#fancyvrb91{ border-top: solid 0.4pt; }
-pre#fancyvrb91{ border-left: solid 0.4pt; }
-pre#fancyvrb91{ border-bottom: solid 0.4pt; }
-pre#fancyvrb91{ border-right: solid 0.4pt; }
-span#textcolor3025{color:rgb(163,20,20)}
-pre#fancyvrb92{padding:5.69054pt;}
-pre#fancyvrb92{ border-top: solid 0.4pt; }
-pre#fancyvrb92{ border-left: solid 0.4pt; }
-pre#fancyvrb92{ border-bottom: solid 0.4pt; }
-pre#fancyvrb92{ border-right: solid 0.4pt; }
-span#textcolor3026{color:rgb(0,127,0)}
-span#textcolor3027{color:rgb(0,127,0)}
-span#textcolor3028{color:rgb(0,127,0)}
+span#textcolor3024{color:rgb(0,0,255)}
+span#textcolor3025{color:rgb(0,0,255)}
+span#textcolor3026{color:rgb(163,20,20)}
+span#textcolor3027{color:rgb(163,20,20)}
+span#textcolor3028{color:rgb(163,20,20)}
span#textcolor3029{color:rgb(0,0,255)}
span#textcolor3030{color:rgb(0,0,255)}
span#textcolor3031{color:rgb(0,0,255)}
-span#textcolor3032{color:rgb(0,127,0)}
+span#textcolor3032{color:rgb(0,0,255)}
span#textcolor3033{color:rgb(0,0,255)}
-span#textcolor3034{color:rgb(0,127,0)}
+span#textcolor3034{color:rgb(0,0,255)}
span#textcolor3035{color:rgb(0,0,255)}
span#textcolor3036{color:rgb(0,0,255)}
span#textcolor3037{color:rgb(0,0,255)}
-span#textcolor3038{color:rgb(0,0,255)}
+span#textcolor3038{color:rgb(0,127,0)}
span#textcolor3039{color:rgb(0,0,255)}
span#textcolor3040{color:rgb(0,0,255)}
span#textcolor3041{color:rgb(43,145,175)}
-span#textcolor3042{color:rgb(43,145,175)}
-span#textcolor3043{color:rgb(43,145,175)}
-span#textcolor3044{color:rgb(43,145,175)}
-span#textcolor3045{color:rgb(0,0,255)}
-span#textcolor3046{color:rgb(0,0,255)}
-span#textcolor3047{color:rgb(0,0,255)}
-span#textcolor3048{color:rgb(0,0,255)}
-span#textcolor3049{color:rgb(0,0,255)}
-span#textcolor3050{color:rgb(43,145,175)}
+span#textcolor3042{color:rgb(0,0,255)}
+span#textcolor3043{color:rgb(0,0,255)}
+span#textcolor3044{color:rgb(0,0,255)}
+span#textcolor3045{color:rgb(43,145,175)}
+span#textcolor3046{color:rgb(43,145,175)}
+span#textcolor3047{color:rgb(43,145,175)}
+span#textcolor3048{color:rgb(43,145,175)}
+span#textcolor3049{color:rgb(43,145,175)}
+span#textcolor3050{color:rgb(0,0,255)}
span#textcolor3051{color:rgb(0,0,255)}
-span#textcolor3052{color:rgb(43,145,175)}
+span#textcolor3052{color:rgb(0,0,255)}
span#textcolor3053{color:rgb(0,0,255)}
-span#textcolor3054{color:rgb(43,145,175)}
-span#textcolor3055{color:rgb(0,0,255)}
-span#textcolor3056{color:rgb(43,145,175)}
-span#textcolor3057{color:rgb(43,145,175)}
-span#textcolor3058{color:rgb(43,145,175)}
+span#textcolor3054{color:rgb(163,20,20)}
+span#textcolor3055{color:rgb(163,20,20)}
+span#textcolor3056{color:rgb(163,20,20)}
+span#textcolor3057{color:rgb(0,0,255)}
+span#textcolor3058{color:rgb(0,0,255)}
span#textcolor3059{color:rgb(0,0,255)}
-span#textcolor3060{color:rgb(43,145,175)}
-span#textcolor3061{color:rgb(43,145,175)}
+span#textcolor3060{color:rgb(0,127,0)}
+span#textcolor3061{color:rgb(0,0,255)}
span#textcolor3062{color:rgb(0,0,255)}
-span#textcolor3063{color:rgb(43,145,175)}
-span#textcolor3064{color:rgb(0,0,255)}
+span#textcolor3063{color:rgb(0,0,255)}
+span#textcolor3064{color:rgb(0,127,0)}
span#textcolor3065{color:rgb(0,0,255)}
-span#textcolor3066{color:rgb(43,145,175)}
-span#textcolor3067{color:rgb(0,0,255)}
+span#textcolor3066{color:rgb(0,0,255)}
+span#textcolor3067{color:rgb(163,20,20)}
span#textcolor3068{color:rgb(43,145,175)}
span#textcolor3069{color:rgb(0,0,255)}
-span#textcolor3070{color:rgb(0,0,255)}
-pre#fancyvrb93{padding:5.69054pt;}
-pre#fancyvrb93{ border-top: solid 0.4pt; }
-pre#fancyvrb93{ border-left: solid 0.4pt; }
-pre#fancyvrb93{ border-bottom: solid 0.4pt; }
-pre#fancyvrb93{ border-right: solid 0.4pt; }
-span#textcolor3071{color:rgb(0,127,0)}
-span#textcolor3072{color:rgb(0,127,0)}
-span#textcolor3073{color:rgb(0,127,0)}
-span#textcolor3074{color:rgb(0,0,255)}
-span#textcolor3075{color:rgb(0,127,0)}
+span#textcolor3070{color:rgb(163,20,20)}
+span#textcolor3071{color:rgb(163,20,20)}
+span#textcolor3072{color:rgb(163,20,20)}
+span#textcolor3073{color:rgb(0,0,255)}
+span#textcolor3074{color:rgb(43,145,175)}
+span#textcolor3075{color:rgb(0,0,255)}
span#textcolor3076{color:rgb(0,0,255)}
span#textcolor3077{color:rgb(0,127,0)}
-span#textcolor3078{color:rgb(0,0,255)}
-span#textcolor3079{color:rgb(0,127,0)}
+span#textcolor3078{color:rgb(0,127,0)}
+span#textcolor3079{color:rgb(0,0,255)}
span#textcolor3080{color:rgb(0,0,255)}
-span#textcolor3081{color:rgb(0,127,0)}
-span#textcolor3082{color:rgb(0,0,255)}
-span#textcolor3083{color:rgb(0,127,0)}
-span#textcolor3084{color:rgb(0,0,255)}
-span#textcolor3085{color:rgb(0,127,0)}
-span#textcolor3086{color:rgb(0,0,255)}
-span#textcolor3087{color:rgb(0,127,0)}
-span#textcolor3088{color:rgb(0,0,255)}
-span#textcolor3089{color:rgb(0,0,255)}
-span#textcolor3090{color:rgb(0,0,255)}
-span#textcolor3091{color:rgb(0,0,255)}
+span#textcolor3081{color:rgb(0,0,255)}
+span#textcolor3082{color:rgb(163,20,20)}
+span#textcolor3083{color:rgb(163,20,20)}
+span#textcolor3084{color:rgb(163,20,20)}
+span#textcolor3085{color:rgb(0,0,255)}
+span#textcolor3086{color:rgb(43,145,175)}
+span#textcolor3087{color:rgb(43,145,175)}
+span#textcolor3088{color:rgb(43,145,175)}
+span#textcolor3089{color:rgb(163,20,20)}
+span#textcolor3090{color:rgb(163,20,20)}
+span#textcolor3091{color:rgb(163,20,20)}
span#textcolor3092{color:rgb(0,0,255)}
-span#textcolor3093{color:rgb(0,0,255)}
-span#textcolor3094{color:rgb(43,145,175)}
-span#textcolor3095{color:rgb(0,0,255)}
+span#textcolor3093{color:rgb(163,20,20)}
+span#textcolor3094{color:rgb(163,20,20)}
+span#textcolor3095{color:rgb(163,20,20)}
span#textcolor3096{color:rgb(0,0,255)}
span#textcolor3097{color:rgb(0,0,255)}
-span#textcolor3098{color:rgb(0,0,255)}
-span#textcolor3099{color:rgb(0,127,0)}
-span#textcolor3100{color:rgb(0,127,0)}
-span#textcolor3101{color:rgb(0,127,0)}
+span#textcolor3098{color:rgb(163,20,20)}
+span#textcolor3099{color:rgb(163,20,20)}
+span#textcolor3100{color:rgb(163,20,20)}
+span#textcolor3101{color:rgb(0,0,255)}
span#textcolor3102{color:rgb(0,0,255)}
span#textcolor3103{color:rgb(0,0,255)}
span#textcolor3104{color:rgb(0,0,255)}
span#textcolor3105{color:rgb(43,145,175)}
span#textcolor3106{color:rgb(43,145,175)}
-span#textcolor3107{color:rgb(0,0,255)}
-span#textcolor3108{color:rgb(0,0,255)}
-span#textcolor3109{color:rgb(0,0,255)}
-span#textcolor3110{color:rgb(0,0,255)}
-span#textcolor3111{color:rgb(0,0,255)}
-span#textcolor3112{color:rgb(0,0,255)}
-span#textcolor3113{color:rgb(0,0,255)}
-span#textcolor3114{color:rgb(0,0,255)}
+span#textcolor3107{color:rgb(163,20,20)}
+span#textcolor3108{color:rgb(163,20,20)}
+span#textcolor3109{color:rgb(163,20,20)}
+span#textcolor3110{color:rgb(163,20,20)}
+span#textcolor3111{color:rgb(163,20,20)}
+pre#fancyvrb90{padding:5.69054pt;}
+pre#fancyvrb90{ border-top: solid 0.4pt; }
+pre#fancyvrb90{ border-left: solid 0.4pt; }
+pre#fancyvrb90{ border-bottom: solid 0.4pt; }
+pre#fancyvrb90{ border-right: solid 0.4pt; }
+span#textcolor3112{color:rgb(163,20,20)}
+pre#fancyvrb91{padding:5.69054pt;}
+pre#fancyvrb91{ border-top: solid 0.4pt; }
+pre#fancyvrb91{ border-left: solid 0.4pt; }
+pre#fancyvrb91{ border-bottom: solid 0.4pt; }
+pre#fancyvrb91{ border-right: solid 0.4pt; }
+span#textcolor3113{color:rgb(163,20,20)}
+pre#fancyvrb92{padding:5.69054pt;}
+pre#fancyvrb92{ border-top: solid 0.4pt; }
+pre#fancyvrb92{ border-left: solid 0.4pt; }
+pre#fancyvrb92{ border-bottom: solid 0.4pt; }
+pre#fancyvrb92{ border-right: solid 0.4pt; }
+span#textcolor3114{color:rgb(0,127,0)}
span#textcolor3115{color:rgb(0,127,0)}
span#textcolor3116{color:rgb(0,127,0)}
-span#textcolor3117{color:rgb(0,127,0)}
-span#textcolor3118{color:rgb(0,0,255)}
+span#textcolor3117{color:rgb(0,0,255)}
+span#textcolor3118{color:rgb(0,127,0)}
span#textcolor3119{color:rgb(0,0,255)}
-span#textcolor3120{color:rgb(43,145,175)}
+span#textcolor3120{color:rgb(0,127,0)}
span#textcolor3121{color:rgb(0,0,255)}
-span#textcolor3122{color:rgb(0,0,255)}
+span#textcolor3122{color:rgb(0,127,0)}
span#textcolor3123{color:rgb(0,0,255)}
-span#textcolor3124{color:rgb(0,0,255)}
+span#textcolor3124{color:rgb(0,127,0)}
span#textcolor3125{color:rgb(0,0,255)}
-span#textcolor3126{color:rgb(0,0,255)}
+span#textcolor3126{color:rgb(0,127,0)}
span#textcolor3127{color:rgb(0,0,255)}
span#textcolor3128{color:rgb(0,0,255)}
span#textcolor3129{color:rgb(0,0,255)}
-span#textcolor3130{color:rgb(43,145,175)}
-span#textcolor3131{color:rgb(0,0,255)}
-span#textcolor3132{color:rgb(0,0,255)}
-span#textcolor3133{color:rgb(43,145,175)}
-span#textcolor3134{color:rgb(0,0,255)}
+span#textcolor3130{color:rgb(0,0,255)}
+span#textcolor3131{color:rgb(43,145,175)}
+span#textcolor3132{color:rgb(43,145,175)}
+span#textcolor3133{color:rgb(0,0,255)}
+span#textcolor3134{color:rgb(43,145,175)}
span#textcolor3135{color:rgb(0,0,255)}
-span#textcolor3136{color:rgb(0,0,255)}
-span#textcolor3137{color:rgb(0,0,255)}
+span#textcolor3136{color:rgb(43,145,175)}
+span#textcolor3137{color:rgb(0,127,0)}
span#textcolor3138{color:rgb(0,0,255)}
span#textcolor3139{color:rgb(43,145,175)}
-span#textcolor3140{color:rgb(0,0,255)}
+span#textcolor3140{color:rgb(43,145,175)}
span#textcolor3141{color:rgb(0,0,255)}
-span#textcolor3142{color:rgb(0,0,255)}
-span#textcolor3143{color:rgb(0,0,255)}
-span#textcolor3144{color:rgb(43,145,175)}
+span#textcolor3142{color:rgb(0,127,0)}
+span#textcolor3143{color:rgb(0,127,0)}
+span#textcolor3144{color:rgb(0,127,0)}
span#textcolor3145{color:rgb(0,0,255)}
-span#textcolor3146{color:rgb(43,145,175)}
+span#textcolor3146{color:rgb(0,0,255)}
span#textcolor3147{color:rgb(43,145,175)}
-span#textcolor3148{color:rgb(43,145,175)}
+span#textcolor3148{color:rgb(0,0,255)}
span#textcolor3149{color:rgb(43,145,175)}
-span#textcolor3150{color:rgb(0,0,255)}
-span#textcolor3151{color:rgb(0,0,255)}
-span#textcolor3152{color:rgb(0,0,255)}
-span#textcolor3153{color:rgb(0,0,255)}
+span#textcolor3150{color:rgb(43,145,175)}
+span#textcolor3151{color:rgb(163,20,20)}
+span#textcolor3152{color:rgb(163,20,20)}
+span#textcolor3153{color:rgb(163,20,20)}
span#textcolor3154{color:rgb(0,0,255)}
span#textcolor3155{color:rgb(0,0,255)}
-span#textcolor3156{color:rgb(0,0,255)}
-span#textcolor3157{color:rgb(43,145,175)}
-span#textcolor3158{color:rgb(0,0,255)}
-span#textcolor3159{color:rgb(0,0,255)}
+span#textcolor3156{color:rgb(43,145,175)}
+span#textcolor3157{color:rgb(0,0,255)}
+span#textcolor3158{color:rgb(43,145,175)}
+span#textcolor3159{color:rgb(43,145,175)}
span#textcolor3160{color:rgb(43,145,175)}
span#textcolor3161{color:rgb(43,145,175)}
span#textcolor3162{color:rgb(43,145,175)}
-span#textcolor3163{color:rgb(0,0,255)}
-span#textcolor3164{color:rgb(0,0,255)}
-span#textcolor3165{color:rgb(43,145,175)}
+span#textcolor3163{color:rgb(0,127,0)}
+span#textcolor3164{color:rgb(0,127,0)}
+span#textcolor3165{color:rgb(0,127,0)}
span#textcolor3166{color:rgb(0,0,255)}
span#textcolor3167{color:rgb(163,20,20)}
-span#textcolor3168{color:rgb(163,20,20)}
-span#textcolor3169{color:rgb(163,20,20)}
-span#textcolor3170{color:rgb(0,0,255)}
-span#textcolor3171{color:rgb(0,0,255)}
-span#textcolor3172{color:rgb(0,0,255)}
+span#textcolor3168{color:rgb(0,0,255)}
+span#textcolor3169{color:rgb(0,0,255)}
+span#textcolor3170{color:rgb(163,20,20)}
+span#textcolor3171{color:rgb(163,20,20)}
+span#textcolor3172{color:rgb(163,20,20)}
span#textcolor3173{color:rgb(0,0,255)}
-span#textcolor3174{color:rgb(0,0,255)}
-span#textcolor3175{color:rgb(0,0,255)}
-span#textcolor3176{color:rgb(0,0,255)}
-span#textcolor3177{color:rgb(0,0,255)}
-span#textcolor3178{color:rgb(43,145,175)}
-span#textcolor3179{color:rgb(0,0,255)}
-span#textcolor3180{color:rgb(0,0,255)}
+span#textcolor3174{color:rgb(163,20,20)}
+span#textcolor3175{color:rgb(163,20,20)}
+span#textcolor3176{color:rgb(163,20,20)}
+span#textcolor3177{color:rgb(163,20,20)}
+span#textcolor3178{color:rgb(163,20,20)}
+span#textcolor3179{color:rgb(0,127,0)}
+span#textcolor3180{color:rgb(0,127,0)}
span#textcolor3181{color:rgb(0,0,255)}
-span#textcolor3182{color:rgb(43,145,175)}
+span#textcolor3182{color:rgb(0,0,255)}
span#textcolor3183{color:rgb(0,0,255)}
-span#textcolor3184{color:rgb(0,127,0)}
+span#textcolor3184{color:rgb(0,0,255)}
span#textcolor3185{color:rgb(0,0,255)}
-span#textcolor3186{color:rgb(43,145,175)}
-span#textcolor3187{color:rgb(0,0,255)}
-span#textcolor3188{color:rgb(0,0,255)}
+span#textcolor3186{color:rgb(0,0,255)}
+span#textcolor3187{color:rgb(43,145,175)}
+span#textcolor3188{color:rgb(43,145,175)}
span#textcolor3189{color:rgb(43,145,175)}
-span#textcolor3190{color:rgb(163,20,20)}
-span#textcolor3191{color:rgb(163,20,20)}
-span#textcolor3192{color:rgb(163,20,20)}
-span#textcolor3193{color:rgb(0,0,255)}
-span#textcolor3194{color:rgb(0,0,255)}
-span#textcolor3195{color:rgb(43,145,175)}
-span#textcolor3196{color:rgb(43,145,175)}
-span#textcolor3197{color:rgb(0,0,255)}
-span#textcolor3198{color:rgb(0,0,255)}
-span#textcolor3199{color:rgb(0,0,255)}
+span#textcolor3190{color:rgb(0,0,255)}
+span#textcolor3191{color:rgb(0,0,255)}
+span#textcolor3192{color:rgb(0,0,255)}
+span#textcolor3193{color:rgb(43,145,175)}
+span#textcolor3194{color:rgb(43,145,175)}
+span#textcolor3195{color:rgb(163,20,20)}
+span#textcolor3196{color:rgb(163,20,20)}
+pre#fancyvrb93{padding:5.69054pt;}
+pre#fancyvrb93{ border-top: solid 0.4pt; }
+pre#fancyvrb93{ border-left: solid 0.4pt; }
+pre#fancyvrb93{ border-bottom: solid 0.4pt; }
+pre#fancyvrb93{ border-right: solid 0.4pt; }
+span#textcolor3197{color:rgb(0,127,0)}
+span#textcolor3198{color:rgb(0,127,0)}
+span#textcolor3199{color:rgb(0,127,0)}
span#textcolor3200{color:rgb(0,0,255)}
-span#textcolor3201{color:rgb(0,0,255)}
+span#textcolor3201{color:rgb(0,127,0)}
span#textcolor3202{color:rgb(0,0,255)}
-span#textcolor3203{color:rgb(0,0,255)}
-span#textcolor3204{color:rgb(0,127,0)}
-span#textcolor3205{color:rgb(0,0,255)}
-span#textcolor3206{color:rgb(163,20,20)}
-span#textcolor3207{color:rgb(163,20,20)}
-span#textcolor3208{color:rgb(163,20,20)}
+span#textcolor3203{color:rgb(0,127,0)}
+span#textcolor3204{color:rgb(0,0,255)}
+span#textcolor3205{color:rgb(0,127,0)}
+span#textcolor3206{color:rgb(0,0,255)}
+span#textcolor3207{color:rgb(43,145,175)}
+span#textcolor3208{color:rgb(43,145,175)}
span#textcolor3209{color:rgb(0,0,255)}
-span#textcolor3210{color:rgb(0,127,0)}
-span#textcolor3211{color:rgb(163,20,20)}
+span#textcolor3210{color:rgb(43,145,175)}
+span#textcolor3211{color:rgb(0,0,255)}
span#textcolor3212{color:rgb(0,0,255)}
span#textcolor3213{color:rgb(0,0,255)}
-span#textcolor3214{color:rgb(0,0,255)}
-span#textcolor3215{color:rgb(43,145,175)}
-span#textcolor3216{color:rgb(0,0,255)}
-span#textcolor3217{color:rgb(43,145,175)}
-span#textcolor3218{color:rgb(0,127,0)}
+span#textcolor3214{color:rgb(163,20,20)}
+span#textcolor3215{color:rgb(163,20,20)}
+span#textcolor3216{color:rgb(163,20,20)}
+span#textcolor3217{color:rgb(163,20,20)}
+span#textcolor3218{color:rgb(163,20,20)}
span#textcolor3219{color:rgb(163,20,20)}
-span#textcolor3220{color:rgb(0,0,255)}
-span#textcolor3221{color:rgb(163,20,20)}
-span#textcolor3222{color:rgb(163,20,20)}
-span#textcolor3223{color:rgb(163,20,20)}
+span#textcolor3220{color:rgb(0,127,0)}
+span#textcolor3221{color:rgb(0,0,255)}
+span#textcolor3222{color:rgb(0,0,255)}
+span#textcolor3223{color:rgb(43,145,175)}
span#textcolor3224{color:rgb(0,0,255)}
-span#textcolor3225{color:rgb(0,0,255)}
-span#textcolor3226{color:rgb(43,145,175)}
-span#textcolor3227{color:rgb(0,0,255)}
-span#textcolor3228{color:rgb(0,0,255)}
+span#textcolor3225{color:rgb(163,20,20)}
+span#textcolor3226{color:rgb(163,20,20)}
+span#textcolor3227{color:rgb(163,20,20)}
+span#textcolor3228{color:rgb(0,127,0)}
span#textcolor3229{color:rgb(0,0,255)}
-span#textcolor3230{color:rgb(43,145,175)}
+span#textcolor3230{color:rgb(0,0,255)}
span#textcolor3231{color:rgb(43,145,175)}
-span#textcolor3232{color:rgb(43,145,175)}
-span#textcolor3233{color:rgb(0,0,255)}
-span#textcolor3234{color:rgb(0,0,255)}
-span#textcolor3235{color:rgb(0,0,255)}
-span#textcolor3236{color:rgb(163,20,20)}
-span#textcolor3237{color:rgb(163,20,20)}
-span#textcolor3238{color:rgb(163,20,20)}
-span#textcolor3239{color:rgb(0,0,255)}
+span#textcolor3232{color:rgb(0,0,255)}
+span#textcolor3233{color:rgb(163,20,20)}
+span#textcolor3234{color:rgb(163,20,20)}
+span#textcolor3235{color:rgb(163,20,20)}
+span#textcolor3236{color:rgb(0,127,0)}
+span#textcolor3237{color:rgb(0,0,255)}
+span#textcolor3238{color:rgb(0,0,255)}
+span#textcolor3239{color:rgb(43,145,175)}
span#textcolor3240{color:rgb(0,0,255)}
-span#textcolor3241{color:rgb(0,0,255)}
-span#textcolor3242{color:rgb(0,0,255)}
-span#textcolor3243{color:rgb(0,0,255)}
-span#textcolor3244{color:rgb(0,0,255)}
+span#textcolor3241{color:rgb(163,20,20)}
+span#textcolor3242{color:rgb(163,20,20)}
+span#textcolor3243{color:rgb(163,20,20)}
+span#textcolor3244{color:rgb(0,127,0)}
span#textcolor3245{color:rgb(0,0,255)}
span#textcolor3246{color:rgb(0,0,255)}
span#textcolor3247{color:rgb(0,0,255)}
-span#textcolor3248{color:rgb(0,127,0)}
+span#textcolor3248{color:rgb(0,0,255)}
span#textcolor3249{color:rgb(0,0,255)}
span#textcolor3250{color:rgb(0,0,255)}
-span#textcolor3251{color:rgb(43,145,175)}
+span#textcolor3251{color:rgb(163,20,20)}
span#textcolor3252{color:rgb(0,0,255)}
-span#textcolor3253{color:rgb(0,0,255)}
-span#textcolor3254{color:rgb(0,0,255)}
+span#textcolor3253{color:rgb(43,145,175)}
+span#textcolor3254{color:rgb(43,145,175)}
span#textcolor3255{color:rgb(43,145,175)}
-span#textcolor3256{color:rgb(43,145,175)}
-span#textcolor3257{color:rgb(43,145,175)}
-span#textcolor3258{color:rgb(43,145,175)}
-span#textcolor3259{color:rgb(43,145,175)}
-span#textcolor3260{color:rgb(0,0,255)}
-span#textcolor3261{color:rgb(0,0,255)}
-span#textcolor3262{color:rgb(0,0,255)}
+span#textcolor3256{color:rgb(163,20,20)}
+span#textcolor3257{color:rgb(163,20,20)}
+span#textcolor3258{color:rgb(163,20,20)}
+span#textcolor3259{color:rgb(0,0,255)}
+span#textcolor3260{color:rgb(163,20,20)}
+span#textcolor3261{color:rgb(163,20,20)}
+span#textcolor3262{color:rgb(163,20,20)}
span#textcolor3263{color:rgb(0,0,255)}
-span#textcolor3264{color:rgb(163,20,20)}
-span#textcolor3265{color:rgb(163,20,20)}
-span#textcolor3266{color:rgb(163,20,20)}
-span#textcolor3267{color:rgb(0,0,255)}
-span#textcolor3268{color:rgb(0,0,255)}
-span#textcolor3269{color:rgb(0,0,255)}
-span#textcolor3270{color:rgb(0,127,0)}
-span#textcolor3271{color:rgb(0,0,255)}
-span#textcolor3272{color:rgb(0,0,255)}
-span#textcolor3273{color:rgb(0,0,255)}
-span#textcolor3274{color:rgb(0,127,0)}
-span#textcolor3275{color:rgb(0,0,255)}
-span#textcolor3276{color:rgb(0,0,255)}
-span#textcolor3277{color:rgb(163,20,20)}
-span#textcolor3278{color:rgb(43,145,175)}
-span#textcolor3279{color:rgb(0,0,255)}
-span#textcolor3280{color:rgb(163,20,20)}
-span#textcolor3281{color:rgb(163,20,20)}
-span#textcolor3282{color:rgb(163,20,20)}
-span#textcolor3283{color:rgb(0,0,255)}
-span#textcolor3284{color:rgb(43,145,175)}
-span#textcolor3285{color:rgb(0,0,255)}
-span#textcolor3286{color:rgb(0,0,255)}
-span#textcolor3287{color:rgb(0,127,0)}
-span#textcolor3288{color:rgb(0,127,0)}
-span#textcolor3289{color:rgb(0,0,255)}
-span#textcolor3290{color:rgb(0,0,255)}
-span#textcolor3291{color:rgb(0,0,255)}
-span#textcolor3292{color:rgb(163,20,20)}
-span#textcolor3293{color:rgb(163,20,20)}
-span#textcolor3294{color:rgb(163,20,20)}
-span#textcolor3295{color:rgb(0,0,255)}
-span#textcolor3296{color:rgb(43,145,175)}
-span#textcolor3297{color:rgb(43,145,175)}
-span#textcolor3298{color:rgb(43,145,175)}
-span#textcolor3299{color:rgb(163,20,20)}
-span#textcolor3300{color:rgb(163,20,20)}
-span#textcolor3301{color:rgb(163,20,20)}
-span#textcolor3302{color:rgb(0,0,255)}
-span#textcolor3303{color:rgb(163,20,20)}
-span#textcolor3304{color:rgb(163,20,20)}
-span#textcolor3305{color:rgb(163,20,20)}
-span#textcolor3306{color:rgb(0,0,255)}
-span#textcolor3307{color:rgb(0,0,255)}
-span#textcolor3308{color:rgb(163,20,20)}
-span#textcolor3309{color:rgb(163,20,20)}
-span#textcolor3310{color:rgb(163,20,20)}
-span#textcolor3311{color:rgb(0,0,255)}
-span#textcolor3312{color:rgb(0,0,255)}
-span#textcolor3313{color:rgb(0,0,255)}
-span#textcolor3314{color:rgb(0,0,255)}
-span#textcolor3315{color:rgb(43,145,175)}
-span#textcolor3316{color:rgb(43,145,175)}
-span#textcolor3317{color:rgb(163,20,20)}
-span#textcolor3318{color:rgb(163,20,20)}
-span#textcolor3319{color:rgb(163,20,20)}
-span#textcolor3320{color:rgb(163,20,20)}
-span#textcolor3321{color:rgb(163,20,20)}
+span#textcolor3264{color:rgb(0,0,255)}
+span#textcolor3265{color:rgb(0,0,255)}
+span#textcolor3266{color:rgb(43,145,175)}
+span#textcolor3267{color:rgb(43,145,175)}
+span#textcolor3268{color:rgb(163,20,20)}
+span#textcolor3269{color:rgb(163,20,20)}
+span#textcolor3270{color:rgb(163,20,20)}
+span#textcolor3271{color:rgb(163,20,20)}
+span#textcolor3272{color:rgb(163,20,20)}
pre#fancyvrb94{padding:5.69054pt;}
pre#fancyvrb94{ border-top: solid 0.4pt; }
pre#fancyvrb94{ border-left: solid 0.4pt; }
pre#fancyvrb94{ border-bottom: solid 0.4pt; }
pre#fancyvrb94{ border-right: solid 0.4pt; }
-span#textcolor3322{color:rgb(163,20,20)}
+span#textcolor3273{color:rgb(0,0,255)}
+span#textcolor3274{color:rgb(0,0,255)}
+span#textcolor3275{color:rgb(0,0,255)}
+span#textcolor3276{color:rgb(0,0,255)}
pre#fancyvrb95{padding:5.69054pt;}
pre#fancyvrb95{ border-top: solid 0.4pt; }
pre#fancyvrb95{ border-left: solid 0.4pt; }
pre#fancyvrb95{ border-bottom: solid 0.4pt; }
pre#fancyvrb95{ border-right: solid 0.4pt; }
-span#textcolor3323{color:rgb(163,20,20)}
pre#fancyvrb96{padding:5.69054pt;}
pre#fancyvrb96{ border-top: solid 0.4pt; }
pre#fancyvrb96{ border-left: solid 0.4pt; }
pre#fancyvrb96{ border-bottom: solid 0.4pt; }
pre#fancyvrb96{ border-right: solid 0.4pt; }
-span#textcolor3324{color:rgb(0,127,0)}
-span#textcolor3325{color:rgb(0,127,0)}
-span#textcolor3326{color:rgb(0,127,0)}
-span#textcolor3327{color:rgb(0,0,255)}
-span#textcolor3328{color:rgb(0,127,0)}
-span#textcolor3329{color:rgb(0,0,255)}
-span#textcolor3330{color:rgb(0,127,0)}
-span#textcolor3331{color:rgb(0,0,255)}
-span#textcolor3332{color:rgb(0,127,0)}
-span#textcolor3333{color:rgb(0,0,255)}
-span#textcolor3334{color:rgb(0,127,0)}
-span#textcolor3335{color:rgb(0,0,255)}
-span#textcolor3336{color:rgb(0,127,0)}
-span#textcolor3337{color:rgb(0,0,255)}
-span#textcolor3338{color:rgb(0,0,255)}
-span#textcolor3339{color:rgb(0,0,255)}
-span#textcolor3340{color:rgb(0,0,255)}
-span#textcolor3341{color:rgb(43,145,175)}
-span#textcolor3342{color:rgb(43,145,175)}
-span#textcolor3343{color:rgb(0,0,255)}
-span#textcolor3344{color:rgb(43,145,175)}
-span#textcolor3345{color:rgb(0,0,255)}
-span#textcolor3346{color:rgb(43,145,175)}
-span#textcolor3347{color:rgb(0,127,0)}
-span#textcolor3348{color:rgb(0,0,255)}
-span#textcolor3349{color:rgb(43,145,175)}
-span#textcolor3350{color:rgb(43,145,175)}
-span#textcolor3351{color:rgb(0,0,255)}
-span#textcolor3352{color:rgb(0,127,0)}
-span#textcolor3353{color:rgb(0,127,0)}
-span#textcolor3354{color:rgb(0,127,0)}
-span#textcolor3355{color:rgb(0,0,255)}
-span#textcolor3356{color:rgb(0,0,255)}
-span#textcolor3357{color:rgb(43,145,175)}
-span#textcolor3358{color:rgb(0,0,255)}
-span#textcolor3359{color:rgb(43,145,175)}
-span#textcolor3360{color:rgb(43,145,175)}
-span#textcolor3361{color:rgb(163,20,20)}
-span#textcolor3362{color:rgb(163,20,20)}
-span#textcolor3363{color:rgb(163,20,20)}
-span#textcolor3364{color:rgb(0,0,255)}
-span#textcolor3365{color:rgb(0,0,255)}
-span#textcolor3366{color:rgb(43,145,175)}
-span#textcolor3367{color:rgb(0,0,255)}
-span#textcolor3368{color:rgb(43,145,175)}
-span#textcolor3369{color:rgb(43,145,175)}
-span#textcolor3370{color:rgb(43,145,175)}
-span#textcolor3371{color:rgb(43,145,175)}
-span#textcolor3372{color:rgb(43,145,175)}
-span#textcolor3373{color:rgb(0,127,0)}
-span#textcolor3374{color:rgb(0,127,0)}
-span#textcolor3375{color:rgb(0,127,0)}
-span#textcolor3376{color:rgb(0,0,255)}
-span#textcolor3377{color:rgb(163,20,20)}
-span#textcolor3378{color:rgb(0,0,255)}
-span#textcolor3379{color:rgb(0,0,255)}
-span#textcolor3380{color:rgb(163,20,20)}
-span#textcolor3381{color:rgb(163,20,20)}
-span#textcolor3382{color:rgb(163,20,20)}
-span#textcolor3383{color:rgb(0,0,255)}
-span#textcolor3384{color:rgb(163,20,20)}
-span#textcolor3385{color:rgb(163,20,20)}
-span#textcolor3386{color:rgb(163,20,20)}
-span#textcolor3387{color:rgb(163,20,20)}
-span#textcolor3388{color:rgb(163,20,20)}
-span#textcolor3389{color:rgb(0,127,0)}
-span#textcolor3390{color:rgb(0,127,0)}
-span#textcolor3391{color:rgb(0,0,255)}
-span#textcolor3392{color:rgb(0,0,255)}
-span#textcolor3393{color:rgb(0,0,255)}
-span#textcolor3394{color:rgb(0,0,255)}
-span#textcolor3395{color:rgb(0,0,255)}
-span#textcolor3396{color:rgb(0,0,255)}
-span#textcolor3397{color:rgb(43,145,175)}
-span#textcolor3398{color:rgb(43,145,175)}
-span#textcolor3399{color:rgb(43,145,175)}
-span#textcolor3400{color:rgb(0,0,255)}
-span#textcolor3401{color:rgb(0,0,255)}
-span#textcolor3402{color:rgb(0,0,255)}
-span#textcolor3403{color:rgb(43,145,175)}
-span#textcolor3404{color:rgb(43,145,175)}
-span#textcolor3405{color:rgb(163,20,20)}
-span#textcolor3406{color:rgb(163,20,20)}
pre#fancyvrb97{padding:5.69054pt;}
pre#fancyvrb97{ border-top: solid 0.4pt; }
pre#fancyvrb97{ border-left: solid 0.4pt; }
pre#fancyvrb97{ border-bottom: solid 0.4pt; }
pre#fancyvrb97{ border-right: solid 0.4pt; }
-span#textcolor3407{color:rgb(0,127,0)}
-span#textcolor3408{color:rgb(0,127,0)}
-span#textcolor3409{color:rgb(0,127,0)}
-span#textcolor3410{color:rgb(0,0,255)}
-span#textcolor3411{color:rgb(0,127,0)}
-span#textcolor3412{color:rgb(0,0,255)}
-span#textcolor3413{color:rgb(0,127,0)}
-span#textcolor3414{color:rgb(0,0,255)}
-span#textcolor3415{color:rgb(0,127,0)}
-span#textcolor3416{color:rgb(0,0,255)}
-span#textcolor3417{color:rgb(43,145,175)}
-span#textcolor3418{color:rgb(43,145,175)}
-span#textcolor3419{color:rgb(0,0,255)}
-span#textcolor3420{color:rgb(43,145,175)}
-span#textcolor3421{color:rgb(0,0,255)}
-span#textcolor3422{color:rgb(0,0,255)}
-span#textcolor3423{color:rgb(0,0,255)}
-span#textcolor3424{color:rgb(163,20,20)}
-span#textcolor3425{color:rgb(163,20,20)}
-span#textcolor3426{color:rgb(163,20,20)}
-span#textcolor3427{color:rgb(163,20,20)}
-span#textcolor3428{color:rgb(163,20,20)}
-span#textcolor3429{color:rgb(163,20,20)}
-span#textcolor3430{color:rgb(0,127,0)}
-span#textcolor3431{color:rgb(0,0,255)}
-span#textcolor3432{color:rgb(0,0,255)}
-span#textcolor3433{color:rgb(43,145,175)}
-span#textcolor3434{color:rgb(0,0,255)}
-span#textcolor3435{color:rgb(163,20,20)}
-span#textcolor3436{color:rgb(163,20,20)}
-span#textcolor3437{color:rgb(163,20,20)}
-span#textcolor3438{color:rgb(0,127,0)}
-span#textcolor3439{color:rgb(0,0,255)}
-span#textcolor3440{color:rgb(0,0,255)}
-span#textcolor3441{color:rgb(43,145,175)}
-span#textcolor3442{color:rgb(0,0,255)}
-span#textcolor3443{color:rgb(163,20,20)}
-span#textcolor3444{color:rgb(163,20,20)}
-span#textcolor3445{color:rgb(163,20,20)}
-span#textcolor3446{color:rgb(0,127,0)}
-span#textcolor3447{color:rgb(0,0,255)}
-span#textcolor3448{color:rgb(0,0,255)}
-span#textcolor3449{color:rgb(43,145,175)}
-span#textcolor3450{color:rgb(0,0,255)}
-span#textcolor3451{color:rgb(163,20,20)}
-span#textcolor3452{color:rgb(163,20,20)}
-span#textcolor3453{color:rgb(163,20,20)}
-span#textcolor3454{color:rgb(0,127,0)}
-span#textcolor3455{color:rgb(0,0,255)}
-span#textcolor3456{color:rgb(0,0,255)}
-span#textcolor3457{color:rgb(0,0,255)}
-span#textcolor3458{color:rgb(0,0,255)}
-span#textcolor3459{color:rgb(0,0,255)}
-span#textcolor3460{color:rgb(0,0,255)}
-span#textcolor3461{color:rgb(163,20,20)}
-span#textcolor3462{color:rgb(0,0,255)}
-span#textcolor3463{color:rgb(43,145,175)}
-span#textcolor3464{color:rgb(43,145,175)}
-span#textcolor3465{color:rgb(43,145,175)}
-span#textcolor3466{color:rgb(163,20,20)}
-span#textcolor3467{color:rgb(163,20,20)}
-span#textcolor3468{color:rgb(163,20,20)}
-span#textcolor3469{color:rgb(0,0,255)}
-span#textcolor3470{color:rgb(163,20,20)}
-span#textcolor3471{color:rgb(163,20,20)}
-span#textcolor3472{color:rgb(163,20,20)}
-span#textcolor3473{color:rgb(0,0,255)}
-span#textcolor3474{color:rgb(0,0,255)}
-span#textcolor3475{color:rgb(0,0,255)}
-span#textcolor3476{color:rgb(43,145,175)}
-span#textcolor3477{color:rgb(43,145,175)}
-span#textcolor3478{color:rgb(163,20,20)}
-span#textcolor3479{color:rgb(163,20,20)}
-span#textcolor3480{color:rgb(163,20,20)}
-span#textcolor3481{color:rgb(163,20,20)}
-span#textcolor3482{color:rgb(163,20,20)}
+span#textcolor3277{color:rgb(163,20,20)}
+span#textcolor3278{color:rgb(163,20,20)}
+span#textcolor3279{color:rgb(163,20,20)}
+span#textcolor3280{color:rgb(0,0,255)}
+span#textcolor3281{color:rgb(163,20,20)}
+span#textcolor3282{color:rgb(163,20,20)}
+span#textcolor3283{color:rgb(163,20,20)}
+span#textcolor3284{color:rgb(163,20,20)}
+span#textcolor3285{color:rgb(163,20,20)}
+span#textcolor3286{color:rgb(163,20,20)}
pre#fancyvrb98{padding:5.69054pt;}
pre#fancyvrb98{ border-top: solid 0.4pt; }
pre#fancyvrb98{ border-left: solid 0.4pt; }
pre#fancyvrb98{ border-bottom: solid 0.4pt; }
pre#fancyvrb98{ border-right: solid 0.4pt; }
-span#textcolor3483{color:rgb(0,0,255)}
-span#textcolor3484{color:rgb(0,0,255)}
-span#textcolor3485{color:rgb(0,0,255)}
-span#textcolor3486{color:rgb(0,0,255)}
+span#textcolor3287{color:rgb(0,127,0)}
+span#textcolor3288{color:rgb(0,127,0)}
+span#textcolor3289{color:rgb(0,127,0)}
+span#textcolor3290{color:rgb(0,0,255)}
+span#textcolor3291{color:rgb(0,127,0)}
+span#textcolor3292{color:rgb(0,0,255)}
+span#textcolor3293{color:rgb(0,127,0)}
+span#textcolor3294{color:rgb(0,0,255)}
+span#textcolor3295{color:rgb(0,127,0)}
+span#textcolor3296{color:rgb(0,0,255)}
+span#textcolor3297{color:rgb(0,127,0)}
+span#textcolor3298{color:rgb(0,0,255)}
+span#textcolor3299{color:rgb(0,127,0)}
+span#textcolor3300{color:rgb(0,0,255)}
+span#textcolor3301{color:rgb(0,127,0)}
+span#textcolor3302{color:rgb(0,0,255)}
+span#textcolor3303{color:rgb(0,127,0)}
+span#textcolor3304{color:rgb(0,0,255)}
+span#textcolor3305{color:rgb(0,127,0)}
+span#textcolor3306{color:rgb(0,0,255)}
+span#textcolor3307{color:rgb(0,127,0)}
+span#textcolor3308{color:rgb(0,0,255)}
+span#textcolor3309{color:rgb(0,127,0)}
+span#textcolor3310{color:rgb(0,0,255)}
+span#textcolor3311{color:rgb(43,145,175)}
+span#textcolor3312{color:rgb(0,0,255)}
+span#textcolor3313{color:rgb(0,0,255)}
+span#textcolor3314{color:rgb(0,0,255)}
+span#textcolor3315{color:rgb(43,145,175)}
+span#textcolor3316{color:rgb(0,0,255)}
+span#textcolor3317{color:rgb(0,0,255)}
+span#textcolor3318{color:rgb(0,0,255)}
+span#textcolor3319{color:rgb(43,145,175)}
+span#textcolor3320{color:rgb(0,0,255)}
+span#textcolor3321{color:rgb(43,145,175)}
+span#textcolor3322{color:rgb(43,145,175)}
+span#textcolor3323{color:rgb(0,0,255)}
+span#textcolor3324{color:rgb(43,145,175)}
+span#textcolor3325{color:rgb(0,0,255)}
+span#textcolor3326{color:rgb(0,0,255)}
+span#textcolor3327{color:rgb(43,145,175)}
+span#textcolor3328{color:rgb(43,145,175)}
+span#textcolor3329{color:rgb(0,0,255)}
+span#textcolor3330{color:rgb(0,0,255)}
+span#textcolor3331{color:rgb(0,0,255)}
+span#textcolor3332{color:rgb(0,0,255)}
+span#textcolor3333{color:rgb(43,145,175)}
+span#textcolor3334{color:rgb(0,0,255)}
+span#textcolor3335{color:rgb(0,0,255)}
+span#textcolor3336{color:rgb(0,0,255)}
+span#textcolor3337{color:rgb(43,145,175)}
+span#textcolor3338{color:rgb(0,0,255)}
+span#textcolor3339{color:rgb(0,0,255)}
+span#textcolor3340{color:rgb(0,0,255)}
+span#textcolor3341{color:rgb(0,0,255)}
+span#textcolor3342{color:rgb(0,0,255)}
+span#textcolor3343{color:rgb(0,0,255)}
+span#textcolor3344{color:rgb(43,145,175)}
+span#textcolor3345{color:rgb(43,145,175)}
+span#textcolor3346{color:rgb(0,0,255)}
+span#textcolor3347{color:rgb(163,20,20)}
+span#textcolor3348{color:rgb(163,20,20)}
+span#textcolor3349{color:rgb(163,20,20)}
+span#textcolor3350{color:rgb(0,0,255)}
+span#textcolor3351{color:rgb(163,20,20)}
+span#textcolor3352{color:rgb(163,20,20)}
+span#textcolor3353{color:rgb(163,20,20)}
+span#textcolor3354{color:rgb(163,20,20)}
+span#textcolor3355{color:rgb(163,20,20)}
+span#textcolor3356{color:rgb(163,20,20)}
+span#textcolor3357{color:rgb(0,0,255)}
+span#textcolor3358{color:rgb(0,0,255)}
+span#textcolor3359{color:rgb(43,145,175)}
+span#textcolor3360{color:rgb(43,145,175)}
+span#textcolor3361{color:rgb(0,127,0)}
+span#textcolor3362{color:rgb(0,127,0)}
+span#textcolor3363{color:rgb(0,127,0)}
+span#textcolor3364{color:rgb(0,127,0)}
+span#textcolor3365{color:rgb(0,127,0)}
+span#textcolor3366{color:rgb(0,127,0)}
+span#textcolor3367{color:rgb(0,0,255)}
+span#textcolor3368{color:rgb(43,145,175)}
+span#textcolor3369{color:rgb(0,0,255)}
+span#textcolor3370{color:rgb(0,0,255)}
+span#textcolor3371{color:rgb(0,0,255)}
+span#textcolor3372{color:rgb(0,0,255)}
+span#textcolor3373{color:rgb(163,20,20)}
+span#textcolor3374{color:rgb(163,20,20)}
+span#textcolor3375{color:rgb(163,20,20)}
+span#textcolor3376{color:rgb(163,20,20)}
+span#textcolor3377{color:rgb(163,20,20)}
+span#textcolor3378{color:rgb(163,20,20)}
+span#textcolor3379{color:rgb(163,20,20)}
+span#textcolor3380{color:rgb(163,20,20)}
+span#textcolor3381{color:rgb(163,20,20)}
+span#textcolor3382{color:rgb(0,0,255)}
+span#textcolor3383{color:rgb(163,20,20)}
+span#textcolor3384{color:rgb(163,20,20)}
+span#textcolor3385{color:rgb(163,20,20)}
+span#textcolor3386{color:rgb(163,20,20)}
+span#textcolor3387{color:rgb(163,20,20)}
+span#textcolor3388{color:rgb(163,20,20)}
+span#textcolor3389{color:rgb(0,0,255)}
+span#textcolor3390{color:rgb(0,127,0)}
+span#textcolor3391{color:rgb(0,127,0)}
+span#textcolor3392{color:rgb(0,127,0)}
+span#textcolor3393{color:rgb(0,0,255)}
+span#textcolor3394{color:rgb(43,145,175)}
+span#textcolor3395{color:rgb(0,0,255)}
+span#textcolor3396{color:rgb(0,0,255)}
+span#textcolor3397{color:rgb(0,127,0)}
+span#textcolor3398{color:rgb(0,127,0)}
+span#textcolor3399{color:rgb(0,127,0)}
+span#textcolor3400{color:rgb(0,127,0)}
+span#textcolor3401{color:rgb(0,127,0)}
+span#textcolor3402{color:rgb(0,0,255)}
+span#textcolor3403{color:rgb(0,127,0)}
+span#textcolor3404{color:rgb(0,127,0)}
+span#textcolor3405{color:rgb(0,127,0)}
+span#textcolor3406{color:rgb(0,127,0)}
+span#textcolor3407{color:rgb(0,0,255)}
+span#textcolor3408{color:rgb(43,145,175)}
+span#textcolor3409{color:rgb(0,0,255)}
+span#textcolor3410{color:rgb(0,127,0)}
+span#textcolor3411{color:rgb(43,145,175)}
+span#textcolor3412{color:rgb(0,127,0)}
+span#textcolor3413{color:rgb(43,145,175)}
+span#textcolor3414{color:rgb(0,127,0)}
+span#textcolor3415{color:rgb(0,127,0)}
+span#textcolor3416{color:rgb(43,145,175)}
+span#textcolor3417{color:rgb(0,0,255)}
+span#textcolor3418{color:rgb(43,145,175)}
+span#textcolor3419{color:rgb(0,0,255)}
+span#textcolor3420{color:rgb(0,127,0)}
+span#textcolor3421{color:rgb(0,127,0)}
+span#textcolor3422{color:rgb(0,0,255)}
+span#textcolor3423{color:rgb(0,127,0)}
+span#textcolor3424{color:rgb(0,127,0)}
+span#textcolor3425{color:rgb(0,0,255)}
+span#textcolor3426{color:rgb(0,127,0)}
+span#textcolor3427{color:rgb(0,127,0)}
+span#textcolor3428{color:rgb(0,127,0)}
+span#textcolor3429{color:rgb(0,127,0)}
+span#textcolor3430{color:rgb(0,127,0)}
+span#textcolor3431{color:rgb(0,127,0)}
+span#textcolor3432{color:rgb(0,127,0)}
+span#textcolor3433{color:rgb(0,0,255)}
+span#textcolor3434{color:rgb(0,127,0)}
+span#textcolor3435{color:rgb(0,0,255)}
+span#textcolor3436{color:rgb(43,145,175)}
+span#textcolor3437{color:rgb(0,0,255)}
+span#textcolor3438{color:rgb(0,0,255)}
+span#textcolor3439{color:rgb(43,145,175)}
+span#textcolor3440{color:rgb(43,145,175)}
+span#textcolor3441{color:rgb(43,145,175)}
+span#textcolor3442{color:rgb(0,0,255)}
+span#textcolor3443{color:rgb(163,20,20)}
+span#textcolor3444{color:rgb(163,20,20)}
+span#textcolor3445{color:rgb(163,20,20)}
+span#textcolor3446{color:rgb(0,0,255)}
+span#textcolor3447{color:rgb(0,0,255)}
+span#textcolor3448{color:rgb(0,0,255)}
+span#textcolor3449{color:rgb(0,0,255)}
+span#textcolor3450{color:rgb(163,20,20)}
+span#textcolor3451{color:rgb(163,20,20)}
+span#textcolor3452{color:rgb(0,0,255)}
+span#textcolor3453{color:rgb(0,0,255)}
+span#textcolor3454{color:rgb(163,20,20)}
+span#textcolor3455{color:rgb(163,20,20)}
+span#textcolor3456{color:rgb(0,0,255)}
+span#textcolor3457{color:rgb(163,20,20)}
+span#textcolor3458{color:rgb(163,20,20)}
+span#textcolor3459{color:rgb(163,20,20)}
+span#textcolor3460{color:rgb(0,0,255)}
+span#textcolor3461{color:rgb(0,127,0)}
+span#textcolor3462{color:rgb(0,0,255)}
+span#textcolor3463{color:rgb(163,20,20)}
pre#fancyvrb99{padding:5.69054pt;}
pre#fancyvrb99{ border-top: solid 0.4pt; }
pre#fancyvrb99{ border-left: solid 0.4pt; }
@@ -4197,212 +4174,5 @@ pre#fancyvrb100{ border-top: solid 0.4pt; }
pre#fancyvrb100{ border-left: solid 0.4pt; }
pre#fancyvrb100{ border-bottom: solid 0.4pt; }
pre#fancyvrb100{ border-right: solid 0.4pt; }
-pre#fancyvrb101{padding:5.69054pt;}
-pre#fancyvrb101{ border-top: solid 0.4pt; }
-pre#fancyvrb101{ border-left: solid 0.4pt; }
-pre#fancyvrb101{ border-bottom: solid 0.4pt; }
-pre#fancyvrb101{ border-right: solid 0.4pt; }
-span#textcolor3487{color:rgb(163,20,20)}
-span#textcolor3488{color:rgb(163,20,20)}
-span#textcolor3489{color:rgb(163,20,20)}
-span#textcolor3490{color:rgb(0,0,255)}
-span#textcolor3491{color:rgb(163,20,20)}
-span#textcolor3492{color:rgb(163,20,20)}
-span#textcolor3493{color:rgb(163,20,20)}
-span#textcolor3494{color:rgb(163,20,20)}
-span#textcolor3495{color:rgb(163,20,20)}
-span#textcolor3496{color:rgb(163,20,20)}
-pre#fancyvrb102{padding:5.69054pt;}
-pre#fancyvrb102{ border-top: solid 0.4pt; }
-pre#fancyvrb102{ border-left: solid 0.4pt; }
-pre#fancyvrb102{ border-bottom: solid 0.4pt; }
-pre#fancyvrb102{ border-right: solid 0.4pt; }
-span#textcolor3497{color:rgb(0,127,0)}
-span#textcolor3498{color:rgb(0,127,0)}
-span#textcolor3499{color:rgb(0,127,0)}
-span#textcolor3500{color:rgb(0,0,255)}
-span#textcolor3501{color:rgb(0,127,0)}
-span#textcolor3502{color:rgb(0,0,255)}
-span#textcolor3503{color:rgb(0,127,0)}
-span#textcolor3504{color:rgb(0,0,255)}
-span#textcolor3505{color:rgb(0,127,0)}
-span#textcolor3506{color:rgb(0,0,255)}
-span#textcolor3507{color:rgb(0,127,0)}
-span#textcolor3508{color:rgb(0,0,255)}
-span#textcolor3509{color:rgb(0,127,0)}
-span#textcolor3510{color:rgb(0,0,255)}
-span#textcolor3511{color:rgb(0,127,0)}
-span#textcolor3512{color:rgb(0,0,255)}
-span#textcolor3513{color:rgb(0,127,0)}
-span#textcolor3514{color:rgb(0,0,255)}
-span#textcolor3515{color:rgb(0,127,0)}
-span#textcolor3516{color:rgb(0,0,255)}
-span#textcolor3517{color:rgb(0,127,0)}
-span#textcolor3518{color:rgb(0,0,255)}
-span#textcolor3519{color:rgb(0,127,0)}
-span#textcolor3520{color:rgb(0,0,255)}
-span#textcolor3521{color:rgb(43,145,175)}
-span#textcolor3522{color:rgb(0,0,255)}
-span#textcolor3523{color:rgb(0,0,255)}
-span#textcolor3524{color:rgb(0,0,255)}
-span#textcolor3525{color:rgb(43,145,175)}
-span#textcolor3526{color:rgb(0,0,255)}
-span#textcolor3527{color:rgb(0,0,255)}
-span#textcolor3528{color:rgb(0,0,255)}
-span#textcolor3529{color:rgb(43,145,175)}
-span#textcolor3530{color:rgb(0,0,255)}
-span#textcolor3531{color:rgb(43,145,175)}
-span#textcolor3532{color:rgb(43,145,175)}
-span#textcolor3533{color:rgb(0,0,255)}
-span#textcolor3534{color:rgb(43,145,175)}
-span#textcolor3535{color:rgb(0,0,255)}
-span#textcolor3536{color:rgb(0,0,255)}
-span#textcolor3537{color:rgb(43,145,175)}
-span#textcolor3538{color:rgb(43,145,175)}
-span#textcolor3539{color:rgb(0,0,255)}
-span#textcolor3540{color:rgb(0,0,255)}
-span#textcolor3541{color:rgb(0,0,255)}
-span#textcolor3542{color:rgb(0,0,255)}
-span#textcolor3543{color:rgb(43,145,175)}
-span#textcolor3544{color:rgb(0,0,255)}
-span#textcolor3545{color:rgb(0,0,255)}
-span#textcolor3546{color:rgb(0,0,255)}
-span#textcolor3547{color:rgb(43,145,175)}
-span#textcolor3548{color:rgb(0,0,255)}
-span#textcolor3549{color:rgb(0,0,255)}
-span#textcolor3550{color:rgb(0,0,255)}
-span#textcolor3551{color:rgb(0,0,255)}
-span#textcolor3552{color:rgb(0,0,255)}
-span#textcolor3553{color:rgb(0,0,255)}
-span#textcolor3554{color:rgb(43,145,175)}
-span#textcolor3555{color:rgb(43,145,175)}
-span#textcolor3556{color:rgb(0,0,255)}
-span#textcolor3557{color:rgb(163,20,20)}
-span#textcolor3558{color:rgb(163,20,20)}
-span#textcolor3559{color:rgb(163,20,20)}
-span#textcolor3560{color:rgb(0,0,255)}
-span#textcolor3561{color:rgb(163,20,20)}
-span#textcolor3562{color:rgb(163,20,20)}
-span#textcolor3563{color:rgb(163,20,20)}
-span#textcolor3564{color:rgb(163,20,20)}
-span#textcolor3565{color:rgb(163,20,20)}
-span#textcolor3566{color:rgb(163,20,20)}
-span#textcolor3567{color:rgb(0,0,255)}
-span#textcolor3568{color:rgb(0,0,255)}
-span#textcolor3569{color:rgb(43,145,175)}
-span#textcolor3570{color:rgb(43,145,175)}
-span#textcolor3571{color:rgb(0,127,0)}
-span#textcolor3572{color:rgb(0,127,0)}
-span#textcolor3573{color:rgb(0,127,0)}
-span#textcolor3574{color:rgb(0,127,0)}
-span#textcolor3575{color:rgb(0,127,0)}
-span#textcolor3576{color:rgb(0,127,0)}
-span#textcolor3577{color:rgb(0,0,255)}
-span#textcolor3578{color:rgb(43,145,175)}
-span#textcolor3579{color:rgb(0,0,255)}
-span#textcolor3580{color:rgb(0,0,255)}
-span#textcolor3581{color:rgb(0,0,255)}
-span#textcolor3582{color:rgb(0,0,255)}
-span#textcolor3583{color:rgb(163,20,20)}
-span#textcolor3584{color:rgb(163,20,20)}
-span#textcolor3585{color:rgb(163,20,20)}
-span#textcolor3586{color:rgb(163,20,20)}
-span#textcolor3587{color:rgb(163,20,20)}
-span#textcolor3588{color:rgb(163,20,20)}
-span#textcolor3589{color:rgb(163,20,20)}
-span#textcolor3590{color:rgb(163,20,20)}
-span#textcolor3591{color:rgb(163,20,20)}
-span#textcolor3592{color:rgb(0,0,255)}
-span#textcolor3593{color:rgb(163,20,20)}
-span#textcolor3594{color:rgb(163,20,20)}
-span#textcolor3595{color:rgb(163,20,20)}
-span#textcolor3596{color:rgb(163,20,20)}
-span#textcolor3597{color:rgb(163,20,20)}
-span#textcolor3598{color:rgb(163,20,20)}
-span#textcolor3599{color:rgb(0,0,255)}
-span#textcolor3600{color:rgb(0,127,0)}
-span#textcolor3601{color:rgb(0,127,0)}
-span#textcolor3602{color:rgb(0,127,0)}
-span#textcolor3603{color:rgb(0,0,255)}
-span#textcolor3604{color:rgb(43,145,175)}
-span#textcolor3605{color:rgb(0,0,255)}
-span#textcolor3606{color:rgb(0,0,255)}
-span#textcolor3607{color:rgb(0,127,0)}
-span#textcolor3608{color:rgb(0,127,0)}
-span#textcolor3609{color:rgb(0,127,0)}
-span#textcolor3610{color:rgb(0,127,0)}
-span#textcolor3611{color:rgb(0,127,0)}
-span#textcolor3612{color:rgb(0,0,255)}
-span#textcolor3613{color:rgb(0,127,0)}
-span#textcolor3614{color:rgb(0,127,0)}
-span#textcolor3615{color:rgb(0,127,0)}
-span#textcolor3616{color:rgb(0,127,0)}
-span#textcolor3617{color:rgb(0,0,255)}
-span#textcolor3618{color:rgb(43,145,175)}
-span#textcolor3619{color:rgb(0,0,255)}
-span#textcolor3620{color:rgb(0,127,0)}
-span#textcolor3621{color:rgb(43,145,175)}
-span#textcolor3622{color:rgb(0,127,0)}
-span#textcolor3623{color:rgb(43,145,175)}
-span#textcolor3624{color:rgb(0,127,0)}
-span#textcolor3625{color:rgb(0,127,0)}
-span#textcolor3626{color:rgb(43,145,175)}
-span#textcolor3627{color:rgb(0,0,255)}
-span#textcolor3628{color:rgb(43,145,175)}
-span#textcolor3629{color:rgb(0,0,255)}
-span#textcolor3630{color:rgb(0,127,0)}
-span#textcolor3631{color:rgb(0,127,0)}
-span#textcolor3632{color:rgb(0,0,255)}
-span#textcolor3633{color:rgb(0,127,0)}
-span#textcolor3634{color:rgb(0,127,0)}
-span#textcolor3635{color:rgb(0,0,255)}
-span#textcolor3636{color:rgb(0,127,0)}
-span#textcolor3637{color:rgb(0,127,0)}
-span#textcolor3638{color:rgb(0,127,0)}
-span#textcolor3639{color:rgb(0,127,0)}
-span#textcolor3640{color:rgb(0,127,0)}
-span#textcolor3641{color:rgb(0,127,0)}
-span#textcolor3642{color:rgb(0,127,0)}
-span#textcolor3643{color:rgb(0,0,255)}
-span#textcolor3644{color:rgb(0,127,0)}
-span#textcolor3645{color:rgb(0,0,255)}
-span#textcolor3646{color:rgb(43,145,175)}
-span#textcolor3647{color:rgb(0,0,255)}
-span#textcolor3648{color:rgb(0,0,255)}
-span#textcolor3649{color:rgb(43,145,175)}
-span#textcolor3650{color:rgb(43,145,175)}
-span#textcolor3651{color:rgb(43,145,175)}
-span#textcolor3652{color:rgb(0,0,255)}
-span#textcolor3653{color:rgb(163,20,20)}
-span#textcolor3654{color:rgb(163,20,20)}
-span#textcolor3655{color:rgb(163,20,20)}
-span#textcolor3656{color:rgb(0,0,255)}
-span#textcolor3657{color:rgb(0,0,255)}
-span#textcolor3658{color:rgb(0,0,255)}
-span#textcolor3659{color:rgb(0,0,255)}
-span#textcolor3660{color:rgb(163,20,20)}
-span#textcolor3661{color:rgb(163,20,20)}
-span#textcolor3662{color:rgb(0,0,255)}
-span#textcolor3663{color:rgb(0,0,255)}
-span#textcolor3664{color:rgb(163,20,20)}
-span#textcolor3665{color:rgb(163,20,20)}
-span#textcolor3666{color:rgb(0,0,255)}
-span#textcolor3667{color:rgb(163,20,20)}
-span#textcolor3668{color:rgb(163,20,20)}
-span#textcolor3669{color:rgb(163,20,20)}
-span#textcolor3670{color:rgb(0,0,255)}
-span#textcolor3671{color:rgb(0,127,0)}
-span#textcolor3672{color:rgb(0,0,255)}
-span#textcolor3673{color:rgb(163,20,20)}
-pre#fancyvrb103{padding:5.69054pt;}
-pre#fancyvrb103{ border-top: solid 0.4pt; }
-pre#fancyvrb103{ border-left: solid 0.4pt; }
-pre#fancyvrb103{ border-bottom: solid 0.4pt; }
-pre#fancyvrb103{ border-right: solid 0.4pt; }
-pre#fancyvrb104{padding:5.69054pt;}
-pre#fancyvrb104{ border-top: solid 0.4pt; }
-pre#fancyvrb104{ border-left: solid 0.4pt; }
-pre#fancyvrb104{ border-bottom: solid 0.4pt; }
-pre#fancyvrb104{ border-right: solid 0.4pt; }
/* end css.sty */
diff --git a/lkmpg-for-ht.html b/lkmpg-for-ht.html
index faf3de8..9ae954c 100644
--- a/lkmpg-for-ht.html
+++ b/lkmpg-for-ht.html
@@ -85,18 +85,15 @@
The Linux Kernel Module Programming Guide is a free book; you may reproduce
@@ -111,14 +108,14 @@ the provisions of the Open Sof
distribute this book free of charge or for a profit. No explicit permission is required
from the author for reproduction of this book in any medium, physical or
electronic.
-
-
-
Derivative works and translations of this document must be placed under the
Open Software License, and the original copyright notice must remain intact. If you
have contributed new material to this book, you must make the material and source
code available for your revisions. Please make revisions and updates available directly
to the document maintainer, Jim Huang <jserv@ccns.ncku.edu.tw>. This will allow
+
+
+
for the merging of updates and provide consistent revisions to the Linux
community.
If you publish or distribute this book commercially, donations, royalties, and/or
@@ -153,13 +150,13 @@ Scarpazza, David Porter, demonsome, Dimo Velev, Ekang Monyet, Ethan
Chan, fennecJ, Francois Audeon, Gilad Reti, heartofrain, Horst Schirmeier,
Hsin-Hsiang Peng, Ignacio Martin, Iûnn Kiàn-îng, Jian-Xing Wu, Johan
Calle, keytouch, Kohei Otsuka, Kuan-Wei Chiu, manbing, Marconi Jiang,
-
-
-
mengxinayan, Peter Lin, Roman Lakeev, Sam Erickson, Shao-Tse Hung,
Shih-Sheng Yang, Stacy Prowell, Steven Lung, Tristan Lelong, Tse-Wei Lin,
Tucker Polomik, Tyler Fanelli, VxTeemo, Wei-Lun Tsai, Xatierlike Lee,
Yin-Chiuan Chen, Yi-Wei Lin, Ylowy, Yu-Hsiang Tseng.
On Arch Linux:
+
- To discover what modules are already loaded within your current kernel use the command
At the dawn of the internet, everybody trusted everybody completely…but that did
-not work out so well. When this guide was originally written, it was a more innocent
-era in which almost nobody actually gave a damn about crypto - least of all kernel
-developers. That is certainly no longer the case now. To handle crypto stuff, the
-kernel has its own API enabling common methods of encryption, decryption and your
-favourite hash functions.
-
- Calculating and checking the hashes of things is a common operation.
-Here is a demonstration of how to calculate a sha256 hash within a
-kernel module. To provide the sha256 algorithm support, make sure
-
- Install the module:
-
- And you should see that the hash was calculated for the test string.
- Finally, remove the test module:
-
-
-
-
-
- Here is an example of symmetrically encrypting a string using the AES algorithm
-and a password.
-
-
- The input device driver is a module that provides a way to communicate
+ The input device driver is a module that provides a way to communicate
with the interaction device via the event. For example, the keyboard
can send the press or release event to tell the kernel what we want to
do. The input device driver will allocate a new input structure with
@@ -5718,7 +5409,7 @@ do. The input device driver will allocate a new input structure with
Here is an example, vinput, It is an API to allow easy
+ Here is an example, vinput, It is an API to allow easy
development of virtual input drivers. The drivers needs to export a
Then using Then using
This function is passed a This function is passed a
This function will receive a user string to interpret and inject the event using the
+ This function will receive a user string to interpret and inject the event using the
This function is used for debugging and should fill the buffer parameter with the
+ This function is used for debugging and should fill the buffer parameter with the
last event sent in the virtual input device format. The buffer will then be copied to
user.
- vinput devices are created and destroyed using sysfs. And, event injection is done
+ vinput devices are created and destroyed using sysfs. And, event injection is done
through a /dev node. The device name will be used by the userland to export a new
virtual input device.
- The The
In vinput.c, the macro In vinput.c, the macro To create a vinputX sysfs entry and /dev node.
+ To create a vinputX sysfs entry and /dev node.
To unexport the device, just echo its id in unexport:
+ To unexport the device, just echo its id in unexport:
Here the virtual keyboard is one of example to use vinput. It supports all
+ Here the virtual keyboard is one of example to use vinput. It supports all
Simulate a key press on "g" ( Simulate a key press on "g" (
Simulate a key release on "g" ( Simulate a key release on "g" (
+
+
Up to this point we have seen all kinds of modules doing all kinds of things, but there
+ Up to this point we have seen all kinds of modules doing all kinds of things, but there
was no consistency in their interfaces with the rest of the kernel. To impose some
consistency such that there is at minimum a standardized way to start, suspend and
resume a device model was added. An example is shown below, and you can
@@ -6396,111 +6090,111 @@ use this as a template to add your own suspend, resume or other interface
functions.
+
+
Sometimes you might want your code to run as quickly as possible,
+ Sometimes you might want your code to run as quickly as possible,
especially if it is handling an interrupt or doing something which might
cause noticeable latency. If your code contains boolean conditions and if
you know that the conditions are almost always likely to evaluate as either
@@ -6512,40 +6206,40 @@ you know that the conditions are almost always likely to evaluate as either
+ When the When the
+
Static keys allow us to enable or disable kernel code paths based on the runtime state
+ Static keys allow us to enable or disable kernel code paths based on the runtime state
of key. Its APIs have been available since 2010 (most architectures are already
supported), use self-modifying code to eliminate the overhead of cache and branch
prediction. The most typical use case of static keys is for performance-sensitive kernel
code, such as tracepoints, context switching, networking, etc. These hot paths of the
kernel often contain branches and can be optimized easily using this technique.
Before we can use static keys in the kernel, we need to make sure that gcc supports
-
To declare a static key, we need to define a global variable using the
+ To declare a static key, we need to define a global variable using the
Once the static key has been declared, we need to add branching code to the
+ Once the static key has been declared, we need to add branching code to the
module that uses the static key. For example, the code includes a fastpath, where a
no-op instruction will be generated at compile time as the key is initialized to false
and the branch is unlikely to be taken.
If the key is enabled at runtime by calling
+ If the key is enabled at runtime by calling
- The following kernel module derived from chardev.c, demonstrates how the
+ The following kernel module derived from chardev.c, demonstrates how the
static key works.
To check the state of the static key, we can use the /dev/key_state
+ To check the state of the static key, we can use the /dev/key_state
interface.
This will display the current state of the key, which is disabled by default.
- To change the state of the static key, we can perform a write operation on the
+ This will display the current state of the key, which is disabled by default.
+ To change the state of the static key, we can perform a write operation on the
file:
This will enable the static key, causing the code path to switch from the fastpath
+ This will enable the static key, causing the code path to switch from the fastpath
to the slowpath.
- In some cases, the key is enabled or disabled at initialization and never changed,
+ In some cases, the key is enabled or disabled at initialization and never changed,
we can declare a static key as read-only, which means that it can only be toggled in
the module init function. To declare a read-only static key, we can use the
+
+
You can not do that. In a kernel module, you can only use kernel functions which are
+the functions you can see in /proc/kallsyms.
- You can not do that. In a kernel module, you can only use kernel functions which are
-the functions you can see in /proc/kallsyms.
-
+
You might need to do this for a short time and that is OK, but if you do not enable
+ You might need to do this for a short time and that is OK, but if you do not enable
them afterwards, your system will be stuck and you will have to power it
off.
-
+
For those deeply interested in kernel programming, kernelnewbies.org and the
+ For those deeply interested in kernel programming, kernelnewbies.org and the
Documentation subdirectory within the kernel source code are highly recommended.
Although the latter may not always be straightforward, it serves as a valuable initial
step for further exploration. Echoing Linus Torvalds’ perspective, the most effective
method to understand the kernel is through personal examination of the source
code.
- Contributions to this guide are welcome, especially if there are any significant
+ Contributions to this guide are welcome, especially if there are any significant
inaccuracies identified. To contribute or report an issue, please initiate an
issue at https://github.com/sysprog21/lkmpg. Pull requests are greatly
appreciated.
- Happy hacking!
+ Happy hacking!
1The goal of threaded interrupts is to push more of the work to separate threads, so that the
minimum needed for acknowledging an interrupt is reduced, and therefore the time spent handling
vinput_register_device()
+
vinput_register_device()
and vinput_unregister_device()
will add a new device to the list of support virtual input devices.
1int init(struct vinput *);
- struct vinput
-
already initialized with an allocated struct input_dev
+
1int init(struct vinput *);
+ struct vinput
+
already initialized with an allocated struct input_dev
. The init()
function is responsible for initializing the capabilities of the input device and register
it.
1int send(struct vinput *, char *, int);
-1int send(struct vinput *, char *, int);
+ input_report_XXXX
or input_event
call. The string is already copied from user.
1int read(struct vinput *, char *, int);
-1int read(struct vinput *, char *, int);
+ class_attribute
+
class_attribute
structure is similar to other attribute types we talked about in section 8:
1struct class_attribute {
-2 struct attribute attr;
-3 ssize_t (*show)(struct class *class, struct class_attribute *attr,
-4 char *buf);
-5 ssize_t (*store)(struct class *class, struct class_attribute *attr,
-6 const char *buf, size_t count);
-7};
-
-
-
- CLASS_ATTR_WO(export/unexport)
+
macros. For example, when allocating memory you are almost always expecting this
to succeed.
1struct class_attribute {
+2 struct attribute attr;
+3 ssize_t (*show)(struct class *class, struct class_attribute *attr,
+4 char *buf);
+5 ssize_t (*store)(struct class *class, struct class_attribute *attr,
+6 const char *buf, size_t count);
+7};
+ CLASS_ATTR_WO(export/unexport)
defined in include/linux/device.h (in this case, device.h is included in include/linux/input.h)
will generate the class_attribute
structures which are named class_attr_export/unexport. Then, put them into
+
+
+
vinput_class_attrs
array and the macro ATTRIBUTE_GROUPS(vinput_class)
-
will generate the struct attribute_group vinput_class_group
+
will generate the struct attribute_group vinput_class_group
that should be assigned in vinput_class
. Finally, call class_register(&vinput_class)
to create attributes in sysfs.
-1echo "vkbd" | sudo tee /sys/class/vinput/export
-1echo "vkbd" | sudo tee /sys/class/vinput/export
+1echo "0" | sudo tee /sys/class/vinput/unexport
+ 1echo "0" | sudo tee /sys/class/vinput/unexport
1/*
-2 * vinput.h
-3 */
-4
-5#ifndef VINPUT_H
-6#define VINPUT_H
-7
-8#include <linux/input.h>
-9#include <linux/spinlock.h>
-10
-11#define VINPUT_MAX_LEN 128
-12#define MAX_VINPUT 32
-13#define VINPUT_MINORS MAX_VINPUT
-14
-15#define dev_to_vinput(dev) container_of(dev, struct vinput, dev)
-16
-17struct vinput_device;
-18
-19struct vinput {
-20 long id;
-21 long devno;
-22 long last_entry;
-23 spinlock_t lock;
-24
-25 void *priv_data;
-26
-27 struct device dev;
-28 struct list_head list;
-29 struct input_dev *input;
-30 struct vinput_device *type;
-31};
-32
-33struct vinput_ops {
-34 int (*init)(struct vinput *);
-35 int (*kill)(struct vinput *);
-36 int (*send)(struct vinput *, char *, int);
-37 int (*read)(struct vinput *, char *, int);
-38};
-39
-40struct vinput_device {
-41 char name[16];
-42 struct list_head list;
-43 struct vinput_ops *ops;
-44};
-45
-46int vinput_register(struct vinput_device *dev);
-47void vinput_unregister(struct vinput_device *dev);
-48
-49#endif
+ 1/*
+2 * vinput.h
+3 */
+4
+5#ifndef VINPUT_H
+6#define VINPUT_H
+7
+8#include <linux/input.h>
+9#include <linux/spinlock.h>
+10
+11#define VINPUT_MAX_LEN 128
+12#define MAX_VINPUT 32
+13#define VINPUT_MINORS MAX_VINPUT
+14
+15#define dev_to_vinput(dev) container_of(dev, struct vinput, dev)
+16
+17struct vinput_device;
+18
+19struct vinput {
+20 long id;
+21 long devno;
+22 long last_entry;
+23 spinlock_t lock;
+24
+25 void *priv_data;
+26
+27 struct device dev;
+28 struct list_head list;
+29 struct input_dev *input;
+30 struct vinput_device *type;
+31};
+32
+33struct vinput_ops {
+34 int (*init)(struct vinput *);
+35 int (*kill)(struct vinput *);
+36 int (*send)(struct vinput *, char *, int);
+37 int (*read)(struct vinput *, char *, int);
+38};
+39
+40struct vinput_device {
+41 char name[16];
+42 struct list_head list;
+43 struct vinput_ops *ops;
+44};
+45
+46int vinput_register(struct vinput_device *dev);
+47void vinput_unregister(struct vinput_device *dev);
+48
+49#endif
1/*
-2 * vinput.c
-3 */
-4
-5#include <linux/cdev.h>
-6#include <linux/input.h>
-7#include <linux/module.h>
-8#include <linux/slab.h>
-9#include <linux/spinlock.h>
-10
-11#include <asm/uaccess.h>
-12
-13#include "vinput.h"
-14
-15#define DRIVER_NAME "vinput"
-16
-17#define dev_to_vinput(dev) container_of(dev, struct vinput, dev)
-18
-19static DECLARE_BITMAP(vinput_ids, VINPUT_MINORS);
-20
-21static LIST_HEAD(vinput_devices);
-22static LIST_HEAD(vinput_vdevices);
-23
-24static int vinput_dev;
-25static struct spinlock vinput_lock;
-26static struct class vinput_class;
-27
-28/* Search the name of vinput device in the vinput_devices linked list,
-29 * which added at vinput_register().
-30 */
-31static struct vinput_device *vinput_get_device_by_type(const char *type)
-32{
-33 int found = 0;
-34 struct vinput_device *vinput;
-35 struct list_head *curr;
-36
-37 spin_lock(&vinput_lock);
-38 list_for_each (curr, &vinput_devices) {
-39 vinput = list_entry(curr, struct vinput_device, list);
-40 if (vinput && strncmp(type, vinput->name, strlen(vinput->name)) == 0) {
-41 found = 1;
-42 break;
-43 }
-44 }
-45 spin_unlock(&vinput_lock);
-46
-47 if (found)
-48 return vinput;
-49 return ERR_PTR(-ENODEV);
-50}
-51
-52/* Search the id of virtual device in the vinput_vdevices linked list,
-53 * which added at vinput_alloc_vdevice().
-54 */
-55static struct vinput *vinput_get_vdevice_by_id(long id)
-56{
-57 struct vinput *vinput = NULL;
-58 struct list_head *curr;
-59
-60 spin_lock(&vinput_lock);
-61 list_for_each (curr, &vinput_vdevices) {
-62 vinput = list_entry(curr, struct vinput, list);
-63 if (vinput && vinput->id == id)
-64 break;
-65 }
-66 spin_unlock(&vinput_lock);
-67
-68 if (vinput && vinput->id == id)
-69 return vinput;
-70 return ERR_PTR(-ENODEV);
-71}
-72
-73static int vinput_open(struct inode *inode, struct file *file)
-74{
-75 int err = 0;
-76 struct vinput *vinput = NULL;
-77
-78 vinput = vinput_get_vdevice_by_id(iminor(inode));
-79
-80 if (IS_ERR(vinput))
-81 err = PTR_ERR(vinput);
-82 else
-83 file->private_data = vinput;
-84
-85 return err;
-86}
-87
-88static int vinput_release(struct inode *inode, struct file *file)
-89{
-90 return 0;
-91}
-92
-93static ssize_t vinput_read(struct file *file, char __user *buffer, size_t count,
-94 loff_t *offset)
-95{
-96 int len;
-97 char buff[VINPUT_MAX_LEN + 1];
-98 struct vinput *vinput = file->private_data;
-99
-100 len = vinput->type->ops->read(vinput, buff, count);
-101
-102 if (*offset > len)
-103 count = 0;
-104 else if (count + *offset > VINPUT_MAX_LEN)
-105 count = len - *offset;
-106
-107 if (raw_copy_to_user(buffer, buff + *offset, count))
-108 count = -EFAULT;
-109
-110 *offset += count;
-111
-112 return count;
-113}
-114
-115static ssize_t vinput_write(struct file *file, const char __user *buffer,
-116 size_t count, loff_t *offset)
-117{
-118 char buff[VINPUT_MAX_LEN + 1];
-119 struct vinput *vinput = file->private_data;
-120
-121 memset(buff, 0, sizeof(char) * (VINPUT_MAX_LEN + 1));
-122
-123 if (count > VINPUT_MAX_LEN) {
-124 dev_warn(&vinput->dev, "Too long. %d bytes allowed\n", VINPUT_MAX_LEN);
-125 return -EINVAL;
-126 }
-127
-128 if (raw_copy_from_user(buff, buffer, count))
-129 return -EFAULT;
-130
-131 return vinput->type->ops->send(vinput, buff, count);
-132}
-133
-134static const struct file_operations vinput_fops = {
-135 .owner = THIS_MODULE,
-136 .open = vinput_open,
-137 .release = vinput_release,
-138 .read = vinput_read,
-139 .write = vinput_write,
-140};
-141
-142static void vinput_unregister_vdevice(struct vinput *vinput)
-143{
-144 input_unregister_device(vinput->input);
-145 if (vinput->type->ops->kill)
-146 vinput->type->ops->kill(vinput);
-147}
-148
-149static void vinput_destroy_vdevice(struct vinput *vinput)
-150{
-151 /* Remove from the list first */
-152 spin_lock(&vinput_lock);
-153 list_del(&vinput->list);
-154 clear_bit(vinput->id, vinput_ids);
-155 spin_unlock(&vinput_lock);
-156
-157 module_put(THIS_MODULE);
-158
-159 kfree(vinput);
-160}
-161
-162static void vinput_release_dev(struct device *dev)
-163{
-164 struct vinput *vinput = dev_to_vinput(dev);
-165 int id = vinput->id;
-166
-167 vinput_destroy_vdevice(vinput);
-168
-169 pr_debug("released vinput%d.\n", id);
-170}
-171
-172static struct vinput *vinput_alloc_vdevice(void)
-173{
-174 int err;
-175 struct vinput *vinput = kzalloc(sizeof(struct vinput), GFP_KERNEL);
-176
-177 try_module_get(THIS_MODULE);
-178
-179 memset(vinput, 0, sizeof(struct vinput));
-180
-181 spin_lock_init(&vinput->lock);
-182
-183 spin_lock(&vinput_lock);
-184 vinput->id = find_first_zero_bit(vinput_ids, VINPUT_MINORS);
-185 if (vinput->id >= VINPUT_MINORS) {
-186 err = -ENOBUFS;
-187 goto fail_id;
-188 }
-189 set_bit(vinput->id, vinput_ids);
-190 list_add(&vinput->list, &vinput_vdevices);
-191 spin_unlock(&vinput_lock);
-192
-193 /* allocate the input device */
-194 vinput->input = input_allocate_device();
-195 if (vinput->input == NULL) {
-196 pr_err("vinput: Cannot allocate vinput input device\n");
-197 err = -ENOMEM;
-198 goto fail_input_dev;
-199 }
-200
-201 /* initialize device */
-202 vinput->dev.class = &vinput_class;
-203 vinput->dev.release = vinput_release_dev;
-204 vinput->dev.devt = MKDEV(vinput_dev, vinput->id);
-205 dev_set_name(&vinput->dev, DRIVER_NAME "%lu", vinput->id);
-206
-207 return vinput;
-208
-209fail_input_dev:
-210 spin_lock(&vinput_lock);
-211 list_del(&vinput->list);
-212fail_id:
-213 spin_unlock(&vinput_lock);
-214 module_put(THIS_MODULE);
-215 kfree(vinput);
-216
-217 return ERR_PTR(err);
-218}
-219
-220static int vinput_register_vdevice(struct vinput *vinput)
-221{
-222 int err = 0;
-223
-224 /* register the input device */
-225 vinput->input->name = vinput->type->name;
-226 vinput->input->phys = "vinput";
-227 vinput->input->dev.parent = &vinput->dev;
-228
-229 vinput->input->id.bustype = BUS_VIRTUAL;
-230 vinput->input->id.product = 0x0000;
-231 vinput->input->id.vendor = 0x0000;
-232 vinput->input->id.version = 0x0000;
-233
-234 err = vinput->type->ops->init(vinput);
-235
-236 if (err == 0)
-237 dev_info(&vinput->dev, "Registered virtual input %s %ld\n",
-238 vinput->type->name, vinput->id);
-239
-240 return err;
-241}
-242
-243static ssize_t export_store(struct class *class, struct class_attribute *attr,
-244 const char *buf, size_t len)
-245{
-246 int err;
-247 struct vinput *vinput;
-248 struct vinput_device *device;
-249
-250 device = vinput_get_device_by_type(buf);
-251 if (IS_ERR(device)) {
-252 pr_info("vinput: This virtual device isn't registered\n");
-253 err = PTR_ERR(device);
-254 goto fail;
-255 }
-256
-257 vinput = vinput_alloc_vdevice();
-258 if (IS_ERR(vinput)) {
-259 err = PTR_ERR(vinput);
-260 goto fail;
-261 }
-262
-263 vinput->type = device;
-264 err = device_register(&vinput->dev);
-265 if (err < 0)
-266 goto fail_register;
-267
-268 err = vinput_register_vdevice(vinput);
-269 if (err < 0)
-270 goto fail_register_vinput;
-271
-272 return len;
-273
-274fail_register_vinput:
-275 device_unregister(&vinput->dev);
-276fail_register:
-277 vinput_destroy_vdevice(vinput);
-278fail:
-279 return err;
-280}
-281/* This macro generates class_attr_export structure and export_store() */
-282static CLASS_ATTR_WO(export);
-283
-284static ssize_t unexport_store(struct class *class, struct class_attribute *attr,
-285 const char *buf, size_t len)
-286{
-287 int err;
-288 unsigned long id;
-289 struct vinput *vinput;
-290
-291 err = kstrtol(buf, 10, &id);
-292 if (err) {
-293 err = -EINVAL;
-294 goto failed;
-295 }
-296
-297 vinput = vinput_get_vdevice_by_id(id);
-298 if (IS_ERR(vinput)) {
-299 pr_err("vinput: No such vinput device %ld\n", id);
-300 err = PTR_ERR(vinput);
-301 goto failed;
-302 }
-303
-304 vinput_unregister_vdevice(vinput);
-305 device_unregister(&vinput->dev);
-306
-307 return len;
-308failed:
-309 return err;
-310}
-311/* This macro generates class_attr_unexport structure and unexport_store() */
-312static CLASS_ATTR_WO(unexport);
-313
-314static struct attribute *vinput_class_attrs[] = {
-315 &class_attr_export.attr,
-316 &class_attr_unexport.attr,
-317 NULL,
-318};
-319
-320/* This macro generates vinput_class_groups structure */
-321ATTRIBUTE_GROUPS(vinput_class);
-322
-323static struct class vinput_class = {
-324 .name = "vinput",
-325 .owner = THIS_MODULE,
-326 .class_groups = vinput_class_groups,
-327};
-328
-329int vinput_register(struct vinput_device *dev)
-330{
-331 spin_lock(&vinput_lock);
-332 list_add(&dev->list, &vinput_devices);
-333 spin_unlock(&vinput_lock);
-334
-335 pr_info("vinput: registered new virtual input device '%s'\n", dev->name);
-336
-337 return 0;
-338}
-339EXPORT_SYMBOL(vinput_register);
-340
-341void vinput_unregister(struct vinput_device *dev)
-342{
-343 struct list_head *curr, *next;
-344
-345 /* Remove from the list first */
-346 spin_lock(&vinput_lock);
-347 list_del(&dev->list);
-348 spin_unlock(&vinput_lock);
-349
-350 /* unregister all devices of this type */
-351 list_for_each_safe (curr, next, &vinput_vdevices) {
-352 struct vinput *vinput = list_entry(curr, struct vinput, list);
-353 if (vinput && vinput->type == dev) {
-354 vinput_unregister_vdevice(vinput);
-355 device_unregister(&vinput->dev);
-356 }
-357 }
-358
-359 pr_info("vinput: unregistered virtual input device '%s'\n", dev->name);
-360}
-361EXPORT_SYMBOL(vinput_unregister);
-362
-363static int __init vinput_init(void)
-364{
-365 int err = 0;
-366
-367 pr_info("vinput: Loading virtual input driver\n");
-368
-369 vinput_dev = register_chrdev(0, DRIVER_NAME, &vinput_fops);
-370 if (vinput_dev < 0) {
-371 pr_err("vinput: Unable to allocate char dev region\n");
-372 err = vinput_dev;
-373 goto failed_alloc;
-374 }
-375
-376 spin_lock_init(&vinput_lock);
-377
-378 err = class_register(&vinput_class);
-379 if (err < 0) {
-380 pr_err("vinput: Unable to register vinput class\n");
-381 goto failed_class;
-382 }
-383
-384 return 0;
-385failed_class:
-386 class_unregister(&vinput_class);
-387failed_alloc:
-388 return err;
-389}
-390
-391static void __exit vinput_end(void)
-392{
-393 pr_info("vinput: Unloading virtual input driver\n");
-394
-395 unregister_chrdev(vinput_dev, DRIVER_NAME);
-396 class_unregister(&vinput_class);
-397}
-398
-399module_init(vinput_init);
-400module_exit(vinput_end);
-401
-402MODULE_LICENSE("GPL");
-403MODULE_DESCRIPTION("Emulate input events");
-1/*
+2 * vinput.c
+3 */
+4
+5#include <linux/cdev.h>
+6#include <linux/input.h>
+7#include <linux/module.h>
+8#include <linux/slab.h>
+9#include <linux/spinlock.h>
+10
+11#include <asm/uaccess.h>
+12
+13#include "vinput.h"
+14
+15#define DRIVER_NAME "vinput"
+16
+17#define dev_to_vinput(dev) container_of(dev, struct vinput, dev)
+18
+19static DECLARE_BITMAP(vinput_ids, VINPUT_MINORS);
+20
+21static LIST_HEAD(vinput_devices);
+22static LIST_HEAD(vinput_vdevices);
+23
+24static int vinput_dev;
+25static struct spinlock vinput_lock;
+26static struct class vinput_class;
+27
+28/* Search the name of vinput device in the vinput_devices linked list,
+29 * which added at vinput_register().
+30 */
+31static struct vinput_device *vinput_get_device_by_type(const char *type)
+32{
+33 int found = 0;
+34 struct vinput_device *vinput;
+35 struct list_head *curr;
+36
+37 spin_lock(&vinput_lock);
+38 list_for_each (curr, &vinput_devices) {
+39 vinput = list_entry(curr, struct vinput_device, list);
+40 if (vinput && strncmp(type, vinput->name, strlen(vinput->name)) == 0) {
+41 found = 1;
+42 break;
+43 }
+44 }
+45 spin_unlock(&vinput_lock);
+46
+47 if (found)
+48 return vinput;
+49 return ERR_PTR(-ENODEV);
+50}
+51
+52/* Search the id of virtual device in the vinput_vdevices linked list,
+53 * which added at vinput_alloc_vdevice().
+54 */
+55static struct vinput *vinput_get_vdevice_by_id(long id)
+56{
+57 struct vinput *vinput = NULL;
+58 struct list_head *curr;
+59
+60 spin_lock(&vinput_lock);
+61 list_for_each (curr, &vinput_vdevices) {
+62 vinput = list_entry(curr, struct vinput, list);
+63 if (vinput && vinput->id == id)
+64 break;
+65 }
+66 spin_unlock(&vinput_lock);
+67
+68 if (vinput && vinput->id == id)
+69 return vinput;
+70 return ERR_PTR(-ENODEV);
+71}
+72
+73static int vinput_open(struct inode *inode, struct file *file)
+74{
+75 int err = 0;
+76 struct vinput *vinput = NULL;
+77
+78 vinput = vinput_get_vdevice_by_id(iminor(inode));
+79
+80 if (IS_ERR(vinput))
+81 err = PTR_ERR(vinput);
+82 else
+83 file->private_data = vinput;
+84
+85 return err;
+86}
+87
+88static int vinput_release(struct inode *inode, struct file *file)
+89{
+90 return 0;
+91}
+92
+93static ssize_t vinput_read(struct file *file, char __user *buffer, size_t count,
+94 loff_t *offset)
+95{
+96 int len;
+97 char buff[VINPUT_MAX_LEN + 1];
+98 struct vinput *vinput = file->private_data;
+99
+100 len = vinput->type->ops->read(vinput, buff, count);
+101
+102 if (*offset > len)
+103 count = 0;
+104 else if (count + *offset > VINPUT_MAX_LEN)
+105 count = len - *offset;
+106
+107 if (raw_copy_to_user(buffer, buff + *offset, count))
+108 count = -EFAULT;
+109
+110 *offset += count;
+111
+112 return count;
+113}
+114
+115static ssize_t vinput_write(struct file *file, const char __user *buffer,
+116 size_t count, loff_t *offset)
+117{
+118 char buff[VINPUT_MAX_LEN + 1];
+119 struct vinput *vinput = file->private_data;
+120
+121 memset(buff, 0, sizeof(char) * (VINPUT_MAX_LEN + 1));
+122
+123 if (count > VINPUT_MAX_LEN) {
+124 dev_warn(&vinput->dev, "Too long. %d bytes allowed\n", VINPUT_MAX_LEN);
+125 return -EINVAL;
+126 }
+127
+128 if (raw_copy_from_user(buff, buffer, count))
+129 return -EFAULT;
+130
+131 return vinput->type->ops->send(vinput, buff, count);
+132}
+133
+134static const struct file_operations vinput_fops = {
+135 .owner = THIS_MODULE,
+136 .open = vinput_open,
+137 .release = vinput_release,
+138 .read = vinput_read,
+139 .write = vinput_write,
+140};
+141
+142static void vinput_unregister_vdevice(struct vinput *vinput)
+143{
+144 input_unregister_device(vinput->input);
+145 if (vinput->type->ops->kill)
+146 vinput->type->ops->kill(vinput);
+147}
+148
+149static void vinput_destroy_vdevice(struct vinput *vinput)
+150{
+151 /* Remove from the list first */
+152 spin_lock(&vinput_lock);
+153 list_del(&vinput->list);
+154 clear_bit(vinput->id, vinput_ids);
+155 spin_unlock(&vinput_lock);
+156
+157 module_put(THIS_MODULE);
+158
+159 kfree(vinput);
+160}
+161
+162static void vinput_release_dev(struct device *dev)
+163{
+164 struct vinput *vinput = dev_to_vinput(dev);
+165 int id = vinput->id;
+166
+167 vinput_destroy_vdevice(vinput);
+168
+169 pr_debug("released vinput%d.\n", id);
+170}
+171
+172static struct vinput *vinput_alloc_vdevice(void)
+173{
+174 int err;
+175 struct vinput *vinput = kzalloc(sizeof(struct vinput), GFP_KERNEL);
+176
+177 try_module_get(THIS_MODULE);
+178
+179 memset(vinput, 0, sizeof(struct vinput));
+180
+181 spin_lock_init(&vinput->lock);
+182
+183 spin_lock(&vinput_lock);
+184 vinput->id = find_first_zero_bit(vinput_ids, VINPUT_MINORS);
+185 if (vinput->id >= VINPUT_MINORS) {
+186 err = -ENOBUFS;
+187 goto fail_id;
+188 }
+189 set_bit(vinput->id, vinput_ids);
+190 list_add(&vinput->list, &vinput_vdevices);
+191 spin_unlock(&vinput_lock);
+192
+193 /* allocate the input device */
+194 vinput->input = input_allocate_device();
+195 if (vinput->input == NULL) {
+196 pr_err("vinput: Cannot allocate vinput input device\n");
+197 err = -ENOMEM;
+198 goto fail_input_dev;
+199 }
+200
+201 /* initialize device */
+202 vinput->dev.class = &vinput_class;
+203 vinput->dev.release = vinput_release_dev;
+204 vinput->dev.devt = MKDEV(vinput_dev, vinput->id);
+205 dev_set_name(&vinput->dev, DRIVER_NAME "%lu", vinput->id);
+206
+207 return vinput;
+208
+209fail_input_dev:
+210 spin_lock(&vinput_lock);
+211 list_del(&vinput->list);
+212fail_id:
+213 spin_unlock(&vinput_lock);
+214 module_put(THIS_MODULE);
+215 kfree(vinput);
+216
+217 return ERR_PTR(err);
+218}
+219
+220static int vinput_register_vdevice(struct vinput *vinput)
+221{
+222 int err = 0;
+223
+224 /* register the input device */
+225 vinput->input->name = vinput->type->name;
+226 vinput->input->phys = "vinput";
+227 vinput->input->dev.parent = &vinput->dev;
+228
+229 vinput->input->id.bustype = BUS_VIRTUAL;
+230 vinput->input->id.product = 0x0000;
+231 vinput->input->id.vendor = 0x0000;
+232 vinput->input->id.version = 0x0000;
+233
+234 err = vinput->type->ops->init(vinput);
+235
+236 if (err == 0)
+237 dev_info(&vinput->dev, "Registered virtual input %s %ld\n",
+238 vinput->type->name, vinput->id);
+239
+240 return err;
+241}
+242
+243static ssize_t export_store(struct class *class, struct class_attribute *attr,
+244 const char *buf, size_t len)
+245{
+246 int err;
+247 struct vinput *vinput;
+248 struct vinput_device *device;
+249
+250 device = vinput_get_device_by_type(buf);
+251 if (IS_ERR(device)) {
+252 pr_info("vinput: This virtual device isn't registered\n");
+253 err = PTR_ERR(device);
+254 goto fail;
+255 }
+256
+257 vinput = vinput_alloc_vdevice();
+258 if (IS_ERR(vinput)) {
+259 err = PTR_ERR(vinput);
+260 goto fail;
+261 }
+262
+263 vinput->type = device;
+264 err = device_register(&vinput->dev);
+265 if (err < 0)
+266 goto fail_register;
+267
+268 err = vinput_register_vdevice(vinput);
+269 if (err < 0)
+270 goto fail_register_vinput;
+271
+272 return len;
+273
+274fail_register_vinput:
+275 device_unregister(&vinput->dev);
+276fail_register:
+277 vinput_destroy_vdevice(vinput);
+278fail:
+279 return err;
+280}
+281/* This macro generates class_attr_export structure and export_store() */
+282static CLASS_ATTR_WO(export);
+283
+284static ssize_t unexport_store(struct class *class, struct class_attribute *attr,
+285 const char *buf, size_t len)
+286{
+287 int err;
+288 unsigned long id;
+289 struct vinput *vinput;
+290
+291 err = kstrtol(buf, 10, &id);
+292 if (err) {
+293 err = -EINVAL;
+294 goto failed;
+295 }
+296
+297 vinput = vinput_get_vdevice_by_id(id);
+298 if (IS_ERR(vinput)) {
+299 pr_err("vinput: No such vinput device %ld\n", id);
+300 err = PTR_ERR(vinput);
+301 goto failed;
+302 }
+303
+304 vinput_unregister_vdevice(vinput);
+305 device_unregister(&vinput->dev);
+306
+307 return len;
+308failed:
+309 return err;
+310}
+311/* This macro generates class_attr_unexport structure and unexport_store() */
+312static CLASS_ATTR_WO(unexport);
+313
+314static struct attribute *vinput_class_attrs[] = {
+315 &class_attr_export.attr,
+316 &class_attr_unexport.attr,
+317 NULL,
+318};
+319
+320/* This macro generates vinput_class_groups structure */
+321ATTRIBUTE_GROUPS(vinput_class);
+322
+323static struct class vinput_class = {
+324 .name = "vinput",
+325 .owner = THIS_MODULE,
+326 .class_groups = vinput_class_groups,
+327};
+328
+329int vinput_register(struct vinput_device *dev)
+330{
+331 spin_lock(&vinput_lock);
+332 list_add(&dev->list, &vinput_devices);
+333 spin_unlock(&vinput_lock);
+334
+335 pr_info("vinput: registered new virtual input device '%s'\n", dev->name);
+336
+337 return 0;
+338}
+339EXPORT_SYMBOL(vinput_register);
+340
+341void vinput_unregister(struct vinput_device *dev)
+342{
+343 struct list_head *curr, *next;
+344
+345 /* Remove from the list first */
+346 spin_lock(&vinput_lock);
+347 list_del(&dev->list);
+348 spin_unlock(&vinput_lock);
+349
+350 /* unregister all devices of this type */
+351 list_for_each_safe (curr, next, &vinput_vdevices) {
+352 struct vinput *vinput = list_entry(curr, struct vinput, list);
+353 if (vinput && vinput->type == dev) {
+354 vinput_unregister_vdevice(vinput);
+355 device_unregister(&vinput->dev);
+356 }
+357 }
+358
+359 pr_info("vinput: unregistered virtual input device '%s'\n", dev->name);
+360}
+361EXPORT_SYMBOL(vinput_unregister);
+362
+363static int __init vinput_init(void)
+364{
+365 int err = 0;
+366
+367 pr_info("vinput: Loading virtual input driver\n");
+368
+369 vinput_dev = register_chrdev(0, DRIVER_NAME, &vinput_fops);
+370 if (vinput_dev < 0) {
+371 pr_err("vinput: Unable to allocate char dev region\n");
+372 err = vinput_dev;
+373 goto failed_alloc;
+374 }
+375
+376 spin_lock_init(&vinput_lock);
+377
+378 err = class_register(&vinput_class);
+379 if (err < 0) {
+380 pr_err("vinput: Unable to register vinput class\n");
+381 goto failed_class;
+382 }
+383
+384 return 0;
+385failed_class:
+386 class_unregister(&vinput_class);
+387failed_alloc:
+388 return err;
+389}
+390
+391static void __exit vinput_end(void)
+392{
+393 pr_info("vinput: Unloading virtual input driver\n");
+394
+395 unregister_chrdev(vinput_dev, DRIVER_NAME);
+396 class_unregister(&vinput_class);
+397}
+398
+399module_init(vinput_init);
+400module_exit(vinput_end);
+401
+402MODULE_LICENSE("GPL");
+403MODULE_DESCRIPTION("Emulate input events");
+ KEY_MAX
keycodes. The injection format is the KEY_CODE
such as defined in include/linux/input.h. A positive value means
@@ -6259,136 +5953,136 @@ will generate the class_attribute
while a negative value is a KEY_RELEASE
. The keyboard supports repetition when the key stays pressed for too long. The
following demonstrates how simulation work.
- KEY_G
+
KEY_G
= 34):
1echo "+34" | sudo tee /dev/vinput0
- KEY_G
+
1echo "+34" | sudo tee /dev/vinput0
+ KEY_G
= 34):
1echo "-34" | sudo tee /dev/vinput0
-1echo "-34" | sudo tee /dev/vinput0
1/*
-2 * vkbd.c
-3 */
-4
-5#include <linux/init.h>
-6#include <linux/input.h>
-7#include <linux/module.h>
-8#include <linux/spinlock.h>
-9
-10#include "vinput.h"
-11
-12#define VINPUT_KBD "vkbd"
-13#define VINPUT_RELEASE 0
-14#define VINPUT_PRESS 1
-15
-16static unsigned short vkeymap[KEY_MAX];
-17
-18static int vinput_vkbd_init(struct vinput *vinput)
-19{
-20 int i;
-21
-22 /* Set up the input bitfield */
-23 vinput->input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
-24 vinput->input->keycodesize = sizeof(unsigned short);
-25 vinput->input->keycodemax = KEY_MAX;
-26 vinput->input->keycode = vkeymap;
-27
-28 for (i = 0; i < KEY_MAX; i++)
-29 set_bit(vkeymap[i], vinput->input->keybit);
-30
-31 /* vinput will help us allocate new input device structure via
-32 * input_allocate_device(). So, we can register it straightforwardly.
-33 */
-34 return input_register_device(vinput->input);
-35}
-36
-37static int vinput_vkbd_read(struct vinput *vinput, char *buff, int len)
-38{
-39 spin_lock(&vinput->lock);
-40 len = snprintf(buff, len, "%+ld\n", vinput->last_entry);
-41 spin_unlock(&vinput->lock);
-42
-43 return len;
-44}
-45
-46static int vinput_vkbd_send(struct vinput *vinput, char *buff, int len)
-47{
-48 int ret;
-49 long key = 0;
-50 short type = VINPUT_PRESS;
-51
-52 /* Determine which event was received (press or release)
-53 * and store the state.
-54 */
-55 if (buff[0] == '+')
-56 ret = kstrtol(buff + 1, 10, &key);
-57 else
-58 ret = kstrtol(buff, 10, &key);
-59 if (ret)
-60 dev_err(&vinput->dev, "error during kstrtol: -%d\n", ret);
-61 spin_lock(&vinput->lock);
-62 vinput->last_entry = key;
-63 spin_unlock(&vinput->lock);
-64
-65 if (key < 0) {
-66 type = VINPUT_RELEASE;
-67 key = -key;
-68 }
-69
-70 dev_info(&vinput->dev, "Event %s code %ld\n",
-71 (type == VINPUT_RELEASE) ? "VINPUT_RELEASE" : "VINPUT_PRESS", key);
-72
-73 /* Report the state received to input subsystem. */
-74 input_report_key(vinput->input, key, type);
-75 /* Tell input subsystem that it finished the report. */
-76 input_sync(vinput->input);
-77
-78 return len;
-79}
-80
-81static struct vinput_ops vkbd_ops = {
-82 .init = vinput_vkbd_init,
-83 .send = vinput_vkbd_send,
-84 .read = vinput_vkbd_read,
-85};
-86
-87static struct vinput_device vkbd_dev = {
-88 .name = VINPUT_KBD,
-89 .ops = &vkbd_ops,
-90};
-91
-92static int __init vkbd_init(void)
-93{
-94 int i;
-95
-96 for (i = 0; i < KEY_MAX; i++)
-97 vkeymap[i] = i;
-98 return vinput_register(&vkbd_dev);
-99}
-100
-101static void __exit vkbd_end(void)
-102{
-103 vinput_unregister(&vkbd_dev);
-104}
-105
-106module_init(vkbd_init);
-107module_exit(vkbd_end);
-108
-109MODULE_LICENSE("GPL");
-110MODULE_DESCRIPTION("Emulate keyboard input events through /dev/vinput");
-1/*
+2 * vkbd.c
+3 */
+4
+5#include <linux/init.h>
+6#include <linux/input.h>
+7#include <linux/module.h>
+8#include <linux/spinlock.h>
+9
+10#include "vinput.h"
+11
+12#define VINPUT_KBD "vkbd"
+13#define VINPUT_RELEASE 0
+14#define VINPUT_PRESS 1
+15
+16static unsigned short vkeymap[KEY_MAX];
+17
+18static int vinput_vkbd_init(struct vinput *vinput)
+19{
+20 int i;
+21
+22 /* Set up the input bitfield */
+23 vinput->input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+24 vinput->input->keycodesize = sizeof(unsigned short);
+25 vinput->input->keycodemax = KEY_MAX;
+26 vinput->input->keycode = vkeymap;
+27
+28 for (i = 0; i < KEY_MAX; i++)
+29 set_bit(vkeymap[i], vinput->input->keybit);
+30
+31 /* vinput will help us allocate new input device structure via
+32 * input_allocate_device(). So, we can register it straightforwardly.
+33 */
+34 return input_register_device(vinput->input);
+35}
+36
+37static int vinput_vkbd_read(struct vinput *vinput, char *buff, int len)
+38{
+39 spin_lock(&vinput->lock);
+40 len = snprintf(buff, len, "%+ld\n", vinput->last_entry);
+41 spin_unlock(&vinput->lock);
+42
+43 return len;
+44}
+45
+46static int vinput_vkbd_send(struct vinput *vinput, char *buff, int len)
+47{
+48 int ret;
+49 long key = 0;
+50 short type = VINPUT_PRESS;
+51
+52 /* Determine which event was received (press or release)
+53 * and store the state.
+54 */
+55 if (buff[0] == '+')
+56 ret = kstrtol(buff + 1, 10, &key);
+57 else
+58 ret = kstrtol(buff, 10, &key);
+59 if (ret)
+60 dev_err(&vinput->dev, "error during kstrtol: -%d\n", ret);
+61 spin_lock(&vinput->lock);
+62 vinput->last_entry = key;
+63 spin_unlock(&vinput->lock);
+64
+65 if (key < 0) {
+66 type = VINPUT_RELEASE;
+67 key = -key;
+68 }
+69
+70 dev_info(&vinput->dev, "Event %s code %ld\n",
+71 (type == VINPUT_RELEASE) ? "VINPUT_RELEASE" : "VINPUT_PRESS", key);
+72
+73 /* Report the state received to input subsystem. */
+74 input_report_key(vinput->input, key, type);
+75 /* Tell input subsystem that it finished the report. */
+76 input_sync(vinput->input);
+77
+78 return len;
+79}
+80
+81static struct vinput_ops vkbd_ops = {
+82 .init = vinput_vkbd_init,
+83 .send = vinput_vkbd_send,
+84 .read = vinput_vkbd_read,
+85};
+86
+87static struct vinput_device vkbd_dev = {
+88 .name = VINPUT_KBD,
+89 .ops = &vkbd_ops,
+90};
+91
+92static int __init vkbd_init(void)
+93{
+94 int i;
+95
+96 for (i = 0; i < KEY_MAX; i++)
+97 vkeymap[i] = i;
+98 return vinput_register(&vkbd_dev);
+99}
+100
+101static void __exit vkbd_end(void)
+102{
+103 vinput_unregister(&vkbd_dev);
+104}
+105
+106module_init(vkbd_init);
+107module_exit(vkbd_end);
+108
+109MODULE_LICENSE("GPL");
+110MODULE_DESCRIPTION("Emulate keyboard input events through /dev/vinput");
+18 Standardizing the interfaces: The Device Model
-17 Standardizing the interfaces: The Device Model
+1/*
-2 * devicemodel.c
-3 */
-4#include <linux/kernel.h>
-5#include <linux/module.h>
-6#include <linux/platform_device.h>
-7
-8struct devicemodel_data {
-9 char *greeting;
-10 int number;
-11};
-12
-13static int devicemodel_probe(struct platform_device *dev)
-14{
-15 struct devicemodel_data *pd =
-16 (struct devicemodel_data *)(dev->dev.platform_data);
-17
-18 pr_info("devicemodel probe\n");
-19 pr_info("devicemodel greeting: %s; %d\n", pd->greeting, pd->number);
-20
-21 /* Your device initialization code */
-22
-23 return 0;
-24}
-25
-26static int devicemodel_remove(struct platform_device *dev)
-27{
-28 pr_info("devicemodel example removed\n");
-29
-30 /* Your device removal code */
-31
-32 return 0;
-33}
-34
-35static int devicemodel_suspend(struct device *dev)
-36{
-37 pr_info("devicemodel example suspend\n");
-38
-39 /* Your device suspend code */
-40
-41 return 0;
-42}
-43
-44static int devicemodel_resume(struct device *dev)
-45{
-46 pr_info("devicemodel example resume\n");
-47
-48 /* Your device resume code */
-49
-50 return 0;
-51}
-52
-53static const struct dev_pm_ops devicemodel_pm_ops = {
-54 .suspend = devicemodel_suspend,
-55 .resume = devicemodel_resume,
-56 .poweroff = devicemodel_suspend,
-57 .freeze = devicemodel_suspend,
-58 .thaw = devicemodel_resume,
-59 .restore = devicemodel_resume,
-60};
-61
-62static struct platform_driver devicemodel_driver = {
-63 .driver =
-64 {
-65 .name = "devicemodel_example",
-66 .pm = &devicemodel_pm_ops,
-67 },
-68 .probe = devicemodel_probe,
-69 .remove = devicemodel_remove,
-70};
-71
-72static int __init devicemodel_init(void)
-73{
-74 int ret;
-75
-76 pr_info("devicemodel init\n");
-77
-78 ret = platform_driver_register(&devicemodel_driver);
-79
-80 if (ret) {
-81 pr_err("Unable to register driver\n");
-82 return ret;
-83 }
-84
-85 return 0;
-86}
-87
-88static void __exit devicemodel_exit(void)
-89{
-90 pr_info("devicemodel exit\n");
-91 platform_driver_unregister(&devicemodel_driver);
-92}
-93
-94module_init(devicemodel_init);
-95module_exit(devicemodel_exit);
-96
-97MODULE_LICENSE("GPL");
-98MODULE_DESCRIPTION("Linux Device Model example");
-1/*
+2 * devicemodel.c
+3 */
+4#include <linux/kernel.h>
+5#include <linux/module.h>
+6#include <linux/platform_device.h>
+7
+8struct devicemodel_data {
+9 char *greeting;
+10 int number;
+11};
+12
+13static int devicemodel_probe(struct platform_device *dev)
+14{
+15 struct devicemodel_data *pd =
+16 (struct devicemodel_data *)(dev->dev.platform_data);
+17
+18 pr_info("devicemodel probe\n");
+19 pr_info("devicemodel greeting: %s; %d\n", pd->greeting, pd->number);
+20
+21 /* Your device initialization code */
+22
+23 return 0;
+24}
+25
+26static int devicemodel_remove(struct platform_device *dev)
+27{
+28 pr_info("devicemodel example removed\n");
+29
+30 /* Your device removal code */
+31
+32 return 0;
+33}
+34
+35static int devicemodel_suspend(struct device *dev)
+36{
+37 pr_info("devicemodel example suspend\n");
+38
+39 /* Your device suspend code */
+40
+41 return 0;
+42}
+43
+44static int devicemodel_resume(struct device *dev)
+45{
+46 pr_info("devicemodel example resume\n");
+47
+48 /* Your device resume code */
+49
+50 return 0;
+51}
+52
+53static const struct dev_pm_ops devicemodel_pm_ops = {
+54 .suspend = devicemodel_suspend,
+55 .resume = devicemodel_resume,
+56 .poweroff = devicemodel_suspend,
+57 .freeze = devicemodel_suspend,
+58 .thaw = devicemodel_resume,
+59 .restore = devicemodel_resume,
+60};
+61
+62static struct platform_driver devicemodel_driver = {
+63 .driver =
+64 {
+65 .name = "devicemodel_example",
+66 .pm = &devicemodel_pm_ops,
+67 },
+68 .probe = devicemodel_probe,
+69 .remove = devicemodel_remove,
+70};
+71
+72static int __init devicemodel_init(void)
+73{
+74 int ret;
+75
+76 pr_info("devicemodel init\n");
+77
+78 ret = platform_driver_register(&devicemodel_driver);
+79
+80 if (ret) {
+81 pr_err("Unable to register driver\n");
+82 return ret;
+83 }
+84
+85 return 0;
+86}
+87
+88static void __exit devicemodel_exit(void)
+89{
+90 pr_info("devicemodel exit\n");
+91 platform_driver_unregister(&devicemodel_driver);
+92}
+93
+94module_init(devicemodel_init);
+95module_exit(devicemodel_exit);
+96
+97MODULE_LICENSE("GPL");
+98MODULE_DESCRIPTION("Linux Device Model example");
+19 Optimizations
-18 Optimizations
+19.1 Likely and Unlikely conditions
-18.1 Likely and Unlikely conditions
+1bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx);
+2if (unlikely(!bvl)) {
+3 mempool_free(bio, bio_pool);
+4 bio = NULL;
+5 goto out;
+6}
-1bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx);
-2if (unlikely(!bvl)) {
-3 mempool_free(bio, bio_pool);
-4 bio = NULL;
-5 goto out;
-6}
- unlikely
+
unlikely
macro is used, the compiler alters its machine instruction output, so that it
continues along the false branch and only jumps if the condition is true. That
avoids flushing the processor pipeline. The opposite happens if you use the
likely
macro.
-19.2 Static keys
-18.2 Static keys
+ asm goto
+
asm goto
inline assembly, and the following kernel configurations are set:
1CONFIG_JUMP_LABEL=y
-2CONFIG_HAVE_ARCH_JUMP_LABEL=y
-3CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y
-1CONFIG_JUMP_LABEL=y
+2CONFIG_HAVE_ARCH_JUMP_LABEL=y
+3CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y
+ DEFINE_STATIC_KEY_FALSE
or DEFINE_STATIC_KEY_TRUE
macro defined in include/linux/jump_label.h. This macro initializes the key with
@@ -6554,268 +6248,268 @@ declare a static key with an initial value of false, we can use the following
code:
1DEFINE_STATIC_KEY_FALSE(fkey);
-1DEFINE_STATIC_KEY_FALSE(fkey);
+1pr_info("fastpath 1\n");
-2if (static_branch_unlikely(&fkey))
-3 pr_alert("do unlikely thing\n");
-4pr_info("fastpath 2\n");
+ 1pr_info("fastpath 1\n");
+2if (static_branch_unlikely(&fkey))
+3 pr_alert("do unlikely thing\n");
+4pr_info("fastpath 2\n");
+ static_branch_enable(&fkey)
+
, the fastpath will be patched with an unconditional jump instruction to the slowpath
- static_branch_enable(&fkey)
-
, the fastpath will be patched with an unconditional jump instruction to the slowpath
code pr_alert
, so the branch will always be taken until the key is disabled again.
-1/*
-2 * static_key.c
-3 */
-4
-5#include <linux/atomic.h>
-6#include <linux/device.h>
-7#include <linux/fs.h>
-8#include <linux/kernel.h> /* for sprintf() */
-9#include <linux/module.h>
-10#include <linux/printk.h>
-11#include <linux/types.h>
-12#include <linux/uaccess.h> /* for get_user and put_user */
-13#include <linux/jump_label.h> /* for static key macros */
-14
-15#include <asm/errno.h>
-16
-17static int device_open(struct inode *inode, struct file *file);
-18static int device_release(struct inode *inode, struct file *file);
-19static ssize_t device_read(struct file *file, char __user *buf, size_t count,
-20 loff_t *ppos);
-21static ssize_t device_write(struct file *file, const char __user *buf,
-22 size_t count, loff_t *ppos);
-23
-24#define SUCCESS 0
-25#define DEVICE_NAME "key_state"
-26#define BUF_LEN 10
-27
-28static int major;
-29
-30enum {
-31 CDEV_NOT_USED = 0,
-32 CDEV_EXCLUSIVE_OPEN = 1,
-33};
-34
-35static atomic_t already_open = ATOMIC_INIT(CDEV_NOT_USED);
-36
-37static char msg[BUF_LEN + 1];
-38
-39static struct class *cls;
-40
-41static DEFINE_STATIC_KEY_FALSE(fkey);
-42
-43static struct file_operations chardev_fops = {
-44 .owner = THIS_MODULE,
-45 .open = device_open,
-46 .release = device_release,
-47 .read = device_read,
-48 .write = device_write,
-49};
-50
-51static int __init chardev_init(void)
-52{
-53 major = register_chrdev(0, DEVICE_NAME, &chardev_fops);
-54 if (major < 0) {
-55 pr_alert("Registering char device failed with %d\n", major);
-56 return major;
-57 }
-58
-59 pr_info("I was assigned major number %d\n", major);
-60
-61 cls = class_create(THIS_MODULE, DEVICE_NAME);
-62
-63 device_create(cls, NULL, MKDEV(major, 0), NULL, DEVICE_NAME);
-64
-65 pr_info("Device created on /dev/%s\n", DEVICE_NAME);
-66
-67 return SUCCESS;
-68}
-69
-70static void __exit chardev_exit(void)
-71{
-72 device_destroy(cls, MKDEV(major, 0));
-73 class_destroy(cls);
-74
-75 /* Unregister the device */
-76 unregister_chrdev(major, DEVICE_NAME);
-77}
-78
-79/* Methods */
-80
-81/**
-82 * Called when a process tried to open the device file, like
-83 * cat /dev/key_state
-84 */
-85static int device_open(struct inode *inode, struct file *file)
-86{
-87 if (atomic_cmpxchg(&already_open, CDEV_NOT_USED, CDEV_EXCLUSIVE_OPEN))
-88 return -EBUSY;
-89
-90 sprintf(msg, static_key_enabled(&fkey) ? "enabled\n" : "disabled\n");
-91
-92 pr_info("fastpath 1\n");
-93 if (static_branch_unlikely(&fkey))
-94 pr_alert("do unlikely thing\n");
-95 pr_info("fastpath 2\n");
-96
-97 try_module_get(THIS_MODULE);
-98
-99 return SUCCESS;
-100}
-101
-102/**
-103 * Called when a process closes the device file
-104 */
-105static int device_release(struct inode *inode, struct file *file)
-106{
-107 /* We are now ready for our next caller. */
-108 atomic_set(&already_open, CDEV_NOT_USED);
-109
-110 /**
-111 * Decrement the usage count, or else once you opened the file, you will
-112 * never get rid of the module.
-113 */
-114 module_put(THIS_MODULE);
-115
-116 return SUCCESS;
-117}
-118
-119/**
-120 * Called when a process, which already opened the dev file, attempts to
-121 * read from it.
-122 */
-123static ssize_t device_read(struct file *filp, /* see include/linux/fs.h */
-124 char __user *buffer, /* buffer to fill with data */
-125 size_t length, /* length of the buffer */
-126 loff_t *offset)
-127{
-128 /* Number of the bytes actually written to the buffer */
-129 int bytes_read = 0;
-130 const char *msg_ptr = msg;
-131
-132 if (!*(msg_ptr + *offset)) { /* We are at the end of the message */
-133 *offset = 0; /* reset the offset */
-134 return 0; /* signify end of file */
-135 }
-136
-137 msg_ptr += *offset;
-138
-139 /* Actually put the data into the buffer */
-140 while (length && *msg_ptr) {
-141 /**
-142 * The buffer is in the user data segment, not the kernel
-143 * segment so "*" assignment won't work. We have to use
-144 * put_user which copies data from the kernel data segment to
-145 * the user data segment.
-146 */
-147 put_user(*(msg_ptr++), buffer++);
-148 length--;
-149 bytes_read++;
-150 }
-151
-152 *offset += bytes_read;
-153
-154 /* Most read functions return the number of bytes put into the buffer. */
-155 return bytes_read;
-156}
-157
-158/* Called when a process writes to dev file; echo "enable" > /dev/key_state */
-159static ssize_t device_write(struct file *filp, const char __user *buffer,
-160 size_t length, loff_t *offset)
-161{
-162 char command[10];
-163
-164 if (length > 10) {
-165 pr_err("command exceeded 10 char\n");
-166 return -EINVAL;
-167 }
-168
-169 if (copy_from_user(command, buffer, length))
-170 return -EFAULT;
-171
-172 if (strncmp(command, "enable", strlen("enable")) == 0)
-173 static_branch_enable(&fkey);
-174 else if (strncmp(command, "disable", strlen("disable")) == 0)
-175 static_branch_disable(&fkey);
-176 else {
-177 pr_err("Invalid command: %s\n", command);
-178 return -EINVAL;
-179 }
-180
-181 /* Again, return the number of input characters used. */
-182 return length;
-183}
-184
-185module_init(chardev_init);
-186module_exit(chardev_exit);
-187
-188MODULE_LICENSE("GPL");
-1/*
+2 * static_key.c
+3 */
+4
+5#include <linux/atomic.h>
+6#include <linux/device.h>
+7#include <linux/fs.h>
+8#include <linux/kernel.h> /* for sprintf() */
+9#include <linux/module.h>
+10#include <linux/printk.h>
+11#include <linux/types.h>
+12#include <linux/uaccess.h> /* for get_user and put_user */
+13#include <linux/jump_label.h> /* for static key macros */
+14
+15#include <asm/errno.h>
+16
+17static int device_open(struct inode *inode, struct file *file);
+18static int device_release(struct inode *inode, struct file *file);
+19static ssize_t device_read(struct file *file, char __user *buf, size_t count,
+20 loff_t *ppos);
+21static ssize_t device_write(struct file *file, const char __user *buf,
+22 size_t count, loff_t *ppos);
+23
+24#define SUCCESS 0
+25#define DEVICE_NAME "key_state"
+26#define BUF_LEN 10
+27
+28static int major;
+29
+30enum {
+31 CDEV_NOT_USED = 0,
+32 CDEV_EXCLUSIVE_OPEN = 1,
+33};
+34
+35static atomic_t already_open = ATOMIC_INIT(CDEV_NOT_USED);
+36
+37static char msg[BUF_LEN + 1];
+38
+39static struct class *cls;
+40
+41static DEFINE_STATIC_KEY_FALSE(fkey);
+42
+43static struct file_operations chardev_fops = {
+44 .owner = THIS_MODULE,
+45 .open = device_open,
+46 .release = device_release,
+47 .read = device_read,
+48 .write = device_write,
+49};
+50
+51static int __init chardev_init(void)
+52{
+53 major = register_chrdev(0, DEVICE_NAME, &chardev_fops);
+54 if (major < 0) {
+55 pr_alert("Registering char device failed with %d\n", major);
+56 return major;
+57 }
+58
+59 pr_info("I was assigned major number %d\n", major);
+60
+61 cls = class_create(THIS_MODULE, DEVICE_NAME);
+62
+63 device_create(cls, NULL, MKDEV(major, 0), NULL, DEVICE_NAME);
+64
+65 pr_info("Device created on /dev/%s\n", DEVICE_NAME);
+66
+67 return SUCCESS;
+68}
+69
+70static void __exit chardev_exit(void)
+71{
+72 device_destroy(cls, MKDEV(major, 0));
+73 class_destroy(cls);
+74
+75 /* Unregister the device */
+76 unregister_chrdev(major, DEVICE_NAME);
+77}
+78
+79/* Methods */
+80
+81/**
+82 * Called when a process tried to open the device file, like
+83 * cat /dev/key_state
+84 */
+85static int device_open(struct inode *inode, struct file *file)
+86{
+87 if (atomic_cmpxchg(&already_open, CDEV_NOT_USED, CDEV_EXCLUSIVE_OPEN))
+88 return -EBUSY;
+89
+90 sprintf(msg, static_key_enabled(&fkey) ? "enabled\n" : "disabled\n");
+91
+92 pr_info("fastpath 1\n");
+93 if (static_branch_unlikely(&fkey))
+94 pr_alert("do unlikely thing\n");
+95 pr_info("fastpath 2\n");
+96
+97 try_module_get(THIS_MODULE);
+98
+99 return SUCCESS;
+100}
+101
+102/**
+103 * Called when a process closes the device file
+104 */
+105static int device_release(struct inode *inode, struct file *file)
+106{
+107 /* We are now ready for our next caller. */
+108 atomic_set(&already_open, CDEV_NOT_USED);
+109
+110 /**
+111 * Decrement the usage count, or else once you opened the file, you will
+112 * never get rid of the module.
+113 */
+114 module_put(THIS_MODULE);
+115
+116 return SUCCESS;
+117}
+118
+119/**
+120 * Called when a process, which already opened the dev file, attempts to
+121 * read from it.
+122 */
+123static ssize_t device_read(struct file *filp, /* see include/linux/fs.h */
+124 char __user *buffer, /* buffer to fill with data */
+125 size_t length, /* length of the buffer */
+126 loff_t *offset)
+127{
+128 /* Number of the bytes actually written to the buffer */
+129 int bytes_read = 0;
+130 const char *msg_ptr = msg;
+131
+132 if (!*(msg_ptr + *offset)) { /* We are at the end of the message */
+133 *offset = 0; /* reset the offset */
+134 return 0; /* signify end of file */
+135 }
+136
+137 msg_ptr += *offset;
+138
+139 /* Actually put the data into the buffer */
+140 while (length && *msg_ptr) {
+141 /**
+142 * The buffer is in the user data segment, not the kernel
+143 * segment so "*" assignment won't work. We have to use
+144 * put_user which copies data from the kernel data segment to
+145 * the user data segment.
+146 */
+147 put_user(*(msg_ptr++), buffer++);
+148 length--;
+149 bytes_read++;
+150 }
+151
+152 *offset += bytes_read;
+153
+154 /* Most read functions return the number of bytes put into the buffer. */
+155 return bytes_read;
+156}
+157
+158/* Called when a process writes to dev file; echo "enable" > /dev/key_state */
+159static ssize_t device_write(struct file *filp, const char __user *buffer,
+160 size_t length, loff_t *offset)
+161{
+162 char command[10];
+163
+164 if (length > 10) {
+165 pr_err("command exceeded 10 char\n");
+166 return -EINVAL;
+167 }
+168
+169 if (copy_from_user(command, buffer, length))
+170 return -EFAULT;
+171
+172 if (strncmp(command, "enable", strlen("enable")) == 0)
+173 static_branch_enable(&fkey);
+174 else if (strncmp(command, "disable", strlen("disable")) == 0)
+175 static_branch_disable(&fkey);
+176 else {
+177 pr_err("Invalid command: %s\n", command);
+178 return -EINVAL;
+179 }
+180
+181 /* Again, return the number of input characters used. */
+182 return length;
+183}
+184
+185module_init(chardev_init);
+186module_exit(chardev_exit);
+187
+188MODULE_LICENSE("GPL");
+1cat /dev/key_state
-1cat /dev/key_state
+1echo enable > /dev/key_state
-1echo enable > /dev/key_state
+ DEFINE_STATIC_KEY_FALSE_RO
or DEFINE_STATIC_KEY_TRUE_RO
macro instead. Attempts to change the key at runtime will result in a page fault. For
more information, see Static keys
-20 Common Pitfalls
-19 Common Pitfalls
+19.1 Using standard libraries
+20.1 Using standard libraries
-20.2 Disabling interrupts
-19.2 Disabling interrupts
+21 Where To Go From Here?
-20 Where To Go From Here?
+
15.1 Interrupt Handlers
15.2 Detecting button presses
15.3 Bottom Half
-
16 Crypto
-
16.1 Hash functions
-
16.2 Symmetric key encryption
-
17 Virtual Input Device Driver
-
18 Standardizing the interfaces: The Device Model
-
19 Optimizations
-
19.1 Likely and Unlikely conditions
-
19.2 Static keys
-
20 Common Pitfalls
-
20.1 Using standard libraries
-
20.2 Disabling interrupts
-
21 Where To Go From Here?
+
16 Virtual Input Device Driver
+
17 Standardizing the interfaces: The Device Model
+
18 Optimizations
+
18.1 Likely and Unlikely conditions
+
18.2 Static keys
+
19 Common Pitfalls
+
19.1 Using standard libraries
+
19.2 Disabling interrupts
+
20 Where To Go From Here?
1 Introduction
1.3 What Is A Kernel Module?
@@ -192,11 +189,11 @@ desired.
1sudo pacman -S gcc kmod
+1.5 What Modules are in my Kernel?
lsmod
@@ -5403,314 +5400,8 @@ when an interrupt is triggered.
168MODULE_DESCRIPTION("Interrupt with top and bottom half");
and sets up input bitfields, device id, version, etc. After that, registers it by calling
16 Crypto
-16.1 Hash functions
- CONFIG_CRYPTO_SHA256
-
is enabled in kernel.
-1/*
-2 * cryptosha256.c
-3 */
-4#include <crypto/internal/hash.h>
-5#include <linux/module.h>
-6
-7#define SHA256_LENGTH 32
-8
-9static void show_hash_result(char *plaintext, char *hash_sha256)
-10{
-11 int i;
-12 char str[SHA256_LENGTH * 2 + 1];
-13
-14 pr_info("sha256 test for string: \"%s\"\n", plaintext);
-15 for (i = 0; i < SHA256_LENGTH; i++)
-16 sprintf(&str[i * 2], "%02x", (unsigned char)hash_sha256[i]);
-17 str[i * 2] = 0;
-18 pr_info("%s\n", str);
-19}
-20
-21static int __init cryptosha256_init(void)
-22{
-23 char *plaintext = "This is a test";
-24 char hash_sha256[SHA256_LENGTH];
-25 struct crypto_shash *sha256;
-26 struct shash_desc *shash;
-27
-28 sha256 = crypto_alloc_shash("sha256", 0, 0);
-29 if (IS_ERR(sha256)) {
-30 pr_err(
-31 "%s(): Failed to allocate sha256 algorithm, enable CONFIG_CRYPTO_SHA256 and try again.\n",
-32 __func__);
-33 return -1;
-34 }
-35
-36 shash = kmalloc(sizeof(struct shash_desc) + crypto_shash_descsize(sha256),
-37 GFP_KERNEL);
-38 if (!shash)
-39 return -ENOMEM;
-40
-41 shash->tfm = sha256;
-42
-43 if (crypto_shash_init(shash))
-44 return -1;
-45
-46 if (crypto_shash_update(shash, plaintext, strlen(plaintext)))
-47 return -1;
-48
-49 if (crypto_shash_final(shash, hash_sha256))
-50 return -1;
-51
-52 kfree(shash);
-53 crypto_free_shash(sha256);
-54
-55 show_hash_result(plaintext, hash_sha256);
-56
-57 return 0;
-58}
-59
-60static void __exit cryptosha256_exit(void)
-61{
-62}
-63
-64module_init(cryptosha256_init);
-65module_exit(cryptosha256_exit);
-66
-67MODULE_DESCRIPTION("sha256 hash test");
-68MODULE_LICENSE("GPL");
-1sudo insmod cryptosha256.ko
-2sudo dmesg
-1sudo rmmod cryptosha256
-16.2 Symmetric key encryption
-1/*
-2 * cryptosk.c
-3 */
-4#include <crypto/internal/skcipher.h>
-5#include <linux/crypto.h>
-6#include <linux/module.h>
-7#include <linux/random.h>
-8#include <linux/scatterlist.h>
-9
-10#define SYMMETRIC_KEY_LENGTH 32
-11#define CIPHER_BLOCK_SIZE 16
-12
-13struct tcrypt_result {
-14 struct completion completion;
-15 int err;
-16};
-17
-18struct skcipher_def {
-19 struct scatterlist sg;
-20 struct crypto_skcipher *tfm;
-21 struct skcipher_request *req;
-22 struct tcrypt_result result;
-23 char *scratchpad;
-24 char *ciphertext;
-25 char *ivdata;
-26};
-27
-28static struct skcipher_def sk;
-29
-30static void test_skcipher_finish(struct skcipher_def *sk)
-31{
-32 if (sk->tfm)
-33 crypto_free_skcipher(sk->tfm);
-34 if (sk->req)
-35 skcipher_request_free(sk->req);
-36 if (sk->ivdata)
-37 kfree(sk->ivdata);
-38 if (sk->scratchpad)
-39 kfree(sk->scratchpad);
-40 if (sk->ciphertext)
-41 kfree(sk->ciphertext);
-42}
-43
-44static int test_skcipher_result(struct skcipher_def *sk, int rc)
-45{
-46 switch (rc) {
-47 case 0:
-48 break;
-49 case -EINPROGRESS:
-50 case -EBUSY:
-51 rc = wait_for_completion_interruptible(&sk->result.completion);
-52 if (!rc && !sk->result.err) {
-53 reinit_completion(&sk->result.completion);
-54 break;
-55 }
-56 pr_info("skcipher encrypt returned with %d result %d\n", rc,
-57 sk->result.err);
-58 break;
-59 default:
-60 pr_info("skcipher encrypt returned with %d result %d\n", rc,
-61 sk->result.err);
-62 break;
-63 }
-64
-65 init_completion(&sk->result.completion);
-66
-67 return rc;
-68}
-69
-70static void test_skcipher_callback(struct crypto_async_request *req, int error)
-71{
-72 struct tcrypt_result *result = req->data;
-73
-74 if (error == -EINPROGRESS)
-75 return;
-76
-77 result->err = error;
-78 complete(&result->completion);
-79 pr_info("Encryption finished successfully\n");
-80
-81 /* decrypt data */
-82#if 0
-83 memset((void*)sk.scratchpad, '-', CIPHER_BLOCK_SIZE);
-84 ret = crypto_skcipher_decrypt(sk.req);
-85 ret = test_skcipher_result(&sk, ret);
-86 if (ret)
-87 return;
-88
-89 sg_copy_from_buffer(&sk.sg, 1, sk.scratchpad, CIPHER_BLOCK_SIZE);
-90 sk.scratchpad[CIPHER_BLOCK_SIZE-1] = 0;
-91
-92 pr_info("Decryption request successful\n");
-93 pr_info("Decrypted: %s\n", sk.scratchpad);
-94#endif
-95}
-96
-97static int test_skcipher_encrypt(char *plaintext, char *password,
-98 struct skcipher_def *sk)
-99{
-100 int ret = -EFAULT;
-101 unsigned char key[SYMMETRIC_KEY_LENGTH];
-102
-103 if (!sk->tfm) {
-104 sk->tfm = crypto_alloc_skcipher("cbc-aes-aesni", 0, 0);
-105 if (IS_ERR(sk->tfm)) {
-106 pr_info("could not allocate skcipher handle\n");
-107 return PTR_ERR(sk->tfm);
-108 }
-109 }
-110
-111 if (!sk->req) {
-112 sk->req = skcipher_request_alloc(sk->tfm, GFP_KERNEL);
-113 if (!sk->req) {
-114 pr_info("could not allocate skcipher request\n");
-115 ret = -ENOMEM;
-116 goto out;
-117 }
-118 }
-119
-120 skcipher_request_set_callback(sk->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
-121 test_skcipher_callback, &sk->result);
-122
-123 /* clear the key */
-124 memset((void *)key, '\0', SYMMETRIC_KEY_LENGTH);
-125
-126 /* Use the world's favourite password */
-127 sprintf((char *)key, "%s", password);
-128
-129 /* AES 256 with given symmetric key */
-130 if (crypto_skcipher_setkey(sk->tfm, key, SYMMETRIC_KEY_LENGTH)) {
-131 pr_info("key could not be set\n");
-132 ret = -EAGAIN;
-133 goto out;
-134 }
-135 pr_info("Symmetric key: %s\n", key);
-136 pr_info("Plaintext: %s\n", plaintext);
-137
-138 if (!sk->ivdata) {
-139 /* see https://en.wikipedia.org/wiki/Initialization_vector */
-140 sk->ivdata = kmalloc(CIPHER_BLOCK_SIZE, GFP_KERNEL);
-141 if (!sk->ivdata) {
-142 pr_info("could not allocate ivdata\n");
-143 goto out;
-144 }
-145 get_random_bytes(sk->ivdata, CIPHER_BLOCK_SIZE);
-146 }
-147
-148 if (!sk->scratchpad) {
-149 /* The text to be encrypted */
-150 sk->scratchpad = kmalloc(CIPHER_BLOCK_SIZE, GFP_KERNEL);
-151 if (!sk->scratchpad) {
-152 pr_info("could not allocate scratchpad\n");
-153 goto out;
-154 }
-155 }
-156 sprintf((char *)sk->scratchpad, "%s", plaintext);
-157
-158 sg_init_one(&sk->sg, sk->scratchpad, CIPHER_BLOCK_SIZE);
-159 skcipher_request_set_crypt(sk->req, &sk->sg, &sk->sg, CIPHER_BLOCK_SIZE,
-160 sk->ivdata);
-161 init_completion(&sk->result.completion);
-162
-163 /* encrypt data */
-164 ret = crypto_skcipher_encrypt(sk->req);
-165 ret = test_skcipher_result(sk, ret);
-166 if (ret)
-167 goto out;
-168
-169 pr_info("Encryption request successful\n");
-170
-171out:
-172 return ret;
-173}
-174
-175static int __init cryptoapi_init(void)
-176{
-177 /* The world's favorite password */
-178 char *password = "password123";
-179
-180 sk.tfm = NULL;
-181 sk.req = NULL;
-182 sk.scratchpad = NULL;
-183 sk.ciphertext = NULL;
-184 sk.ivdata = NULL;
-185
-186 test_skcipher_encrypt("Testing", password, &sk);
-187 return 0;
-188}
-189
-190static void __exit cryptoapi_exit(void)
-191{
-192 test_skcipher_finish(&sk);
-193}
-194
-195module_init(cryptoapi_init);
-196module_exit(cryptoapi_exit);
-197
-198MODULE_DESCRIPTION("Symmetric key encryption example");
-199MODULE_LICENSE("GPL");
-17 Virtual Input Device Driver
-16 Virtual Input Device Driver
+ input_register_device()
.
- vinput_device()
that contains the virtual device name and
@@ -5731,527 +5422,530 @@ development of virtual input drivers. The drivers needs to export a
send()
+
+
+
read()
vinput_register_device()
+
vinput_register_device()
and vinput_unregister_device()
will add a new device to the list of support virtual input devices.
1int init(struct vinput *);
- struct vinput
-
already initialized with an allocated struct input_dev
+
1int init(struct vinput *);
+ struct vinput
+
already initialized with an allocated struct input_dev
. The init()
function is responsible for initializing the capabilities of the input device and register
it.
1int send(struct vinput *, char *, int);
-1int send(struct vinput *, char *, int);
+ input_report_XXXX
or input_event
call. The string is already copied from user.
1int read(struct vinput *, char *, int);
-1int read(struct vinput *, char *, int);
+ class_attribute
+
class_attribute
structure is similar to other attribute types we talked about in section 8:
1struct class_attribute {
-2 struct attribute attr;
-3 ssize_t (*show)(struct class *class, struct class_attribute *attr,
-4 char *buf);
-5 ssize_t (*store)(struct class *class, struct class_attribute *attr,
-6 const char *buf, size_t count);
-7};
-
-
-
- CLASS_ATTR_WO(export/unexport)
+
macros. For example, when allocating memory you are almost always expecting this
to succeed.
1struct class_attribute {
+2 struct attribute attr;
+3 ssize_t (*show)(struct class *class, struct class_attribute *attr,
+4 char *buf);
+5 ssize_t (*store)(struct class *class, struct class_attribute *attr,
+6 const char *buf, size_t count);
+7};
+ CLASS_ATTR_WO(export/unexport)
defined in include/linux/device.h (in this case, device.h is included in include/linux/input.h)
will generate the class_attribute
structures which are named class_attr_export/unexport. Then, put them into
+
+
+
vinput_class_attrs
array and the macro ATTRIBUTE_GROUPS(vinput_class)
-
will generate the struct attribute_group vinput_class_group
+
will generate the struct attribute_group vinput_class_group
that should be assigned in vinput_class
. Finally, call class_register(&vinput_class)
to create attributes in sysfs.
-1echo "vkbd" | sudo tee /sys/class/vinput/export
-1echo "vkbd" | sudo tee /sys/class/vinput/export
+1echo "0" | sudo tee /sys/class/vinput/unexport
+ 1echo "0" | sudo tee /sys/class/vinput/unexport
1/*
-2 * vinput.h
-3 */
-4
-5#ifndef VINPUT_H
-6#define VINPUT_H
-7
-8#include <linux/input.h>
-9#include <linux/spinlock.h>
-10
-11#define VINPUT_MAX_LEN 128
-12#define MAX_VINPUT 32
-13#define VINPUT_MINORS MAX_VINPUT
-14
-15#define dev_to_vinput(dev) container_of(dev, struct vinput, dev)
-16
-17struct vinput_device;
-18
-19struct vinput {
-20 long id;
-21 long devno;
-22 long last_entry;
-23 spinlock_t lock;
-24
-25 void *priv_data;
-26
-27 struct device dev;
-28 struct list_head list;
-29 struct input_dev *input;
-30 struct vinput_device *type;
-31};
-32
-33struct vinput_ops {
-34 int (*init)(struct vinput *);
-35 int (*kill)(struct vinput *);
-36 int (*send)(struct vinput *, char *, int);
-37 int (*read)(struct vinput *, char *, int);
-38};
-39
-40struct vinput_device {
-41 char name[16];
-42 struct list_head list;
-43 struct vinput_ops *ops;
-44};
-45
-46int vinput_register(struct vinput_device *dev);
-47void vinput_unregister(struct vinput_device *dev);
-48
-49#endif
+ 1/*
+2 * vinput.h
+3 */
+4
+5#ifndef VINPUT_H
+6#define VINPUT_H
+7
+8#include <linux/input.h>
+9#include <linux/spinlock.h>
+10
+11#define VINPUT_MAX_LEN 128
+12#define MAX_VINPUT 32
+13#define VINPUT_MINORS MAX_VINPUT
+14
+15#define dev_to_vinput(dev) container_of(dev, struct vinput, dev)
+16
+17struct vinput_device;
+18
+19struct vinput {
+20 long id;
+21 long devno;
+22 long last_entry;
+23 spinlock_t lock;
+24
+25 void *priv_data;
+26
+27 struct device dev;
+28 struct list_head list;
+29 struct input_dev *input;
+30 struct vinput_device *type;
+31};
+32
+33struct vinput_ops {
+34 int (*init)(struct vinput *);
+35 int (*kill)(struct vinput *);
+36 int (*send)(struct vinput *, char *, int);
+37 int (*read)(struct vinput *, char *, int);
+38};
+39
+40struct vinput_device {
+41 char name[16];
+42 struct list_head list;
+43 struct vinput_ops *ops;
+44};
+45
+46int vinput_register(struct vinput_device *dev);
+47void vinput_unregister(struct vinput_device *dev);
+48
+49#endif
1/*
-2 * vinput.c
-3 */
-4
-5#include <linux/cdev.h>
-6#include <linux/input.h>
-7#include <linux/module.h>
-8#include <linux/slab.h>
-9#include <linux/spinlock.h>
-10
-11#include <asm/uaccess.h>
-12
-13#include "vinput.h"
-14
-15#define DRIVER_NAME "vinput"
-16
-17#define dev_to_vinput(dev) container_of(dev, struct vinput, dev)
-18
-19static DECLARE_BITMAP(vinput_ids, VINPUT_MINORS);
-20
-21static LIST_HEAD(vinput_devices);
-22static LIST_HEAD(vinput_vdevices);
-23
-24static int vinput_dev;
-25static struct spinlock vinput_lock;
-26static struct class vinput_class;
-27
-28/* Search the name of vinput device in the vinput_devices linked list,
-29 * which added at vinput_register().
-30 */
-31static struct vinput_device *vinput_get_device_by_type(const char *type)
-32{
-33 int found = 0;
-34 struct vinput_device *vinput;
-35 struct list_head *curr;
-36
-37 spin_lock(&vinput_lock);
-38 list_for_each (curr, &vinput_devices) {
-39 vinput = list_entry(curr, struct vinput_device, list);
-40 if (vinput && strncmp(type, vinput->name, strlen(vinput->name)) == 0) {
-41 found = 1;
-42 break;
-43 }
-44 }
-45 spin_unlock(&vinput_lock);
-46
-47 if (found)
-48 return vinput;
-49 return ERR_PTR(-ENODEV);
-50}
-51
-52/* Search the id of virtual device in the vinput_vdevices linked list,
-53 * which added at vinput_alloc_vdevice().
-54 */
-55static struct vinput *vinput_get_vdevice_by_id(long id)
-56{
-57 struct vinput *vinput = NULL;
-58 struct list_head *curr;
-59
-60 spin_lock(&vinput_lock);
-61 list_for_each (curr, &vinput_vdevices) {
-62 vinput = list_entry(curr, struct vinput, list);
-63 if (vinput && vinput->id == id)
-64 break;
-65 }
-66 spin_unlock(&vinput_lock);
-67
-68 if (vinput && vinput->id == id)
-69 return vinput;
-70 return ERR_PTR(-ENODEV);
-71}
-72
-73static int vinput_open(struct inode *inode, struct file *file)
-74{
-75 int err = 0;
-76 struct vinput *vinput = NULL;
-77
-78 vinput = vinput_get_vdevice_by_id(iminor(inode));
-79
-80 if (IS_ERR(vinput))
-81 err = PTR_ERR(vinput);
-82 else
-83 file->private_data = vinput;
-84
-85 return err;
-86}
-87
-88static int vinput_release(struct inode *inode, struct file *file)
-89{
-90 return 0;
-91}
-92
-93static ssize_t vinput_read(struct file *file, char __user *buffer, size_t count,
-94 loff_t *offset)
-95{
-96 int len;
-97 char buff[VINPUT_MAX_LEN + 1];
-98 struct vinput *vinput = file->private_data;
-99
-100 len = vinput->type->ops->read(vinput, buff, count);
-101
-102 if (*offset > len)
-103 count = 0;
-104 else if (count + *offset > VINPUT_MAX_LEN)
-105 count = len - *offset;
-106
-107 if (raw_copy_to_user(buffer, buff + *offset, count))
-108 count = -EFAULT;
-109
-110 *offset += count;
-111
-112 return count;
-113}
-114
-115static ssize_t vinput_write(struct file *file, const char __user *buffer,
-116 size_t count, loff_t *offset)
-117{
-118 char buff[VINPUT_MAX_LEN + 1];
-119 struct vinput *vinput = file->private_data;
-120
-121 memset(buff, 0, sizeof(char) * (VINPUT_MAX_LEN + 1));
-122
-123 if (count > VINPUT_MAX_LEN) {
-124 dev_warn(&vinput->dev, "Too long. %d bytes allowed\n", VINPUT_MAX_LEN);
-125 return -EINVAL;
-126 }
-127
-128 if (raw_copy_from_user(buff, buffer, count))
-129 return -EFAULT;
-130
-131 return vinput->type->ops->send(vinput, buff, count);
-132}
-133
-134static const struct file_operations vinput_fops = {
-135 .owner = THIS_MODULE,
-136 .open = vinput_open,
-137 .release = vinput_release,
-138 .read = vinput_read,
-139 .write = vinput_write,
-140};
-141
-142static void vinput_unregister_vdevice(struct vinput *vinput)
-143{
-144 input_unregister_device(vinput->input);
-145 if (vinput->type->ops->kill)
-146 vinput->type->ops->kill(vinput);
-147}
-148
-149static void vinput_destroy_vdevice(struct vinput *vinput)
-150{
-151 /* Remove from the list first */
-152 spin_lock(&vinput_lock);
-153 list_del(&vinput->list);
-154 clear_bit(vinput->id, vinput_ids);
-155 spin_unlock(&vinput_lock);
-156
-157 module_put(THIS_MODULE);
-158
-159 kfree(vinput);
-160}
-161
-162static void vinput_release_dev(struct device *dev)
-163{
-164 struct vinput *vinput = dev_to_vinput(dev);
-165 int id = vinput->id;
-166
-167 vinput_destroy_vdevice(vinput);
-168
-169 pr_debug("released vinput%d.\n", id);
-170}
-171
-172static struct vinput *vinput_alloc_vdevice(void)
-173{
-174 int err;
-175 struct vinput *vinput = kzalloc(sizeof(struct vinput), GFP_KERNEL);
-176
-177 try_module_get(THIS_MODULE);
-178
-179 memset(vinput, 0, sizeof(struct vinput));
-180
-181 spin_lock_init(&vinput->lock);
-182
-183 spin_lock(&vinput_lock);
-184 vinput->id = find_first_zero_bit(vinput_ids, VINPUT_MINORS);
-185 if (vinput->id >= VINPUT_MINORS) {
-186 err = -ENOBUFS;
-187 goto fail_id;
-188 }
-189 set_bit(vinput->id, vinput_ids);
-190 list_add(&vinput->list, &vinput_vdevices);
-191 spin_unlock(&vinput_lock);
-192
-193 /* allocate the input device */
-194 vinput->input = input_allocate_device();
-195 if (vinput->input == NULL) {
-196 pr_err("vinput: Cannot allocate vinput input device\n");
-197 err = -ENOMEM;
-198 goto fail_input_dev;
-199 }
-200
-201 /* initialize device */
-202 vinput->dev.class = &vinput_class;
-203 vinput->dev.release = vinput_release_dev;
-204 vinput->dev.devt = MKDEV(vinput_dev, vinput->id);
-205 dev_set_name(&vinput->dev, DRIVER_NAME "%lu", vinput->id);
-206
-207 return vinput;
-208
-209fail_input_dev:
-210 spin_lock(&vinput_lock);
-211 list_del(&vinput->list);
-212fail_id:
-213 spin_unlock(&vinput_lock);
-214 module_put(THIS_MODULE);
-215 kfree(vinput);
-216
-217 return ERR_PTR(err);
-218}
-219
-220static int vinput_register_vdevice(struct vinput *vinput)
-221{
-222 int err = 0;
-223
-224 /* register the input device */
-225 vinput->input->name = vinput->type->name;
-226 vinput->input->phys = "vinput";
-227 vinput->input->dev.parent = &vinput->dev;
-228
-229 vinput->input->id.bustype = BUS_VIRTUAL;
-230 vinput->input->id.product = 0x0000;
-231 vinput->input->id.vendor = 0x0000;
-232 vinput->input->id.version = 0x0000;
-233
-234 err = vinput->type->ops->init(vinput);
-235
-236 if (err == 0)
-237 dev_info(&vinput->dev, "Registered virtual input %s %ld\n",
-238 vinput->type->name, vinput->id);
-239
-240 return err;
-241}
-242
-243static ssize_t export_store(struct class *class, struct class_attribute *attr,
-244 const char *buf, size_t len)
-245{
-246 int err;
-247 struct vinput *vinput;
-248 struct vinput_device *device;
-249
-250 device = vinput_get_device_by_type(buf);
-251 if (IS_ERR(device)) {
-252 pr_info("vinput: This virtual device isn't registered\n");
-253 err = PTR_ERR(device);
-254 goto fail;
-255 }
-256
-257 vinput = vinput_alloc_vdevice();
-258 if (IS_ERR(vinput)) {
-259 err = PTR_ERR(vinput);
-260 goto fail;
-261 }
-262
-263 vinput->type = device;
-264 err = device_register(&vinput->dev);
-265 if (err < 0)
-266 goto fail_register;
-267
-268 err = vinput_register_vdevice(vinput);
-269 if (err < 0)
-270 goto fail_register_vinput;
-271
-272 return len;
-273
-274fail_register_vinput:
-275 device_unregister(&vinput->dev);
-276fail_register:
-277 vinput_destroy_vdevice(vinput);
-278fail:
-279 return err;
-280}
-281/* This macro generates class_attr_export structure and export_store() */
-282static CLASS_ATTR_WO(export);
-283
-284static ssize_t unexport_store(struct class *class, struct class_attribute *attr,
-285 const char *buf, size_t len)
-286{
-287 int err;
-288 unsigned long id;
-289 struct vinput *vinput;
-290
-291 err = kstrtol(buf, 10, &id);
-292 if (err) {
-293 err = -EINVAL;
-294 goto failed;
-295 }
-296
-297 vinput = vinput_get_vdevice_by_id(id);
-298 if (IS_ERR(vinput)) {
-299 pr_err("vinput: No such vinput device %ld\n", id);
-300 err = PTR_ERR(vinput);
-301 goto failed;
-302 }
-303
-304 vinput_unregister_vdevice(vinput);
-305 device_unregister(&vinput->dev);
-306
-307 return len;
-308failed:
-309 return err;
-310}
-311/* This macro generates class_attr_unexport structure and unexport_store() */
-312static CLASS_ATTR_WO(unexport);
-313
-314static struct attribute *vinput_class_attrs[] = {
-315 &class_attr_export.attr,
-316 &class_attr_unexport.attr,
-317 NULL,
-318};
-319
-320/* This macro generates vinput_class_groups structure */
-321ATTRIBUTE_GROUPS(vinput_class);
-322
-323static struct class vinput_class = {
-324 .name = "vinput",
-325 .owner = THIS_MODULE,
-326 .class_groups = vinput_class_groups,
-327};
-328
-329int vinput_register(struct vinput_device *dev)
-330{
-331 spin_lock(&vinput_lock);
-332 list_add(&dev->list, &vinput_devices);
-333 spin_unlock(&vinput_lock);
-334
-335 pr_info("vinput: registered new virtual input device '%s'\n", dev->name);
-336
-337 return 0;
-338}
-339EXPORT_SYMBOL(vinput_register);
-340
-341void vinput_unregister(struct vinput_device *dev)
-342{
-343 struct list_head *curr, *next;
-344
-345 /* Remove from the list first */
-346 spin_lock(&vinput_lock);
-347 list_del(&dev->list);
-348 spin_unlock(&vinput_lock);
-349
-350 /* unregister all devices of this type */
-351 list_for_each_safe (curr, next, &vinput_vdevices) {
-352 struct vinput *vinput = list_entry(curr, struct vinput, list);
-353 if (vinput && vinput->type == dev) {
-354 vinput_unregister_vdevice(vinput);
-355 device_unregister(&vinput->dev);
-356 }
-357 }
-358
-359 pr_info("vinput: unregistered virtual input device '%s'\n", dev->name);
-360}
-361EXPORT_SYMBOL(vinput_unregister);
-362
-363static int __init vinput_init(void)
-364{
-365 int err = 0;
-366
-367 pr_info("vinput: Loading virtual input driver\n");
-368
-369 vinput_dev = register_chrdev(0, DRIVER_NAME, &vinput_fops);
-370 if (vinput_dev < 0) {
-371 pr_err("vinput: Unable to allocate char dev region\n");
-372 err = vinput_dev;
-373 goto failed_alloc;
-374 }
-375
-376 spin_lock_init(&vinput_lock);
-377
-378 err = class_register(&vinput_class);
-379 if (err < 0) {
-380 pr_err("vinput: Unable to register vinput class\n");
-381 goto failed_class;
-382 }
-383
-384 return 0;
-385failed_class:
-386 class_unregister(&vinput_class);
-387failed_alloc:
-388 return err;
-389}
-390
-391static void __exit vinput_end(void)
-392{
-393 pr_info("vinput: Unloading virtual input driver\n");
-394
-395 unregister_chrdev(vinput_dev, DRIVER_NAME);
-396 class_unregister(&vinput_class);
-397}
-398
-399module_init(vinput_init);
-400module_exit(vinput_end);
-401
-402MODULE_LICENSE("GPL");
-403MODULE_DESCRIPTION("Emulate input events");
-1/*
+2 * vinput.c
+3 */
+4
+5#include <linux/cdev.h>
+6#include <linux/input.h>
+7#include <linux/module.h>
+8#include <linux/slab.h>
+9#include <linux/spinlock.h>
+10
+11#include <asm/uaccess.h>
+12
+13#include "vinput.h"
+14
+15#define DRIVER_NAME "vinput"
+16
+17#define dev_to_vinput(dev) container_of(dev, struct vinput, dev)
+18
+19static DECLARE_BITMAP(vinput_ids, VINPUT_MINORS);
+20
+21static LIST_HEAD(vinput_devices);
+22static LIST_HEAD(vinput_vdevices);
+23
+24static int vinput_dev;
+25static struct spinlock vinput_lock;
+26static struct class vinput_class;
+27
+28/* Search the name of vinput device in the vinput_devices linked list,
+29 * which added at vinput_register().
+30 */
+31static struct vinput_device *vinput_get_device_by_type(const char *type)
+32{
+33 int found = 0;
+34 struct vinput_device *vinput;
+35 struct list_head *curr;
+36
+37 spin_lock(&vinput_lock);
+38 list_for_each (curr, &vinput_devices) {
+39 vinput = list_entry(curr, struct vinput_device, list);
+40 if (vinput && strncmp(type, vinput->name, strlen(vinput->name)) == 0) {
+41 found = 1;
+42 break;
+43 }
+44 }
+45 spin_unlock(&vinput_lock);
+46
+47 if (found)
+48 return vinput;
+49 return ERR_PTR(-ENODEV);
+50}
+51
+52/* Search the id of virtual device in the vinput_vdevices linked list,
+53 * which added at vinput_alloc_vdevice().
+54 */
+55static struct vinput *vinput_get_vdevice_by_id(long id)
+56{
+57 struct vinput *vinput = NULL;
+58 struct list_head *curr;
+59
+60 spin_lock(&vinput_lock);
+61 list_for_each (curr, &vinput_vdevices) {
+62 vinput = list_entry(curr, struct vinput, list);
+63 if (vinput && vinput->id == id)
+64 break;
+65 }
+66 spin_unlock(&vinput_lock);
+67
+68 if (vinput && vinput->id == id)
+69 return vinput;
+70 return ERR_PTR(-ENODEV);
+71}
+72
+73static int vinput_open(struct inode *inode, struct file *file)
+74{
+75 int err = 0;
+76 struct vinput *vinput = NULL;
+77
+78 vinput = vinput_get_vdevice_by_id(iminor(inode));
+79
+80 if (IS_ERR(vinput))
+81 err = PTR_ERR(vinput);
+82 else
+83 file->private_data = vinput;
+84
+85 return err;
+86}
+87
+88static int vinput_release(struct inode *inode, struct file *file)
+89{
+90 return 0;
+91}
+92
+93static ssize_t vinput_read(struct file *file, char __user *buffer, size_t count,
+94 loff_t *offset)
+95{
+96 int len;
+97 char buff[VINPUT_MAX_LEN + 1];
+98 struct vinput *vinput = file->private_data;
+99
+100 len = vinput->type->ops->read(vinput, buff, count);
+101
+102 if (*offset > len)
+103 count = 0;
+104 else if (count + *offset > VINPUT_MAX_LEN)
+105 count = len - *offset;
+106
+107 if (raw_copy_to_user(buffer, buff + *offset, count))
+108 count = -EFAULT;
+109
+110 *offset += count;
+111
+112 return count;
+113}
+114
+115static ssize_t vinput_write(struct file *file, const char __user *buffer,
+116 size_t count, loff_t *offset)
+117{
+118 char buff[VINPUT_MAX_LEN + 1];
+119 struct vinput *vinput = file->private_data;
+120
+121 memset(buff, 0, sizeof(char) * (VINPUT_MAX_LEN + 1));
+122
+123 if (count > VINPUT_MAX_LEN) {
+124 dev_warn(&vinput->dev, "Too long. %d bytes allowed\n", VINPUT_MAX_LEN);
+125 return -EINVAL;
+126 }
+127
+128 if (raw_copy_from_user(buff, buffer, count))
+129 return -EFAULT;
+130
+131 return vinput->type->ops->send(vinput, buff, count);
+132}
+133
+134static const struct file_operations vinput_fops = {
+135 .owner = THIS_MODULE,
+136 .open = vinput_open,
+137 .release = vinput_release,
+138 .read = vinput_read,
+139 .write = vinput_write,
+140};
+141
+142static void vinput_unregister_vdevice(struct vinput *vinput)
+143{
+144 input_unregister_device(vinput->input);
+145 if (vinput->type->ops->kill)
+146 vinput->type->ops->kill(vinput);
+147}
+148
+149static void vinput_destroy_vdevice(struct vinput *vinput)
+150{
+151 /* Remove from the list first */
+152 spin_lock(&vinput_lock);
+153 list_del(&vinput->list);
+154 clear_bit(vinput->id, vinput_ids);
+155 spin_unlock(&vinput_lock);
+156
+157 module_put(THIS_MODULE);
+158
+159 kfree(vinput);
+160}
+161
+162static void vinput_release_dev(struct device *dev)
+163{
+164 struct vinput *vinput = dev_to_vinput(dev);
+165 int id = vinput->id;
+166
+167 vinput_destroy_vdevice(vinput);
+168
+169 pr_debug("released vinput%d.\n", id);
+170}
+171
+172static struct vinput *vinput_alloc_vdevice(void)
+173{
+174 int err;
+175 struct vinput *vinput = kzalloc(sizeof(struct vinput), GFP_KERNEL);
+176
+177 try_module_get(THIS_MODULE);
+178
+179 memset(vinput, 0, sizeof(struct vinput));
+180
+181 spin_lock_init(&vinput->lock);
+182
+183 spin_lock(&vinput_lock);
+184 vinput->id = find_first_zero_bit(vinput_ids, VINPUT_MINORS);
+185 if (vinput->id >= VINPUT_MINORS) {
+186 err = -ENOBUFS;
+187 goto fail_id;
+188 }
+189 set_bit(vinput->id, vinput_ids);
+190 list_add(&vinput->list, &vinput_vdevices);
+191 spin_unlock(&vinput_lock);
+192
+193 /* allocate the input device */
+194 vinput->input = input_allocate_device();
+195 if (vinput->input == NULL) {
+196 pr_err("vinput: Cannot allocate vinput input device\n");
+197 err = -ENOMEM;
+198 goto fail_input_dev;
+199 }
+200
+201 /* initialize device */
+202 vinput->dev.class = &vinput_class;
+203 vinput->dev.release = vinput_release_dev;
+204 vinput->dev.devt = MKDEV(vinput_dev, vinput->id);
+205 dev_set_name(&vinput->dev, DRIVER_NAME "%lu", vinput->id);
+206
+207 return vinput;
+208
+209fail_input_dev:
+210 spin_lock(&vinput_lock);
+211 list_del(&vinput->list);
+212fail_id:
+213 spin_unlock(&vinput_lock);
+214 module_put(THIS_MODULE);
+215 kfree(vinput);
+216
+217 return ERR_PTR(err);
+218}
+219
+220static int vinput_register_vdevice(struct vinput *vinput)
+221{
+222 int err = 0;
+223
+224 /* register the input device */
+225 vinput->input->name = vinput->type->name;
+226 vinput->input->phys = "vinput";
+227 vinput->input->dev.parent = &vinput->dev;
+228
+229 vinput->input->id.bustype = BUS_VIRTUAL;
+230 vinput->input->id.product = 0x0000;
+231 vinput->input->id.vendor = 0x0000;
+232 vinput->input->id.version = 0x0000;
+233
+234 err = vinput->type->ops->init(vinput);
+235
+236 if (err == 0)
+237 dev_info(&vinput->dev, "Registered virtual input %s %ld\n",
+238 vinput->type->name, vinput->id);
+239
+240 return err;
+241}
+242
+243static ssize_t export_store(struct class *class, struct class_attribute *attr,
+244 const char *buf, size_t len)
+245{
+246 int err;
+247 struct vinput *vinput;
+248 struct vinput_device *device;
+249
+250 device = vinput_get_device_by_type(buf);
+251 if (IS_ERR(device)) {
+252 pr_info("vinput: This virtual device isn't registered\n");
+253 err = PTR_ERR(device);
+254 goto fail;
+255 }
+256
+257 vinput = vinput_alloc_vdevice();
+258 if (IS_ERR(vinput)) {
+259 err = PTR_ERR(vinput);
+260 goto fail;
+261 }
+262
+263 vinput->type = device;
+264 err = device_register(&vinput->dev);
+265 if (err < 0)
+266 goto fail_register;
+267
+268 err = vinput_register_vdevice(vinput);
+269 if (err < 0)
+270 goto fail_register_vinput;
+271
+272 return len;
+273
+274fail_register_vinput:
+275 device_unregister(&vinput->dev);
+276fail_register:
+277 vinput_destroy_vdevice(vinput);
+278fail:
+279 return err;
+280}
+281/* This macro generates class_attr_export structure and export_store() */
+282static CLASS_ATTR_WO(export);
+283
+284static ssize_t unexport_store(struct class *class, struct class_attribute *attr,
+285 const char *buf, size_t len)
+286{
+287 int err;
+288 unsigned long id;
+289 struct vinput *vinput;
+290
+291 err = kstrtol(buf, 10, &id);
+292 if (err) {
+293 err = -EINVAL;
+294 goto failed;
+295 }
+296
+297 vinput = vinput_get_vdevice_by_id(id);
+298 if (IS_ERR(vinput)) {
+299 pr_err("vinput: No such vinput device %ld\n", id);
+300 err = PTR_ERR(vinput);
+301 goto failed;
+302 }
+303
+304 vinput_unregister_vdevice(vinput);
+305 device_unregister(&vinput->dev);
+306
+307 return len;
+308failed:
+309 return err;
+310}
+311/* This macro generates class_attr_unexport structure and unexport_store() */
+312static CLASS_ATTR_WO(unexport);
+313
+314static struct attribute *vinput_class_attrs[] = {
+315 &class_attr_export.attr,
+316 &class_attr_unexport.attr,
+317 NULL,
+318};
+319
+320/* This macro generates vinput_class_groups structure */
+321ATTRIBUTE_GROUPS(vinput_class);
+322
+323static struct class vinput_class = {
+324 .name = "vinput",
+325 .owner = THIS_MODULE,
+326 .class_groups = vinput_class_groups,
+327};
+328
+329int vinput_register(struct vinput_device *dev)
+330{
+331 spin_lock(&vinput_lock);
+332 list_add(&dev->list, &vinput_devices);
+333 spin_unlock(&vinput_lock);
+334
+335 pr_info("vinput: registered new virtual input device '%s'\n", dev->name);
+336
+337 return 0;
+338}
+339EXPORT_SYMBOL(vinput_register);
+340
+341void vinput_unregister(struct vinput_device *dev)
+342{
+343 struct list_head *curr, *next;
+344
+345 /* Remove from the list first */
+346 spin_lock(&vinput_lock);
+347 list_del(&dev->list);
+348 spin_unlock(&vinput_lock);
+349
+350 /* unregister all devices of this type */
+351 list_for_each_safe (curr, next, &vinput_vdevices) {
+352 struct vinput *vinput = list_entry(curr, struct vinput, list);
+353 if (vinput && vinput->type == dev) {
+354 vinput_unregister_vdevice(vinput);
+355 device_unregister(&vinput->dev);
+356 }
+357 }
+358
+359 pr_info("vinput: unregistered virtual input device '%s'\n", dev->name);
+360}
+361EXPORT_SYMBOL(vinput_unregister);
+362
+363static int __init vinput_init(void)
+364{
+365 int err = 0;
+366
+367 pr_info("vinput: Loading virtual input driver\n");
+368
+369 vinput_dev = register_chrdev(0, DRIVER_NAME, &vinput_fops);
+370 if (vinput_dev < 0) {
+371 pr_err("vinput: Unable to allocate char dev region\n");
+372 err = vinput_dev;
+373 goto failed_alloc;
+374 }
+375
+376 spin_lock_init(&vinput_lock);
+377
+378 err = class_register(&vinput_class);
+379 if (err < 0) {
+380 pr_err("vinput: Unable to register vinput class\n");
+381 goto failed_class;
+382 }
+383
+384 return 0;
+385failed_class:
+386 class_unregister(&vinput_class);
+387failed_alloc:
+388 return err;
+389}
+390
+391static void __exit vinput_end(void)
+392{
+393 pr_info("vinput: Unloading virtual input driver\n");
+394
+395 unregister_chrdev(vinput_dev, DRIVER_NAME);
+396 class_unregister(&vinput_class);
+397}
+398
+399module_init(vinput_init);
+400module_exit(vinput_end);
+401
+402MODULE_LICENSE("GPL");
+403MODULE_DESCRIPTION("Emulate input events");
+ KEY_MAX
keycodes. The injection format is the KEY_CODE
such as defined in include/linux/input.h. A positive value means
@@ -6259,136 +5953,136 @@ will generate the class_attribute
while a negative value is a KEY_RELEASE
. The keyboard supports repetition when the key stays pressed for too long. The
following demonstrates how simulation work.
- KEY_G
+
KEY_G
= 34):
1echo "+34" | sudo tee /dev/vinput0
- KEY_G
+
1echo "+34" | sudo tee /dev/vinput0
+ KEY_G
= 34):
1echo "-34" | sudo tee /dev/vinput0
-1echo "-34" | sudo tee /dev/vinput0
1/*
-2 * vkbd.c
-3 */
-4
-5#include <linux/init.h>
-6#include <linux/input.h>
-7#include <linux/module.h>
-8#include <linux/spinlock.h>
-9
-10#include "vinput.h"
-11
-12#define VINPUT_KBD "vkbd"
-13#define VINPUT_RELEASE 0
-14#define VINPUT_PRESS 1
-15
-16static unsigned short vkeymap[KEY_MAX];
-17
-18static int vinput_vkbd_init(struct vinput *vinput)
-19{
-20 int i;
-21
-22 /* Set up the input bitfield */
-23 vinput->input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
-24 vinput->input->keycodesize = sizeof(unsigned short);
-25 vinput->input->keycodemax = KEY_MAX;
-26 vinput->input->keycode = vkeymap;
-27
-28 for (i = 0; i < KEY_MAX; i++)
-29 set_bit(vkeymap[i], vinput->input->keybit);
-30
-31 /* vinput will help us allocate new input device structure via
-32 * input_allocate_device(). So, we can register it straightforwardly.
-33 */
-34 return input_register_device(vinput->input);
-35}
-36
-37static int vinput_vkbd_read(struct vinput *vinput, char *buff, int len)
-38{
-39 spin_lock(&vinput->lock);
-40 len = snprintf(buff, len, "%+ld\n", vinput->last_entry);
-41 spin_unlock(&vinput->lock);
-42
-43 return len;
-44}
-45
-46static int vinput_vkbd_send(struct vinput *vinput, char *buff, int len)
-47{
-48 int ret;
-49 long key = 0;
-50 short type = VINPUT_PRESS;
-51
-52 /* Determine which event was received (press or release)
-53 * and store the state.
-54 */
-55 if (buff[0] == '+')
-56 ret = kstrtol(buff + 1, 10, &key);
-57 else
-58 ret = kstrtol(buff, 10, &key);
-59 if (ret)
-60 dev_err(&vinput->dev, "error during kstrtol: -%d\n", ret);
-61 spin_lock(&vinput->lock);
-62 vinput->last_entry = key;
-63 spin_unlock(&vinput->lock);
-64
-65 if (key < 0) {
-66 type = VINPUT_RELEASE;
-67 key = -key;
-68 }
-69
-70 dev_info(&vinput->dev, "Event %s code %ld\n",
-71 (type == VINPUT_RELEASE) ? "VINPUT_RELEASE" : "VINPUT_PRESS", key);
-72
-73 /* Report the state received to input subsystem. */
-74 input_report_key(vinput->input, key, type);
-75 /* Tell input subsystem that it finished the report. */
-76 input_sync(vinput->input);
-77
-78 return len;
-79}
-80
-81static struct vinput_ops vkbd_ops = {
-82 .init = vinput_vkbd_init,
-83 .send = vinput_vkbd_send,
-84 .read = vinput_vkbd_read,
-85};
-86
-87static struct vinput_device vkbd_dev = {
-88 .name = VINPUT_KBD,
-89 .ops = &vkbd_ops,
-90};
-91
-92static int __init vkbd_init(void)
-93{
-94 int i;
-95
-96 for (i = 0; i < KEY_MAX; i++)
-97 vkeymap[i] = i;
-98 return vinput_register(&vkbd_dev);
-99}
-100
-101static void __exit vkbd_end(void)
-102{
-103 vinput_unregister(&vkbd_dev);
-104}
-105
-106module_init(vkbd_init);
-107module_exit(vkbd_end);
-108
-109MODULE_LICENSE("GPL");
-110MODULE_DESCRIPTION("Emulate keyboard input events through /dev/vinput");
-1/*
+2 * vkbd.c
+3 */
+4
+5#include <linux/init.h>
+6#include <linux/input.h>
+7#include <linux/module.h>
+8#include <linux/spinlock.h>
+9
+10#include "vinput.h"
+11
+12#define VINPUT_KBD "vkbd"
+13#define VINPUT_RELEASE 0
+14#define VINPUT_PRESS 1
+15
+16static unsigned short vkeymap[KEY_MAX];
+17
+18static int vinput_vkbd_init(struct vinput *vinput)
+19{
+20 int i;
+21
+22 /* Set up the input bitfield */
+23 vinput->input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+24 vinput->input->keycodesize = sizeof(unsigned short);
+25 vinput->input->keycodemax = KEY_MAX;
+26 vinput->input->keycode = vkeymap;
+27
+28 for (i = 0; i < KEY_MAX; i++)
+29 set_bit(vkeymap[i], vinput->input->keybit);
+30
+31 /* vinput will help us allocate new input device structure via
+32 * input_allocate_device(). So, we can register it straightforwardly.
+33 */
+34 return input_register_device(vinput->input);
+35}
+36
+37static int vinput_vkbd_read(struct vinput *vinput, char *buff, int len)
+38{
+39 spin_lock(&vinput->lock);
+40 len = snprintf(buff, len, "%+ld\n", vinput->last_entry);
+41 spin_unlock(&vinput->lock);
+42
+43 return len;
+44}
+45
+46static int vinput_vkbd_send(struct vinput *vinput, char *buff, int len)
+47{
+48 int ret;
+49 long key = 0;
+50 short type = VINPUT_PRESS;
+51
+52 /* Determine which event was received (press or release)
+53 * and store the state.
+54 */
+55 if (buff[0] == '+')
+56 ret = kstrtol(buff + 1, 10, &key);
+57 else
+58 ret = kstrtol(buff, 10, &key);
+59 if (ret)
+60 dev_err(&vinput->dev, "error during kstrtol: -%d\n", ret);
+61 spin_lock(&vinput->lock);
+62 vinput->last_entry = key;
+63 spin_unlock(&vinput->lock);
+64
+65 if (key < 0) {
+66 type = VINPUT_RELEASE;
+67 key = -key;
+68 }
+69
+70 dev_info(&vinput->dev, "Event %s code %ld\n",
+71 (type == VINPUT_RELEASE) ? "VINPUT_RELEASE" : "VINPUT_PRESS", key);
+72
+73 /* Report the state received to input subsystem. */
+74 input_report_key(vinput->input, key, type);
+75 /* Tell input subsystem that it finished the report. */
+76 input_sync(vinput->input);
+77
+78 return len;
+79}
+80
+81static struct vinput_ops vkbd_ops = {
+82 .init = vinput_vkbd_init,
+83 .send = vinput_vkbd_send,
+84 .read = vinput_vkbd_read,
+85};
+86
+87static struct vinput_device vkbd_dev = {
+88 .name = VINPUT_KBD,
+89 .ops = &vkbd_ops,
+90};
+91
+92static int __init vkbd_init(void)
+93{
+94 int i;
+95
+96 for (i = 0; i < KEY_MAX; i++)
+97 vkeymap[i] = i;
+98 return vinput_register(&vkbd_dev);
+99}
+100
+101static void __exit vkbd_end(void)
+102{
+103 vinput_unregister(&vkbd_dev);
+104}
+105
+106module_init(vkbd_init);
+107module_exit(vkbd_end);
+108
+109MODULE_LICENSE("GPL");
+110MODULE_DESCRIPTION("Emulate keyboard input events through /dev/vinput");
+18 Standardizing the interfaces: The Device Model
-17 Standardizing the interfaces: The Device Model
+1/*
-2 * devicemodel.c
-3 */
-4#include <linux/kernel.h>
-5#include <linux/module.h>
-6#include <linux/platform_device.h>
-7
-8struct devicemodel_data {
-9 char *greeting;
-10 int number;
-11};
-12
-13static int devicemodel_probe(struct platform_device *dev)
-14{
-15 struct devicemodel_data *pd =
-16 (struct devicemodel_data *)(dev->dev.platform_data);
-17
-18 pr_info("devicemodel probe\n");
-19 pr_info("devicemodel greeting: %s; %d\n", pd->greeting, pd->number);
-20
-21 /* Your device initialization code */
-22
-23 return 0;
-24}
-25
-26static int devicemodel_remove(struct platform_device *dev)
-27{
-28 pr_info("devicemodel example removed\n");
-29
-30 /* Your device removal code */
-31
-32 return 0;
-33}
-34
-35static int devicemodel_suspend(struct device *dev)
-36{
-37 pr_info("devicemodel example suspend\n");
-38
-39 /* Your device suspend code */
-40
-41 return 0;
-42}
-43
-44static int devicemodel_resume(struct device *dev)
-45{
-46 pr_info("devicemodel example resume\n");
-47
-48 /* Your device resume code */
-49
-50 return 0;
-51}
-52
-53static const struct dev_pm_ops devicemodel_pm_ops = {
-54 .suspend = devicemodel_suspend,
-55 .resume = devicemodel_resume,
-56 .poweroff = devicemodel_suspend,
-57 .freeze = devicemodel_suspend,
-58 .thaw = devicemodel_resume,
-59 .restore = devicemodel_resume,
-60};
-61
-62static struct platform_driver devicemodel_driver = {
-63 .driver =
-64 {
-65 .name = "devicemodel_example",
-66 .pm = &devicemodel_pm_ops,
-67 },
-68 .probe = devicemodel_probe,
-69 .remove = devicemodel_remove,
-70};
-71
-72static int __init devicemodel_init(void)
-73{
-74 int ret;
-75
-76 pr_info("devicemodel init\n");
-77
-78 ret = platform_driver_register(&devicemodel_driver);
-79
-80 if (ret) {
-81 pr_err("Unable to register driver\n");
-82 return ret;
-83 }
-84
-85 return 0;
-86}
-87
-88static void __exit devicemodel_exit(void)
-89{
-90 pr_info("devicemodel exit\n");
-91 platform_driver_unregister(&devicemodel_driver);
-92}
-93
-94module_init(devicemodel_init);
-95module_exit(devicemodel_exit);
-96
-97MODULE_LICENSE("GPL");
-98MODULE_DESCRIPTION("Linux Device Model example");
-1/*
+2 * devicemodel.c
+3 */
+4#include <linux/kernel.h>
+5#include <linux/module.h>
+6#include <linux/platform_device.h>
+7
+8struct devicemodel_data {
+9 char *greeting;
+10 int number;
+11};
+12
+13static int devicemodel_probe(struct platform_device *dev)
+14{
+15 struct devicemodel_data *pd =
+16 (struct devicemodel_data *)(dev->dev.platform_data);
+17
+18 pr_info("devicemodel probe\n");
+19 pr_info("devicemodel greeting: %s; %d\n", pd->greeting, pd->number);
+20
+21 /* Your device initialization code */
+22
+23 return 0;
+24}
+25
+26static int devicemodel_remove(struct platform_device *dev)
+27{
+28 pr_info("devicemodel example removed\n");
+29
+30 /* Your device removal code */
+31
+32 return 0;
+33}
+34
+35static int devicemodel_suspend(struct device *dev)
+36{
+37 pr_info("devicemodel example suspend\n");
+38
+39 /* Your device suspend code */
+40
+41 return 0;
+42}
+43
+44static int devicemodel_resume(struct device *dev)
+45{
+46 pr_info("devicemodel example resume\n");
+47
+48 /* Your device resume code */
+49
+50 return 0;
+51}
+52
+53static const struct dev_pm_ops devicemodel_pm_ops = {
+54 .suspend = devicemodel_suspend,
+55 .resume = devicemodel_resume,
+56 .poweroff = devicemodel_suspend,
+57 .freeze = devicemodel_suspend,
+58 .thaw = devicemodel_resume,
+59 .restore = devicemodel_resume,
+60};
+61
+62static struct platform_driver devicemodel_driver = {
+63 .driver =
+64 {
+65 .name = "devicemodel_example",
+66 .pm = &devicemodel_pm_ops,
+67 },
+68 .probe = devicemodel_probe,
+69 .remove = devicemodel_remove,
+70};
+71
+72static int __init devicemodel_init(void)
+73{
+74 int ret;
+75
+76 pr_info("devicemodel init\n");
+77
+78 ret = platform_driver_register(&devicemodel_driver);
+79
+80 if (ret) {
+81 pr_err("Unable to register driver\n");
+82 return ret;
+83 }
+84
+85 return 0;
+86}
+87
+88static void __exit devicemodel_exit(void)
+89{
+90 pr_info("devicemodel exit\n");
+91 platform_driver_unregister(&devicemodel_driver);
+92}
+93
+94module_init(devicemodel_init);
+95module_exit(devicemodel_exit);
+96
+97MODULE_LICENSE("GPL");
+98MODULE_DESCRIPTION("Linux Device Model example");
+19 Optimizations
-18 Optimizations
+19.1 Likely and Unlikely conditions
-18.1 Likely and Unlikely conditions
+1bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx);
+2if (unlikely(!bvl)) {
+3 mempool_free(bio, bio_pool);
+4 bio = NULL;
+5 goto out;
+6}
-1bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx);
-2if (unlikely(!bvl)) {
-3 mempool_free(bio, bio_pool);
-4 bio = NULL;
-5 goto out;
-6}
- unlikely
+
unlikely
macro is used, the compiler alters its machine instruction output, so that it
continues along the false branch and only jumps if the condition is true. That
avoids flushing the processor pipeline. The opposite happens if you use the
likely
macro.
-19.2 Static keys
-18.2 Static keys
+ asm goto
+
asm goto
inline assembly, and the following kernel configurations are set:
1CONFIG_JUMP_LABEL=y
-2CONFIG_HAVE_ARCH_JUMP_LABEL=y
-3CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y
-1CONFIG_JUMP_LABEL=y
+2CONFIG_HAVE_ARCH_JUMP_LABEL=y
+3CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y
+ DEFINE_STATIC_KEY_FALSE
or DEFINE_STATIC_KEY_TRUE
macro defined in include/linux/jump_label.h. This macro initializes the key with
@@ -6554,268 +6248,268 @@ declare a static key with an initial value of false, we can use the following
code:
1DEFINE_STATIC_KEY_FALSE(fkey);
-1DEFINE_STATIC_KEY_FALSE(fkey);
+1pr_info("fastpath 1\n");
-2if (static_branch_unlikely(&fkey))
-3 pr_alert("do unlikely thing\n");
-4pr_info("fastpath 2\n");
+ 1pr_info("fastpath 1\n");
+2if (static_branch_unlikely(&fkey))
+3 pr_alert("do unlikely thing\n");
+4pr_info("fastpath 2\n");
+ static_branch_enable(&fkey)
+
, the fastpath will be patched with an unconditional jump instruction to the slowpath
- static_branch_enable(&fkey)
-
, the fastpath will be patched with an unconditional jump instruction to the slowpath
code pr_alert
, so the branch will always be taken until the key is disabled again.
-1/*
-2 * static_key.c
-3 */
-4
-5#include <linux/atomic.h>
-6#include <linux/device.h>
-7#include <linux/fs.h>
-8#include <linux/kernel.h> /* for sprintf() */
-9#include <linux/module.h>
-10#include <linux/printk.h>
-11#include <linux/types.h>
-12#include <linux/uaccess.h> /* for get_user and put_user */
-13#include <linux/jump_label.h> /* for static key macros */
-14
-15#include <asm/errno.h>
-16
-17static int device_open(struct inode *inode, struct file *file);
-18static int device_release(struct inode *inode, struct file *file);
-19static ssize_t device_read(struct file *file, char __user *buf, size_t count,
-20 loff_t *ppos);
-21static ssize_t device_write(struct file *file, const char __user *buf,
-22 size_t count, loff_t *ppos);
-23
-24#define SUCCESS 0
-25#define DEVICE_NAME "key_state"
-26#define BUF_LEN 10
-27
-28static int major;
-29
-30enum {
-31 CDEV_NOT_USED = 0,
-32 CDEV_EXCLUSIVE_OPEN = 1,
-33};
-34
-35static atomic_t already_open = ATOMIC_INIT(CDEV_NOT_USED);
-36
-37static char msg[BUF_LEN + 1];
-38
-39static struct class *cls;
-40
-41static DEFINE_STATIC_KEY_FALSE(fkey);
-42
-43static struct file_operations chardev_fops = {
-44 .owner = THIS_MODULE,
-45 .open = device_open,
-46 .release = device_release,
-47 .read = device_read,
-48 .write = device_write,
-49};
-50
-51static int __init chardev_init(void)
-52{
-53 major = register_chrdev(0, DEVICE_NAME, &chardev_fops);
-54 if (major < 0) {
-55 pr_alert("Registering char device failed with %d\n", major);
-56 return major;
-57 }
-58
-59 pr_info("I was assigned major number %d\n", major);
-60
-61 cls = class_create(THIS_MODULE, DEVICE_NAME);
-62
-63 device_create(cls, NULL, MKDEV(major, 0), NULL, DEVICE_NAME);
-64
-65 pr_info("Device created on /dev/%s\n", DEVICE_NAME);
-66
-67 return SUCCESS;
-68}
-69
-70static void __exit chardev_exit(void)
-71{
-72 device_destroy(cls, MKDEV(major, 0));
-73 class_destroy(cls);
-74
-75 /* Unregister the device */
-76 unregister_chrdev(major, DEVICE_NAME);
-77}
-78
-79/* Methods */
-80
-81/**
-82 * Called when a process tried to open the device file, like
-83 * cat /dev/key_state
-84 */
-85static int device_open(struct inode *inode, struct file *file)
-86{
-87 if (atomic_cmpxchg(&already_open, CDEV_NOT_USED, CDEV_EXCLUSIVE_OPEN))
-88 return -EBUSY;
-89
-90 sprintf(msg, static_key_enabled(&fkey) ? "enabled\n" : "disabled\n");
-91
-92 pr_info("fastpath 1\n");
-93 if (static_branch_unlikely(&fkey))
-94 pr_alert("do unlikely thing\n");
-95 pr_info("fastpath 2\n");
-96
-97 try_module_get(THIS_MODULE);
-98
-99 return SUCCESS;
-100}
-101
-102/**
-103 * Called when a process closes the device file
-104 */
-105static int device_release(struct inode *inode, struct file *file)
-106{
-107 /* We are now ready for our next caller. */
-108 atomic_set(&already_open, CDEV_NOT_USED);
-109
-110 /**
-111 * Decrement the usage count, or else once you opened the file, you will
-112 * never get rid of the module.
-113 */
-114 module_put(THIS_MODULE);
-115
-116 return SUCCESS;
-117}
-118
-119/**
-120 * Called when a process, which already opened the dev file, attempts to
-121 * read from it.
-122 */
-123static ssize_t device_read(struct file *filp, /* see include/linux/fs.h */
-124 char __user *buffer, /* buffer to fill with data */
-125 size_t length, /* length of the buffer */
-126 loff_t *offset)
-127{
-128 /* Number of the bytes actually written to the buffer */
-129 int bytes_read = 0;
-130 const char *msg_ptr = msg;
-131
-132 if (!*(msg_ptr + *offset)) { /* We are at the end of the message */
-133 *offset = 0; /* reset the offset */
-134 return 0; /* signify end of file */
-135 }
-136
-137 msg_ptr += *offset;
-138
-139 /* Actually put the data into the buffer */
-140 while (length && *msg_ptr) {
-141 /**
-142 * The buffer is in the user data segment, not the kernel
-143 * segment so "*" assignment won't work. We have to use
-144 * put_user which copies data from the kernel data segment to
-145 * the user data segment.
-146 */
-147 put_user(*(msg_ptr++), buffer++);
-148 length--;
-149 bytes_read++;
-150 }
-151
-152 *offset += bytes_read;
-153
-154 /* Most read functions return the number of bytes put into the buffer. */
-155 return bytes_read;
-156}
-157
-158/* Called when a process writes to dev file; echo "enable" > /dev/key_state */
-159static ssize_t device_write(struct file *filp, const char __user *buffer,
-160 size_t length, loff_t *offset)
-161{
-162 char command[10];
-163
-164 if (length > 10) {
-165 pr_err("command exceeded 10 char\n");
-166 return -EINVAL;
-167 }
-168
-169 if (copy_from_user(command, buffer, length))
-170 return -EFAULT;
-171
-172 if (strncmp(command, "enable", strlen("enable")) == 0)
-173 static_branch_enable(&fkey);
-174 else if (strncmp(command, "disable", strlen("disable")) == 0)
-175 static_branch_disable(&fkey);
-176 else {
-177 pr_err("Invalid command: %s\n", command);
-178 return -EINVAL;
-179 }
-180
-181 /* Again, return the number of input characters used. */
-182 return length;
-183}
-184
-185module_init(chardev_init);
-186module_exit(chardev_exit);
-187
-188MODULE_LICENSE("GPL");
-1/*
+2 * static_key.c
+3 */
+4
+5#include <linux/atomic.h>
+6#include <linux/device.h>
+7#include <linux/fs.h>
+8#include <linux/kernel.h> /* for sprintf() */
+9#include <linux/module.h>
+10#include <linux/printk.h>
+11#include <linux/types.h>
+12#include <linux/uaccess.h> /* for get_user and put_user */
+13#include <linux/jump_label.h> /* for static key macros */
+14
+15#include <asm/errno.h>
+16
+17static int device_open(struct inode *inode, struct file *file);
+18static int device_release(struct inode *inode, struct file *file);
+19static ssize_t device_read(struct file *file, char __user *buf, size_t count,
+20 loff_t *ppos);
+21static ssize_t device_write(struct file *file, const char __user *buf,
+22 size_t count, loff_t *ppos);
+23
+24#define SUCCESS 0
+25#define DEVICE_NAME "key_state"
+26#define BUF_LEN 10
+27
+28static int major;
+29
+30enum {
+31 CDEV_NOT_USED = 0,
+32 CDEV_EXCLUSIVE_OPEN = 1,
+33};
+34
+35static atomic_t already_open = ATOMIC_INIT(CDEV_NOT_USED);
+36
+37static char msg[BUF_LEN + 1];
+38
+39static struct class *cls;
+40
+41static DEFINE_STATIC_KEY_FALSE(fkey);
+42
+43static struct file_operations chardev_fops = {
+44 .owner = THIS_MODULE,
+45 .open = device_open,
+46 .release = device_release,
+47 .read = device_read,
+48 .write = device_write,
+49};
+50
+51static int __init chardev_init(void)
+52{
+53 major = register_chrdev(0, DEVICE_NAME, &chardev_fops);
+54 if (major < 0) {
+55 pr_alert("Registering char device failed with %d\n", major);
+56 return major;
+57 }
+58
+59 pr_info("I was assigned major number %d\n", major);
+60
+61 cls = class_create(THIS_MODULE, DEVICE_NAME);
+62
+63 device_create(cls, NULL, MKDEV(major, 0), NULL, DEVICE_NAME);
+64
+65 pr_info("Device created on /dev/%s\n", DEVICE_NAME);
+66
+67 return SUCCESS;
+68}
+69
+70static void __exit chardev_exit(void)
+71{
+72 device_destroy(cls, MKDEV(major, 0));
+73 class_destroy(cls);
+74
+75 /* Unregister the device */
+76 unregister_chrdev(major, DEVICE_NAME);
+77}
+78
+79/* Methods */
+80
+81/**
+82 * Called when a process tried to open the device file, like
+83 * cat /dev/key_state
+84 */
+85static int device_open(struct inode *inode, struct file *file)
+86{
+87 if (atomic_cmpxchg(&already_open, CDEV_NOT_USED, CDEV_EXCLUSIVE_OPEN))
+88 return -EBUSY;
+89
+90 sprintf(msg, static_key_enabled(&fkey) ? "enabled\n" : "disabled\n");
+91
+92 pr_info("fastpath 1\n");
+93 if (static_branch_unlikely(&fkey))
+94 pr_alert("do unlikely thing\n");
+95 pr_info("fastpath 2\n");
+96
+97 try_module_get(THIS_MODULE);
+98
+99 return SUCCESS;
+100}
+101
+102/**
+103 * Called when a process closes the device file
+104 */
+105static int device_release(struct inode *inode, struct file *file)
+106{
+107 /* We are now ready for our next caller. */
+108 atomic_set(&already_open, CDEV_NOT_USED);
+109
+110 /**
+111 * Decrement the usage count, or else once you opened the file, you will
+112 * never get rid of the module.
+113 */
+114 module_put(THIS_MODULE);
+115
+116 return SUCCESS;
+117}
+118
+119/**
+120 * Called when a process, which already opened the dev file, attempts to
+121 * read from it.
+122 */
+123static ssize_t device_read(struct file *filp, /* see include/linux/fs.h */
+124 char __user *buffer, /* buffer to fill with data */
+125 size_t length, /* length of the buffer */
+126 loff_t *offset)
+127{
+128 /* Number of the bytes actually written to the buffer */
+129 int bytes_read = 0;
+130 const char *msg_ptr = msg;
+131
+132 if (!*(msg_ptr + *offset)) { /* We are at the end of the message */
+133 *offset = 0; /* reset the offset */
+134 return 0; /* signify end of file */
+135 }
+136
+137 msg_ptr += *offset;
+138
+139 /* Actually put the data into the buffer */
+140 while (length && *msg_ptr) {
+141 /**
+142 * The buffer is in the user data segment, not the kernel
+143 * segment so "*" assignment won't work. We have to use
+144 * put_user which copies data from the kernel data segment to
+145 * the user data segment.
+146 */
+147 put_user(*(msg_ptr++), buffer++);
+148 length--;
+149 bytes_read++;
+150 }
+151
+152 *offset += bytes_read;
+153
+154 /* Most read functions return the number of bytes put into the buffer. */
+155 return bytes_read;
+156}
+157
+158/* Called when a process writes to dev file; echo "enable" > /dev/key_state */
+159static ssize_t device_write(struct file *filp, const char __user *buffer,
+160 size_t length, loff_t *offset)
+161{
+162 char command[10];
+163
+164 if (length > 10) {
+165 pr_err("command exceeded 10 char\n");
+166 return -EINVAL;
+167 }
+168
+169 if (copy_from_user(command, buffer, length))
+170 return -EFAULT;
+171
+172 if (strncmp(command, "enable", strlen("enable")) == 0)
+173 static_branch_enable(&fkey);
+174 else if (strncmp(command, "disable", strlen("disable")) == 0)
+175 static_branch_disable(&fkey);
+176 else {
+177 pr_err("Invalid command: %s\n", command);
+178 return -EINVAL;
+179 }
+180
+181 /* Again, return the number of input characters used. */
+182 return length;
+183}
+184
+185module_init(chardev_init);
+186module_exit(chardev_exit);
+187
+188MODULE_LICENSE("GPL");
+1cat /dev/key_state
-1cat /dev/key_state
+1echo enable > /dev/key_state
-1echo enable > /dev/key_state
+ DEFINE_STATIC_KEY_FALSE_RO
or DEFINE_STATIC_KEY_TRUE_RO
macro instead. Attempts to change the key at runtime will result in a page fault. For
more information, see Static keys
-20 Common Pitfalls
-19 Common Pitfalls
+19.1 Using standard libraries
+20.1 Using standard libraries
-20.2 Disabling interrupts
-19.2 Disabling interrupts
+21 Where To Go From Here?
-20 Where To Go From Here?
+