Skip to content

Commit b2572ee

Browse files
committed
Lenovo: Add Legion 7 Gen 10 (C197) support
1 parent d591cd6 commit b2572ee

5 files changed

Lines changed: 198 additions & 47 deletions

File tree

Controllers/LenovoControllers/LenovoDevices.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#define LEGION_S7GEN8 0xC987
3838
#define LEGION_7GEN9 0xC997
3939
#define LEGION_7GEN9_H 0xC998
40+
#define LEGION_7GEN10 0xC197
4041

4142
enum LENOVO_KEYBOARD
4243
{
@@ -1878,6 +1879,28 @@ const lenovo_led legion_7gen7_vents_leds[]
18781879
{0xF0, "Vent group 8"},//7
18791880
};
18801881

1882+
const lenovo_led legion_7gen10_vents_leds[]
1883+
{
1884+
{0xE9, "Vent group 1"},//0
1885+
{0xEA, "Vent group 2"},//1
1886+
{0xEB, "Vent group 3"},//2
1887+
{0xEC, "Vent group 4"},//3
1888+
{0xED, "Vent group 5"},//4
1889+
{0xEE, "Vent group 6"},//5
1890+
{0xEF, "Vent group 7"},//6
1891+
{0xF0, "Vent group 8"},//7
1892+
{0xF1, "Vent group 9"},//8
1893+
{0xF2, "Vent group 10"},//9
1894+
{0xF3, "Vent group 11"},//10
1895+
{0xF4, "Vent group 12"},//11
1896+
{0xF5, "Vent group 13"},//12
1897+
{0xF6, "Vent group 14"},//13
1898+
{0xF7, "Vent group 15"},//14
1899+
{0xF8, "Vent group 16"},//15
1900+
{0xF9, "Vent group 17"},//16
1901+
{0xFA, "Vent group 18"},//17
1902+
};
1903+
18811904
const lenovo_led legion_7gen7_logo_leds[]
18821905
{
18831906
{0xDD, "Logo"},//0
@@ -1931,6 +1954,19 @@ static lenovo_zone lenovo_legion_7gen7_vents
19311954
7,
19321955
};
19331956

1957+
static lenovo_zone lenovo_legion_7gen10_vents
1958+
{
1959+
"Vents",
1960+
ZONE_TYPE_LINEAR,
1961+
3,
1962+
1,
1963+
18,
1964+
NULL,
1965+
legion_7gen10_vents_leds,
1966+
0,
1967+
17,
1968+
};
1969+
19341970
/*------*\
19351971
|neon |
19361972
\*------*/

