linux/drivers/hid/hid-lg-g15.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 *  HID driver for gaming keys on Logitech gaming keyboards (such as the G15)
   4 *
   5 *  Copyright (c) 2019 Hans de Goede <hdegoede@redhat.com>
   6 */
   7
   8#include <linux/device.h>
   9#include <linux/hid.h>
  10#include <linux/module.h>
  11#include <linux/random.h>
  12#include <linux/sched.h>
  13#include <linux/usb.h>
  14#include <linux/wait.h>
  15
  16#include "hid-ids.h"
  17
  18#define LG_G15_TRANSFER_BUF_SIZE        20
  19
  20#define LG_G15_FEATURE_REPORT           0x02
  21
  22#define LG_G510_FEATURE_M_KEYS_LEDS     0x04
  23#define LG_G510_FEATURE_BACKLIGHT_RGB   0x05
  24#define LG_G510_FEATURE_POWER_ON_RGB    0x06
  25
  26enum lg_g15_model {
  27        LG_G15,
  28        LG_G15_V2,
  29        LG_G510,
  30        LG_G510_USB_AUDIO,
  31        LG_Z10,
  32};
  33
  34enum lg_g15_led_type {
  35        LG_G15_KBD_BRIGHTNESS,
  36        LG_G15_LCD_BRIGHTNESS,
  37        LG_G15_BRIGHTNESS_MAX,
  38        LG_G15_MACRO_PRESET1 = 2,
  39        LG_G15_MACRO_PRESET2,
  40        LG_G15_MACRO_PRESET3,
  41        LG_G15_MACRO_RECORD,
  42        LG_G15_LED_MAX
  43};
  44
  45struct lg_g15_led {
  46        struct led_classdev cdev;
  47        enum led_brightness brightness;
  48        enum lg_g15_led_type led;
  49        u8 red, green, blue;
  50};
  51
  52struct lg_g15_data {
  53        /* Must be first for proper dma alignment */
  54        u8 transfer_buf[LG_G15_TRANSFER_BUF_SIZE];
  55        /* Protects the transfer_buf and led brightness */
  56        struct mutex mutex;
  57        struct work_struct work;
  58        struct input_dev *input;
  59        struct hid_device *hdev;
  60        enum lg_g15_model model;
  61        struct lg_g15_led leds[LG_G15_LED_MAX];
  62        bool game_mode_enabled;
  63};
  64
  65/******** G15 and G15 v2 LED functions ********/
  66
  67static int lg_g15_update_led_brightness(struct lg_g15_data *g15)
  68{
  69        int ret;
  70
  71        ret = hid_hw_raw_request(g15->hdev, LG_G15_FEATURE_REPORT,
  72                                 g15->transfer_buf, 4,
  73                                 HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
  74        if (ret != 4) {
  75                hid_err(g15->hdev, "Error getting LED brightness: %d\n", ret);
  76                return (ret < 0) ? ret : -EIO;
  77        }
  78
  79        g15->leds[LG_G15_KBD_BRIGHTNESS].brightness = g15->transfer_buf[1];
  80        g15->leds[LG_G15_LCD_BRIGHTNESS].brightness = g15->transfer_buf[2];
  81
  82        g15->leds[LG_G15_MACRO_PRESET1].brightness =
  83                !(g15->transfer_buf[3] & 0x01);
  84        g15->leds[LG_G15_MACRO_PRESET2].brightness =
  85                !(g15->transfer_buf[3] & 0x02);
  86        g15->leds[LG_G15_MACRO_PRESET3].brightness =
  87                !(g15->transfer_buf[3] & 0x04);
  88        g15->leds[LG_G15_MACRO_RECORD].brightness =
  89                !(g15->transfer_buf[3] & 0x08);
  90
  91        return 0;
  92}
  93
  94static enum led_brightness lg_g15_led_get(struct led_classdev *led_cdev)
  95{
  96        struct lg_g15_led *g15_led =
  97                container_of(led_cdev, struct lg_g15_led, cdev);
  98        struct lg_g15_data *g15 = dev_get_drvdata(led_cdev->dev->parent);
  99        enum led_brightness brightness;
 100
 101        mutex_lock(&g15->mutex);
 102        lg_g15_update_led_brightness(g15);
 103        brightness = g15->leds[g15_led->led].brightness;
 104        mutex_unlock(&g15->mutex);
 105
 106        return brightness;
 107}
 108
 109static int lg_g15_led_set(struct led_classdev *led_cdev,
 110                          enum led_brightness brightness)
 111{
 112        struct lg_g15_led *g15_led =
 113                container_of(led_cdev, struct lg_g15_led, cdev);
 114        struct lg_g15_data *g15 = dev_get_drvdata(led_cdev->dev->parent);
 115        u8 val, mask = 0;
 116        int i, ret;
 117
 118        /* Ignore LED off on unregister / keyboard unplug */
 119        if (led_cdev->flags & LED_UNREGISTERING)
 120                return 0;
 121
 122        mutex_lock(&g15->mutex);
 123
 124        g15->transfer_buf[0] = LG_G15_FEATURE_REPORT;
 125        g15->transfer_buf[3] = 0;
 126
 127        if (g15_led->led < LG_G15_BRIGHTNESS_MAX) {
 128                g15->transfer_buf[1] = g15_led->led + 1;
 129                g15->transfer_buf[2] = brightness << (g15_led->led * 4);
 130        } else {
 131                for (i = LG_G15_MACRO_PRESET1; i < LG_G15_LED_MAX; i++) {
 132                        if (i == g15_led->led)
 133                                val = brightness;
 134                        else
 135                                val = g15->leds[i].brightness;
 136
 137                        if (val)
 138                                mask |= 1 << (i - LG_G15_MACRO_PRESET1);
 139                }
 140
 141                g15->transfer_buf[1] = 0x04;
 142                g15->transfer_buf[2] = ~mask;
 143        }
 144
 145        ret = hid_hw_raw_request(g15->hdev, LG_G15_FEATURE_REPORT,
 146                                 g15->transfer_buf, 4,
 147                                 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
 148        if (ret == 4) {
 149                /* Success */
 150                g15_led->brightness = brightness;
 151                ret = 0;
 152        } else {
 153                hid_err(g15->hdev, "Error setting LED brightness: %d\n", ret);
 154                ret = (ret < 0) ? ret : -EIO;
 155        }
 156
 157        mutex_unlock(&g15->mutex);
 158
 159        return ret;
 160}
 161
 162static void lg_g15_leds_changed_work(struct work_struct *work)
 163{
 164        struct lg_g15_data *g15 = container_of(work, struct lg_g15_data, work);
 165        enum led_brightness old_brightness[LG_G15_BRIGHTNESS_MAX];
 166        enum led_brightness brightness[LG_G15_BRIGHTNESS_MAX];
 167        int i, ret;
 168
 169        mutex_lock(&g15->mutex);
 170        for (i = 0; i < LG_G15_BRIGHTNESS_MAX; i++)
 171                old_brightness[i] = g15->leds[i].brightness;
 172
 173        ret = lg_g15_update_led_brightness(g15);
 174
 175        for (i = 0; i < LG_G15_BRIGHTNESS_MAX; i++)
 176                brightness[i] = g15->leds[i].brightness;
 177        mutex_unlock(&g15->mutex);
 178
 179        if (ret)
 180                return;
 181
 182        for (i = 0; i < LG_G15_BRIGHTNESS_MAX; i++) {
 183                if (brightness[i] == old_brightness[i])
 184                        continue;
 185
 186                led_classdev_notify_brightness_hw_changed(&g15->leds[i].cdev,
 187                                                          brightness[i]);
 188        }
 189}
 190
 191/******** G510 LED functions ********/
 192
 193static int lg_g510_get_initial_led_brightness(struct lg_g15_data *g15, int i)
 194{
 195        int ret, high;
 196
 197        ret = hid_hw_raw_request(g15->hdev, LG_G510_FEATURE_BACKLIGHT_RGB + i,
 198                                 g15->transfer_buf, 4,
 199                                 HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
 200        if (ret != 4) {
 201                hid_err(g15->hdev, "Error getting LED brightness: %d\n", ret);
 202                return (ret < 0) ? ret : -EIO;
 203        }
 204
 205        high = max3(g15->transfer_buf[1], g15->transfer_buf[2],
 206                    g15->transfer_buf[3]);
 207
 208        if (high) {
 209                g15->leds[i].red =
 210                        DIV_ROUND_CLOSEST(g15->transfer_buf[1] * 255, high);
 211                g15->leds[i].green =
 212                        DIV_ROUND_CLOSEST(g15->transfer_buf[2] * 255, high);
 213                g15->leds[i].blue =
 214                        DIV_ROUND_CLOSEST(g15->transfer_buf[3] * 255, high);
 215                g15->leds[i].brightness = high;
 216        } else {
 217                g15->leds[i].red   = 255;
 218                g15->leds[i].green = 255;
 219                g15->leds[i].blue  = 255;
 220                g15->leds[i].brightness = 0;
 221        }
 222
 223        return 0;
 224}
 225
 226/* Must be called with g15->mutex locked */
 227static int lg_g510_kbd_led_write(struct lg_g15_data *g15,
 228                                 struct lg_g15_led *g15_led,
 229                                 enum led_brightness brightness)
 230{
 231        int ret;
 232
 233        g15->transfer_buf[0] = 5 + g15_led->led;
 234        g15->transfer_buf[1] =
 235                DIV_ROUND_CLOSEST(g15_led->red * brightness, 255);
 236        g15->transfer_buf[2] =
 237                DIV_ROUND_CLOSEST(g15_led->green * brightness, 255);
 238        g15->transfer_buf[3] =
 239                DIV_ROUND_CLOSEST(g15_led->blue * brightness, 255);
 240
 241        ret = hid_hw_raw_request(g15->hdev,
 242                                 LG_G510_FEATURE_BACKLIGHT_RGB + g15_led->led,
 243                                 g15->transfer_buf, 4,
 244                                 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
 245        if (ret == 4) {
 246                /* Success */
 247                g15_led->brightness = brightness;
 248                ret = 0;
 249        } else {
 250                hid_err(g15->hdev, "Error setting LED brightness: %d\n", ret);
 251                ret = (ret < 0) ? ret : -EIO;
 252        }
 253
 254        return ret;
 255}
 256
 257static int lg_g510_kbd_led_set(struct led_classdev *led_cdev,
 258                               enum led_brightness brightness)
 259{
 260        struct lg_g15_led *g15_led =
 261                container_of(led_cdev, struct lg_g15_led, cdev);
 262        struct lg_g15_data *g15 = dev_get_drvdata(led_cdev->dev->parent);
 263        int ret;
 264
 265        /* Ignore LED off on unregister / keyboard unplug */
 266        if (led_cdev->flags & LED_UNREGISTERING)
 267                return 0;
 268
 269        mutex_lock(&g15->mutex);
 270        ret = lg_g510_kbd_led_write(g15, g15_led, brightness);
 271        mutex_unlock(&g15->mutex);
 272
 273        return ret;
 274}
 275
 276static enum led_brightness lg_g510_kbd_led_get(struct led_classdev *led_cdev)
 277{
 278        struct lg_g15_led *g15_led =
 279                container_of(led_cdev, struct lg_g15_led, cdev);
 280
 281        return g15_led->brightness;
 282}
 283
 284static ssize_t color_store(struct device *dev, struct device_attribute *attr,
 285                           const char *buf, size_t count)
 286{
 287        struct led_classdev *led_cdev = dev_get_drvdata(dev);
 288        struct lg_g15_led *g15_led =
 289                container_of(led_cdev, struct lg_g15_led, cdev);
 290        struct lg_g15_data *g15 = dev_get_drvdata(led_cdev->dev->parent);
 291        unsigned long value;
 292        int ret;
 293
 294        if (count < 7 || (count == 8 && buf[7] != '\n') || count > 8)
 295                return -EINVAL;
 296
 297        if (buf[0] != '#')
 298                return -EINVAL;
 299
 300        ret = kstrtoul(buf + 1, 16, &value);
 301        if (ret)
 302                return ret;
 303
 304        mutex_lock(&g15->mutex);
 305        g15_led->red   = (value & 0xff0000) >> 16;
 306        g15_led->green = (value & 0x00ff00) >> 8;
 307        g15_led->blue  = (value & 0x0000ff);
 308        ret = lg_g510_kbd_led_write(g15, g15_led, g15_led->brightness);
 309        mutex_unlock(&g15->mutex);
 310
 311        return (ret < 0) ? ret : count;
 312}
 313
 314static ssize_t color_show(struct device *dev, struct device_attribute *attr,
 315                          char *buf)
 316{
 317        struct led_classdev *led_cdev = dev_get_drvdata(dev);
 318        struct lg_g15_led *g15_led =
 319                container_of(led_cdev, struct lg_g15_led, cdev);
 320        struct lg_g15_data *g15 = dev_get_drvdata(led_cdev->dev->parent);
 321        ssize_t ret;
 322
 323        mutex_lock(&g15->mutex);
 324        ret = sprintf(buf, "#%02x%02x%02x\n",
 325                      g15_led->red, g15_led->green, g15_led->blue);
 326        mutex_unlock(&g15->mutex);
 327
 328        return ret;
 329}
 330
 331static DEVICE_ATTR_RW(color);
 332
 333static struct attribute *lg_g510_kbd_led_attrs[] = {
 334        &dev_attr_color.attr,
 335        NULL,
 336};
 337
 338static const struct attribute_group lg_g510_kbd_led_group = {
 339        .attrs = lg_g510_kbd_led_attrs,
 340};
 341
 342static const struct attribute_group *lg_g510_kbd_led_groups[] = {
 343        &lg_g510_kbd_led_group,
 344        NULL,
 345};
 346
 347static void lg_g510_leds_sync_work(struct work_struct *work)
 348{
 349        struct lg_g15_data *g15 = container_of(work, struct lg_g15_data, work);
 350
 351        mutex_lock(&g15->mutex);
 352        lg_g510_kbd_led_write(g15, &g15->leds[LG_G15_KBD_BRIGHTNESS],
 353                              g15->leds[LG_G15_KBD_BRIGHTNESS].brightness);
 354        mutex_unlock(&g15->mutex);
 355}
 356
 357static int lg_g510_update_mkey_led_brightness(struct lg_g15_data *g15)
 358{
 359        int ret;
 360
 361        ret = hid_hw_raw_request(g15->hdev, LG_G510_FEATURE_M_KEYS_LEDS,
 362                                 g15->transfer_buf, 2,
 363                                 HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
 364        if (ret != 2) {
 365                hid_err(g15->hdev, "Error getting LED brightness: %d\n", ret);
 366                ret = (ret < 0) ? ret : -EIO;
 367        }
 368
 369        g15->leds[LG_G15_MACRO_PRESET1].brightness =
 370                !!(g15->transfer_buf[1] & 0x80);
 371        g15->leds[LG_G15_MACRO_PRESET2].brightness =
 372                !!(g15->transfer_buf[1] & 0x40);
 373        g15->leds[LG_G15_MACRO_PRESET3].brightness =
 374                !!(g15->transfer_buf[1] & 0x20);
 375        g15->leds[LG_G15_MACRO_RECORD].brightness =
 376                !!(g15->transfer_buf[1] & 0x10);
 377
 378        return 0;
 379}
 380
 381static enum led_brightness lg_g510_mkey_led_get(struct led_classdev *led_cdev)
 382{
 383        struct lg_g15_led *g15_led =
 384                container_of(led_cdev, struct lg_g15_led, cdev);
 385        struct lg_g15_data *g15 = dev_get_drvdata(led_cdev->dev->parent);
 386        enum led_brightness brightness;
 387
 388        mutex_lock(&g15->mutex);
 389        lg_g510_update_mkey_led_brightness(g15);
 390        brightness = g15->leds[g15_led->led].brightness;
 391        mutex_unlock(&g15->mutex);
 392
 393        return brightness;
 394}
 395
 396static int lg_g510_mkey_led_set(struct led_classdev *led_cdev,
 397                                enum led_brightness brightness)
 398{
 399        struct lg_g15_led *g15_led =
 400                container_of(led_cdev, struct lg_g15_led, cdev);
 401        struct lg_g15_data *g15 = dev_get_drvdata(led_cdev->dev->parent);
 402        u8 val, mask = 0;
 403        int i, ret;
 404
 405        /* Ignore LED off on unregister / keyboard unplug */
 406        if (led_cdev->flags & LED_UNREGISTERING)
 407                return 0;
 408
 409        mutex_lock(&g15->mutex);
 410
 411        for (i = LG_G15_MACRO_PRESET1; i < LG_G15_LED_MAX; i++) {
 412                if (i == g15_led->led)
 413                        val = brightness;
 414                else
 415                        val = g15->leds[i].brightness;
 416
 417                if (val)
 418                        mask |= 0x80 >> (i - LG_G15_MACRO_PRESET1);
 419        }
 420
 421        g15->transfer_buf[0] = LG_G510_FEATURE_M_KEYS_LEDS;
 422        g15->transfer_buf[1] = mask;
 423
 424        ret = hid_hw_raw_request(g15->hdev, LG_G510_FEATURE_M_KEYS_LEDS,
 425                                 g15->transfer_buf, 2,
 426                                 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
 427        if (ret == 2) {
 428                /* Success */
 429                g15_led->brightness = brightness;
 430                ret = 0;
 431        } else {
 432                hid_err(g15->hdev, "Error setting LED brightness: %d\n", ret);
 433                ret = (ret < 0) ? ret : -EIO;
 434        }
 435
 436        mutex_unlock(&g15->mutex);
 437
 438        return ret;
 439}
 440
 441/******** Generic LED functions ********/
 442static int lg_g15_get_initial_led_brightness(struct lg_g15_data *g15)
 443{
 444        int ret;
 445
 446        switch (g15->model) {
 447        case LG_G15:
 448        case LG_G15_V2:
 449                return lg_g15_update_led_brightness(g15);
 450        case LG_G510:
 451        case LG_G510_USB_AUDIO:
 452                ret = lg_g510_get_initial_led_brightness(g15, 0);
 453                if (ret)
 454                        return ret;
 455
 456                ret = lg_g510_get_initial_led_brightness(g15, 1);
 457                if (ret)
 458                        return ret;
 459
 460                return lg_g510_update_mkey_led_brightness(g15);
 461        case LG_Z10:
 462                /*
 463                 * Getting the LCD backlight brightness is not supported.
 464                 * Reading Feature(2) fails with -EPIPE and this crashes
 465                 * the LCD and touch keys part of the speakers.
 466                 */
 467                return 0;
 468        }
 469        return -EINVAL; /* Never reached */
 470}
 471
 472/******** Input functions ********/
 473
 474/* On the G15 Mark I Logitech has been quite creative with which bit is what */
 475static void lg_g15_handle_lcd_menu_keys(struct lg_g15_data *g15, u8 *data)
 476{
 477        int i, val;
 478
 479        /* Most left (round/display) button below the LCD */
 480        input_report_key(g15->input, KEY_KBD_LCD_MENU1, data[8] & 0x80);
 481        /* 4 other buttons below the LCD */
 482        for (i = 0; i < 4; i++) {
 483                val = data[i + 2] & 0x80;
 484                input_report_key(g15->input, KEY_KBD_LCD_MENU2 + i, val);
 485        }
 486}
 487
 488static int lg_g15_event(struct lg_g15_data *g15, u8 *data)
 489{
 490        int i, val;
 491
 492        /* G1 - G6 */
 493        for (i = 0; i < 6; i++) {
 494                val = data[i + 1] & (1 << i);
 495                input_report_key(g15->input, KEY_MACRO1 + i, val);
 496        }
 497        /* G7 - G12 */
 498        for (i = 0; i < 6; i++) {
 499                val = data[i + 2] & (1 << i);
 500                input_report_key(g15->input, KEY_MACRO7 + i, val);
 501        }
 502        /* G13 - G17 */
 503        for (i = 0; i < 5; i++) {
 504                val = data[i + 1] & (4 << i);
 505                input_report_key(g15->input, KEY_MACRO13 + i, val);
 506        }
 507        /* G18 */
 508        input_report_key(g15->input, KEY_MACRO18, data[8] & 0x40);
 509
 510        /* M1 - M3 */
 511        for (i = 0; i < 3; i++) {
 512                val = data[i + 6] & (1 << i);
 513                input_report_key(g15->input, KEY_MACRO_PRESET1 + i, val);
 514        }
 515        /* MR */
 516        input_report_key(g15->input, KEY_MACRO_RECORD_START, data[7] & 0x40);
 517
 518        lg_g15_handle_lcd_menu_keys(g15, data);
 519
 520        /* Backlight cycle button pressed? */
 521        if (data[1] & 0x80)
 522                schedule_work(&g15->work);
 523
 524        input_sync(g15->input);
 525        return 0;
 526}
 527
 528static int lg_g15_v2_event(struct lg_g15_data *g15, u8 *data)
 529{
 530        int i, val;
 531
 532        /* G1 - G6 */
 533        for (i = 0; i < 6; i++) {
 534                val = data[1] & (1 << i);
 535                input_report_key(g15->input, KEY_MACRO1 + i, val);
 536        }
 537
 538        /* M1 - M3 + MR */
 539        input_report_key(g15->input, KEY_MACRO_PRESET1, data[1] & 0x40);
 540        input_report_key(g15->input, KEY_MACRO_PRESET2, data[1] & 0x80);
 541        input_report_key(g15->input, KEY_MACRO_PRESET3, data[2] & 0x20);
 542        input_report_key(g15->input, KEY_MACRO_RECORD_START, data[2] & 0x40);
 543
 544        /* Round button to the left of the LCD */
 545        input_report_key(g15->input, KEY_KBD_LCD_MENU1, data[2] & 0x80);
 546        /* 4 buttons below the LCD */
 547        for (i = 0; i < 4; i++) {
 548                val = data[2] & (2 << i);
 549                input_report_key(g15->input, KEY_KBD_LCD_MENU2 + i, val);
 550        }
 551
 552        /* Backlight cycle button pressed? */
 553        if (data[2] & 0x01)
 554                schedule_work(&g15->work);
 555
 556        input_sync(g15->input);
 557        return 0;
 558}
 559
 560static int lg_g510_event(struct lg_g15_data *g15, u8 *data)
 561{
 562        bool game_mode_enabled;
 563        int i, val;
 564
 565        /* G1 - G18 */
 566        for (i = 0; i < 18; i++) {
 567                val = data[i / 8 + 1] & (1 << (i % 8));
 568                input_report_key(g15->input, KEY_MACRO1 + i, val);
 569        }
 570
 571        /* Game mode on/off slider */
 572        game_mode_enabled = data[3] & 0x04;
 573        if (game_mode_enabled != g15->game_mode_enabled) {
 574                if (game_mode_enabled)
 575                        hid_info(g15->hdev, "Game Mode enabled, Windows (super) key is disabled\n");
 576                else
 577                        hid_info(g15->hdev, "Game Mode disabled\n");
 578                g15->game_mode_enabled = game_mode_enabled;
 579        }
 580
 581        /* M1 - M3 */
 582        for (i = 0; i < 3; i++) {
 583                val = data[3] & (0x10 << i);
 584                input_report_key(g15->input, KEY_MACRO_PRESET1 + i, val);
 585        }
 586        /* MR */
 587        input_report_key(g15->input, KEY_MACRO_RECORD_START, data[3] & 0x80);
 588
 589        /* LCD menu keys */
 590        for (i = 0; i < 5; i++) {
 591                val = data[4] & (1 << i);
 592                input_report_key(g15->input, KEY_KBD_LCD_MENU1 + i, val);
 593        }
 594
 595        /* Headphone Mute */
 596        input_report_key(g15->input, KEY_MUTE, data[4] & 0x20);
 597        /* Microphone Mute */
 598        input_report_key(g15->input, KEY_F20, data[4] & 0x40);
 599
 600        input_sync(g15->input);
 601        return 0;
 602}
 603
 604static int lg_g510_leds_event(struct lg_g15_data *g15, u8 *data)
 605{
 606        bool backlight_disabled;
 607
 608        /*
 609         * The G510 ignores backlight updates when the backlight is turned off
 610         * through the light toggle button on the keyboard, to work around this
 611         * we queue a workitem to sync values when the backlight is turned on.
 612         */
 613        backlight_disabled = data[1] & 0x04;
 614        if (!backlight_disabled)
 615                schedule_work(&g15->work);
 616
 617        return 0;
 618}
 619
 620static int lg_g15_raw_event(struct hid_device *hdev, struct hid_report *report,
 621                            u8 *data, int size)
 622{
 623        struct lg_g15_data *g15 = hid_get_drvdata(hdev);
 624
 625        if (!g15)
 626                return 0;
 627
 628        switch (g15->model) {
 629        case LG_G15:
 630                if (data[0] == 0x02 && size == 9)
 631                        return lg_g15_event(g15, data);
 632                break;
 633        case LG_G15_V2:
 634                if (data[0] == 0x02 && size == 5)
 635                        return lg_g15_v2_event(g15, data);
 636                break;
 637        case LG_Z10:
 638                if (data[0] == 0x02 && size == 9) {
 639                        lg_g15_handle_lcd_menu_keys(g15, data);
 640                        input_sync(g15->input);
 641                }
 642                break;
 643        case LG_G510:
 644        case LG_G510_USB_AUDIO:
 645                if (data[0] == 0x03 && size == 5)
 646                        return lg_g510_event(g15, data);
 647                if (data[0] == 0x04 && size == 2)
 648                        return lg_g510_leds_event(g15, data);
 649                break;
 650        }
 651
 652        return 0;
 653}
 654
 655static int lg_g15_input_open(struct input_dev *dev)
 656{
 657        struct hid_device *hdev = input_get_drvdata(dev);
 658
 659        return hid_hw_open(hdev);
 660}
 661
 662static void lg_g15_input_close(struct input_dev *dev)
 663{
 664        struct hid_device *hdev = input_get_drvdata(dev);
 665
 666        hid_hw_close(hdev);
 667}
 668
 669static int lg_g15_register_led(struct lg_g15_data *g15, int i, const char *name)
 670{
 671        g15->leds[i].led = i;
 672        g15->leds[i].cdev.name = name;
 673
 674        switch (g15->model) {
 675        case LG_G15:
 676        case LG_G15_V2:
 677                g15->leds[i].cdev.brightness_get = lg_g15_led_get;
 678                fallthrough;
 679        case LG_Z10:
 680                g15->leds[i].cdev.brightness_set_blocking = lg_g15_led_set;
 681                if (i < LG_G15_BRIGHTNESS_MAX) {
 682                        g15->leds[i].cdev.flags = LED_BRIGHT_HW_CHANGED;
 683                        g15->leds[i].cdev.max_brightness = 2;
 684                } else {
 685                        g15->leds[i].cdev.max_brightness = 1;
 686                }
 687                break;
 688        case LG_G510:
 689        case LG_G510_USB_AUDIO:
 690                switch (i) {
 691                case LG_G15_LCD_BRIGHTNESS:
 692                        /*
 693                         * The G510 does not have a separate LCD brightness,
 694                         * but it does have a separate power-on (reset) value.
 695                         */
 696                        g15->leds[i].cdev.name = "g15::power_on_backlight_val";
 697                        fallthrough;
 698                case LG_G15_KBD_BRIGHTNESS:
 699                        g15->leds[i].cdev.brightness_set_blocking =
 700                                lg_g510_kbd_led_set;
 701                        g15->leds[i].cdev.brightness_get =
 702                                lg_g510_kbd_led_get;
 703                        g15->leds[i].cdev.max_brightness = 255;
 704                        g15->leds[i].cdev.groups = lg_g510_kbd_led_groups;
 705                        break;
 706                default:
 707                        g15->leds[i].cdev.brightness_set_blocking =
 708                                lg_g510_mkey_led_set;
 709                        g15->leds[i].cdev.brightness_get =
 710                                lg_g510_mkey_led_get;
 711                        g15->leds[i].cdev.max_brightness = 1;
 712                }
 713                break;
 714        }
 715
 716        return devm_led_classdev_register(&g15->hdev->dev, &g15->leds[i].cdev);
 717}
 718
 719/* Common input device init code shared between keyboards and Z-10 speaker handling */
 720static void lg_g15_init_input_dev(struct hid_device *hdev, struct input_dev *input,
 721                                  const char *name)
 722{
 723        int i;
 724
 725        input->name = name;
 726        input->phys = hdev->phys;
 727        input->uniq = hdev->uniq;
 728        input->id.bustype = hdev->bus;
 729        input->id.vendor  = hdev->vendor;
 730        input->id.product = hdev->product;
 731        input->id.version = hdev->version;
 732        input->dev.parent = &hdev->dev;
 733        input->open = lg_g15_input_open;
 734        input->close = lg_g15_input_close;
 735
 736        /* Keys below the LCD, intended for controlling a menu on the LCD */
 737        for (i = 0; i < 5; i++)
 738                input_set_capability(input, EV_KEY, KEY_KBD_LCD_MENU1 + i);
 739}
 740
 741static int lg_g15_probe(struct hid_device *hdev, const struct hid_device_id *id)
 742{
 743        static const char * const led_names[] = {
 744                "g15::kbd_backlight",
 745                "g15::lcd_backlight",
 746                "g15::macro_preset1",
 747                "g15::macro_preset2",
 748                "g15::macro_preset3",
 749                "g15::macro_record",
 750        };
 751        u8 gkeys_settings_output_report = 0;
 752        u8 gkeys_settings_feature_report = 0;
 753        struct hid_report_enum *rep_enum;
 754        unsigned int connect_mask = 0;
 755        bool has_ff000000 = false;
 756        struct lg_g15_data *g15;
 757        struct input_dev *input;
 758        struct hid_report *rep;
 759        int ret, i, gkeys = 0;
 760
 761        hdev->quirks |= HID_QUIRK_INPUT_PER_APP;
 762
 763        ret = hid_parse(hdev);
 764        if (ret)
 765                return ret;
 766
 767        /*
 768         * Some models have multiple interfaces, we want the interface with
 769         * with the f000.0000 application input report.
 770         */
 771        rep_enum = &hdev->report_enum[HID_INPUT_REPORT];
 772        list_for_each_entry(rep, &rep_enum->report_list, list) {
 773                if (rep->application == 0xff000000)
 774                        has_ff000000 = true;
 775        }
 776        if (!has_ff000000)
 777                return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 778
 779        g15 = devm_kzalloc(&hdev->dev, sizeof(*g15), GFP_KERNEL);
 780        if (!g15)
 781                return -ENOMEM;
 782
 783        mutex_init(&g15->mutex);
 784
 785        input = devm_input_allocate_device(&hdev->dev);
 786        if (!input)
 787                return -ENOMEM;
 788
 789        g15->hdev = hdev;
 790        g15->model = id->driver_data;
 791        g15->input = input;
 792        input_set_drvdata(input, hdev);
 793        hid_set_drvdata(hdev, (void *)g15);
 794
 795        switch (g15->model) {
 796        case LG_G15:
 797                INIT_WORK(&g15->work, lg_g15_leds_changed_work);
 798                /*
 799                 * The G15 and G15 v2 use a separate usb-device (on a builtin
 800                 * hub) which emulates a keyboard for the F1 - F12 emulation
 801                 * on the G-keys, which we disable, rendering the emulated kbd
 802                 * non-functional, so we do not let hid-input connect.
 803                 */
 804                connect_mask = HID_CONNECT_HIDRAW;
 805                gkeys_settings_output_report = 0x02;
 806                gkeys = 18;
 807                break;
 808        case LG_G15_V2:
 809                INIT_WORK(&g15->work, lg_g15_leds_changed_work);
 810                connect_mask = HID_CONNECT_HIDRAW;
 811                gkeys_settings_output_report = 0x02;
 812                gkeys = 6;
 813                break;
 814        case LG_G510:
 815        case LG_G510_USB_AUDIO:
 816                INIT_WORK(&g15->work, lg_g510_leds_sync_work);
 817                connect_mask = HID_CONNECT_HIDINPUT | HID_CONNECT_HIDRAW;
 818                gkeys_settings_feature_report = 0x01;
 819                gkeys = 18;
 820                break;
 821        case LG_Z10:
 822                connect_mask = HID_CONNECT_HIDRAW;
 823                break;
 824        }
 825
 826        ret = hid_hw_start(hdev, connect_mask);
 827        if (ret)
 828                return ret;
 829
 830        /* Tell the keyboard to stop sending F1-F12 + 1-6 for G1 - G18 */
 831        if (gkeys_settings_output_report) {
 832                g15->transfer_buf[0] = gkeys_settings_output_report;
 833                memset(g15->transfer_buf + 1, 0, gkeys);
 834                /*
 835                 * The kbd ignores our output report if we do not queue
 836                 * an URB on the USB input endpoint first...
 837                 */
 838                ret = hid_hw_open(hdev);
 839                if (ret)
 840                        goto error_hw_stop;
 841                ret = hid_hw_output_report(hdev, g15->transfer_buf, gkeys + 1);
 842                hid_hw_close(hdev);
 843        }
 844
 845        if (gkeys_settings_feature_report) {
 846                g15->transfer_buf[0] = gkeys_settings_feature_report;
 847                memset(g15->transfer_buf + 1, 0, gkeys);
 848                ret = hid_hw_raw_request(g15->hdev,
 849                                gkeys_settings_feature_report,
 850                                g15->transfer_buf, gkeys + 1,
 851                                HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
 852        }
 853
 854        if (ret < 0) {
 855                hid_err(hdev, "Error %d disabling keyboard emulation for the G-keys, falling back to generic hid-input driver\n",
 856                        ret);
 857                hid_set_drvdata(hdev, NULL);
 858                return 0;
 859        }
 860
 861        /* Get initial brightness levels */
 862        ret = lg_g15_get_initial_led_brightness(g15);
 863        if (ret)
 864                goto error_hw_stop;
 865
 866        if (g15->model == LG_Z10) {
 867                lg_g15_init_input_dev(hdev, g15->input, "Logitech Z-10 LCD Menu Keys");
 868                ret = input_register_device(g15->input);
 869                if (ret)
 870                        goto error_hw_stop;
 871
 872                ret = lg_g15_register_led(g15, 1, "z-10::lcd_backlight");
 873                if (ret)
 874                        goto error_hw_stop;
 875
 876                return 0; /* All done */
 877        }
 878
 879        /* Setup and register input device */
 880        lg_g15_init_input_dev(hdev, input, "Logitech Gaming Keyboard Gaming Keys");
 881
 882        /* G-keys */
 883        for (i = 0; i < gkeys; i++)
 884                input_set_capability(input, EV_KEY, KEY_MACRO1 + i);
 885
 886        /* M1 - M3 and MR keys */
 887        for (i = 0; i < 3; i++)
 888                input_set_capability(input, EV_KEY, KEY_MACRO_PRESET1 + i);
 889        input_set_capability(input, EV_KEY, KEY_MACRO_RECORD_START);
 890
 891        /*
 892         * On the G510 only report headphone and mic mute keys when *not* using
 893         * the builtin USB audio device. When the builtin audio is used these
 894         * keys directly toggle mute (and the LEDs) on/off.
 895         */
 896        if (g15->model == LG_G510) {
 897                input_set_capability(input, EV_KEY, KEY_MUTE);
 898                /* Userspace expects F20 for micmute */
 899                input_set_capability(input, EV_KEY, KEY_F20);
 900        }
 901
 902        ret = input_register_device(input);
 903        if (ret)
 904                goto error_hw_stop;
 905
 906        /* Register LED devices */
 907        for (i = 0; i < LG_G15_LED_MAX; i++) {
 908                ret = lg_g15_register_led(g15, i, led_names[i]);
 909                if (ret)
 910                        goto error_hw_stop;
 911        }
 912
 913        return 0;
 914
 915error_hw_stop:
 916        hid_hw_stop(hdev);
 917        return ret;
 918}
 919
 920static const struct hid_device_id lg_g15_devices[] = {
 921        /* The G11 is a G15 without the LCD, treat it as a G15 */
 922        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
 923                USB_DEVICE_ID_LOGITECH_G11),
 924                .driver_data = LG_G15 },
 925        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
 926                         USB_DEVICE_ID_LOGITECH_G15_LCD),
 927                .driver_data = LG_G15 },
 928        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
 929                         USB_DEVICE_ID_LOGITECH_G15_V2_LCD),
 930                .driver_data = LG_G15_V2 },
 931        /* G510 without a headset plugged in */
 932        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
 933                         USB_DEVICE_ID_LOGITECH_G510),
 934                .driver_data = LG_G510 },
 935        /* G510 with headset plugged in / with extra USB audio interface */
 936        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
 937                         USB_DEVICE_ID_LOGITECH_G510_USB_AUDIO),
 938                .driver_data = LG_G510_USB_AUDIO },
 939        /* Z-10 speakers */
 940        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
 941                         USB_DEVICE_ID_LOGITECH_Z_10_SPK),
 942                .driver_data = LG_Z10 },
 943        { }
 944};
 945MODULE_DEVICE_TABLE(hid, lg_g15_devices);
 946
 947static struct hid_driver lg_g15_driver = {
 948        .name                   = "lg-g15",
 949        .id_table               = lg_g15_devices,
 950        .raw_event              = lg_g15_raw_event,
 951        .probe                  = lg_g15_probe,
 952};
 953module_hid_driver(lg_g15_driver);
 954
 955MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
 956MODULE_LICENSE("GPL");
 957