cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

hid-lg-g15.c (24875B)


      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");