]> git.karo-electronics.de Git - linux-beck.git/commitdiff
HID: hid-led: add support for devices with multiple independent LEDs
authorHeiner Kallweit <hkallweit1@gmail.com>
Tue, 21 Jun 2016 19:48:26 +0000 (21:48 +0200)
committerJiri Kosina <jkosina@suse.cz>
Thu, 23 Jun 2016 06:47:40 +0000 (08:47 +0200)
Add generic support for devices with multiple independent LED's.

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
drivers/hid/hid-led.c

index 43fb089a8cd56a3255cd367e4ba386cda81926e2..d5d8d941c4b0a79e614ed6fd61253318e0f3765d 100644 (file)
@@ -43,12 +43,14 @@ static unsigned const char riso_kagaku_tbl[] = {
 #define RISO_KAGAKU_IX(r, g, b) riso_kagaku_tbl[((r)?1:0)+((g)?2:0)+((b)?4:0)]
 
 struct hidled_device;
+struct hidled_rgb;
 
 struct hidled_config {
        enum hidled_type        type;
        const char              *name;
        const char              *short_name;
        enum led_brightness     max_brightness;
+       int                     num_leds;
        size_t                  report_size;
        enum hidled_report_type report_type;
        u8                      report_id;
@@ -58,16 +60,22 @@ struct hidled_config {
 
 struct hidled_led {
        struct led_classdev     cdev;
-       struct hidled_device    *ldev;
+       struct hidled_rgb       *rgb;
        char                    name[32];
 };
 
-struct hidled_device {
-       const struct hidled_config *config;
+struct hidled_rgb {
+       struct hidled_device    *ldev;
        struct hidled_led       red;
        struct hidled_led       green;
        struct hidled_led       blue;
+       u8                      num;
+};
+
+struct hidled_device {
+       const struct hidled_config *config;
        struct hid_device       *hdev;
+       struct hidled_rgb       *rgb;
        struct mutex            lock;
 };
 
@@ -107,13 +115,13 @@ static int hidled_send(struct hidled_device *ldev, __u8 *buf)
        return ret == ldev->config->report_size ? 0 : -EMSGSIZE;
 }
 
-static u8 riso_kagaku_index(struct hidled_device *ldev)
+static u8 riso_kagaku_index(struct hidled_rgb *rgb)
 {
        enum led_brightness r, g, b;
 
-       r = ldev->red.cdev.brightness;
-       g = ldev->green.cdev.brightness;
-       b = ldev->blue.cdev.brightness;
+       r = rgb->red.cdev.brightness;
+       g = rgb->green.cdev.brightness;
+       b = rgb->blue.cdev.brightness;
 
        if (riso_kagaku_switch_green_blue)
                return RISO_KAGAKU_IX(r, b, g);
@@ -124,27 +132,27 @@ static u8 riso_kagaku_index(struct hidled_device *ldev)
 static int riso_kagaku_write(struct led_classdev *cdev, enum led_brightness br)
 {
        struct hidled_led *led = to_hidled_led(cdev);
-       struct hidled_device *ldev = led->ldev;
+       struct hidled_rgb *rgb = led->rgb;
        __u8 buf[MAX_REPORT_SIZE] = {};
 
-       buf[1] = riso_kagaku_index(ldev);
+       buf[1] = riso_kagaku_index(rgb);
 
-       return hidled_send(ldev, buf);
+       return hidled_send(rgb->ldev, buf);
 }
 
 static int dream_cheeky_write(struct led_classdev *cdev, enum led_brightness br)
 {
        struct hidled_led *led = to_hidled_led(cdev);
-       struct hidled_device *ldev = led->ldev;
+       struct hidled_rgb *rgb = led->rgb;
        __u8 buf[MAX_REPORT_SIZE] = {};
 
-       buf[1] = ldev->red.cdev.brightness;
-       buf[2] = ldev->green.cdev.brightness;
-       buf[3] = ldev->blue.cdev.brightness;
+       buf[1] = rgb->red.cdev.brightness;
+       buf[2] = rgb->green.cdev.brightness;
+       buf[3] = rgb->blue.cdev.brightness;
        buf[7] = 0x1a;
        buf[8] = 0x05;
 
-       return hidled_send(ldev, buf);
+       return hidled_send(rgb->ldev, buf);
 }
 
 static int dream_cheeky_init(struct hidled_device *ldev)
@@ -167,6 +175,7 @@ static const struct hidled_config hidled_configs[] = {
                .name = "Riso Kagaku Webmail Notifier",
                .short_name = "riso_kagaku",
                .max_brightness = 1,
+               .num_leds = 1,
                .report_size = 6,
                .report_type = OUTPUT_REPORT,
                .report_id = 0,
@@ -177,6 +186,7 @@ static const struct hidled_config hidled_configs[] = {
                .name = "Dream Cheeky Webmail Notifier",
                .short_name = "dream_cheeky",
                .max_brightness = 31,
+               .num_leds = 1,
                .report_size = 9,
                .report_type = RAW_REQUEST,
                .report_id = 0,
@@ -186,35 +196,41 @@ static const struct hidled_config hidled_configs[] = {
 };
 
 static int hidled_init_led(struct hidled_led *led, const char *color_name,
-                          struct hidled_device *ldev, unsigned int minor)
+                          struct hidled_rgb *rgb, unsigned int minor)
 {
-       snprintf(led->name, sizeof(led->name), "%s%u:%s",
-                ldev->config->short_name, minor, color_name);
+       const struct hidled_config *config = rgb->ldev->config;
+
+       if (config->num_leds > 1)
+               snprintf(led->name, sizeof(led->name), "%s%u:%s:led%u",
+                        config->short_name, minor, color_name, rgb->num);
+       else
+               snprintf(led->name, sizeof(led->name), "%s%u:%s",
+                        config->short_name, minor, color_name);
        led->cdev.name = led->name;
-       led->cdev.max_brightness = ldev->config->max_brightness;
-       led->cdev.brightness_set_blocking = ldev->config->write;
+       led->cdev.max_brightness = config->max_brightness;
+       led->cdev.brightness_set_blocking = config->write;
        led->cdev.flags = LED_HW_PLUGGABLE;
-       led->ldev = ldev;
+       led->rgb = rgb;
 
-       return devm_led_classdev_register(&ldev->hdev->dev, &led->cdev);
+       return devm_led_classdev_register(&rgb->ldev->hdev->dev, &led->cdev);
 }
 
-static int hidled_init_rgb(struct hidled_device *ldev, unsigned int minor)
+static int hidled_init_rgb(struct hidled_rgb *rgb, unsigned int minor)
 {
        int ret;
 
        /* Register the red diode */
-       ret = hidled_init_led(&ldev->red, "red", ldev, minor);
+       ret = hidled_init_led(&rgb->red, "red", rgb, minor);
        if (ret)
                return ret;
 
        /* Register the green diode */
-       ret = hidled_init_led(&ldev->green, "green", ldev, minor);
+       ret = hidled_init_led(&rgb->green, "green", rgb, minor);
        if (ret)
                return ret;
 
        /* Register the blue diode */
-       return hidled_init_led(&ldev->blue, "blue", ldev, minor);
+       return hidled_init_led(&rgb->blue, "blue", rgb, minor);
 }
 
 static int hidled_probe(struct hid_device *hdev, const struct hid_device_id *id)
@@ -247,16 +263,25 @@ static int hidled_probe(struct hid_device *hdev, const struct hid_device_id *id)
                        return ret;
        }
 
+       ldev->rgb = devm_kcalloc(&hdev->dev, ldev->config->num_leds,
+                                sizeof(struct hidled_rgb), GFP_KERNEL);
+       if (!ldev->rgb)
+               return -ENOMEM;
+
        ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
        if (ret)
                return ret;
 
        minor = ((struct hidraw *) hdev->hidraw)->minor;
 
-       ret = hidled_init_rgb(ldev, minor);
-       if (ret) {
-               hid_hw_stop(hdev);
-               return ret;
+       for (i = 0; i < ldev->config->num_leds; i++) {
+               ldev->rgb[i].ldev = ldev;
+               ldev->rgb[i].num = i;
+               ret = hidled_init_rgb(&ldev->rgb[i], minor);
+               if (ret) {
+                       hid_hw_stop(hdev);
+                       return ret;
+               }
        }
 
        hid_info(hdev, "%s initialized\n", ldev->config->name);