Controllers/LenovoControllers/LenovoUSBControllerDetect.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,4 @@ REGISTER_HID_DETECTOR_PU("Lenovo Legion 7 Gen 8", DetectLenovoLegionUSBControl
6666
REGISTER_HID_DETECTOR_PU("Lenovo Legion 7S Gen 8", DetectLenovoLegionUSBControllersGen7And8, ITE_VID, LEGION_S7GEN8, LENOVO_PAGE, LENOVO_USAGE);
6767
REGISTER_HID_DETECTOR_PU("Lenovo Legion 7 Gen 9", DetectLenovoLegionUSBControllersGen7And8, ITE_VID, LEGION_7GEN9, LENOVO_PAGE, LENOVO_USAGE);
6868
REGISTER_HID_DETECTOR_PU("Lenovo Legion 7 Gen 9", DetectLenovoLegionUSBControllersGen7And8, ITE_VID, LEGION_7GEN9_H, LENOVO_PAGE, LENOVO_USAGE);
69+
REGISTER_HID_DETECTOR_PU("Lenovo Legion 7 Gen 10", DetectLenovoLegionUSBControllersGen7And8, ITE_VID, LEGION_7GEN10, LENOVO_PAGE, LENOVO_USAGE);

Controllers/LenovoControllers/LenovoUSBController_Gen7_8/LenovoUSBController_Gen7_8.cpp

Lines changed: 111 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,23 @@
99

1010
#include <iomanip>
1111
#include <sstream>
12+
#include "LenovoDevices.h"
1213
#include "LenovoUSBController_Gen7_8.h"
1314
#include "StringUtils.h"
1415

1516
using namespace std;
1617

18+
static void SetGen10PayloadLength(uint16_t pid, uint8_t* buffer, uint16_t payload_length)
19+
{
20+
if(pid != LEGION_7GEN10)
21+
{
22+
return;
23+
}
24+
25+
buffer[2] = payload_length & 0xFF;
26+
buffer[3] = (payload_length >> 8) & 0xFF;
27+
}
28+
1729
LenovoGen7And8USBController::LenovoGen7And8USBController(hid_device* dev_handle, const char* path, uint16_t in_pid, std::string dev_name)
1830
{
1931
dev = dev_handle;
@@ -44,54 +56,74 @@ string LenovoGen7And8USBController::getLocation()
4456

4557
void LenovoGen7And8USBController::setLedsByGroup(uint8_t profile_id, vector<led_group> led_groups)
4658
{
47-
uint8_t buffer[PACKET_SIZE];
48-
memset(buffer, 0x00, PACKET_SIZE);
49-
50-
size_t i = 0;
51-
buffer[i++] = REPORT_ID;
52-
buffer[i++] = SAVE_PROFILE;
53-
buffer[i++] = 0xC0;
54-
buffer[i++] = 0x03;
55-
buffer[i++] = profile_id;
56-
buffer[i++] = 0x01;
57-
buffer[i++] = 0x01;
59+
if(led_groups.empty())
60+
{
61+
return;
62+
}
5863

59-
for(size_t group = 0; group < led_groups.size() && i < PACKET_SIZE - 21; group++)
64+
/*---------------------------------------------------------*\
65+
| Some devices require many groups for per-key updates. |
66+
| Send as many groups as fit in one report, then continue |
67+
| in additional reports. |
68+
\*---------------------------------------------------------*/
69+
size_t group = 0;
70+
while(group < led_groups.size())
6071
{
61-
buffer[i++] = (uint8_t)group + 1; //Group index
62-
buffer[i++] = 0x06;
63-
buffer[i++] = 0x01;
64-
buffer[i++] = led_groups[group].mode;
65-
buffer[i++] = 0x02;
66-
buffer[i++] = led_groups[group].speed;
72+
uint8_t buffer[PACKET_SIZE];
73+
memset(buffer, 0x00, PACKET_SIZE);
74+
75+
size_t i = 0;
76+
buffer[i++] = REPORT_ID;
77+
buffer[i++] = SAVE_PROFILE;
78+
buffer[i++] = 0xC0;
6779
buffer[i++] = 0x03;
68-
buffer[i++] = led_groups[group].spin;
69-
buffer[i++] = 0x04;
70-
buffer[i++] = led_groups[group].direction;
71-
buffer[i++] = 0x05;
72-
buffer[i++] = led_groups[group].color_mode;
73-
buffer[i++] = 0x06;
74-
buffer[i++] = 0x00;
80+
buffer[i++] = profile_id;
81+
buffer[i++] = 0x01;
82+
buffer[i++] = 0x01;
7583

76-
buffer[i++] = (uint8_t)led_groups[group].colors.size();
77-
for(RGBColor c : led_groups[group].colors)
84+
for(; group < led_groups.size() && i < PACKET_SIZE - 21; group++)
7885
{
79-
buffer[i++] = RGBGetRValue(c);
80-
buffer[i++] = RGBGetGValue(c);
81-
buffer[i++] = RGBGetBValue(c);
86+
buffer[i++] = (uint8_t)group + 1; //Group index
87+
buffer[i++] = 0x06;
88+
buffer[i++] = 0x01;
89+
buffer[i++] = led_groups[group].mode;
90+
buffer[i++] = 0x02;
91+
buffer[i++] = led_groups[group].speed;
92+
buffer[i++] = 0x03;
93+
buffer[i++] = led_groups[group].spin;
94+
buffer[i++] = 0x04;
95+
buffer[i++] = led_groups[group].direction;
96+
buffer[i++] = 0x05;
97+
buffer[i++] = led_groups[group].color_mode;
98+
buffer[i++] = 0x06;
99+
buffer[i++] = 0x00;
100+
101+
buffer[i++] = (uint8_t)led_groups[group].colors.size();
102+
for(RGBColor c : led_groups[group].colors)
103+
{
104+
buffer[i++] = RGBGetRValue(c);
105+
buffer[i++] = RGBGetGValue(c);
106+
buffer[i++] = RGBGetBValue(c);
107+
}
108+
109+
vector<uint16_t> leds = led_groups[group].leds;
110+
size_t led_count = min(leds.size(), (PACKET_SIZE - i)/2);
111+
buffer[i++] = (uint8_t)led_count;
112+
uint8_t* byte_ptr = reinterpret_cast<uint8_t*>(leds.data());
113+
std::copy(byte_ptr, byte_ptr + led_count * sizeof(uint16_t), buffer + i);
114+
i+= led_count * sizeof(uint16_t);
82115
}
83116

84-
vector<uint16_t> leds = led_groups[group].leds;
85-
size_t led_count = min(leds.size(), (PACKET_SIZE - i)/2);
86-
buffer[i++] = (uint8_t)led_count;
87-
uint8_t* byte_ptr = reinterpret_cast<uint8_t*>(leds.data());
88-
std::copy(byte_ptr, byte_ptr + led_count * sizeof(uint16_t), buffer + i);
89-
i+= led_count * sizeof(uint16_t);
117+
if(pid == LEGION_7GEN10)
118+
{
119+
SetGen10PayloadLength(pid, buffer, static_cast<uint16_t>(i - 4));
120+
}
121+
else
122+
{
123+
buffer[2] = (uint8_t)i;
124+
}
125+
sendFeatureReport(buffer, PACKET_SIZE);
90126
}
91-
92-
buffer[2] = (uint8_t)i;
93-
94-
sendFeatureReport(buffer, PACKET_SIZE);
95127
}
96128

97129
void LenovoGen7And8USBController::setLedsDirectOn(uint8_t profile_id)
@@ -107,6 +139,7 @@ void LenovoGen7And8USBController::setLedsDirectOn(uint8_t profile_id)
107139
buffer[i++] = 0x01;
108140
buffer[i++] = profile_id;
109141

142+
SetGen10PayloadLength(pid, buffer, 2);
110143
sendFeatureReport(buffer, PACKET_SIZE);
111144
}
112145

@@ -123,11 +156,43 @@ void LenovoGen7And8USBController::setLedsDirectOff(uint8_t profile_id)
123156
buffer[i++] = 0x02;
124157
buffer[i++] = profile_id;
125158

159+
SetGen10PayloadLength(pid, buffer, 2);
126160
sendFeatureReport(buffer, PACKET_SIZE);
127161
}
128162

