LCOV - code coverage report
Current view: top level - drivers/input - input-leds.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 52 87 59.8 %
Date: 2022-03-28 15:32:58 Functions: 5 8 62.5 %
Branches: 15 30 50.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * LED support for the input layer
       4                 :            :  *
       5                 :            :  * Copyright 2010-2015 Samuel Thibault <samuel.thibault@ens-lyon.org>
       6                 :            :  */
       7                 :            : 
       8                 :            : #include <linux/kernel.h>
       9                 :            : #include <linux/slab.h>
      10                 :            : #include <linux/module.h>
      11                 :            : #include <linux/init.h>
      12                 :            : #include <linux/leds.h>
      13                 :            : #include <linux/input.h>
      14                 :            : 
      15                 :            : #if IS_ENABLED(CONFIG_VT)
      16                 :            : #define VT_TRIGGER(_name)       .trigger = _name
      17                 :            : #else
      18                 :            : #define VT_TRIGGER(_name)       .trigger = NULL
      19                 :            : #endif
      20                 :            : 
      21                 :            : static const struct {
      22                 :            :         const char *name;
      23                 :            :         const char *trigger;
      24                 :            : } input_led_info[LED_CNT] = {
      25                 :            :         [LED_NUML]      = { "numlock", VT_TRIGGER("kbd-numlock") },
      26                 :            :         [LED_CAPSL]     = { "capslock", VT_TRIGGER("kbd-capslock") },
      27                 :            :         [LED_SCROLLL]   = { "scrolllock", VT_TRIGGER("kbd-scrolllock") },
      28                 :            :         [LED_COMPOSE]   = { "compose" },
      29                 :            :         [LED_KANA]      = { "kana", VT_TRIGGER("kbd-kanalock") },
      30                 :            :         [LED_SLEEP]     = { "sleep" } ,
      31                 :            :         [LED_SUSPEND]   = { "suspend" },
      32                 :            :         [LED_MUTE]      = { "mute" },
      33                 :            :         [LED_MISC]      = { "misc" },
      34                 :            :         [LED_MAIL]      = { "mail" },
      35                 :            :         [LED_CHARGING]  = { "charging" },
      36                 :            : };
      37                 :            : 
      38                 :            : struct input_led {
      39                 :            :         struct led_classdev cdev;
      40                 :            :         struct input_handle *handle;
      41                 :            :         unsigned int code; /* One of LED_* constants */
      42                 :            : };
      43                 :            : 
      44                 :            : struct input_leds {
      45                 :            :         struct input_handle handle;
      46                 :            :         unsigned int num_leds;
      47                 :            :         struct input_led leds[];
      48                 :            : };
      49                 :            : 
      50                 :         84 : static enum led_brightness input_leds_brightness_get(struct led_classdev *cdev)
      51                 :            : {
      52                 :         84 :         struct input_led *led = container_of(cdev, struct input_led, cdev);
      53                 :         84 :         struct input_dev *input = led->handle->dev;
      54                 :            : 
      55         [ -  + ]:         84 :         return test_bit(led->code, input->led) ? cdev->max_brightness : 0;
      56                 :            : }
      57                 :            : 
      58                 :         84 : static void input_leds_brightness_set(struct led_classdev *cdev,
      59                 :            :                                       enum led_brightness brightness)
      60                 :            : {
      61                 :         84 :         struct input_led *led = container_of(cdev, struct input_led, cdev);
      62                 :            : 
      63                 :         84 :         input_inject_event(led->handle, EV_LED, led->code, !!brightness);
      64                 :         84 : }
      65                 :            : 
      66                 :          0 : static void input_leds_event(struct input_handle *handle, unsigned int type,
      67                 :            :                              unsigned int code, int value)
      68                 :            : {
      69                 :          0 : }
      70                 :            : 
      71                 :         28 : static int input_leds_get_count(struct input_dev *dev)
      72                 :            : {
      73                 :         28 :         unsigned int led_code;
      74                 :         28 :         int count = 0;
      75                 :            : 
      76         [ +  + ]:        112 :         for_each_set_bit(led_code, dev->ledbit, LED_CNT)
      77         [ +  - ]:         84 :                 if (input_led_info[led_code].name)
      78                 :         84 :                         count++;
      79                 :            : 
      80                 :         28 :         return count;
      81                 :            : }
      82                 :            : 
      83                 :         28 : static int input_leds_connect(struct input_handler *handler,
      84                 :            :                               struct input_dev *dev,
      85                 :            :                               const struct input_device_id *id)
      86                 :            : {
      87                 :         28 :         struct input_leds *leds;
      88                 :         28 :         struct input_led *led;
      89                 :         28 :         unsigned int num_leds;
      90                 :         28 :         unsigned int led_code;
      91                 :         28 :         int led_no;
      92                 :         28 :         int error;
      93                 :            : 
      94                 :         28 :         num_leds = input_leds_get_count(dev);
      95         [ +  - ]:         28 :         if (!num_leds)
      96                 :            :                 return -ENXIO;
      97                 :            : 
      98         [ -  + ]:         28 :         leds = kzalloc(struct_size(leds, leds, num_leds), GFP_KERNEL);
      99         [ +  - ]:         28 :         if (!leds)
     100                 :            :                 return -ENOMEM;
     101                 :            : 
     102                 :         28 :         leds->num_leds = num_leds;
     103                 :            : 
     104                 :         28 :         leds->handle.dev = dev;
     105                 :         28 :         leds->handle.handler = handler;
     106                 :         28 :         leds->handle.name = "leds";
     107                 :         28 :         leds->handle.private = leds;
     108                 :            : 
     109                 :         28 :         error = input_register_handle(&leds->handle);
     110         [ -  + ]:         28 :         if (error)
     111                 :          0 :                 goto err_free_mem;
     112                 :            : 
     113                 :         28 :         error = input_open_device(&leds->handle);
     114         [ -  + ]:         28 :         if (error)
     115                 :          0 :                 goto err_unregister_handle;
     116                 :            : 
     117                 :         28 :         led_no = 0;
     118         [ +  + ]:        112 :         for_each_set_bit(led_code, dev->ledbit, LED_CNT) {
     119         [ -  + ]:         84 :                 if (!input_led_info[led_code].name)
     120                 :          0 :                         continue;
     121                 :            : 
     122                 :         84 :                 led = &leds->leds[led_no];
     123                 :         84 :                 led->handle = &leds->handle;
     124                 :         84 :                 led->code = led_code;
     125                 :            : 
     126         [ +  - ]:        168 :                 led->cdev.name = kasprintf(GFP_KERNEL, "%s::%s",
     127                 :            :                                            dev_name(&dev->dev),
     128                 :            :                                            input_led_info[led_code].name);
     129         [ -  + ]:         84 :                 if (!led->cdev.name) {
     130                 :          0 :                         error = -ENOMEM;
     131                 :          0 :                         goto err_unregister_leds;
     132                 :            :                 }
     133                 :            : 
     134                 :         84 :                 led->cdev.max_brightness = 1;
     135                 :         84 :                 led->cdev.brightness_get = input_leds_brightness_get;
     136                 :         84 :                 led->cdev.brightness_set = input_leds_brightness_set;
     137                 :         84 :                 led->cdev.default_trigger = input_led_info[led_code].trigger;
     138                 :            : 
     139                 :         84 :                 error = led_classdev_register(&dev->dev, &led->cdev);
     140         [ -  + ]:         84 :                 if (error) {
     141                 :          0 :                         dev_err(&dev->dev, "failed to register LED %s: %d\n",
     142                 :            :                                 led->cdev.name, error);
     143                 :          0 :                         kfree(led->cdev.name);
     144                 :          0 :                         goto err_unregister_leds;
     145                 :            :                 }
     146                 :            : 
     147                 :         84 :                 led_no++;
     148                 :            :         }
     149                 :            : 
     150                 :            :         return 0;
     151                 :            : 
     152                 :          0 : err_unregister_leds:
     153         [ #  # ]:          0 :         while (--led_no >= 0) {
     154                 :          0 :                 struct input_led *led = &leds->leds[led_no];
     155                 :            : 
     156                 :          0 :                 led_classdev_unregister(&led->cdev);
     157                 :          0 :                 kfree(led->cdev.name);
     158                 :            :         }
     159                 :            : 
     160                 :          0 :         input_close_device(&leds->handle);
     161                 :            : 
     162                 :          0 : err_unregister_handle:
     163                 :          0 :         input_unregister_handle(&leds->handle);
     164                 :            : 
     165                 :          0 : err_free_mem:
     166                 :          0 :         kfree(leds);
     167                 :          0 :         return error;
     168                 :            : }
     169                 :            : 
     170                 :          0 : static void input_leds_disconnect(struct input_handle *handle)
     171                 :            : {
     172                 :          0 :         struct input_leds *leds = handle->private;
     173                 :          0 :         int i;
     174                 :            : 
     175         [ #  # ]:          0 :         for (i = 0; i < leds->num_leds; i++) {
     176                 :          0 :                 struct input_led *led = &leds->leds[i];
     177                 :            : 
     178                 :          0 :                 led_classdev_unregister(&led->cdev);
     179                 :          0 :                 kfree(led->cdev.name);
     180                 :            :         }
     181                 :            : 
     182                 :          0 :         input_close_device(handle);
     183                 :          0 :         input_unregister_handle(handle);
     184                 :            : 
     185                 :          0 :         kfree(leds);
     186                 :          0 : }
     187                 :            : 
     188                 :            : static const struct input_device_id input_leds_ids[] = {
     189                 :            :         {
     190                 :            :                 .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
     191                 :            :                 .evbit = { BIT_MASK(EV_LED) },
     192                 :            :         },
     193                 :            :         { },
     194                 :            : };
     195                 :            : MODULE_DEVICE_TABLE(input, input_leds_ids);
     196                 :            : 
     197                 :            : static struct input_handler input_leds_handler = {
     198                 :            :         .event =        input_leds_event,
     199                 :            :         .connect =      input_leds_connect,
     200                 :            :         .disconnect =   input_leds_disconnect,
     201                 :            :         .name =         "leds",
     202                 :            :         .id_table =     input_leds_ids,
     203                 :            : };
     204                 :            : 
     205                 :         28 : static int __init input_leds_init(void)
     206                 :            : {
     207                 :         28 :         return input_register_handler(&input_leds_handler);
     208                 :            : }
     209                 :            : module_init(input_leds_init);
     210                 :            : 
     211                 :          0 : static void __exit input_leds_exit(void)
     212                 :            : {
     213                 :          0 :         input_unregister_handler(&input_leds_handler);
     214                 :          0 : }
     215                 :            : module_exit(input_leds_exit);
     216                 :            : 
     217                 :            : MODULE_AUTHOR("Samuel Thibault <samuel.thibault@ens-lyon.org>");
     218                 :            : MODULE_AUTHOR("Dmitry Torokhov <dmitry.torokhov@gmail.com>");
     219                 :            : MODULE_DESCRIPTION("Input -> LEDs Bridge");
     220                 :            : MODULE_LICENSE("GPL v2");

Generated by: LCOV version 1.14