diff --git a/index.html b/index.html index d40de12..970470d 100644 --- a/index.html +++ b/index.html @@ -5174,136 +5174,200 @@ appropriate for your board. 13#include <linux/kernel.h> /* for ARRAY_SIZE() */ 14#include <linux/module.h> 15#include <linux/printk.h> -16 -17static int button_irqs[] = { -1, -1 }; -18 -19/* Define GPIOs for LEDs. -20 * TODO: Change the numbers for the GPIO on your board. -21 */ -22static struct gpio leds[] = { { 4, GPIOF_OUT_INIT_LOW, "LED 1" } }; +16#include <linux/version.h> +17 +18#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) +19#define NO_GPIO_REQUEST_ARRAY +20#endif +21 +22static int button_irqs[] = { -1, -1 }; 23 -24/* Define GPIOs for BUTTONS -25 * TODO: Change the numbers for the GPIO on your board. -26 */ -27static struct gpio buttons[] = { { 17, GPIOF_IN, "LED 1 ON BUTTON" }, -28 { 18, GPIOF_IN, "LED 1 OFF BUTTON" } }; -29 -30/* interrupt function triggered when a button is pressed. */ -31static irqreturn_t button_isr(int irq, void *data) -32{ -33 /* first button */ -34 if (irq == button_irqs[0] && !gpio_get_value(leds[0].gpio)) -35 gpio_set_value(leds[0].gpio, 1); -36 /* second button */ -37 else if (irq == button_irqs[1] && gpio_get_value(leds[0].gpio)) -38 gpio_set_value(leds[0].gpio, 0); -39 -40 return IRQ_HANDLED; -41} -42 -43static int __init intrpt_init(void) -44{ -45 int ret = 0; -46 -47 pr_info("%s\n", __func__); -48 -49 /* register LED gpios */ -50 ret = gpio_request_array(leds, ARRAY_SIZE(leds)); +24/* Define GPIOs for LEDs. +25 * TODO: Change the numbers for the GPIO on your board. +26 */ +27static struct gpio leds[] = { { 4, GPIOF_OUT_INIT_LOW, "LED 1" } }; +28 +29/* Define GPIOs for BUTTONS +30 * TODO: Change the numbers for the GPIO on your board. +31 */ +32static struct gpio buttons[] = { { 17, GPIOF_IN, "LED 1 ON BUTTON" }, +33 { 18, GPIOF_IN, "LED 1 OFF BUTTON" } }; +34 +35/* interrupt function triggered when a button is pressed. */ +36static irqreturn_t button_isr(int irq, void *data) +37{ +38 /* first button */ +39 if (irq == button_irqs[0] && !gpio_get_value(leds[0].gpio)) +40 gpio_set_value(leds[0].gpio, 1); +41 /* second button */ +42 else if (irq == button_irqs[1] && gpio_get_value(leds[0].gpio)) +43 gpio_set_value(leds[0].gpio, 0); +44 +45 return IRQ_HANDLED; +46} +47 +48static int __init intrpt_init(void) +49{ +50 int ret = 0; 51 -52 if (ret) { -53 pr_err("Unable to request GPIOs for LEDs: %d\n", ret); -54 return ret; -55 } -56 -57 /* register BUTTON gpios */ -58 ret = gpio_request_array(buttons, ARRAY_SIZE(buttons)); -59 -60 if (ret) { -61 pr_err("Unable to request GPIOs for BUTTONs: %d\n", ret); -62 goto fail1; -63 } -64 -65 pr_info("Current button1 value: %d\n", gpio_get_value(buttons[0].gpio)); -66 -67 ret = gpio_to_irq(buttons[0].gpio); -68 -69 if (ret < 0) { -70 pr_err("Unable to request IRQ: %d\n", ret); -71 goto fail2; -72 } -73 -74 button_irqs[0] = ret; -75 -76 pr_info("Successfully requested BUTTON1 IRQ # %d\n", button_irqs[0]); -77 -78 ret = request_irq(button_irqs[0], button_isr, -79 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, -80 "gpiomod#button1", NULL); -81 -82 if (ret) { -83 pr_err("Unable to request IRQ: %d\n", ret); -84 goto fail2; -85 } -86 -87 ret = gpio_to_irq(buttons[1].gpio); -88 -89 if (ret < 0) { -90 pr_err("Unable to request IRQ: %d\n", ret); -91 goto fail2; -92 } +52 pr_info("%s\n", __func__); +53 +54 /* register LED gpios */ +55#ifdef NO_GPIO_REQUEST_ARRAY +56 ret = gpio_request(leds[0].gpio, leds[0].label); +57#else +58 ret = gpio_request_array(leds, ARRAY_SIZE(leds)); +59#endif +60 +61 if (ret) { +62 pr_err("Unable to request GPIOs for LEDs: %d\n", ret); +63 return ret; +64 } +65 +66 /* register BUTTON gpios */ +67#ifdef NO_GPIO_REQUEST_ARRAY +68 ret = gpio_request(buttons[0].gpio, buttons[0].label); +69 +70 if (ret) { +71 pr_err("Unable to request GPIOs for BUTTONs: %d\n", ret); +72 goto fail1; +73 } +74 +75 ret = gpio_request(buttons[1].gpio, buttons[1].label); +76 +77 if (ret) { +78 pr_err("Unable to request GPIOs for BUTTONs: %d\n", ret); +79 goto fail2; +80 } +81#else +82 ret = gpio_request_array(buttons, ARRAY_SIZE(buttons)); +83 +84 if (ret) { +85 pr_err("Unable to request GPIOs for BUTTONs: %d\n", ret); +86 goto fail1; +87 } +88#endif +89 +90 pr_info("Current button1 value: %d\n", gpio_get_value(buttons[0].gpio)); +91 +92 ret = gpio_to_irq(buttons[0].gpio); 93 -94 button_irqs[1] = ret; -95 -96 pr_info("Successfully requested BUTTON2 IRQ # %d\n", button_irqs[1]); -97 -98 ret = request_irq(button_irqs[1], button_isr, -99 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, -100 "gpiomod#button2", NULL); -101 -102 if (ret) { -103 pr_err("Unable to request IRQ: %d\n", ret); -104 goto fail3; -105 } +94 if (ret < 0) { +95 pr_err("Unable to request IRQ: %d\n", ret); +96#ifdef NO_GPIO_REQUEST_ARRAY +97 goto fail3; +98#else +99 goto fail2; +100#endif +101 } +102 +103 button_irqs[0] = ret; +104 +105 pr_info("Successfully requested BUTTON1 IRQ # %d\n", button_irqs[0]); 106 -107 return 0; -108 -109/* cleanup what has been setup so far */ -110fail3: -111 free_irq(button_irqs[0], NULL); -112 -113fail2: -114 gpio_free_array(buttons, ARRAY_SIZE(leds)); -115 -116fail1: -117 gpio_free_array(leds, ARRAY_SIZE(leds)); -118 -119 return ret; -120} +107 ret = request_irq(button_irqs[0], button_isr, +108 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, +109 "gpiomod#button1", NULL); +110 +111 if (ret) { +112 pr_err("Unable to request IRQ: %d\n", ret); +113#ifdef NO_GPIO_REQUEST_ARRAY +114 goto fail3; +115#else +116 goto fail2; +117#endif +118 } +119 +120 ret = gpio_to_irq(buttons[1].gpio); 121 -122static void __exit intrpt_exit(void) -123{ -124 int i; -125 -126 pr_info("%s\n", __func__); -127 -128 /* free irqs */ -129 free_irq(button_irqs[0], NULL); -130 free_irq(button_irqs[1], NULL); -131 -132 /* turn all LEDs off */ -133 for (i = 0; i < ARRAY_SIZE(leds); i++) -134 gpio_set_value(leds[i].gpio, 0); -135 -136 /* unregister */ -137 gpio_free_array(leds, ARRAY_SIZE(leds)); -138 gpio_free_array(buttons, ARRAY_SIZE(buttons)); -139} -140 -141module_init(intrpt_init); -142module_exit(intrpt_exit); -143 -144MODULE_LICENSE("GPL"); -145MODULE_DESCRIPTION("Handle some GPIO interrupts"); +122 if (ret < 0) { +123 pr_err("Unable to request IRQ: %d\n", ret); +124#ifdef NO_GPIO_REQUEST_ARRAY +125 goto fail3; +126#else +127 goto fail2; +128#endif +129 } +130 +131 button_irqs[1] = ret; +132 +133 pr_info("Successfully requested BUTTON2 IRQ # %d\n", button_irqs[1]); +134 +135 ret = request_irq(button_irqs[1], button_isr, +136 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, +137 "gpiomod#button2", NULL); +138 +139 if (ret) { +140 pr_err("Unable to request IRQ: %d\n", ret); +141#ifdef NO_GPIO_REQUEST_ARRAY +142 goto fail4; +143#else +144 goto fail3; +145#endif +146 } +147 +148 return 0; +149 +150/* cleanup what has been setup so far */ +151#ifdef NO_GPIO_REQUEST_ARRAY +152fail4: +153 free_irq(button_irqs[0], NULL); +154 +155fail3: +156 gpio_free(buttons[1].gpio); +157 +158fail2: +159 gpio_free(buttons[0].gpio); +160 +161fail1: +162 gpio_free(leds[0].gpio); +163#else +164fail3: +165 free_irq(button_irqs[0], NULL); +166 +167fail2: +168 gpio_free_array(buttons, ARRAY_SIZE(leds)); +169 +170fail1: +171 gpio_free_array(leds, ARRAY_SIZE(leds)); +172#endif +173 +174 return ret; +175} +176 +177static void __exit intrpt_exit(void) +178{ +179 pr_info("%s\n", __func__); +180 +181 /* free irqs */ +182 free_irq(button_irqs[0], NULL); +183 free_irq(button_irqs[1], NULL); +184 +185 /* turn all LEDs off */ +186#ifdef NO_GPIO_REQUEST_ARRAY +187 gpio_set_value(leds[0].gpio, 0); +188#else +189 int i; +190 for (i = 0; i < ARRAY_SIZE(leds); i++) +191 gpio_set_value(leds[i].gpio, 0); +192#endif +193 +194 /* unregister */ +195#ifdef NO_GPIO_REQUEST_ARRAY +196 gpio_free(leds[0].gpio); +197 gpio_free(buttons[0].gpio); +198 gpio_free(buttons[1].gpio); +199#else +200 gpio_free_array(leds, ARRAY_SIZE(leds)); +201 gpio_free_array(buttons, ARRAY_SIZE(buttons)); +202#endif +203} +204 +205module_init(intrpt_init); +206module_exit(intrpt_exit); +207 +208MODULE_LICENSE("GPL"); +209MODULE_DESCRIPTION("Handle some GPIO interrupts");
@@ -5318,174 +5382,238 @@ scheduler. when an interrupt is triggered.
-
1/* -2 * bottomhalf.c - Top and bottom half interrupt handling -3 * -4 * Based upon the RPi example by Stefan Wendler (devnull@kaltpost.de) -5 * from: -6 * https://github.com/wendlers/rpi-kmod-samples -7 * -8 * Press one button to turn on an LED and another to turn it off -9 */ +1/* +2 * bottomhalf.c - Top and bottom half interrupt handling +3 * +4 * Based upon the RPi example by Stefan Wendler (devnull@kaltpost.de) +5 * from: +6 * https://github.com/wendlers/rpi-kmod-samples +7 * +8 * Press one button to turn on an LED and another to turn it off +9 */ 10 -11#include <linux/delay.h> -12#include <linux/gpio.h> -13#include <linux/interrupt.h> -14#include <linux/module.h> -15#include <linux/printk.h> -16#include <linux/init.h> -17 -18/* Macro DECLARE_TASKLET_OLD exists for compatibility. -19 * See https://lwn.net/Articles/830964/ -20 */ -21#ifndef DECLARE_TASKLET_OLD -22#define DECLARE_TASKLET_OLD(arg1, arg2) DECLARE_TASKLET(arg1, arg2, 0L) -23#endif -24 -25static int button_irqs[] = { -1, -1 }; -26 -27/* Define GPIOs for LEDs. -28 * TODO: Change the numbers for the GPIO on your board. -29 */ -30static struct gpio leds[] = { { 4, GPIOF_OUT_INIT_LOW, "LED 1" } }; +11#include <linux/delay.h> +12#include <linux/gpio.h> +13#include <linux/interrupt.h> +14#include <linux/module.h> +15#include <linux/printk.h> +16#include <linux/init.h> +17#include <linux/version.h> +18 +19#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) +20#define NO_GPIO_REQUEST_ARRAY +21#endif +22 +23/* Macro DECLARE_TASKLET_OLD exists for compatibility. +24 * See https://lwn.net/Articles/830964/ +25 */ +26#ifndef DECLARE_TASKLET_OLD +27#define DECLARE_TASKLET_OLD(arg1, arg2) DECLARE_TASKLET(arg1, arg2, 0L) +28#endif +29 +30static int button_irqs[] = { -1, -1 }; 31 -32/* Define GPIOs for BUTTONS -33 * TODO: Change the numbers for the GPIO on your board. -34 */ -35static struct gpio buttons[] = { -36 { 17, GPIOF_IN, "LED 1 ON BUTTON" }, -37 { 18, GPIOF_IN, "LED 1 OFF BUTTON" }, -38}; -39 -40/* Tasklet containing some non-trivial amount of processing */ -41static void bottomhalf_tasklet_fn(unsigned long data) -42{ -43 pr_info("Bottom half tasklet starts\n"); -44 /* do something which takes a while */ -45 mdelay(500); -46 pr_info("Bottom half tasklet ends\n"); -47} -48 -49static DECLARE_TASKLET_OLD(buttontask, bottomhalf_tasklet_fn); -50 -51/* interrupt function triggered when a button is pressed */ -52static irqreturn_t button_isr(int irq, void *data) -53{ -54 /* Do something quickly right now */ -55 if (irq == button_irqs[0] && !gpio_get_value(leds[0].gpio)) -56 gpio_set_value(leds[0].gpio, 1); -57 else if (irq == button_irqs[1] && gpio_get_value(leds[0].gpio)) -58 gpio_set_value(leds[0].gpio, 0); -59 -60 /* Do the rest at leisure via the scheduler */ -61 tasklet_schedule(&buttontask); -62 -63 return IRQ_HANDLED; -64} -65 -66static int __init bottomhalf_init(void) -67{ -68 int ret = 0; -69 -70 pr_info("%s\n", __func__); -71 -72 /* register LED gpios */ -73 ret = gpio_request_array(leds, ARRAY_SIZE(leds)); +32/* Define GPIOs for LEDs. +33 * TODO: Change the numbers for the GPIO on your board. +34 */ +35static struct gpio leds[] = { { 4, GPIOF_OUT_INIT_LOW, "LED 1" } }; +36 +37/* Define GPIOs for BUTTONS +38 * TODO: Change the numbers for the GPIO on your board. +39 */ +40static struct gpio buttons[] = { +41 { 17, GPIOF_IN, "LED 1 ON BUTTON" }, +42 { 18, GPIOF_IN, "LED 1 OFF BUTTON" }, +43}; +44 +45/* Tasklet containing some non-trivial amount of processing */ +46static void bottomhalf_tasklet_fn(unsigned long data) +47{ +48 pr_info("Bottom half tasklet starts\n"); +49 /* do something which takes a while */ +50 mdelay(500); +51 pr_info("Bottom half tasklet ends\n"); +52} +53 +54static DECLARE_TASKLET_OLD(buttontask, bottomhalf_tasklet_fn); +55 +56/* interrupt function triggered when a button is pressed */ +57static irqreturn_t button_isr(int irq, void *data) +58{ +59 /* Do something quickly right now */ +60 if (irq == button_irqs[0] && !gpio_get_value(leds[0].gpio)) +61 gpio_set_value(leds[0].gpio, 1); +62 else if (irq == button_irqs[1] && gpio_get_value(leds[0].gpio)) +63 gpio_set_value(leds[0].gpio, 0); +64 +65 /* Do the rest at leisure via the scheduler */ +66 tasklet_schedule(&buttontask); +67 +68 return IRQ_HANDLED; +69} +70 +71static int __init bottomhalf_init(void) +72{ +73 int ret = 0; 74 -75 if (ret) { -76 pr_err("Unable to request GPIOs for LEDs: %d\n", ret); -77 return ret; -78 } -79 -80 /* register BUTTON gpios */ -81 ret = gpio_request_array(buttons, ARRAY_SIZE(buttons)); -82 -83 if (ret) { -84 pr_err("Unable to request GPIOs for BUTTONs: %d\n", ret); -85 goto fail1; -86 } -87 -88 pr_info("Current button1 value: %d\n", gpio_get_value(buttons[0].gpio)); -89 -90 ret = gpio_to_irq(buttons[0].gpio); -91 -92 if (ret < 0) { -93 pr_err("Unable to request IRQ: %d\n", ret); -94 goto fail2; -95 } -96 -97 button_irqs[0] = ret; -98 -99 pr_info("Successfully requested BUTTON1 IRQ # %d\n", button_irqs[0]); -100 -101 ret = request_irq(button_irqs[0], button_isr, -102 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, -103 "gpiomod#button1", NULL); -104 -105 if (ret) { -106 pr_err("Unable to request IRQ: %d\n", ret); -107 goto fail2; -108 } -109 -110 ret = gpio_to_irq(buttons[1].gpio); -111 -112 if (ret < 0) { -113 pr_err("Unable to request IRQ: %d\n", ret); -114 goto fail2; -115 } +75 pr_info("%s\n", __func__); +76 +77 /* register LED gpios */ +78#ifdef NO_GPIO_REQUEST_ARRAY +79 ret = gpio_request(leds[0].gpio, leds[0].label); +80#else +81 ret = gpio_request_array(leds, ARRAY_SIZE(leds)); +82#endif +83 +84 if (ret) { +85 pr_err("Unable to request GPIOs for LEDs: %d\n", ret); +86 return ret; +87 } +88 +89 /* register BUTTON gpios */ +90#ifdef NO_GPIO_REQUEST_ARRAY +91 ret = gpio_request(buttons[0].gpio, buttons[0].label); +92 +93 if (ret) { +94 pr_err("Unable to request GPIOs for BUTTONs: %d\n", ret); +95 goto fail1; +96 } +97 +98 ret = gpio_request(buttons[1].gpio, buttons[1].label); +99 +100 if (ret) { +101 pr_err("Unable to request GPIOs for BUTTONs: %d\n", ret); +102 goto fail2; +103 } +104#else +105 ret = gpio_request_array(buttons, ARRAY_SIZE(buttons)); +106 +107 if (ret) { +108 pr_err("Unable to request GPIOs for BUTTONs: %d\n", ret); +109 goto fail1; +110 } +111#endif +112 +113 pr_info("Current button1 value: %d\n", gpio_get_value(buttons[0].gpio)); +114 +115 ret = gpio_to_irq(buttons[0].gpio); 116 -117 button_irqs[1] = ret; -118 -119 pr_info("Successfully requested BUTTON2 IRQ # %d\n", button_irqs[1]); -120 -121 ret = request_irq(button_irqs[1], button_isr, -122 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, -123 "gpiomod#button2", NULL); -124 -125 if (ret) { -126 pr_err("Unable to request IRQ: %d\n", ret); -127 goto fail3; -128 } +117 if (ret < 0) { +118 pr_err("Unable to request IRQ: %d\n", ret); +119#ifdef NO_GPIO_REQUEST_ARRAY +120 goto fail3; +121#else +122 goto fail2; +123#endif +124 } +125 +126 button_irqs[0] = ret; +127 +128 pr_info("Successfully requested BUTTON1 IRQ # %d\n", button_irqs[0]); 129 -130 return 0; -131 -132/* cleanup what has been setup so far */ -133fail3: -134 free_irq(button_irqs[0], NULL); -135 -136fail2: -137 gpio_free_array(buttons, ARRAY_SIZE(leds)); -138 -139fail1: -140 gpio_free_array(leds, ARRAY_SIZE(leds)); -141 -142 return ret; -143} +130 ret = request_irq(button_irqs[0], button_isr, +131 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, +132 "gpiomod#button1", NULL); +133 +134 if (ret) { +135 pr_err("Unable to request IRQ: %d\n", ret); +136#ifdef NO_GPIO_REQUEST_ARRAY +137 goto fail3; +138#else +139 goto fail2; +140#endif +141 } +142 +143 ret = gpio_to_irq(buttons[1].gpio); 144 -145static void __exit bottomhalf_exit(void) -146{ -147 int i; -148 -149 pr_info("%s\n", __func__); -150 -151 /* free irqs */ -152 free_irq(button_irqs[0], NULL); -153 free_irq(button_irqs[1], NULL); -154 -155 /* turn all LEDs off */ -156 for (i = 0; i < ARRAY_SIZE(leds); i++) -157 gpio_set_value(leds[i].gpio, 0); -158 -159 /* unregister */ -160 gpio_free_array(leds, ARRAY_SIZE(leds)); -161 gpio_free_array(buttons, ARRAY_SIZE(buttons)); -162} -163 -164module_init(bottomhalf_init); -165module_exit(bottomhalf_exit); -166 -167MODULE_LICENSE("GPL"); -168MODULE_DESCRIPTION("Interrupt with top and bottom half");+145 if (ret < 0) { +146 pr_err("Unable to request IRQ: %d\n", ret); +147#ifdef NO_GPIO_REQUEST_ARRAY +148 goto fail3; +149#else +150 goto fail2; +151#endif +152 } +153 +154 button_irqs[1] = ret; +155 +156 pr_info("Successfully requested BUTTON2 IRQ # %d\n", button_irqs[1]); +157 +158 ret = request_irq(button_irqs[1], button_isr, +159 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, +160 "gpiomod#button2", NULL); +161 +162 if (ret) { +163 pr_err("Unable to request IRQ: %d\n", ret); +164#ifdef NO_GPIO_REQUEST_ARRAY +165 goto fail4; +166#else +167 goto fail3; +168#endif +169 } +170 +171 return 0; +172 +173/* cleanup what has been setup so far */ +174#ifdef NO_GPIO_REQUEST_ARRAY +175fail4: +176 free_irq(button_irqs[0], NULL); +177 +178fail3: +179 gpio_free(buttons[1].gpio); +180 +181fail2: +182 gpio_free(buttons[0].gpio); +183 +184fail1: +185 gpio_free(leds[0].gpio); +186#else +187fail3: +188 free_irq(button_irqs[0], NULL); +189 +190fail2: +191 gpio_free_array(buttons, ARRAY_SIZE(leds)); +192 +193fail1: +194 gpio_free_array(leds, ARRAY_SIZE(leds)); +195#endif +196 +197 return ret; +198} +199 +200static void __exit bottomhalf_exit(void) +201{ +202 pr_info("%s\n", __func__); +203 +204 /* free irqs */ +205 free_irq(button_irqs[0], NULL); +206 free_irq(button_irqs[1], NULL); +207 +208 /* turn all LEDs off */ +209#ifdef NO_GPIO_REQUEST_ARRAY +210 gpio_set_value(leds[0].gpio, 0); +211#else +212 int i; +213 for (i = 0; i < ARRAY_SIZE(leds); i++) +214 gpio_set_value(leds[i].gpio, 0); +215#endif +216 +217 /* unregister */ +218#ifdef NO_GPIO_REQUEST_ARRAY +219 gpio_free(leds[0].gpio); +220 gpio_free(buttons[0].gpio); +221 gpio_free(buttons[1].gpio); +222#else +223 gpio_free_array(leds, ARRAY_SIZE(leds)); +224 gpio_free_array(buttons, ARRAY_SIZE(buttons)); +225#endif +226} +227 +228module_init(bottomhalf_init); +229module_exit(bottomhalf_exit); +230 +231MODULE_LICENSE("GPL"); +232MODULE_DESCRIPTION("Interrupt with top and bottom half");
-
1/* -2 * bh_thread.c - Top and bottom half interrupt handling -3 * -4 * Based upon the RPi example by Stefan Wendler (devnull@kaltpost.de) -5 * from: -6 * https://github.com/wendlers/rpi-kmod-samples -7 * -8 * Press one button to turn on a LED and another to turn it off -9 */ +1/* +2 * bh_thread.c - Top and bottom half interrupt handling +3 * +4 * Based upon the RPi example by Stefan Wendler (devnull@kaltpost.de) +5 * from: +6 * https://github.com/wendlers/rpi-kmod-samples +7 * +8 * Press one button to turn on a LED and another to turn it off +9 */ 10 -11#include <linux/module.h> -12#include <linux/kernel.h> -13#include <linux/gpio.h> -14#include <linux/delay.h> -15#include <linux/interrupt.h> -16 -17static int button_irqs[] = { -1, -1 }; -18 -19/* Define GPIOs for LEDs. -20 * FIXME: Change the numbers for the GPIO on your board. -21 */ -22static struct gpio leds[] = { { 4, GPIOF_OUT_INIT_LOW, "LED 1" } }; +11#include <linux/module.h> +12#include <linux/kernel.h> +13#include <linux/gpio.h> +14#include <linux/delay.h> +15#include <linux/interrupt.h> +16#include <linux/version.h> +17 +18#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) +19#define NO_GPIO_REQUEST_ARRAY +20#endif +21 +22static int button_irqs[] = { -1, -1 }; 23 -24/* Define GPIOs for BUTTONS -25 * FIXME: Change the numbers for the GPIO on your board. -26 */ -27static struct gpio buttons[] = { -28 { 17, GPIOF_IN, "LED 1 ON BUTTON" }, -29 { 18, GPIOF_IN, "LED 1 OFF BUTTON" }, -30}; -31 -32/* This happens immediately, when the IRQ is triggered */ -33static irqreturn_t button_top_half(int irq, void *ident) -34{ -35 return IRQ_WAKE_THREAD; -36} -37 -38/* This can happen at leisure, freeing up IRQs for other high priority task */ -39static irqreturn_t button_bottom_half(int irq, void *ident) -40{ -41 pr_info("Bottom half task starts\n"); -42 mdelay(500); /* do something which takes a while */ -43 pr_info("Bottom half task ends\n"); -44 return IRQ_HANDLED; -45} -46 -47static int __init bottomhalf_init(void) -48{ -49 int ret = 0; -50 -51 pr_info("%s\n", __func__); -52 -53 /* register LED gpios */ -54 ret = gpio_request_array(leds, ARRAY_SIZE(leds)); +24/* Define GPIOs for LEDs. +25 * FIXME: Change the numbers for the GPIO on your board. +26 */ +27static struct gpio leds[] = { { 4, GPIOF_OUT_INIT_LOW, "LED 1" } }; +28 +29/* Define GPIOs for BUTTONS +30 * FIXME: Change the numbers for the GPIO on your board. +31 */ +32static struct gpio buttons[] = { +33 { 17, GPIOF_IN, "LED 1 ON BUTTON" }, +34 { 18, GPIOF_IN, "LED 1 OFF BUTTON" }, +35}; +36 +37/* This happens immediately, when the IRQ is triggered */ +38static irqreturn_t button_top_half(int irq, void *ident) +39{ +40 return IRQ_WAKE_THREAD; +41} +42 +43/* This can happen at leisure, freeing up IRQs for other high priority task */ +44static irqreturn_t button_bottom_half(int irq, void *ident) +45{ +46 pr_info("Bottom half task starts\n"); +47 mdelay(500); /* do something which takes a while */ +48 pr_info("Bottom half task ends\n"); +49 return IRQ_HANDLED; +50} +51 +52static int __init bottomhalf_init(void) +53{ +54 int ret = 0; 55 -56 if (ret) { -57 pr_err("Unable to request GPIOs for LEDs: %d\n", ret); -58 return ret; -59 } -60 -61 /* register BUTTON gpios */ -62 ret = gpio_request_array(buttons, ARRAY_SIZE(buttons)); -63 -64 if (ret) { -65 pr_err("Unable to request GPIOs for BUTTONs: %d\n", ret); -66 goto fail1; -67 } -68 -69 pr_info("Current button1 value: %d\n", gpio_get_value(buttons[0].gpio)); -70 -71 ret = gpio_to_irq(buttons[0].gpio); -72 -73 if (ret < 0) { -74 pr_err("Unable to request IRQ: %d\n", ret); -75 goto fail2; -76 } -77 -78 button_irqs[0] = ret; -79 -80 pr_info("Successfully requested BUTTON1 IRQ # %d\n", button_irqs[0]); -81 -82 ret = request_threaded_irq(button_irqs[0], button_top_half, -83 button_bottom_half, -84 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, -85 "gpiomod#button1", &buttons[0]); -86 -87 if (ret) { -88 pr_err("Unable to request IRQ: %d\n", ret); -89 goto fail2; -90 } -91 -92 ret = gpio_to_irq(buttons[1].gpio); +56 pr_info("%s\n", __func__); +57 +58/* register LED gpios */ +59#ifdef NO_GPIO_REQUEST_ARRAY +60 ret = gpio_request(leds[0].gpio, leds[0].label); +61#else +62 ret = gpio_request_array(leds, ARRAY_SIZE(leds)); +63#endif +64 +65 if (ret) { +66 pr_err("Unable to request GPIOs for LEDs: %d\n", ret); +67 return ret; +68 } +69 +70/* register BUTTON gpios */ +71#ifdef NO_GPIO_REQUEST_ARRAY +72 ret = gpio_request(buttons[0].gpio, buttons[0].label); +73 +74 if (ret) { +75 pr_err("Unable to request GPIOs for BUTTONs: %d\n", ret); +76 goto fail1; +77 } +78 +79 ret = gpio_request(buttons[1].gpio, buttons[1].label); +80 +81 if (ret) { +82 pr_err("Unable to request GPIOs for BUTTONs: %d\n", ret); +83 goto fail2; +84 } +85#else +86 ret = gpio_request_array(buttons, ARRAY_SIZE(buttons)); +87 +88 if (ret) { +89 pr_err("Unable to request GPIOs for BUTTONs: %d\n", ret); +90 goto fail1; +91 } +92#endif 93 -94 if (ret < 0) { -95 pr_err("Unable to request IRQ: %d\n", ret); -96 goto fail2; -97 } -98 -99 button_irqs[1] = ret; -100 -101 pr_info("Successfully requested BUTTON2 IRQ # %d\n", button_irqs[1]); -102 -103 ret = request_threaded_irq(button_irqs[1], button_top_half, -104 button_bottom_half, -105 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, -106 "gpiomod#button2", &buttons[1]); -107 -108 if (ret) { -109 pr_err("Unable to request IRQ: %d\n", ret); -110 goto fail3; -111 } -112 -113 return 0; -114 -115/* cleanup what has been setup so far */ -116fail3: -117 free_irq(button_irqs[0], NULL); -118 -119fail2: -120 gpio_free_array(buttons, ARRAY_SIZE(leds)); -121 -122fail1: -123 gpio_free_array(leds, ARRAY_SIZE(leds)); +94 pr_info("Current button1 value: %d\n", gpio_get_value(buttons[0].gpio)); +95 +96 ret = gpio_to_irq(buttons[0].gpio); +97 +98 if (ret < 0) { +99 pr_err("Unable to request IRQ: %d\n", ret); +100#ifdef NO_GPIO_REQUEST_ARRAY +101 goto fail3; +102#else +103 goto fail2; +104#endif +105 } +106 +107 button_irqs[0] = ret; +108 +109 pr_info("Successfully requested BUTTON1 IRQ # %d\n", button_irqs[0]); +110 +111 ret = request_threaded_irq(button_irqs[0], button_top_half, +112 button_bottom_half, +113 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, +114 "gpiomod#button1", &buttons[0]); +115 +116 if (ret) { +117 pr_err("Unable to request IRQ: %d\n", ret); +118#ifdef NO_GPIO_REQUEST_ARRAY +119 goto fail3; +120#else +121 goto fail2; +122#endif +123 } 124 -125 return ret; -126} -127 -128static void __exit bottomhalf_exit(void) -129{ -130 int i; -131 -132 pr_info("%s\n", __func__); -133 -134 /* free irqs */ -135 free_irq(button_irqs[0], NULL); -136 free_irq(button_irqs[1], NULL); +125 ret = gpio_to_irq(buttons[1].gpio); +126 +127 if (ret < 0) { +128 pr_err("Unable to request IRQ: %d\n", ret); +129#ifdef NO_GPIO_REQUEST_ARRAY +130 goto fail3; +131#else +132 goto fail2; +133#endif +134 } +135 +136 button_irqs[1] = ret; 137 -138 /* turn all LEDs off */ -139 for (i = 0; i < ARRAY_SIZE(leds); i++) -140 gpio_set_value(leds[i].gpio, 0); -141 -142 /* unregister */ -143 gpio_free_array(leds, ARRAY_SIZE(leds)); -144 gpio_free_array(buttons, ARRAY_SIZE(buttons)); -145} -146 -147module_init(bottomhalf_init); -148module_exit(bottomhalf_exit); -149 -150MODULE_LICENSE("GPL"); -151MODULE_DESCRIPTION("Interrupt with top and bottom half");+138 pr_info("Successfully requested BUTTON2 IRQ # %d\n", button_irqs[1]); +139 +140 ret = request_threaded_irq(button_irqs[1], button_top_half, +141 button_bottom_half, +142 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, +143 "gpiomod#button2", &buttons[1]); +144 +145 if (ret) { +146 pr_err("Unable to request IRQ: %d\n", ret); +147#ifdef NO_GPIO_REQUEST_ARRAY +148 goto fail4; +149#else +150 goto fail3; +151#endif +152 } +153 +154 return 0; +155 +156/* cleanup what has been setup so far */ +157#ifdef NO_GPIO_REQUEST_ARRAY +158fail4: +159 free_irq(button_irqs[0], NULL); +160 +161fail3: +162 gpio_free(buttons[1].gpio); +163 +164fail2: +165 gpio_free(buttons[0].gpio); +166 +167fail1: +168 gpio_free(leds[0].gpio); +169#else +170fail3: +171 free_irq(button_irqs[0], NULL); +172 +173fail2: +174 gpio_free_array(buttons, ARRAY_SIZE(leds)); +175 +176fail1: +177 gpio_free_array(leds, ARRAY_SIZE(leds)); +178#endif +179 +180 return ret; +181} +182 +183static void __exit bottomhalf_exit(void) +184{ +185 pr_info("%s\n", __func__); +186 +187 /* free irqs */ +188 free_irq(button_irqs[0], NULL); +189 free_irq(button_irqs[1], NULL); +190 +191/* turn all LEDs off */ +192#ifdef NO_GPIO_REQUEST_ARRAY +193 gpio_set_value(leds[0].gpio, 0); +194#else +195 int i; +196 for (i = 0; i < ARRAY_SIZE(leds); i++) +197 gpio_set_value(leds[i].gpio, 0); +198#endif +199 +200/* unregister */ +201#ifdef NO_GPIO_REQUEST_ARRAY +202 gpio_free(leds[0].gpio); +203 gpio_free(buttons[0].gpio); +204 gpio_free(buttons[1].gpio); +205#else +206 gpio_free_array(leds, ARRAY_SIZE(leds)); +207 gpio_free_array(buttons, ARRAY_SIZE(buttons)); +208#endif +209} +210 +211module_init(bottomhalf_init); +212module_exit(bottomhalf_exit); +213 +214MODULE_LICENSE("GPL"); +215MODULE_DESCRIPTION("Interrupt with top and bottom half");
A threaded IRQ is registered using request_threaded_irq()
. This function only takes one additional parameter than the
request_irq()
@@ -5719,22 +5911,22 @@ development of virtual input drivers. The drivers needs to export a
will add a new device to the list of support virtual input devices.
-
1int init(struct vinput *);-
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 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.
@@ -5745,12 +5937,12 @@ virtual input device.
struct vinput
-
already initialized with an allocated struct input_dev
+
structure is similar to other attribute types we talked about in section 8:
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);
-
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); ++122 if (ret < 0) { +123 pr_err("Unable to request IRQ: %d\n", ret); +124#ifdef NO_GPIO_REQUEST_ARRAY +125 goto fail3; +126#else +127 goto fail2; +128#endif +129 } +130 +131 button_irqs[1] = ret; +132 +133 pr_info("Successfully requested BUTTON2 IRQ # %d\n", button_irqs[1]); +134 +135 ret = request_irq(button_irqs[1], button_isr, +136 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, +137 "gpiomod#button2", NULL); +138 +139 if (ret) { +140 pr_err("Unable to request IRQ: %d\n", ret); +141#ifdef NO_GPIO_REQUEST_ARRAY +142 goto fail4; +143#else +144 goto fail3; +145#endif +146 } +147 +148 return 0; +149 +150/* cleanup what has been setup so far */ +151#ifdef NO_GPIO_REQUEST_ARRAY +152fail4: +153 free_irq(button_irqs[0], NULL); +154 +155fail3: +156 gpio_free(buttons[1].gpio); +157 +158fail2: +159 gpio_free(buttons[0].gpio); +160 +161fail1: +162 gpio_free(leds[0].gpio); +163#else +164fail3: +165 free_irq(button_irqs[0], NULL); +166 +167fail2: +168 gpio_free_array(buttons, ARRAY_SIZE(leds)); +169 +170fail1: +171 gpio_free_array(leds, ARRAY_SIZE(leds)); +172#endif +173 +174 return ret; +175} +176 +177static void __exit intrpt_exit(void) +178{ +179 pr_info("%s\n", __func__); +180 +181 /* free irqs */ +182 free_irq(button_irqs[0], NULL); +183 free_irq(button_irqs[1], NULL); +184 +185 /* turn all LEDs off */ +186#ifdef NO_GPIO_REQUEST_ARRAY +187 gpio_set_value(leds[0].gpio, 0); +188#else +189 int i; +190 for (i = 0; i < ARRAY_SIZE(leds); i++) +191 gpio_set_value(leds[i].gpio, 0); +192#endif +193 +194 /* unregister */ +195#ifdef NO_GPIO_REQUEST_ARRAY +196 gpio_free(leds[0].gpio); +197 gpio_free(buttons[0].gpio); +198 gpio_free(buttons[1].gpio); +199#else +200 gpio_free_array(leds, ARRAY_SIZE(leds)); +201 gpio_free_array(buttons, ARRAY_SIZE(buttons)); +202#endif +203} +204 +205module_init(intrpt_init); +206module_exit(intrpt_exit); +207 +208MODULE_LICENSE("GPL"); +209MODULE_DESCRIPTION("Handle some GPIO interrupts");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};@@ -5761,227 +5953,227 @@ will generate theclass_attribute
structures which are named class_attr_export/unexport. Then, put them intovinput_class_attrs
array and the macroATTRIBUTE_GROUPS(vinput_class) -
will generate thestruct attribute_group vinput_class_group +
will generate thestruct attribute_group vinput_class_group
that should be assigned invinput_class
. Finally, callclass_register(&vinput_class)
to create attributes in sysfs.To create a vinputX sysfs entry and /dev node.
-
1echo "vkbd" | sudo tee /sys/class/vinput/export+1echo "vkbd" | sudo tee /sys/class/vinput/exportTo unexport the device, just echo its id in unexport:
-
1echo "0" | sudo tee /sys/class/vinput/unexport+1echo "0" | sudo tee /sys/class/vinput/unexport-
1/* -2 * vinput.h -3 */ +1/* +2 * vinput.h +3 */ 4 -5#ifndef VINPUT_H -6#define VINPUT_H +5#ifndef VINPUT_H +6#define VINPUT_H 7 -8#include <linux/input.h> -9#include <linux/spinlock.h> +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 +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) +15#define dev_to_vinput(dev) container_of(dev, struct vinput, dev) 16 -17struct vinput_device; +17struct vinput_device; 18 -19struct vinput { -20 long id; -21 long devno; -22 long last_entry; +19struct vinput { +20 long id; +21 long devno; +22 long last_entry; 23 spinlock_t lock; 24 -25 void *priv_data; +25 void *priv_data; 26 -27 struct device dev; -28 struct list_head list; -29 struct input_dev *input; -30 struct vinput_device *type; +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); +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; +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); +46int vinput_register(struct vinput_device *dev); +47void vinput_unregister(struct vinput_device *dev); 48 -49#endif+49#endif-
1/* -2 * vinput.c -3 */ +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#include <linux/version.h> +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#include <linux/version.h> 11 -12#include <asm/uaccess.h> +12#include <asm/uaccess.h> 13 -14#include "vinput.h" +14#include "vinput.h" 15 -16#define DRIVER_NAME "vinput" +16#define DRIVER_NAME "vinput" 17 -18#define dev_to_vinput(dev) container_of(dev, struct vinput, dev) +18#define dev_to_vinput(dev) container_of(dev, struct vinput, dev) 19 -20static DECLARE_BITMAP(vinput_ids, VINPUT_MINORS); +20static DECLARE_BITMAP(vinput_ids, VINPUT_MINORS); 21 -22static LIST_HEAD(vinput_devices); -23static LIST_HEAD(vinput_vdevices); +22static LIST_HEAD(vinput_devices); +23static LIST_HEAD(vinput_vdevices); 24 -25static int vinput_dev; -26static struct spinlock vinput_lock; -27static struct class vinput_class; +25static int vinput_dev; +26static struct spinlock vinput_lock; +27static struct class vinput_class; 28 -29/* Search the name of vinput device in the vinput_devices linked list, -30 * which added at vinput_register(). -31 */ -32static struct vinput_device *vinput_get_device_by_type(const char *type) +29/* Search the name of vinput device in the vinput_devices linked list, +30 * which added at vinput_register(). +31 */ +32static struct vinput_device *vinput_get_device_by_type(const char *type) 33{ -34 int found = 0; -35 struct vinput_device *vinput; -36 struct list_head *curr; +34 int found = 0; +35 struct vinput_device *vinput; +36 struct list_head *curr; 37 38 spin_lock(&vinput_lock); 39 list_for_each (curr, &vinput_devices) { -40 vinput = list_entry(curr, struct vinput_device, list); -41 if (vinput && strncmp(type, vinput->name, strlen(vinput->name)) == 0) { +40 vinput = list_entry(curr, struct vinput_device, list); +41 if (vinput && strncmp(type, vinput->name, strlen(vinput->name)) == 0) { 42 found = 1; -43 break; +43 break; 44 } 45 } 46 spin_unlock(&vinput_lock); 47 -48 if (found) -49 return vinput; -50 return ERR_PTR(-ENODEV); +48 if (found) +49 return vinput; +50 return ERR_PTR(-ENODEV); 51} 52 -53/* Search the id of virtual device in the vinput_vdevices linked list, -54 * which added at vinput_alloc_vdevice(). -55 */ -56static struct vinput *vinput_get_vdevice_by_id(long id) +53/* Search the id of virtual device in the vinput_vdevices linked list, +54 * which added at vinput_alloc_vdevice(). +55 */ +56static struct vinput *vinput_get_vdevice_by_id(long id) 57{ -58 struct vinput *vinput = NULL; -59 struct list_head *curr; +58 struct vinput *vinput = NULL; +59 struct list_head *curr; 60 61 spin_lock(&vinput_lock); 62 list_for_each (curr, &vinput_vdevices) { -63 vinput = list_entry(curr, struct vinput, list); -64 if (vinput && vinput->id == id) -65 break; +63 vinput = list_entry(curr, struct vinput, list); +64 if (vinput && vinput->id == id) +65 break; 66 } 67 spin_unlock(&vinput_lock); 68 -69 if (vinput && vinput->id == id) -70 return vinput; -71 return ERR_PTR(-ENODEV); +69 if (vinput && vinput->id == id) +70 return vinput; +71 return ERR_PTR(-ENODEV); 72} 73 -74static int vinput_open(struct inode *inode, struct file *file) +74static int vinput_open(struct inode *inode, struct file *file) 75{ -76 int err = 0; -77 struct vinput *vinput = NULL; +76 int err = 0; +77 struct vinput *vinput = NULL; 78 79 vinput = vinput_get_vdevice_by_id(iminor(inode)); 80 -81 if (IS_ERR(vinput)) +81 if (IS_ERR(vinput)) 82 err = PTR_ERR(vinput); -83 else +83 else 84 file->private_data = vinput; 85 -86 return err; +86 return err; 87} 88 -89static int vinput_release(struct inode *inode, struct file *file) +89static int vinput_release(struct inode *inode, struct file *file) 90{ -91 return 0; +91 return 0; 92} 93 -94static ssize_t vinput_read(struct file *file, char __user *buffer, size_t count, +94static ssize_t vinput_read(struct file *file, char __user *buffer, size_t count, 95 loff_t *offset) 96{ -97 int len; -98 char buff[VINPUT_MAX_LEN + 1]; -99 struct vinput *vinput = file->private_data; +97 int len; +98 char buff[VINPUT_MAX_LEN + 1]; +99 struct vinput *vinput = file->private_data; 100 101 len = vinput->type->ops->read(vinput, buff, count); 102 -103 if (*offset > len) +103 if (*offset > len) 104 count = 0; -105 else if (count + *offset > VINPUT_MAX_LEN) +105 else if (count + *offset > VINPUT_MAX_LEN) 106 count = len - *offset; 107 -108 if (raw_copy_to_user(buffer, buff + *offset, count)) -109 return -EFAULT; +108 if (raw_copy_to_user(buffer, buff + *offset, count)) +109 return -EFAULT; 110 111 *offset += count; 112 -113 return count; +113 return count; 114} 115 -116static ssize_t vinput_write(struct file *file, const char __user *buffer, -117 size_t count, loff_t *offset) +116static ssize_t vinput_write(struct file *file, const char __user *buffer, +117 size_t count, loff_t *offset) 118{ -119 char buff[VINPUT_MAX_LEN + 1]; -120 struct vinput *vinput = file->private_data; +119 char buff[VINPUT_MAX_LEN + 1]; +120 struct vinput *vinput = file->private_data; 121 -122 memset(buff, 0, sizeof(char) * (VINPUT_MAX_LEN + 1)); +122 memset(buff, 0, sizeof(char) * (VINPUT_MAX_LEN + 1)); 123 -124 if (count > VINPUT_MAX_LEN) { -125 dev_warn(&vinput->dev, "Too long. %d bytes allowed\n", VINPUT_MAX_LEN); -126 return -EINVAL; +124 if (count > VINPUT_MAX_LEN) { +125 dev_warn(&vinput->dev, "Too long. %d bytes allowed\n", VINPUT_MAX_LEN); +126 return -EINVAL; 127 } 128 -129 if (raw_copy_from_user(buff, buffer, count)) -130 return -EFAULT; +129 if (raw_copy_from_user(buff, buffer, count)) +130 return -EFAULT; 131 -132 return vinput->type->ops->send(vinput, buff, count); +132 return vinput->type->ops->send(vinput, buff, count); 133} 134 -135static const struct file_operations vinput_fops = { -136#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) +135static const struct file_operations vinput_fops = { +136#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) 137 .owner = THIS_MODULE, -138#endif +138#endif 139 .open = vinput_open, 140 .release = vinput_release, 141 .read = vinput_read, 142 .write = vinput_write, 143}; 144 -145static void vinput_unregister_vdevice(struct vinput *vinput) +145static void vinput_unregister_vdevice(struct vinput *vinput) 146{ 147 input_unregister_device(vinput->input); -148 if (vinput->type->ops->kill) +148 if (vinput->type->ops->kill) 149 vinput->type->ops->kill(vinput); 150} 151 -152static void vinput_destroy_vdevice(struct vinput *vinput) +152static void vinput_destroy_vdevice(struct vinput *vinput) 153{ -154 /* Remove from the list first */ +154 /* Remove from the list first */ 155 spin_lock(&vinput_lock); 156 list_del(&vinput->list); 157 clear_bit(vinput->id, vinput_ids); @@ -5992,24 +6184,24 @@ will generate the+424MODULE_LICENSE("GPL"); +425MODULE_DESCRIPTION("Emulate input events");class_attribute 162 kfree(vinput); 163} 164 -165static void vinput_release_dev(struct device *dev) +165static void vinput_release_dev(struct device *dev) 166{ -167 struct vinput *vinput = dev_to_vinput(dev); -168 int id = vinput->id; +167 struct vinput *vinput = dev_to_vinput(dev); +168 int id = vinput->id; 169 170 vinput_destroy_vdevice(vinput); 171 -172 pr_debug("released vinput%d.\n", id); +172 pr_debug("released vinput%d.\n", id); 173} 174 -175static struct vinput *vinput_alloc_vdevice(void) +175static struct vinput *vinput_alloc_vdevice(void) 176{ -177 int err; -178 struct vinput *vinput = kzalloc(sizeof(struct vinput), GFP_KERNEL); +177 int err; +178 struct vinput *vinput = kzalloc(sizeof(struct vinput), GFP_KERNEL); 179 -180 if (!vinput) { -181 pr_err("vinput: Cannot allocate vinput input device\n"); -182 return ERR_PTR(-ENOMEM); +180 if (!vinput) { +181 pr_err("vinput: Cannot allocate vinput input device\n"); +182 return ERR_PTR(-ENOMEM); 183 } 184 185 try_module_get(THIS_MODULE); @@ -6018,29 +6210,29 @@ will generate the
class_attribute 188 189 spin_lock(&vinput_lock); 190 vinput->id = find_first_zero_bit(vinput_ids, VINPUT_MINORS); -191 if (vinput->id >= VINPUT_MINORS) { +191 if (vinput->id >= VINPUT_MINORS) { 192 err = -ENOBUFS; -193 goto fail_id; +193 goto fail_id; 194 } 195 set_bit(vinput->id, vinput_ids); 196 list_add(&vinput->list, &vinput_vdevices); 197 spin_unlock(&vinput_lock); 198 -199 /* allocate the input device */ +199 /* allocate the input device */ 200 vinput->input = input_allocate_device(); -201 if (vinput->input == NULL) { -202 pr_err("vinput: Cannot allocate vinput input device\n"); +201 if (vinput->input == NULL) { +202 pr_err("vinput: Cannot allocate vinput input device\n"); 203 err = -ENOMEM; -204 goto fail_input_dev; +204 goto fail_input_dev; 205 } 206 -207 /* initialize device */ +207 /* initialize device */ 208 vinput->dev.class = &vinput_class; 209 vinput->dev.release = vinput_release_dev; 210 vinput->dev.devt = MKDEV(vinput_dev, vinput->id); -211 dev_set_name(&vinput->dev, DRIVER_NAME "%lu", vinput->id); +211 dev_set_name(&vinput->dev, DRIVER_NAME "%lu", vinput->id); 212 -213 return vinput; +213 return vinput; 214 215fail_input_dev: 216 spin_lock(&vinput_lock); @@ -6050,16 +6242,16 @@ will generate the
class_attribute 220 module_put(THIS_MODULE); 221 kfree(vinput); 222 -223 return ERR_PTR(err); +223 return ERR_PTR(err); 224} 225 -226static int vinput_register_vdevice(struct vinput *vinput) +226static int vinput_register_vdevice(struct vinput *vinput) 227{ -228 int err = 0; +228 int err = 0; 229 -230 /* register the input device */ +230 /* register the input device */ 231 vinput->input->name = vinput->type->name; -232 vinput->input->phys = "vinput"; +232 vinput->input->phys = "vinput"; 233 vinput->input->dev.parent = &vinput->dev; 234 235 vinput->input->id.bustype = BUS_VIRTUAL; @@ -6069,180 +6261,180 @@ will generate the
class_attribute 239 240 err = vinput->type->ops->init(vinput); 241 -242 if (err == 0) -243 dev_info(&vinput->dev, "Registered virtual input %s %ld\n", +242 if (err == 0) +243 dev_info(&vinput->dev, "Registered virtual input %s %ld\n", 244 vinput->type->name, vinput->id); 245 -246 return err; +246 return err; 247} 248 -249#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) -250static ssize_t export_store(const struct class *class, -251 const struct class_attribute *attr, -252#else -253static ssize_t export_store(struct class *class, struct class_attribute *attr, -254#endif -255 const char *buf, size_t len) +249#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) +250static ssize_t export_store(const struct class *class, +251 const struct class_attribute *attr, +252#else +253static ssize_t export_store(struct class *class, struct class_attribute *attr, +254#endif +255 const char *buf, size_t len) 256{ -257 int err; -258 struct vinput *vinput; -259 struct vinput_device *device; +257 int err; +258 struct vinput *vinput; +259 struct vinput_device *device; 260 261 device = vinput_get_device_by_type(buf); -262 if (IS_ERR(device)) { -263 pr_info("vinput: This virtual device isn't registered\n"); +262 if (IS_ERR(device)) { +263 pr_info("vinput: This virtual device isn't registered\n"); 264 err = PTR_ERR(device); -265 goto fail; +265 goto fail; 266 } 267 268 vinput = vinput_alloc_vdevice(); -269 if (IS_ERR(vinput)) { +269 if (IS_ERR(vinput)) { 270 err = PTR_ERR(vinput); -271 goto fail; +271 goto fail; 272 } 273 274 vinput->type = device; 275 err = device_register(&vinput->dev); -276 if (err < 0) -277 goto fail_register; +276 if (err < 0) +277 goto fail_register; 278 279 err = vinput_register_vdevice(vinput); -280 if (err < 0) -281 goto fail_register_vinput; +280 if (err < 0) +281 goto fail_register_vinput; 282 -283 return len; +283 return len; 284 285fail_register_vinput: 286 input_free_device(vinput->input); 287 device_unregister(&vinput->dev); -288 /* avoid calling vinput_destroy_vdevice() twice */ -289 return err; +288 /* avoid calling vinput_destroy_vdevice() twice */ +289 return err; 290fail_register: 291 input_free_device(vinput->input); 292 vinput_destroy_vdevice(vinput); 293fail: -294 return err; +294 return err; 295} -296/* This macro generates class_attr_export structure and export_store() */ -297static CLASS_ATTR_WO(export); +296/* This macro generates class_attr_export structure and export_store() */ +297static CLASS_ATTR_WO(export); 298 -299#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) -300static ssize_t unexport_store(const struct class *class, -301 const struct class_attribute *attr, -302#else -303static ssize_t unexport_store(struct class *class, struct class_attribute *attr, -304#endif -305 const char *buf, size_t len) +299#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) +300static ssize_t unexport_store(const struct class *class, +301 const struct class_attribute *attr, +302#else +303static ssize_t unexport_store(struct class *class, struct class_attribute *attr, +304#endif +305 const char *buf, size_t len) 306{ -307 int err; -308 unsigned long id; -309 struct vinput *vinput; +307 int err; +308 unsigned long id; +309 struct vinput *vinput; 310 311 err = kstrtol(buf, 10, &id); -312 if (err) { +312 if (err) { 313 err = -EINVAL; -314 goto failed; +314 goto failed; 315 } 316 317 vinput = vinput_get_vdevice_by_id(id); -318 if (IS_ERR(vinput)) { -319 pr_err("vinput: No such vinput device %ld\n", id); +318 if (IS_ERR(vinput)) { +319 pr_err("vinput: No such vinput device %ld\n", id); 320 err = PTR_ERR(vinput); -321 goto failed; +321 goto failed; 322 } 323 324 vinput_unregister_vdevice(vinput); 325 device_unregister(&vinput->dev); 326 -327 return len; +327 return len; 328failed: -329 return err; +329 return err; 330} -331/* This macro generates class_attr_unexport structure and unexport_store() */ -332static CLASS_ATTR_WO(unexport); +331/* This macro generates class_attr_unexport structure and unexport_store() */ +332static CLASS_ATTR_WO(unexport); 333 -334static struct attribute *vinput_class_attrs[] = { +334static struct attribute *vinput_class_attrs[] = { 335 &class_attr_export.attr, 336 &class_attr_unexport.attr, 337 NULL, 338}; 339 -340/* This macro generates vinput_class_groups structure */ +340/* This macro generates vinput_class_groups structure */ 341ATTRIBUTE_GROUPS(vinput_class); 342 -343static struct class vinput_class = { -344 .name = "vinput", -345#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) +343static struct class vinput_class = { +344 .name = "vinput", +345#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) 346 .owner = THIS_MODULE, -347#endif +347#endif 348 .class_groups = vinput_class_groups, 349}; 350 -351int vinput_register(struct vinput_device *dev) +351int vinput_register(struct vinput_device *dev) 352{ 353 spin_lock(&vinput_lock); 354 list_add(&dev->list, &vinput_devices); 355 spin_unlock(&vinput_lock); 356 -357 pr_info("vinput: registered new virtual input device '%s'\n", dev->name); +357 pr_info("vinput: registered new virtual input device '%s'\n", dev->name); 358 -359 return 0; +359 return 0; 360} 361EXPORT_SYMBOL(vinput_register); 362 -363void vinput_unregister(struct vinput_device *dev) +363void vinput_unregister(struct vinput_device *dev) 364{ -365 struct list_head *curr, *next; +365 struct list_head *curr, *next; 366 -367 /* Remove from the list first */ +367 /* Remove from the list first */ 368 spin_lock(&vinput_lock); 369 list_del(&dev->list); 370 spin_unlock(&vinput_lock); 371 -372 /* unregister all devices of this type */ +372 /* unregister all devices of this type */ 373 list_for_each_safe (curr, next, &vinput_vdevices) { -374 struct vinput *vinput = list_entry(curr, struct vinput, list); -375 if (vinput && vinput->type == dev) { +374 struct vinput *vinput = list_entry(curr, struct vinput, list); +375 if (vinput && vinput->type == dev) { 376 vinput_unregister_vdevice(vinput); 377 device_unregister(&vinput->dev); 378 } 379 } 380 -381 pr_info("vinput: unregistered virtual input device '%s'\n", dev->name); +381 pr_info("vinput: unregistered virtual input device '%s'\n", dev->name); 382} 383EXPORT_SYMBOL(vinput_unregister); 384 -385static int __init vinput_init(void) +385static int __init vinput_init(void) 386{ -387 int err = 0; +387 int err = 0; 388 -389 pr_info("vinput: Loading virtual input driver\n"); +389 pr_info("vinput: Loading virtual input driver\n"); 390 391 vinput_dev = register_chrdev(0, DRIVER_NAME, &vinput_fops); -392 if (vinput_dev < 0) { -393 pr_err("vinput: Unable to allocate char dev region\n"); +392 if (vinput_dev < 0) { +393 pr_err("vinput: Unable to allocate char dev region\n"); 394 err = vinput_dev; -395 goto failed_alloc; +395 goto failed_alloc; 396 } 397 398 spin_lock_init(&vinput_lock); 399 400 err = class_register(&vinput_class); -401 if (err < 0) { -402 pr_err("vinput: Unable to register vinput class\n"); -403 goto failed_class; +401 if (err < 0) { +402 pr_err("vinput: Unable to register vinput class\n"); +403 goto failed_class; 404 } 405 -406 return 0; +406 return 0; 407failed_class: 408 unregister_chrdev(vinput_dev, DRIVER_NAME); 409failed_alloc: -410 return err; +410 return err; 411} 412 -413static void __exit vinput_end(void) +413static void __exit vinput_end(void) 414{ -415 pr_info("vinput: Unloading virtual input driver\n"); +415 pr_info("vinput: Unloading virtual input driver\n"); 416 417 unregister_chrdev(vinput_dev, DRIVER_NAME); 418 class_unregister(&vinput_class); @@ -6251,8 +6443,8 @@ will generate the
class_attribute 421module_init(vinput_init); 422module_exit(vinput_end); 423 -424MODULE_LICENSE("GPL"); -425MODULE_DESCRIPTION("Emulate input events");
Here the virtual keyboard is one of example to use vinput. It supports all
KEY_MAX
keycodes. The injection format is theKEY_CODE @@ -6265,7 +6457,7 @@ following demonstrates how simulation work.
= 34):-
1echo "+34" | sudo tee /dev/vinput0+1echo "+34" | sudo tee /dev/vinput0Simulate a key release on "g" (
KEY_G
= 34):@@ -6273,111 +6465,111 @@ following demonstrates how simulation work.
-1echo "-34" | sudo tee /dev/vinput0+1echo "-34" | sudo tee /dev/vinput0-
1/* -2 * vkbd.c -3 */ +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> +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" +10#include "vinput.h" 11 -12#define VINPUT_KBD "vkbd" -13#define VINPUT_RELEASE 0 -14#define VINPUT_PRESS 1 +12#define VINPUT_KBD "vkbd" +13#define VINPUT_RELEASE 0 +14#define VINPUT_PRESS 1 15 -16static unsigned short vkeymap[KEY_MAX]; +16static unsigned short vkeymap[KEY_MAX]; 17 -18static int vinput_vkbd_init(struct vinput *vinput) +18static int vinput_vkbd_init(struct vinput *vinput) 19{ -20 int i; +20 int i; 21 -22 /* Set up the input bitfield */ +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); +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++) +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); +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) +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); +40 len = snprintf(buff, len, "%+ld\n", vinput->last_entry); 41 spin_unlock(&vinput->lock); 42 -43 return len; +43 return len; 44} 45 -46static int vinput_vkbd_send(struct vinput *vinput, char *buff, int len) +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; +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] == '+') +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 +57 else 58 ret = kstrtol(buff, 10, &key); -59 if (ret) -60 dev_err(&vinput->dev, "error during kstrtol: -%d\n", ret); +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) { +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); +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. */ +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. */ +75 /* Tell input subsystem that it finished the report. */ 76 input_sync(vinput->input); 77 -78 return len; +78 return len; 79} 80 -81static struct vinput_ops vkbd_ops = { +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 = { +87static struct vinput_device vkbd_dev = { 88 .name = VINPUT_KBD, 89 .ops = &vkbd_ops, 90}; 91 -92static int __init vkbd_init(void) +92static int __init vkbd_init(void) 93{ -94 int i; +94 int i; 95 -96 for (i = 0; i < KEY_MAX; i++) +96 for (i = 0; i < KEY_MAX; i++) 97 vkeymap[i] = i; -98 return vinput_register(&vkbd_dev); +98 return vinput_register(&vkbd_dev); 99} 100 -101static void __exit vkbd_end(void) +101static void __exit vkbd_end(void) 102{ 103 vinput_unregister(&vkbd_dev); 104} @@ -6385,8 +6577,8 @@ following demonstrates how simulation work. 106module_init(vkbd_init); 107module_exit(vkbd_end); 108 -109MODULE_LICENSE("GPL"); -110MODULE_DESCRIPTION("Emulate keyboard input events through /dev/vinput");+109MODULE_LICENSE("GPL"); +110MODULE_DESCRIPTION("Emulate keyboard input events through /dev/vinput");
17 Standardizing the interfaces: The Device Model
@@ -6398,59 +6590,59 @@ use this as a template to add your own suspend, resume or other interface functions.-
1/* -2 * devicemodel.c -3 */ -4#include <linux/kernel.h> -5#include <linux/module.h> -6#include <linux/platform_device.h> +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; +8struct devicemodel_data { +9 char *greeting; +10 int number; 11}; 12 -13static int devicemodel_probe(struct platform_device *dev) +13static int devicemodel_probe(struct platform_device *dev) 14{ -15 struct devicemodel_data *pd = -16 (struct devicemodel_data *)(dev->dev.platform_data); +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); +18 pr_info("devicemodel probe\n"); +19 pr_info("devicemodel greeting: %s; %d\n", pd->greeting, pd->number); 20 -21 /* Your device initialization code */ +21 /* Your device initialization code */ 22 -23 return 0; +23 return 0; 24} 25 -26static int devicemodel_remove(struct platform_device *dev) +26static int devicemodel_remove(struct platform_device *dev) 27{ -28 pr_info("devicemodel example removed\n"); +28 pr_info("devicemodel example removed\n"); 29 -30 /* Your device removal code */ +30 /* Your device removal code */ 31 -32 return 0; +32 return 0; 33} 34 -35static int devicemodel_suspend(struct device *dev) +35static int devicemodel_suspend(struct device *dev) 36{ -37 pr_info("devicemodel example suspend\n"); +37 pr_info("devicemodel example suspend\n"); 38 -39 /* Your device suspend code */ +39 /* Your device suspend code */ 40 -41 return 0; +41 return 0; 42} 43 -44static int devicemodel_resume(struct device *dev) +44static int devicemodel_resume(struct device *dev) 45{ -46 pr_info("devicemodel example resume\n"); +46 pr_info("devicemodel example resume\n"); 47 -48 /* Your device resume code */ +48 /* Your device resume code */ 49 -50 return 0; +50 return 0; 51} 52 -53static const struct dev_pm_ops devicemodel_pm_ops = { +53static const struct dev_pm_ops devicemodel_pm_ops = { 54 .suspend = devicemodel_suspend, 55 .resume = devicemodel_resume, 56 .poweroff = devicemodel_suspend, @@ -6459,43 +6651,43 @@ functions. 59 .restore = devicemodel_resume, 60}; 61 -62static struct platform_driver devicemodel_driver = { +62static struct platform_driver devicemodel_driver = { 63 .driver = 64 { -65 .name = "devicemodel_example", +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) +72static int __init devicemodel_init(void) 73{ -74 int ret; +74 int ret; 75 -76 pr_info("devicemodel init\n"); +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; +80 if (ret) { +81 pr_err("Unable to register driver\n"); +82 return ret; 83 } 84 -85 return 0; +85 return 0; 86} 87 -88static void __exit devicemodel_exit(void) +88static void __exit devicemodel_exit(void) 89{ -90 pr_info("devicemodel exit\n"); +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");+97MODULE_LICENSE("GPL"); +98MODULE_DESCRIPTION("Linux Device Model example");
18 Optimizations
@@ -6519,10 +6711,10 @@ to succeed.1bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx); -2if (unlikely(!bvl)) { +2if (unlikely(!bvl)) { 3 mempool_free(bio, bio_pool); 4 bio = NULL; -5 goto out; +5 goto out; 6}When the
unlikely
macro is used, the compiler alters its machine instruction output, so that it @@ -6540,7 +6732,7 @@ prediction. The most typical use case of static keys is for performance-sensitiv 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 -asm goto +
asm goto
inline assembly, and the following kernel configurations are set:@@ -6563,10 +6755,10 @@ no-op instruction will be generated at compile time as the key is initialized to and the branch is unlikely to be taken.
-
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");@@ -6579,159 +6771,159 @@ codepr_alert static key works.
-
1/* -2 * static_key.c -3 */ +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#include <linux/version.h> +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#include <linux/version.h> 15 -16#include <asm/errno.h> +16#include <asm/errno.h> 17 -18static int device_open(struct inode *inode, struct file *file); -19static int device_release(struct inode *inode, struct file *file); -20static ssize_t device_read(struct file *file, char __user *buf, size_t count, +18static int device_open(struct inode *inode, struct file *file); +19static int device_release(struct inode *inode, struct file *file); +20static ssize_t device_read(struct file *file, char __user *buf, size_t count, 21 loff_t *ppos); -22static ssize_t device_write(struct file *file, const char __user *buf, -23 size_t count, loff_t *ppos); +22static ssize_t device_write(struct file *file, const char __user *buf, +23 size_t count, loff_t *ppos); 24 -25#define SUCCESS 0 -26#define DEVICE_NAME "key_state" -27#define BUF_LEN 10 +25#define SUCCESS 0 +26#define DEVICE_NAME "key_state" +27#define BUF_LEN 10 28 -29static int major; +29static int major; 30 -31enum { +31enum { 32 CDEV_NOT_USED, 33 CDEV_EXCLUSIVE_OPEN, 34}; 35 -36static atomic_t already_open = ATOMIC_INIT(CDEV_NOT_USED); +36static atomic_t already_open = ATOMIC_INIT(CDEV_NOT_USED); 37 -38static char msg[BUF_LEN + 1]; +38static char msg[BUF_LEN + 1]; 39 -40static struct class *cls; +40static struct class *cls; 41 -42static DEFINE_STATIC_KEY_FALSE(fkey); +42static DEFINE_STATIC_KEY_FALSE(fkey); 43 -44static struct file_operations chardev_fops = { -45#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) +44static struct file_operations chardev_fops = { +45#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) 46 .owner = THIS_MODULE, -47#endif +47#endif 48 .open = device_open, 49 .release = device_release, 50 .read = device_read, 51 .write = device_write, 52}; 53 -54static int __init chardev_init(void) +54static int __init chardev_init(void) 55{ 56 major = register_chrdev(0, DEVICE_NAME, &chardev_fops); -57 if (major < 0) { -58 pr_alert("Registering char device failed with %d\n", major); -59 return major; +57 if (major < 0) { +58 pr_alert("Registering char device failed with %d\n", major); +59 return major; 60 } 61 -62 pr_info("I was assigned major number %d\n", major); +62 pr_info("I was assigned major number %d\n", major); 63 -64#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) +64#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) 65 cls = class_create(THIS_MODULE, DEVICE_NAME); -66#else +66#else 67 cls = class_create(DEVICE_NAME); -68#endif +68#endif 69 70 device_create(cls, NULL, MKDEV(major, 0), NULL, DEVICE_NAME); 71 -72 pr_info("Device created on /dev/%s\n", DEVICE_NAME); +72 pr_info("Device created on /dev/%s\n", DEVICE_NAME); 73 -74 return SUCCESS; +74 return SUCCESS; 75} 76 -77static void __exit chardev_exit(void) +77static void __exit chardev_exit(void) 78{ 79 device_destroy(cls, MKDEV(major, 0)); 80 class_destroy(cls); 81 -82 /* Unregister the device */ +82 /* Unregister the device */ 83 unregister_chrdev(major, DEVICE_NAME); 84} 85 -86/* Methods */ +86/* Methods */ 87 -88/** -89 * Called when a process tried to open the device file, like -90 * cat /dev/key_state -91 */ -92static int device_open(struct inode *inode, struct file *file) +88/** +89 * Called when a process tried to open the device file, like +90 * cat /dev/key_state +91 */ +92static int device_open(struct inode *inode, struct file *file) 93{ -94 if (atomic_cmpxchg(&already_open, CDEV_NOT_USED, CDEV_EXCLUSIVE_OPEN)) -95 return -EBUSY; +94 if (atomic_cmpxchg(&already_open, CDEV_NOT_USED, CDEV_EXCLUSIVE_OPEN)) +95 return -EBUSY; 96 -97 sprintf(msg, static_key_enabled(&fkey) ? "enabled\n" : "disabled\n"); +97 sprintf(msg, static_key_enabled(&fkey) ? "enabled\n" : "disabled\n"); 98 -99 pr_info("fastpath 1\n"); -100 if (static_branch_unlikely(&fkey)) -101 pr_alert("do unlikely thing\n"); -102 pr_info("fastpath 2\n"); +99 pr_info("fastpath 1\n"); +100 if (static_branch_unlikely(&fkey)) +101 pr_alert("do unlikely thing\n"); +102 pr_info("fastpath 2\n"); 103 104 try_module_get(THIS_MODULE); 105 -106 return SUCCESS; +106 return SUCCESS; 107} 108 -109/** -110 * Called when a process closes the device file -111 */ -112static int device_release(struct inode *inode, struct file *file) +109/** +110 * Called when a process closes the device file +111 */ +112static int device_release(struct inode *inode, struct file *file) 113{ -114 /* We are now ready for our next caller. */ +114 /* We are now ready for our next caller. */ 115 atomic_set(&already_open, CDEV_NOT_USED); 116 -117 /** -118 * Decrement the usage count, or else once you opened the file, you will -119 * never get rid of the module. -120 */ +117 /** +118 * Decrement the usage count, or else once you opened the file, you will +119 * never get rid of the module. +120 */ 121 module_put(THIS_MODULE); 122 -123 return SUCCESS; +123 return SUCCESS; 124} 125 -126/** -127 * Called when a process, which already opened the dev file, attempts to -128 * read from it. -129 */ -130static ssize_t device_read(struct file *filp, /* see include/linux/fs.h */ -131 char __user *buffer, /* buffer to fill with data */ -132 size_t length, /* length of the buffer */ +126/** +127 * Called when a process, which already opened the dev file, attempts to +128 * read from it. +129 */ +130static ssize_t device_read(struct file *filp, /* see include/linux/fs.h */ +131 char __user *buffer, /* buffer to fill with data */ +132 size_t length, /* length of the buffer */ 133 loff_t *offset) 134{ -135 /* Number of the bytes actually written to the buffer */ -136 int bytes_read = 0; -137 const char *msg_ptr = msg; +135 /* Number of the bytes actually written to the buffer */ +136 int bytes_read = 0; +137 const char *msg_ptr = msg; 138 -139 if (!*(msg_ptr + *offset)) { /* We are at the end of the message */ -140 *offset = 0; /* reset the offset */ -141 return 0; /* signify end of file */ +139 if (!*(msg_ptr + *offset)) { /* We are at the end of the message */ +140 *offset = 0; /* reset the offset */ +141 return 0; /* signify end of file */ 142 } 143 144 msg_ptr += *offset; 145 -146 /* Actually put the data into the buffer */ -147 while (length && *msg_ptr) { -148 /** -149 * The buffer is in the user data segment, not the kernel -150 * segment so "*" assignment won't work. We have to use -151 * put_user which copies data from the kernel data segment to -152 * the user data segment. -153 */ +146 /* Actually put the data into the buffer */ +147 while (length && *msg_ptr) { +148 /** +149 * The buffer is in the user data segment, not the kernel +150 * segment so "*" assignment won't work. We have to use +151 * put_user which copies data from the kernel data segment to +152 * the user data segment. +153 */ 154 put_user(*(msg_ptr++), buffer++); 155 length--; 156 bytes_read++; @@ -6739,41 +6931,41 @@ static key works. 158 159 *offset += bytes_read; 160 -161 /* Most read functions return the number of bytes put into the buffer. */ -162 return bytes_read; +161 /* Most read functions return the number of bytes put into the buffer. */ +162 return bytes_read; 163} 164 -165/* Called when a process writes to dev file; echo "enable" > /dev/key_state */ -166static ssize_t device_write(struct file *filp, const char __user *buffer, -167 size_t length, loff_t *offset) +165/* Called when a process writes to dev file; echo "enable" > /dev/key_state */ +166static ssize_t device_write(struct file *filp, const char __user *buffer, +167 size_t length, loff_t *offset) 168{ -169 char command[10]; +169 char command[10]; 170 -171 if (length > 10) { -172 pr_err("command exceeded 10 char\n"); -173 return -EINVAL; +171 if (length > 10) { +172 pr_err("command exceeded 10 char\n"); +173 return -EINVAL; 174 } 175 -176 if (copy_from_user(command, buffer, length)) -177 return -EFAULT; +176 if (copy_from_user(command, buffer, length)) +177 return -EFAULT; 178 -179 if (strncmp(command, "enable", strlen("enable")) == 0) +179 if (strncmp(command, "enable", strlen("enable")) == 0) 180 static_branch_enable(&fkey); -181 else if (strncmp(command, "disable", strlen("disable")) == 0) +181 else if (strncmp(command, "disable", strlen("disable")) == 0) 182 static_branch_disable(&fkey); -183 else { -184 pr_err("Invalid command: %s\n", command); -185 return -EINVAL; +183 else { +184 pr_err("Invalid command: %s\n", command); +185 return -EINVAL; 186 } 187 -188 /* Again, return the number of input characters used. */ -189 return length; +188 /* Again, return the number of input characters used. */ +189 return length; 190} 191 192module_init(chardev_init); 193module_exit(chardev_exit); 194 -195MODULE_LICENSE("GPL");+195MODULE_LICENSE("GPL");To check the state of the static key, we can use the /dev/key_state interface.
diff --git a/lkmpg-for-ht.css b/lkmpg-for-ht.css index d00784d..197b071 100644 --- a/lkmpg-for-ht.css +++ b/lkmpg-for-ht.css @@ -3245,937 +3245,1075 @@ span#textcolor2625{color:rgb(0,127,0)} span#textcolor2626{color:rgb(0,0,255)} span#textcolor2627{color:rgb(0,127,0)} span#textcolor2628{color:rgb(0,0,255)} -span#textcolor2629{color:rgb(43,145,175)} -span#textcolor2630{color:rgb(0,127,0)} -span#textcolor2631{color:rgb(0,127,0)} -span#textcolor2632{color:rgb(0,127,0)} +span#textcolor2629{color:rgb(0,127,0)} +span#textcolor2630{color:rgb(0,0,255)} +span#textcolor2631{color:rgb(0,0,255)} +span#textcolor2632{color:rgb(0,0,255)} span#textcolor2633{color:rgb(0,0,255)} -span#textcolor2634{color:rgb(0,0,255)} -span#textcolor2635{color:rgb(163,20,20)} +span#textcolor2634{color:rgb(43,145,175)} +span#textcolor2635{color:rgb(0,127,0)} span#textcolor2636{color:rgb(0,127,0)} span#textcolor2637{color:rgb(0,127,0)} -span#textcolor2638{color:rgb(0,127,0)} +span#textcolor2638{color:rgb(0,0,255)} span#textcolor2639{color:rgb(0,0,255)} -span#textcolor2640{color:rgb(0,0,255)} -span#textcolor2641{color:rgb(163,20,20)} -span#textcolor2642{color:rgb(163,20,20)} +span#textcolor2640{color:rgb(163,20,20)} +span#textcolor2641{color:rgb(0,127,0)} +span#textcolor2642{color:rgb(0,127,0)} span#textcolor2643{color:rgb(0,127,0)} span#textcolor2644{color:rgb(0,0,255)} -span#textcolor2645{color:rgb(43,145,175)} -span#textcolor2646{color:rgb(43,145,175)} -span#textcolor2647{color:rgb(0,127,0)} -span#textcolor2648{color:rgb(0,0,255)} -span#textcolor2649{color:rgb(0,127,0)} -span#textcolor2650{color:rgb(0,0,255)} -span#textcolor2651{color:rgb(0,0,255)} -span#textcolor2652{color:rgb(0,0,255)} +span#textcolor2645{color:rgb(0,0,255)} +span#textcolor2646{color:rgb(163,20,20)} +span#textcolor2647{color:rgb(163,20,20)} +span#textcolor2648{color:rgb(0,127,0)} +span#textcolor2649{color:rgb(0,0,255)} +span#textcolor2650{color:rgb(43,145,175)} +span#textcolor2651{color:rgb(43,145,175)} +span#textcolor2652{color:rgb(0,127,0)} span#textcolor2653{color:rgb(0,0,255)} -span#textcolor2654{color:rgb(43,145,175)} -span#textcolor2655{color:rgb(43,145,175)} -span#textcolor2656{color:rgb(43,145,175)} -span#textcolor2657{color:rgb(163,20,20)} -span#textcolor2658{color:rgb(163,20,20)} -span#textcolor2659{color:rgb(163,20,20)} -span#textcolor2660{color:rgb(0,127,0)} -span#textcolor2661{color:rgb(0,0,255)} +span#textcolor2654{color:rgb(0,127,0)} +span#textcolor2655{color:rgb(0,0,255)} +span#textcolor2656{color:rgb(0,0,255)} +span#textcolor2657{color:rgb(0,0,255)} +span#textcolor2658{color:rgb(0,0,255)} +span#textcolor2659{color:rgb(43,145,175)} +span#textcolor2660{color:rgb(43,145,175)} +span#textcolor2661{color:rgb(43,145,175)} span#textcolor2662{color:rgb(163,20,20)} span#textcolor2663{color:rgb(163,20,20)} span#textcolor2664{color:rgb(163,20,20)} -span#textcolor2665{color:rgb(0,0,255)} -span#textcolor2666{color:rgb(0,127,0)} +span#textcolor2665{color:rgb(0,127,0)} +span#textcolor2666{color:rgb(0,0,255)} span#textcolor2667{color:rgb(0,0,255)} -span#textcolor2668{color:rgb(163,20,20)} -span#textcolor2669{color:rgb(163,20,20)} +span#textcolor2668{color:rgb(0,0,255)} +span#textcolor2669{color:rgb(0,0,255)} span#textcolor2670{color:rgb(163,20,20)} -span#textcolor2671{color:rgb(0,0,255)} +span#textcolor2671{color:rgb(163,20,20)} span#textcolor2672{color:rgb(163,20,20)} -span#textcolor2673{color:rgb(163,20,20)} -span#textcolor2674{color:rgb(163,20,20)} +span#textcolor2673{color:rgb(0,0,255)} +span#textcolor2674{color:rgb(0,127,0)} span#textcolor2675{color:rgb(0,0,255)} -span#textcolor2676{color:rgb(163,20,20)} +span#textcolor2676{color:rgb(0,0,255)} span#textcolor2677{color:rgb(163,20,20)} span#textcolor2678{color:rgb(163,20,20)} -span#textcolor2679{color:rgb(0,0,255)} -span#textcolor2680{color:rgb(163,20,20)} -span#textcolor2681{color:rgb(163,20,20)} +span#textcolor2679{color:rgb(163,20,20)} +span#textcolor2680{color:rgb(0,0,255)} +span#textcolor2681{color:rgb(0,0,255)} span#textcolor2682{color:rgb(163,20,20)} span#textcolor2683{color:rgb(163,20,20)} -span#textcolor2684{color:rgb(0,0,255)} -span#textcolor2685{color:rgb(163,20,20)} -span#textcolor2686{color:rgb(163,20,20)} -span#textcolor2687{color:rgb(163,20,20)} -span#textcolor2688{color:rgb(0,0,255)} -span#textcolor2689{color:rgb(0,0,255)} +span#textcolor2684{color:rgb(163,20,20)} +span#textcolor2685{color:rgb(0,0,255)} +span#textcolor2686{color:rgb(0,0,255)} +span#textcolor2687{color:rgb(0,0,255)} +span#textcolor2688{color:rgb(163,20,20)} +span#textcolor2689{color:rgb(163,20,20)} span#textcolor2690{color:rgb(163,20,20)} -span#textcolor2691{color:rgb(163,20,20)} -span#textcolor2692{color:rgb(163,20,20)} -span#textcolor2693{color:rgb(0,0,255)} +span#textcolor2691{color:rgb(0,0,255)} +span#textcolor2692{color:rgb(0,0,255)} +span#textcolor2693{color:rgb(163,20,20)} span#textcolor2694{color:rgb(163,20,20)} span#textcolor2695{color:rgb(163,20,20)} -span#textcolor2696{color:rgb(163,20,20)} +span#textcolor2696{color:rgb(0,0,255)} span#textcolor2697{color:rgb(163,20,20)} -span#textcolor2698{color:rgb(0,0,255)} +span#textcolor2698{color:rgb(163,20,20)} span#textcolor2699{color:rgb(163,20,20)} -span#textcolor2700{color:rgb(163,20,20)} -span#textcolor2701{color:rgb(163,20,20)} +span#textcolor2700{color:rgb(0,0,255)} +span#textcolor2701{color:rgb(0,0,255)} span#textcolor2702{color:rgb(0,0,255)} span#textcolor2703{color:rgb(0,0,255)} -span#textcolor2704{color:rgb(0,127,0)} -span#textcolor2705{color:rgb(0,0,255)} -span#textcolor2706{color:rgb(0,0,255)} -span#textcolor2707{color:rgb(43,145,175)} -span#textcolor2708{color:rgb(43,145,175)} -span#textcolor2709{color:rgb(43,145,175)} +span#textcolor2704{color:rgb(0,0,255)} +span#textcolor2705{color:rgb(163,20,20)} +span#textcolor2706{color:rgb(163,20,20)} +span#textcolor2707{color:rgb(163,20,20)} +span#textcolor2708{color:rgb(163,20,20)} +span#textcolor2709{color:rgb(0,0,255)} span#textcolor2710{color:rgb(163,20,20)} span#textcolor2711{color:rgb(163,20,20)} span#textcolor2712{color:rgb(163,20,20)} -span#textcolor2713{color:rgb(0,127,0)} -span#textcolor2714{color:rgb(0,127,0)} +span#textcolor2713{color:rgb(0,0,255)} +span#textcolor2714{color:rgb(0,0,255)} span#textcolor2715{color:rgb(0,0,255)} -span#textcolor2716{color:rgb(0,127,0)} -span#textcolor2717{color:rgb(163,20,20)} -span#textcolor2718{color:rgb(163,20,20)} -pre#fancyvrb81{padding:5.69054pt;} -pre#fancyvrb81{ border-top: solid 0.4pt; } -pre#fancyvrb81{ border-left: solid 0.4pt; } -pre#fancyvrb81{ border-bottom: solid 0.4pt; } -pre#fancyvrb81{ border-right: solid 0.4pt; } -span#textcolor2719{color:rgb(0,127,0)} -span#textcolor2720{color:rgb(0,127,0)} -span#textcolor2721{color:rgb(0,127,0)} -span#textcolor2722{color:rgb(0,127,0)} -span#textcolor2723{color:rgb(0,127,0)} -span#textcolor2724{color:rgb(0,127,0)} -span#textcolor2725{color:rgb(0,127,0)} -span#textcolor2726{color:rgb(0,127,0)} -span#textcolor2727{color:rgb(0,127,0)} -span#textcolor2728{color:rgb(0,0,255)} -span#textcolor2729{color:rgb(0,127,0)} -span#textcolor2730{color:rgb(0,0,255)} -span#textcolor2731{color:rgb(0,127,0)} -span#textcolor2732{color:rgb(0,0,255)} -span#textcolor2733{color:rgb(0,127,0)} -span#textcolor2734{color:rgb(0,0,255)} -span#textcolor2735{color:rgb(0,127,0)} +span#textcolor2716{color:rgb(0,0,255)} +span#textcolor2717{color:rgb(0,0,255)} +span#textcolor2718{color:rgb(0,0,255)} +span#textcolor2719{color:rgb(163,20,20)} +span#textcolor2720{color:rgb(163,20,20)} +span#textcolor2721{color:rgb(163,20,20)} +span#textcolor2722{color:rgb(0,0,255)} +span#textcolor2723{color:rgb(0,0,255)} +span#textcolor2724{color:rgb(0,0,255)} +span#textcolor2725{color:rgb(0,0,255)} +span#textcolor2726{color:rgb(0,0,255)} +span#textcolor2727{color:rgb(163,20,20)} +span#textcolor2728{color:rgb(163,20,20)} +span#textcolor2729{color:rgb(163,20,20)} +span#textcolor2730{color:rgb(163,20,20)} +span#textcolor2731{color:rgb(0,0,255)} +span#textcolor2732{color:rgb(163,20,20)} +span#textcolor2733{color:rgb(163,20,20)} +span#textcolor2734{color:rgb(163,20,20)} +span#textcolor2735{color:rgb(0,0,255)} span#textcolor2736{color:rgb(0,0,255)} -span#textcolor2737{color:rgb(0,127,0)} +span#textcolor2737{color:rgb(0,0,255)} span#textcolor2738{color:rgb(0,0,255)} -span#textcolor2739{color:rgb(0,127,0)} -span#textcolor2740{color:rgb(0,127,0)} +span#textcolor2739{color:rgb(0,0,255)} +span#textcolor2740{color:rgb(0,0,255)} span#textcolor2741{color:rgb(0,127,0)} -span#textcolor2742{color:rgb(0,127,0)} +span#textcolor2742{color:rgb(0,0,255)} span#textcolor2743{color:rgb(0,0,255)} span#textcolor2744{color:rgb(0,0,255)} span#textcolor2745{color:rgb(0,0,255)} span#textcolor2746{color:rgb(0,0,255)} span#textcolor2747{color:rgb(43,145,175)} -span#textcolor2748{color:rgb(0,127,0)} -span#textcolor2749{color:rgb(0,127,0)} -span#textcolor2750{color:rgb(0,127,0)} -span#textcolor2751{color:rgb(0,0,255)} -span#textcolor2752{color:rgb(0,0,255)} -span#textcolor2753{color:rgb(163,20,20)} -span#textcolor2754{color:rgb(0,127,0)} -span#textcolor2755{color:rgb(0,127,0)} -span#textcolor2756{color:rgb(0,127,0)} +span#textcolor2748{color:rgb(43,145,175)} +span#textcolor2749{color:rgb(163,20,20)} +span#textcolor2750{color:rgb(163,20,20)} +span#textcolor2751{color:rgb(163,20,20)} +span#textcolor2752{color:rgb(0,127,0)} +span#textcolor2753{color:rgb(0,127,0)} +span#textcolor2754{color:rgb(0,0,255)} +span#textcolor2755{color:rgb(0,0,255)} +span#textcolor2756{color:rgb(43,145,175)} span#textcolor2757{color:rgb(0,0,255)} span#textcolor2758{color:rgb(0,0,255)} -span#textcolor2759{color:rgb(163,20,20)} -span#textcolor2760{color:rgb(163,20,20)} -span#textcolor2761{color:rgb(0,127,0)} +span#textcolor2759{color:rgb(0,127,0)} +span#textcolor2760{color:rgb(0,0,255)} +span#textcolor2761{color:rgb(0,0,255)} span#textcolor2762{color:rgb(0,0,255)} -span#textcolor2763{color:rgb(43,145,175)} -span#textcolor2764{color:rgb(43,145,175)} -span#textcolor2765{color:rgb(43,145,175)} -span#textcolor2766{color:rgb(163,20,20)} -span#textcolor2767{color:rgb(163,20,20)} -span#textcolor2768{color:rgb(163,20,20)} +span#textcolor2763{color:rgb(163,20,20)} +span#textcolor2764{color:rgb(163,20,20)} +pre#fancyvrb81{padding:5.69054pt;} +pre#fancyvrb81{ border-top: solid 0.4pt; } +pre#fancyvrb81{ border-left: solid 0.4pt; } +pre#fancyvrb81{ border-bottom: solid 0.4pt; } +pre#fancyvrb81{ border-right: solid 0.4pt; } +span#textcolor2765{color:rgb(0,127,0)} +span#textcolor2766{color:rgb(0,127,0)} +span#textcolor2767{color:rgb(0,127,0)} +span#textcolor2768{color:rgb(0,127,0)} span#textcolor2769{color:rgb(0,127,0)} -span#textcolor2770{color:rgb(163,20,20)} -span#textcolor2771{color:rgb(163,20,20)} -span#textcolor2772{color:rgb(163,20,20)} -span#textcolor2773{color:rgb(0,0,255)} -span#textcolor2774{color:rgb(0,127,0)} -span#textcolor2775{color:rgb(0,0,255)} -span#textcolor2776{color:rgb(43,145,175)} -span#textcolor2777{color:rgb(43,145,175)} -span#textcolor2778{color:rgb(0,127,0)} -span#textcolor2779{color:rgb(0,0,255)} +span#textcolor2770{color:rgb(0,127,0)} +span#textcolor2771{color:rgb(0,127,0)} +span#textcolor2772{color:rgb(0,127,0)} +span#textcolor2773{color:rgb(0,127,0)} +span#textcolor2774{color:rgb(0,0,255)} +span#textcolor2775{color:rgb(0,127,0)} +span#textcolor2776{color:rgb(0,0,255)} +span#textcolor2777{color:rgb(0,127,0)} +span#textcolor2778{color:rgb(0,0,255)} +span#textcolor2779{color:rgb(0,127,0)} span#textcolor2780{color:rgb(0,0,255)} -span#textcolor2781{color:rgb(0,0,255)} -span#textcolor2782{color:rgb(0,127,0)} -span#textcolor2783{color:rgb(0,0,255)} +span#textcolor2781{color:rgb(0,127,0)} +span#textcolor2782{color:rgb(0,0,255)} +span#textcolor2783{color:rgb(0,127,0)} span#textcolor2784{color:rgb(0,0,255)} -span#textcolor2785{color:rgb(43,145,175)} -span#textcolor2786{color:rgb(43,145,175)} -span#textcolor2787{color:rgb(43,145,175)} -span#textcolor2788{color:rgb(163,20,20)} -span#textcolor2789{color:rgb(163,20,20)} -span#textcolor2790{color:rgb(163,20,20)} +span#textcolor2785{color:rgb(0,127,0)} +span#textcolor2786{color:rgb(0,0,255)} +span#textcolor2787{color:rgb(0,127,0)} +span#textcolor2788{color:rgb(0,0,255)} +span#textcolor2789{color:rgb(0,0,255)} +span#textcolor2790{color:rgb(0,0,255)} span#textcolor2791{color:rgb(0,127,0)} -span#textcolor2792{color:rgb(0,0,255)} -span#textcolor2793{color:rgb(163,20,20)} -span#textcolor2794{color:rgb(163,20,20)} -span#textcolor2795{color:rgb(163,20,20)} +span#textcolor2792{color:rgb(0,127,0)} +span#textcolor2793{color:rgb(0,127,0)} +span#textcolor2794{color:rgb(0,0,255)} +span#textcolor2795{color:rgb(0,0,255)} span#textcolor2796{color:rgb(0,0,255)} -span#textcolor2797{color:rgb(0,127,0)} -span#textcolor2798{color:rgb(0,0,255)} -span#textcolor2799{color:rgb(163,20,20)} -span#textcolor2800{color:rgb(163,20,20)} -span#textcolor2801{color:rgb(163,20,20)} +span#textcolor2797{color:rgb(0,0,255)} +span#textcolor2798{color:rgb(43,145,175)} +span#textcolor2799{color:rgb(0,127,0)} +span#textcolor2800{color:rgb(0,127,0)} +span#textcolor2801{color:rgb(0,127,0)} span#textcolor2802{color:rgb(0,0,255)} -span#textcolor2803{color:rgb(163,20,20)} +span#textcolor2803{color:rgb(0,0,255)} span#textcolor2804{color:rgb(163,20,20)} -span#textcolor2805{color:rgb(163,20,20)} -span#textcolor2806{color:rgb(0,0,255)} -span#textcolor2807{color:rgb(163,20,20)} -span#textcolor2808{color:rgb(163,20,20)} -span#textcolor2809{color:rgb(163,20,20)} -span#textcolor2810{color:rgb(0,0,255)} +span#textcolor2805{color:rgb(0,127,0)} +span#textcolor2806{color:rgb(0,127,0)} +span#textcolor2807{color:rgb(0,127,0)} +span#textcolor2808{color:rgb(0,0,255)} +span#textcolor2809{color:rgb(0,0,255)} +span#textcolor2810{color:rgb(163,20,20)} span#textcolor2811{color:rgb(163,20,20)} -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(163,20,20)} +span#textcolor2812{color:rgb(0,127,0)} +span#textcolor2813{color:rgb(0,0,255)} +span#textcolor2814{color:rgb(43,145,175)} +span#textcolor2815{color:rgb(43,145,175)} +span#textcolor2816{color:rgb(43,145,175)} span#textcolor2817{color:rgb(163,20,20)} span#textcolor2818{color:rgb(163,20,20)} -span#textcolor2819{color:rgb(0,0,255)} -span#textcolor2820{color:rgb(0,0,255)} +span#textcolor2819{color:rgb(163,20,20)} +span#textcolor2820{color:rgb(0,127,0)} span#textcolor2821{color:rgb(163,20,20)} span#textcolor2822{color:rgb(163,20,20)} 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(163,20,20)} -span#textcolor2829{color:rgb(0,0,255)} -span#textcolor2830{color:rgb(163,20,20)} -span#textcolor2831{color:rgb(163,20,20)} -span#textcolor2832{color:rgb(163,20,20)} -span#textcolor2833{color:rgb(0,0,255)} +span#textcolor2825{color:rgb(0,127,0)} +span#textcolor2826{color:rgb(0,0,255)} +span#textcolor2827{color:rgb(43,145,175)} +span#textcolor2828{color:rgb(43,145,175)} +span#textcolor2829{color:rgb(0,127,0)} +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,127,0)} span#textcolor2834{color:rgb(0,0,255)} -span#textcolor2835{color:rgb(0,127,0)} -span#textcolor2836{color:rgb(0,0,255)} -span#textcolor2837{color:rgb(0,0,255)} +span#textcolor2835{color:rgb(0,0,255)} +span#textcolor2836{color:rgb(43,145,175)} +span#textcolor2837{color:rgb(43,145,175)} span#textcolor2838{color:rgb(43,145,175)} -span#textcolor2839{color:rgb(43,145,175)} -span#textcolor2840{color:rgb(43,145,175)} +span#textcolor2839{color:rgb(163,20,20)} +span#textcolor2840{color:rgb(163,20,20)} span#textcolor2841{color:rgb(163,20,20)} -span#textcolor2842{color:rgb(163,20,20)} -span#textcolor2843{color:rgb(163,20,20)} -span#textcolor2844{color:rgb(0,127,0)} -span#textcolor2845{color:rgb(0,127,0)} +span#textcolor2842{color:rgb(0,127,0)} +span#textcolor2843{color:rgb(0,0,255)} +span#textcolor2844{color:rgb(0,0,255)} +span#textcolor2845{color:rgb(0,0,255)} span#textcolor2846{color:rgb(0,0,255)} -span#textcolor2847{color:rgb(0,127,0)} +span#textcolor2847{color:rgb(163,20,20)} span#textcolor2848{color:rgb(163,20,20)} span#textcolor2849{color:rgb(163,20,20)} +span#textcolor2850{color:rgb(0,0,255)} +span#textcolor2851{color:rgb(0,127,0)} +span#textcolor2852{color:rgb(0,0,255)} +span#textcolor2853{color:rgb(0,0,255)} +span#textcolor2854{color:rgb(163,20,20)} +span#textcolor2855{color:rgb(163,20,20)} +span#textcolor2856{color:rgb(163,20,20)} +span#textcolor2857{color:rgb(0,0,255)} +span#textcolor2858{color:rgb(0,0,255)} +span#textcolor2859{color:rgb(163,20,20)} +span#textcolor2860{color:rgb(163,20,20)} +span#textcolor2861{color:rgb(163,20,20)} +span#textcolor2862{color:rgb(0,0,255)} +span#textcolor2863{color:rgb(0,0,255)} +span#textcolor2864{color:rgb(0,0,255)} +span#textcolor2865{color:rgb(163,20,20)} +span#textcolor2866{color:rgb(163,20,20)} +span#textcolor2867{color:rgb(163,20,20)} +span#textcolor2868{color:rgb(0,0,255)} +span#textcolor2869{color:rgb(0,0,255)} +span#textcolor2870{color:rgb(163,20,20)} +span#textcolor2871{color:rgb(163,20,20)} +span#textcolor2872{color:rgb(163,20,20)} +span#textcolor2873{color:rgb(0,0,255)} +span#textcolor2874{color:rgb(163,20,20)} +span#textcolor2875{color:rgb(163,20,20)} +span#textcolor2876{color:rgb(163,20,20)} +span#textcolor2877{color:rgb(0,0,255)} +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(163,20,20)} +span#textcolor2883{color:rgb(163,20,20)} +span#textcolor2884{color:rgb(163,20,20)} +span#textcolor2885{color:rgb(163,20,20)} +span#textcolor2886{color:rgb(0,0,255)} +span#textcolor2887{color:rgb(163,20,20)} +span#textcolor2888{color:rgb(163,20,20)} +span#textcolor2889{color:rgb(163,20,20)} +span#textcolor2890{color:rgb(0,0,255)} +span#textcolor2891{color:rgb(0,0,255)} +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(0,0,255)} +span#textcolor2896{color:rgb(163,20,20)} +span#textcolor2897{color:rgb(163,20,20)} +span#textcolor2898{color:rgb(163,20,20)} +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(0,0,255)} +span#textcolor2904{color:rgb(163,20,20)} +span#textcolor2905{color:rgb(163,20,20)} +span#textcolor2906{color:rgb(163,20,20)} +span#textcolor2907{color:rgb(163,20,20)} +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,0,255)} +span#textcolor2913{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,127,0)} +span#textcolor2919{color:rgb(0,0,255)} +span#textcolor2920{color:rgb(0,0,255)} +span#textcolor2921{color:rgb(0,0,255)} +span#textcolor2922{color:rgb(0,0,255)} +span#textcolor2923{color:rgb(0,0,255)} +span#textcolor2924{color:rgb(43,145,175)} +span#textcolor2925{color:rgb(43,145,175)} +span#textcolor2926{color:rgb(163,20,20)} +span#textcolor2927{color:rgb(163,20,20)} +span#textcolor2928{color:rgb(163,20,20)} +span#textcolor2929{color:rgb(0,127,0)} +span#textcolor2930{color:rgb(0,127,0)} +span#textcolor2931{color:rgb(0,0,255)} +span#textcolor2932{color:rgb(0,0,255)} +span#textcolor2933{color:rgb(43,145,175)} +span#textcolor2934{color:rgb(0,0,255)} +span#textcolor2935{color:rgb(0,0,255)} +span#textcolor2936{color:rgb(0,127,0)} +span#textcolor2937{color:rgb(0,0,255)} +span#textcolor2938{color:rgb(0,0,255)} +span#textcolor2939{color:rgb(0,0,255)} +span#textcolor2940{color:rgb(163,20,20)} +span#textcolor2941{color:rgb(163,20,20)} pre#fancyvrb82{padding:5.69054pt;} 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#textcolor2850{color:rgb(0,127,0)} -span#textcolor2851{color:rgb(0,127,0)} -span#textcolor2852{color:rgb(0,127,0)} -span#textcolor2853{color:rgb(0,127,0)} -span#textcolor2854{color:rgb(0,127,0)} -span#textcolor2855{color:rgb(0,127,0)} -span#textcolor2856{color:rgb(0,127,0)} -span#textcolor2857{color:rgb(0,127,0)} -span#textcolor2858{color:rgb(0,127,0)} -span#textcolor2859{color:rgb(0,0,255)} -span#textcolor2860{color:rgb(0,127,0)} -span#textcolor2861{color:rgb(0,0,255)} -span#textcolor2862{color:rgb(0,127,0)} -span#textcolor2863{color:rgb(0,0,255)} -span#textcolor2864{color:rgb(0,127,0)} -span#textcolor2865{color:rgb(0,0,255)} -span#textcolor2866{color:rgb(0,127,0)} -span#textcolor2867{color:rgb(0,0,255)} -span#textcolor2868{color:rgb(0,127,0)} -span#textcolor2869{color:rgb(0,0,255)} -span#textcolor2870{color:rgb(43,145,175)} -span#textcolor2871{color:rgb(0,127,0)} -span#textcolor2872{color:rgb(0,127,0)} -span#textcolor2873{color:rgb(0,127,0)} -span#textcolor2874{color:rgb(0,0,255)} -span#textcolor2875{color:rgb(0,0,255)} -span#textcolor2876{color:rgb(163,20,20)} -span#textcolor2877{color:rgb(0,127,0)} -span#textcolor2878{color:rgb(0,127,0)} -span#textcolor2879{color:rgb(0,127,0)} -span#textcolor2880{color:rgb(0,0,255)} -span#textcolor2881{color:rgb(0,0,255)} -span#textcolor2882{color:rgb(163,20,20)} -span#textcolor2883{color:rgb(163,20,20)} -span#textcolor2884{color:rgb(0,127,0)} -span#textcolor2885{color:rgb(0,0,255)} -span#textcolor2886{color:rgb(43,145,175)} -span#textcolor2887{color:rgb(43,145,175)} -span#textcolor2888{color:rgb(0,0,255)} -span#textcolor2889{color:rgb(0,127,0)} -span#textcolor2890{color:rgb(0,0,255)} -span#textcolor2891{color:rgb(43,145,175)} -span#textcolor2892{color:rgb(43,145,175)} -span#textcolor2893{color:rgb(163,20,20)} -span#textcolor2894{color:rgb(163,20,20)} -span#textcolor2895{color:rgb(163,20,20)} -span#textcolor2896{color:rgb(0,127,0)} -span#textcolor2897{color:rgb(163,20,20)} -span#textcolor2898{color:rgb(163,20,20)} -span#textcolor2899{color:rgb(163,20,20)} -span#textcolor2900{color:rgb(0,0,255)} -span#textcolor2901{color:rgb(0,0,255)} -span#textcolor2902{color:rgb(43,145,175)} -span#textcolor2903{color:rgb(43,145,175)} -span#textcolor2904{color:rgb(43,145,175)} -span#textcolor2905{color:rgb(163,20,20)} -span#textcolor2906{color:rgb(163,20,20)} -span#textcolor2907{color:rgb(163,20,20)} -span#textcolor2908{color:rgb(0,127,0)} -span#textcolor2909{color:rgb(0,0,255)} -span#textcolor2910{color:rgb(163,20,20)} -span#textcolor2911{color:rgb(163,20,20)} -span#textcolor2912{color:rgb(163,20,20)} -span#textcolor2913{color:rgb(0,0,255)} -span#textcolor2914{color:rgb(0,127,0)} -span#textcolor2915{color:rgb(0,0,255)} -span#textcolor2916{color:rgb(163,20,20)} -span#textcolor2917{color:rgb(163,20,20)} -span#textcolor2918{color:rgb(163,20,20)} -span#textcolor2919{color:rgb(0,0,255)} -span#textcolor2920{color:rgb(163,20,20)} -span#textcolor2921{color:rgb(163,20,20)} -span#textcolor2922{color:rgb(163,20,20)} -span#textcolor2923{color:rgb(0,0,255)} -span#textcolor2924{color:rgb(163,20,20)} -span#textcolor2925{color:rgb(163,20,20)} -span#textcolor2926{color:rgb(163,20,20)} -span#textcolor2927{color:rgb(0,0,255)} -span#textcolor2928{color:rgb(163,20,20)} -span#textcolor2929{color:rgb(163,20,20)} -span#textcolor2930{color:rgb(163,20,20)} -span#textcolor2931{color:rgb(163,20,20)} -span#textcolor2932{color:rgb(0,0,255)} -span#textcolor2933{color:rgb(163,20,20)} -span#textcolor2934{color:rgb(163,20,20)} -span#textcolor2935{color:rgb(163,20,20)} -span#textcolor2936{color:rgb(0,0,255)} -span#textcolor2937{color:rgb(0,0,255)} -span#textcolor2938{color:rgb(163,20,20)} -span#textcolor2939{color:rgb(163,20,20)} -span#textcolor2940{color:rgb(163,20,20)} -span#textcolor2941{color:rgb(0,0,255)} -span#textcolor2942{color:rgb(163,20,20)} -span#textcolor2943{color:rgb(163,20,20)} -span#textcolor2944{color:rgb(163,20,20)} -span#textcolor2945{color:rgb(163,20,20)} -span#textcolor2946{color:rgb(0,0,255)} -span#textcolor2947{color:rgb(163,20,20)} -span#textcolor2948{color:rgb(163,20,20)} -span#textcolor2949{color:rgb(163,20,20)} -span#textcolor2950{color:rgb(0,0,255)} +span#textcolor2942{color:rgb(0,127,0)} +span#textcolor2943{color:rgb(0,127,0)} +span#textcolor2944{color:rgb(0,127,0)} +span#textcolor2945{color:rgb(0,127,0)} +span#textcolor2946{color:rgb(0,127,0)} +span#textcolor2947{color:rgb(0,127,0)} +span#textcolor2948{color:rgb(0,127,0)} +span#textcolor2949{color:rgb(0,127,0)} +span#textcolor2950{color:rgb(0,127,0)} span#textcolor2951{color:rgb(0,0,255)} span#textcolor2952{color:rgb(0,127,0)} 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(43,145,175)} -span#textcolor2957{color:rgb(43,145,175)} -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(0,127,0)} +span#textcolor2954{color:rgb(0,127,0)} +span#textcolor2955{color:rgb(0,0,255)} +span#textcolor2956{color:rgb(0,127,0)} +span#textcolor2957{color:rgb(0,0,255)} +span#textcolor2958{color:rgb(0,127,0)} +span#textcolor2959{color:rgb(0,0,255)} +span#textcolor2960{color:rgb(0,127,0)} +span#textcolor2961{color:rgb(0,0,255)} span#textcolor2962{color:rgb(0,127,0)} span#textcolor2963{color:rgb(0,0,255)} -span#textcolor2964{color:rgb(0,127,0)} -span#textcolor2965{color:rgb(163,20,20)} -span#textcolor2966{color:rgb(163,20,20)} +span#textcolor2964{color:rgb(0,0,255)} +span#textcolor2965{color:rgb(0,0,255)} +span#textcolor2966{color:rgb(0,0,255)} +span#textcolor2967{color:rgb(43,145,175)} +span#textcolor2968{color:rgb(0,127,0)} +span#textcolor2969{color:rgb(0,127,0)} +span#textcolor2970{color:rgb(0,127,0)} +span#textcolor2971{color:rgb(0,0,255)} +span#textcolor2972{color:rgb(0,0,255)} +span#textcolor2973{color:rgb(163,20,20)} +span#textcolor2974{color:rgb(0,127,0)} +span#textcolor2975{color:rgb(0,127,0)} +span#textcolor2976{color:rgb(0,127,0)} +span#textcolor2977{color:rgb(0,0,255)} +span#textcolor2978{color:rgb(0,0,255)} +span#textcolor2979{color:rgb(163,20,20)} +span#textcolor2980{color:rgb(163,20,20)} +span#textcolor2981{color:rgb(0,127,0)} +span#textcolor2982{color:rgb(0,0,255)} +span#textcolor2983{color:rgb(43,145,175)} +span#textcolor2984{color:rgb(43,145,175)} +span#textcolor2985{color:rgb(0,0,255)} +span#textcolor2986{color:rgb(0,127,0)} +span#textcolor2987{color:rgb(0,0,255)} +span#textcolor2988{color:rgb(43,145,175)} +span#textcolor2989{color:rgb(43,145,175)} +span#textcolor2990{color:rgb(163,20,20)} +span#textcolor2991{color:rgb(163,20,20)} +span#textcolor2992{color:rgb(163,20,20)} +span#textcolor2993{color:rgb(0,127,0)} +span#textcolor2994{color:rgb(163,20,20)} +span#textcolor2995{color:rgb(163,20,20)} +span#textcolor2996{color:rgb(163,20,20)} +span#textcolor2997{color:rgb(0,0,255)} +span#textcolor2998{color:rgb(0,0,255)} +span#textcolor2999{color:rgb(43,145,175)} +span#textcolor3000{color:rgb(43,145,175)} +span#textcolor3001{color:rgb(43,145,175)} +span#textcolor3002{color:rgb(163,20,20)} +span#textcolor3003{color:rgb(163,20,20)} +span#textcolor3004{color:rgb(163,20,20)} +span#textcolor3005{color:rgb(0,127,0)} +span#textcolor3006{color:rgb(0,0,255)} +span#textcolor3007{color:rgb(0,0,255)} +span#textcolor3008{color:rgb(0,0,255)} +span#textcolor3009{color:rgb(0,0,255)} +span#textcolor3010{color:rgb(163,20,20)} +span#textcolor3011{color:rgb(163,20,20)} +span#textcolor3012{color:rgb(163,20,20)} +span#textcolor3013{color:rgb(0,0,255)} +span#textcolor3014{color:rgb(0,127,0)} +span#textcolor3015{color:rgb(0,0,255)} +span#textcolor3016{color:rgb(0,0,255)} +span#textcolor3017{color:rgb(163,20,20)} +span#textcolor3018{color:rgb(163,20,20)} +span#textcolor3019{color:rgb(163,20,20)} +span#textcolor3020{color:rgb(0,0,255)} +span#textcolor3021{color:rgb(0,0,255)} +span#textcolor3022{color:rgb(163,20,20)} +span#textcolor3023{color:rgb(163,20,20)} +span#textcolor3024{color:rgb(163,20,20)} +span#textcolor3025{color:rgb(0,0,255)} +span#textcolor3026{color:rgb(0,0,255)} +span#textcolor3027{color:rgb(0,0,255)} +span#textcolor3028{color:rgb(163,20,20)} +span#textcolor3029{color:rgb(163,20,20)} +span#textcolor3030{color:rgb(163,20,20)} +span#textcolor3031{color:rgb(0,0,255)} +span#textcolor3032{color:rgb(0,0,255)} +span#textcolor3033{color:rgb(163,20,20)} +span#textcolor3034{color:rgb(163,20,20)} +span#textcolor3035{color:rgb(163,20,20)} +span#textcolor3036{color:rgb(0,0,255)} +span#textcolor3037{color:rgb(163,20,20)} +span#textcolor3038{color:rgb(163,20,20)} +span#textcolor3039{color:rgb(163,20,20)} +span#textcolor3040{color:rgb(0,0,255)} +span#textcolor3041{color:rgb(0,0,255)} +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(163,20,20)} +span#textcolor3046{color:rgb(163,20,20)} +span#textcolor3047{color:rgb(163,20,20)} +span#textcolor3048{color:rgb(163,20,20)} +span#textcolor3049{color:rgb(0,0,255)} +span#textcolor3050{color:rgb(163,20,20)} +span#textcolor3051{color:rgb(163,20,20)} +span#textcolor3052{color:rgb(163,20,20)} +span#textcolor3053{color:rgb(0,0,255)} +span#textcolor3054{color:rgb(0,0,255)} +span#textcolor3055{color:rgb(0,0,255)} +span#textcolor3056{color:rgb(0,0,255)} +span#textcolor3057{color:rgb(0,0,255)} +span#textcolor3058{color:rgb(0,0,255)} +span#textcolor3059{color:rgb(163,20,20)} +span#textcolor3060{color:rgb(163,20,20)} +span#textcolor3061{color:rgb(163,20,20)} +span#textcolor3062{color:rgb(0,0,255)} +span#textcolor3063{color:rgb(0,0,255)} +span#textcolor3064{color:rgb(0,0,255)} +span#textcolor3065{color:rgb(0,0,255)} +span#textcolor3066{color:rgb(0,0,255)} +span#textcolor3067{color:rgb(163,20,20)} +span#textcolor3068{color:rgb(163,20,20)} +span#textcolor3069{color:rgb(163,20,20)} +span#textcolor3070{color:rgb(163,20,20)} +span#textcolor3071{color:rgb(0,0,255)} +span#textcolor3072{color:rgb(163,20,20)} +span#textcolor3073{color:rgb(163,20,20)} +span#textcolor3074{color:rgb(163,20,20)} +span#textcolor3075{color:rgb(0,0,255)} +span#textcolor3076{color:rgb(0,0,255)} +span#textcolor3077{color:rgb(0,0,255)} +span#textcolor3078{color:rgb(0,0,255)} +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,0,255)} +span#textcolor3084{color:rgb(0,0,255)} +span#textcolor3085{color:rgb(0,0,255)} +span#textcolor3086{color:rgb(0,0,255)} +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,127,0)} +span#textcolor3093{color:rgb(0,127,0)} +span#textcolor3094{color:rgb(0,0,255)} +span#textcolor3095{color:rgb(0,0,255)} +span#textcolor3096{color:rgb(43,145,175)} +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,0,255)} +span#textcolor3101{color:rgb(0,0,255)} +span#textcolor3102{color:rgb(0,0,255)} +span#textcolor3103{color:rgb(163,20,20)} +span#textcolor3104{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#textcolor2967{color:rgb(43,145,175)} -span#textcolor2968{color:rgb(0,0,255)} -span#textcolor2969{color:rgb(0,0,255)} -span#textcolor2970{color:rgb(0,0,255)} +span#textcolor3105{color:rgb(43,145,175)} +span#textcolor3106{color:rgb(0,0,255)} +span#textcolor3107{color:rgb(0,0,255)} +span#textcolor3108{color:rgb(0,0,255)} 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#textcolor2971{color:rgb(43,145,175)} -span#textcolor2972{color:rgb(0,0,255)} -span#textcolor2973{color:rgb(43,145,175)} -span#textcolor2974{color:rgb(43,145,175)} +span#textcolor3109{color:rgb(43,145,175)} +span#textcolor3110{color:rgb(0,0,255)} +span#textcolor3111{color:rgb(43,145,175)} +span#textcolor3112{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#textcolor2975{color:rgb(43,145,175)} -span#textcolor2976{color:rgb(0,0,255)} -span#textcolor2977{color:rgb(43,145,175)} -span#textcolor2978{color:rgb(43,145,175)} +span#textcolor3113{color:rgb(43,145,175)} +span#textcolor3114{color:rgb(0,0,255)} +span#textcolor3115{color:rgb(43,145,175)} +span#textcolor3116{color:rgb(43,145,175)} 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#textcolor2979{color:rgb(0,0,255)} -span#textcolor2980{color:rgb(0,0,255)} -span#textcolor2981{color:rgb(43,145,175)} -span#textcolor2982{color:rgb(0,0,255)} -span#textcolor2983{color:rgb(0,0,255)} -span#textcolor2984{color:rgb(43,145,175)} -span#textcolor2985{color:rgb(43,145,175)} -span#textcolor2986{color:rgb(0,0,255)} -span#textcolor2987{color:rgb(0,0,255)} -span#textcolor2988{color:rgb(0,0,255)} -span#textcolor2989{color:rgb(43,145,175)} -span#textcolor2990{color:rgb(43,145,175)} -span#textcolor2991{color:rgb(0,0,255)} +span#textcolor3117{color:rgb(0,0,255)} +span#textcolor3118{color:rgb(0,0,255)} +span#textcolor3119{color:rgb(43,145,175)} +span#textcolor3120{color:rgb(0,0,255)} +span#textcolor3121{color:rgb(0,0,255)} +span#textcolor3122{color:rgb(43,145,175)} +span#textcolor3123{color:rgb(43,145,175)} +span#textcolor3124{color:rgb(0,0,255)} +span#textcolor3125{color:rgb(0,0,255)} +span#textcolor3126{color:rgb(0,0,255)} +span#textcolor3127{color:rgb(43,145,175)} +span#textcolor3128{color:rgb(43,145,175)} +span#textcolor3129{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#textcolor2992{color:rgb(163,20,20)} +span#textcolor3130{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#textcolor2993{color:rgb(163,20,20)} +span#textcolor3131{color:rgb(163,20,20)} 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#textcolor2994{color:rgb(0,127,0)} -span#textcolor2995{color:rgb(0,127,0)} -span#textcolor2996{color:rgb(0,127,0)} -span#textcolor2997{color:rgb(0,0,255)} -span#textcolor2998{color:rgb(0,0,255)} -span#textcolor2999{color:rgb(0,0,255)} -span#textcolor3000{color:rgb(0,127,0)} -span#textcolor3001{color:rgb(0,0,255)} -span#textcolor3002{color:rgb(0,127,0)} -span#textcolor3003{color:rgb(0,0,255)} -span#textcolor3004{color:rgb(0,0,255)} -span#textcolor3005{color:rgb(0,0,255)} -span#textcolor3006{color:rgb(0,0,255)} -span#textcolor3007{color:rgb(0,0,255)} -span#textcolor3008{color:rgb(0,0,255)} -span#textcolor3009{color:rgb(43,145,175)} -span#textcolor3010{color:rgb(43,145,175)} -span#textcolor3011{color:rgb(43,145,175)} -span#textcolor3012{color:rgb(43,145,175)} -span#textcolor3013{color:rgb(0,0,255)} -span#textcolor3014{color:rgb(0,0,255)} -span#textcolor3015{color:rgb(0,0,255)} -span#textcolor3016{color:rgb(0,0,255)} -span#textcolor3017{color:rgb(0,0,255)} -span#textcolor3018{color:rgb(43,145,175)} -span#textcolor3019{color:rgb(0,0,255)} -span#textcolor3020{color:rgb(43,145,175)} -span#textcolor3021{color:rgb(0,0,255)} -span#textcolor3022{color:rgb(43,145,175)} -span#textcolor3023{color:rgb(0,0,255)} -span#textcolor3024{color:rgb(43,145,175)} -span#textcolor3025{color:rgb(43,145,175)} -span#textcolor3026{color:rgb(43,145,175)} -span#textcolor3027{color:rgb(0,0,255)} -span#textcolor3028{color:rgb(43,145,175)} -span#textcolor3029{color:rgb(43,145,175)} -span#textcolor3030{color:rgb(0,0,255)} -span#textcolor3031{color:rgb(43,145,175)} -span#textcolor3032{color:rgb(0,0,255)} -span#textcolor3033{color:rgb(0,0,255)} -span#textcolor3034{color:rgb(43,145,175)} -span#textcolor3035{color:rgb(0,0,255)} -span#textcolor3036{color:rgb(43,145,175)} -span#textcolor3037{color:rgb(0,0,255)} -span#textcolor3038{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#textcolor3039{color:rgb(0,127,0)} -span#textcolor3040{color:rgb(0,127,0)} -span#textcolor3041{color:rgb(0,127,0)} -span#textcolor3042{color:rgb(0,0,255)} -span#textcolor3043{color:rgb(0,127,0)} -span#textcolor3044{color:rgb(0,0,255)} -span#textcolor3045{color:rgb(0,127,0)} -span#textcolor3046{color:rgb(0,0,255)} -span#textcolor3047{color:rgb(0,127,0)} -span#textcolor3048{color:rgb(0,0,255)} -span#textcolor3049{color:rgb(0,127,0)} -span#textcolor3050{color:rgb(0,0,255)} -span#textcolor3051{color:rgb(0,127,0)} -span#textcolor3052{color:rgb(0,0,255)} -span#textcolor3053{color:rgb(0,127,0)} -span#textcolor3054{color:rgb(0,0,255)} -span#textcolor3055{color:rgb(0,127,0)} -span#textcolor3056{color:rgb(0,0,255)} -span#textcolor3057{color:rgb(0,127,0)} -span#textcolor3058{color:rgb(0,0,255)} -span#textcolor3059{color:rgb(0,0,255)} -span#textcolor3060{color:rgb(0,0,255)} -span#textcolor3061{color:rgb(0,0,255)} -span#textcolor3062{color:rgb(0,0,255)} -span#textcolor3063{color:rgb(0,0,255)} -span#textcolor3064{color:rgb(43,145,175)} -span#textcolor3065{color:rgb(0,0,255)} -span#textcolor3066{color:rgb(0,0,255)} -span#textcolor3067{color:rgb(0,0,255)} -span#textcolor3068{color:rgb(0,0,255)} -span#textcolor3069{color:rgb(0,127,0)} -span#textcolor3070{color:rgb(0,127,0)} -span#textcolor3071{color:rgb(0,127,0)} -span#textcolor3072{color:rgb(0,0,255)} -span#textcolor3073{color:rgb(0,0,255)} -span#textcolor3074{color:rgb(0,0,255)} -span#textcolor3075{color:rgb(43,145,175)} -span#textcolor3076{color:rgb(43,145,175)} -span#textcolor3077{color:rgb(0,0,255)} -span#textcolor3078{color:rgb(0,0,255)} -span#textcolor3079{color:rgb(0,0,255)} -span#textcolor3080{color:rgb(0,0,255)} -span#textcolor3081{color:rgb(0,0,255)} -span#textcolor3082{color:rgb(0,0,255)} -span#textcolor3083{color:rgb(0,0,255)} -span#textcolor3084{color:rgb(0,0,255)} -span#textcolor3085{color:rgb(0,127,0)} -span#textcolor3086{color:rgb(0,127,0)} -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(43,145,175)} -span#textcolor3091{color:rgb(0,0,255)} -span#textcolor3092{color:rgb(0,0,255)} -span#textcolor3093{color:rgb(0,0,255)} -span#textcolor3094{color:rgb(0,0,255)} -span#textcolor3095{color:rgb(0,0,255)} -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,0,255)} -span#textcolor3100{color:rgb(43,145,175)} -span#textcolor3101{color:rgb(0,0,255)} -span#textcolor3102{color:rgb(0,0,255)} -span#textcolor3103{color:rgb(43,145,175)} -span#textcolor3104{color:rgb(0,0,255)} -span#textcolor3105{color:rgb(0,0,255)} -span#textcolor3106{color:rgb(0,0,255)} -span#textcolor3107{color:rgb(0,0,255)} -span#textcolor3108{color:rgb(0,0,255)} -span#textcolor3109{color:rgb(43,145,175)} -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(43,145,175)} -span#textcolor3115{color:rgb(0,0,255)} -span#textcolor3116{color:rgb(43,145,175)} -span#textcolor3117{color:rgb(43,145,175)} -span#textcolor3118{color:rgb(43,145,175)} -span#textcolor3119{color:rgb(43,145,175)} -span#textcolor3120{color:rgb(0,0,255)} -span#textcolor3121{color:rgb(0,0,255)} -span#textcolor3122{color:rgb(0,0,255)} -span#textcolor3123{color:rgb(0,0,255)} -span#textcolor3124{color:rgb(0,0,255)} -span#textcolor3125{color:rgb(0,0,255)} -span#textcolor3126{color:rgb(0,0,255)} -span#textcolor3127{color:rgb(0,0,255)} -span#textcolor3128{color:rgb(43,145,175)} -span#textcolor3129{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(43,145,175)} -span#textcolor3134{color:rgb(0,0,255)} +span#textcolor3132{color:rgb(0,127,0)} +span#textcolor3133{color:rgb(0,127,0)} +span#textcolor3134{color:rgb(0,127,0)} span#textcolor3135{color:rgb(0,0,255)} -span#textcolor3136{color:rgb(43,145,175)} +span#textcolor3136{color:rgb(0,0,255)} span#textcolor3137{color:rgb(0,0,255)} -span#textcolor3138{color:rgb(163,20,20)} -span#textcolor3139{color:rgb(163,20,20)} -span#textcolor3140{color:rgb(163,20,20)} +span#textcolor3138{color:rgb(0,127,0)} +span#textcolor3139{color:rgb(0,0,255)} +span#textcolor3140{color:rgb(0,127,0)} 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(0,0,255)} span#textcolor3145{color:rgb(0,0,255)} span#textcolor3146{color:rgb(0,0,255)} -span#textcolor3147{color:rgb(0,0,255)} -span#textcolor3148{color:rgb(0,0,255)} -span#textcolor3149{color:rgb(0,0,255)} -span#textcolor3150{color:rgb(0,0,255)} -span#textcolor3151{color:rgb(43,145,175)} +span#textcolor3147{color:rgb(43,145,175)} +span#textcolor3148{color:rgb(43,145,175)} +span#textcolor3149{color:rgb(43,145,175)} +span#textcolor3150{color:rgb(43,145,175)} +span#textcolor3151{color:rgb(0,0,255)} span#textcolor3152{color:rgb(0,0,255)} span#textcolor3153{color:rgb(0,0,255)} span#textcolor3154{color:rgb(0,0,255)} -span#textcolor3155{color:rgb(43,145,175)} -span#textcolor3156{color:rgb(0,0,255)} -span#textcolor3157{color:rgb(0,127,0)} -span#textcolor3158{color:rgb(0,0,255)} -span#textcolor3159{color:rgb(43,145,175)} -span#textcolor3160{color:rgb(0,0,255)} +span#textcolor3155{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(0,0,255)} +span#textcolor3160{color:rgb(43,145,175)} span#textcolor3161{color:rgb(0,0,255)} span#textcolor3162{color:rgb(43,145,175)} -span#textcolor3163{color:rgb(163,20,20)} -span#textcolor3164{color:rgb(163,20,20)} -span#textcolor3165{color:rgb(163,20,20)} -span#textcolor3166{color:rgb(0,0,255)} -span#textcolor3167{color:rgb(0,0,255)} -span#textcolor3168{color:rgb(43,145,175)} +span#textcolor3163{color:rgb(43,145,175)} +span#textcolor3164{color:rgb(43,145,175)} +span#textcolor3165{color:rgb(0,0,255)} +span#textcolor3166{color:rgb(43,145,175)} +span#textcolor3167{color:rgb(43,145,175)} +span#textcolor3168{color:rgb(0,0,255)} span#textcolor3169{color:rgb(43,145,175)} span#textcolor3170{color:rgb(0,0,255)} span#textcolor3171{color:rgb(0,0,255)} -span#textcolor3172{color:rgb(0,0,255)} +span#textcolor3172{color:rgb(43,145,175)} span#textcolor3173{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(0,0,255)} -span#textcolor3178{color:rgb(0,0,255)} -span#textcolor3179{color:rgb(0,0,255)} -span#textcolor3180{color:rgb(0,127,0)} -span#textcolor3181{color:rgb(0,0,255)} -span#textcolor3182{color:rgb(163,20,20)} -span#textcolor3183{color:rgb(163,20,20)} -span#textcolor3184{color:rgb(163,20,20)} -span#textcolor3185{color:rgb(0,0,255)} -span#textcolor3186{color:rgb(0,127,0)} -span#textcolor3187{color:rgb(163,20,20)} +span#textcolor3174{color:rgb(43,145,175)} +span#textcolor3175{color:rgb(0,0,255)} +span#textcolor3176{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#textcolor3177{color:rgb(0,127,0)} +span#textcolor3178{color:rgb(0,127,0)} +span#textcolor3179{color:rgb(0,127,0)} +span#textcolor3180{color:rgb(0,0,255)} +span#textcolor3181{color:rgb(0,127,0)} +span#textcolor3182{color:rgb(0,0,255)} +span#textcolor3183{color:rgb(0,127,0)} +span#textcolor3184{color:rgb(0,0,255)} +span#textcolor3185{color:rgb(0,127,0)} +span#textcolor3186{color:rgb(0,0,255)} +span#textcolor3187{color:rgb(0,127,0)} span#textcolor3188{color:rgb(0,0,255)} -span#textcolor3189{color:rgb(0,0,255)} +span#textcolor3189{color:rgb(0,127,0)} span#textcolor3190{color:rgb(0,0,255)} -span#textcolor3191{color:rgb(43,145,175)} +span#textcolor3191{color:rgb(0,127,0)} span#textcolor3192{color:rgb(0,0,255)} -span#textcolor3193{color:rgb(43,145,175)} -span#textcolor3194{color:rgb(0,127,0)} -span#textcolor3195{color:rgb(163,20,20)} +span#textcolor3193{color:rgb(0,127,0)} +span#textcolor3194{color:rgb(0,0,255)} +span#textcolor3195{color:rgb(0,127,0)} span#textcolor3196{color:rgb(0,0,255)} -span#textcolor3197{color:rgb(163,20,20)} -span#textcolor3198{color:rgb(163,20,20)} -span#textcolor3199{color:rgb(163,20,20)} +span#textcolor3197{color:rgb(0,0,255)} +span#textcolor3198{color:rgb(0,0,255)} +span#textcolor3199{color:rgb(0,0,255)} span#textcolor3200{color:rgb(0,0,255)} span#textcolor3201{color:rgb(0,0,255)} -span#textcolor3202{color:rgb(0,0,255)} -span#textcolor3203{color:rgb(43,145,175)} +span#textcolor3202{color:rgb(43,145,175)} +span#textcolor3203{color:rgb(0,0,255)} span#textcolor3204{color:rgb(0,0,255)} span#textcolor3205{color:rgb(0,0,255)} span#textcolor3206{color:rgb(0,0,255)} -span#textcolor3207{color:rgb(0,0,255)} -span#textcolor3208{color:rgb(0,0,255)} -span#textcolor3209{color:rgb(0,0,255)} -span#textcolor3210{color:rgb(43,145,175)} +span#textcolor3207{color:rgb(0,127,0)} +span#textcolor3208{color:rgb(0,127,0)} +span#textcolor3209{color:rgb(0,127,0)} +span#textcolor3210{color:rgb(0,0,255)} 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(43,145,175)} -span#textcolor3217{color:rgb(43,145,175)} +span#textcolor3213{color:rgb(43,145,175)} +span#textcolor3214{color:rgb(43,145,175)} +span#textcolor3215{color:rgb(0,0,255)} +span#textcolor3216{color:rgb(0,0,255)} +span#textcolor3217{color:rgb(0,0,255)} span#textcolor3218{color:rgb(0,0,255)} span#textcolor3219{color:rgb(0,0,255)} 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#textcolor3224{color:rgb(0,0,255)} -span#textcolor3225{color:rgb(0,0,255)} +span#textcolor3221{color:rgb(0,0,255)} +span#textcolor3222{color:rgb(0,0,255)} +span#textcolor3223{color:rgb(0,127,0)} +span#textcolor3224{color:rgb(0,127,0)} +span#textcolor3225{color:rgb(0,127,0)} span#textcolor3226{color:rgb(0,0,255)} span#textcolor3227{color:rgb(0,0,255)} -span#textcolor3228{color:rgb(0,0,255)} +span#textcolor3228{color:rgb(43,145,175)} span#textcolor3229{color:rgb(0,0,255)} span#textcolor3230{color:rgb(0,0,255)} span#textcolor3231{color:rgb(0,0,255)} -span#textcolor3232{color:rgb(0,127,0)} +span#textcolor3232{color:rgb(0,0,255)} span#textcolor3233{color:rgb(0,0,255)} span#textcolor3234{color:rgb(0,0,255)} -span#textcolor3235{color:rgb(0,127,0)} +span#textcolor3235{color:rgb(0,0,255)} span#textcolor3236{color:rgb(0,0,255)} span#textcolor3237{color:rgb(0,0,255)} -span#textcolor3238{color:rgb(0,0,255)} -span#textcolor3239{color:rgb(43,145,175)} +span#textcolor3238{color:rgb(43,145,175)} +span#textcolor3239{color:rgb(0,0,255)} span#textcolor3240{color:rgb(0,0,255)} -span#textcolor3241{color:rgb(0,0,255)} +span#textcolor3241{color:rgb(43,145,175)} span#textcolor3242{color:rgb(0,0,255)} span#textcolor3243{color:rgb(0,0,255)} span#textcolor3244{color:rgb(0,0,255)} span#textcolor3245{color:rgb(0,0,255)} -span#textcolor3246{color:rgb(43,145,175)} -span#textcolor3247{color:rgb(0,0,255)} +span#textcolor3246{color:rgb(0,0,255)} +span#textcolor3247{color:rgb(43,145,175)} 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(0,0,255)} span#textcolor3252{color:rgb(43,145,175)} -span#textcolor3253{color:rgb(43,145,175)} +span#textcolor3253{color:rgb(0,0,255)} span#textcolor3254{color:rgb(43,145,175)} span#textcolor3255{color:rgb(43,145,175)} -span#textcolor3256{color:rgb(0,0,255)} -span#textcolor3257{color:rgb(0,0,255)} +span#textcolor3256{color:rgb(43,145,175)} +span#textcolor3257{color:rgb(43,145,175)} span#textcolor3258{color:rgb(0,0,255)} 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#textcolor3260{color:rgb(0,0,255)} +span#textcolor3261{color:rgb(0,0,255)} +span#textcolor3262{color:rgb(0,0,255)} span#textcolor3263{color:rgb(0,0,255)} span#textcolor3264{color:rgb(0,0,255)} span#textcolor3265{color:rgb(0,0,255)} -span#textcolor3266{color:rgb(0,127,0)} +span#textcolor3266{color:rgb(43,145,175)} 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#textcolor3269{color:rgb(43,145,175)} +span#textcolor3270{color:rgb(43,145,175)} +span#textcolor3271{color:rgb(43,145,175)} span#textcolor3272{color:rgb(0,0,255)} -span#textcolor3273{color:rgb(163,20,20)} -span#textcolor3274{color:rgb(0,0,255)} +span#textcolor3273{color:rgb(0,0,255)} +span#textcolor3274{color:rgb(43,145,175)} span#textcolor3275{color:rgb(0,0,255)} -span#textcolor3276{color:rgb(43,145,175)} -span#textcolor3277{color:rgb(0,0,255)} +span#textcolor3276{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(163,20,20)} +span#textcolor3279{color:rgb(0,0,255)} +span#textcolor3280{color:rgb(0,0,255)} span#textcolor3281{color:rgb(0,0,255)} -span#textcolor3282{color:rgb(43,145,175)} +span#textcolor3282{color:rgb(0,0,255)} span#textcolor3283{color:rgb(0,0,255)} span#textcolor3284{color:rgb(0,0,255)} -span#textcolor3285{color:rgb(0,127,0)} -span#textcolor3286{color:rgb(0,127,0)} +span#textcolor3285{color:rgb(0,0,255)} +span#textcolor3286{color:rgb(0,0,255)} span#textcolor3287{color:rgb(0,0,255)} span#textcolor3288{color:rgb(0,0,255)} -span#textcolor3289{color:rgb(0,0,255)} -span#textcolor3290{color:rgb(163,20,20)} -span#textcolor3291{color:rgb(163,20,20)} -span#textcolor3292{color:rgb(163,20,20)} -span#textcolor3293{color:rgb(0,0,255)} -span#textcolor3294{color:rgb(43,145,175)} -span#textcolor3295{color:rgb(43,145,175)} -span#textcolor3296{color:rgb(43,145,175)} -span#textcolor3297{color:rgb(163,20,20)} -span#textcolor3298{color:rgb(163,20,20)} -span#textcolor3299{color:rgb(163,20,20)} -span#textcolor3300{color:rgb(0,0,255)} +span#textcolor3289{color:rgb(43,145,175)} +span#textcolor3290{color:rgb(0,0,255)} +span#textcolor3291{color:rgb(0,0,255)} +span#textcolor3292{color:rgb(0,0,255)} +span#textcolor3293{color:rgb(43,145,175)} +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(43,145,175)} +span#textcolor3298{color:rgb(0,0,255)} +span#textcolor3299{color:rgb(0,0,255)} +span#textcolor3300{color:rgb(43,145,175)} span#textcolor3301{color:rgb(163,20,20)} span#textcolor3302{color:rgb(163,20,20)} span#textcolor3303{color:rgb(163,20,20)} span#textcolor3304{color:rgb(0,0,255)} span#textcolor3305{color:rgb(0,0,255)} -span#textcolor3306{color:rgb(163,20,20)} -span#textcolor3307{color:rgb(163,20,20)} -span#textcolor3308{color:rgb(163,20,20)} +span#textcolor3306{color:rgb(43,145,175)} +span#textcolor3307{color:rgb(43,145,175)} +span#textcolor3308{color:rgb(0,0,255)} span#textcolor3309{color:rgb(0,0,255)} span#textcolor3310{color:rgb(0,0,255)} span#textcolor3311{color:rgb(0,0,255)} -span#textcolor3312{color:rgb(0,0,255)} -span#textcolor3313{color:rgb(43,145,175)} -span#textcolor3314{color:rgb(43,145,175)} -span#textcolor3315{color:rgb(163,20,20)} -span#textcolor3316{color:rgb(163,20,20)} -span#textcolor3317{color:rgb(163,20,20)} -span#textcolor3318{color:rgb(163,20,20)} -span#textcolor3319{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#textcolor3312{color:rgb(163,20,20)} +span#textcolor3313{color:rgb(163,20,20)} +span#textcolor3314{color:rgb(163,20,20)} +span#textcolor3315{color:rgb(0,0,255)} +span#textcolor3316{color:rgb(0,0,255)} +span#textcolor3317{color:rgb(0,0,255)} +span#textcolor3318{color:rgb(0,127,0)} +span#textcolor3319{color:rgb(0,0,255)} span#textcolor3320{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#textcolor3321{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#textcolor3322{color:rgb(0,127,0)} -span#textcolor3323{color:rgb(0,127,0)} +span#textcolor3322{color:rgb(163,20,20)} +span#textcolor3323{color:rgb(0,0,255)} span#textcolor3324{color:rgb(0,127,0)} -span#textcolor3325{color:rgb(0,0,255)} -span#textcolor3326{color:rgb(0,127,0)} +span#textcolor3325{color:rgb(163,20,20)} +span#textcolor3326{color:rgb(0,0,255)} 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#textcolor3328{color:rgb(0,0,255)} +span#textcolor3329{color:rgb(43,145,175)} +span#textcolor3330{color:rgb(0,0,255)} +span#textcolor3331{color:rgb(43,145,175)} 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,0,255)} -span#textcolor3337{color:rgb(0,0,255)} +span#textcolor3333{color:rgb(163,20,20)} +span#textcolor3334{color:rgb(0,0,255)} +span#textcolor3335{color:rgb(163,20,20)} +span#textcolor3336{color:rgb(163,20,20)} +span#textcolor3337{color:rgb(163,20,20)} span#textcolor3338{color:rgb(0,0,255)} -span#textcolor3339{color:rgb(43,145,175)} -span#textcolor3340{color:rgb(43,145,175)} -span#textcolor3341{color:rgb(0,0,255)} -span#textcolor3342{color:rgb(43,145,175)} +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(0,0,255)} span#textcolor3343{color:rgb(0,0,255)} -span#textcolor3344{color:rgb(43,145,175)} -span#textcolor3345{color:rgb(0,127,0)} +span#textcolor3344{color:rgb(0,0,255)} +span#textcolor3345{color:rgb(0,0,255)} span#textcolor3346{color:rgb(0,0,255)} -span#textcolor3347{color:rgb(43,145,175)} +span#textcolor3347{color:rgb(0,0,255)} span#textcolor3348{color:rgb(43,145,175)} span#textcolor3349{color:rgb(0,0,255)} -span#textcolor3350{color:rgb(0,127,0)} -span#textcolor3351{color:rgb(0,127,0)} -span#textcolor3352{color:rgb(0,127,0)} -span#textcolor3353{color:rgb(0,0,255)} -span#textcolor3354{color:rgb(0,0,255)} +span#textcolor3350{color:rgb(0,0,255)} +span#textcolor3351{color:rgb(0,0,255)} +span#textcolor3352{color:rgb(0,0,255)} +span#textcolor3353{color:rgb(43,145,175)} +span#textcolor3354{color:rgb(43,145,175)} span#textcolor3355{color:rgb(43,145,175)} span#textcolor3356{color:rgb(0,0,255)} -span#textcolor3357{color:rgb(43,145,175)} -span#textcolor3358{color:rgb(43,145,175)} +span#textcolor3357{color:rgb(0,0,255)} +span#textcolor3358{color:rgb(0,0,255)} span#textcolor3359{color:rgb(163,20,20)} span#textcolor3360{color:rgb(163,20,20)} span#textcolor3361{color:rgb(163,20,20)} span#textcolor3362{color:rgb(0,0,255)} span#textcolor3363{color:rgb(0,0,255)} -span#textcolor3364{color:rgb(43,145,175)} +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(43,145,175)} -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(0,127,0)} -span#textcolor3372{color:rgb(0,127,0)} +span#textcolor3366{color:rgb(0,0,255)} +span#textcolor3367{color:rgb(0,0,255)} +span#textcolor3368{color:rgb(0,0,255)} +span#textcolor3369{color:rgb(0,0,255)} +span#textcolor3370{color:rgb(0,127,0)} +span#textcolor3371{color:rgb(0,0,255)} +span#textcolor3372{color:rgb(0,0,255)} span#textcolor3373{color:rgb(0,127,0)} span#textcolor3374{color:rgb(0,0,255)} -span#textcolor3375{color:rgb(163,20,20)} +span#textcolor3375{color:rgb(0,0,255)} span#textcolor3376{color:rgb(0,0,255)} -span#textcolor3377{color:rgb(0,0,255)} -span#textcolor3378{color:rgb(163,20,20)} -span#textcolor3379{color:rgb(163,20,20)} -span#textcolor3380{color:rgb(163,20,20)} +span#textcolor3377{color:rgb(43,145,175)} +span#textcolor3378{color:rgb(0,0,255)} +span#textcolor3379{color:rgb(0,0,255)} +span#textcolor3380{color:rgb(0,0,255)} span#textcolor3381{color:rgb(0,0,255)} -span#textcolor3382{color:rgb(163,20,20)} -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(0,127,0)} -span#textcolor3388{color:rgb(0,127,0)} -span#textcolor3389{color:rgb(0,0,255)} -span#textcolor3390{color:rgb(0,0,255)} -span#textcolor3391{color:rgb(0,0,255)} -span#textcolor3392{color:rgb(0,0,255)} -span#textcolor3393{color:rgb(0,0,255)} +span#textcolor3382{color:rgb(0,0,255)} +span#textcolor3383{color:rgb(0,0,255)} +span#textcolor3384{color:rgb(43,145,175)} +span#textcolor3385{color:rgb(0,0,255)} +span#textcolor3386{color:rgb(0,0,255)} +span#textcolor3387{color:rgb(0,0,255)} +span#textcolor3388{color:rgb(0,0,255)} +span#textcolor3389{color:rgb(43,145,175)} +span#textcolor3390{color:rgb(43,145,175)} +span#textcolor3391{color:rgb(43,145,175)} +span#textcolor3392{color:rgb(43,145,175)} +span#textcolor3393{color:rgb(43,145,175)} span#textcolor3394{color:rgb(0,0,255)} -span#textcolor3395{color:rgb(43,145,175)} -span#textcolor3396{color:rgb(43,145,175)} -span#textcolor3397{color:rgb(43,145,175)} -span#textcolor3398{color:rgb(0,0,255)} -span#textcolor3399{color:rgb(0,0,255)} -span#textcolor3400{color:rgb(0,0,255)} -span#textcolor3401{color:rgb(43,145,175)} -span#textcolor3402{color:rgb(43,145,175)} -span#textcolor3403{color:rgb(163,20,20)} -span#textcolor3404{color:rgb(163,20,20)} +span#textcolor3395{color:rgb(0,0,255)} +span#textcolor3396{color:rgb(0,0,255)} +span#textcolor3397{color:rgb(0,0,255)} +span#textcolor3398{color:rgb(163,20,20)} +span#textcolor3399{color:rgb(163,20,20)} +span#textcolor3400{color:rgb(163,20,20)} +span#textcolor3401{color:rgb(0,0,255)} +span#textcolor3402{color:rgb(0,0,255)} +span#textcolor3403{color:rgb(0,0,255)} +span#textcolor3404{color:rgb(0,127,0)} +span#textcolor3405{color:rgb(0,0,255)} +span#textcolor3406{color:rgb(0,0,255)} +span#textcolor3407{color:rgb(0,0,255)} +span#textcolor3408{color:rgb(0,127,0)} +span#textcolor3409{color:rgb(0,0,255)} +span#textcolor3410{color:rgb(0,0,255)} +span#textcolor3411{color:rgb(163,20,20)} +span#textcolor3412{color:rgb(0,0,255)} +span#textcolor3413{color:rgb(0,0,255)} +span#textcolor3414{color:rgb(43,145,175)} +span#textcolor3415{color:rgb(0,0,255)} +span#textcolor3416{color:rgb(163,20,20)} +span#textcolor3417{color:rgb(163,20,20)} +span#textcolor3418{color:rgb(163,20,20)} +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,127,0)} +span#textcolor3424{color:rgb(0,127,0)} +span#textcolor3425{color:rgb(0,0,255)} +span#textcolor3426{color:rgb(0,0,255)} +span#textcolor3427{color:rgb(0,0,255)} +span#textcolor3428{color:rgb(163,20,20)} +span#textcolor3429{color:rgb(163,20,20)} +span#textcolor3430{color:rgb(163,20,20)} +span#textcolor3431{color:rgb(0,0,255)} +span#textcolor3432{color:rgb(43,145,175)} +span#textcolor3433{color:rgb(43,145,175)} +span#textcolor3434{color:rgb(43,145,175)} +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,0,255)} +span#textcolor3439{color:rgb(163,20,20)} +span#textcolor3440{color:rgb(163,20,20)} +span#textcolor3441{color:rgb(163,20,20)} +span#textcolor3442{color:rgb(0,0,255)} +span#textcolor3443{color:rgb(0,0,255)} +span#textcolor3444{color:rgb(163,20,20)} +span#textcolor3445{color:rgb(163,20,20)} +span#textcolor3446{color:rgb(163,20,20)} +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(0,0,255)} +span#textcolor3451{color:rgb(43,145,175)} +span#textcolor3452{color:rgb(43,145,175)} +span#textcolor3453{color:rgb(163,20,20)} +span#textcolor3454{color:rgb(163,20,20)} +span#textcolor3455{color:rgb(163,20,20)} +span#textcolor3456{color:rgb(163,20,20)} +span#textcolor3457{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#textcolor3458{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#textcolor3459{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#textcolor3460{color:rgb(0,127,0)} +span#textcolor3461{color:rgb(0,127,0)} +span#textcolor3462{color:rgb(0,127,0)} +span#textcolor3463{color:rgb(0,0,255)} +span#textcolor3464{color:rgb(0,127,0)} +span#textcolor3465{color:rgb(0,0,255)} +span#textcolor3466{color:rgb(0,127,0)} +span#textcolor3467{color:rgb(0,0,255)} +span#textcolor3468{color:rgb(0,127,0)} +span#textcolor3469{color:rgb(0,0,255)} +span#textcolor3470{color:rgb(0,127,0)} +span#textcolor3471{color:rgb(0,0,255)} +span#textcolor3472{color:rgb(0,127,0)} +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(0,0,255)} +span#textcolor3477{color:rgb(43,145,175)} +span#textcolor3478{color:rgb(43,145,175)} +span#textcolor3479{color:rgb(0,0,255)} +span#textcolor3480{color:rgb(43,145,175)} +span#textcolor3481{color:rgb(0,0,255)} +span#textcolor3482{color:rgb(43,145,175)} +span#textcolor3483{color:rgb(0,127,0)} +span#textcolor3484{color:rgb(0,0,255)} +span#textcolor3485{color:rgb(43,145,175)} +span#textcolor3486{color:rgb(43,145,175)} +span#textcolor3487{color:rgb(0,0,255)} +span#textcolor3488{color:rgb(0,127,0)} +span#textcolor3489{color:rgb(0,127,0)} +span#textcolor3490{color:rgb(0,127,0)} +span#textcolor3491{color:rgb(0,0,255)} +span#textcolor3492{color:rgb(0,0,255)} +span#textcolor3493{color:rgb(43,145,175)} +span#textcolor3494{color:rgb(0,0,255)} +span#textcolor3495{color:rgb(43,145,175)} +span#textcolor3496{color:rgb(43,145,175)} +span#textcolor3497{color:rgb(163,20,20)} +span#textcolor3498{color:rgb(163,20,20)} +span#textcolor3499{color:rgb(163,20,20)} +span#textcolor3500{color:rgb(0,0,255)} +span#textcolor3501{color:rgb(0,0,255)} +span#textcolor3502{color:rgb(43,145,175)} +span#textcolor3503{color:rgb(0,0,255)} +span#textcolor3504{color:rgb(43,145,175)} +span#textcolor3505{color:rgb(43,145,175)} +span#textcolor3506{color:rgb(43,145,175)} +span#textcolor3507{color:rgb(43,145,175)} +span#textcolor3508{color:rgb(43,145,175)} +span#textcolor3509{color:rgb(0,127,0)} +span#textcolor3510{color:rgb(0,127,0)} +span#textcolor3511{color:rgb(0,127,0)} +span#textcolor3512{color:rgb(0,0,255)} +span#textcolor3513{color:rgb(163,20,20)} +span#textcolor3514{color:rgb(0,0,255)} +span#textcolor3515{color:rgb(0,0,255)} +span#textcolor3516{color:rgb(163,20,20)} +span#textcolor3517{color:rgb(163,20,20)} +span#textcolor3518{color:rgb(163,20,20)} +span#textcolor3519{color:rgb(0,0,255)} +span#textcolor3520{color:rgb(163,20,20)} +span#textcolor3521{color:rgb(163,20,20)} +span#textcolor3522{color:rgb(163,20,20)} +span#textcolor3523{color:rgb(163,20,20)} +span#textcolor3524{color:rgb(163,20,20)} +span#textcolor3525{color:rgb(0,127,0)} +span#textcolor3526{color:rgb(0,127,0)} +span#textcolor3527{color:rgb(0,0,255)} +span#textcolor3528{color:rgb(0,0,255)} +span#textcolor3529{color:rgb(0,0,255)} +span#textcolor3530{color:rgb(0,0,255)} +span#textcolor3531{color:rgb(0,0,255)} +span#textcolor3532{color:rgb(0,0,255)} +span#textcolor3533{color:rgb(43,145,175)} +span#textcolor3534{color:rgb(43,145,175)} +span#textcolor3535{color:rgb(43,145,175)} +span#textcolor3536{color:rgb(0,0,255)} +span#textcolor3537{color:rgb(0,0,255)} +span#textcolor3538{color:rgb(0,0,255)} +span#textcolor3539{color:rgb(43,145,175)} +span#textcolor3540{color:rgb(43,145,175)} +span#textcolor3541{color:rgb(163,20,20)} +span#textcolor3542{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#textcolor3405{color:rgb(0,127,0)} -span#textcolor3406{color:rgb(0,127,0)} -span#textcolor3407{color:rgb(0,127,0)} -span#textcolor3408{color:rgb(0,0,255)} -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(43,145,175)} -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,0,255)} -span#textcolor3421{color:rgb(0,0,255)} -span#textcolor3422{color:rgb(163,20,20)} -span#textcolor3423{color:rgb(163,20,20)} -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(0,127,0)} -span#textcolor3429{color:rgb(0,0,255)} -span#textcolor3430{color:rgb(0,0,255)} -span#textcolor3431{color:rgb(43,145,175)} -span#textcolor3432{color:rgb(0,0,255)} -span#textcolor3433{color:rgb(163,20,20)} -span#textcolor3434{color:rgb(163,20,20)} -span#textcolor3435{color:rgb(163,20,20)} -span#textcolor3436{color:rgb(0,127,0)} -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(0,0,255)} -span#textcolor3441{color:rgb(163,20,20)} -span#textcolor3442{color:rgb(163,20,20)} -span#textcolor3443{color:rgb(163,20,20)} -span#textcolor3444{color:rgb(0,127,0)} -span#textcolor3445{color:rgb(0,0,255)} -span#textcolor3446{color:rgb(0,0,255)} -span#textcolor3447{color:rgb(43,145,175)} -span#textcolor3448{color:rgb(0,0,255)} -span#textcolor3449{color:rgb(163,20,20)} -span#textcolor3450{color:rgb(163,20,20)} -span#textcolor3451{color:rgb(163,20,20)} -span#textcolor3452{color:rgb(0,127,0)} -span#textcolor3453{color:rgb(0,0,255)} -span#textcolor3454{color:rgb(0,0,255)} -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(163,20,20)} -span#textcolor3460{color:rgb(0,0,255)} -span#textcolor3461{color:rgb(43,145,175)} -span#textcolor3462{color:rgb(43,145,175)} -span#textcolor3463{color:rgb(43,145,175)} -span#textcolor3464{color:rgb(163,20,20)} -span#textcolor3465{color:rgb(163,20,20)} -span#textcolor3466{color:rgb(163,20,20)} -span#textcolor3467{color:rgb(0,0,255)} -span#textcolor3468{color:rgb(163,20,20)} -span#textcolor3469{color:rgb(163,20,20)} -span#textcolor3470{color:rgb(163,20,20)} -span#textcolor3471{color:rgb(0,0,255)} -span#textcolor3472{color:rgb(0,0,255)} -span#textcolor3473{color:rgb(0,0,255)} -span#textcolor3474{color:rgb(43,145,175)} -span#textcolor3475{color:rgb(43,145,175)} -span#textcolor3476{color:rgb(163,20,20)} -span#textcolor3477{color:rgb(163,20,20)} -span#textcolor3478{color:rgb(163,20,20)} -span#textcolor3479{color:rgb(163,20,20)} -span#textcolor3480{color:rgb(163,20,20)} +span#textcolor3543{color:rgb(0,127,0)} +span#textcolor3544{color:rgb(0,127,0)} +span#textcolor3545{color:rgb(0,127,0)} +span#textcolor3546{color:rgb(0,0,255)} +span#textcolor3547{color:rgb(0,127,0)} +span#textcolor3548{color:rgb(0,0,255)} +span#textcolor3549{color:rgb(0,127,0)} +span#textcolor3550{color:rgb(0,0,255)} +span#textcolor3551{color:rgb(0,127,0)} +span#textcolor3552{color:rgb(0,0,255)} +span#textcolor3553{color:rgb(43,145,175)} +span#textcolor3554{color:rgb(43,145,175)} +span#textcolor3555{color:rgb(0,0,255)} +span#textcolor3556{color:rgb(43,145,175)} +span#textcolor3557{color:rgb(0,0,255)} +span#textcolor3558{color:rgb(0,0,255)} +span#textcolor3559{color:rgb(0,0,255)} +span#textcolor3560{color:rgb(163,20,20)} +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(0,127,0)} +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(0,0,255)} +span#textcolor3571{color:rgb(163,20,20)} +span#textcolor3572{color:rgb(163,20,20)} +span#textcolor3573{color:rgb(163,20,20)} +span#textcolor3574{color:rgb(0,127,0)} +span#textcolor3575{color:rgb(0,0,255)} +span#textcolor3576{color:rgb(0,0,255)} +span#textcolor3577{color:rgb(43,145,175)} +span#textcolor3578{color:rgb(0,0,255)} +span#textcolor3579{color:rgb(163,20,20)} +span#textcolor3580{color:rgb(163,20,20)} +span#textcolor3581{color:rgb(163,20,20)} +span#textcolor3582{color:rgb(0,127,0)} +span#textcolor3583{color:rgb(0,0,255)} +span#textcolor3584{color:rgb(0,0,255)} +span#textcolor3585{color:rgb(43,145,175)} +span#textcolor3586{color:rgb(0,0,255)} +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(0,127,0)} +span#textcolor3591{color:rgb(0,0,255)} +span#textcolor3592{color:rgb(0,0,255)} +span#textcolor3593{color:rgb(0,0,255)} +span#textcolor3594{color:rgb(0,0,255)} +span#textcolor3595{color:rgb(0,0,255)} +span#textcolor3596{color:rgb(0,0,255)} +span#textcolor3597{color:rgb(163,20,20)} +span#textcolor3598{color:rgb(0,0,255)} +span#textcolor3599{color:rgb(43,145,175)} +span#textcolor3600{color:rgb(43,145,175)} +span#textcolor3601{color:rgb(43,145,175)} +span#textcolor3602{color:rgb(163,20,20)} +span#textcolor3603{color:rgb(163,20,20)} +span#textcolor3604{color:rgb(163,20,20)} +span#textcolor3605{color:rgb(0,0,255)} +span#textcolor3606{color:rgb(163,20,20)} +span#textcolor3607{color:rgb(163,20,20)} +span#textcolor3608{color:rgb(163,20,20)} +span#textcolor3609{color:rgb(0,0,255)} +span#textcolor3610{color:rgb(0,0,255)} +span#textcolor3611{color:rgb(0,0,255)} +span#textcolor3612{color:rgb(43,145,175)} +span#textcolor3613{color:rgb(43,145,175)} +span#textcolor3614{color:rgb(163,20,20)} +span#textcolor3615{color:rgb(163,20,20)} +span#textcolor3616{color:rgb(163,20,20)} +span#textcolor3617{color:rgb(163,20,20)} +span#textcolor3618{color:rgb(163,20,20)} 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#textcolor3481{color:rgb(0,0,255)} -span#textcolor3482{color:rgb(0,0,255)} -span#textcolor3483{color:rgb(0,0,255)} -span#textcolor3484{color:rgb(0,0,255)} +span#textcolor3619{color:rgb(0,0,255)} +span#textcolor3620{color:rgb(0,0,255)} +span#textcolor3621{color:rgb(0,0,255)} +span#textcolor3622{color:rgb(0,0,255)} pre#fancyvrb96{padding:5.69054pt;} pre#fancyvrb96{ border-top: solid 0.4pt; } pre#fancyvrb96{ border-left: solid 0.4pt; } @@ -4191,205 +4329,205 @@ 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#textcolor3485{color:rgb(163,20,20)} -span#textcolor3486{color:rgb(163,20,20)} -span#textcolor3487{color:rgb(163,20,20)} -span#textcolor3488{color:rgb(0,0,255)} -span#textcolor3489{color:rgb(163,20,20)} -span#textcolor3490{color:rgb(163,20,20)} -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#textcolor3623{color:rgb(163,20,20)} +span#textcolor3624{color:rgb(163,20,20)} +span#textcolor3625{color:rgb(163,20,20)} +span#textcolor3626{color:rgb(0,0,255)} +span#textcolor3627{color:rgb(163,20,20)} +span#textcolor3628{color:rgb(163,20,20)} +span#textcolor3629{color:rgb(163,20,20)} +span#textcolor3630{color:rgb(163,20,20)} +span#textcolor3631{color:rgb(163,20,20)} +span#textcolor3632{color:rgb(163,20,20)} pre#fancyvrb99{padding:5.69054pt;} pre#fancyvrb99{ border-top: solid 0.4pt; } pre#fancyvrb99{ border-left: solid 0.4pt; } pre#fancyvrb99{ border-bottom: solid 0.4pt; } pre#fancyvrb99{ border-right: solid 0.4pt; } -span#textcolor3495{color:rgb(0,127,0)} -span#textcolor3496{color:rgb(0,127,0)} -span#textcolor3497{color:rgb(0,127,0)} -span#textcolor3498{color:rgb(0,0,255)} -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(0,0,255)} -span#textcolor3555{color:rgb(0,0,255)} -span#textcolor3556{color:rgb(43,145,175)} -span#textcolor3557{color:rgb(43,145,175)} -span#textcolor3558{color:rgb(0,0,255)} -span#textcolor3559{color:rgb(163,20,20)} -span#textcolor3560{color:rgb(163,20,20)} -span#textcolor3561{color:rgb(163,20,20)} -span#textcolor3562{color:rgb(0,0,255)} -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(0,0,255)} -span#textcolor3567{color:rgb(0,0,255)} -span#textcolor3568{color:rgb(0,0,255)} -span#textcolor3569{color:rgb(163,20,20)} -span#textcolor3570{color:rgb(163,20,20)} -span#textcolor3571{color:rgb(163,20,20)} -span#textcolor3572{color:rgb(0,0,255)} -span#textcolor3573{color:rgb(0,0,255)} -span#textcolor3574{color:rgb(43,145,175)} -span#textcolor3575{color:rgb(43,145,175)} -span#textcolor3576{color:rgb(0,127,0)} -span#textcolor3577{color:rgb(0,127,0)} -span#textcolor3578{color:rgb(0,127,0)} -span#textcolor3579{color:rgb(0,127,0)} -span#textcolor3580{color:rgb(0,127,0)} -span#textcolor3581{color:rgb(0,127,0)} -span#textcolor3582{color:rgb(0,0,255)} -span#textcolor3583{color:rgb(43,145,175)} -span#textcolor3584{color:rgb(0,0,255)} -span#textcolor3585{color:rgb(0,0,255)} -span#textcolor3586{color:rgb(0,0,255)} -span#textcolor3587{color:rgb(0,0,255)} -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(163,20,20)} -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(0,0,255)} -span#textcolor3598{color:rgb(163,20,20)} -span#textcolor3599{color:rgb(163,20,20)} -span#textcolor3600{color:rgb(163,20,20)} -span#textcolor3601{color:rgb(163,20,20)} -span#textcolor3602{color:rgb(163,20,20)} -span#textcolor3603{color:rgb(163,20,20)} -span#textcolor3604{color:rgb(0,0,255)} -span#textcolor3605{color:rgb(0,127,0)} -span#textcolor3606{color:rgb(0,127,0)} -span#textcolor3607{color:rgb(0,127,0)} -span#textcolor3608{color:rgb(0,0,255)} -span#textcolor3609{color:rgb(43,145,175)} -span#textcolor3610{color:rgb(0,0,255)} -span#textcolor3611{color:rgb(0,0,255)} -span#textcolor3612{color:rgb(0,127,0)} -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(0,127,0)} -span#textcolor3619{color:rgb(0,127,0)} -span#textcolor3620{color:rgb(0,127,0)} -span#textcolor3621{color:rgb(0,127,0)} -span#textcolor3622{color:rgb(0,0,255)} -span#textcolor3623{color:rgb(43,145,175)} -span#textcolor3624{color:rgb(0,0,255)} -span#textcolor3625{color:rgb(0,127,0)} -span#textcolor3626{color:rgb(43,145,175)} -span#textcolor3627{color:rgb(0,127,0)} -span#textcolor3628{color:rgb(43,145,175)} -span#textcolor3629{color:rgb(0,127,0)} -span#textcolor3630{color:rgb(0,127,0)} -span#textcolor3631{color:rgb(43,145,175)} -span#textcolor3632{color:rgb(0,0,255)} -span#textcolor3633{color:rgb(43,145,175)} -span#textcolor3634{color:rgb(0,0,255)} +span#textcolor3633{color:rgb(0,127,0)} +span#textcolor3634{color:rgb(0,127,0)} span#textcolor3635{color:rgb(0,127,0)} -span#textcolor3636{color:rgb(0,127,0)} -span#textcolor3637{color:rgb(0,0,255)} -span#textcolor3638{color:rgb(0,127,0)} +span#textcolor3636{color:rgb(0,0,255)} +span#textcolor3637{color:rgb(0,127,0)} +span#textcolor3638{color:rgb(0,0,255)} span#textcolor3639{color:rgb(0,127,0)} span#textcolor3640{color:rgb(0,0,255)} span#textcolor3641{color:rgb(0,127,0)} -span#textcolor3642{color:rgb(0,127,0)} +span#textcolor3642{color:rgb(0,0,255)} span#textcolor3643{color:rgb(0,127,0)} -span#textcolor3644{color:rgb(0,127,0)} +span#textcolor3644{color:rgb(0,0,255)} span#textcolor3645{color:rgb(0,127,0)} -span#textcolor3646{color:rgb(0,127,0)} +span#textcolor3646{color:rgb(0,0,255)} span#textcolor3647{color:rgb(0,127,0)} span#textcolor3648{color:rgb(0,0,255)} span#textcolor3649{color:rgb(0,127,0)} span#textcolor3650{color:rgb(0,0,255)} -span#textcolor3651{color:rgb(43,145,175)} +span#textcolor3651{color:rgb(0,127,0)} span#textcolor3652{color:rgb(0,0,255)} -span#textcolor3653{color:rgb(0,0,255)} -span#textcolor3654{color:rgb(43,145,175)} -span#textcolor3655{color:rgb(43,145,175)} -span#textcolor3656{color:rgb(43,145,175)} -span#textcolor3657{color:rgb(0,0,255)} -span#textcolor3658{color:rgb(163,20,20)} -span#textcolor3659{color:rgb(163,20,20)} -span#textcolor3660{color:rgb(163,20,20)} +span#textcolor3653{color:rgb(0,127,0)} +span#textcolor3654{color:rgb(0,0,255)} +span#textcolor3655{color:rgb(0,127,0)} +span#textcolor3656{color:rgb(0,0,255)} +span#textcolor3657{color:rgb(0,127,0)} +span#textcolor3658{color:rgb(0,0,255)} +span#textcolor3659{color:rgb(43,145,175)} +span#textcolor3660{color:rgb(0,0,255)} span#textcolor3661{color:rgb(0,0,255)} span#textcolor3662{color:rgb(0,0,255)} -span#textcolor3663{color:rgb(0,0,255)} +span#textcolor3663{color:rgb(43,145,175)} span#textcolor3664{color:rgb(0,0,255)} -span#textcolor3665{color:rgb(163,20,20)} -span#textcolor3666{color:rgb(163,20,20)} -span#textcolor3667{color:rgb(0,0,255)} +span#textcolor3665{color:rgb(0,0,255)} +span#textcolor3666{color:rgb(0,0,255)} +span#textcolor3667{color:rgb(43,145,175)} span#textcolor3668{color:rgb(0,0,255)} -span#textcolor3669{color:rgb(163,20,20)} -span#textcolor3670{color:rgb(163,20,20)} +span#textcolor3669{color:rgb(43,145,175)} +span#textcolor3670{color:rgb(43,145,175)} span#textcolor3671{color:rgb(0,0,255)} -span#textcolor3672{color:rgb(163,20,20)} -span#textcolor3673{color:rgb(163,20,20)} -span#textcolor3674{color:rgb(163,20,20)} -span#textcolor3675{color:rgb(0,0,255)} -span#textcolor3676{color:rgb(0,127,0)} +span#textcolor3672{color:rgb(43,145,175)} +span#textcolor3673{color:rgb(0,0,255)} +span#textcolor3674{color:rgb(0,0,255)} +span#textcolor3675{color:rgb(43,145,175)} +span#textcolor3676{color:rgb(43,145,175)} span#textcolor3677{color:rgb(0,0,255)} -span#textcolor3678{color:rgb(163,20,20)} +span#textcolor3678{color:rgb(0,0,255)} +span#textcolor3679{color:rgb(0,0,255)} +span#textcolor3680{color:rgb(0,0,255)} +span#textcolor3681{color:rgb(43,145,175)} +span#textcolor3682{color:rgb(0,0,255)} +span#textcolor3683{color:rgb(0,0,255)} +span#textcolor3684{color:rgb(0,0,255)} +span#textcolor3685{color:rgb(43,145,175)} +span#textcolor3686{color:rgb(0,0,255)} +span#textcolor3687{color:rgb(0,0,255)} +span#textcolor3688{color:rgb(0,0,255)} +span#textcolor3689{color:rgb(0,0,255)} +span#textcolor3690{color:rgb(0,0,255)} +span#textcolor3691{color:rgb(0,0,255)} +span#textcolor3692{color:rgb(0,0,255)} +span#textcolor3693{color:rgb(0,0,255)} +span#textcolor3694{color:rgb(43,145,175)} +span#textcolor3695{color:rgb(43,145,175)} +span#textcolor3696{color:rgb(0,0,255)} +span#textcolor3697{color:rgb(163,20,20)} +span#textcolor3698{color:rgb(163,20,20)} +span#textcolor3699{color:rgb(163,20,20)} +span#textcolor3700{color:rgb(0,0,255)} +span#textcolor3701{color:rgb(163,20,20)} +span#textcolor3702{color:rgb(163,20,20)} +span#textcolor3703{color:rgb(163,20,20)} +span#textcolor3704{color:rgb(0,0,255)} +span#textcolor3705{color:rgb(0,0,255)} +span#textcolor3706{color:rgb(0,0,255)} +span#textcolor3707{color:rgb(163,20,20)} +span#textcolor3708{color:rgb(163,20,20)} +span#textcolor3709{color:rgb(163,20,20)} +span#textcolor3710{color:rgb(0,0,255)} +span#textcolor3711{color:rgb(0,0,255)} +span#textcolor3712{color:rgb(43,145,175)} +span#textcolor3713{color:rgb(43,145,175)} +span#textcolor3714{color:rgb(0,127,0)} +span#textcolor3715{color:rgb(0,127,0)} +span#textcolor3716{color:rgb(0,127,0)} +span#textcolor3717{color:rgb(0,127,0)} +span#textcolor3718{color:rgb(0,127,0)} +span#textcolor3719{color:rgb(0,127,0)} +span#textcolor3720{color:rgb(0,0,255)} +span#textcolor3721{color:rgb(43,145,175)} +span#textcolor3722{color:rgb(0,0,255)} +span#textcolor3723{color:rgb(0,0,255)} +span#textcolor3724{color:rgb(0,0,255)} +span#textcolor3725{color:rgb(0,0,255)} +span#textcolor3726{color:rgb(163,20,20)} +span#textcolor3727{color:rgb(163,20,20)} +span#textcolor3728{color:rgb(163,20,20)} +span#textcolor3729{color:rgb(163,20,20)} +span#textcolor3730{color:rgb(163,20,20)} +span#textcolor3731{color:rgb(163,20,20)} +span#textcolor3732{color:rgb(163,20,20)} +span#textcolor3733{color:rgb(163,20,20)} +span#textcolor3734{color:rgb(163,20,20)} +span#textcolor3735{color:rgb(0,0,255)} +span#textcolor3736{color:rgb(163,20,20)} +span#textcolor3737{color:rgb(163,20,20)} +span#textcolor3738{color:rgb(163,20,20)} +span#textcolor3739{color:rgb(163,20,20)} +span#textcolor3740{color:rgb(163,20,20)} +span#textcolor3741{color:rgb(163,20,20)} +span#textcolor3742{color:rgb(0,0,255)} +span#textcolor3743{color:rgb(0,127,0)} +span#textcolor3744{color:rgb(0,127,0)} +span#textcolor3745{color:rgb(0,127,0)} +span#textcolor3746{color:rgb(0,0,255)} +span#textcolor3747{color:rgb(43,145,175)} +span#textcolor3748{color:rgb(0,0,255)} +span#textcolor3749{color:rgb(0,0,255)} +span#textcolor3750{color:rgb(0,127,0)} +span#textcolor3751{color:rgb(0,127,0)} +span#textcolor3752{color:rgb(0,127,0)} +span#textcolor3753{color:rgb(0,127,0)} +span#textcolor3754{color:rgb(0,127,0)} +span#textcolor3755{color:rgb(0,0,255)} +span#textcolor3756{color:rgb(0,127,0)} +span#textcolor3757{color:rgb(0,127,0)} +span#textcolor3758{color:rgb(0,127,0)} +span#textcolor3759{color:rgb(0,127,0)} +span#textcolor3760{color:rgb(0,0,255)} +span#textcolor3761{color:rgb(43,145,175)} +span#textcolor3762{color:rgb(0,0,255)} +span#textcolor3763{color:rgb(0,127,0)} +span#textcolor3764{color:rgb(43,145,175)} +span#textcolor3765{color:rgb(0,127,0)} +span#textcolor3766{color:rgb(43,145,175)} +span#textcolor3767{color:rgb(0,127,0)} +span#textcolor3768{color:rgb(0,127,0)} +span#textcolor3769{color:rgb(43,145,175)} +span#textcolor3770{color:rgb(0,0,255)} +span#textcolor3771{color:rgb(43,145,175)} +span#textcolor3772{color:rgb(0,0,255)} +span#textcolor3773{color:rgb(0,127,0)} +span#textcolor3774{color:rgb(0,127,0)} +span#textcolor3775{color:rgb(0,0,255)} +span#textcolor3776{color:rgb(0,127,0)} +span#textcolor3777{color:rgb(0,127,0)} +span#textcolor3778{color:rgb(0,0,255)} +span#textcolor3779{color:rgb(0,127,0)} +span#textcolor3780{color:rgb(0,127,0)} +span#textcolor3781{color:rgb(0,127,0)} +span#textcolor3782{color:rgb(0,127,0)} +span#textcolor3783{color:rgb(0,127,0)} +span#textcolor3784{color:rgb(0,127,0)} +span#textcolor3785{color:rgb(0,127,0)} +span#textcolor3786{color:rgb(0,0,255)} +span#textcolor3787{color:rgb(0,127,0)} +span#textcolor3788{color:rgb(0,0,255)} +span#textcolor3789{color:rgb(43,145,175)} +span#textcolor3790{color:rgb(0,0,255)} +span#textcolor3791{color:rgb(0,0,255)} +span#textcolor3792{color:rgb(43,145,175)} +span#textcolor3793{color:rgb(43,145,175)} +span#textcolor3794{color:rgb(43,145,175)} +span#textcolor3795{color:rgb(0,0,255)} +span#textcolor3796{color:rgb(163,20,20)} +span#textcolor3797{color:rgb(163,20,20)} +span#textcolor3798{color:rgb(163,20,20)} +span#textcolor3799{color:rgb(0,0,255)} +span#textcolor3800{color:rgb(0,0,255)} +span#textcolor3801{color:rgb(0,0,255)} +span#textcolor3802{color:rgb(0,0,255)} +span#textcolor3803{color:rgb(163,20,20)} +span#textcolor3804{color:rgb(163,20,20)} +span#textcolor3805{color:rgb(0,0,255)} +span#textcolor3806{color:rgb(0,0,255)} +span#textcolor3807{color:rgb(163,20,20)} +span#textcolor3808{color:rgb(163,20,20)} +span#textcolor3809{color:rgb(0,0,255)} +span#textcolor3810{color:rgb(163,20,20)} +span#textcolor3811{color:rgb(163,20,20)} +span#textcolor3812{color:rgb(163,20,20)} +span#textcolor3813{color:rgb(0,0,255)} +span#textcolor3814{color:rgb(0,127,0)} +span#textcolor3815{color:rgb(0,0,255)} +span#textcolor3816{color:rgb(163,20,20)} pre#fancyvrb100{padding:5.69054pt;} pre#fancyvrb100{ border-top: solid 0.4pt; } pre#fancyvrb100{ border-left: solid 0.4pt; } diff --git a/lkmpg-for-ht.html b/lkmpg-for-ht.html index d40de12..970470d 100644 --- a/lkmpg-for-ht.html +++ b/lkmpg-for-ht.html @@ -5174,136 +5174,200 @@ appropriate for your board. 13#include <linux/kernel.h> /* for ARRAY_SIZE() */ 14#include <linux/module.h> 15#include <linux/printk.h> -16 -17static int button_irqs[] = { -1, -1 }; -18 -19/* Define GPIOs for LEDs. -20 * TODO: Change the numbers for the GPIO on your board. -21 */ -22static struct gpio leds[] = { { 4, GPIOF_OUT_INIT_LOW, "LED 1" } }; +16#include <linux/version.h> +17 +18#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) +19#define NO_GPIO_REQUEST_ARRAY +20#endif +21 +22static int button_irqs[] = { -1, -1 }; 23 -24/* Define GPIOs for BUTTONS -25 * TODO: Change the numbers for the GPIO on your board. -26 */ -27static struct gpio buttons[] = { { 17, GPIOF_IN, "LED 1 ON BUTTON" }, -28 { 18, GPIOF_IN, "LED 1 OFF BUTTON" } }; -29 -30/* interrupt function triggered when a button is pressed. */ -31static irqreturn_t button_isr(int irq, void *data) -32{ -33 /* first button */ -34 if (irq == button_irqs[0] && !gpio_get_value(leds[0].gpio)) -35 gpio_set_value(leds[0].gpio, 1); -36 /* second button */ -37 else if (irq == button_irqs[1] && gpio_get_value(leds[0].gpio)) -38 gpio_set_value(leds[0].gpio, 0); -39 -40 return IRQ_HANDLED; -41} -42 -43static int __init intrpt_init(void) -44{ -45 int ret = 0; -46 -47 pr_info("%s\n", __func__); -48 -49 /* register LED gpios */ -50 ret = gpio_request_array(leds, ARRAY_SIZE(leds)); +24/* Define GPIOs for LEDs. +25 * TODO: Change the numbers for the GPIO on your board. +26 */ +27static struct gpio leds[] = { { 4, GPIOF_OUT_INIT_LOW, "LED 1" } }; +28 +29/* Define GPIOs for BUTTONS +30 * TODO: Change the numbers for the GPIO on your board. +31 */ +32static struct gpio buttons[] = { { 17, GPIOF_IN, "LED 1 ON BUTTON" }, +33 { 18, GPIOF_IN, "LED 1 OFF BUTTON" } }; +34 +35/* interrupt function triggered when a button is pressed. */ +36static irqreturn_t button_isr(int irq, void *data) +37{ +38 /* first button */ +39 if (irq == button_irqs[0] && !gpio_get_value(leds[0].gpio)) +40 gpio_set_value(leds[0].gpio, 1); +41 /* second button */ +42 else if (irq == button_irqs[1] && gpio_get_value(leds[0].gpio)) +43 gpio_set_value(leds[0].gpio, 0); +44 +45 return IRQ_HANDLED; +46} +47 +48static int __init intrpt_init(void) +49{ +50 int ret = 0; 51 -52 if (ret) { -53 pr_err("Unable to request GPIOs for LEDs: %d\n", ret); -54 return ret; -55 } -56 -57 /* register BUTTON gpios */ -58 ret = gpio_request_array(buttons, ARRAY_SIZE(buttons)); -59 -60 if (ret) { -61 pr_err("Unable to request GPIOs for BUTTONs: %d\n", ret); -62 goto fail1; -63 } -64 -65 pr_info("Current button1 value: %d\n", gpio_get_value(buttons[0].gpio)); -66 -67 ret = gpio_to_irq(buttons[0].gpio); -68 -69 if (ret < 0) { -70 pr_err("Unable to request IRQ: %d\n", ret); -71 goto fail2; -72 } -73 -74 button_irqs[0] = ret; -75 -76 pr_info("Successfully requested BUTTON1 IRQ # %d\n", button_irqs[0]); -77 -78 ret = request_irq(button_irqs[0], button_isr, -79 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, -80 "gpiomod#button1", NULL); -81 -82 if (ret) { -83 pr_err("Unable to request IRQ: %d\n", ret); -84 goto fail2; -85 } -86 -87 ret = gpio_to_irq(buttons[1].gpio); -88 -89 if (ret < 0) { -90 pr_err("Unable to request IRQ: %d\n", ret); -91 goto fail2; -92 } +52 pr_info("%s\n", __func__); +53 +54 /* register LED gpios */ +55#ifdef NO_GPIO_REQUEST_ARRAY +56 ret = gpio_request(leds[0].gpio, leds[0].label); +57#else +58 ret = gpio_request_array(leds, ARRAY_SIZE(leds)); +59#endif +60 +61 if (ret) { +62 pr_err("Unable to request GPIOs for LEDs: %d\n", ret); +63 return ret; +64 } +65 +66 /* register BUTTON gpios */ +67#ifdef NO_GPIO_REQUEST_ARRAY +68 ret = gpio_request(buttons[0].gpio, buttons[0].label); +69 +70 if (ret) { +71 pr_err("Unable to request GPIOs for BUTTONs: %d\n", ret); +72 goto fail1; +73 } +74 +75 ret = gpio_request(buttons[1].gpio, buttons[1].label); +76 +77 if (ret) { +78 pr_err("Unable to request GPIOs for BUTTONs: %d\n", ret); +79 goto fail2; +80 } +81#else +82 ret = gpio_request_array(buttons, ARRAY_SIZE(buttons)); +83 +84 if (ret) { +85 pr_err("Unable to request GPIOs for BUTTONs: %d\n", ret); +86 goto fail1; +87 } +88#endif +89 +90 pr_info("Current button1 value: %d\n", gpio_get_value(buttons[0].gpio)); +91 +92 ret = gpio_to_irq(buttons[0].gpio); 93 -94 button_irqs[1] = ret; -95 -96 pr_info("Successfully requested BUTTON2 IRQ # %d\n", button_irqs[1]); -97 -98 ret = request_irq(button_irqs[1], button_isr, -99 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, -100 "gpiomod#button2", NULL); -101 -102 if (ret) { -103 pr_err("Unable to request IRQ: %d\n", ret); -104 goto fail3; -105 } +94 if (ret < 0) { +95 pr_err("Unable to request IRQ: %d\n", ret); +96#ifdef NO_GPIO_REQUEST_ARRAY +97 goto fail3; +98#else +99 goto fail2; +100#endif +101 } +102 +103 button_irqs[0] = ret; +104 +105 pr_info("Successfully requested BUTTON1 IRQ # %d\n", button_irqs[0]); 106 -107 return 0; -108 -109/* cleanup what has been setup so far */ -110fail3: -111 free_irq(button_irqs[0], NULL); -112 -113fail2: -114 gpio_free_array(buttons, ARRAY_SIZE(leds)); -115 -116fail1: -117 gpio_free_array(leds, ARRAY_SIZE(leds)); -118 -119 return ret; -120} +107 ret = request_irq(button_irqs[0], button_isr, +108 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, +109 "gpiomod#button1", NULL); +110 +111 if (ret) { +112 pr_err("Unable to request IRQ: %d\n", ret); +113#ifdef NO_GPIO_REQUEST_ARRAY +114 goto fail3; +115#else +116 goto fail2; +117#endif +118 } +119 +120 ret = gpio_to_irq(buttons[1].gpio); 121 -122static void __exit intrpt_exit(void) -123{ -124 int i; -125 -126 pr_info("%s\n", __func__); -127 -128 /* free irqs */ -129 free_irq(button_irqs[0], NULL); -130 free_irq(button_irqs[1], NULL); -131 -132 /* turn all LEDs off */ -133 for (i = 0; i < ARRAY_SIZE(leds); i++) -134 gpio_set_value(leds[i].gpio, 0); -135 -136 /* unregister */ -137 gpio_free_array(leds, ARRAY_SIZE(leds)); -138 gpio_free_array(buttons, ARRAY_SIZE(buttons)); -139} -140 -141module_init(intrpt_init); -142module_exit(intrpt_exit); -143 -144MODULE_LICENSE("GPL"); -145MODULE_DESCRIPTION("Handle some GPIO interrupts");
@@ -5318,174 +5382,238 @@ scheduler. when an interrupt is triggered.
-
1/* -2 * bottomhalf.c - Top and bottom half interrupt handling -3 * -4 * Based upon the RPi example by Stefan Wendler (devnull@kaltpost.de) -5 * from: -6 * https://github.com/wendlers/rpi-kmod-samples -7 * -8 * Press one button to turn on an LED and another to turn it off -9 */ +1/* +2 * bottomhalf.c - Top and bottom half interrupt handling +3 * +4 * Based upon the RPi example by Stefan Wendler (devnull@kaltpost.de) +5 * from: +6 * https://github.com/wendlers/rpi-kmod-samples +7 * +8 * Press one button to turn on an LED and another to turn it off +9 */ 10 -11#include <linux/delay.h> -12#include <linux/gpio.h> -13#include <linux/interrupt.h> -14#include <linux/module.h> -15#include <linux/printk.h> -16#include <linux/init.h> -17 -18/* Macro DECLARE_TASKLET_OLD exists for compatibility. -19 * See https://lwn.net/Articles/830964/ -20 */ -21#ifndef DECLARE_TASKLET_OLD -22#define DECLARE_TASKLET_OLD(arg1, arg2) DECLARE_TASKLET(arg1, arg2, 0L) -23#endif -24 -25static int button_irqs[] = { -1, -1 }; -26 -27/* Define GPIOs for LEDs. -28 * TODO: Change the numbers for the GPIO on your board. -29 */ -30static struct gpio leds[] = { { 4, GPIOF_OUT_INIT_LOW, "LED 1" } }; +11#include <linux/delay.h> +12#include <linux/gpio.h> +13#include <linux/interrupt.h> +14#include <linux/module.h> +15#include <linux/printk.h> +16#include <linux/init.h> +17#include <linux/version.h> +18 +19#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) +20#define NO_GPIO_REQUEST_ARRAY +21#endif +22 +23/* Macro DECLARE_TASKLET_OLD exists for compatibility. +24 * See https://lwn.net/Articles/830964/ +25 */ +26#ifndef DECLARE_TASKLET_OLD +27#define DECLARE_TASKLET_OLD(arg1, arg2) DECLARE_TASKLET(arg1, arg2, 0L) +28#endif +29 +30static int button_irqs[] = { -1, -1 }; 31 -32/* Define GPIOs for BUTTONS -33 * TODO: Change the numbers for the GPIO on your board. -34 */ -35static struct gpio buttons[] = { -36 { 17, GPIOF_IN, "LED 1 ON BUTTON" }, -37 { 18, GPIOF_IN, "LED 1 OFF BUTTON" }, -38}; -39 -40/* Tasklet containing some non-trivial amount of processing */ -41static void bottomhalf_tasklet_fn(unsigned long data) -42{ -43 pr_info("Bottom half tasklet starts\n"); -44 /* do something which takes a while */ -45 mdelay(500); -46 pr_info("Bottom half tasklet ends\n"); -47} -48 -49static DECLARE_TASKLET_OLD(buttontask, bottomhalf_tasklet_fn); -50 -51/* interrupt function triggered when a button is pressed */ -52static irqreturn_t button_isr(int irq, void *data) -53{ -54 /* Do something quickly right now */ -55 if (irq == button_irqs[0] && !gpio_get_value(leds[0].gpio)) -56 gpio_set_value(leds[0].gpio, 1); -57 else if (irq == button_irqs[1] && gpio_get_value(leds[0].gpio)) -58 gpio_set_value(leds[0].gpio, 0); -59 -60 /* Do the rest at leisure via the scheduler */ -61 tasklet_schedule(&buttontask); -62 -63 return IRQ_HANDLED; -64} -65 -66static int __init bottomhalf_init(void) -67{ -68 int ret = 0; -69 -70 pr_info("%s\n", __func__); -71 -72 /* register LED gpios */ -73 ret = gpio_request_array(leds, ARRAY_SIZE(leds)); +32/* Define GPIOs for LEDs. +33 * TODO: Change the numbers for the GPIO on your board. +34 */ +35static struct gpio leds[] = { { 4, GPIOF_OUT_INIT_LOW, "LED 1" } }; +36 +37/* Define GPIOs for BUTTONS +38 * TODO: Change the numbers for the GPIO on your board. +39 */ +40static struct gpio buttons[] = { +41 { 17, GPIOF_IN, "LED 1 ON BUTTON" }, +42 { 18, GPIOF_IN, "LED 1 OFF BUTTON" }, +43}; +44 +45/* Tasklet containing some non-trivial amount of processing */ +46static void bottomhalf_tasklet_fn(unsigned long data) +47{ +48 pr_info("Bottom half tasklet starts\n"); +49 /* do something which takes a while */ +50 mdelay(500); +51 pr_info("Bottom half tasklet ends\n"); +52} +53 +54static DECLARE_TASKLET_OLD(buttontask, bottomhalf_tasklet_fn); +55 +56/* interrupt function triggered when a button is pressed */ +57static irqreturn_t button_isr(int irq, void *data) +58{ +59 /* Do something quickly right now */ +60 if (irq == button_irqs[0] && !gpio_get_value(leds[0].gpio)) +61 gpio_set_value(leds[0].gpio, 1); +62 else if (irq == button_irqs[1] && gpio_get_value(leds[0].gpio)) +63 gpio_set_value(leds[0].gpio, 0); +64 +65 /* Do the rest at leisure via the scheduler */ +66 tasklet_schedule(&buttontask); +67 +68 return IRQ_HANDLED; +69} +70 +71static int __init bottomhalf_init(void) +72{ +73 int ret = 0; 74 -75 if (ret) { -76 pr_err("Unable to request GPIOs for LEDs: %d\n", ret); -77 return ret; -78 } -79 -80 /* register BUTTON gpios */ -81 ret = gpio_request_array(buttons, ARRAY_SIZE(buttons)); -82 -83 if (ret) { -84 pr_err("Unable to request GPIOs for BUTTONs: %d\n", ret); -85 goto fail1; -86 } -87 -88 pr_info("Current button1 value: %d\n", gpio_get_value(buttons[0].gpio)); -89 -90 ret = gpio_to_irq(buttons[0].gpio); -91 -92 if (ret < 0) { -93 pr_err("Unable to request IRQ: %d\n", ret); -94 goto fail2; -95 } -96 -97 button_irqs[0] = ret; -98 -99 pr_info("Successfully requested BUTTON1 IRQ # %d\n", button_irqs[0]); -100 -101 ret = request_irq(button_irqs[0], button_isr, -102 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, -103 "gpiomod#button1", NULL); -104 -105 if (ret) { -106 pr_err("Unable to request IRQ: %d\n", ret); -107 goto fail2; -108 } -109 -110 ret = gpio_to_irq(buttons[1].gpio); -111 -112 if (ret < 0) { -113 pr_err("Unable to request IRQ: %d\n", ret); -114 goto fail2; -115 } +75 pr_info("%s\n", __func__); +76 +77 /* register LED gpios */ +78#ifdef NO_GPIO_REQUEST_ARRAY +79 ret = gpio_request(leds[0].gpio, leds[0].label); +80#else +81 ret = gpio_request_array(leds, ARRAY_SIZE(leds)); +82#endif +83 +84 if (ret) { +85 pr_err("Unable to request GPIOs for LEDs: %d\n", ret); +86 return ret; +87 } +88 +89 /* register BUTTON gpios */ +90#ifdef NO_GPIO_REQUEST_ARRAY +91 ret = gpio_request(buttons[0].gpio, buttons[0].label); +92 +93 if (ret) { +94 pr_err("Unable to request GPIOs for BUTTONs: %d\n", ret); +95 goto fail1; +96 } +97 +98 ret = gpio_request(buttons[1].gpio, buttons[1].label); +99 +100 if (ret) { +101 pr_err("Unable to request GPIOs for BUTTONs: %d\n", ret); +102 goto fail2; +103 } +104#else +105 ret = gpio_request_array(buttons, ARRAY_SIZE(buttons)); +106 +107 if (ret) { +108 pr_err("Unable to request GPIOs for BUTTONs: %d\n", ret); +109 goto fail1; +110 } +111#endif +112 +113 pr_info("Current button1 value: %d\n", gpio_get_value(buttons[0].gpio)); +114 +115 ret = gpio_to_irq(buttons[0].gpio); 116 -117 button_irqs[1] = ret; -118 -119 pr_info("Successfully requested BUTTON2 IRQ # %d\n", button_irqs[1]); -120 -121 ret = request_irq(button_irqs[1], button_isr, -122 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, -123 "gpiomod#button2", NULL); -124 -125 if (ret) { -126 pr_err("Unable to request IRQ: %d\n", ret); -127 goto fail3; -128 } +117 if (ret < 0) { +118 pr_err("Unable to request IRQ: %d\n", ret); +119#ifdef NO_GPIO_REQUEST_ARRAY +120 goto fail3; +121#else +122 goto fail2; +123#endif +124 } +125 +126 button_irqs[0] = ret; +127 +128 pr_info("Successfully requested BUTTON1 IRQ # %d\n", button_irqs[0]); 129 -130 return 0; -131 -132/* cleanup what has been setup so far */ -133fail3: -134 free_irq(button_irqs[0], NULL); -135 -136fail2: -137 gpio_free_array(buttons, ARRAY_SIZE(leds)); -138 -139fail1: -140 gpio_free_array(leds, ARRAY_SIZE(leds)); -141 -142 return ret; -143} +130 ret = request_irq(button_irqs[0], button_isr, +131 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, +132 "gpiomod#button1", NULL); +133 +134 if (ret) { +135 pr_err("Unable to request IRQ: %d\n", ret); +136#ifdef NO_GPIO_REQUEST_ARRAY +137 goto fail3; +138#else +139 goto fail2; +140#endif +141 } +142 +143 ret = gpio_to_irq(buttons[1].gpio); 144 -145static void __exit bottomhalf_exit(void) -146{ -147 int i; -148 -149 pr_info("%s\n", __func__); -150 -151 /* free irqs */ -152 free_irq(button_irqs[0], NULL); -153 free_irq(button_irqs[1], NULL); -154 -155 /* turn all LEDs off */ -156 for (i = 0; i < ARRAY_SIZE(leds); i++) -157 gpio_set_value(leds[i].gpio, 0); -158 -159 /* unregister */ -160 gpio_free_array(leds, ARRAY_SIZE(leds)); -161 gpio_free_array(buttons, ARRAY_SIZE(buttons)); -162} -163 -164module_init(bottomhalf_init); -165module_exit(bottomhalf_exit); -166 -167MODULE_LICENSE("GPL"); -168MODULE_DESCRIPTION("Interrupt with top and bottom half");+145 if (ret < 0) { +146 pr_err("Unable to request IRQ: %d\n", ret); +147#ifdef NO_GPIO_REQUEST_ARRAY +148 goto fail3; +149#else +150 goto fail2; +151#endif +152 } +153 +154 button_irqs[1] = ret; +155 +156 pr_info("Successfully requested BUTTON2 IRQ # %d\n", button_irqs[1]); +157 +158 ret = request_irq(button_irqs[1], button_isr, +159 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, +160 "gpiomod#button2", NULL); +161 +162 if (ret) { +163 pr_err("Unable to request IRQ: %d\n", ret); +164#ifdef NO_GPIO_REQUEST_ARRAY +165 goto fail4; +166#else +167 goto fail3; +168#endif +169 } +170 +171 return 0; +172 +173/* cleanup what has been setup so far */ +174#ifdef NO_GPIO_REQUEST_ARRAY +175fail4: +176 free_irq(button_irqs[0], NULL); +177 +178fail3: +179 gpio_free(buttons[1].gpio); +180 +181fail2: +182 gpio_free(buttons[0].gpio); +183 +184fail1: +185 gpio_free(leds[0].gpio); +186#else +187fail3: +188 free_irq(button_irqs[0], NULL); +189 +190fail2: +191 gpio_free_array(buttons, ARRAY_SIZE(leds)); +192 +193fail1: +194 gpio_free_array(leds, ARRAY_SIZE(leds)); +195#endif +196 +197 return ret; +198} +199 +200static void __exit bottomhalf_exit(void) +201{ +202 pr_info("%s\n", __func__); +203 +204 /* free irqs */ +205 free_irq(button_irqs[0], NULL); +206 free_irq(button_irqs[1], NULL); +207 +208 /* turn all LEDs off */ +209#ifdef NO_GPIO_REQUEST_ARRAY +210 gpio_set_value(leds[0].gpio, 0); +211#else +212 int i; +213 for (i = 0; i < ARRAY_SIZE(leds); i++) +214 gpio_set_value(leds[i].gpio, 0); +215#endif +216 +217 /* unregister */ +218#ifdef NO_GPIO_REQUEST_ARRAY +219 gpio_free(leds[0].gpio); +220 gpio_free(buttons[0].gpio); +221 gpio_free(buttons[1].gpio); +222#else +223 gpio_free_array(leds, ARRAY_SIZE(leds)); +224 gpio_free_array(buttons, ARRAY_SIZE(buttons)); +225#endif +226} +227 +228module_init(bottomhalf_init); +229module_exit(bottomhalf_exit); +230 +231MODULE_LICENSE("GPL"); +232MODULE_DESCRIPTION("Interrupt with top and bottom half");
-
1/* -2 * bh_thread.c - Top and bottom half interrupt handling -3 * -4 * Based upon the RPi example by Stefan Wendler (devnull@kaltpost.de) -5 * from: -6 * https://github.com/wendlers/rpi-kmod-samples -7 * -8 * Press one button to turn on a LED and another to turn it off -9 */ +1/* +2 * bh_thread.c - Top and bottom half interrupt handling +3 * +4 * Based upon the RPi example by Stefan Wendler (devnull@kaltpost.de) +5 * from: +6 * https://github.com/wendlers/rpi-kmod-samples +7 * +8 * Press one button to turn on a LED and another to turn it off +9 */ 10 -11#include <linux/module.h> -12#include <linux/kernel.h> -13#include <linux/gpio.h> -14#include <linux/delay.h> -15#include <linux/interrupt.h> -16 -17static int button_irqs[] = { -1, -1 }; -18 -19/* Define GPIOs for LEDs. -20 * FIXME: Change the numbers for the GPIO on your board. -21 */ -22static struct gpio leds[] = { { 4, GPIOF_OUT_INIT_LOW, "LED 1" } }; +11#include <linux/module.h> +12#include <linux/kernel.h> +13#include <linux/gpio.h> +14#include <linux/delay.h> +15#include <linux/interrupt.h> +16#include <linux/version.h> +17 +18#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) +19#define NO_GPIO_REQUEST_ARRAY +20#endif +21 +22static int button_irqs[] = { -1, -1 }; 23 -24/* Define GPIOs for BUTTONS -25 * FIXME: Change the numbers for the GPIO on your board. -26 */ -27static struct gpio buttons[] = { -28 { 17, GPIOF_IN, "LED 1 ON BUTTON" }, -29 { 18, GPIOF_IN, "LED 1 OFF BUTTON" }, -30}; -31 -32/* This happens immediately, when the IRQ is triggered */ -33static irqreturn_t button_top_half(int irq, void *ident) -34{ -35 return IRQ_WAKE_THREAD; -36} -37 -38/* This can happen at leisure, freeing up IRQs for other high priority task */ -39static irqreturn_t button_bottom_half(int irq, void *ident) -40{ -41 pr_info("Bottom half task starts\n"); -42 mdelay(500); /* do something which takes a while */ -43 pr_info("Bottom half task ends\n"); -44 return IRQ_HANDLED; -45} -46 -47static int __init bottomhalf_init(void) -48{ -49 int ret = 0; -50 -51 pr_info("%s\n", __func__); -52 -53 /* register LED gpios */ -54 ret = gpio_request_array(leds, ARRAY_SIZE(leds)); +24/* Define GPIOs for LEDs. +25 * FIXME: Change the numbers for the GPIO on your board. +26 */ +27static struct gpio leds[] = { { 4, GPIOF_OUT_INIT_LOW, "LED 1" } }; +28 +29/* Define GPIOs for BUTTONS +30 * FIXME: Change the numbers for the GPIO on your board. +31 */ +32static struct gpio buttons[] = { +33 { 17, GPIOF_IN, "LED 1 ON BUTTON" }, +34 { 18, GPIOF_IN, "LED 1 OFF BUTTON" }, +35}; +36 +37/* This happens immediately, when the IRQ is triggered */ +38static irqreturn_t button_top_half(int irq, void *ident) +39{ +40 return IRQ_WAKE_THREAD; +41} +42 +43/* This can happen at leisure, freeing up IRQs for other high priority task */ +44static irqreturn_t button_bottom_half(int irq, void *ident) +45{ +46 pr_info("Bottom half task starts\n"); +47 mdelay(500); /* do something which takes a while */ +48 pr_info("Bottom half task ends\n"); +49 return IRQ_HANDLED; +50} +51 +52static int __init bottomhalf_init(void) +53{ +54 int ret = 0; 55 -56 if (ret) { -57 pr_err("Unable to request GPIOs for LEDs: %d\n", ret); -58 return ret; -59 } -60 -61 /* register BUTTON gpios */ -62 ret = gpio_request_array(buttons, ARRAY_SIZE(buttons)); -63 -64 if (ret) { -65 pr_err("Unable to request GPIOs for BUTTONs: %d\n", ret); -66 goto fail1; -67 } -68 -69 pr_info("Current button1 value: %d\n", gpio_get_value(buttons[0].gpio)); -70 -71 ret = gpio_to_irq(buttons[0].gpio); -72 -73 if (ret < 0) { -74 pr_err("Unable to request IRQ: %d\n", ret); -75 goto fail2; -76 } -77 -78 button_irqs[0] = ret; -79 -80 pr_info("Successfully requested BUTTON1 IRQ # %d\n", button_irqs[0]); -81 -82 ret = request_threaded_irq(button_irqs[0], button_top_half, -83 button_bottom_half, -84 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, -85 "gpiomod#button1", &buttons[0]); -86 -87 if (ret) { -88 pr_err("Unable to request IRQ: %d\n", ret); -89 goto fail2; -90 } -91 -92 ret = gpio_to_irq(buttons[1].gpio); +56 pr_info("%s\n", __func__); +57 +58/* register LED gpios */ +59#ifdef NO_GPIO_REQUEST_ARRAY +60 ret = gpio_request(leds[0].gpio, leds[0].label); +61#else +62 ret = gpio_request_array(leds, ARRAY_SIZE(leds)); +63#endif +64 +65 if (ret) { +66 pr_err("Unable to request GPIOs for LEDs: %d\n", ret); +67 return ret; +68 } +69 +70/* register BUTTON gpios */ +71#ifdef NO_GPIO_REQUEST_ARRAY +72 ret = gpio_request(buttons[0].gpio, buttons[0].label); +73 +74 if (ret) { +75 pr_err("Unable to request GPIOs for BUTTONs: %d\n", ret); +76 goto fail1; +77 } +78 +79 ret = gpio_request(buttons[1].gpio, buttons[1].label); +80 +81 if (ret) { +82 pr_err("Unable to request GPIOs for BUTTONs: %d\n", ret); +83 goto fail2; +84 } +85#else +86 ret = gpio_request_array(buttons, ARRAY_SIZE(buttons)); +87 +88 if (ret) { +89 pr_err("Unable to request GPIOs for BUTTONs: %d\n", ret); +90 goto fail1; +91 } +92#endif 93 -94 if (ret < 0) { -95 pr_err("Unable to request IRQ: %d\n", ret); -96 goto fail2; -97 } -98 -99 button_irqs[1] = ret; -100 -101 pr_info("Successfully requested BUTTON2 IRQ # %d\n", button_irqs[1]); -102 -103 ret = request_threaded_irq(button_irqs[1], button_top_half, -104 button_bottom_half, -105 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, -106 "gpiomod#button2", &buttons[1]); -107 -108 if (ret) { -109 pr_err("Unable to request IRQ: %d\n", ret); -110 goto fail3; -111 } -112 -113 return 0; -114 -115/* cleanup what has been setup so far */ -116fail3: -117 free_irq(button_irqs[0], NULL); -118 -119fail2: -120 gpio_free_array(buttons, ARRAY_SIZE(leds)); -121 -122fail1: -123 gpio_free_array(leds, ARRAY_SIZE(leds)); +94 pr_info("Current button1 value: %d\n", gpio_get_value(buttons[0].gpio)); +95 +96 ret = gpio_to_irq(buttons[0].gpio); +97 +98 if (ret < 0) { +99 pr_err("Unable to request IRQ: %d\n", ret); +100#ifdef NO_GPIO_REQUEST_ARRAY +101 goto fail3; +102#else +103 goto fail2; +104#endif +105 } +106 +107 button_irqs[0] = ret; +108 +109 pr_info("Successfully requested BUTTON1 IRQ # %d\n", button_irqs[0]); +110 +111 ret = request_threaded_irq(button_irqs[0], button_top_half, +112 button_bottom_half, +113 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, +114 "gpiomod#button1", &buttons[0]); +115 +116 if (ret) { +117 pr_err("Unable to request IRQ: %d\n", ret); +118#ifdef NO_GPIO_REQUEST_ARRAY +119 goto fail3; +120#else +121 goto fail2; +122#endif +123 } 124 -125 return ret; -126} -127 -128static void __exit bottomhalf_exit(void) -129{ -130 int i; -131 -132 pr_info("%s\n", __func__); -133 -134 /* free irqs */ -135 free_irq(button_irqs[0], NULL); -136 free_irq(button_irqs[1], NULL); +125 ret = gpio_to_irq(buttons[1].gpio); +126 +127 if (ret < 0) { +128 pr_err("Unable to request IRQ: %d\n", ret); +129#ifdef NO_GPIO_REQUEST_ARRAY +130 goto fail3; +131#else +132 goto fail2; +133#endif +134 } +135 +136 button_irqs[1] = ret; 137 -138 /* turn all LEDs off */ -139 for (i = 0; i < ARRAY_SIZE(leds); i++) -140 gpio_set_value(leds[i].gpio, 0); -141 -142 /* unregister */ -143 gpio_free_array(leds, ARRAY_SIZE(leds)); -144 gpio_free_array(buttons, ARRAY_SIZE(buttons)); -145} -146 -147module_init(bottomhalf_init); -148module_exit(bottomhalf_exit); -149 -150MODULE_LICENSE("GPL"); -151MODULE_DESCRIPTION("Interrupt with top and bottom half");+138 pr_info("Successfully requested BUTTON2 IRQ # %d\n", button_irqs[1]); +139 +140 ret = request_threaded_irq(button_irqs[1], button_top_half, +141 button_bottom_half, +142 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, +143 "gpiomod#button2", &buttons[1]); +144 +145 if (ret) { +146 pr_err("Unable to request IRQ: %d\n", ret); +147#ifdef NO_GPIO_REQUEST_ARRAY +148 goto fail4; +149#else +150 goto fail3; +151#endif +152 } +153 +154 return 0; +155 +156/* cleanup what has been setup so far */ +157#ifdef NO_GPIO_REQUEST_ARRAY +158fail4: +159 free_irq(button_irqs[0], NULL); +160 +161fail3: +162 gpio_free(buttons[1].gpio); +163 +164fail2: +165 gpio_free(buttons[0].gpio); +166 +167fail1: +168 gpio_free(leds[0].gpio); +169#else +170fail3: +171 free_irq(button_irqs[0], NULL); +172 +173fail2: +174 gpio_free_array(buttons, ARRAY_SIZE(leds)); +175 +176fail1: +177 gpio_free_array(leds, ARRAY_SIZE(leds)); +178#endif +179 +180 return ret; +181} +182 +183static void __exit bottomhalf_exit(void) +184{ +185 pr_info("%s\n", __func__); +186 +187 /* free irqs */ +188 free_irq(button_irqs[0], NULL); +189 free_irq(button_irqs[1], NULL); +190 +191/* turn all LEDs off */ +192#ifdef NO_GPIO_REQUEST_ARRAY +193 gpio_set_value(leds[0].gpio, 0); +194#else +195 int i; +196 for (i = 0; i < ARRAY_SIZE(leds); i++) +197 gpio_set_value(leds[i].gpio, 0); +198#endif +199 +200/* unregister */ +201#ifdef NO_GPIO_REQUEST_ARRAY +202 gpio_free(leds[0].gpio); +203 gpio_free(buttons[0].gpio); +204 gpio_free(buttons[1].gpio); +205#else +206 gpio_free_array(leds, ARRAY_SIZE(leds)); +207 gpio_free_array(buttons, ARRAY_SIZE(buttons)); +208#endif +209} +210 +211module_init(bottomhalf_init); +212module_exit(bottomhalf_exit); +213 +214MODULE_LICENSE("GPL"); +215MODULE_DESCRIPTION("Interrupt with top and bottom half");
A threaded IRQ is registered using request_threaded_irq()
. This function only takes one additional parameter than the
request_irq()
@@ -5719,22 +5911,22 @@ development of virtual input drivers. The drivers needs to export a
will add a new device to the list of support virtual input devices.
-
1int init(struct vinput *);-
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 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.
@@ -5745,12 +5937,12 @@ virtual input device.
struct vinput
-
already initialized with an allocated struct input_dev
+
structure is similar to other attribute types we talked about in section 8:
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);
-
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); +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};@@ -5761,227 +5953,227 @@ will generate theclass_attribute
structures which are named class_attr_export/unexport. Then, put them intovinput_class_attrs
array and the macroATTRIBUTE_GROUPS(vinput_class) -
will generate thestruct attribute_group vinput_class_group +
will generate thestruct attribute_group vinput_class_group
that should be assigned invinput_class
. Finally, callclass_register(&vinput_class)
to create attributes in sysfs.To create a vinputX sysfs entry and /dev node.
-
1echo "vkbd" | sudo tee /sys/class/vinput/export+1echo "vkbd" | sudo tee /sys/class/vinput/exportTo unexport the device, just echo its id in unexport:
-
1echo "0" | sudo tee /sys/class/vinput/unexport+1echo "0" | sudo tee /sys/class/vinput/unexport-
1/* -2 * vinput.h -3 */ +1/* +2 * vinput.h +3 */ 4 -5#ifndef VINPUT_H -6#define VINPUT_H +5#ifndef VINPUT_H +6#define VINPUT_H 7 -8#include <linux/input.h> -9#include <linux/spinlock.h> +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 +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) +15#define dev_to_vinput(dev) container_of(dev, struct vinput, dev) 16 -17struct vinput_device; +17struct vinput_device; 18 -19struct vinput { -20 long id; -21 long devno; -22 long last_entry; +19struct vinput { +20 long id; +21 long devno; +22 long last_entry; 23 spinlock_t lock; 24 -25 void *priv_data; +25 void *priv_data; 26 -27 struct device dev; -28 struct list_head list; -29 struct input_dev *input; -30 struct vinput_device *type; +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); +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; +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); +46int vinput_register(struct vinput_device *dev); +47void vinput_unregister(struct vinput_device *dev); 48 -49#endif+49#endif-
1/* -2 * vinput.c -3 */ +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#include <linux/version.h> +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#include <linux/version.h> 11 -12#include <asm/uaccess.h> +12#include <asm/uaccess.h> 13 -14#include "vinput.h" +14#include "vinput.h" 15 -16#define DRIVER_NAME "vinput" +16#define DRIVER_NAME "vinput" 17 -18#define dev_to_vinput(dev) container_of(dev, struct vinput, dev) +18#define dev_to_vinput(dev) container_of(dev, struct vinput, dev) 19 -20static DECLARE_BITMAP(vinput_ids, VINPUT_MINORS); +20static DECLARE_BITMAP(vinput_ids, VINPUT_MINORS); 21 -22static LIST_HEAD(vinput_devices); -23static LIST_HEAD(vinput_vdevices); +22static LIST_HEAD(vinput_devices); +23static LIST_HEAD(vinput_vdevices); 24 -25static int vinput_dev; -26static struct spinlock vinput_lock; -27static struct class vinput_class; +25static int vinput_dev; +26static struct spinlock vinput_lock; +27static struct class vinput_class; 28 -29/* Search the name of vinput device in the vinput_devices linked list, -30 * which added at vinput_register(). -31 */ -32static struct vinput_device *vinput_get_device_by_type(const char *type) +29/* Search the name of vinput device in the vinput_devices linked list, +30 * which added at vinput_register(). +31 */ +32static struct vinput_device *vinput_get_device_by_type(const char *type) 33{ -34 int found = 0; -35 struct vinput_device *vinput; -36 struct list_head *curr; +34 int found = 0; +35 struct vinput_device *vinput; +36 struct list_head *curr; 37 38 spin_lock(&vinput_lock); 39 list_for_each (curr, &vinput_devices) { -40 vinput = list_entry(curr, struct vinput_device, list); -41 if (vinput && strncmp(type, vinput->name, strlen(vinput->name)) == 0) { +40 vinput = list_entry(curr, struct vinput_device, list); +41 if (vinput && strncmp(type, vinput->name, strlen(vinput->name)) == 0) { 42 found = 1; -43 break; +43 break; 44 } 45 } 46 spin_unlock(&vinput_lock); 47 -48 if (found) -49 return vinput; -50 return ERR_PTR(-ENODEV); +48 if (found) +49 return vinput; +50 return ERR_PTR(-ENODEV); 51} 52 -53/* Search the id of virtual device in the vinput_vdevices linked list, -54 * which added at vinput_alloc_vdevice(). -55 */ -56static struct vinput *vinput_get_vdevice_by_id(long id) +53/* Search the id of virtual device in the vinput_vdevices linked list, +54 * which added at vinput_alloc_vdevice(). +55 */ +56static struct vinput *vinput_get_vdevice_by_id(long id) 57{ -58 struct vinput *vinput = NULL; -59 struct list_head *curr; +58 struct vinput *vinput = NULL; +59 struct list_head *curr; 60 61 spin_lock(&vinput_lock); 62 list_for_each (curr, &vinput_vdevices) { -63 vinput = list_entry(curr, struct vinput, list); -64 if (vinput && vinput->id == id) -65 break; +63 vinput = list_entry(curr, struct vinput, list); +64 if (vinput && vinput->id == id) +65 break; 66 } 67 spin_unlock(&vinput_lock); 68 -69 if (vinput && vinput->id == id) -70 return vinput; -71 return ERR_PTR(-ENODEV); +69 if (vinput && vinput->id == id) +70 return vinput; +71 return ERR_PTR(-ENODEV); 72} 73 -74static int vinput_open(struct inode *inode, struct file *file) +74static int vinput_open(struct inode *inode, struct file *file) 75{ -76 int err = 0; -77 struct vinput *vinput = NULL; +76 int err = 0; +77 struct vinput *vinput = NULL; 78 79 vinput = vinput_get_vdevice_by_id(iminor(inode)); 80 -81 if (IS_ERR(vinput)) +81 if (IS_ERR(vinput)) 82 err = PTR_ERR(vinput); -83 else +83 else 84 file->private_data = vinput; 85 -86 return err; +86 return err; 87} 88 -89static int vinput_release(struct inode *inode, struct file *file) +89static int vinput_release(struct inode *inode, struct file *file) 90{ -91 return 0; +91 return 0; 92} 93 -94static ssize_t vinput_read(struct file *file, char __user *buffer, size_t count, +94static ssize_t vinput_read(struct file *file, char __user *buffer, size_t count, 95 loff_t *offset) 96{ -97 int len; -98 char buff[VINPUT_MAX_LEN + 1]; -99 struct vinput *vinput = file->private_data; +97 int len; +98 char buff[VINPUT_MAX_LEN + 1]; +99 struct vinput *vinput = file->private_data; 100 101 len = vinput->type->ops->read(vinput, buff, count); 102 -103 if (*offset > len) +103 if (*offset > len) 104 count = 0; -105 else if (count + *offset > VINPUT_MAX_LEN) +105 else if (count + *offset > VINPUT_MAX_LEN) 106 count = len - *offset; 107 -108 if (raw_copy_to_user(buffer, buff + *offset, count)) -109 return -EFAULT; +108 if (raw_copy_to_user(buffer, buff + *offset, count)) +109 return -EFAULT; 110 111 *offset += count; 112 -113 return count; +113 return count; 114} 115 -116static ssize_t vinput_write(struct file *file, const char __user *buffer, -117 size_t count, loff_t *offset) +116static ssize_t vinput_write(struct file *file, const char __user *buffer, +117 size_t count, loff_t *offset) 118{ -119 char buff[VINPUT_MAX_LEN + 1]; -120 struct vinput *vinput = file->private_data; +119 char buff[VINPUT_MAX_LEN + 1]; +120 struct vinput *vinput = file->private_data; 121 -122 memset(buff, 0, sizeof(char) * (VINPUT_MAX_LEN + 1)); +122 memset(buff, 0, sizeof(char) * (VINPUT_MAX_LEN + 1)); 123 -124 if (count > VINPUT_MAX_LEN) { -125 dev_warn(&vinput->dev, "Too long. %d bytes allowed\n", VINPUT_MAX_LEN); -126 return -EINVAL; +124 if (count > VINPUT_MAX_LEN) { +125 dev_warn(&vinput->dev, "Too long. %d bytes allowed\n", VINPUT_MAX_LEN); +126 return -EINVAL; 127 } 128 -129 if (raw_copy_from_user(buff, buffer, count)) -130 return -EFAULT; +129 if (raw_copy_from_user(buff, buffer, count)) +130 return -EFAULT; 131 -132 return vinput->type->ops->send(vinput, buff, count); +132 return vinput->type->ops->send(vinput, buff, count); 133} 134 -135static const struct file_operations vinput_fops = { -136#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) +135static const struct file_operations vinput_fops = { +136#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) 137 .owner = THIS_MODULE, -138#endif +138#endif 139 .open = vinput_open, 140 .release = vinput_release, 141 .read = vinput_read, 142 .write = vinput_write, 143}; 144 -145static void vinput_unregister_vdevice(struct vinput *vinput) +145static void vinput_unregister_vdevice(struct vinput *vinput) 146{ 147 input_unregister_device(vinput->input); -148 if (vinput->type->ops->kill) +148 if (vinput->type->ops->kill) 149 vinput->type->ops->kill(vinput); 150} 151 -152static void vinput_destroy_vdevice(struct vinput *vinput) +152static void vinput_destroy_vdevice(struct vinput *vinput) 153{ -154 /* Remove from the list first */ +154 /* Remove from the list first */ 155 spin_lock(&vinput_lock); 156 list_del(&vinput->list); 157 clear_bit(vinput->id, vinput_ids); @@ -5992,24 +6184,24 @@ will generate the+424MODULE_LICENSE("GPL"); +425MODULE_DESCRIPTION("Emulate input events");class_attribute 162 kfree(vinput); 163} 164 -165static void vinput_release_dev(struct device *dev) +165static void vinput_release_dev(struct device *dev) 166{ -167 struct vinput *vinput = dev_to_vinput(dev); -168 int id = vinput->id; +167 struct vinput *vinput = dev_to_vinput(dev); +168 int id = vinput->id; 169 170 vinput_destroy_vdevice(vinput); 171 -172 pr_debug("released vinput%d.\n", id); +172 pr_debug("released vinput%d.\n", id); 173} 174 -175static struct vinput *vinput_alloc_vdevice(void) +175static struct vinput *vinput_alloc_vdevice(void) 176{ -177 int err; -178 struct vinput *vinput = kzalloc(sizeof(struct vinput), GFP_KERNEL); +177 int err; +178 struct vinput *vinput = kzalloc(sizeof(struct vinput), GFP_KERNEL); 179 -180 if (!vinput) { -181 pr_err("vinput: Cannot allocate vinput input device\n"); -182 return ERR_PTR(-ENOMEM); +180 if (!vinput) { +181 pr_err("vinput: Cannot allocate vinput input device\n"); +182 return ERR_PTR(-ENOMEM); 183 } 184 185 try_module_get(THIS_MODULE); @@ -6018,29 +6210,29 @@ will generate the
class_attribute 188 189 spin_lock(&vinput_lock); 190 vinput->id = find_first_zero_bit(vinput_ids, VINPUT_MINORS); -191 if (vinput->id >= VINPUT_MINORS) { +191 if (vinput->id >= VINPUT_MINORS) { 192 err = -ENOBUFS; -193 goto fail_id; +193 goto fail_id; 194 } 195 set_bit(vinput->id, vinput_ids); 196 list_add(&vinput->list, &vinput_vdevices); 197 spin_unlock(&vinput_lock); 198 -199 /* allocate the input device */ +199 /* allocate the input device */ 200 vinput->input = input_allocate_device(); -201 if (vinput->input == NULL) { -202 pr_err("vinput: Cannot allocate vinput input device\n"); +201 if (vinput->input == NULL) { +202 pr_err("vinput: Cannot allocate vinput input device\n"); 203 err = -ENOMEM; -204 goto fail_input_dev; +204 goto fail_input_dev; 205 } 206 -207 /* initialize device */ +207 /* initialize device */ 208 vinput->dev.class = &vinput_class; 209 vinput->dev.release = vinput_release_dev; 210 vinput->dev.devt = MKDEV(vinput_dev, vinput->id); -211 dev_set_name(&vinput->dev, DRIVER_NAME "%lu", vinput->id); +211 dev_set_name(&vinput->dev, DRIVER_NAME "%lu", vinput->id); 212 -213 return vinput; +213 return vinput; 214 215fail_input_dev: 216 spin_lock(&vinput_lock); @@ -6050,16 +6242,16 @@ will generate the
class_attribute 220 module_put(THIS_MODULE); 221 kfree(vinput); 222 -223 return ERR_PTR(err); +223 return ERR_PTR(err); 224} 225 -226static int vinput_register_vdevice(struct vinput *vinput) +226static int vinput_register_vdevice(struct vinput *vinput) 227{ -228 int err = 0; +228 int err = 0; 229 -230 /* register the input device */ +230 /* register the input device */ 231 vinput->input->name = vinput->type->name; -232 vinput->input->phys = "vinput"; +232 vinput->input->phys = "vinput"; 233 vinput->input->dev.parent = &vinput->dev; 234 235 vinput->input->id.bustype = BUS_VIRTUAL; @@ -6069,180 +6261,180 @@ will generate the
class_attribute 239 240 err = vinput->type->ops->init(vinput); 241 -242 if (err == 0) -243 dev_info(&vinput->dev, "Registered virtual input %s %ld\n", +242 if (err == 0) +243 dev_info(&vinput->dev, "Registered virtual input %s %ld\n", 244 vinput->type->name, vinput->id); 245 -246 return err; +246 return err; 247} 248 -249#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) -250static ssize_t export_store(const struct class *class, -251 const struct class_attribute *attr, -252#else -253static ssize_t export_store(struct class *class, struct class_attribute *attr, -254#endif -255 const char *buf, size_t len) +249#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) +250static ssize_t export_store(const struct class *class, +251 const struct class_attribute *attr, +252#else +253static ssize_t export_store(struct class *class, struct class_attribute *attr, +254#endif +255 const char *buf, size_t len) 256{ -257 int err; -258 struct vinput *vinput; -259 struct vinput_device *device; +257 int err; +258 struct vinput *vinput; +259 struct vinput_device *device; 260 261 device = vinput_get_device_by_type(buf); -262 if (IS_ERR(device)) { -263 pr_info("vinput: This virtual device isn't registered\n"); +262 if (IS_ERR(device)) { +263 pr_info("vinput: This virtual device isn't registered\n"); 264 err = PTR_ERR(device); -265 goto fail; +265 goto fail; 266 } 267 268 vinput = vinput_alloc_vdevice(); -269 if (IS_ERR(vinput)) { +269 if (IS_ERR(vinput)) { 270 err = PTR_ERR(vinput); -271 goto fail; +271 goto fail; 272 } 273 274 vinput->type = device; 275 err = device_register(&vinput->dev); -276 if (err < 0) -277 goto fail_register; +276 if (err < 0) +277 goto fail_register; 278 279 err = vinput_register_vdevice(vinput); -280 if (err < 0) -281 goto fail_register_vinput; +280 if (err < 0) +281 goto fail_register_vinput; 282 -283 return len; +283 return len; 284 285fail_register_vinput: 286 input_free_device(vinput->input); 287 device_unregister(&vinput->dev); -288 /* avoid calling vinput_destroy_vdevice() twice */ -289 return err; +288 /* avoid calling vinput_destroy_vdevice() twice */ +289 return err; 290fail_register: 291 input_free_device(vinput->input); 292 vinput_destroy_vdevice(vinput); 293fail: -294 return err; +294 return err; 295} -296/* This macro generates class_attr_export structure and export_store() */ -297static CLASS_ATTR_WO(export); +296/* This macro generates class_attr_export structure and export_store() */ +297static CLASS_ATTR_WO(export); 298 -299#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) -300static ssize_t unexport_store(const struct class *class, -301 const struct class_attribute *attr, -302#else -303static ssize_t unexport_store(struct class *class, struct class_attribute *attr, -304#endif -305 const char *buf, size_t len) +299#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) +300static ssize_t unexport_store(const struct class *class, +301 const struct class_attribute *attr, +302#else +303static ssize_t unexport_store(struct class *class, struct class_attribute *attr, +304#endif +305 const char *buf, size_t len) 306{ -307 int err; -308 unsigned long id; -309 struct vinput *vinput; +307 int err; +308 unsigned long id; +309 struct vinput *vinput; 310 311 err = kstrtol(buf, 10, &id); -312 if (err) { +312 if (err) { 313 err = -EINVAL; -314 goto failed; +314 goto failed; 315 } 316 317 vinput = vinput_get_vdevice_by_id(id); -318 if (IS_ERR(vinput)) { -319 pr_err("vinput: No such vinput device %ld\n", id); +318 if (IS_ERR(vinput)) { +319 pr_err("vinput: No such vinput device %ld\n", id); 320 err = PTR_ERR(vinput); -321 goto failed; +321 goto failed; 322 } 323 324 vinput_unregister_vdevice(vinput); 325 device_unregister(&vinput->dev); 326 -327 return len; +327 return len; 328failed: -329 return err; +329 return err; 330} -331/* This macro generates class_attr_unexport structure and unexport_store() */ -332static CLASS_ATTR_WO(unexport); +331/* This macro generates class_attr_unexport structure and unexport_store() */ +332static CLASS_ATTR_WO(unexport); 333 -334static struct attribute *vinput_class_attrs[] = { +334static struct attribute *vinput_class_attrs[] = { 335 &class_attr_export.attr, 336 &class_attr_unexport.attr, 337 NULL, 338}; 339 -340/* This macro generates vinput_class_groups structure */ +340/* This macro generates vinput_class_groups structure */ 341ATTRIBUTE_GROUPS(vinput_class); 342 -343static struct class vinput_class = { -344 .name = "vinput", -345#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) +343static struct class vinput_class = { +344 .name = "vinput", +345#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) 346 .owner = THIS_MODULE, -347#endif +347#endif 348 .class_groups = vinput_class_groups, 349}; 350 -351int vinput_register(struct vinput_device *dev) +351int vinput_register(struct vinput_device *dev) 352{ 353 spin_lock(&vinput_lock); 354 list_add(&dev->list, &vinput_devices); 355 spin_unlock(&vinput_lock); 356 -357 pr_info("vinput: registered new virtual input device '%s'\n", dev->name); +357 pr_info("vinput: registered new virtual input device '%s'\n", dev->name); 358 -359 return 0; +359 return 0; 360} 361EXPORT_SYMBOL(vinput_register); 362 -363void vinput_unregister(struct vinput_device *dev) +363void vinput_unregister(struct vinput_device *dev) 364{ -365 struct list_head *curr, *next; +365 struct list_head *curr, *next; 366 -367 /* Remove from the list first */ +367 /* Remove from the list first */ 368 spin_lock(&vinput_lock); 369 list_del(&dev->list); 370 spin_unlock(&vinput_lock); 371 -372 /* unregister all devices of this type */ +372 /* unregister all devices of this type */ 373 list_for_each_safe (curr, next, &vinput_vdevices) { -374 struct vinput *vinput = list_entry(curr, struct vinput, list); -375 if (vinput && vinput->type == dev) { +374 struct vinput *vinput = list_entry(curr, struct vinput, list); +375 if (vinput && vinput->type == dev) { 376 vinput_unregister_vdevice(vinput); 377 device_unregister(&vinput->dev); 378 } 379 } 380 -381 pr_info("vinput: unregistered virtual input device '%s'\n", dev->name); +381 pr_info("vinput: unregistered virtual input device '%s'\n", dev->name); 382} 383EXPORT_SYMBOL(vinput_unregister); 384 -385static int __init vinput_init(void) +385static int __init vinput_init(void) 386{ -387 int err = 0; +387 int err = 0; 388 -389 pr_info("vinput: Loading virtual input driver\n"); +389 pr_info("vinput: Loading virtual input driver\n"); 390 391 vinput_dev = register_chrdev(0, DRIVER_NAME, &vinput_fops); -392 if (vinput_dev < 0) { -393 pr_err("vinput: Unable to allocate char dev region\n"); +392 if (vinput_dev < 0) { +393 pr_err("vinput: Unable to allocate char dev region\n"); 394 err = vinput_dev; -395 goto failed_alloc; +395 goto failed_alloc; 396 } 397 398 spin_lock_init(&vinput_lock); 399 400 err = class_register(&vinput_class); -401 if (err < 0) { -402 pr_err("vinput: Unable to register vinput class\n"); -403 goto failed_class; +401 if (err < 0) { +402 pr_err("vinput: Unable to register vinput class\n"); +403 goto failed_class; 404 } 405 -406 return 0; +406 return 0; 407failed_class: 408 unregister_chrdev(vinput_dev, DRIVER_NAME); 409failed_alloc: -410 return err; +410 return err; 411} 412 -413static void __exit vinput_end(void) +413static void __exit vinput_end(void) 414{ -415 pr_info("vinput: Unloading virtual input driver\n"); +415 pr_info("vinput: Unloading virtual input driver\n"); 416 417 unregister_chrdev(vinput_dev, DRIVER_NAME); 418 class_unregister(&vinput_class); @@ -6251,8 +6443,8 @@ will generate the
class_attribute 421module_init(vinput_init); 422module_exit(vinput_end); 423 -424MODULE_LICENSE("GPL"); -425MODULE_DESCRIPTION("Emulate input events");
Here the virtual keyboard is one of example to use vinput. It supports all
KEY_MAX
keycodes. The injection format is theKEY_CODE @@ -6265,7 +6457,7 @@ following demonstrates how simulation work.
= 34):-
1echo "+34" | sudo tee /dev/vinput0+1echo "+34" | sudo tee /dev/vinput0Simulate a key release on "g" (
KEY_G
= 34):@@ -6273,111 +6465,111 @@ following demonstrates how simulation work.
-1echo "-34" | sudo tee /dev/vinput0+1echo "-34" | sudo tee /dev/vinput0-
1/* -2 * vkbd.c -3 */ +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> +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" +10#include "vinput.h" 11 -12#define VINPUT_KBD "vkbd" -13#define VINPUT_RELEASE 0 -14#define VINPUT_PRESS 1 +12#define VINPUT_KBD "vkbd" +13#define VINPUT_RELEASE 0 +14#define VINPUT_PRESS 1 15 -16static unsigned short vkeymap[KEY_MAX]; +16static unsigned short vkeymap[KEY_MAX]; 17 -18static int vinput_vkbd_init(struct vinput *vinput) +18static int vinput_vkbd_init(struct vinput *vinput) 19{ -20 int i; +20 int i; 21 -22 /* Set up the input bitfield */ +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); +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++) +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); +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) +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); +40 len = snprintf(buff, len, "%+ld\n", vinput->last_entry); 41 spin_unlock(&vinput->lock); 42 -43 return len; +43 return len; 44} 45 -46static int vinput_vkbd_send(struct vinput *vinput, char *buff, int len) +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; +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] == '+') +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 +57 else 58 ret = kstrtol(buff, 10, &key); -59 if (ret) -60 dev_err(&vinput->dev, "error during kstrtol: -%d\n", ret); +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) { +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); +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. */ +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. */ +75 /* Tell input subsystem that it finished the report. */ 76 input_sync(vinput->input); 77 -78 return len; +78 return len; 79} 80 -81static struct vinput_ops vkbd_ops = { +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 = { +87static struct vinput_device vkbd_dev = { 88 .name = VINPUT_KBD, 89 .ops = &vkbd_ops, 90}; 91 -92static int __init vkbd_init(void) +92static int __init vkbd_init(void) 93{ -94 int i; +94 int i; 95 -96 for (i = 0; i < KEY_MAX; i++) +96 for (i = 0; i < KEY_MAX; i++) 97 vkeymap[i] = i; -98 return vinput_register(&vkbd_dev); +98 return vinput_register(&vkbd_dev); 99} 100 -101static void __exit vkbd_end(void) +101static void __exit vkbd_end(void) 102{ 103 vinput_unregister(&vkbd_dev); 104} @@ -6385,8 +6577,8 @@ following demonstrates how simulation work. 106module_init(vkbd_init); 107module_exit(vkbd_end); 108 -109MODULE_LICENSE("GPL"); -110MODULE_DESCRIPTION("Emulate keyboard input events through /dev/vinput");+109MODULE_LICENSE("GPL"); +110MODULE_DESCRIPTION("Emulate keyboard input events through /dev/vinput");
17 Standardizing the interfaces: The Device Model
@@ -6398,59 +6590,59 @@ use this as a template to add your own suspend, resume or other interface functions.-
1/* -2 * devicemodel.c -3 */ -4#include <linux/kernel.h> -5#include <linux/module.h> -6#include <linux/platform_device.h> +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; +8struct devicemodel_data { +9 char *greeting; +10 int number; 11}; 12 -13static int devicemodel_probe(struct platform_device *dev) +13static int devicemodel_probe(struct platform_device *dev) 14{ -15 struct devicemodel_data *pd = -16 (struct devicemodel_data *)(dev->dev.platform_data); +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); +18 pr_info("devicemodel probe\n"); +19 pr_info("devicemodel greeting: %s; %d\n", pd->greeting, pd->number); 20 -21 /* Your device initialization code */ +21 /* Your device initialization code */ 22 -23 return 0; +23 return 0; 24} 25 -26static int devicemodel_remove(struct platform_device *dev) +26static int devicemodel_remove(struct platform_device *dev) 27{ -28 pr_info("devicemodel example removed\n"); +28 pr_info("devicemodel example removed\n"); 29 -30 /* Your device removal code */ +30 /* Your device removal code */ 31 -32 return 0; +32 return 0; 33} 34 -35static int devicemodel_suspend(struct device *dev) +35static int devicemodel_suspend(struct device *dev) 36{ -37 pr_info("devicemodel example suspend\n"); +37 pr_info("devicemodel example suspend\n"); 38 -39 /* Your device suspend code */ +39 /* Your device suspend code */ 40 -41 return 0; +41 return 0; 42} 43 -44static int devicemodel_resume(struct device *dev) +44static int devicemodel_resume(struct device *dev) 45{ -46 pr_info("devicemodel example resume\n"); +46 pr_info("devicemodel example resume\n"); 47 -48 /* Your device resume code */ +48 /* Your device resume code */ 49 -50 return 0; +50 return 0; 51} 52 -53static const struct dev_pm_ops devicemodel_pm_ops = { +53static const struct dev_pm_ops devicemodel_pm_ops = { 54 .suspend = devicemodel_suspend, 55 .resume = devicemodel_resume, 56 .poweroff = devicemodel_suspend, @@ -6459,43 +6651,43 @@ functions. 59 .restore = devicemodel_resume, 60}; 61 -62static struct platform_driver devicemodel_driver = { +62static struct platform_driver devicemodel_driver = { 63 .driver = 64 { -65 .name = "devicemodel_example", +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) +72static int __init devicemodel_init(void) 73{ -74 int ret; +74 int ret; 75 -76 pr_info("devicemodel init\n"); +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; +80 if (ret) { +81 pr_err("Unable to register driver\n"); +82 return ret; 83 } 84 -85 return 0; +85 return 0; 86} 87 -88static void __exit devicemodel_exit(void) +88static void __exit devicemodel_exit(void) 89{ -90 pr_info("devicemodel exit\n"); +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");+97MODULE_LICENSE("GPL"); +98MODULE_DESCRIPTION("Linux Device Model example");
18 Optimizations
@@ -6519,10 +6711,10 @@ to succeed.1bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx); -2if (unlikely(!bvl)) { +2if (unlikely(!bvl)) { 3 mempool_free(bio, bio_pool); 4 bio = NULL; -5 goto out; +5 goto out; 6}When the
unlikely
macro is used, the compiler alters its machine instruction output, so that it @@ -6540,7 +6732,7 @@ prediction. The most typical use case of static keys is for performance-sensitiv 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 -asm goto +
asm goto
inline assembly, and the following kernel configurations are set:@@ -6563,10 +6755,10 @@ no-op instruction will be generated at compile time as the key is initialized to and the branch is unlikely to be taken.
-
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");@@ -6579,159 +6771,159 @@ codepr_alert static key works.
-
1/* -2 * static_key.c -3 */ +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#include <linux/version.h> +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#include <linux/version.h> 15 -16#include <asm/errno.h> +16#include <asm/errno.h> 17 -18static int device_open(struct inode *inode, struct file *file); -19static int device_release(struct inode *inode, struct file *file); -20static ssize_t device_read(struct file *file, char __user *buf, size_t count, +18static int device_open(struct inode *inode, struct file *file); +19static int device_release(struct inode *inode, struct file *file); +20static ssize_t device_read(struct file *file, char __user *buf, size_t count, 21 loff_t *ppos); -22static ssize_t device_write(struct file *file, const char __user *buf, -23 size_t count, loff_t *ppos); +22static ssize_t device_write(struct file *file, const char __user *buf, +23 size_t count, loff_t *ppos); 24 -25#define SUCCESS 0 -26#define DEVICE_NAME "key_state" -27#define BUF_LEN 10 +25#define SUCCESS 0 +26#define DEVICE_NAME "key_state" +27#define BUF_LEN 10 28 -29static int major; +29static int major; 30 -31enum { +31enum { 32 CDEV_NOT_USED, 33 CDEV_EXCLUSIVE_OPEN, 34}; 35 -36static atomic_t already_open = ATOMIC_INIT(CDEV_NOT_USED); +36static atomic_t already_open = ATOMIC_INIT(CDEV_NOT_USED); 37 -38static char msg[BUF_LEN + 1]; +38static char msg[BUF_LEN + 1]; 39 -40static struct class *cls; +40static struct class *cls; 41 -42static DEFINE_STATIC_KEY_FALSE(fkey); +42static DEFINE_STATIC_KEY_FALSE(fkey); 43 -44static struct file_operations chardev_fops = { -45#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) +44static struct file_operations chardev_fops = { +45#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) 46 .owner = THIS_MODULE, -47#endif +47#endif 48 .open = device_open, 49 .release = device_release, 50 .read = device_read, 51 .write = device_write, 52}; 53 -54static int __init chardev_init(void) +54static int __init chardev_init(void) 55{ 56 major = register_chrdev(0, DEVICE_NAME, &chardev_fops); -57 if (major < 0) { -58 pr_alert("Registering char device failed with %d\n", major); -59 return major; +57 if (major < 0) { +58 pr_alert("Registering char device failed with %d\n", major); +59 return major; 60 } 61 -62 pr_info("I was assigned major number %d\n", major); +62 pr_info("I was assigned major number %d\n", major); 63 -64#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) +64#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) 65 cls = class_create(THIS_MODULE, DEVICE_NAME); -66#else +66#else 67 cls = class_create(DEVICE_NAME); -68#endif +68#endif 69 70 device_create(cls, NULL, MKDEV(major, 0), NULL, DEVICE_NAME); 71 -72 pr_info("Device created on /dev/%s\n", DEVICE_NAME); +72 pr_info("Device created on /dev/%s\n", DEVICE_NAME); 73 -74 return SUCCESS; +74 return SUCCESS; 75} 76 -77static void __exit chardev_exit(void) +77static void __exit chardev_exit(void) 78{ 79 device_destroy(cls, MKDEV(major, 0)); 80 class_destroy(cls); 81 -82 /* Unregister the device */ +82 /* Unregister the device */ 83 unregister_chrdev(major, DEVICE_NAME); 84} 85 -86/* Methods */ +86/* Methods */ 87 -88/** -89 * Called when a process tried to open the device file, like -90 * cat /dev/key_state -91 */ -92static int device_open(struct inode *inode, struct file *file) +88/** +89 * Called when a process tried to open the device file, like +90 * cat /dev/key_state +91 */ +92static int device_open(struct inode *inode, struct file *file) 93{ -94 if (atomic_cmpxchg(&already_open, CDEV_NOT_USED, CDEV_EXCLUSIVE_OPEN)) -95 return -EBUSY; +94 if (atomic_cmpxchg(&already_open, CDEV_NOT_USED, CDEV_EXCLUSIVE_OPEN)) +95 return -EBUSY; 96 -97 sprintf(msg, static_key_enabled(&fkey) ? "enabled\n" : "disabled\n"); +97 sprintf(msg, static_key_enabled(&fkey) ? "enabled\n" : "disabled\n"); 98 -99 pr_info("fastpath 1\n"); -100 if (static_branch_unlikely(&fkey)) -101 pr_alert("do unlikely thing\n"); -102 pr_info("fastpath 2\n"); +99 pr_info("fastpath 1\n"); +100 if (static_branch_unlikely(&fkey)) +101 pr_alert("do unlikely thing\n"); +102 pr_info("fastpath 2\n"); 103 104 try_module_get(THIS_MODULE); 105 -106 return SUCCESS; +106 return SUCCESS; 107} 108 -109/** -110 * Called when a process closes the device file -111 */ -112static int device_release(struct inode *inode, struct file *file) +109/** +110 * Called when a process closes the device file +111 */ +112static int device_release(struct inode *inode, struct file *file) 113{ -114 /* We are now ready for our next caller. */ +114 /* We are now ready for our next caller. */ 115 atomic_set(&already_open, CDEV_NOT_USED); 116 -117 /** -118 * Decrement the usage count, or else once you opened the file, you will -119 * never get rid of the module. -120 */ +117 /** +118 * Decrement the usage count, or else once you opened the file, you will +119 * never get rid of the module. +120 */ 121 module_put(THIS_MODULE); 122 -123 return SUCCESS; +123 return SUCCESS; 124} 125 -126/** -127 * Called when a process, which already opened the dev file, attempts to -128 * read from it. -129 */ -130static ssize_t device_read(struct file *filp, /* see include/linux/fs.h */ -131 char __user *buffer, /* buffer to fill with data */ -132 size_t length, /* length of the buffer */ +126/** +127 * Called when a process, which already opened the dev file, attempts to +128 * read from it. +129 */ +130static ssize_t device_read(struct file *filp, /* see include/linux/fs.h */ +131 char __user *buffer, /* buffer to fill with data */ +132 size_t length, /* length of the buffer */ 133 loff_t *offset) 134{ -135 /* Number of the bytes actually written to the buffer */ -136 int bytes_read = 0; -137 const char *msg_ptr = msg; +135 /* Number of the bytes actually written to the buffer */ +136 int bytes_read = 0; +137 const char *msg_ptr = msg; 138 -139 if (!*(msg_ptr + *offset)) { /* We are at the end of the message */ -140 *offset = 0; /* reset the offset */ -141 return 0; /* signify end of file */ +139 if (!*(msg_ptr + *offset)) { /* We are at the end of the message */ +140 *offset = 0; /* reset the offset */ +141 return 0; /* signify end of file */ 142 } 143 144 msg_ptr += *offset; 145 -146 /* Actually put the data into the buffer */ -147 while (length && *msg_ptr) { -148 /** -149 * The buffer is in the user data segment, not the kernel -150 * segment so "*" assignment won't work. We have to use -151 * put_user which copies data from the kernel data segment to -152 * the user data segment. -153 */ +146 /* Actually put the data into the buffer */ +147 while (length && *msg_ptr) { +148 /** +149 * The buffer is in the user data segment, not the kernel +150 * segment so "*" assignment won't work. We have to use +151 * put_user which copies data from the kernel data segment to +152 * the user data segment. +153 */ 154 put_user(*(msg_ptr++), buffer++); 155 length--; 156 bytes_read++; @@ -6739,41 +6931,41 @@ static key works. 158 159 *offset += bytes_read; 160 -161 /* Most read functions return the number of bytes put into the buffer. */ -162 return bytes_read; +161 /* Most read functions return the number of bytes put into the buffer. */ +162 return bytes_read; 163} 164 -165/* Called when a process writes to dev file; echo "enable" > /dev/key_state */ -166static ssize_t device_write(struct file *filp, const char __user *buffer, -167 size_t length, loff_t *offset) +165/* Called when a process writes to dev file; echo "enable" > /dev/key_state */ +166static ssize_t device_write(struct file *filp, const char __user *buffer, +167 size_t length, loff_t *offset) 168{ -169 char command[10]; +169 char command[10]; 170 -171 if (length > 10) { -172 pr_err("command exceeded 10 char\n"); -173 return -EINVAL; +171 if (length > 10) { +172 pr_err("command exceeded 10 char\n"); +173 return -EINVAL; 174 } 175 -176 if (copy_from_user(command, buffer, length)) -177 return -EFAULT; +176 if (copy_from_user(command, buffer, length)) +177 return -EFAULT; 178 -179 if (strncmp(command, "enable", strlen("enable")) == 0) +179 if (strncmp(command, "enable", strlen("enable")) == 0) 180 static_branch_enable(&fkey); -181 else if (strncmp(command, "disable", strlen("disable")) == 0) +181 else if (strncmp(command, "disable", strlen("disable")) == 0) 182 static_branch_disable(&fkey); -183 else { -184 pr_err("Invalid command: %s\n", command); -185 return -EINVAL; +183 else { +184 pr_err("Invalid command: %s\n", command); +185 return -EINVAL; 186 } 187 -188 /* Again, return the number of input characters used. */ -189 return length; +188 /* Again, return the number of input characters used. */ +189 return length; 190} 191 192module_init(chardev_init); 193module_exit(chardev_exit); 194 -195MODULE_LICENSE("GPL");+195MODULE_LICENSE("GPL");To check the state of the static key, we can use the /dev/key_state interface.