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");

15.4 Threaded IRQ

@@ -5510,157 +5638,221 @@ The thread then runs the bottom-half handler. halves, but using threads.

-
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 struct vinput - already initialized with an allocated struct input_dev +

1int init(struct vinput *);
+

This function is passed a 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);

This function will receive a user string to interpret and inject the event using the 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);

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. structure is similar to other attribute types we talked about in section 8:

-
1struct class_attribute { 
-2    struct attribute attr; 
-3    ssize_t (*show)(struct class *class, struct class_attribute *attr, 
-4                    char *buf); 
-5    ssize_t (*store)(struct class *class, struct class_attribute *attr, 
-6                    const char *buf, size_t count); 
+   
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 the class_attribute structures which are named class_attr_export/unexport. Then, put them into vinput_class_attrs array and the macro ATTRIBUTE_GROUPS(vinput_class) - will generate the struct attribute_group vinput_class_group + will generate the struct attribute_group vinput_class_group that should be assigned in vinput_class . Finally, call class_register(&vinput_class) to create attributes in sysfs.

To create a vinputX sysfs entry and /dev node.

-
1echo "vkbd" | sudo tee /sys/class/vinput/export
+
1echo "vkbd" | sudo tee /sys/class/vinput/export

To 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   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");
+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 the KEY_CODE @@ -6265,7 +6457,7 @@ following demonstrates how simulation work. = 34):

-
1echo "+34" | sudo tee /dev/vinput0
+
1echo "+34" | sudo tee /dev/vinput0

Simulate 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 @@ code pr_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");

+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");

15.4 Threaded IRQ

@@ -5510,157 +5638,221 @@ The thread then runs the bottom-half handler. halves, but using threads.

-
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 struct vinput - already initialized with an allocated struct input_dev +

1int init(struct vinput *);
+

This function is passed a 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);

This function will receive a user string to interpret and inject the event using the 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);

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. structure is similar to other attribute types we talked about in section 8:

-
1struct class_attribute { 
-2    struct attribute attr; 
-3    ssize_t (*show)(struct class *class, struct class_attribute *attr, 
-4                    char *buf); 
-5    ssize_t (*store)(struct class *class, struct class_attribute *attr, 
-6                    const char *buf, size_t count); 
+   
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 the class_attribute structures which are named class_attr_export/unexport. Then, put them into vinput_class_attrs array and the macro ATTRIBUTE_GROUPS(vinput_class) - will generate the struct attribute_group vinput_class_group + will generate the struct attribute_group vinput_class_group that should be assigned in vinput_class . Finally, call class_register(&vinput_class) to create attributes in sysfs.

To create a vinputX sysfs entry and /dev node.

-
1echo "vkbd" | sudo tee /sys/class/vinput/export
+
1echo "vkbd" | sudo tee /sys/class/vinput/export

To 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   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");
+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 the KEY_CODE @@ -6265,7 +6457,7 @@ following demonstrates how simulation work. = 34):

-
1echo "+34" | sudo tee /dev/vinput0
+
1echo "+34" | sudo tee /dev/vinput0

Simulate 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 @@ code pr_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.