Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /***************************************************************************
0003  *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
0004  *                                                                         *
0005  *   Based on Logitech G13 driver (v0.4)                                   *
0006  *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
0007  *                                                                         *
0008  ***************************************************************************/
0009 
0010 #include <linux/hid.h>
0011 #include <linux/hid-debug.h>
0012 #include <linux/input.h>
0013 #include "hid-ids.h"
0014 
0015 #include <linux/fb.h>
0016 #include <linux/vmalloc.h>
0017 #include <linux/backlight.h>
0018 #include <linux/lcd.h>
0019 
0020 #include <linux/leds.h>
0021 
0022 #include <linux/seq_file.h>
0023 #include <linux/debugfs.h>
0024 
0025 #include <linux/completion.h>
0026 #include <linux/uaccess.h>
0027 #include <linux/module.h>
0028 
0029 #include "hid-picolcd.h"
0030 
0031 
0032 void picolcd_leds_set(struct picolcd_data *data)
0033 {
0034     struct hid_report *report;
0035     unsigned long flags;
0036 
0037     if (!data->led[0])
0038         return;
0039     report = picolcd_out_report(REPORT_LED_STATE, data->hdev);
0040     if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
0041         return;
0042 
0043     spin_lock_irqsave(&data->lock, flags);
0044     hid_set_field(report->field[0], 0, data->led_state);
0045     if (!(data->status & PICOLCD_FAILED))
0046         hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT);
0047     spin_unlock_irqrestore(&data->lock, flags);
0048 }
0049 
0050 static void picolcd_led_set_brightness(struct led_classdev *led_cdev,
0051             enum led_brightness value)
0052 {
0053     struct device *dev;
0054     struct hid_device *hdev;
0055     struct picolcd_data *data;
0056     int i, state = 0;
0057 
0058     dev  = led_cdev->dev->parent;
0059     hdev = to_hid_device(dev);
0060     data = hid_get_drvdata(hdev);
0061     if (!data)
0062         return;
0063     for (i = 0; i < 8; i++) {
0064         if (led_cdev != data->led[i])
0065             continue;
0066         state = (data->led_state >> i) & 1;
0067         if (value == LED_OFF && state) {
0068             data->led_state &= ~(1 << i);
0069             picolcd_leds_set(data);
0070         } else if (value != LED_OFF && !state) {
0071             data->led_state |= 1 << i;
0072             picolcd_leds_set(data);
0073         }
0074         break;
0075     }
0076 }
0077 
0078 static enum led_brightness picolcd_led_get_brightness(struct led_classdev *led_cdev)
0079 {
0080     struct device *dev;
0081     struct hid_device *hdev;
0082     struct picolcd_data *data;
0083     int i, value = 0;
0084 
0085     dev  = led_cdev->dev->parent;
0086     hdev = to_hid_device(dev);
0087     data = hid_get_drvdata(hdev);
0088     for (i = 0; i < 8; i++)
0089         if (led_cdev == data->led[i]) {
0090             value = (data->led_state >> i) & 1;
0091             break;
0092         }
0093     return value ? LED_FULL : LED_OFF;
0094 }
0095 
0096 int picolcd_init_leds(struct picolcd_data *data, struct hid_report *report)
0097 {
0098     struct device *dev = &data->hdev->dev;
0099     struct led_classdev *led;
0100     size_t name_sz = strlen(dev_name(dev)) + 8;
0101     char *name;
0102     int i, ret = 0;
0103 
0104     if (!report)
0105         return -ENODEV;
0106     if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
0107             report->field[0]->report_size != 8) {
0108         dev_err(dev, "unsupported LED_STATE report");
0109         return -EINVAL;
0110     }
0111 
0112     for (i = 0; i < 8; i++) {
0113         led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
0114         if (!led) {
0115             dev_err(dev, "can't allocate memory for LED %d\n", i);
0116             ret = -ENOMEM;
0117             goto err;
0118         }
0119         name = (void *)(&led[1]);
0120         snprintf(name, name_sz, "%s::GPO%d", dev_name(dev), i);
0121         led->name = name;
0122         led->brightness = 0;
0123         led->max_brightness = 1;
0124         led->brightness_get = picolcd_led_get_brightness;
0125         led->brightness_set = picolcd_led_set_brightness;
0126 
0127         data->led[i] = led;
0128         ret = led_classdev_register(dev, data->led[i]);
0129         if (ret) {
0130             data->led[i] = NULL;
0131             kfree(led);
0132             dev_err(dev, "can't register LED %d\n", i);
0133             goto err;
0134         }
0135     }
0136     return 0;
0137 err:
0138     for (i = 0; i < 8; i++)
0139         if (data->led[i]) {
0140             led = data->led[i];
0141             data->led[i] = NULL;
0142             led_classdev_unregister(led);
0143             kfree(led);
0144         }
0145     return ret;
0146 }
0147 
0148 void picolcd_exit_leds(struct picolcd_data *data)
0149 {
0150     struct led_classdev *led;
0151     int i;
0152 
0153     for (i = 0; i < 8; i++) {
0154         led = data->led[i];
0155         data->led[i] = NULL;
0156         if (!led)
0157             continue;
0158         led_classdev_unregister(led);
0159         kfree(led);
0160     }
0161 }
0162 
0163