linux/drivers/hid/hid-picolcd_leds.c
<<
>>
Prefs
   1/***************************************************************************
   2 *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
   3 *                                                                         *
   4 *   Based on Logitech G13 driver (v0.4)                                   *
   5 *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
   6 *                                                                         *
   7 *   This program is free software: you can redistribute it and/or modify  *
   8 *   it under the terms of the GNU General Public License as published by  *
   9 *   the Free Software Foundation, version 2 of the License.               *
  10 *                                                                         *
  11 *   This driver is distributed in the hope that it will be useful, but    *
  12 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
  13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
  14 *   General Public License for more details.                              *
  15 *                                                                         *
  16 *   You should have received a copy of the GNU General Public License     *
  17 *   along with this software. If not see <http://www.gnu.org/licenses/>.  *
  18 ***************************************************************************/
  19
  20#include <linux/hid.h>
  21#include <linux/hid-debug.h>
  22#include <linux/input.h>
  23#include "hid-ids.h"
  24
  25#include <linux/fb.h>
  26#include <linux/vmalloc.h>
  27#include <linux/backlight.h>
  28#include <linux/lcd.h>
  29
  30#include <linux/leds.h>
  31
  32#include <linux/seq_file.h>
  33#include <linux/debugfs.h>
  34
  35#include <linux/completion.h>
  36#include <linux/uaccess.h>
  37#include <linux/module.h>
  38
  39#include "hid-picolcd.h"
  40
  41
  42void picolcd_leds_set(struct picolcd_data *data)
  43{
  44        struct hid_report *report;
  45        unsigned long flags;
  46
  47        if (!data->led[0])
  48                return;
  49        report = picolcd_out_report(REPORT_LED_STATE, data->hdev);
  50        if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
  51                return;
  52
  53        spin_lock_irqsave(&data->lock, flags);
  54        hid_set_field(report->field[0], 0, data->led_state);
  55        if (!(data->status & PICOLCD_FAILED))
  56                hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT);
  57        spin_unlock_irqrestore(&data->lock, flags);
  58}
  59
  60static void picolcd_led_set_brightness(struct led_classdev *led_cdev,
  61                        enum led_brightness value)
  62{
  63        struct device *dev;
  64        struct hid_device *hdev;
  65        struct picolcd_data *data;
  66        int i, state = 0;
  67
  68        dev  = led_cdev->dev->parent;
  69        hdev = container_of(dev, struct hid_device, dev);
  70        data = hid_get_drvdata(hdev);
  71        if (!data)
  72                return;
  73        for (i = 0; i < 8; i++) {
  74                if (led_cdev != data->led[i])
  75                        continue;
  76                state = (data->led_state >> i) & 1;
  77                if (value == LED_OFF && state) {
  78                        data->led_state &= ~(1 << i);
  79                        picolcd_leds_set(data);
  80                } else if (value != LED_OFF && !state) {
  81                        data->led_state |= 1 << i;
  82                        picolcd_leds_set(data);
  83                }
  84                break;
  85        }
  86}
  87
  88static enum led_brightness picolcd_led_get_brightness(struct led_classdev *led_cdev)
  89{
  90        struct device *dev;
  91        struct hid_device *hdev;
  92        struct picolcd_data *data;
  93        int i, value = 0;
  94
  95        dev  = led_cdev->dev->parent;
  96        hdev = container_of(dev, struct hid_device, dev);
  97        data = hid_get_drvdata(hdev);
  98        for (i = 0; i < 8; i++)
  99                if (led_cdev == data->led[i]) {
 100                        value = (data->led_state >> i) & 1;
 101                        break;
 102                }
 103        return value ? LED_FULL : LED_OFF;
 104}
 105
 106int picolcd_init_leds(struct picolcd_data *data, struct hid_report *report)
 107{
 108        struct device *dev = &data->hdev->dev;
 109        struct led_classdev *led;
 110        size_t name_sz = strlen(dev_name(dev)) + 8;
 111        char *name;
 112        int i, ret = 0;
 113
 114        if (!report)
 115                return -ENODEV;
 116        if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
 117                        report->field[0]->report_size != 8) {
 118                dev_err(dev, "unsupported LED_STATE report");
 119                return -EINVAL;
 120        }
 121
 122        for (i = 0; i < 8; i++) {
 123                led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
 124                if (!led) {
 125                        dev_err(dev, "can't allocate memory for LED %d\n", i);
 126                        ret = -ENOMEM;
 127                        goto err;
 128                }
 129                name = (void *)(&led[1]);
 130                snprintf(name, name_sz, "%s::GPO%d", dev_name(dev), i);
 131                led->name = name;
 132                led->brightness = 0;
 133                led->max_brightness = 1;
 134                led->brightness_get = picolcd_led_get_brightness;
 135                led->brightness_set = picolcd_led_set_brightness;
 136
 137                data->led[i] = led;
 138                ret = led_classdev_register(dev, data->led[i]);
 139                if (ret) {
 140                        data->led[i] = NULL;
 141                        kfree(led);
 142                        dev_err(dev, "can't register LED %d\n", i);
 143                        goto err;
 144                }
 145        }
 146        return 0;
 147err:
 148        for (i = 0; i < 8; i++)
 149                if (data->led[i]) {
 150                        led = data->led[i];
 151                        data->led[i] = NULL;
 152                        led_classdev_unregister(led);
 153                        kfree(led);
 154                }
 155        return ret;
 156}
 157
 158void picolcd_exit_leds(struct picolcd_data *data)
 159{
 160        struct led_classdev *led;
 161        int i;
 162
 163        for (i = 0; i < 8; i++) {
 164                led = data->led[i];
 165                data->led[i] = NULL;
 166                if (!led)
 167                        continue;
 168                led_classdev_unregister(led);
 169                kfree(led);
 170        }
 171}
 172
 173
 174