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#include "usbhid/usbhid.h"
  25#include <linux/usb.h>
  26
  27#include <linux/fb.h>
  28#include <linux/vmalloc.h>
  29#include <linux/backlight.h>
  30#include <linux/lcd.h>
  31
  32#include <linux/leds.h>
  33
  34#include <linux/seq_file.h>
  35#include <linux/debugfs.h>
  36
  37#include <linux/completion.h>
  38#include <linux/uaccess.h>
  39#include <linux/module.h>
  40
  41#include "hid-picolcd.h"
  42
  43
  44void picolcd_leds_set(struct picolcd_data *data)
  45{
  46        struct hid_report *report;
  47        unsigned long flags;
  48
  49        if (!data->led[0])
  50                return;
  51        report = picolcd_out_report(REPORT_LED_STATE, data->hdev);
  52        if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
  53                return;
  54
  55        spin_lock_irqsave(&data->lock, flags);
  56        hid_set_field(report->field[0], 0, data->led_state);
  57        if (!(data->status & PICOLCD_FAILED))
  58                usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
  59        spin_unlock_irqrestore(&data->lock, flags);
  60}
  61
  62static void picolcd_led_set_brightness(struct led_classdev *led_cdev,
  63                        enum led_brightness value)
  64{
  65        struct device *dev;
  66        struct hid_device *hdev;
  67        struct picolcd_data *data;
  68        int i, state = 0;
  69
  70        dev  = led_cdev->dev->parent;
  71        hdev = container_of(dev, struct hid_device, dev);
  72        data = hid_get_drvdata(hdev);
  73        if (!data)
  74                return;
  75        for (i = 0; i < 8; i++) {
  76                if (led_cdev != data->led[i])
  77                        continue;
  78                state = (data->led_state >> i) & 1;
  79                if (value == LED_OFF && state) {
  80                        data->led_state &= ~(1 << i);
  81                        picolcd_leds_set(data);
  82                } else if (value != LED_OFF && !state) {
  83                        data->led_state |= 1 << i;
  84                        picolcd_leds_set(data);
  85                }
  86                break;
  87        }
  88}
  89
  90static enum led_brightness picolcd_led_get_brightness(struct led_classdev *led_cdev)
  91{
  92        struct device *dev;
  93        struct hid_device *hdev;
  94        struct picolcd_data *data;
  95        int i, value = 0;
  96
  97        dev  = led_cdev->dev->parent;
  98        hdev = container_of(dev, struct hid_device, dev);
  99        data = hid_get_drvdata(hdev);
 100        for (i = 0; i < 8; i++)
 101                if (led_cdev == data->led[i]) {
 102                        value = (data->led_state >> i) & 1;
 103                        break;
 104                }
 105        return value ? LED_FULL : LED_OFF;
 106}
 107
 108int picolcd_init_leds(struct picolcd_data *data, struct hid_report *report)
 109{
 110        struct device *dev = &data->hdev->dev;
 111        struct led_classdev *led;
 112        size_t name_sz = strlen(dev_name(dev)) + 8;
 113        char *name;
 114        int i, ret = 0;
 115
 116        if (!report)
 117                return -ENODEV;
 118        if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
 119                        report->field[0]->report_size != 8) {
 120                dev_err(dev, "unsupported LED_STATE report");
 121                return -EINVAL;
 122        }
 123
 124        for (i = 0; i < 8; i++) {
 125                led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
 126                if (!led) {
 127                        dev_err(dev, "can't allocate memory for LED %d\n", i);
 128                        ret = -ENOMEM;
 129                        goto err;
 130                }
 131                name = (void *)(&led[1]);
 132                snprintf(name, name_sz, "%s::GPO%d", dev_name(dev), i);
 133                led->name = name;
 134                led->brightness = 0;
 135                led->max_brightness = 1;
 136                led->brightness_get = picolcd_led_get_brightness;
 137                led->brightness_set = picolcd_led_set_brightness;
 138
 139                data->led[i] = led;
 140                ret = led_classdev_register(dev, data->led[i]);
 141                if (ret) {
 142                        data->led[i] = NULL;
 143                        kfree(led);
 144                        dev_err(dev, "can't register LED %d\n", i);
 145                        goto err;
 146                }
 147        }
 148        return 0;
 149err:
 150        for (i = 0; i < 8; i++)
 151                if (data->led[i]) {
 152                        led = data->led[i];
 153                        data->led[i] = NULL;
 154                        led_classdev_unregister(led);
 155                        kfree(led);
 156                }
 157        return ret;
 158}
 159
 160void picolcd_exit_leds(struct picolcd_data *data)
 161{
 162        struct led_classdev *led;
 163        int i;
 164
 165        for (i = 0; i < 8; i++) {
 166                led = data->led[i];
 167                data->led[i] = NULL;
 168                if (!led)
 169                        continue;
 170                led_classdev_unregister(led);
 171                kfree(led);
 172        }
 173}
 174
 175
 176
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.