cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

input-leds.c (5151B)


      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
     21static 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
     38struct input_led {
     39	struct led_classdev cdev;
     40	struct input_handle *handle;
     41	unsigned int code; /* One of LED_* constants */
     42};
     43
     44struct input_leds {
     45	struct input_handle handle;
     46	unsigned int num_leds;
     47	struct input_led leds[];
     48};
     49
     50static enum led_brightness input_leds_brightness_get(struct led_classdev *cdev)
     51{
     52	struct input_led *led = container_of(cdev, struct input_led, cdev);
     53	struct input_dev *input = led->handle->dev;
     54
     55	return test_bit(led->code, input->led) ? cdev->max_brightness : 0;
     56}
     57
     58static void input_leds_brightness_set(struct led_classdev *cdev,
     59				      enum led_brightness brightness)
     60{
     61	struct input_led *led = container_of(cdev, struct input_led, cdev);
     62
     63	input_inject_event(led->handle, EV_LED, led->code, !!brightness);
     64}
     65
     66static void input_leds_event(struct input_handle *handle, unsigned int type,
     67			     unsigned int code, int value)
     68{
     69}
     70
     71static int input_leds_get_count(struct input_dev *dev)
     72{
     73	unsigned int led_code;
     74	int count = 0;
     75
     76	for_each_set_bit(led_code, dev->ledbit, LED_CNT)
     77		if (input_led_info[led_code].name)
     78			count++;
     79
     80	return count;
     81}
     82
     83static int input_leds_connect(struct input_handler *handler,
     84			      struct input_dev *dev,
     85			      const struct input_device_id *id)
     86{
     87	struct input_leds *leds;
     88	struct input_led *led;
     89	unsigned int num_leds;
     90	unsigned int led_code;
     91	int led_no;
     92	int error;
     93
     94	num_leds = input_leds_get_count(dev);
     95	if (!num_leds)
     96		return -ENXIO;
     97
     98	leds = kzalloc(struct_size(leds, leds, num_leds), GFP_KERNEL);
     99	if (!leds)
    100		return -ENOMEM;
    101
    102	leds->num_leds = num_leds;
    103
    104	leds->handle.dev = dev;
    105	leds->handle.handler = handler;
    106	leds->handle.name = "leds";
    107	leds->handle.private = leds;
    108
    109	error = input_register_handle(&leds->handle);
    110	if (error)
    111		goto err_free_mem;
    112
    113	error = input_open_device(&leds->handle);
    114	if (error)
    115		goto err_unregister_handle;
    116
    117	led_no = 0;
    118	for_each_set_bit(led_code, dev->ledbit, LED_CNT) {
    119		if (!input_led_info[led_code].name)
    120			continue;
    121
    122		led = &leds->leds[led_no];
    123		led->handle = &leds->handle;
    124		led->code = led_code;
    125
    126		led->cdev.name = kasprintf(GFP_KERNEL, "%s::%s",
    127					   dev_name(&dev->dev),
    128					   input_led_info[led_code].name);
    129		if (!led->cdev.name) {
    130			error = -ENOMEM;
    131			goto err_unregister_leds;
    132		}
    133
    134		led->cdev.max_brightness = 1;
    135		led->cdev.brightness_get = input_leds_brightness_get;
    136		led->cdev.brightness_set = input_leds_brightness_set;
    137		led->cdev.default_trigger = input_led_info[led_code].trigger;
    138
    139		error = led_classdev_register(&dev->dev, &led->cdev);
    140		if (error) {
    141			dev_err(&dev->dev, "failed to register LED %s: %d\n",
    142				led->cdev.name, error);
    143			kfree(led->cdev.name);
    144			goto err_unregister_leds;
    145		}
    146
    147		led_no++;
    148	}
    149
    150	return 0;
    151
    152err_unregister_leds:
    153	while (--led_no >= 0) {
    154		struct input_led *led = &leds->leds[led_no];
    155
    156		led_classdev_unregister(&led->cdev);
    157		kfree(led->cdev.name);
    158	}
    159
    160	input_close_device(&leds->handle);
    161
    162err_unregister_handle:
    163	input_unregister_handle(&leds->handle);
    164
    165err_free_mem:
    166	kfree(leds);
    167	return error;
    168}
    169
    170static void input_leds_disconnect(struct input_handle *handle)
    171{
    172	struct input_leds *leds = handle->private;
    173	int i;
    174
    175	for (i = 0; i < leds->num_leds; i++) {
    176		struct input_led *led = &leds->leds[i];
    177
    178		led_classdev_unregister(&led->cdev);
    179		kfree(led->cdev.name);
    180	}
    181
    182	input_close_device(handle);
    183	input_unregister_handle(handle);
    184
    185	kfree(leds);
    186}
    187
    188static 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};
    195MODULE_DEVICE_TABLE(input, input_leds_ids);
    196
    197static 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
    205static int __init input_leds_init(void)
    206{
    207	return input_register_handler(&input_leds_handler);
    208}
    209module_init(input_leds_init);
    210
    211static void __exit input_leds_exit(void)
    212{
    213	input_unregister_handler(&input_leds_handler);
    214}
    215module_exit(input_leds_exit);
    216
    217MODULE_AUTHOR("Samuel Thibault <samuel.thibault@ens-lyon.org>");
    218MODULE_AUTHOR("Dmitry Torokhov <dmitry.torokhov@gmail.com>");
    219MODULE_DESCRIPTION("Input -> LEDs Bridge");
    220MODULE_LICENSE("GPL v2");