129163
void LenovoGen7And8USBController::setLedsDirect(std::vector<led> &leds, std::vector<RGBColor> &colors)
130164
{
165+
if(pid == LEGION_7GEN10)
166+
{
167+
/*---------------------------------------------------------*\
168+
| Gen10 uses 0x07/A1 direct updates, with payload length |
169+
| stored in bytes 2-3. |
170+
\*---------------------------------------------------------*/
171+
uint8_t buffer[PACKET_SIZE];
172+
memset(buffer, 0x00, PACKET_SIZE);
173+
174+
size_t i = 0;
175+
buffer[i++] = REPORT_ID;
176+
buffer[i++] = DIRECT_MODE;
177+
buffer[i++] = 0x00;
178+
buffer[i++] = 0x00;
179+
180+
size_t count = 0;
181+
for(size_t index = 0; index < leds.size() && index < colors.size() && i + 5 <= PACKET_SIZE; index++)
182+
{
183+
buffer[i++] = leds[index].value & 0xFF;
184+
buffer[i++] = leds[index].value >> 8 & 0xFF;
185+
buffer[i++] = RGBGetRValue(colors[index]);
186+
buffer[i++] = RGBGetGValue(colors[index]);
187+
buffer[i++] = RGBGetBValue(colors[index]);
188+
count++;
189+
}
190+
191+
SetGen10PayloadLength(pid, buffer, static_cast<uint16_t>(count * 5));
192+
sendFeatureReport(buffer, PACKET_SIZE);
193+
return;
194+
}
195+
131196
uint8_t buffer[PACKET_SIZE];
132197
memset(buffer, 0x00, PACKET_SIZE);
133198

@@ -153,13 +218,15 @@ void LenovoGen7And8USBController::setLedsAllOff(uint8_t profile_id)
153218
{
154219
uint8_t buffer[PACKET_SIZE] = {REPORT_ID, SAVE_PROFILE, 0xC0, 0x03, profile_id, 0x01, 0x01};
155220

221+
SetGen10PayloadLength(pid, buffer, 3);
156222
sendFeatureReport(buffer, PACKET_SIZE);
157223
}
158224

159225
uint8_t LenovoGen7And8USBController::getCurrentProfileId()
160226
{
161227
uint8_t buffer[PACKET_SIZE] = {REPORT_ID, GET_ACTIVE_PROFILE, 0xC0, 0x03};
162228

229+
SetGen10PayloadLength(pid, buffer, 1);
163230
vector<uint8_t> response = getFeatureReport(buffer, PACKET_SIZE);
164231

165232
return response.size()>4?response[4]:0x01;
@@ -169,6 +236,7 @@ uint8_t LenovoGen7And8USBController::getCurrentBrightness()
169236
{
170237
uint8_t buffer[PACKET_SIZE] = {REPORT_ID, GET_BRIGHTNESS, 0xC0, 0x03};
171238

239+
SetGen10PayloadLength(pid, buffer, 1);
172240
vector<uint8_t> response = getFeatureReport(buffer, PACKET_SIZE);
173241

174242
return response.size()>4?response[4]:0x00;
@@ -179,20 +247,23 @@ void LenovoGen7And8USBController::setBrightness(uint8_t brightness)
179247
{
180248
uint8_t buffer[PACKET_SIZE] = {REPORT_ID, SET_BRIGHTNESS, 0xC0, 0x03, brightness};
181249

250+
SetGen10PayloadLength(pid, buffer, 1);
182251
sendFeatureReport(buffer, PACKET_SIZE);
183252
}
184253

185254
void LenovoGen7And8USBController::switchProfileTo(uint8_t profile_id)
186255
{
187256
uint8_t buffer[PACKET_SIZE] = {REPORT_ID, SWITCH_PROFILE, 0xC0, 0x03, profile_id};
188257

258+
SetGen10PayloadLength(pid, buffer, 1);
189259
sendFeatureReport(buffer, PACKET_SIZE);
190260
}
191261

192262
std::vector<led_group> LenovoGen7And8USBController::getProfileSettings(uint8_t profile_id)
193263
{
194264
uint8_t buffer[PACKET_SIZE] = {REPORT_ID, GET_PROFILE, 0xC0, 0x03, profile_id};
195265

266+
SetGen10PayloadLength(pid, buffer, PACKET_SIZE - 4);
196267
vector<uint8_t> response = getFeatureReport(buffer, PACKET_SIZE);
197268

198269
vector<led_group> groups;

0 commit comments

Comments
 (0)