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

hid-picolcd_leds.c (4053B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/***************************************************************************
      3 *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
      4 *                                                                         *
      5 *   Based on Logitech G13 driver (v0.4)                                   *
      6 *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
      7 *                                                                         *
      8 ***************************************************************************/
      9
     10#include <linux/hid.h>
     11#include <linux/hid-debug.h>
     12#include <linux/input.h>
     13#include "hid-ids.h"
     14
     15#include <linux/fb.h>
     16#include <linux/vmalloc.h>
     17#include <linux/backlight.h>
     18#include <linux/lcd.h>
     19
     20#include <linux/leds.h>
     21
     22#include <linux/seq_file.h>
     23#include <linux/debugfs.h>
     24
     25#include <linux/completion.h>
     26#include <linux/uaccess.h>
     27#include <linux/module.h>
     28
     29#include "hid-picolcd.h"
     30
     31
     32void picolcd_leds_set(struct picolcd_data *data)
     33{
     34	struct hid_report *report;
     35	unsigned long flags;
     36
     37	if (!data->led[0])
     38		return;
     39	report = picolcd_out_report(REPORT_LED_STATE, data->hdev);
     40	if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
     41		return;
     42
     43	spin_lock_irqsave(&data->lock, flags);
     44	hid_set_field(report->field[0], 0, data->led_state);
     45	if (!(data->status & PICOLCD_FAILED))
     46		hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT);
     47	spin_unlock_irqrestore(&data->lock, flags);
     48}
     49
     50static void picolcd_led_set_brightness(struct led_classdev *led_cdev,
     51			enum led_brightness value)
     52{
     53	struct device *dev;
     54	struct hid_device *hdev;
     55	struct picolcd_data *data;
     56	int i, state = 0;
     57
     58	dev  = led_cdev->dev->parent;
     59	hdev = to_hid_device(dev);
     60	data = hid_get_drvdata(hdev);
     61	if (!data)
     62		return;
     63	for (i = 0; i < 8; i++) {
     64		if (led_cdev != data->led[i])
     65			continue;
     66		state = (data->led_state >> i) & 1;
     67		if (value == LED_OFF && state) {
     68			data->led_state &= ~(1 << i);
     69			picolcd_leds_set(data);
     70		} else if (value != LED_OFF && !state) {
     71			data->led_state |= 1 << i;
     72			picolcd_leds_set(data);
     73		}
     74		break;
     75	}
     76}
     77
     78static enum led_brightness picolcd_led_get_brightness(struct led_classdev *led_cdev)
     79{
     80	struct device *dev;
     81	struct hid_device *hdev;
     82	struct picolcd_data *data;
     83	int i, value = 0;
     84
     85	dev  = led_cdev->dev->parent;
     86	hdev = to_hid_device(dev);
     87	data = hid_get_drvdata(hdev);
     88	for (i = 0; i < 8; i++)
     89		if (led_cdev == data->led[i]) {
     90			value = (data->led_state >> i) & 1;
     91			break;
     92		}
     93	return value ? LED_FULL : LED_OFF;
     94}
     95
     96int picolcd_init_leds(struct picolcd_data *data, struct hid_report *report)
     97{
     98	struct device *dev = &data->hdev->dev;
     99	struct led_classdev *led;
    100	size_t name_sz = strlen(dev_name(dev)) + 8;
    101	char *name;
    102	int i, ret = 0;
    103
    104	if (!report)
    105		return -ENODEV;
    106	if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
    107			report->field[0]->report_size != 8) {
    108		dev_err(dev, "unsupported LED_STATE report");
    109		return -EINVAL;
    110	}
    111
    112	for (i = 0; i < 8; i++) {
    113		led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
    114		if (!led) {
    115			dev_err(dev, "can't allocate memory for LED %d\n", i);
    116			ret = -ENOMEM;
    117			goto err;
    118		}
    119		name = (void *)(&led[1]);
    120		snprintf(name, name_sz, "%s::GPO%d", dev_name(dev), i);
    121		led->name = name;
    122		led->brightness = 0;
    123		led->max_brightness = 1;
    124		led->brightness_get = picolcd_led_get_brightness;
    125		led->brightness_set = picolcd_led_set_brightness;
    126
    127		data->led[i] = led;
    128		ret = led_classdev_register(dev, data->led[i]);
    129		if (ret) {
    130			data->led[i] = NULL;
    131			kfree(led);
    132			dev_err(dev, "can't register LED %d\n", i);
    133			goto err;
    134		}
    135	}
    136	return 0;
    137err:
    138	for (i = 0; i < 8; i++)
    139		if (data->led[i]) {
    140			led = data->led[i];
    141			data->led[i] = NULL;
    142			led_classdev_unregister(led);
    143			kfree(led);
    144		}
    145	return ret;
    146}
    147
    148void picolcd_exit_leds(struct picolcd_data *data)
    149{
    150	struct led_classdev *led;
    151	int i;
    152
    153	for (i = 0; i < 8; i++) {
    154		led = data->led[i];
    155		data->led[i] = NULL;
    156		if (!led)
    157			continue;
    158		led_classdev_unregister(led);
    159		kfree(led);
    160	}
    161}
    162
    163