Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'for-7.1/lenovo-v2' into for-linus

- new driver for Lenovo Legion Go / S devices (Derek J. Clark)

+5127 -2
+724
Documentation/ABI/testing/sysfs-driver-hid-lenovo-go
··· 1 + What: /sys/class/leds/go:rgb:joystick_rings/effect 2 + Date: April 2026 3 + Contact: linux-input@vger.kernel.org 4 + Description: This controls the display effect of the RGB interface. 5 + 6 + Values are monocolor, breathe, chroma, or rainbow. 7 + 8 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 9 + 10 + What: /sys/class/leds/go:rgb:joystick_rings/effect_index 11 + Date: April 2026 12 + Contact: linux-input@vger.kernel.org 13 + Description: This displays the available options for the effect attribute. 14 + 15 + Values are monocolor, breathe, chroma, or rainbow. 16 + 17 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 18 + 19 + What: /sys/class/leds/go:rgb:joystick_rings/enabled 20 + Date: April 2026 21 + Contact: linux-input@vger.kernel.org 22 + Description: This controls enabling or disabling the RGB interface. 23 + 24 + Values are true or false. 25 + 26 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 27 + 28 + What: /sys/class/leds/go:rgb:joystick_rings/enabled_index 29 + Date: April 2026 30 + Contact: linux-input@vger.kernel.org 31 + Description: This displays the available options for the enabled attribute. 32 + 33 + Values are true or false. 34 + 35 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 36 + 37 + What: /sys/class/leds/go:rgb:joystick_rings/mode 38 + Date: April 2026 39 + Contact: linux-input@vger.kernel.org 40 + Description: This controls the operating mode of the RGB interface. 41 + 42 + Values are dynamic or custom. Custom allows setting the RGB effect and color. 43 + Dynamic is a Windows mode for syncing Lenovo RGB interfaces not currently 44 + supported under Linux. 45 + 46 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 47 + 48 + What: /sys/class/leds/go:rgb:joystick_rings/mode_index 49 + Date: April 2026 50 + Contact: linux-input@vger.kernel.org 51 + Description: This displays the available options for the mode attribute. 52 + 53 + Values are dynamic or custom. 54 + 55 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 56 + 57 + What: /sys/class/leds/go:rgb:joystick_rings/profile 58 + Date: April 2026 59 + Contact: linux-input@vger.kernel.org 60 + Description: This controls selecting the configured RGB profile. 61 + 62 + Values are 1-3. 63 + 64 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 65 + 66 + What: /sys/class/leds/go:rgb:joystick_rings/profile_range 67 + Date: April 2026 68 + Contact: linux-input@vger.kernel.org 69 + Description: This displays the available options for the profile attribute. 70 + 71 + Values are 1-3. 72 + 73 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 74 + 75 + What: /sys/class/leds/go:rgb:joystick_rings/speed 76 + Date: April 2026 77 + Contact: linux-input@vger.kernel.org 78 + Description: This controls the change rate for the breathe, chroma, and rainbow effects. 79 + 80 + Values are 0-100. 81 + 82 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 83 + 84 + What: /sys/class/leds/go:rgb:joystick_rings/speed_range 85 + Date: April 2026 86 + Contact: linux-input@vger.kernel.org 87 + Description: This displays the available options for the speed attribute. 88 + 89 + Values are 0-100. 90 + 91 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 92 + 93 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/firmware_version 94 + Date: April 2026 95 + Contact: linux-input@vger.kernel.org 96 + Description: This displays the firmware version of the internal MCU. 97 + 98 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 99 + 100 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/fps_mode_dpi 101 + Date: April 2026 102 + Contact: linux-input@vger.kernel.org 103 + Description: This displays the DPI of the right handle when the FPS mode switch is on. 104 + 105 + Values are 500, 800, 1200, and 1800. 106 + 107 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 108 + 109 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/fps_mode_dpi_index 110 + Date: April 2026 111 + Contact: linux-input@vger.kernel.org 112 + Description: This displays the available options for the fps_mode_dpi attribute. 113 + 114 + Values are 500, 800, 1200, and 1800. 115 + 116 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 117 + 118 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/hardware_generation 119 + Date: April 2026 120 + Contact: linux-input@vger.kernel.org 121 + Description: This displays the hardware generation of the internal MCU. 122 + 123 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 124 + 125 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/hardware_version 126 + Date: April 2026 127 + Contact: linux-input@vger.kernel.org 128 + Description: This displays the hardware version of the internal MCU. 129 + 130 + 131 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 132 + 133 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/auto_sleep_time 134 + Date: April 2026 135 + Contact: linux-input@vger.kernel.org 136 + Description: This controls the sleep timer due to inactivity for the left removable controller. 137 + 138 + Values are 0-255. 139 + 140 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 141 + 142 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/auto_sleep_time_range 143 + Date: April 2026 144 + Contact: linux-input@vger.kernel.org 145 + Description: This displays the available options for the left_handle/auto_sleep_time attribute. 146 + 147 + Values are 0-255. 148 + 149 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 150 + 151 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/calibrate_gyro 152 + Date: April 2026 153 + Contact: linux-input@vger.kernel.org 154 + Description: This initiates or halts calibration of the left removable controller's IMU. 155 + 156 + Values are start, stop. 157 + 158 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 159 + 160 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/calibrate_gyro_index 161 + Date: April 2026 162 + Contact: linux-input@vger.kernel.org 163 + Description: This displays the available options for the left_handle/calibrate_gyro attribute. 164 + 165 + Values are start, stop. 166 + 167 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 168 + 169 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/calibrate_gyro_status 170 + Date: April 2026 171 + Contact: linux-input@vger.kernel.org 172 + Description: This displays the result of the last attempted calibration of the left removable controller's IMU. 173 + 174 + Values are unknown, success, failure. 175 + 176 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 177 + 178 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/calibrate_joystick 179 + Date: April 2026 180 + Contact: linux-input@vger.kernel.org 181 + Description: This initiates or halts calibration of the left removable controller's joystick. 182 + 183 + Values are start, stop. 184 + 185 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 186 + 187 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/calibrate_joystick_index 188 + Date: April 2026 189 + Contact: linux-input@vger.kernel.org 190 + Description: This displays the available options for the left_handle/calibrate_jotstick attribute. 191 + 192 + Values are start, stop. 193 + 194 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 195 + 196 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/calibrate_joystick_status 197 + Date: April 2026 198 + Contact: linux-input@vger.kernel.org 199 + Description: This displays the result of the last attempted calibration of the left removable controller's joystick. 200 + 201 + Values are unknown, success, failure. 202 + 203 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 204 + 205 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/calibrate_tirgger 206 + Date: April 2026 207 + Contact: linux-input@vger.kernel.org 208 + Description: This initiates or halts calibration of the left removable controller's trigger. 209 + 210 + Values are start, stop. 211 + 212 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 213 + 214 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/calibrate_gyro_trigger 215 + Date: April 2026 216 + Contact: linux-input@vger.kernel.org 217 + Description: This displays the available options for the left_handle/calibrate_trigger attribute. 218 + 219 + Values are start, stop. 220 + 221 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 222 + 223 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/calibrate_trigger_status 224 + Date: April 2026 225 + Contact: linux-input@vger.kernel.org 226 + Description: This displays the result of the last attempted calibration of the left removable controller's trigger. 227 + 228 + Values are unknown, success, failure. 229 + 230 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 231 + 232 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/firmware_version 233 + Date: April 2026 234 + Contact: linux-input@vger.kernel.org 235 + Description: This displays the left removable controller's firmware version. 236 + 237 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 238 + 239 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/hardware_generation 240 + Date: April 2026 241 + Contact: linux-input@vger.kernel.org 242 + Description: This displays the hardware generation of the left removable controller. 243 + 244 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 245 + 246 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/hardware_version 247 + Date: April 2026 248 + Contact: linux-input@vger.kernel.org 249 + Description: This displays the hardware version of the left removable controller. 250 + 251 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 252 + 253 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/imu_bypass_enabled 254 + Date: April 2026 255 + Contact: linux-input@vger.kernel.org 256 + Description: This controls enabling or disabling the IMU bypass function of the left removable controller. 257 + 258 + Values are true or false. 259 + 260 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 261 + 262 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/imu_bypass_enabled_index 263 + Date: April 2026 264 + Contact: linux-input@vger.kernel.org 265 + Description: This displays the available options for the left_handle/imu_bypass_enabled attribute. 266 + 267 + Values are true or false. 268 + 269 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/imu_enabled 270 + Date: April 2026 271 + Contact: linux-input@vger.kernel.org 272 + Description: This controls enabling or disabling the IMU of the left removable controller. 273 + 274 + Values are true or false. 275 + 276 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 277 + 278 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/imu_enabled_index 279 + Date: April 2026 280 + Contact: linux-input@vger.kernel.org 281 + Description: This displays the available options for the left_handle/imu_enabled attribute. 282 + 283 + Values are true or false. 284 + 285 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 286 + 287 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/product_version 288 + Date: April 2026 289 + Contact: linux-input@vger.kernel.org 290 + Description: This displays the product version of the left removable controller. 291 + 292 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 293 + 294 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/protocol_version 295 + Date: April 2026 296 + Contact: linux-input@vger.kernel.org 297 + Description: This displays the protocol version of the left removable controller. 298 + 299 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 300 + 301 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/reset 302 + Date: April 2026 303 + Contact: linux-input@vger.kernel.org 304 + Description: Resets the left removable controller to factory defaults. 305 + 306 + Writing 1 to this path initiates. 307 + 308 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 309 + 310 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/rumble_mode 311 + Date: April 2026 312 + Contact: linux-input@vger.kernel.org 313 + Description: This controls setting the response behavior for rumble events for the left removable controller. 314 + 315 + Values are fps, racing, standarg, spg, rpg. 316 + 317 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 318 + 319 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/rumble_mode_index 320 + Date: April 2026 321 + Contact: linux-input@vger.kernel.org 322 + Description: This displays the available options for the left_handle/rumble_mode attribute. 323 + 324 + Values are fps, racing, standarg, spg, rpg. 325 + 326 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 327 + 328 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/rumble_notification 329 + Date: April 2026 330 + Contact: linux-input@vger.kernel.org 331 + Description: This controls enabling haptic rumble events for the left removable controller. 332 + 333 + Values are true, false. 334 + 335 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 336 + 337 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/rumble_notification_index 338 + Date: April 2026 339 + Contact: linux-input@vger.kernel.org 340 + Description: This displays the available options for the left_handle/rumble_notification attribute. 341 + 342 + Values are true, false. 343 + 344 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 345 + 346 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/mode 347 + Date: April 2026 348 + Contact: linux-input@vger.kernel.org 349 + Description: This controls the operating mode of the built-in controller. 350 + 351 + Values are xinput or dinput. 352 + 353 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 354 + 355 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/mode_index 356 + Date: April 2026 357 + Contact: linux-input@vger.kernel.org 358 + Description: This displays the available options for the mode attribute. 359 + 360 + Values are xinput or dinput. 361 + 362 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 363 + 364 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/os_mode 365 + Date: April 2026 366 + Contact: linux-input@vger.kernel.org 367 + Description: This controls the behavior of built in chord combinations. 368 + 369 + Values are windows or linux. 370 + 371 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 372 + 373 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/os_mode_index 374 + Date: April 2026 375 + Contact: linux-input@vger.kernel.org 376 + Description: This displays the available options for the os_mode attribute. 377 + 378 + Values are windows or linux. 379 + 380 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 381 + 382 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/product_version 383 + Date: April 2026 384 + Contact: linux-input@vger.kernel.org 385 + Description: This displays the product version of the internal MCU. 386 + 387 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 388 + 389 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/protocol_version 390 + Date: April 2026 391 + Contact: linux-input@vger.kernel.org 392 + Description: This displays the protocol version of the internal MCU. 393 + 394 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 395 + 396 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/reset_mcu 397 + Date: April 2026 398 + Contact: linux-input@vger.kernel.org 399 + Description: Resets the internal MCU to factory defaults. 400 + 401 + Writing 1 to this path initiates. 402 + 403 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 404 + 405 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/auto_sleep_time 406 + Date: April 2026 407 + Contact: linux-input@vger.kernel.org 408 + Description: This controls the sleep timer due to inactivity for the right removable controller. 409 + 410 + Values are 0-255. 411 + 412 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 413 + 414 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/auto_sleep_time_range 415 + Date: April 2026 416 + Contact: linux-input@vger.kernel.org 417 + Description: This displays the available options for the right_handle/auto_sleep_time attribute. 418 + 419 + Values are 0-255. 420 + 421 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 422 + 423 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/calibrate_gyro 424 + Date: April 2026 425 + Contact: linux-input@vger.kernel.org 426 + Description: This initiates or halts calibration of the right removable controller's IMU. 427 + 428 + Values are start, stop. 429 + 430 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 431 + 432 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/calibrate_gyro_index 433 + Date: April 2026 434 + Contact: linux-input@vger.kernel.org 435 + Description: This displays the available options for the right_handle/calibrate_gyro attribute. 436 + 437 + Values are start, stop. 438 + 439 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 440 + 441 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/calibrate_gyro_status 442 + Date: April 2026 443 + Contact: linux-input@vger.kernel.org 444 + Description: This displays the result of the last attempted calibration of the right removable controller's IMU. 445 + 446 + Values are unknown, success, failure. 447 + 448 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 449 + 450 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/calibrate_joystick 451 + Date: April 2026 452 + Contact: linux-input@vger.kernel.org 453 + Description: This initiates or halts calibration of the right removable controller's joystick. 454 + 455 + Values are start, stop. 456 + 457 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 458 + 459 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/calibrate_joystick_index 460 + Date: April 2026 461 + Contact: linux-input@vger.kernel.org 462 + Description: This displays the available options for the right_handle/calibrate_jotstick attribute. 463 + 464 + Values are start, stop. 465 + 466 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 467 + 468 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/calibrate_joystick_status 469 + Date: April 2026 470 + Contact: linux-input@vger.kernel.org 471 + Description: This displays the result of the last attempted calibration of the right removable controller's joystick. 472 + 473 + Values are unknown, success, failure. 474 + 475 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 476 + 477 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/calibrate_tirgger 478 + Date: April 2026 479 + Contact: linux-input@vger.kernel.org 480 + Description: This initiates or halts calibration of the right removable controller's trigger. 481 + 482 + Values are start, stop. 483 + 484 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 485 + 486 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/calibrate_gyro_trigger 487 + Date: April 2026 488 + Contact: linux-input@vger.kernel.org 489 + Description: This displays the available options for the right_handle/calibrate_trigger attribute. 490 + 491 + Values are start, stop. 492 + 493 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 494 + 495 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/calibrate_trigger_status 496 + Date: April 2026 497 + Contact: linux-input@vger.kernel.org 498 + Description: This displays the result of the last attempted calibration of the right removable controller's trigger. 499 + 500 + Values are unknown, success, failure. 501 + 502 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 503 + 504 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/firmware_version 505 + Date: April 2026 506 + Contact: linux-input@vger.kernel.org 507 + Description: This displays the right removable controller's firmware version. 508 + 509 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 510 + 511 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/hardware_generation 512 + Date: April 2026 513 + Contact: linux-input@vger.kernel.org 514 + Description: This displays the hardware generation of the right removable controller. 515 + 516 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 517 + 518 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/hardware_version 519 + Date: April 2026 520 + Contact: linux-input@vger.kernel.org 521 + Description: This displays the hardware version of the right removable controller. 522 + 523 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 524 + 525 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/imu_bypass_enabled 526 + Date: April 2026 527 + Contact: linux-input@vger.kernel.org 528 + Description: This controls enabling or disabling the IMU bypass function of the right removable controller. 529 + 530 + Values are true or false. 531 + 532 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 533 + 534 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/imu_bypass_enabled_index 535 + Date: April 2026 536 + Contact: linux-input@vger.kernel.org 537 + Description: This displays the available options for the right_handle/imu_bypass_enabled attribute. 538 + 539 + Values are true or false. 540 + 541 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/imu_enabled 542 + Date: April 2026 543 + Contact: linux-input@vger.kernel.org 544 + Description: This controls enabling or disabling the IMU of the right removable controller. 545 + 546 + Values are true or false. 547 + 548 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 549 + 550 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/imu_enabled_index 551 + Date: April 2026 552 + Contact: linux-input@vger.kernel.org 553 + Description: This displays the available options for the right_handle/imu_enabled attribute. 554 + 555 + Values are true or false. 556 + 557 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 558 + 559 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/product_version 560 + Date: April 2026 561 + Contact: linux-input@vger.kernel.org 562 + Description: This displays the product version of the right removable controller. 563 + 564 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 565 + 566 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/protocol_version 567 + Date: April 2026 568 + Contact: linux-input@vger.kernel.org 569 + Description: This displays the protocol version of the right removable controller. 570 + 571 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 572 + 573 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/reset 574 + Date: April 2026 575 + Contact: linux-input@vger.kernel.org 576 + Description: Resets the right removable controller to factory defaults. 577 + 578 + Writing 1 to this path initiates. 579 + 580 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 581 + 582 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/rumble_mode 583 + Date: April 2026 584 + Contact: linux-input@vger.kernel.org 585 + Description: This controls setting the response behavior for rumble events for the right removable controller. 586 + 587 + Values are fps, racing, standarg, spg, rpg. 588 + 589 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 590 + 591 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/rumble_mode_index 592 + Date: April 2026 593 + Contact: linux-input@vger.kernel.org 594 + Description: This displays the available options for the right_handle/rumble_mode attribute. 595 + 596 + Values are fps, racing, standarg, spg, rpg. 597 + 598 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 599 + 600 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/rumble_notification 601 + Date: April 2026 602 + Contact: linux-input@vger.kernel.org 603 + Description: This controls enabling haptic rumble events for the right removable controller. 604 + 605 + Values are true, false. 606 + 607 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 608 + 609 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/rumble_notification_index 610 + Date: April 2026 611 + Contact: linux-input@vger.kernel.org 612 + Description: This displays the available options for the right_handle/rumble_notification attribute. 613 + 614 + Values are true, false. 615 + 616 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 617 + 618 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/rumble_intensity 619 + Date: April 2026 620 + Contact: linux-input@vger.kernel.org 621 + Description: This controls setting the rumble intensity for both removable controllers. 622 + 623 + Values are off, low, medium, high. 624 + 625 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 626 + 627 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/rumble_intensity_index 628 + Date: April 2026 629 + Contact: linux-input@vger.kernel.org 630 + Description: This displays the available options for the rumble_intensity attribute. 631 + 632 + Values are off, low, medium, high. 633 + 634 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 635 + 636 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/enabled 637 + Date: April 2026 638 + Contact: linux-input@vger.kernel.org 639 + Description: This controls enabling or disabling the touchpad. 640 + 641 + Values are true, false. 642 + 643 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 644 + 645 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/enabled_index 646 + Date: April 2026 647 + Contact: linux-input@vger.kernel.org 648 + Description: This displays the available options for the touchpad/enabled attribute. 649 + 650 + Values are true, false. 651 + 652 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 653 + 654 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/vibration_enabled 655 + Date: April 2026 656 + Contact: linux-input@vger.kernel.org 657 + Description: This controls enabling haptic rumble events for the touchpad. 658 + 659 + Values are true, false. 660 + 661 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 662 + 663 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/vibration_enabled_index 664 + Date: April 2026 665 + Contact: linux-input@vger.kernel.org 666 + Description: This displays the available options for the touchpad/vibration_enabled attribute. 667 + 668 + Values are true, false. 669 + 670 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 671 + 672 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/vibration_intensity 673 + Date: April 2026 674 + Contact: linux-input@vger.kernel.org 675 + Description: This controls setting the intensity of the touchpad haptics. 676 + 677 + Values are off, low, medium, high. 678 + 679 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 680 + 681 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/vibration_intensity_index 682 + Date: April 2026 683 + Contact: linux-input@vger.kernel.org 684 + Description: This displays the available options for the touchpad/vibration_intensity attribute. 685 + 686 + Values are off, low, medium, high. 687 + 688 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 689 + 690 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/tx_dongle/firmware_version 691 + Date: April 2026 692 + Contact: linux-input@vger.kernel.org 693 + Description: This displays the firmware version of the internal wireless transmission dongle. 694 + 695 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 696 + 697 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/tx_dongle/hardware_generation 698 + Date: April 2026 699 + Contact: linux-input@vger.kernel.org 700 + Description: This displays the hardware generation of the internal wireless transmission dongle. 701 + 702 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 703 + 704 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/tx_dongle/hardware_version 705 + Date: April 2026 706 + Contact: linux-input@vger.kernel.org 707 + Description: This displays the hardware version of the internal wireless transmission dongle. 708 + 709 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 710 + 711 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/tx_dongle/product_version 712 + Date: April 2026 713 + Contact: linux-input@vger.kernel.org 714 + Description: This displays the product version of the internal wireless transmission dongle. 715 + 716 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 717 + 718 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/tx_dongle/protocol_version 719 + Date: April 2026 720 + Contact: linux-input@vger.kernel.org 721 + Description: This displays the protocol version of the internal wireless transmission dongle. 722 + 723 + Applies to Lenovo Legion Go and Go 2 line of handheld devices. 724 +
+304
Documentation/ABI/testing/sysfs-driver-hid-lenovo-go-s
··· 1 + What: /sys/class/leds/go_s:rgb:joystick_rings/effect 2 + Date: April 2026 3 + Contact: linux-input@vger.kernel.org 4 + Description: This controls the display effect of the RGB interface. 5 + 6 + Values are monocolor, breathe, chroma, or rainbow. 7 + 8 + Applies to Lenovo Legion Go S line of handheld devices. 9 + 10 + What: /sys/class/leds/go_s:rgb:joystick_rings/effect_index 11 + Date: April 2026 12 + Contact: linux-input@vger.kernel.org 13 + Description: This displays the available options for the effect attribute. 14 + 15 + Values are monocolor, breathe, chroma, or rainbow. 16 + 17 + Applies to Lenovo Legion Go S line of handheld devices. 18 + 19 + What: /sys/class/leds/go_s:rgb:joystick_rings/enabled 20 + Date: April 2026 21 + Contact: linux-input@vger.kernel.org 22 + Description: This controls enabling or disabling the RGB interface. 23 + 24 + Values are true or false. 25 + 26 + Applies to Lenovo Legion Go S line of handheld devices. 27 + 28 + What: /sys/class/leds/go_s:rgb:joystick_rings/enabled_index 29 + Date: April 2026 30 + Contact: linux-input@vger.kernel.org 31 + Description: This displays the available options for the enabled attribute. 32 + 33 + Values are true or false. 34 + 35 + Applies to Lenovo Legion Go S line of handheld devices. 36 + 37 + What: /sys/class/leds/go_s:rgb:joystick_rings/mode 38 + Date: April 2026 39 + Contact: linux-input@vger.kernel.org 40 + Description: This controls the operating mode of the RGB interface. 41 + 42 + Values are dynamic or custom. Custom allows setting the RGB effect and color. 43 + Dynamic is a Windows mode for syncing Lenovo RGB interfaces not currently 44 + supported under Linux. 45 + 46 + Applies to Lenovo Legion Go S line of handheld devices. 47 + 48 + What: /sys/class/leds/go_s:rgb:joystick_rings/mode_index 49 + Date: April 2026 50 + Contact: linux-input@vger.kernel.org 51 + Description: This displays the available options for the mode attribute. 52 + 53 + Values are dynamic or custom. 54 + 55 + Applies to Lenovo Legion Go S line of handheld devices. 56 + 57 + What: /sys/class/leds/go_s:rgb:joystick_rings/profile 58 + Date: April 2026 59 + Contact: linux-input@vger.kernel.org 60 + Description: This controls selecting the configured RGB profile. 61 + 62 + Values are 1-3. 63 + 64 + Applies to Lenovo Legion Go S line of handheld devices. 65 + 66 + What: /sys/class/leds/go_s:rgb:joystick_rings/profile_range 67 + Date: April 2026 68 + Contact: linux-input@vger.kernel.org 69 + Description: This displays the available options for the profile attribute. 70 + 71 + Values are 1-3. 72 + 73 + Applies to Lenovo Legion Go S line of handheld devices. 74 + 75 + What: /sys/class/leds/go_s:rgb:joystick_rings/speed 76 + Date: April 2026 77 + Contact: linux-input@vger.kernel.org 78 + Description: This controls the change rate for the breathe, chroma, and rainbow effects. 79 + 80 + Values are 0-100. 81 + 82 + Applies to Lenovo Legion Go S line of handheld devices. 83 + 84 + What: /sys/class/leds/go_s:rgb:joystick_rings/speed_range 85 + Date: April 2026 86 + Contact: linux-input@vger.kernel.org 87 + Description: This displays the available options for the speed attribute. 88 + 89 + Values are 0-100. 90 + 91 + Applies to Lenovo Legion Go S line of handheld devices. 92 + 93 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/gamepad/auto_sleep_time 94 + Date: April 2026 95 + Contact: linux-input@vger.kernel.org 96 + Description: This controls the sleep timer due to inactivity for the built-in controller. 97 + 98 + Values are 0-255. 99 + 100 + Applies to Lenovo Legion Go S line of handheld devices. 101 + 102 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/gamepad/auto_sleep_time_range 103 + Date: April 2026 104 + Contact: linux-input@vger.kernel.org 105 + Description: This displays the available options for the gamepad/auto_sleep_time attribute. 106 + 107 + Values are 0-255. 108 + 109 + Applies to Lenovo Legion Go S line of handheld devices. 110 + 111 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/gamepad/dpad_mode 112 + Date: April 2026 113 + Contact: linux-input@vger.kernel.org 114 + Description: This controls the operating mode of the built-in controllers D-pad. 115 + 116 + Values are 4-way or 8-way. 117 + 118 + Applies to Lenovo Legion Go S line of handheld devices. 119 + 120 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/gamepad/dpad_mode_index 121 + Date: April 2026 122 + Contact: linux-input@vger.kernel.org 123 + Description: This displays the available options for the gamepad/dpad_mode attribute. 124 + 125 + Values are 4-way or 8-way. 126 + 127 + Applies to Lenovo Legion Go S line of handheld devices. 128 + 129 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/gamepad/mode 130 + Date: April 2026 131 + Contact: linux-input@vger.kernel.org 132 + Description: This controls the operating mode of the built-in controller. 133 + 134 + Values are xinput or dinput. 135 + 136 + Applies to Lenovo Legion Go S line of handheld devices. 137 + 138 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/gamepad/mode_index 139 + Date: April 2026 140 + Contact: linux-input@vger.kernel.org 141 + Description: This displays the available options for the gamepad/mode attribute. 142 + 143 + Values are xinput or dinput. 144 + 145 + Applies to Lenovo Legion Go S line of handheld devices. 146 + 147 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/gamepad/poll_rate 148 + Date: April 2026 149 + Contact: linux-input@vger.kernel.org 150 + Description: This controls the poll rate in Hz of the built-in controller. 151 + 152 + Values are 125, 250, 500, or 1000. 153 + 154 + Applies to Lenovo Legion Go S line of handheld devices. 155 + 156 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/gamepad/poll_rate_index 157 + Date: April 2026 158 + Contact: linux-input@vger.kernel.org 159 + Description: This displays the available options for the gamepad/poll_rate attribute. 160 + 161 + Values are 125, 250, 500, or 1000. 162 + 163 + Applies to Lenovo Legion Go S line of handheld devices. 164 + 165 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/imu/bypass_enabled 166 + Date: April 2026 167 + Contact: linux-input@vger.kernel.org 168 + Description: This controls enabling or disabling the IMU bypass function. When enabled the IMU data is directly reported to the OS through 169 + an HIDRAW interface. 170 + 171 + Values are true or false. 172 + 173 + Applies to Lenovo Legion Go S line of handheld devices. 174 + 175 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/imu/bypass_enabled_index 176 + Date: April 2026 177 + Contact: linux-input@vger.kernel.org 178 + Description: This displays the available options for the imu/bypass_enabled attribute. 179 + 180 + Values are true or false. 181 + 182 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/imu/manufacturer 183 + Date: April 2026 184 + Contact: linux-input@vger.kernel.org 185 + Description: This displays the manufacturer of the intertial measurment unit. 186 + 187 + Values are Bosch or ST. 188 + 189 + Applies to Lenovo Legion Go S line of handheld devices. 190 + 191 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/imu/sensor_enabled 192 + Date: April 2026 193 + Contact: linux-input@vger.kernel.org 194 + Description: This controls enabling or disabling the IMU. 195 + 196 + Values are true, false, or wake-2s. 197 + 198 + Applies to Lenovo Legion Go S line of handheld devices. 199 + 200 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/imu/sensor_enabled_index 201 + Date: April 2026 202 + Contact: linux-input@vger.kernel.org 203 + Description: This displays the available options for the imu/sensor_enabled attribute. 204 + 205 + Values are true, false, or wake-2s. 206 + 207 + Applies to Lenovo Legion Go S line of handheld devices. 208 + 209 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/mcu_id 210 + Date: April 2026 211 + Contact: linux-input@vger.kernel.org 212 + Description: This displays the MCU Identification Number 213 + 214 + Applies to Lenovo Legion Go S line of handheld devices. 215 + 216 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/mouse/step 217 + Date: April 2026 218 + Contact: linux-input@vger.kernel.org 219 + Description: This controls which value is used for the mouse sensitivity. 220 + 221 + Values are 1-127. 222 + 223 + Applies to Lenovo Legion Go S line of handheld devices. 224 + 225 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/mouse/step_range 226 + Date: April 2026 227 + Contact: linux-input@vger.kernel.org 228 + Description: This displays the available options for the mouse/step attribute. 229 + 230 + Values are 1-127. 231 + 232 + Applies to Lenovo Legion Go S line of handheld devices. 233 + 234 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/os_mode 235 + Date: April 2026 236 + Contact: linux-input@vger.kernel.org 237 + Description: This controls which value is used for the touchpads operating mode. 238 + 239 + Values are windows or linux. 240 + 241 + Applies to Lenovo Legion Go S line of handheld devices. 242 + 243 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/os_mode_index 244 + Date: April 2026 245 + Contact: linux-input@vger.kernel.org 246 + Description: This displays the available options for the os_mode attribute. 247 + 248 + Values are windows or linux. 249 + 250 + Applies to Lenovo Legion Go S line of handheld devices. 251 + 252 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/enabled 253 + Date: April 2026 254 + Contact: linux-input@vger.kernel.org 255 + Description: This controls enabling or disabling the built-in touchpad. 256 + 257 + Values are true or false. 258 + 259 + Applies to Lenovo Legion Go S line of handheld devices. 260 + 261 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/enabled_index 262 + Date: April 2026 263 + Contact: linux-input@vger.kernel.org 264 + Description: This displays the available options for the touchpad/enabled attribute. 265 + 266 + Values are true or false. 267 + 268 + Applies to Lenovo Legion Go S line of handheld devices. 269 + 270 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/linux_mode 271 + Date: April 2026 272 + Contact: linux-input@vger.kernel.org 273 + Description: This controls behavior of the touchpad events when os_mode is set to linux. 274 + 275 + Values are absolute or relative. 276 + 277 + Applies to Lenovo Legion Go S line of handheld devices. 278 + 279 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/linux_mode_index 280 + Date: April 2026 281 + Contact: linux-input@vger.kernel.org 282 + Description: This displays the available options for the touchpad/linux_mode attribute. 283 + 284 + Values are absolute or relative. 285 + 286 + Applies to Lenovo Legion Go S line of handheld devices. 287 + 288 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/windows_mode 289 + Date: April 2026 290 + Contact: linux-input@vger.kernel.org 291 + Description: This controls behavior of the touchpad events when os_mode is set to windows. 292 + 293 + Values are absolute or relative. 294 + 295 + Applies to Lenovo Legion Go S line of handheld devices. 296 + 297 + What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/windows_mode_index 298 + Date: April 2026 299 + Contact: linux-input@vger.kernel.org 300 + Description: This displays the available options for the touchpad/windows_mode attribute. 301 + 302 + Values are absolute or relative. 303 + 304 + Applies to Lenovo Legion Go S line of handheld devices.
+11
MAINTAINERS
··· 14469 14469 S: Maintained 14470 14470 F: drivers/platform/x86/lenovo/wmi-hotkey-utilities.c 14471 14471 14472 + LENOVO HID drivers 14473 + M: Derek J. Clark <derekjohn.clark@gmail.com> 14474 + M: Mark Pearson <mpearson-lenovo@squebb.ca> 14475 + L: linux-input@vger.kernel.org 14476 + S: Maintained 14477 + F: Documentation/ABI/testing/sysfs-driver-hid-lenovo-go 14478 + F: Documentation/ABI/testing/sysfs-driver-hid-lenovo-go-s 14479 + F: drivers/hid/hid-lenovo-go-s.c 14480 + F: drivers/hid/hid-lenovo-go.c 14481 + F: drivers/hid/hid-lenovo.c 14482 + 14472 14483 LETSKETCH HID TABLET DRIVER 14473 14484 M: Hans de Goede <hansg@kernel.org> 14474 14485 L: linux-input@vger.kernel.org
+23 -2
drivers/hid/Kconfig
··· 601 601 602 602 config HID_LENOVO 603 603 tristate "Lenovo / Thinkpad devices" 604 - select NEW_LEDS 605 - select LEDS_CLASS 604 + depends on LEDS_CLASS 606 605 help 607 606 Support for IBM/Lenovo devices that are not fully compliant with HID standard. 608 607 ··· 612 613 configuration) 613 614 - ThinkPad Compact Bluetooth Keyboard with TrackPoint (supports Fn keys) 614 615 - ThinkPad Compact USB Keyboard with TrackPoint (supports Fn keys) 616 + 617 + config HID_LENOVO_GO 618 + tristate "HID Driver for Lenovo Legion Go Series Controllers" 619 + depends on USB_HID 620 + depends on LEDS_CLASS_MULTICOLOR 621 + help 622 + Support for Lenovo Legion Go devices with detachable controllers. 623 + 624 + Say Y here to include configuration interface support for the Lenovo Legion Go 625 + and Legion Go 2 Handheld Console Controllers. Say M here to compile this 626 + driver as a module. The module will be called hid-lenovo-go. 627 + 628 + config HID_LENOVO_GO_S 629 + tristate "HID Driver for Lenovo Legion Go S Controller" 630 + depends on USB_HID 631 + depends on LEDS_CLASS_MULTICOLOR 632 + help 633 + Support for Lenovo Legion Go S Handheld Console Controller. 634 + 635 + Say Y here to include configuration interface support for the Lenovo Legion Go 636 + S. Say M here to compile this driver as a module. The module will be called 637 + hid-lenovo-go-s. 615 638 616 639 config HID_LETSKETCH 617 640 tristate "Letsketch WP9620N tablets"
+2
drivers/hid/Makefile
··· 76 76 obj-$(CONFIG_HID_KYSONA) += hid-kysona.o 77 77 obj-$(CONFIG_HID_LCPOWER) += hid-lcpower.o 78 78 obj-$(CONFIG_HID_LENOVO) += hid-lenovo.o 79 + obj-$(CONFIG_HID_LENOVO_GO) += hid-lenovo-go.o 80 + obj-$(CONFIG_HID_LENOVO_GO_S) += hid-lenovo-go-s.o 79 81 obj-$(CONFIG_HID_LETSKETCH) += hid-letsketch.o 80 82 obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o 81 83 obj-$(CONFIG_HID_LOGITECH) += hid-lg-g15.o
+5
drivers/hid/hid-core.c
··· 2895 2895 if (add_uevent_var(env, "MODALIAS=hid:b%04Xg%04Xv%08Xp%08X", 2896 2896 hdev->bus, hdev->group, hdev->vendor, hdev->product)) 2897 2897 return -ENOMEM; 2898 + if (hdev->firmware_version) { 2899 + if (add_uevent_var(env, "HID_FIRMWARE_VERSION=0x%04llX", 2900 + hdev->firmware_version)) 2901 + return -ENOMEM; 2902 + } 2898 2903 2899 2904 return 0; 2900 2905 }
+7
drivers/hid/hid-ids.h
··· 754 754 #define USB_DEVICE_ID_ITE8595 0x8595 755 755 #define USB_DEVICE_ID_ITE_MEDION_E1239T 0xce50 756 756 757 + #define USB_VENDOR_ID_QHE 0x1a86 758 + #define USB_DEVICE_ID_LENOVO_LEGION_GO_S_XINPUT 0xe310 759 + #define USB_DEVICE_ID_LENOVO_LEGION_GO_S_DINPUT 0xe311 760 + 757 761 #define USB_VENDOR_ID_JABRA 0x0b0e 758 762 #define USB_DEVICE_ID_JABRA_SPEAK_410 0x0412 759 763 #define USB_DEVICE_ID_JABRA_SPEAK_510 0x0420 ··· 877 873 #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E 0x602e 878 874 #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6093 0x6093 879 875 #define USB_DEVICE_ID_LENOVO_LEGION_GO_DUAL_DINPUT 0x6184 876 + #define USB_DEVICE_ID_LENOVO_LEGION_GO2_XINPUT 0x61eb 877 + #define USB_DEVICE_ID_LENOVO_LEGION_GO2_DINPUT 0x61ec 880 878 #define USB_DEVICE_ID_LENOVO_LEGION_GO2_DUAL_DINPUT 0x61ed 879 + #define USB_DEVICE_ID_LENOVO_LEGION_GO2_FPS 0x61ee 881 880 882 881 #define USB_VENDOR_ID_LETSKETCH 0x6161 883 882 #define USB_DEVICE_ID_WP9620N 0x4d15
+1504
drivers/hid/hid-lenovo-go-s.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * HID driver for Lenovo Legion Go S devices. 4 + * 5 + * Copyright (c) 2026 Derek J. Clark <derekjohn.clark@gmail.com> 6 + * Copyright (c) 2026 Valve Corporation 7 + */ 8 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 9 + 10 + #include <linux/array_size.h> 11 + #include <linux/cleanup.h> 12 + #include <linux/completion.h> 13 + #include <linux/delay.h> 14 + #include <linux/dev_printk.h> 15 + #include <linux/device.h> 16 + #include <linux/hid.h> 17 + #include <linux/jiffies.h> 18 + #include <linux/kstrtox.h> 19 + #include <linux/led-class-multicolor.h> 20 + #include <linux/mutex.h> 21 + #include <linux/printk.h> 22 + #include <linux/string.h> 23 + #include <linux/sysfs.h> 24 + #include <linux/types.h> 25 + #include <linux/unaligned.h> 26 + #include <linux/usb.h> 27 + #include <linux/workqueue.h> 28 + #include <linux/workqueue_types.h> 29 + 30 + #include "hid-ids.h" 31 + 32 + #define GO_S_CFG_INTF_IN 0x84 33 + #define GO_S_PACKET_SIZE 64 34 + 35 + static struct hid_gos_cfg { 36 + struct delayed_work gos_cfg_setup; 37 + struct completion send_cmd_complete; 38 + struct led_classdev *led_cdev; 39 + struct hid_device *hdev; 40 + struct mutex cfg_mutex; /*ensure single synchronous output report*/ 41 + u8 gp_auto_sleep_time; 42 + u8 gp_dpad_mode; 43 + u8 gp_mode; 44 + u8 gp_poll_rate; 45 + u8 imu_bypass_en; 46 + u8 imu_manufacturer; 47 + u8 imu_sensor_en; 48 + u8 mcu_id[12]; 49 + u8 mouse_step; 50 + u8 os_mode; 51 + u8 rgb_effect; 52 + u8 rgb_en; 53 + u8 rgb_mode; 54 + u8 rgb_profile; 55 + u8 rgb_speed; 56 + u8 tp_en; 57 + u8 tp_linux_mode; 58 + u8 tp_windows_mode; 59 + u8 tp_version; 60 + u8 tp_manufacturer; 61 + } drvdata; 62 + 63 + struct gos_cfg_attr { 64 + u8 index; 65 + }; 66 + 67 + struct command_report { 68 + u8 cmd; 69 + u8 sub_cmd; 70 + u8 data[63]; 71 + } __packed; 72 + 73 + struct version_report { 74 + u8 cmd; 75 + u32 version; 76 + u8 reserved[59]; 77 + } __packed; 78 + 79 + enum mcu_command_index { 80 + GET_VERSION = 0x01, 81 + GET_MCU_ID, 82 + GET_GAMEPAD_CFG, 83 + SET_GAMEPAD_CFG, 84 + GET_TP_PARAM, 85 + SET_TP_PARAM, 86 + GET_RGB_CFG = 0x0f, 87 + SET_RGB_CFG, 88 + GET_PL_TEST = 0xdf, 89 + }; 90 + 91 + enum feature_enabled_index { 92 + FEATURE_DISABLED, 93 + FEATURE_ENABLED, 94 + }; 95 + 96 + static const char *const feature_enabled_text[] = { 97 + [FEATURE_DISABLED] = "false", 98 + [FEATURE_ENABLED] = "true", 99 + }; 100 + 101 + enum feature_status_index { 102 + FEATURE_NONE = 0x00, 103 + FEATURE_GAMEPAD_MODE = 0x01, 104 + FEATURE_AUTO_SLEEP_TIME = 0x04, 105 + FEATURE_IMU_BYPASS, 106 + FEATURE_RGB_ENABLE, 107 + FEATURE_IMU_ENABLE, 108 + FEATURE_TOUCHPAD_ENABLE, 109 + FEATURE_OS_MODE = 0x0A, 110 + FEATURE_POLL_RATE = 0x10, 111 + FEATURE_DPAD_MODE, 112 + FEATURE_MOUSE_WHEEL_STEP, 113 + }; 114 + 115 + enum gamepad_mode_index { 116 + XINPUT, 117 + DINPUT, 118 + }; 119 + 120 + static const char *const gamepad_mode_text[] = { 121 + [XINPUT] = "xinput", 122 + [DINPUT] = "dinput", 123 + }; 124 + 125 + enum os_type_index { 126 + WINDOWS, 127 + LINUX, 128 + }; 129 + 130 + static const char *const os_type_text[] = { 131 + [WINDOWS] = "windows", 132 + [LINUX] = "linux", 133 + }; 134 + 135 + enum poll_rate_index { 136 + HZ125, 137 + HZ250, 138 + HZ500, 139 + HZ1000, 140 + }; 141 + 142 + static const char *const poll_rate_text[] = { 143 + [HZ125] = "125", 144 + [HZ250] = "250", 145 + [HZ500] = "500", 146 + [HZ1000] = "1000", 147 + }; 148 + 149 + enum dpad_mode_index { 150 + DIR8, 151 + DIR4, 152 + }; 153 + 154 + static const char *const dpad_mode_text[] = { 155 + [DIR8] = "8-way", 156 + [DIR4] = "4-way", 157 + }; 158 + 159 + enum touchpad_mode_index { 160 + TP_REL, 161 + TP_ABS, 162 + }; 163 + 164 + static const char *const touchpad_mode_text[] = { 165 + [TP_REL] = "relative", 166 + [TP_ABS] = "absolute", 167 + }; 168 + 169 + enum touchpad_config_index { 170 + CFG_WINDOWS_MODE = 0x03, 171 + CFG_LINUX_MODE, 172 + 173 + }; 174 + 175 + enum rgb_mode_index { 176 + RGB_MODE_DYNAMIC, 177 + RGB_MODE_CUSTOM, 178 + }; 179 + 180 + static const char *const rgb_mode_text[] = { 181 + [RGB_MODE_DYNAMIC] = "dynamic", 182 + [RGB_MODE_CUSTOM] = "custom", 183 + }; 184 + 185 + enum rgb_effect_index { 186 + RGB_EFFECT_MONO, 187 + RGB_EFFECT_BREATHE, 188 + RGB_EFFECT_CHROMA, 189 + RGB_EFFECT_RAINBOW, 190 + }; 191 + 192 + static const char *const rgb_effect_text[] = { 193 + [RGB_EFFECT_MONO] = "monocolor", 194 + [RGB_EFFECT_BREATHE] = "breathe", 195 + [RGB_EFFECT_CHROMA] = "chroma", 196 + [RGB_EFFECT_RAINBOW] = "rainbow", 197 + }; 198 + 199 + enum rgb_config_index { 200 + LIGHT_MODE_SEL = 0x01, 201 + LIGHT_PROFILE_SEL, 202 + USR_LIGHT_PROFILE_1, 203 + USR_LIGHT_PROFILE_2, 204 + USR_LIGHT_PROFILE_3, 205 + }; 206 + 207 + enum test_command_index { 208 + TEST_TP_MFR = 0x02, 209 + TEST_IMU_MFR, 210 + TEST_TP_VER, 211 + }; 212 + 213 + enum tp_mfr_index { 214 + TP_NONE, 215 + TP_BETTERLIFE, 216 + TP_SIPO, 217 + }; 218 + 219 + static const char *const touchpad_manufacturer_text[] = { 220 + [TP_NONE] = "none", 221 + [TP_BETTERLIFE] = "BetterLife", 222 + [TP_SIPO] = "SIPO", 223 + }; 224 + 225 + enum imu_mfr_index { 226 + IMU_NONE, 227 + IMU_BOSCH, 228 + IMU_ST, 229 + }; 230 + 231 + static const char *const imu_manufacturer_text[] = { 232 + [IMU_NONE] = "none", 233 + [IMU_BOSCH] = "Bosch", 234 + [IMU_ST] = "ST", 235 + }; 236 + 237 + static int hid_gos_version_event(u8 *data) 238 + { 239 + struct version_report *ver_rep = (struct version_report *)data; 240 + 241 + drvdata.hdev->firmware_version = get_unaligned_le32(&ver_rep->version); 242 + return 0; 243 + } 244 + 245 + static int hid_gos_mcu_id_event(struct command_report *cmd_rep) 246 + { 247 + drvdata.mcu_id[0] = cmd_rep->sub_cmd; 248 + memcpy(&drvdata.mcu_id[1], cmd_rep->data, 11); 249 + 250 + return 0; 251 + } 252 + 253 + static int hid_gos_gamepad_cfg_event(struct command_report *cmd_rep) 254 + { 255 + int ret = 0; 256 + 257 + switch (cmd_rep->sub_cmd) { 258 + case FEATURE_GAMEPAD_MODE: 259 + drvdata.gp_mode = cmd_rep->data[0]; 260 + break; 261 + case FEATURE_AUTO_SLEEP_TIME: 262 + drvdata.gp_auto_sleep_time = cmd_rep->data[0]; 263 + break; 264 + case FEATURE_IMU_BYPASS: 265 + drvdata.imu_bypass_en = cmd_rep->data[0]; 266 + break; 267 + case FEATURE_RGB_ENABLE: 268 + drvdata.rgb_en = cmd_rep->data[0]; 269 + break; 270 + case FEATURE_IMU_ENABLE: 271 + drvdata.imu_sensor_en = cmd_rep->data[0]; 272 + break; 273 + case FEATURE_TOUCHPAD_ENABLE: 274 + drvdata.tp_en = cmd_rep->data[0]; 275 + break; 276 + case FEATURE_OS_MODE: 277 + drvdata.os_mode = cmd_rep->data[0]; 278 + break; 279 + case FEATURE_POLL_RATE: 280 + drvdata.gp_poll_rate = cmd_rep->data[0]; 281 + break; 282 + case FEATURE_DPAD_MODE: 283 + drvdata.gp_dpad_mode = cmd_rep->data[0]; 284 + break; 285 + case FEATURE_MOUSE_WHEEL_STEP: 286 + drvdata.mouse_step = cmd_rep->data[0]; 287 + break; 288 + default: 289 + ret = -EINVAL; 290 + break; 291 + } 292 + 293 + return ret; 294 + } 295 + 296 + static int hid_gos_touchpad_event(struct command_report *cmd_rep) 297 + { 298 + int ret = 0; 299 + 300 + switch (cmd_rep->sub_cmd) { 301 + case CFG_LINUX_MODE: 302 + drvdata.tp_linux_mode = cmd_rep->data[0]; 303 + break; 304 + case CFG_WINDOWS_MODE: 305 + drvdata.tp_windows_mode = cmd_rep->data[0]; 306 + break; 307 + default: 308 + ret = -EINVAL; 309 + break; 310 + } 311 + 312 + return ret; 313 + } 314 + 315 + static int hid_gos_pl_test_event(struct command_report *cmd_rep) 316 + { 317 + int ret = 0; 318 + 319 + switch (cmd_rep->sub_cmd) { 320 + case TEST_TP_MFR: 321 + drvdata.tp_manufacturer = cmd_rep->data[0]; 322 + ret = 0; 323 + break; 324 + case TEST_IMU_MFR: 325 + drvdata.imu_manufacturer = cmd_rep->data[0]; 326 + ret = 0; 327 + break; 328 + case TEST_TP_VER: 329 + drvdata.tp_version = cmd_rep->data[0]; 330 + ret = 0; 331 + break; 332 + default: 333 + ret = -EINVAL; 334 + break; 335 + } 336 + return ret; 337 + } 338 + 339 + static int hid_gos_light_event(struct command_report *cmd_rep) 340 + { 341 + struct led_classdev_mc *mc_cdev; 342 + int ret = 0; 343 + 344 + switch (cmd_rep->sub_cmd) { 345 + case LIGHT_MODE_SEL: 346 + drvdata.rgb_mode = cmd_rep->data[0]; 347 + ret = 0; 348 + break; 349 + case LIGHT_PROFILE_SEL: 350 + drvdata.rgb_profile = cmd_rep->data[0]; 351 + ret = 0; 352 + break; 353 + case USR_LIGHT_PROFILE_1: 354 + case USR_LIGHT_PROFILE_2: 355 + case USR_LIGHT_PROFILE_3: 356 + mc_cdev = lcdev_to_mccdev(drvdata.led_cdev); 357 + drvdata.rgb_effect = cmd_rep->data[0]; 358 + mc_cdev->subled_info[0].intensity = cmd_rep->data[1]; 359 + mc_cdev->subled_info[1].intensity = cmd_rep->data[2]; 360 + mc_cdev->subled_info[2].intensity = cmd_rep->data[3]; 361 + drvdata.led_cdev->brightness = cmd_rep->data[4]; 362 + drvdata.rgb_speed = cmd_rep->data[5]; 363 + ret = 0; 364 + break; 365 + default: 366 + ret = -EINVAL; 367 + break; 368 + } 369 + return ret; 370 + } 371 + 372 + static int hid_gos_set_event_return(struct command_report *cmd_rep) 373 + { 374 + if (cmd_rep->data[0] != 0) 375 + return -EIO; 376 + 377 + return 0; 378 + } 379 + 380 + static int get_endpoint_address(struct hid_device *hdev) 381 + { 382 + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 383 + struct usb_host_endpoint *ep; 384 + 385 + if (intf) { 386 + ep = intf->cur_altsetting->endpoint; 387 + if (ep) 388 + return ep->desc.bEndpointAddress; 389 + } 390 + 391 + return -ENODEV; 392 + } 393 + 394 + static int hid_gos_raw_event(struct hid_device *hdev, struct hid_report *report, 395 + u8 *data, int size) 396 + { 397 + struct command_report *cmd_rep; 398 + int ep, ret; 399 + 400 + ep = get_endpoint_address(hdev); 401 + if (ep != GO_S_CFG_INTF_IN) 402 + return 0; 403 + 404 + if (size != GO_S_PACKET_SIZE) 405 + return -EINVAL; 406 + 407 + cmd_rep = (struct command_report *)data; 408 + 409 + switch (cmd_rep->cmd) { 410 + case GET_VERSION: 411 + ret = hid_gos_version_event(data); 412 + break; 413 + case GET_MCU_ID: 414 + ret = hid_gos_mcu_id_event(cmd_rep); 415 + break; 416 + case GET_GAMEPAD_CFG: 417 + ret = hid_gos_gamepad_cfg_event(cmd_rep); 418 + break; 419 + case GET_TP_PARAM: 420 + ret = hid_gos_touchpad_event(cmd_rep); 421 + break; 422 + case GET_PL_TEST: 423 + ret = hid_gos_pl_test_event(cmd_rep); 424 + break; 425 + case GET_RGB_CFG: 426 + ret = hid_gos_light_event(cmd_rep); 427 + break; 428 + case SET_GAMEPAD_CFG: 429 + case SET_RGB_CFG: 430 + case SET_TP_PARAM: 431 + ret = hid_gos_set_event_return(cmd_rep); 432 + break; 433 + default: 434 + ret = -EINVAL; 435 + break; 436 + } 437 + dev_dbg(&hdev->dev, "Rx data as raw input report: [%*ph]\n", 438 + GO_S_PACKET_SIZE, data); 439 + 440 + complete(&drvdata.send_cmd_complete); 441 + return ret; 442 + } 443 + 444 + static int mcu_property_out(struct hid_device *hdev, u8 command, u8 index, 445 + u8 *data, size_t len) 446 + { 447 + unsigned char *dmabuf __free(kfree) = NULL; 448 + u8 header[] = { command, index }; 449 + size_t header_size = ARRAY_SIZE(header); 450 + int timeout, ret; 451 + 452 + if (header_size + len > GO_S_PACKET_SIZE) 453 + return -EINVAL; 454 + 455 + guard(mutex)(&drvdata.cfg_mutex); 456 + /* We can't use a devm_alloc reusable buffer without side effects during suspend */ 457 + dmabuf = kzalloc(GO_S_PACKET_SIZE, GFP_KERNEL); 458 + if (!dmabuf) 459 + return -ENOMEM; 460 + 461 + memcpy(dmabuf, header, header_size); 462 + memcpy(dmabuf + header_size, data, len); 463 + 464 + dev_dbg(&hdev->dev, "Send data as raw output report: [%*ph]\n", 465 + GO_S_PACKET_SIZE, dmabuf); 466 + 467 + ret = hid_hw_output_report(hdev, dmabuf, GO_S_PACKET_SIZE); 468 + if (ret < 0) 469 + return ret; 470 + 471 + ret = ret == GO_S_PACKET_SIZE ? 0 : -EINVAL; 472 + if (ret) 473 + return ret; 474 + 475 + /* PL_TEST commands can take longer because they go out to another device */ 476 + timeout = (command == GET_PL_TEST) ? 200 : 5; 477 + ret = wait_for_completion_interruptible_timeout(&drvdata.send_cmd_complete, 478 + msecs_to_jiffies(timeout)); 479 + 480 + if (ret == 0) /* timeout occurred */ 481 + ret = -EBUSY; 482 + 483 + reinit_completion(&drvdata.send_cmd_complete); 484 + return 0; 485 + } 486 + 487 + static ssize_t gamepad_property_store(struct device *dev, 488 + struct device_attribute *attr, 489 + const char *buf, size_t count, 490 + enum feature_status_index index) 491 + { 492 + size_t size = 1; 493 + u8 val = 0; 494 + int ret; 495 + 496 + switch (index) { 497 + case FEATURE_GAMEPAD_MODE: 498 + ret = sysfs_match_string(gamepad_mode_text, buf); 499 + if (ret < 0) 500 + return ret; 501 + val = ret; 502 + break; 503 + case FEATURE_AUTO_SLEEP_TIME: 504 + ret = kstrtou8(buf, 10, &val); 505 + if (ret) 506 + return ret; 507 + break; 508 + case FEATURE_IMU_ENABLE: 509 + ret = sysfs_match_string(feature_enabled_text, buf); 510 + if (ret < 0) 511 + return ret; 512 + val = ret; 513 + break; 514 + case FEATURE_IMU_BYPASS: 515 + ret = sysfs_match_string(feature_enabled_text, buf); 516 + if (ret < 0) 517 + return ret; 518 + val = ret; 519 + break; 520 + case FEATURE_RGB_ENABLE: 521 + ret = sysfs_match_string(feature_enabled_text, buf); 522 + if (ret < 0) 523 + return ret; 524 + val = ret; 525 + break; 526 + case FEATURE_TOUCHPAD_ENABLE: 527 + ret = sysfs_match_string(feature_enabled_text, buf); 528 + if (ret < 0) 529 + return ret; 530 + val = ret; 531 + break; 532 + case FEATURE_OS_MODE: 533 + ret = sysfs_match_string(os_type_text, buf); 534 + if (ret < 0) 535 + return ret; 536 + val = ret; 537 + break; 538 + case FEATURE_POLL_RATE: 539 + ret = sysfs_match_string(poll_rate_text, buf); 540 + if (ret < 0) 541 + return ret; 542 + val = ret; 543 + break; 544 + case FEATURE_DPAD_MODE: 545 + ret = sysfs_match_string(dpad_mode_text, buf); 546 + if (ret < 0) 547 + return ret; 548 + val = ret; 549 + break; 550 + case FEATURE_MOUSE_WHEEL_STEP: 551 + ret = kstrtou8(buf, 10, &val); 552 + if (ret) 553 + return ret; 554 + if (val < 1 || val > 127) 555 + return -EINVAL; 556 + break; 557 + default: 558 + return -EINVAL; 559 + } 560 + 561 + if (!val) 562 + size = 0; 563 + 564 + ret = mcu_property_out(drvdata.hdev, SET_GAMEPAD_CFG, index, &val, 565 + size); 566 + if (ret < 0) 567 + return ret; 568 + 569 + return count; 570 + } 571 + 572 + static ssize_t gamepad_property_show(struct device *dev, 573 + struct device_attribute *attr, char *buf, 574 + enum feature_status_index index) 575 + { 576 + ssize_t count = 0; 577 + u8 i; 578 + 579 + count = mcu_property_out(drvdata.hdev, GET_GAMEPAD_CFG, index, NULL, 0); 580 + if (count < 0) 581 + return count; 582 + 583 + switch (index) { 584 + case FEATURE_GAMEPAD_MODE: 585 + i = drvdata.gp_mode; 586 + if (i >= ARRAY_SIZE(gamepad_mode_text)) 587 + return -EINVAL; 588 + count = sysfs_emit(buf, "%s\n", gamepad_mode_text[i]); 589 + break; 590 + case FEATURE_AUTO_SLEEP_TIME: 591 + count = sysfs_emit(buf, "%u\n", drvdata.gp_auto_sleep_time); 592 + break; 593 + case FEATURE_IMU_ENABLE: 594 + i = drvdata.imu_sensor_en; 595 + if (i >= ARRAY_SIZE(feature_enabled_text)) 596 + return -EINVAL; 597 + count = sysfs_emit(buf, "%s\n", feature_enabled_text[i]); 598 + break; 599 + case FEATURE_IMU_BYPASS: 600 + i = drvdata.imu_bypass_en; 601 + if (i >= ARRAY_SIZE(feature_enabled_text)) 602 + return -EINVAL; 603 + count = sysfs_emit(buf, "%s\n", feature_enabled_text[i]); 604 + break; 605 + case FEATURE_RGB_ENABLE: 606 + i = drvdata.rgb_en; 607 + if (i >= ARRAY_SIZE(feature_enabled_text)) 608 + return -EINVAL; 609 + count = sysfs_emit(buf, "%s\n", feature_enabled_text[i]); 610 + break; 611 + case FEATURE_TOUCHPAD_ENABLE: 612 + i = drvdata.tp_en; 613 + if (i >= ARRAY_SIZE(feature_enabled_text)) 614 + return -EINVAL; 615 + count = sysfs_emit(buf, "%s\n", feature_enabled_text[i]); 616 + break; 617 + case FEATURE_OS_MODE: 618 + i = drvdata.os_mode; 619 + if (i >= ARRAY_SIZE(os_type_text)) 620 + return -EINVAL; 621 + count = sysfs_emit(buf, "%s\n", os_type_text[i]); 622 + break; 623 + case FEATURE_POLL_RATE: 624 + i = drvdata.gp_poll_rate; 625 + if (i >= ARRAY_SIZE(poll_rate_text)) 626 + return -EINVAL; 627 + count = sysfs_emit(buf, "%s\n", poll_rate_text[i]); 628 + break; 629 + case FEATURE_DPAD_MODE: 630 + i = drvdata.gp_dpad_mode; 631 + if (i >= ARRAY_SIZE(dpad_mode_text)) 632 + return -EINVAL; 633 + count = sysfs_emit(buf, "%s\n", dpad_mode_text[i]); 634 + break; 635 + case FEATURE_MOUSE_WHEEL_STEP: 636 + i = drvdata.mouse_step; 637 + if (i < 1 || i > 127) 638 + return -EINVAL; 639 + count = sysfs_emit(buf, "%u\n", i); 640 + break; 641 + default: 642 + return -EINVAL; 643 + } 644 + 645 + return count; 646 + } 647 + 648 + static ssize_t gamepad_property_options(struct device *dev, 649 + struct device_attribute *attr, 650 + char *buf, 651 + enum feature_status_index index) 652 + { 653 + size_t count = 0; 654 + unsigned int i; 655 + 656 + switch (index) { 657 + case FEATURE_GAMEPAD_MODE: 658 + for (i = 0; i < ARRAY_SIZE(gamepad_mode_text); i++) { 659 + count += sysfs_emit_at(buf, count, "%s ", 660 + gamepad_mode_text[i]); 661 + } 662 + break; 663 + case FEATURE_AUTO_SLEEP_TIME: 664 + return sysfs_emit(buf, "0-255\n"); 665 + case FEATURE_IMU_ENABLE: 666 + for (i = 0; i < ARRAY_SIZE(feature_enabled_text); i++) { 667 + count += sysfs_emit_at(buf, count, "%s ", 668 + feature_enabled_text[i]); 669 + } 670 + break; 671 + case FEATURE_IMU_BYPASS: 672 + case FEATURE_RGB_ENABLE: 673 + case FEATURE_TOUCHPAD_ENABLE: 674 + for (i = 0; i < ARRAY_SIZE(feature_enabled_text); i++) { 675 + count += sysfs_emit_at(buf, count, "%s ", 676 + feature_enabled_text[i]); 677 + } 678 + break; 679 + case FEATURE_OS_MODE: 680 + for (i = 0; i < ARRAY_SIZE(os_type_text); i++) { 681 + count += sysfs_emit_at(buf, count, "%s ", 682 + os_type_text[i]); 683 + } 684 + break; 685 + case FEATURE_POLL_RATE: 686 + for (i = 0; i < ARRAY_SIZE(poll_rate_text); i++) { 687 + count += sysfs_emit_at(buf, count, "%s ", 688 + poll_rate_text[i]); 689 + } 690 + break; 691 + case FEATURE_DPAD_MODE: 692 + for (i = 0; i < ARRAY_SIZE(dpad_mode_text); i++) { 693 + count += sysfs_emit_at(buf, count, "%s ", 694 + dpad_mode_text[i]); 695 + } 696 + break; 697 + case FEATURE_MOUSE_WHEEL_STEP: 698 + return sysfs_emit(buf, "1-127\n"); 699 + default: 700 + return count; 701 + } 702 + 703 + if (count) 704 + buf[count - 1] = '\n'; 705 + 706 + return count; 707 + } 708 + 709 + static ssize_t touchpad_property_store(struct device *dev, 710 + struct device_attribute *attr, 711 + const char *buf, size_t count, 712 + enum touchpad_config_index index) 713 + { 714 + size_t size = 1; 715 + u8 val = 0; 716 + int ret; 717 + 718 + switch (index) { 719 + case CFG_WINDOWS_MODE: 720 + ret = sysfs_match_string(touchpad_mode_text, buf); 721 + if (ret < 0) 722 + return ret; 723 + val = ret; 724 + break; 725 + case CFG_LINUX_MODE: 726 + ret = sysfs_match_string(touchpad_mode_text, buf); 727 + if (ret < 0) 728 + return ret; 729 + val = ret; 730 + break; 731 + default: 732 + return -EINVAL; 733 + } 734 + if (!val) 735 + size = 0; 736 + 737 + ret = mcu_property_out(drvdata.hdev, SET_TP_PARAM, index, &val, size); 738 + if (ret < 0) 739 + return ret; 740 + 741 + return count; 742 + } 743 + 744 + static ssize_t touchpad_property_show(struct device *dev, 745 + struct device_attribute *attr, char *buf, 746 + enum touchpad_config_index index) 747 + { 748 + int ret = 0; 749 + u8 i; 750 + 751 + ret = mcu_property_out(drvdata.hdev, GET_TP_PARAM, index, NULL, 0); 752 + if (ret < 0) 753 + return ret; 754 + 755 + switch (index) { 756 + case CFG_WINDOWS_MODE: 757 + i = drvdata.tp_windows_mode; 758 + break; 759 + case CFG_LINUX_MODE: 760 + i = drvdata.tp_linux_mode; 761 + break; 762 + default: 763 + return -EINVAL; 764 + } 765 + 766 + if (i >= ARRAY_SIZE(touchpad_mode_text)) 767 + return -EINVAL; 768 + 769 + return sysfs_emit(buf, "%s\n", touchpad_mode_text[i]); 770 + } 771 + 772 + static ssize_t touchpad_property_options(struct device *dev, 773 + struct device_attribute *attr, 774 + char *buf, 775 + enum touchpad_config_index index) 776 + { 777 + size_t count = 0; 778 + unsigned int i; 779 + 780 + switch (index) { 781 + case CFG_WINDOWS_MODE: 782 + case CFG_LINUX_MODE: 783 + for (i = 0; i < ARRAY_SIZE(touchpad_mode_text); i++) { 784 + count += sysfs_emit_at(buf, count, "%s ", 785 + touchpad_mode_text[i]); 786 + } 787 + break; 788 + default: 789 + return count; 790 + } 791 + 792 + if (count) 793 + buf[count - 1] = '\n'; 794 + 795 + return count; 796 + } 797 + 798 + static ssize_t test_property_show(struct device *dev, 799 + struct device_attribute *attr, char *buf, 800 + enum test_command_index index) 801 + { 802 + size_t count = 0; 803 + u8 i; 804 + 805 + switch (index) { 806 + case TEST_TP_MFR: 807 + i = drvdata.tp_manufacturer; 808 + if (i >= ARRAY_SIZE(touchpad_manufacturer_text)) 809 + return -EINVAL; 810 + count = sysfs_emit(buf, "%s\n", touchpad_manufacturer_text[i]); 811 + break; 812 + case TEST_IMU_MFR: 813 + i = drvdata.imu_manufacturer; 814 + if (i >= ARRAY_SIZE(imu_manufacturer_text)) 815 + return -EINVAL; 816 + count = sysfs_emit(buf, "%s\n", imu_manufacturer_text[i]); 817 + break; 818 + case TEST_TP_VER: 819 + count = sysfs_emit(buf, "%u\n", drvdata.tp_version); 820 + break; 821 + default: 822 + count = -EINVAL; 823 + break; 824 + } 825 + 826 + return count; 827 + } 828 + 829 + static ssize_t mcu_id_show(struct device *dev, struct device_attribute *attr, 830 + char *buf) 831 + { 832 + return sysfs_emit(buf, "%*phN\n", 12, &drvdata.mcu_id); 833 + } 834 + 835 + static int rgb_cfg_call(struct hid_device *hdev, enum mcu_command_index cmd, 836 + enum rgb_config_index index, u8 *val, size_t size) 837 + { 838 + if (cmd != SET_RGB_CFG && cmd != GET_RGB_CFG) 839 + return -EINVAL; 840 + 841 + if (index < LIGHT_MODE_SEL || index > USR_LIGHT_PROFILE_3) 842 + return -EINVAL; 843 + 844 + return mcu_property_out(hdev, cmd, index, val, size); 845 + } 846 + 847 + static int rgb_attr_show(void) 848 + { 849 + enum rgb_config_index index; 850 + 851 + index = drvdata.rgb_profile + 2; 852 + 853 + return rgb_cfg_call(drvdata.hdev, GET_RGB_CFG, index, NULL, 0); 854 + }; 855 + 856 + static ssize_t rgb_effect_store(struct device *dev, 857 + struct device_attribute *attr, const char *buf, 858 + size_t count) 859 + { 860 + struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(drvdata.led_cdev); 861 + enum rgb_config_index index; 862 + u8 effect; 863 + int ret; 864 + 865 + ret = sysfs_match_string(rgb_effect_text, buf); 866 + if (ret < 0) 867 + return ret; 868 + 869 + effect = ret; 870 + index = drvdata.rgb_profile + 2; 871 + u8 rgb_profile[6] = { effect, 872 + mc_cdev->subled_info[0].intensity, 873 + mc_cdev->subled_info[1].intensity, 874 + mc_cdev->subled_info[2].intensity, 875 + drvdata.led_cdev->brightness, 876 + drvdata.rgb_speed }; 877 + 878 + ret = rgb_cfg_call(drvdata.hdev, SET_RGB_CFG, index, rgb_profile, 6); 879 + if (ret) 880 + return ret; 881 + 882 + drvdata.rgb_effect = effect; 883 + return count; 884 + }; 885 + 886 + static ssize_t rgb_effect_show(struct device *dev, 887 + struct device_attribute *attr, char *buf) 888 + { 889 + int ret; 890 + 891 + ret = rgb_attr_show(); 892 + if (ret) 893 + return ret; 894 + 895 + if (drvdata.rgb_effect >= ARRAY_SIZE(rgb_effect_text)) 896 + return -EINVAL; 897 + 898 + return sysfs_emit(buf, "%s\n", rgb_effect_text[drvdata.rgb_effect]); 899 + } 900 + 901 + static ssize_t rgb_effect_index_show(struct device *dev, 902 + struct device_attribute *attr, char *buf) 903 + { 904 + ssize_t count = 0; 905 + unsigned int i; 906 + 907 + for (i = 0; i < ARRAY_SIZE(rgb_effect_text); i++) 908 + count += sysfs_emit_at(buf, count, "%s ", rgb_effect_text[i]); 909 + 910 + if (count) 911 + buf[count - 1] = '\n'; 912 + 913 + return count; 914 + } 915 + 916 + static ssize_t rgb_speed_store(struct device *dev, 917 + struct device_attribute *attr, const char *buf, 918 + size_t count) 919 + { 920 + struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(drvdata.led_cdev); 921 + enum rgb_config_index index; 922 + int val = 0; 923 + int ret; 924 + 925 + ret = kstrtoint(buf, 10, &val); 926 + if (ret) 927 + return ret; 928 + 929 + if (val < 0 || val > 100) 930 + return -EINVAL; 931 + 932 + index = drvdata.rgb_profile + 2; 933 + u8 rgb_profile[6] = { drvdata.rgb_effect, 934 + mc_cdev->subled_info[0].intensity, 935 + mc_cdev->subled_info[1].intensity, 936 + mc_cdev->subled_info[2].intensity, 937 + drvdata.led_cdev->brightness, 938 + val }; 939 + 940 + ret = rgb_cfg_call(drvdata.hdev, SET_RGB_CFG, index, rgb_profile, 6); 941 + if (ret) 942 + return ret; 943 + 944 + drvdata.rgb_speed = val; 945 + 946 + return count; 947 + }; 948 + 949 + static ssize_t rgb_speed_show(struct device *dev, struct device_attribute *attr, 950 + char *buf) 951 + { 952 + int ret; 953 + 954 + ret = rgb_attr_show(); 955 + if (ret) 956 + return ret; 957 + 958 + if (drvdata.rgb_speed > 100) 959 + return -EINVAL; 960 + 961 + return sysfs_emit(buf, "%hhu\n", drvdata.rgb_speed); 962 + } 963 + 964 + static ssize_t rgb_speed_range_show(struct device *dev, 965 + struct device_attribute *attr, char *buf) 966 + { 967 + return sysfs_emit(buf, "0-100\n"); 968 + } 969 + 970 + static ssize_t rgb_mode_store(struct device *dev, struct device_attribute *attr, 971 + const char *buf, size_t count) 972 + { 973 + int ret; 974 + u8 val; 975 + 976 + ret = sysfs_match_string(rgb_mode_text, buf); 977 + if (ret <= 0) 978 + return ret; 979 + 980 + val = ret; 981 + 982 + ret = rgb_cfg_call(drvdata.hdev, SET_RGB_CFG, LIGHT_MODE_SEL, &val, 983 + 1); 984 + if (ret) 985 + return ret; 986 + 987 + drvdata.rgb_mode = val; 988 + 989 + return count; 990 + }; 991 + 992 + static ssize_t rgb_mode_show(struct device *dev, struct device_attribute *attr, 993 + char *buf) 994 + { 995 + int ret; 996 + 997 + ret = rgb_cfg_call(drvdata.hdev, GET_RGB_CFG, LIGHT_MODE_SEL, NULL, 0); 998 + if (ret) 999 + return ret; 1000 + 1001 + if (drvdata.rgb_mode >= ARRAY_SIZE(rgb_mode_text)) 1002 + return -EINVAL; 1003 + 1004 + return sysfs_emit(buf, "%s\n", rgb_mode_text[drvdata.rgb_mode]); 1005 + }; 1006 + 1007 + static ssize_t rgb_mode_index_show(struct device *dev, 1008 + struct device_attribute *attr, char *buf) 1009 + { 1010 + ssize_t count = 0; 1011 + unsigned int i; 1012 + 1013 + for (i = 1; i < ARRAY_SIZE(rgb_mode_text); i++) 1014 + count += sysfs_emit_at(buf, count, "%s ", rgb_mode_text[i]); 1015 + 1016 + if (count) 1017 + buf[count - 1] = '\n'; 1018 + 1019 + return count; 1020 + } 1021 + 1022 + static ssize_t rgb_profile_store(struct device *dev, 1023 + struct device_attribute *attr, const char *buf, 1024 + size_t count) 1025 + { 1026 + size_t size = 1; 1027 + int ret; 1028 + u8 val; 1029 + 1030 + ret = kstrtou8(buf, 10, &val); 1031 + if (ret < 0) 1032 + return ret; 1033 + 1034 + if (val < 1 || val > 3) 1035 + return -EINVAL; 1036 + 1037 + ret = rgb_cfg_call(drvdata.hdev, SET_RGB_CFG, LIGHT_PROFILE_SEL, &val, size); 1038 + if (ret) 1039 + return ret; 1040 + 1041 + drvdata.rgb_profile = val; 1042 + 1043 + return count; 1044 + }; 1045 + 1046 + static ssize_t rgb_profile_show(struct device *dev, 1047 + struct device_attribute *attr, char *buf) 1048 + { 1049 + int ret; 1050 + 1051 + ret = rgb_cfg_call(drvdata.hdev, GET_RGB_CFG, LIGHT_PROFILE_SEL, NULL, 0); 1052 + if (ret) 1053 + return ret; 1054 + 1055 + if (drvdata.rgb_profile < 1 || drvdata.rgb_profile > 3) 1056 + return -EINVAL; 1057 + 1058 + return sysfs_emit(buf, "%hhu\n", drvdata.rgb_profile); 1059 + }; 1060 + 1061 + static ssize_t rgb_profile_range_show(struct device *dev, 1062 + struct device_attribute *attr, char *buf) 1063 + { 1064 + return sysfs_emit(buf, "1-3\n"); 1065 + } 1066 + 1067 + static void hid_gos_brightness_set(struct led_classdev *led_cdev, 1068 + enum led_brightness brightness) 1069 + { 1070 + struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(drvdata.led_cdev); 1071 + enum rgb_config_index index; 1072 + int ret; 1073 + 1074 + if (brightness > led_cdev->max_brightness) { 1075 + dev_err(led_cdev->dev, "Invalid argument\n"); 1076 + return; 1077 + } 1078 + 1079 + index = drvdata.rgb_profile + 2; 1080 + u8 rgb_profile[6] = { drvdata.rgb_effect, 1081 + mc_cdev->subled_info[0].intensity, 1082 + mc_cdev->subled_info[1].intensity, 1083 + mc_cdev->subled_info[2].intensity, 1084 + brightness, 1085 + drvdata.rgb_speed }; 1086 + 1087 + ret = rgb_cfg_call(drvdata.hdev, SET_RGB_CFG, index, rgb_profile, 6); 1088 + switch (ret) { 1089 + case 0: 1090 + led_cdev->brightness = brightness; 1091 + break; 1092 + case -ENODEV: /* during switch to IAP -ENODEV is expected */ 1093 + case -ENOSYS: /* during rmmod -ENOSYS is expected */ 1094 + dev_dbg(led_cdev->dev, "Failed to write RGB profile: %i\n", 1095 + ret); 1096 + break; 1097 + default: 1098 + dev_err(led_cdev->dev, "Failed to write RGB profile: %i\n", 1099 + ret); 1100 + } 1101 + } 1102 + 1103 + #define LEGOS_DEVICE_ATTR_RW(_name, _attrname, _rtype, _group) \ 1104 + static ssize_t _name##_store(struct device *dev, \ 1105 + struct device_attribute *attr, \ 1106 + const char *buf, size_t count) \ 1107 + { \ 1108 + return _group##_property_store(dev, attr, buf, count, \ 1109 + _name.index); \ 1110 + } \ 1111 + static ssize_t _name##_show(struct device *dev, \ 1112 + struct device_attribute *attr, char *buf) \ 1113 + { \ 1114 + return _group##_property_show(dev, attr, buf, _name.index); \ 1115 + } \ 1116 + static ssize_t _name##_##_rtype##_show( \ 1117 + struct device *dev, struct device_attribute *attr, char *buf) \ 1118 + { \ 1119 + return _group##_property_options(dev, attr, buf, _name.index); \ 1120 + } \ 1121 + static DEVICE_ATTR_RW_NAMED(_name, _attrname) 1122 + 1123 + #define LEGOS_DEVICE_ATTR_RO(_name, _attrname, _group) \ 1124 + static ssize_t _name##_show(struct device *dev, \ 1125 + struct device_attribute *attr, char *buf) \ 1126 + { \ 1127 + return _group##_property_show(dev, attr, buf, _name.index); \ 1128 + } \ 1129 + static DEVICE_ATTR_RO_NAMED(_name, _attrname) 1130 + 1131 + /* Gamepad */ 1132 + static struct gos_cfg_attr auto_sleep_time = { FEATURE_AUTO_SLEEP_TIME }; 1133 + LEGOS_DEVICE_ATTR_RW(auto_sleep_time, "auto_sleep_time", range, gamepad); 1134 + static DEVICE_ATTR_RO(auto_sleep_time_range); 1135 + 1136 + static struct gos_cfg_attr dpad_mode = { FEATURE_DPAD_MODE }; 1137 + LEGOS_DEVICE_ATTR_RW(dpad_mode, "dpad_mode", index, gamepad); 1138 + static DEVICE_ATTR_RO(dpad_mode_index); 1139 + 1140 + static struct gos_cfg_attr gamepad_mode = { FEATURE_GAMEPAD_MODE }; 1141 + LEGOS_DEVICE_ATTR_RW(gamepad_mode, "mode", index, gamepad); 1142 + static DEVICE_ATTR_RO_NAMED(gamepad_mode_index, "mode_index"); 1143 + 1144 + static struct gos_cfg_attr gamepad_poll_rate = { FEATURE_POLL_RATE }; 1145 + LEGOS_DEVICE_ATTR_RW(gamepad_poll_rate, "poll_rate", index, gamepad); 1146 + static DEVICE_ATTR_RO_NAMED(gamepad_poll_rate_index, "poll_rate_index"); 1147 + 1148 + static struct attribute *legos_gamepad_attrs[] = { 1149 + &dev_attr_auto_sleep_time.attr, 1150 + &dev_attr_auto_sleep_time_range.attr, 1151 + &dev_attr_dpad_mode.attr, 1152 + &dev_attr_dpad_mode_index.attr, 1153 + &dev_attr_gamepad_mode.attr, 1154 + &dev_attr_gamepad_mode_index.attr, 1155 + &dev_attr_gamepad_poll_rate.attr, 1156 + &dev_attr_gamepad_poll_rate_index.attr, 1157 + NULL, 1158 + }; 1159 + 1160 + static const struct attribute_group gamepad_attr_group = { 1161 + .name = "gamepad", 1162 + .attrs = legos_gamepad_attrs, 1163 + }; 1164 + 1165 + /* IMU */ 1166 + static struct gos_cfg_attr imu_bypass_enabled = { FEATURE_IMU_BYPASS }; 1167 + LEGOS_DEVICE_ATTR_RW(imu_bypass_enabled, "bypass_enabled", index, gamepad); 1168 + static DEVICE_ATTR_RO_NAMED(imu_bypass_enabled_index, "bypass_enabled_index"); 1169 + 1170 + static struct gos_cfg_attr imu_manufacturer = { TEST_IMU_MFR }; 1171 + LEGOS_DEVICE_ATTR_RO(imu_manufacturer, "manufacturer", test); 1172 + 1173 + static struct gos_cfg_attr imu_sensor_enabled = { FEATURE_IMU_ENABLE }; 1174 + LEGOS_DEVICE_ATTR_RW(imu_sensor_enabled, "sensor_enabled", index, gamepad); 1175 + static DEVICE_ATTR_RO_NAMED(imu_sensor_enabled_index, "sensor_enabled_index"); 1176 + 1177 + static struct attribute *legos_imu_attrs[] = { 1178 + &dev_attr_imu_bypass_enabled.attr, 1179 + &dev_attr_imu_bypass_enabled_index.attr, 1180 + &dev_attr_imu_manufacturer.attr, 1181 + &dev_attr_imu_sensor_enabled.attr, 1182 + &dev_attr_imu_sensor_enabled_index.attr, 1183 + NULL, 1184 + }; 1185 + 1186 + static const struct attribute_group imu_attr_group = { 1187 + .name = "imu", 1188 + .attrs = legos_imu_attrs, 1189 + }; 1190 + 1191 + /* MCU */ 1192 + static DEVICE_ATTR_RO(mcu_id); 1193 + 1194 + static struct gos_cfg_attr os_mode = { FEATURE_OS_MODE }; 1195 + LEGOS_DEVICE_ATTR_RW(os_mode, "os_mode", index, gamepad); 1196 + static DEVICE_ATTR_RO(os_mode_index); 1197 + 1198 + static struct attribute *legos_mcu_attrs[] = { 1199 + &dev_attr_mcu_id.attr, 1200 + &dev_attr_os_mode.attr, 1201 + &dev_attr_os_mode_index.attr, 1202 + NULL, 1203 + }; 1204 + 1205 + static const struct attribute_group mcu_attr_group = { 1206 + .attrs = legos_mcu_attrs, 1207 + }; 1208 + 1209 + /* Mouse */ 1210 + static struct gos_cfg_attr mouse_wheel_step = { FEATURE_MOUSE_WHEEL_STEP }; 1211 + LEGOS_DEVICE_ATTR_RW(mouse_wheel_step, "step", range, gamepad); 1212 + static DEVICE_ATTR_RO_NAMED(mouse_wheel_step_range, "step_range"); 1213 + 1214 + static struct attribute *legos_mouse_attrs[] = { 1215 + &dev_attr_mouse_wheel_step.attr, 1216 + &dev_attr_mouse_wheel_step_range.attr, 1217 + NULL, 1218 + }; 1219 + 1220 + static const struct attribute_group mouse_attr_group = { 1221 + .name = "mouse", 1222 + .attrs = legos_mouse_attrs, 1223 + }; 1224 + 1225 + /* Touchpad */ 1226 + static struct gos_cfg_attr touchpad_enabled = { FEATURE_TOUCHPAD_ENABLE }; 1227 + LEGOS_DEVICE_ATTR_RW(touchpad_enabled, "enabled", index, gamepad); 1228 + static DEVICE_ATTR_RO_NAMED(touchpad_enabled_index, "enabled_index"); 1229 + 1230 + static struct gos_cfg_attr touchpad_linux_mode = { CFG_LINUX_MODE }; 1231 + LEGOS_DEVICE_ATTR_RW(touchpad_linux_mode, "linux_mode", index, touchpad); 1232 + static DEVICE_ATTR_RO_NAMED(touchpad_linux_mode_index, "linux_mode_index"); 1233 + 1234 + static struct gos_cfg_attr touchpad_manufacturer = { TEST_TP_MFR }; 1235 + LEGOS_DEVICE_ATTR_RO(touchpad_manufacturer, "manufacturer", test); 1236 + 1237 + static struct gos_cfg_attr touchpad_version = { TEST_TP_VER }; 1238 + LEGOS_DEVICE_ATTR_RO(touchpad_version, "version", test); 1239 + 1240 + static struct gos_cfg_attr touchpad_windows_mode = { CFG_WINDOWS_MODE }; 1241 + LEGOS_DEVICE_ATTR_RW(touchpad_windows_mode, "windows_mode", index, touchpad); 1242 + static DEVICE_ATTR_RO_NAMED(touchpad_windows_mode_index, "windows_mode_index"); 1243 + 1244 + static struct attribute *legos_touchpad_attrs[] = { 1245 + &dev_attr_touchpad_enabled.attr, 1246 + &dev_attr_touchpad_enabled_index.attr, 1247 + &dev_attr_touchpad_linux_mode.attr, 1248 + &dev_attr_touchpad_linux_mode_index.attr, 1249 + &dev_attr_touchpad_manufacturer.attr, 1250 + &dev_attr_touchpad_version.attr, 1251 + &dev_attr_touchpad_windows_mode.attr, 1252 + &dev_attr_touchpad_windows_mode_index.attr, 1253 + NULL, 1254 + }; 1255 + 1256 + static const struct attribute_group touchpad_attr_group = { 1257 + .name = "touchpad", 1258 + .attrs = legos_touchpad_attrs, 1259 + }; 1260 + 1261 + static const struct attribute_group *top_level_attr_groups[] = { 1262 + &gamepad_attr_group, 1263 + &imu_attr_group, 1264 + &mcu_attr_group, 1265 + &mouse_attr_group, 1266 + &touchpad_attr_group, 1267 + NULL, 1268 + }; 1269 + 1270 + /* RGB */ 1271 + static struct gos_cfg_attr rgb_enabled = { FEATURE_RGB_ENABLE }; 1272 + LEGOS_DEVICE_ATTR_RW(rgb_enabled, "enabled", index, gamepad); 1273 + static DEVICE_ATTR_RO_NAMED(rgb_enabled_index, "enabled_index"); 1274 + 1275 + static DEVICE_ATTR_RW_NAMED(rgb_effect, "effect"); 1276 + static DEVICE_ATTR_RO_NAMED(rgb_effect_index, "effect_index"); 1277 + static DEVICE_ATTR_RW_NAMED(rgb_mode, "mode"); 1278 + static DEVICE_ATTR_RO_NAMED(rgb_mode_index, "mode_index"); 1279 + static DEVICE_ATTR_RW_NAMED(rgb_profile, "profile"); 1280 + static DEVICE_ATTR_RO_NAMED(rgb_profile_range, "profile_range"); 1281 + static DEVICE_ATTR_RW_NAMED(rgb_speed, "speed"); 1282 + static DEVICE_ATTR_RO_NAMED(rgb_speed_range, "speed_range"); 1283 + 1284 + static struct attribute *gos_rgb_attrs[] = { 1285 + &dev_attr_rgb_enabled.attr, 1286 + &dev_attr_rgb_enabled_index.attr, 1287 + &dev_attr_rgb_effect.attr, 1288 + &dev_attr_rgb_effect_index.attr, 1289 + &dev_attr_rgb_mode.attr, 1290 + &dev_attr_rgb_mode_index.attr, 1291 + &dev_attr_rgb_profile.attr, 1292 + &dev_attr_rgb_profile_range.attr, 1293 + &dev_attr_rgb_speed.attr, 1294 + &dev_attr_rgb_speed_range.attr, 1295 + NULL, 1296 + }; 1297 + 1298 + static struct attribute_group rgb_attr_group = { 1299 + .attrs = gos_rgb_attrs, 1300 + }; 1301 + 1302 + static struct mc_subled gos_rgb_subled_info[] = { 1303 + { 1304 + .color_index = LED_COLOR_ID_RED, 1305 + .brightness = 0x50, 1306 + .intensity = 0x24, 1307 + .channel = 0x1, 1308 + }, 1309 + { 1310 + .color_index = LED_COLOR_ID_GREEN, 1311 + .brightness = 0x50, 1312 + .intensity = 0x22, 1313 + .channel = 0x2, 1314 + }, 1315 + { 1316 + .color_index = LED_COLOR_ID_BLUE, 1317 + .brightness = 0x50, 1318 + .intensity = 0x99, 1319 + .channel = 0x3, 1320 + }, 1321 + }; 1322 + 1323 + static struct led_classdev_mc gos_cdev_rgb = { 1324 + .led_cdev = { 1325 + .name = "go_s:rgb:joystick_rings", 1326 + .brightness = 0x50, 1327 + .max_brightness = 0x64, 1328 + .brightness_set = hid_gos_brightness_set, 1329 + }, 1330 + .num_colors = ARRAY_SIZE(gos_rgb_subled_info), 1331 + .subled_info = gos_rgb_subled_info, 1332 + }; 1333 + 1334 + static void cfg_setup(struct work_struct *work) 1335 + { 1336 + int ret; 1337 + 1338 + /* MCU */ 1339 + ret = mcu_property_out(drvdata.hdev, GET_MCU_ID, FEATURE_NONE, NULL, 0); 1340 + if (ret) { 1341 + dev_err(&drvdata.hdev->dev, "Failed to retrieve MCU ID: %i\n", 1342 + ret); 1343 + return; 1344 + } 1345 + 1346 + ret = mcu_property_out(drvdata.hdev, GET_VERSION, FEATURE_NONE, NULL, 0); 1347 + if (ret) { 1348 + dev_err(&drvdata.hdev->dev, "Failed to retrieve MCU Version: %i\n", ret); 1349 + return; 1350 + } 1351 + 1352 + ret = mcu_property_out(drvdata.hdev, GET_PL_TEST, TEST_TP_MFR, NULL, 0); 1353 + if (ret) { 1354 + dev_err(&drvdata.hdev->dev, 1355 + "Failed to retrieve Touchpad Manufacturer: %i\n", ret); 1356 + return; 1357 + } 1358 + 1359 + ret = mcu_property_out(drvdata.hdev, GET_PL_TEST, TEST_TP_VER, NULL, 0); 1360 + if (ret) { 1361 + dev_err(&drvdata.hdev->dev, 1362 + "Failed to retrieve Touchpad Firmware Version: %i\n", ret); 1363 + return; 1364 + } 1365 + 1366 + ret = mcu_property_out(drvdata.hdev, GET_PL_TEST, TEST_IMU_MFR, NULL, 0); 1367 + if (ret) { 1368 + dev_err(&drvdata.hdev->dev, 1369 + "Failed to retrieve IMU Manufacturer: %i\n", ret); 1370 + return; 1371 + } 1372 + } 1373 + 1374 + static int hid_gos_cfg_probe(struct hid_device *hdev, 1375 + const struct hid_device_id *_id) 1376 + { 1377 + int ret; 1378 + 1379 + hid_set_drvdata(hdev, &drvdata); 1380 + drvdata.hdev = hdev; 1381 + mutex_init(&drvdata.cfg_mutex); 1382 + 1383 + ret = sysfs_create_groups(&hdev->dev.kobj, top_level_attr_groups); 1384 + if (ret) { 1385 + dev_err_probe(&hdev->dev, ret, 1386 + "Failed to create gamepad configuration attributes\n"); 1387 + return ret; 1388 + } 1389 + 1390 + ret = devm_led_classdev_multicolor_register(&hdev->dev, &gos_cdev_rgb); 1391 + if (ret) { 1392 + dev_err_probe(&hdev->dev, ret, "Failed to create RGB device\n"); 1393 + return ret; 1394 + } 1395 + 1396 + ret = devm_device_add_group(gos_cdev_rgb.led_cdev.dev, &rgb_attr_group); 1397 + if (ret) { 1398 + dev_err_probe(&hdev->dev, ret, 1399 + "Failed to create RGB configuration attributes\n"); 1400 + return ret; 1401 + } 1402 + 1403 + drvdata.led_cdev = &gos_cdev_rgb.led_cdev; 1404 + 1405 + init_completion(&drvdata.send_cmd_complete); 1406 + 1407 + /* Executing calls prior to returning from probe will lock the MCU. Schedule 1408 + * initial data call after probe has completed and MCU can accept calls. 1409 + */ 1410 + INIT_DELAYED_WORK(&drvdata.gos_cfg_setup, &cfg_setup); 1411 + ret = schedule_delayed_work(&drvdata.gos_cfg_setup, msecs_to_jiffies(2)); 1412 + if (!ret) { 1413 + dev_err(&hdev->dev, "Failed to schedule startup delayed work\n"); 1414 + return -ENODEV; 1415 + } 1416 + 1417 + return 0; 1418 + } 1419 + 1420 + static void hid_gos_cfg_remove(struct hid_device *hdev) 1421 + { 1422 + guard(mutex)(&drvdata.cfg_mutex); 1423 + cancel_delayed_work_sync(&drvdata.gos_cfg_setup); 1424 + sysfs_remove_groups(&hdev->dev.kobj, top_level_attr_groups); 1425 + hid_hw_close(hdev); 1426 + hid_hw_stop(hdev); 1427 + hid_set_drvdata(hdev, NULL); 1428 + } 1429 + 1430 + static int hid_gos_probe(struct hid_device *hdev, 1431 + const struct hid_device_id *id) 1432 + { 1433 + int ret, ep; 1434 + 1435 + ret = hid_parse(hdev); 1436 + if (ret) { 1437 + hid_err(hdev, "Parse failed\n"); 1438 + return ret; 1439 + } 1440 + 1441 + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); 1442 + if (ret) { 1443 + hid_err(hdev, "Failed to start HID device\n"); 1444 + return ret; 1445 + } 1446 + 1447 + ret = hid_hw_open(hdev); 1448 + if (ret) { 1449 + hid_err(hdev, "Failed to open HID device\n"); 1450 + hid_hw_stop(hdev); 1451 + return ret; 1452 + } 1453 + 1454 + ep = get_endpoint_address(hdev); 1455 + if (ep != GO_S_CFG_INTF_IN) { 1456 + dev_dbg(&hdev->dev, "Started interface %x as generic HID device.\n", ep); 1457 + return 0; 1458 + } 1459 + 1460 + ret = hid_gos_cfg_probe(hdev, id); 1461 + if (ret) 1462 + dev_err_probe(&hdev->dev, ret, "Failed to start configuration interface"); 1463 + 1464 + dev_dbg(&hdev->dev, "Started interface %x as Go S configuration interface\n", ep); 1465 + return ret; 1466 + } 1467 + 1468 + static void hid_gos_remove(struct hid_device *hdev) 1469 + { 1470 + int ep = get_endpoint_address(hdev); 1471 + 1472 + switch (ep) { 1473 + case GO_S_CFG_INTF_IN: 1474 + hid_gos_cfg_remove(hdev); 1475 + break; 1476 + default: 1477 + hid_hw_close(hdev); 1478 + hid_hw_stop(hdev); 1479 + 1480 + break; 1481 + } 1482 + } 1483 + 1484 + static const struct hid_device_id hid_gos_devices[] = { 1485 + { HID_USB_DEVICE(USB_VENDOR_ID_QHE, 1486 + USB_DEVICE_ID_LENOVO_LEGION_GO_S_XINPUT) }, 1487 + { HID_USB_DEVICE(USB_VENDOR_ID_QHE, 1488 + USB_DEVICE_ID_LENOVO_LEGION_GO_S_DINPUT) }, 1489 + {} 1490 + }; 1491 + 1492 + MODULE_DEVICE_TABLE(hid, hid_gos_devices); 1493 + static struct hid_driver hid_lenovo_go_s = { 1494 + .name = "hid-lenovo-go-s", 1495 + .id_table = hid_gos_devices, 1496 + .probe = hid_gos_probe, 1497 + .remove = hid_gos_remove, 1498 + .raw_event = hid_gos_raw_event, 1499 + }; 1500 + module_hid_driver(hid_lenovo_go_s); 1501 + 1502 + MODULE_AUTHOR("Derek J. Clark"); 1503 + MODULE_DESCRIPTION("HID Driver for Lenovo Legion Go S Series gamepad."); 1504 + MODULE_LICENSE("GPL");
+2500
drivers/hid/hid-lenovo-go.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * HID driver for Lenovo Legion Go series gamepads. 4 + * 5 + * Copyright (c) 2026 Derek J. Clark <derekjohn.clark@gmail.com> 6 + * Copyright (c) 2026 Valve Corporation 7 + */ 8 + 9 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10 + 11 + #include <linux/array_size.h> 12 + #include <linux/cleanup.h> 13 + #include <linux/completion.h> 14 + #include <linux/delay.h> 15 + #include <linux/dev_printk.h> 16 + #include <linux/device.h> 17 + #include <linux/device/devres.h> 18 + #include <linux/hid.h> 19 + #include <linux/jiffies.h> 20 + #include <linux/kstrtox.h> 21 + #include <linux/led-class-multicolor.h> 22 + #include <linux/mutex.h> 23 + #include <linux/printk.h> 24 + #include <linux/sysfs.h> 25 + #include <linux/types.h> 26 + #include <linux/unaligned.h> 27 + #include <linux/usb.h> 28 + #include <linux/workqueue.h> 29 + #include <linux/workqueue_types.h> 30 + 31 + #include "hid-ids.h" 32 + 33 + #define GO_GP_INTF_IN 0x83 34 + #define GO_OUTPUT_REPORT_ID 0x05 35 + #define GO_GP_RESET_SUCCESS 0x01 36 + #define GO_PACKET_SIZE 64 37 + 38 + static struct hid_go_cfg { 39 + struct delayed_work go_cfg_setup; 40 + struct completion send_cmd_complete; 41 + struct led_classdev *led_cdev; 42 + struct hid_device *hdev; 43 + struct mutex cfg_mutex; /*ensure single synchronous output report*/ 44 + u8 fps_mode; 45 + u8 gp_left_auto_sleep_time; 46 + u8 gp_left_gyro_cal_status; 47 + u8 gp_left_joy_cal_status; 48 + u8 gp_left_notify_en; 49 + u8 gp_left_rumble_mode; 50 + u8 gp_left_trigg_cal_status; 51 + u32 gp_left_version_firmware; 52 + u8 gp_left_version_gen; 53 + u32 gp_left_version_hardware; 54 + u32 gp_left_version_product; 55 + u32 gp_left_version_protocol; 56 + u8 gp_mode; 57 + u8 gp_right_auto_sleep_time; 58 + u8 gp_right_gyro_cal_status; 59 + u8 gp_right_joy_cal_status; 60 + u8 gp_right_notify_en; 61 + u8 gp_right_rumble_mode; 62 + u8 gp_right_trigg_cal_status; 63 + u32 gp_right_version_firmware; 64 + u8 gp_right_version_gen; 65 + u32 gp_right_version_hardware; 66 + u32 gp_right_version_product; 67 + u32 gp_right_version_protocol; 68 + u8 gp_rumble_intensity; 69 + u8 imu_left_bypass_en; 70 + u8 imu_left_sensor_en; 71 + u8 imu_right_bypass_en; 72 + u8 imu_right_sensor_en; 73 + u32 mcu_version_firmware; 74 + u8 mcu_version_gen; 75 + u32 mcu_version_hardware; 76 + u32 mcu_version_product; 77 + u32 mcu_version_protocol; 78 + u32 mouse_dpi; 79 + u8 os_mode; 80 + u8 rgb_effect; 81 + u8 rgb_en; 82 + u8 rgb_mode; 83 + u8 rgb_profile; 84 + u8 rgb_speed; 85 + u8 tp_en; 86 + u8 tp_vibration_en; 87 + u8 tp_vibration_intensity; 88 + u32 tx_dongle_version_firmware; 89 + u8 tx_dongle_version_gen; 90 + u32 tx_dongle_version_hardware; 91 + u32 tx_dongle_version_product; 92 + u32 tx_dongle_version_protocol; 93 + } drvdata; 94 + 95 + struct go_cfg_attr { 96 + u8 index; 97 + }; 98 + 99 + struct command_report { 100 + u8 report_id; 101 + u8 id; 102 + u8 cmd; 103 + u8 sub_cmd; 104 + u8 device_type; 105 + u8 data[59]; 106 + } __packed; 107 + 108 + enum command_id { 109 + MCU_CONFIG_DATA = 0x00, 110 + OS_MODE_DATA = 0x06, 111 + GAMEPAD_DATA = 0x3c, 112 + }; 113 + 114 + enum mcu_command_index { 115 + GET_VERSION_DATA = 0x02, 116 + GET_FEATURE_STATUS, 117 + SET_FEATURE_STATUS, 118 + GET_MOTOR_CFG, 119 + SET_MOTOR_CFG, 120 + GET_DPI_CFG, 121 + SET_DPI_CFG, 122 + SET_TRIGGER_CFG = 0x0a, 123 + SET_JOYSTICK_CFG = 0x0c, 124 + SET_GYRO_CFG = 0x0e, 125 + GET_RGB_CFG, 126 + SET_RGB_CFG, 127 + GET_DEVICE_STATUS = 0xa0, 128 + 129 + }; 130 + 131 + enum dev_type { 132 + UNSPECIFIED, 133 + USB_MCU, 134 + TX_DONGLE, 135 + LEFT_CONTROLLER, 136 + RIGHT_CONTROLLER, 137 + }; 138 + 139 + enum enabled_status_index { 140 + FEATURE_UNKNOWN, 141 + FEATURE_ENABLED, 142 + FEATURE_DISABLED, 143 + }; 144 + 145 + static const char *const enabled_status_text[] = { 146 + [FEATURE_UNKNOWN] = "unknown", 147 + [FEATURE_ENABLED] = "true", 148 + [FEATURE_DISABLED] = "false", 149 + }; 150 + 151 + enum version_data_index { 152 + PRODUCT_VERSION = 0x02, 153 + PROTOCOL_VERSION, 154 + FIRMWARE_VERSION, 155 + HARDWARE_VERSION, 156 + HARDWARE_GENERATION, 157 + }; 158 + 159 + enum feature_status_index { 160 + FEATURE_RESET_GAMEPAD = 0x02, 161 + FEATURE_IMU_BYPASS, 162 + FEATURE_IMU_ENABLE = 0x05, 163 + FEATURE_TOUCHPAD_ENABLE = 0x07, 164 + FEATURE_LIGHT_ENABLE, 165 + FEATURE_AUTO_SLEEP_TIME, 166 + FEATURE_FPS_SWITCH_STATUS = 0x0b, 167 + FEATURE_GAMEPAD_MODE = 0x0e, 168 + }; 169 + 170 + #define FEATURE_OS_MODE 0x69 171 + 172 + enum fps_switch_status_index { 173 + FPS_STATUS_UNKNOWN, 174 + GAMEPAD, 175 + FPS, 176 + }; 177 + 178 + static const char *const fps_switch_text[] = { 179 + [FPS_STATUS_UNKNOWN] = "unknown", 180 + [GAMEPAD] = "gamepad", 181 + [FPS] = "fps", 182 + }; 183 + 184 + enum gamepad_mode_index { 185 + GAMEPAD_MODE_UNKNOWN, 186 + XINPUT, 187 + DINPUT, 188 + }; 189 + 190 + static const char *const gamepad_mode_text[] = { 191 + [GAMEPAD_MODE_UNKNOWN] = "unknown", 192 + [XINPUT] = "xinput", 193 + [DINPUT] = "dinput", 194 + }; 195 + 196 + enum motor_cfg_index { 197 + MOTOR_CFG_ALL = 0x01, 198 + MOTOR_INTENSITY, 199 + VIBRATION_NOTIFY_ENABLE, 200 + RUMBLE_MODE, 201 + TP_VIBRATION_ENABLE, 202 + TP_VIBRATION_INTENSITY, 203 + }; 204 + 205 + enum intensity_index { 206 + INTENSITY_UNKNOWN, 207 + INTENSITY_OFF, 208 + INTENSITY_LOW, 209 + INTENSITY_MEDIUM, 210 + INTENSITY_HIGH, 211 + }; 212 + 213 + static const char *const intensity_text[] = { 214 + [INTENSITY_UNKNOWN] = "unknown", 215 + [INTENSITY_OFF] = "off", 216 + [INTENSITY_LOW] = "low", 217 + [INTENSITY_MEDIUM] = "medium", 218 + [INTENSITY_HIGH] = "high", 219 + }; 220 + 221 + enum rumble_mode_index { 222 + RUMBLE_MODE_UNKNOWN, 223 + RUMBLE_MODE_FPS, 224 + RUMBLE_MODE_RACE, 225 + RUMBLE_MODE_AVERAGE, 226 + RUMBLE_MODE_SPG, 227 + RUMBLE_MODE_RPG, 228 + }; 229 + 230 + static const char *const rumble_mode_text[] = { 231 + [RUMBLE_MODE_UNKNOWN] = "unknown", 232 + [RUMBLE_MODE_FPS] = "fps", 233 + [RUMBLE_MODE_RACE] = "racing", 234 + [RUMBLE_MODE_AVERAGE] = "standard", 235 + [RUMBLE_MODE_SPG] = "spg", 236 + [RUMBLE_MODE_RPG] = "rpg", 237 + }; 238 + 239 + #define FPS_MODE_DPI 0x02 240 + #define TRIGGER_CALIBRATE 0x04 241 + #define JOYSTICK_CALIBRATE 0x04 242 + #define GYRO_CALIBRATE 0x06 243 + 244 + enum cal_device_type { 245 + CALDEV_GYROSCOPE = 0x01, 246 + CALDEV_JOYSTICK, 247 + CALDEV_TRIGGER, 248 + CALDEV_JOY_TRIGGER, 249 + }; 250 + 251 + enum cal_enable { 252 + CAL_UNKNOWN, 253 + CAL_START, 254 + CAL_STOP, 255 + }; 256 + 257 + static const char *const cal_enabled_text[] = { 258 + [CAL_UNKNOWN] = "unknown", 259 + [CAL_START] = "start", 260 + [CAL_STOP] = "stop", 261 + }; 262 + 263 + enum cal_status_index { 264 + CAL_STAT_UNKNOWN, 265 + CAL_STAT_SUCCESS, 266 + CAL_STAT_FAILURE, 267 + }; 268 + 269 + static const char *const cal_status_text[] = { 270 + [CAL_STAT_UNKNOWN] = "unknown", 271 + [CAL_STAT_SUCCESS] = "success", 272 + [CAL_STAT_FAILURE] = "failure", 273 + }; 274 + 275 + enum rgb_config_index { 276 + LIGHT_CFG_ALL = 0x01, 277 + LIGHT_MODE_SEL, 278 + LIGHT_PROFILE_SEL, 279 + USR_LIGHT_PROFILE_1, 280 + USR_LIGHT_PROFILE_2, 281 + USR_LIGHT_PROFILE_3, 282 + }; 283 + 284 + enum rgb_mode_index { 285 + RGB_MODE_UNKNOWN, 286 + RGB_MODE_DYNAMIC, 287 + RGB_MODE_CUSTOM, 288 + }; 289 + 290 + static const char *const rgb_mode_text[] = { 291 + [RGB_MODE_UNKNOWN] = "unknown", 292 + [RGB_MODE_DYNAMIC] = "dynamic", 293 + [RGB_MODE_CUSTOM] = "custom", 294 + }; 295 + 296 + enum rgb_effect_index { 297 + RGB_EFFECT_MONO, 298 + RGB_EFFECT_BREATHE, 299 + RGB_EFFECT_CHROMA, 300 + RGB_EFFECT_RAINBOW, 301 + }; 302 + 303 + static const char *const rgb_effect_text[] = { 304 + [RGB_EFFECT_MONO] = "monocolor", 305 + [RGB_EFFECT_BREATHE] = "breathe", 306 + [RGB_EFFECT_CHROMA] = "chroma", 307 + [RGB_EFFECT_RAINBOW] = "rainbow", 308 + }; 309 + 310 + enum device_status_index { 311 + GET_CAL_STATUS = 0x02, 312 + GET_UPGRADE_STATUS, 313 + GET_MACRO_REC_STATUS, 314 + GET_HOTKEY_TRIGG_STATUS, 315 + }; 316 + 317 + enum os_mode_cfg_index { 318 + SET_OS_MODE = 0x09, 319 + GET_OS_MODE, 320 + }; 321 + 322 + enum os_mode_type_index { 323 + OS_UNKNOWN, 324 + WINDOWS, 325 + LINUX, 326 + }; 327 + 328 + static const char *const os_mode_text[] = { 329 + [OS_UNKNOWN] = "unknown", 330 + [WINDOWS] = "windows", 331 + [LINUX] = "linux", 332 + }; 333 + 334 + static int hid_go_version_event(struct command_report *cmd_rep) 335 + { 336 + switch (cmd_rep->sub_cmd) { 337 + case PRODUCT_VERSION: 338 + switch (cmd_rep->device_type) { 339 + case USB_MCU: 340 + drvdata.mcu_version_product = 341 + get_unaligned_be32(cmd_rep->data); 342 + return 0; 343 + case TX_DONGLE: 344 + drvdata.tx_dongle_version_product = 345 + get_unaligned_be32(cmd_rep->data); 346 + return 0; 347 + case LEFT_CONTROLLER: 348 + drvdata.gp_left_version_product = 349 + get_unaligned_be32(cmd_rep->data); 350 + return 0; 351 + case RIGHT_CONTROLLER: 352 + drvdata.gp_right_version_product = 353 + get_unaligned_be32(cmd_rep->data); 354 + return 0; 355 + default: 356 + return -EINVAL; 357 + } 358 + case PROTOCOL_VERSION: 359 + switch (cmd_rep->device_type) { 360 + case USB_MCU: 361 + drvdata.mcu_version_protocol = 362 + get_unaligned_be32(cmd_rep->data); 363 + return 0; 364 + case TX_DONGLE: 365 + drvdata.tx_dongle_version_protocol = 366 + get_unaligned_be32(cmd_rep->data); 367 + return 0; 368 + case LEFT_CONTROLLER: 369 + drvdata.gp_left_version_protocol = 370 + get_unaligned_be32(cmd_rep->data); 371 + return 0; 372 + case RIGHT_CONTROLLER: 373 + drvdata.gp_right_version_protocol = 374 + get_unaligned_be32(cmd_rep->data); 375 + return 0; 376 + default: 377 + return -EINVAL; 378 + } 379 + case FIRMWARE_VERSION: 380 + switch (cmd_rep->device_type) { 381 + case USB_MCU: 382 + drvdata.mcu_version_firmware = 383 + get_unaligned_be32(cmd_rep->data); 384 + return 0; 385 + case TX_DONGLE: 386 + drvdata.tx_dongle_version_firmware = 387 + get_unaligned_be32(cmd_rep->data); 388 + return 0; 389 + case LEFT_CONTROLLER: 390 + drvdata.gp_left_version_firmware = 391 + get_unaligned_be32(cmd_rep->data); 392 + return 0; 393 + case RIGHT_CONTROLLER: 394 + drvdata.gp_right_version_firmware = 395 + get_unaligned_be32(cmd_rep->data); 396 + return 0; 397 + default: 398 + return -EINVAL; 399 + } 400 + case HARDWARE_VERSION: 401 + switch (cmd_rep->device_type) { 402 + case USB_MCU: 403 + drvdata.mcu_version_hardware = 404 + get_unaligned_be32(cmd_rep->data); 405 + return 0; 406 + case TX_DONGLE: 407 + drvdata.tx_dongle_version_hardware = 408 + get_unaligned_be32(cmd_rep->data); 409 + return 0; 410 + case LEFT_CONTROLLER: 411 + drvdata.gp_left_version_hardware = 412 + get_unaligned_be32(cmd_rep->data); 413 + return 0; 414 + case RIGHT_CONTROLLER: 415 + drvdata.gp_right_version_hardware = 416 + get_unaligned_be32(cmd_rep->data); 417 + return 0; 418 + default: 419 + return -EINVAL; 420 + } 421 + case HARDWARE_GENERATION: 422 + switch (cmd_rep->device_type) { 423 + case USB_MCU: 424 + drvdata.mcu_version_gen = cmd_rep->data[0]; 425 + return 0; 426 + case TX_DONGLE: 427 + drvdata.tx_dongle_version_gen = cmd_rep->data[0]; 428 + return 0; 429 + case LEFT_CONTROLLER: 430 + drvdata.gp_left_version_gen = cmd_rep->data[0]; 431 + return 0; 432 + case RIGHT_CONTROLLER: 433 + drvdata.gp_right_version_gen = cmd_rep->data[0]; 434 + return 0; 435 + default: 436 + return -EINVAL; 437 + } 438 + default: 439 + return -EINVAL; 440 + } 441 + } 442 + 443 + static int hid_go_feature_status_event(struct command_report *cmd_rep) 444 + { 445 + switch (cmd_rep->sub_cmd) { 446 + case FEATURE_RESET_GAMEPAD: 447 + return 0; 448 + case FEATURE_IMU_ENABLE: 449 + switch (cmd_rep->device_type) { 450 + case LEFT_CONTROLLER: 451 + drvdata.imu_left_sensor_en = cmd_rep->data[0]; 452 + return 0; 453 + case RIGHT_CONTROLLER: 454 + drvdata.imu_right_sensor_en = cmd_rep->data[0]; 455 + return 0; 456 + default: 457 + return -EINVAL; 458 + } 459 + case FEATURE_IMU_BYPASS: 460 + switch (cmd_rep->device_type) { 461 + case LEFT_CONTROLLER: 462 + drvdata.imu_left_bypass_en = cmd_rep->data[0]; 463 + return 0; 464 + case RIGHT_CONTROLLER: 465 + drvdata.imu_right_bypass_en = cmd_rep->data[0]; 466 + return 0; 467 + default: 468 + return -EINVAL; 469 + } 470 + break; 471 + case FEATURE_LIGHT_ENABLE: 472 + drvdata.rgb_en = cmd_rep->data[0]; 473 + return 0; 474 + case FEATURE_AUTO_SLEEP_TIME: 475 + switch (cmd_rep->device_type) { 476 + case LEFT_CONTROLLER: 477 + drvdata.gp_left_auto_sleep_time = cmd_rep->data[0]; 478 + return 0; 479 + case RIGHT_CONTROLLER: 480 + drvdata.gp_right_auto_sleep_time = cmd_rep->data[0]; 481 + return 0; 482 + default: 483 + return -EINVAL; 484 + } 485 + break; 486 + case FEATURE_TOUCHPAD_ENABLE: 487 + drvdata.tp_en = cmd_rep->data[0]; 488 + return 0; 489 + case FEATURE_GAMEPAD_MODE: 490 + drvdata.gp_mode = cmd_rep->data[0]; 491 + return 0; 492 + case FEATURE_FPS_SWITCH_STATUS: 493 + drvdata.fps_mode = cmd_rep->data[0]; 494 + return 0; 495 + default: 496 + return -EINVAL; 497 + } 498 + } 499 + 500 + static int hid_go_motor_event(struct command_report *cmd_rep) 501 + { 502 + switch (cmd_rep->sub_cmd) { 503 + case MOTOR_CFG_ALL: 504 + return -EINVAL; 505 + case MOTOR_INTENSITY: 506 + drvdata.gp_rumble_intensity = cmd_rep->data[0]; 507 + return 0; 508 + case VIBRATION_NOTIFY_ENABLE: 509 + switch (cmd_rep->device_type) { 510 + case LEFT_CONTROLLER: 511 + drvdata.gp_left_notify_en = cmd_rep->data[0]; 512 + return 0; 513 + case RIGHT_CONTROLLER: 514 + drvdata.gp_right_notify_en = cmd_rep->data[0]; 515 + return 0; 516 + default: 517 + return -EINVAL; 518 + } 519 + break; 520 + case RUMBLE_MODE: 521 + switch (cmd_rep->device_type) { 522 + case LEFT_CONTROLLER: 523 + drvdata.gp_left_rumble_mode = cmd_rep->data[0]; 524 + return 0; 525 + case RIGHT_CONTROLLER: 526 + drvdata.gp_right_rumble_mode = cmd_rep->data[0]; 527 + return 0; 528 + default: 529 + return -EINVAL; 530 + } 531 + case TP_VIBRATION_ENABLE: 532 + drvdata.tp_vibration_en = cmd_rep->data[0]; 533 + return 0; 534 + case TP_VIBRATION_INTENSITY: 535 + drvdata.tp_vibration_intensity = cmd_rep->data[0]; 536 + return 0; 537 + } 538 + return -EINVAL; 539 + } 540 + 541 + static int hid_go_fps_dpi_event(struct command_report *cmd_rep) 542 + { 543 + if (cmd_rep->sub_cmd != FPS_MODE_DPI) 544 + return -EINVAL; 545 + 546 + drvdata.mouse_dpi = get_unaligned_le32(cmd_rep->data); 547 + 548 + return 0; 549 + } 550 + 551 + static int hid_go_light_event(struct command_report *cmd_rep) 552 + { 553 + struct led_classdev_mc *mc_cdev; 554 + 555 + switch (cmd_rep->sub_cmd) { 556 + case LIGHT_MODE_SEL: 557 + drvdata.rgb_mode = cmd_rep->data[0]; 558 + return 0; 559 + case LIGHT_PROFILE_SEL: 560 + drvdata.rgb_profile = cmd_rep->data[0]; 561 + return 0; 562 + case USR_LIGHT_PROFILE_1: 563 + case USR_LIGHT_PROFILE_2: 564 + case USR_LIGHT_PROFILE_3: 565 + mc_cdev = lcdev_to_mccdev(drvdata.led_cdev); 566 + drvdata.rgb_effect = cmd_rep->data[0]; 567 + mc_cdev->subled_info[0].intensity = cmd_rep->data[1]; 568 + mc_cdev->subled_info[1].intensity = cmd_rep->data[2]; 569 + mc_cdev->subled_info[2].intensity = cmd_rep->data[3]; 570 + drvdata.led_cdev->brightness = cmd_rep->data[4]; 571 + drvdata.rgb_speed = 100 - cmd_rep->data[5]; 572 + return 0; 573 + default: 574 + return -EINVAL; 575 + } 576 + } 577 + 578 + static int hid_go_device_status_event(struct command_report *cmd_rep) 579 + { 580 + switch (cmd_rep->device_type) { 581 + case LEFT_CONTROLLER: 582 + switch (cmd_rep->data[0]) { 583 + case CALDEV_GYROSCOPE: 584 + drvdata.gp_left_gyro_cal_status = cmd_rep->data[1]; 585 + return 0; 586 + case CALDEV_JOYSTICK: 587 + drvdata.gp_left_joy_cal_status = cmd_rep->data[1]; 588 + return 0; 589 + case CALDEV_TRIGGER: 590 + drvdata.gp_left_trigg_cal_status = cmd_rep->data[1]; 591 + return 0; 592 + default: 593 + return -EINVAL; 594 + } 595 + break; 596 + case RIGHT_CONTROLLER: 597 + switch (cmd_rep->data[0]) { 598 + case CALDEV_GYROSCOPE: 599 + drvdata.gp_right_gyro_cal_status = cmd_rep->data[1]; 600 + return 0; 601 + case CALDEV_JOYSTICK: 602 + drvdata.gp_right_joy_cal_status = cmd_rep->data[1]; 603 + return 0; 604 + case CALDEV_TRIGGER: 605 + drvdata.gp_right_trigg_cal_status = cmd_rep->data[1]; 606 + return 0; 607 + default: 608 + return -EINVAL; 609 + } 610 + break; 611 + default: 612 + return -EINVAL; 613 + } 614 + } 615 + 616 + static int hid_go_os_mode_cfg_event(struct command_report *cmd_rep) 617 + { 618 + switch (cmd_rep->sub_cmd) { 619 + case SET_OS_MODE: 620 + if (cmd_rep->data[0] != 1) 621 + return -EIO; 622 + return 0; 623 + case GET_OS_MODE: 624 + drvdata.os_mode = cmd_rep->data[0]; 625 + return 0; 626 + default: 627 + return -EINVAL; 628 + } 629 + } 630 + 631 + static int hid_go_set_event_return(struct command_report *cmd_rep) 632 + { 633 + if (cmd_rep->data[0] != 0) 634 + return -EIO; 635 + 636 + return 0; 637 + } 638 + 639 + static int get_endpoint_address(struct hid_device *hdev) 640 + { 641 + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 642 + struct usb_host_endpoint *ep; 643 + 644 + if (!intf) 645 + return -ENODEV; 646 + 647 + ep = intf->cur_altsetting->endpoint; 648 + if (!ep) 649 + return -ENODEV; 650 + 651 + return ep->desc.bEndpointAddress; 652 + } 653 + 654 + static int hid_go_raw_event(struct hid_device *hdev, struct hid_report *report, 655 + u8 *data, int size) 656 + { 657 + struct command_report *cmd_rep; 658 + int ep, ret; 659 + 660 + if (size != GO_PACKET_SIZE) 661 + goto passthrough; 662 + 663 + ep = get_endpoint_address(hdev); 664 + if (ep != GO_GP_INTF_IN) 665 + goto passthrough; 666 + 667 + cmd_rep = (struct command_report *)data; 668 + 669 + switch (cmd_rep->id) { 670 + case MCU_CONFIG_DATA: 671 + switch (cmd_rep->cmd) { 672 + case GET_VERSION_DATA: 673 + ret = hid_go_version_event(cmd_rep); 674 + break; 675 + case GET_FEATURE_STATUS: 676 + ret = hid_go_feature_status_event(cmd_rep); 677 + break; 678 + case GET_MOTOR_CFG: 679 + ret = hid_go_motor_event(cmd_rep); 680 + break; 681 + case GET_DPI_CFG: 682 + ret = hid_go_fps_dpi_event(cmd_rep); 683 + break; 684 + case GET_RGB_CFG: 685 + ret = hid_go_light_event(cmd_rep); 686 + break; 687 + case GET_DEVICE_STATUS: 688 + ret = hid_go_device_status_event(cmd_rep); 689 + break; 690 + case SET_FEATURE_STATUS: 691 + case SET_MOTOR_CFG: 692 + case SET_DPI_CFG: 693 + case SET_RGB_CFG: 694 + case SET_TRIGGER_CFG: 695 + case SET_JOYSTICK_CFG: 696 + case SET_GYRO_CFG: 697 + ret = hid_go_set_event_return(cmd_rep); 698 + break; 699 + default: 700 + ret = -EINVAL; 701 + break; 702 + } 703 + break; 704 + case OS_MODE_DATA: 705 + ret = hid_go_os_mode_cfg_event(cmd_rep); 706 + break; 707 + default: 708 + goto passthrough; 709 + } 710 + dev_dbg(&hdev->dev, "Rx data as raw input report: [%*ph]\n", 711 + GO_PACKET_SIZE, data); 712 + 713 + complete(&drvdata.send_cmd_complete); 714 + return ret; 715 + 716 + passthrough: 717 + /* Forward other HID reports so they generate events */ 718 + hid_input_report(hdev, HID_INPUT_REPORT, data, size, 1); 719 + return 0; 720 + } 721 + 722 + static int mcu_property_out(struct hid_device *hdev, u8 id, u8 command, 723 + u8 index, enum dev_type device, u8 *data, size_t len) 724 + { 725 + unsigned char *dmabuf __free(kfree) = NULL; 726 + u8 header[] = { GO_OUTPUT_REPORT_ID, id, command, index, device }; 727 + size_t header_size = ARRAY_SIZE(header); 728 + int timeout = 50; 729 + int ret; 730 + 731 + if (header_size + len > GO_PACKET_SIZE) 732 + return -EINVAL; 733 + 734 + guard(mutex)(&drvdata.cfg_mutex); 735 + /* We can't use a devm_alloc reusable buffer without side effects during suspend */ 736 + dmabuf = kzalloc(GO_PACKET_SIZE, GFP_KERNEL); 737 + if (!dmabuf) 738 + return -ENOMEM; 739 + 740 + memcpy(dmabuf, header, header_size); 741 + memcpy(dmabuf + header_size, data, len); 742 + 743 + dev_dbg(&hdev->dev, "Send data as raw output report: [%*ph]\n", 744 + GO_PACKET_SIZE, dmabuf); 745 + 746 + ret = hid_hw_output_report(hdev, dmabuf, GO_PACKET_SIZE); 747 + if (ret < 0) 748 + return ret; 749 + 750 + ret = ret == GO_PACKET_SIZE ? 0 : -EINVAL; 751 + if (ret) 752 + return ret; 753 + 754 + ret = wait_for_completion_interruptible_timeout(&drvdata.send_cmd_complete, 755 + msecs_to_jiffies(timeout)); 756 + 757 + if (ret == 0) /* timeout occurred */ 758 + ret = -EBUSY; 759 + 760 + reinit_completion(&drvdata.send_cmd_complete); 761 + return 0; 762 + } 763 + 764 + static ssize_t version_show(struct device *dev, struct device_attribute *attr, 765 + char *buf, enum version_data_index index, 766 + enum dev_type device_type) 767 + { 768 + ssize_t count = 0; 769 + int ret; 770 + 771 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, 772 + index, device_type, NULL, 0); 773 + if (ret) 774 + return ret; 775 + 776 + switch (index) { 777 + case PRODUCT_VERSION: 778 + switch (device_type) { 779 + case USB_MCU: 780 + count = sysfs_emit(buf, "%x\n", 781 + drvdata.mcu_version_product); 782 + break; 783 + case TX_DONGLE: 784 + count = sysfs_emit(buf, "%x\n", 785 + drvdata.tx_dongle_version_product); 786 + break; 787 + case LEFT_CONTROLLER: 788 + count = sysfs_emit(buf, "%x\n", 789 + drvdata.gp_left_version_product); 790 + break; 791 + case RIGHT_CONTROLLER: 792 + count = sysfs_emit(buf, "%x\n", 793 + drvdata.gp_right_version_product); 794 + break; 795 + default: 796 + return -EINVAL; 797 + } 798 + break; 799 + case PROTOCOL_VERSION: 800 + switch (device_type) { 801 + case USB_MCU: 802 + count = sysfs_emit(buf, "%x\n", 803 + drvdata.mcu_version_protocol); 804 + break; 805 + case TX_DONGLE: 806 + count = sysfs_emit(buf, "%x\n", 807 + drvdata.tx_dongle_version_protocol); 808 + break; 809 + case LEFT_CONTROLLER: 810 + count = sysfs_emit(buf, "%x\n", 811 + drvdata.gp_left_version_protocol); 812 + break; 813 + case RIGHT_CONTROLLER: 814 + count = sysfs_emit(buf, "%x\n", 815 + drvdata.gp_right_version_protocol); 816 + break; 817 + default: 818 + return -EINVAL; 819 + } 820 + break; 821 + case FIRMWARE_VERSION: 822 + switch (device_type) { 823 + case USB_MCU: 824 + count = sysfs_emit(buf, "%x\n", 825 + drvdata.mcu_version_firmware); 826 + break; 827 + case TX_DONGLE: 828 + count = sysfs_emit(buf, "%x\n", 829 + drvdata.tx_dongle_version_firmware); 830 + break; 831 + case LEFT_CONTROLLER: 832 + count = sysfs_emit(buf, "%x\n", 833 + drvdata.gp_left_version_firmware); 834 + break; 835 + case RIGHT_CONTROLLER: 836 + count = sysfs_emit(buf, "%x\n", 837 + drvdata.gp_right_version_firmware); 838 + break; 839 + default: 840 + return -EINVAL; 841 + } 842 + break; 843 + case HARDWARE_VERSION: 844 + switch (device_type) { 845 + case USB_MCU: 846 + count = sysfs_emit(buf, "%x\n", 847 + drvdata.mcu_version_hardware); 848 + break; 849 + case TX_DONGLE: 850 + count = sysfs_emit(buf, "%x\n", 851 + drvdata.tx_dongle_version_hardware); 852 + break; 853 + case LEFT_CONTROLLER: 854 + count = sysfs_emit(buf, "%x\n", 855 + drvdata.gp_left_version_hardware); 856 + break; 857 + case RIGHT_CONTROLLER: 858 + count = sysfs_emit(buf, "%x\n", 859 + drvdata.gp_right_version_hardware); 860 + break; 861 + default: 862 + return -EINVAL; 863 + } 864 + break; 865 + case HARDWARE_GENERATION: 866 + switch (device_type) { 867 + case USB_MCU: 868 + count = sysfs_emit(buf, "%x\n", 869 + drvdata.mcu_version_gen); 870 + break; 871 + case TX_DONGLE: 872 + count = sysfs_emit(buf, "%x\n", 873 + drvdata.tx_dongle_version_gen); 874 + break; 875 + case LEFT_CONTROLLER: 876 + count = sysfs_emit(buf, "%x\n", 877 + drvdata.gp_left_version_gen); 878 + break; 879 + case RIGHT_CONTROLLER: 880 + count = sysfs_emit(buf, "%x\n", 881 + drvdata.gp_right_version_gen); 882 + break; 883 + default: 884 + return -EINVAL; 885 + } 886 + break; 887 + } 888 + 889 + return count; 890 + } 891 + 892 + static ssize_t feature_status_store(struct device *dev, 893 + struct device_attribute *attr, 894 + const char *buf, size_t count, 895 + enum feature_status_index index, 896 + enum dev_type device_type) 897 + { 898 + size_t size = 1; 899 + u8 val = 0; 900 + int ret; 901 + 902 + switch (index) { 903 + case FEATURE_IMU_ENABLE: 904 + case FEATURE_IMU_BYPASS: 905 + case FEATURE_LIGHT_ENABLE: 906 + case FEATURE_TOUCHPAD_ENABLE: 907 + ret = sysfs_match_string(enabled_status_text, buf); 908 + val = ret; 909 + break; 910 + case FEATURE_AUTO_SLEEP_TIME: 911 + ret = kstrtou8(buf, 10, &val); 912 + break; 913 + case FEATURE_RESET_GAMEPAD: 914 + ret = kstrtou8(buf, 10, &val); 915 + if (val != GO_GP_RESET_SUCCESS) 916 + return -EINVAL; 917 + break; 918 + case FEATURE_FPS_SWITCH_STATUS: 919 + ret = sysfs_match_string(fps_switch_text, buf); 920 + val = ret; 921 + break; 922 + case FEATURE_GAMEPAD_MODE: 923 + ret = sysfs_match_string(gamepad_mode_text, buf); 924 + val = ret; 925 + break; 926 + default: 927 + return -EINVAL; 928 + } 929 + 930 + if (ret < 0) 931 + return ret; 932 + 933 + if (!val) 934 + size = 0; 935 + 936 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, 937 + SET_FEATURE_STATUS, index, device_type, &val, 938 + size); 939 + if (ret < 0) 940 + return ret; 941 + 942 + return count; 943 + } 944 + 945 + static ssize_t feature_status_show(struct device *dev, 946 + struct device_attribute *attr, char *buf, 947 + enum feature_status_index index, 948 + enum dev_type device_type) 949 + { 950 + ssize_t count = 0; 951 + int ret; 952 + u8 i; 953 + 954 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, 955 + GET_FEATURE_STATUS, index, device_type, NULL, 0); 956 + if (ret) 957 + return ret; 958 + 959 + switch (index) { 960 + case FEATURE_IMU_ENABLE: 961 + switch (device_type) { 962 + case LEFT_CONTROLLER: 963 + i = drvdata.imu_left_sensor_en; 964 + break; 965 + case RIGHT_CONTROLLER: 966 + i = drvdata.imu_right_sensor_en; 967 + break; 968 + default: 969 + return -EINVAL; 970 + } 971 + if (i >= ARRAY_SIZE(enabled_status_text)) 972 + return -EINVAL; 973 + 974 + count = sysfs_emit(buf, "%s\n", enabled_status_text[i]); 975 + break; 976 + case FEATURE_IMU_BYPASS: 977 + switch (device_type) { 978 + case LEFT_CONTROLLER: 979 + i = drvdata.imu_left_bypass_en; 980 + break; 981 + case RIGHT_CONTROLLER: 982 + i = drvdata.imu_right_bypass_en; 983 + break; 984 + default: 985 + return -EINVAL; 986 + } 987 + if (i >= ARRAY_SIZE(enabled_status_text)) 988 + return -EINVAL; 989 + 990 + count = sysfs_emit(buf, "%s\n", enabled_status_text[i]); 991 + break; 992 + case FEATURE_LIGHT_ENABLE: 993 + i = drvdata.rgb_en; 994 + if (i >= ARRAY_SIZE(enabled_status_text)) 995 + return -EINVAL; 996 + 997 + count = sysfs_emit(buf, "%s\n", enabled_status_text[i]); 998 + break; 999 + case FEATURE_TOUCHPAD_ENABLE: 1000 + i = drvdata.tp_en; 1001 + if (i >= ARRAY_SIZE(enabled_status_text)) 1002 + return -EINVAL; 1003 + 1004 + count = sysfs_emit(buf, "%s\n", enabled_status_text[i]); 1005 + break; 1006 + case FEATURE_AUTO_SLEEP_TIME: 1007 + switch (device_type) { 1008 + case LEFT_CONTROLLER: 1009 + i = drvdata.gp_left_auto_sleep_time; 1010 + break; 1011 + case RIGHT_CONTROLLER: 1012 + i = drvdata.gp_right_auto_sleep_time; 1013 + break; 1014 + default: 1015 + return -EINVAL; 1016 + } 1017 + count = sysfs_emit(buf, "%u\n", i); 1018 + break; 1019 + case FEATURE_FPS_SWITCH_STATUS: 1020 + i = drvdata.fps_mode; 1021 + if (i >= ARRAY_SIZE(fps_switch_text)) 1022 + return -EINVAL; 1023 + 1024 + count = sysfs_emit(buf, "%s\n", fps_switch_text[i]); 1025 + break; 1026 + case FEATURE_GAMEPAD_MODE: 1027 + i = drvdata.gp_mode; 1028 + if (i >= ARRAY_SIZE(gamepad_mode_text)) 1029 + return -EINVAL; 1030 + 1031 + count = sysfs_emit(buf, "%s\n", gamepad_mode_text[i]); 1032 + break; 1033 + default: 1034 + return -EINVAL; 1035 + } 1036 + 1037 + return count; 1038 + } 1039 + 1040 + static ssize_t feature_status_options(struct device *dev, 1041 + struct device_attribute *attr, char *buf, 1042 + enum feature_status_index index) 1043 + { 1044 + ssize_t count = 0; 1045 + unsigned int i; 1046 + 1047 + switch (index) { 1048 + case FEATURE_IMU_ENABLE: 1049 + case FEATURE_IMU_BYPASS: 1050 + case FEATURE_LIGHT_ENABLE: 1051 + case FEATURE_TOUCHPAD_ENABLE: 1052 + for (i = 1; i < ARRAY_SIZE(enabled_status_text); i++) { 1053 + count += sysfs_emit_at(buf, count, "%s ", 1054 + enabled_status_text[i]); 1055 + } 1056 + break; 1057 + case FEATURE_AUTO_SLEEP_TIME: 1058 + return sysfs_emit(buf, "0-255\n"); 1059 + case FEATURE_FPS_SWITCH_STATUS: 1060 + for (i = 1; i < ARRAY_SIZE(fps_switch_text); i++) { 1061 + count += sysfs_emit_at(buf, count, "%s ", 1062 + fps_switch_text[i]); 1063 + } 1064 + break; 1065 + case FEATURE_GAMEPAD_MODE: 1066 + for (i = 1; i < ARRAY_SIZE(gamepad_mode_text); i++) { 1067 + count += sysfs_emit_at(buf, count, "%s ", 1068 + gamepad_mode_text[i]); 1069 + } 1070 + break; 1071 + default: 1072 + return -EINVAL; 1073 + } 1074 + 1075 + if (count) 1076 + buf[count - 1] = '\n'; 1077 + 1078 + return count; 1079 + } 1080 + 1081 + static ssize_t motor_config_store(struct device *dev, 1082 + struct device_attribute *attr, 1083 + const char *buf, size_t count, 1084 + enum motor_cfg_index index, 1085 + enum dev_type device_type) 1086 + { 1087 + size_t size = 1; 1088 + u8 val = 0; 1089 + int ret; 1090 + 1091 + switch (index) { 1092 + case MOTOR_CFG_ALL: 1093 + return -EINVAL; 1094 + case MOTOR_INTENSITY: 1095 + ret = sysfs_match_string(intensity_text, buf); 1096 + val = ret; 1097 + break; 1098 + case VIBRATION_NOTIFY_ENABLE: 1099 + ret = sysfs_match_string(enabled_status_text, buf); 1100 + val = ret; 1101 + break; 1102 + case RUMBLE_MODE: 1103 + ret = sysfs_match_string(rumble_mode_text, buf); 1104 + val = ret; 1105 + break; 1106 + case TP_VIBRATION_ENABLE: 1107 + ret = sysfs_match_string(enabled_status_text, buf); 1108 + val = ret; 1109 + break; 1110 + case TP_VIBRATION_INTENSITY: 1111 + ret = sysfs_match_string(intensity_text, buf); 1112 + val = ret; 1113 + break; 1114 + } 1115 + 1116 + if (ret < 0) 1117 + return ret; 1118 + 1119 + if (!val) 1120 + size = 0; 1121 + 1122 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, SET_MOTOR_CFG, 1123 + index, device_type, &val, size); 1124 + if (ret < 0) 1125 + return ret; 1126 + 1127 + return count; 1128 + } 1129 + 1130 + static ssize_t motor_config_show(struct device *dev, 1131 + struct device_attribute *attr, char *buf, 1132 + enum motor_cfg_index index, 1133 + enum dev_type device_type) 1134 + { 1135 + ssize_t count = 0; 1136 + int ret; 1137 + u8 i; 1138 + 1139 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_MOTOR_CFG, 1140 + index, device_type, NULL, 0); 1141 + if (ret) 1142 + return ret; 1143 + 1144 + switch (index) { 1145 + case MOTOR_CFG_ALL: 1146 + return -EINVAL; 1147 + case MOTOR_INTENSITY: 1148 + i = drvdata.gp_rumble_intensity; 1149 + if (i >= ARRAY_SIZE(intensity_text)) 1150 + return -EINVAL; 1151 + 1152 + count = sysfs_emit(buf, "%s\n", intensity_text[i]); 1153 + break; 1154 + case VIBRATION_NOTIFY_ENABLE: 1155 + switch (device_type) { 1156 + case LEFT_CONTROLLER: 1157 + i = drvdata.gp_left_notify_en; 1158 + break; 1159 + case RIGHT_CONTROLLER: 1160 + i = drvdata.gp_right_notify_en; 1161 + break; 1162 + default: 1163 + return -EINVAL; 1164 + } 1165 + if (i >= ARRAY_SIZE(enabled_status_text)) 1166 + return -EINVAL; 1167 + 1168 + count = sysfs_emit(buf, "%s\n", enabled_status_text[i]); 1169 + break; 1170 + case RUMBLE_MODE: 1171 + switch (device_type) { 1172 + case LEFT_CONTROLLER: 1173 + i = drvdata.gp_left_rumble_mode; 1174 + break; 1175 + case RIGHT_CONTROLLER: 1176 + i = drvdata.gp_right_rumble_mode; 1177 + break; 1178 + default: 1179 + return -EINVAL; 1180 + } 1181 + if (i >= ARRAY_SIZE(rumble_mode_text)) 1182 + return -EINVAL; 1183 + 1184 + count = sysfs_emit(buf, "%s\n", rumble_mode_text[i]); 1185 + break; 1186 + case TP_VIBRATION_ENABLE: 1187 + i = drvdata.tp_vibration_en; 1188 + if (i >= ARRAY_SIZE(enabled_status_text)) 1189 + return -EINVAL; 1190 + 1191 + count = sysfs_emit(buf, "%s\n", enabled_status_text[i]); 1192 + break; 1193 + case TP_VIBRATION_INTENSITY: 1194 + i = drvdata.tp_vibration_intensity; 1195 + if (i >= ARRAY_SIZE(intensity_text)) 1196 + return -EINVAL; 1197 + 1198 + count = sysfs_emit(buf, "%s\n", intensity_text[i]); 1199 + break; 1200 + } 1201 + 1202 + return count; 1203 + } 1204 + 1205 + static ssize_t motor_config_options(struct device *dev, 1206 + struct device_attribute *attr, char *buf, 1207 + enum motor_cfg_index index) 1208 + { 1209 + ssize_t count = 0; 1210 + unsigned int i; 1211 + 1212 + switch (index) { 1213 + case MOTOR_CFG_ALL: 1214 + break; 1215 + case RUMBLE_MODE: 1216 + for (i = 1; i < ARRAY_SIZE(rumble_mode_text); i++) { 1217 + count += sysfs_emit_at(buf, count, "%s ", 1218 + rumble_mode_text[i]); 1219 + } 1220 + break; 1221 + case MOTOR_INTENSITY: 1222 + case TP_VIBRATION_INTENSITY: 1223 + for (i = 1; i < ARRAY_SIZE(intensity_text); i++) { 1224 + count += sysfs_emit_at(buf, count, "%s ", 1225 + intensity_text[i]); 1226 + } 1227 + break; 1228 + case VIBRATION_NOTIFY_ENABLE: 1229 + case TP_VIBRATION_ENABLE: 1230 + for (i = 1; i < ARRAY_SIZE(enabled_status_text); i++) { 1231 + count += sysfs_emit_at(buf, count, "%s ", 1232 + enabled_status_text[i]); 1233 + } 1234 + break; 1235 + } 1236 + 1237 + if (count) 1238 + buf[count - 1] = '\n'; 1239 + 1240 + return count; 1241 + } 1242 + 1243 + static ssize_t fps_mode_dpi_store(struct device *dev, 1244 + struct device_attribute *attr, 1245 + const char *buf, size_t count) 1246 + 1247 + { 1248 + size_t size = 4; 1249 + u32 value; 1250 + u8 val[4]; 1251 + int ret; 1252 + 1253 + ret = kstrtou32(buf, 10, &value); 1254 + if (ret) 1255 + return ret; 1256 + 1257 + if (value != 500 && value != 800 && value != 1200 && value != 1800) 1258 + return -EINVAL; 1259 + 1260 + put_unaligned_le32(value, val); 1261 + 1262 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, SET_DPI_CFG, 1263 + FPS_MODE_DPI, UNSPECIFIED, val, size); 1264 + if (ret < 0) 1265 + return ret; 1266 + 1267 + return count; 1268 + } 1269 + 1270 + static ssize_t fps_mode_dpi_show(struct device *dev, 1271 + struct device_attribute *attr, char *buf) 1272 + { 1273 + int ret; 1274 + 1275 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_DPI_CFG, 1276 + FPS_MODE_DPI, UNSPECIFIED, NULL, 0); 1277 + if (ret < 0) 1278 + return ret; 1279 + 1280 + return sysfs_emit(buf, "%u\n", drvdata.mouse_dpi); 1281 + } 1282 + 1283 + static ssize_t fps_mode_dpi_index_show(struct device *dev, 1284 + struct device_attribute *attr, char *buf) 1285 + { 1286 + return sysfs_emit(buf, "500 800 1200 1800\n"); 1287 + } 1288 + 1289 + static ssize_t device_status_show(struct device *dev, 1290 + struct device_attribute *attr, char *buf, 1291 + enum device_status_index index, 1292 + enum dev_type device_type, 1293 + enum cal_device_type cal_type) 1294 + { 1295 + u8 i; 1296 + 1297 + switch (index) { 1298 + case GET_CAL_STATUS: 1299 + switch (device_type) { 1300 + case LEFT_CONTROLLER: 1301 + switch (cal_type) { 1302 + case CALDEV_GYROSCOPE: 1303 + i = drvdata.gp_left_gyro_cal_status; 1304 + break; 1305 + case CALDEV_JOYSTICK: 1306 + i = drvdata.gp_left_joy_cal_status; 1307 + break; 1308 + case CALDEV_TRIGGER: 1309 + i = drvdata.gp_left_trigg_cal_status; 1310 + break; 1311 + default: 1312 + return -EINVAL; 1313 + } 1314 + break; 1315 + case RIGHT_CONTROLLER: 1316 + switch (cal_type) { 1317 + case CALDEV_GYROSCOPE: 1318 + i = drvdata.gp_right_gyro_cal_status; 1319 + break; 1320 + case CALDEV_JOYSTICK: 1321 + i = drvdata.gp_right_joy_cal_status; 1322 + break; 1323 + case CALDEV_TRIGGER: 1324 + i = drvdata.gp_right_trigg_cal_status; 1325 + break; 1326 + default: 1327 + return -EINVAL; 1328 + } 1329 + break; 1330 + default: 1331 + return -EINVAL; 1332 + } 1333 + break; 1334 + default: 1335 + return -EINVAL; 1336 + } 1337 + 1338 + if (i >= ARRAY_SIZE(cal_status_text)) 1339 + return -EINVAL; 1340 + 1341 + return sysfs_emit(buf, "%s\n", cal_status_text[i]); 1342 + } 1343 + 1344 + static ssize_t calibrate_config_store(struct device *dev, 1345 + struct device_attribute *attr, 1346 + const char *buf, u8 cmd, u8 sub_cmd, 1347 + size_t count, enum dev_type device_type) 1348 + { 1349 + size_t size = 1; 1350 + u8 val = 0; 1351 + int ret; 1352 + 1353 + ret = sysfs_match_string(cal_enabled_text, buf); 1354 + if (ret < 0) 1355 + return ret; 1356 + 1357 + val = ret; 1358 + if (!val) 1359 + size = 0; 1360 + 1361 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, cmd, sub_cmd, 1362 + device_type, &val, size); 1363 + if (ret < 0) 1364 + return ret; 1365 + 1366 + return count; 1367 + } 1368 + 1369 + static ssize_t calibrate_config_options(struct device *dev, 1370 + struct device_attribute *attr, 1371 + char *buf) 1372 + { 1373 + ssize_t count = 0; 1374 + unsigned int i; 1375 + 1376 + for (i = 1; i < ARRAY_SIZE(cal_enabled_text); i++) 1377 + count += sysfs_emit_at(buf, count, "%s ", cal_enabled_text[i]); 1378 + 1379 + buf[count - 1] = '\n'; 1380 + 1381 + return count; 1382 + } 1383 + 1384 + static ssize_t os_mode_store(struct device *dev, struct device_attribute *attr, 1385 + const char *buf, size_t count) 1386 + { 1387 + size_t size = 1; 1388 + int ret; 1389 + u8 val; 1390 + 1391 + ret = sysfs_match_string(os_mode_text, buf); 1392 + if (ret <= 0) 1393 + return ret; 1394 + 1395 + val = ret; 1396 + ret = mcu_property_out(drvdata.hdev, OS_MODE_DATA, FEATURE_OS_MODE, 1397 + SET_OS_MODE, USB_MCU, &val, size); 1398 + if (ret < 0) 1399 + return ret; 1400 + 1401 + drvdata.os_mode = val; 1402 + 1403 + return count; 1404 + } 1405 + 1406 + static ssize_t os_mode_show(struct device *dev, struct device_attribute *attr, 1407 + char *buf) 1408 + { 1409 + ssize_t count = 0; 1410 + int ret; 1411 + u8 i; 1412 + 1413 + ret = mcu_property_out(drvdata.hdev, OS_MODE_DATA, FEATURE_OS_MODE, 1414 + GET_OS_MODE, USB_MCU, NULL, 0); 1415 + if (ret) 1416 + return ret; 1417 + 1418 + i = drvdata.os_mode; 1419 + if (i >= ARRAY_SIZE(os_mode_text)) 1420 + return -EINVAL; 1421 + 1422 + count = sysfs_emit(buf, "%s\n", os_mode_text[i]); 1423 + 1424 + return count; 1425 + } 1426 + 1427 + static ssize_t os_mode_index_show(struct device *dev, 1428 + struct device_attribute *attr, char *buf) 1429 + { 1430 + ssize_t count = 0; 1431 + unsigned int i; 1432 + 1433 + for (i = 1; i < ARRAY_SIZE(os_mode_text); i++) 1434 + count += sysfs_emit_at(buf, count, "%s ", os_mode_text[i]); 1435 + 1436 + if (count) 1437 + buf[count - 1] = '\n'; 1438 + 1439 + return count; 1440 + } 1441 + 1442 + static int rgb_cfg_call(struct hid_device *hdev, enum mcu_command_index cmd, 1443 + enum rgb_config_index index, u8 *val, size_t size) 1444 + { 1445 + if (cmd != SET_RGB_CFG && cmd != GET_RGB_CFG) 1446 + return -EINVAL; 1447 + 1448 + if (index < LIGHT_CFG_ALL || index > USR_LIGHT_PROFILE_3) 1449 + return -EINVAL; 1450 + 1451 + return mcu_property_out(hdev, MCU_CONFIG_DATA, cmd, index, UNSPECIFIED, 1452 + val, size); 1453 + } 1454 + 1455 + static int rgb_attr_show(void) 1456 + { 1457 + enum rgb_config_index index; 1458 + 1459 + index = drvdata.rgb_profile + 3; 1460 + 1461 + return rgb_cfg_call(drvdata.hdev, GET_RGB_CFG, index, NULL, 0); 1462 + } 1463 + 1464 + static ssize_t rgb_effect_store(struct device *dev, 1465 + struct device_attribute *attr, const char *buf, 1466 + size_t count) 1467 + { 1468 + struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(drvdata.led_cdev); 1469 + enum rgb_config_index index; 1470 + u8 effect; 1471 + int ret; 1472 + 1473 + ret = sysfs_match_string(rgb_effect_text, buf); 1474 + if (ret < 0) 1475 + return ret; 1476 + 1477 + effect = ret; 1478 + index = drvdata.rgb_profile + 3; 1479 + u8 rgb_profile[6] = { effect, 1480 + mc_cdev->subled_info[0].intensity, 1481 + mc_cdev->subled_info[1].intensity, 1482 + mc_cdev->subled_info[2].intensity, 1483 + drvdata.led_cdev->brightness, 1484 + drvdata.rgb_speed }; 1485 + 1486 + ret = rgb_cfg_call(drvdata.hdev, SET_RGB_CFG, index, rgb_profile, 6); 1487 + if (ret) 1488 + return ret; 1489 + 1490 + drvdata.rgb_effect = effect; 1491 + return count; 1492 + } 1493 + 1494 + static ssize_t rgb_effect_show(struct device *dev, 1495 + struct device_attribute *attr, char *buf) 1496 + { 1497 + int ret; 1498 + 1499 + ret = rgb_attr_show(); 1500 + if (ret) 1501 + return ret; 1502 + 1503 + if (drvdata.rgb_effect >= ARRAY_SIZE(rgb_effect_text)) 1504 + return -EINVAL; 1505 + 1506 + return sysfs_emit(buf, "%s\n", rgb_effect_text[drvdata.rgb_effect]); 1507 + } 1508 + 1509 + static ssize_t rgb_effect_index_show(struct device *dev, 1510 + struct device_attribute *attr, char *buf) 1511 + { 1512 + ssize_t count = 0; 1513 + unsigned int i; 1514 + 1515 + for (i = 0; i < ARRAY_SIZE(rgb_effect_text); i++) 1516 + count += sysfs_emit_at(buf, count, "%s ", rgb_effect_text[i]); 1517 + 1518 + if (count) 1519 + buf[count - 1] = '\n'; 1520 + 1521 + return count; 1522 + } 1523 + 1524 + static ssize_t rgb_speed_store(struct device *dev, 1525 + struct device_attribute *attr, const char *buf, 1526 + size_t count) 1527 + { 1528 + struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(drvdata.led_cdev); 1529 + enum rgb_config_index index; 1530 + int val = 0; 1531 + int ret; 1532 + 1533 + ret = kstrtoint(buf, 10, &val); 1534 + if (ret) 1535 + return ret; 1536 + 1537 + if (val < 0 || val > 100) 1538 + return -EINVAL; 1539 + 1540 + /* This is a delay setting, invert logic for consistency with other drivers */ 1541 + val = 100 - val; 1542 + 1543 + index = drvdata.rgb_profile + 3; 1544 + u8 rgb_profile[6] = { drvdata.rgb_effect, 1545 + mc_cdev->subled_info[0].intensity, 1546 + mc_cdev->subled_info[1].intensity, 1547 + mc_cdev->subled_info[2].intensity, 1548 + drvdata.led_cdev->brightness, 1549 + val }; 1550 + 1551 + ret = rgb_cfg_call(drvdata.hdev, SET_RGB_CFG, index, rgb_profile, 6); 1552 + if (ret) 1553 + return ret; 1554 + 1555 + drvdata.rgb_speed = val; 1556 + 1557 + return count; 1558 + } 1559 + 1560 + static ssize_t rgb_speed_show(struct device *dev, struct device_attribute *attr, 1561 + char *buf) 1562 + { 1563 + int ret, val; 1564 + 1565 + ret = rgb_attr_show(); 1566 + if (ret) 1567 + return ret; 1568 + 1569 + if (drvdata.rgb_speed > 100) 1570 + return -EINVAL; 1571 + 1572 + val = drvdata.rgb_speed; 1573 + 1574 + return sysfs_emit(buf, "%hhu\n", val); 1575 + } 1576 + 1577 + static ssize_t rgb_speed_range_show(struct device *dev, 1578 + struct device_attribute *attr, char *buf) 1579 + { 1580 + return sysfs_emit(buf, "0-100\n"); 1581 + } 1582 + 1583 + static ssize_t rgb_mode_store(struct device *dev, struct device_attribute *attr, 1584 + const char *buf, size_t count) 1585 + { 1586 + int ret; 1587 + u8 val; 1588 + 1589 + ret = sysfs_match_string(rgb_mode_text, buf); 1590 + if (ret <= 0) 1591 + return ret; 1592 + 1593 + val = ret; 1594 + 1595 + ret = rgb_cfg_call(drvdata.hdev, SET_RGB_CFG, LIGHT_MODE_SEL, &val, 1); 1596 + if (ret) 1597 + return ret; 1598 + 1599 + drvdata.rgb_mode = val; 1600 + 1601 + return count; 1602 + } 1603 + 1604 + static ssize_t rgb_mode_show(struct device *dev, struct device_attribute *attr, 1605 + char *buf) 1606 + { 1607 + int ret; 1608 + 1609 + ret = rgb_cfg_call(drvdata.hdev, GET_RGB_CFG, LIGHT_MODE_SEL, NULL, 0); 1610 + if (ret) 1611 + return ret; 1612 + 1613 + if (drvdata.rgb_mode >= ARRAY_SIZE(rgb_mode_text)) 1614 + return -EINVAL; 1615 + 1616 + return sysfs_emit(buf, "%s\n", rgb_mode_text[drvdata.rgb_mode]); 1617 + } 1618 + 1619 + static ssize_t rgb_mode_index_show(struct device *dev, 1620 + struct device_attribute *attr, char *buf) 1621 + { 1622 + ssize_t count = 0; 1623 + unsigned int i; 1624 + 1625 + for (i = 1; i < ARRAY_SIZE(rgb_mode_text); i++) 1626 + count += sysfs_emit_at(buf, count, "%s ", rgb_mode_text[i]); 1627 + 1628 + if (count) 1629 + buf[count - 1] = '\n'; 1630 + 1631 + return count; 1632 + } 1633 + 1634 + static ssize_t rgb_profile_store(struct device *dev, 1635 + struct device_attribute *attr, const char *buf, 1636 + size_t count) 1637 + { 1638 + size_t size = 1; 1639 + int ret; 1640 + u8 val; 1641 + 1642 + ret = kstrtou8(buf, 10, &val); 1643 + if (ret < 0) 1644 + return ret; 1645 + 1646 + if (val < 1 || val > 3) 1647 + return -EINVAL; 1648 + 1649 + ret = rgb_cfg_call(drvdata.hdev, SET_RGB_CFG, LIGHT_PROFILE_SEL, &val, size); 1650 + if (ret) 1651 + return ret; 1652 + 1653 + drvdata.rgb_profile = val; 1654 + 1655 + return count; 1656 + } 1657 + 1658 + static ssize_t rgb_profile_show(struct device *dev, 1659 + struct device_attribute *attr, char *buf) 1660 + { 1661 + int ret; 1662 + 1663 + ret = rgb_cfg_call(drvdata.hdev, GET_RGB_CFG, LIGHT_PROFILE_SEL, NULL, 0); 1664 + if (ret) 1665 + return ret; 1666 + 1667 + if (drvdata.rgb_profile < 1 || drvdata.rgb_profile > 3) 1668 + return -EINVAL; 1669 + 1670 + return sysfs_emit(buf, "%hhu\n", drvdata.rgb_profile); 1671 + } 1672 + 1673 + static ssize_t rgb_profile_range_show(struct device *dev, 1674 + struct device_attribute *attr, char *buf) 1675 + { 1676 + return sysfs_emit(buf, "1-3\n"); 1677 + } 1678 + 1679 + static void hid_go_brightness_set(struct led_classdev *led_cdev, 1680 + enum led_brightness brightness) 1681 + { 1682 + struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(drvdata.led_cdev); 1683 + enum rgb_config_index index; 1684 + int ret; 1685 + 1686 + if (brightness > led_cdev->max_brightness) { 1687 + dev_err(led_cdev->dev, "Invalid argument\n"); 1688 + return; 1689 + } 1690 + 1691 + index = drvdata.rgb_profile + 3; 1692 + u8 rgb_profile[6] = { drvdata.rgb_effect, 1693 + mc_cdev->subled_info[0].intensity, 1694 + mc_cdev->subled_info[1].intensity, 1695 + mc_cdev->subled_info[2].intensity, 1696 + brightness, 1697 + drvdata.rgb_speed }; 1698 + 1699 + ret = rgb_cfg_call(drvdata.hdev, SET_RGB_CFG, index, rgb_profile, 6); 1700 + switch (ret) { 1701 + case 0: 1702 + led_cdev->brightness = brightness; 1703 + break; 1704 + case -ENODEV: /* during switch to IAP -ENODEV is expected */ 1705 + case -ENOSYS: /* during rmmod -ENOSYS is expected */ 1706 + dev_dbg(led_cdev->dev, "Failed to write RGB profile: %i\n", ret); 1707 + break; 1708 + default: 1709 + dev_err(led_cdev->dev, "Failed to write RGB profile: %i\n", ret); 1710 + } 1711 + } 1712 + 1713 + #define LEGO_DEVICE_ATTR_RW(_name, _attrname, _dtype, _rtype, _group) \ 1714 + static ssize_t _name##_store(struct device *dev, \ 1715 + struct device_attribute *attr, \ 1716 + const char *buf, size_t count) \ 1717 + { \ 1718 + return _group##_store(dev, attr, buf, count, _name.index, \ 1719 + _dtype); \ 1720 + } \ 1721 + static ssize_t _name##_show(struct device *dev, \ 1722 + struct device_attribute *attr, char *buf) \ 1723 + { \ 1724 + return _group##_show(dev, attr, buf, _name.index, _dtype); \ 1725 + } \ 1726 + static ssize_t _name##_##_rtype##_show( \ 1727 + struct device *dev, struct device_attribute *attr, char *buf) \ 1728 + { \ 1729 + return _group##_options(dev, attr, buf, _name.index); \ 1730 + } \ 1731 + static DEVICE_ATTR_RW_NAMED(_name, _attrname) 1732 + 1733 + #define LEGO_DEVICE_ATTR_WO(_name, _attrname, _dtype, _group) \ 1734 + static ssize_t _name##_store(struct device *dev, \ 1735 + struct device_attribute *attr, \ 1736 + const char *buf, size_t count) \ 1737 + { \ 1738 + return _group##_store(dev, attr, buf, count, _name.index, \ 1739 + _dtype); \ 1740 + } \ 1741 + static DEVICE_ATTR_WO_NAMED(_name, _attrname) 1742 + 1743 + #define LEGO_DEVICE_ATTR_RO(_name, _attrname, _dtype, _group) \ 1744 + static ssize_t _name##_show(struct device *dev, \ 1745 + struct device_attribute *attr, char *buf) \ 1746 + { \ 1747 + return _group##_show(dev, attr, buf, _name.index, _dtype); \ 1748 + } \ 1749 + static DEVICE_ATTR_RO_NAMED(_name, _attrname) 1750 + 1751 + #define LEGO_CAL_DEVICE_ATTR(_name, _attrname, _scmd, _dtype, _rtype) \ 1752 + static ssize_t _name##_store(struct device *dev, \ 1753 + struct device_attribute *attr, \ 1754 + const char *buf, size_t count) \ 1755 + { \ 1756 + return calibrate_config_store(dev, attr, buf, _name.index, \ 1757 + _scmd, count, _dtype); \ 1758 + } \ 1759 + static ssize_t _name##_##_rtype##_show( \ 1760 + struct device *dev, struct device_attribute *attr, char *buf) \ 1761 + { \ 1762 + return calibrate_config_options(dev, attr, buf); \ 1763 + } \ 1764 + static DEVICE_ATTR_WO_NAMED(_name, _attrname) 1765 + 1766 + #define LEGO_DEVICE_STATUS_ATTR(_name, _attrname, _scmd, _dtype) \ 1767 + static ssize_t _name##_show(struct device *dev, \ 1768 + struct device_attribute *attr, char *buf) \ 1769 + { \ 1770 + return device_status_show(dev, attr, buf, _name.index, _scmd, \ 1771 + _dtype); \ 1772 + } \ 1773 + static DEVICE_ATTR_RO_NAMED(_name, _attrname) 1774 + 1775 + /* Gamepad - MCU */ 1776 + static struct go_cfg_attr version_product_mcu = { PRODUCT_VERSION }; 1777 + LEGO_DEVICE_ATTR_RO(version_product_mcu, "product_version", USB_MCU, version); 1778 + 1779 + static struct go_cfg_attr version_protocol_mcu = { PROTOCOL_VERSION }; 1780 + LEGO_DEVICE_ATTR_RO(version_protocol_mcu, "protocol_version", USB_MCU, version); 1781 + 1782 + static struct go_cfg_attr version_firmware_mcu = { FIRMWARE_VERSION }; 1783 + LEGO_DEVICE_ATTR_RO(version_firmware_mcu, "firmware_version", USB_MCU, version); 1784 + 1785 + static struct go_cfg_attr version_hardware_mcu = { HARDWARE_VERSION }; 1786 + LEGO_DEVICE_ATTR_RO(version_hardware_mcu, "hardware_version", USB_MCU, version); 1787 + 1788 + static struct go_cfg_attr version_gen_mcu = { HARDWARE_GENERATION }; 1789 + LEGO_DEVICE_ATTR_RO(version_gen_mcu, "hardware_generation", USB_MCU, version); 1790 + 1791 + static struct go_cfg_attr fps_switch_status = { FEATURE_FPS_SWITCH_STATUS }; 1792 + LEGO_DEVICE_ATTR_RO(fps_switch_status, "fps_switch_status", UNSPECIFIED, 1793 + feature_status); 1794 + 1795 + static struct go_cfg_attr gamepad_mode = { FEATURE_GAMEPAD_MODE }; 1796 + LEGO_DEVICE_ATTR_RW(gamepad_mode, "mode", UNSPECIFIED, index, feature_status); 1797 + static DEVICE_ATTR_RO_NAMED(gamepad_mode_index, "mode_index"); 1798 + 1799 + static struct go_cfg_attr reset_mcu = { FEATURE_RESET_GAMEPAD }; 1800 + LEGO_DEVICE_ATTR_WO(reset_mcu, "reset_mcu", USB_MCU, feature_status); 1801 + 1802 + static struct go_cfg_attr gamepad_rumble_intensity = { MOTOR_INTENSITY }; 1803 + LEGO_DEVICE_ATTR_RW(gamepad_rumble_intensity, "rumble_intensity", UNSPECIFIED, 1804 + index, motor_config); 1805 + static DEVICE_ATTR_RO_NAMED(gamepad_rumble_intensity_index, 1806 + "rumble_intensity_index"); 1807 + 1808 + static DEVICE_ATTR_RW(fps_mode_dpi); 1809 + static DEVICE_ATTR_RO(fps_mode_dpi_index); 1810 + 1811 + static DEVICE_ATTR_RW(os_mode); 1812 + static DEVICE_ATTR_RO(os_mode_index); 1813 + 1814 + static struct attribute *mcu_attrs[] = { 1815 + &dev_attr_fps_mode_dpi.attr, 1816 + &dev_attr_fps_mode_dpi_index.attr, 1817 + &dev_attr_fps_switch_status.attr, 1818 + &dev_attr_gamepad_mode.attr, 1819 + &dev_attr_gamepad_mode_index.attr, 1820 + &dev_attr_gamepad_rumble_intensity.attr, 1821 + &dev_attr_gamepad_rumble_intensity_index.attr, 1822 + &dev_attr_os_mode.attr, 1823 + &dev_attr_os_mode_index.attr, 1824 + &dev_attr_reset_mcu.attr, 1825 + &dev_attr_version_firmware_mcu.attr, 1826 + &dev_attr_version_gen_mcu.attr, 1827 + &dev_attr_version_hardware_mcu.attr, 1828 + &dev_attr_version_product_mcu.attr, 1829 + &dev_attr_version_protocol_mcu.attr, 1830 + NULL, 1831 + }; 1832 + 1833 + static const struct attribute_group mcu_attr_group = { 1834 + .attrs = mcu_attrs, 1835 + }; 1836 + 1837 + /* Gamepad - TX Dongle */ 1838 + static struct go_cfg_attr version_product_tx_dongle = { PRODUCT_VERSION }; 1839 + LEGO_DEVICE_ATTR_RO(version_product_tx_dongle, "product_version", TX_DONGLE, version); 1840 + 1841 + static struct go_cfg_attr version_protocol_tx_dongle = { PROTOCOL_VERSION }; 1842 + LEGO_DEVICE_ATTR_RO(version_protocol_tx_dongle, "protocol_version", TX_DONGLE, version); 1843 + 1844 + static struct go_cfg_attr version_firmware_tx_dongle = { FIRMWARE_VERSION }; 1845 + LEGO_DEVICE_ATTR_RO(version_firmware_tx_dongle, "firmware_version", TX_DONGLE, version); 1846 + 1847 + static struct go_cfg_attr version_hardware_tx_dongle = { HARDWARE_VERSION }; 1848 + LEGO_DEVICE_ATTR_RO(version_hardware_tx_dongle, "hardware_version", TX_DONGLE, version); 1849 + 1850 + static struct go_cfg_attr version_gen_tx_dongle = { HARDWARE_GENERATION }; 1851 + LEGO_DEVICE_ATTR_RO(version_gen_tx_dongle, "hardware_generation", TX_DONGLE, version); 1852 + 1853 + static struct go_cfg_attr reset_tx_dongle = { FEATURE_RESET_GAMEPAD }; 1854 + LEGO_DEVICE_ATTR_RO(reset_tx_dongle, "reset", TX_DONGLE, feature_status); 1855 + 1856 + static struct attribute *tx_dongle_attrs[] = { 1857 + &dev_attr_reset_tx_dongle.attr, 1858 + &dev_attr_version_hardware_tx_dongle.attr, 1859 + &dev_attr_version_firmware_tx_dongle.attr, 1860 + &dev_attr_version_gen_tx_dongle.attr, 1861 + &dev_attr_version_product_tx_dongle.attr, 1862 + &dev_attr_version_protocol_tx_dongle.attr, 1863 + NULL, 1864 + }; 1865 + 1866 + static const struct attribute_group tx_dongle_attr_group = { 1867 + .name = "tx_dongle", 1868 + .attrs = tx_dongle_attrs, 1869 + }; 1870 + 1871 + /* Gamepad - Left */ 1872 + static struct go_cfg_attr version_product_left = { PRODUCT_VERSION }; 1873 + LEGO_DEVICE_ATTR_RO(version_product_left, "product_version", LEFT_CONTROLLER, version); 1874 + 1875 + static struct go_cfg_attr version_protocol_left = { PROTOCOL_VERSION }; 1876 + LEGO_DEVICE_ATTR_RO(version_protocol_left, "protocol_version", LEFT_CONTROLLER, version); 1877 + 1878 + static struct go_cfg_attr version_firmware_left = { FIRMWARE_VERSION }; 1879 + LEGO_DEVICE_ATTR_RO(version_firmware_left, "firmware_version", LEFT_CONTROLLER, version); 1880 + 1881 + static struct go_cfg_attr version_hardware_left = { HARDWARE_VERSION }; 1882 + LEGO_DEVICE_ATTR_RO(version_hardware_left, "hardware_version", LEFT_CONTROLLER, version); 1883 + 1884 + static struct go_cfg_attr version_gen_left = { HARDWARE_GENERATION }; 1885 + LEGO_DEVICE_ATTR_RO(version_gen_left, "hardware_generation", LEFT_CONTROLLER, version); 1886 + 1887 + static struct go_cfg_attr auto_sleep_time_left = { FEATURE_AUTO_SLEEP_TIME }; 1888 + LEGO_DEVICE_ATTR_RW(auto_sleep_time_left, "auto_sleep_time", LEFT_CONTROLLER, 1889 + range, feature_status); 1890 + static DEVICE_ATTR_RO_NAMED(auto_sleep_time_left_range, 1891 + "auto_sleep_time_range"); 1892 + 1893 + static struct go_cfg_attr imu_bypass_left = { FEATURE_IMU_BYPASS }; 1894 + LEGO_DEVICE_ATTR_RW(imu_bypass_left, "imu_bypass_enabled", LEFT_CONTROLLER, 1895 + index, feature_status); 1896 + static DEVICE_ATTR_RO_NAMED(imu_bypass_left_index, "imu_bypass_enabled_index"); 1897 + 1898 + static struct go_cfg_attr imu_enabled_left = { FEATURE_IMU_ENABLE }; 1899 + LEGO_DEVICE_ATTR_RW(imu_enabled_left, "imu_enabled", LEFT_CONTROLLER, index, 1900 + feature_status); 1901 + static DEVICE_ATTR_RO_NAMED(imu_enabled_left_index, "imu_enabled_index"); 1902 + 1903 + static struct go_cfg_attr reset_left = { FEATURE_RESET_GAMEPAD }; 1904 + LEGO_DEVICE_ATTR_WO(reset_left, "reset", LEFT_CONTROLLER, feature_status); 1905 + 1906 + static struct go_cfg_attr rumble_mode_left = { RUMBLE_MODE }; 1907 + LEGO_DEVICE_ATTR_RW(rumble_mode_left, "rumble_mode", LEFT_CONTROLLER, index, 1908 + motor_config); 1909 + static DEVICE_ATTR_RO_NAMED(rumble_mode_left_index, "rumble_mode_index"); 1910 + 1911 + static struct go_cfg_attr rumble_notification_left = { VIBRATION_NOTIFY_ENABLE }; 1912 + LEGO_DEVICE_ATTR_RW(rumble_notification_left, "rumble_notification", 1913 + LEFT_CONTROLLER, index, motor_config); 1914 + static DEVICE_ATTR_RO_NAMED(rumble_notification_left_index, 1915 + "rumble_notification_index"); 1916 + 1917 + static struct go_cfg_attr cal_trigg_left = { TRIGGER_CALIBRATE }; 1918 + LEGO_CAL_DEVICE_ATTR(cal_trigg_left, "calibrate_trigger", SET_TRIGGER_CFG, 1919 + LEFT_CONTROLLER, index); 1920 + static DEVICE_ATTR_RO_NAMED(cal_trigg_left_index, "calibrate_trigger_index"); 1921 + 1922 + static struct go_cfg_attr cal_joy_left = { JOYSTICK_CALIBRATE }; 1923 + LEGO_CAL_DEVICE_ATTR(cal_joy_left, "calibrate_joystick", SET_JOYSTICK_CFG, 1924 + LEFT_CONTROLLER, index); 1925 + static DEVICE_ATTR_RO_NAMED(cal_joy_left_index, "calibrate_joystick_index"); 1926 + 1927 + static struct go_cfg_attr cal_gyro_left = { GYRO_CALIBRATE }; 1928 + LEGO_CAL_DEVICE_ATTR(cal_gyro_left, "calibrate_gyro", SET_GYRO_CFG, 1929 + LEFT_CONTROLLER, index); 1930 + static DEVICE_ATTR_RO_NAMED(cal_gyro_left_index, "calibrate_gyro_index"); 1931 + 1932 + static struct go_cfg_attr cal_trigg_left_status = { GET_CAL_STATUS }; 1933 + LEGO_DEVICE_STATUS_ATTR(cal_trigg_left_status, "calibrate_trigger_status", 1934 + LEFT_CONTROLLER, CALDEV_TRIGGER); 1935 + 1936 + static struct go_cfg_attr cal_joy_left_status = { GET_CAL_STATUS }; 1937 + LEGO_DEVICE_STATUS_ATTR(cal_joy_left_status, "calibrate_joystick_status", 1938 + LEFT_CONTROLLER, CALDEV_JOYSTICK); 1939 + 1940 + static struct go_cfg_attr cal_gyro_left_status = { GET_CAL_STATUS }; 1941 + LEGO_DEVICE_STATUS_ATTR(cal_gyro_left_status, "calibrate_gyro_status", 1942 + LEFT_CONTROLLER, CALDEV_GYROSCOPE); 1943 + 1944 + static struct attribute *left_gamepad_attrs[] = { 1945 + &dev_attr_auto_sleep_time_left.attr, 1946 + &dev_attr_auto_sleep_time_left_range.attr, 1947 + &dev_attr_cal_gyro_left.attr, 1948 + &dev_attr_cal_gyro_left_index.attr, 1949 + &dev_attr_cal_gyro_left_status.attr, 1950 + &dev_attr_cal_joy_left.attr, 1951 + &dev_attr_cal_joy_left_index.attr, 1952 + &dev_attr_cal_joy_left_status.attr, 1953 + &dev_attr_cal_trigg_left.attr, 1954 + &dev_attr_cal_trigg_left_index.attr, 1955 + &dev_attr_cal_trigg_left_status.attr, 1956 + &dev_attr_imu_bypass_left.attr, 1957 + &dev_attr_imu_bypass_left_index.attr, 1958 + &dev_attr_imu_enabled_left.attr, 1959 + &dev_attr_imu_enabled_left_index.attr, 1960 + &dev_attr_reset_left.attr, 1961 + &dev_attr_rumble_mode_left.attr, 1962 + &dev_attr_rumble_mode_left_index.attr, 1963 + &dev_attr_rumble_notification_left.attr, 1964 + &dev_attr_rumble_notification_left_index.attr, 1965 + &dev_attr_version_hardware_left.attr, 1966 + &dev_attr_version_firmware_left.attr, 1967 + &dev_attr_version_gen_left.attr, 1968 + &dev_attr_version_product_left.attr, 1969 + &dev_attr_version_protocol_left.attr, 1970 + NULL, 1971 + }; 1972 + 1973 + static const struct attribute_group left_gamepad_attr_group = { 1974 + .name = "left_handle", 1975 + .attrs = left_gamepad_attrs, 1976 + }; 1977 + 1978 + /* Gamepad - Right */ 1979 + static struct go_cfg_attr version_product_right = { PRODUCT_VERSION }; 1980 + LEGO_DEVICE_ATTR_RO(version_product_right, "product_version", RIGHT_CONTROLLER, version); 1981 + 1982 + static struct go_cfg_attr version_protocol_right = { PROTOCOL_VERSION }; 1983 + LEGO_DEVICE_ATTR_RO(version_protocol_right, "protocol_version", RIGHT_CONTROLLER, version); 1984 + 1985 + static struct go_cfg_attr version_firmware_right = { FIRMWARE_VERSION }; 1986 + LEGO_DEVICE_ATTR_RO(version_firmware_right, "firmware_version", RIGHT_CONTROLLER, version); 1987 + 1988 + static struct go_cfg_attr version_hardware_right = { HARDWARE_VERSION }; 1989 + LEGO_DEVICE_ATTR_RO(version_hardware_right, "hardware_version", RIGHT_CONTROLLER, version); 1990 + 1991 + static struct go_cfg_attr version_gen_right = { HARDWARE_GENERATION }; 1992 + LEGO_DEVICE_ATTR_RO(version_gen_right, "hardware_generation", RIGHT_CONTROLLER, version); 1993 + 1994 + static struct go_cfg_attr auto_sleep_time_right = { FEATURE_AUTO_SLEEP_TIME }; 1995 + LEGO_DEVICE_ATTR_RW(auto_sleep_time_right, "auto_sleep_time", RIGHT_CONTROLLER, 1996 + range, feature_status); 1997 + static DEVICE_ATTR_RO_NAMED(auto_sleep_time_right_range, 1998 + "auto_sleep_time_range"); 1999 + 2000 + static struct go_cfg_attr imu_bypass_right = { FEATURE_IMU_BYPASS }; 2001 + LEGO_DEVICE_ATTR_RW(imu_bypass_right, "imu_bypass_enabled", RIGHT_CONTROLLER, 2002 + index, feature_status); 2003 + static DEVICE_ATTR_RO_NAMED(imu_bypass_right_index, "imu_bypass_enabled_index"); 2004 + 2005 + static struct go_cfg_attr imu_enabled_right = { FEATURE_IMU_BYPASS }; 2006 + LEGO_DEVICE_ATTR_RW(imu_enabled_right, "imu_enabled", RIGHT_CONTROLLER, index, 2007 + feature_status); 2008 + static DEVICE_ATTR_RO_NAMED(imu_enabled_right_index, "imu_enabled_index"); 2009 + 2010 + static struct go_cfg_attr reset_right = { FEATURE_RESET_GAMEPAD }; 2011 + LEGO_DEVICE_ATTR_WO(reset_right, "reset", LEFT_CONTROLLER, feature_status); 2012 + 2013 + static struct go_cfg_attr rumble_mode_right = { RUMBLE_MODE }; 2014 + LEGO_DEVICE_ATTR_RW(rumble_mode_right, "rumble_mode", RIGHT_CONTROLLER, index, 2015 + motor_config); 2016 + static DEVICE_ATTR_RO_NAMED(rumble_mode_right_index, "rumble_mode_index"); 2017 + 2018 + static struct go_cfg_attr rumble_notification_right = { VIBRATION_NOTIFY_ENABLE }; 2019 + LEGO_DEVICE_ATTR_RW(rumble_notification_right, "rumble_notification", 2020 + RIGHT_CONTROLLER, index, motor_config); 2021 + static DEVICE_ATTR_RO_NAMED(rumble_notification_right_index, 2022 + "rumble_notification_index"); 2023 + 2024 + static struct go_cfg_attr cal_trigg_right = { TRIGGER_CALIBRATE }; 2025 + LEGO_CAL_DEVICE_ATTR(cal_trigg_right, "calibrate_trigger", SET_TRIGGER_CFG, 2026 + RIGHT_CONTROLLER, index); 2027 + static DEVICE_ATTR_RO_NAMED(cal_trigg_right_index, "calibrate_trigger_index"); 2028 + 2029 + static struct go_cfg_attr cal_joy_right = { JOYSTICK_CALIBRATE }; 2030 + LEGO_CAL_DEVICE_ATTR(cal_joy_right, "calibrate_joystick", SET_JOYSTICK_CFG, 2031 + RIGHT_CONTROLLER, index); 2032 + static DEVICE_ATTR_RO_NAMED(cal_joy_right_index, "calibrate_joystick_index"); 2033 + 2034 + static struct go_cfg_attr cal_gyro_right = { GYRO_CALIBRATE }; 2035 + LEGO_CAL_DEVICE_ATTR(cal_gyro_right, "calibrate_gyro", SET_GYRO_CFG, 2036 + RIGHT_CONTROLLER, index); 2037 + static DEVICE_ATTR_RO_NAMED(cal_gyro_right_index, "calibrate_gyro_index"); 2038 + 2039 + static struct go_cfg_attr cal_trigg_right_status = { GET_CAL_STATUS }; 2040 + LEGO_DEVICE_STATUS_ATTR(cal_trigg_right_status, "calibrate_trigger_status", 2041 + RIGHT_CONTROLLER, CALDEV_TRIGGER); 2042 + 2043 + static struct go_cfg_attr cal_joy_right_status = { GET_CAL_STATUS }; 2044 + LEGO_DEVICE_STATUS_ATTR(cal_joy_right_status, "calibrate_joystick_status", 2045 + RIGHT_CONTROLLER, CALDEV_JOYSTICK); 2046 + 2047 + static struct go_cfg_attr cal_gyro_right_status = { GET_CAL_STATUS }; 2048 + LEGO_DEVICE_STATUS_ATTR(cal_gyro_right_status, "calibrate_gyro_status", 2049 + RIGHT_CONTROLLER, CALDEV_GYROSCOPE); 2050 + 2051 + static struct attribute *right_gamepad_attrs[] = { 2052 + &dev_attr_auto_sleep_time_right.attr, 2053 + &dev_attr_auto_sleep_time_right_range.attr, 2054 + &dev_attr_cal_gyro_right.attr, 2055 + &dev_attr_cal_gyro_right_index.attr, 2056 + &dev_attr_cal_gyro_right_status.attr, 2057 + &dev_attr_cal_joy_right.attr, 2058 + &dev_attr_cal_joy_right_index.attr, 2059 + &dev_attr_cal_joy_right_status.attr, 2060 + &dev_attr_cal_trigg_right.attr, 2061 + &dev_attr_cal_trigg_right_index.attr, 2062 + &dev_attr_cal_trigg_right_status.attr, 2063 + &dev_attr_imu_bypass_right.attr, 2064 + &dev_attr_imu_bypass_right_index.attr, 2065 + &dev_attr_imu_enabled_right.attr, 2066 + &dev_attr_imu_enabled_right_index.attr, 2067 + &dev_attr_reset_right.attr, 2068 + &dev_attr_rumble_mode_right.attr, 2069 + &dev_attr_rumble_mode_right_index.attr, 2070 + &dev_attr_rumble_notification_right.attr, 2071 + &dev_attr_rumble_notification_right_index.attr, 2072 + &dev_attr_version_hardware_right.attr, 2073 + &dev_attr_version_firmware_right.attr, 2074 + &dev_attr_version_gen_right.attr, 2075 + &dev_attr_version_product_right.attr, 2076 + &dev_attr_version_protocol_right.attr, 2077 + NULL, 2078 + }; 2079 + 2080 + static const struct attribute_group right_gamepad_attr_group = { 2081 + .name = "right_handle", 2082 + .attrs = right_gamepad_attrs, 2083 + }; 2084 + 2085 + /* Touchpad */ 2086 + static struct go_cfg_attr touchpad_enabled = { FEATURE_TOUCHPAD_ENABLE }; 2087 + LEGO_DEVICE_ATTR_RW(touchpad_enabled, "enabled", UNSPECIFIED, index, 2088 + feature_status); 2089 + static DEVICE_ATTR_RO_NAMED(touchpad_enabled_index, "enabled_index"); 2090 + 2091 + static struct go_cfg_attr touchpad_vibration_enabled = { TP_VIBRATION_ENABLE }; 2092 + LEGO_DEVICE_ATTR_RW(touchpad_vibration_enabled, "vibration_enabled", UNSPECIFIED, 2093 + index, motor_config); 2094 + static DEVICE_ATTR_RO_NAMED(touchpad_vibration_enabled_index, 2095 + "vibration_enabled_index"); 2096 + 2097 + static struct go_cfg_attr touchpad_vibration_intensity = { TP_VIBRATION_INTENSITY }; 2098 + LEGO_DEVICE_ATTR_RW(touchpad_vibration_intensity, "vibration_intensity", 2099 + UNSPECIFIED, index, motor_config); 2100 + static DEVICE_ATTR_RO_NAMED(touchpad_vibration_intensity_index, 2101 + "vibration_intensity_index"); 2102 + 2103 + static struct attribute *touchpad_attrs[] = { 2104 + &dev_attr_touchpad_enabled.attr, 2105 + &dev_attr_touchpad_enabled_index.attr, 2106 + &dev_attr_touchpad_vibration_enabled.attr, 2107 + &dev_attr_touchpad_vibration_enabled_index.attr, 2108 + &dev_attr_touchpad_vibration_intensity.attr, 2109 + &dev_attr_touchpad_vibration_intensity_index.attr, 2110 + NULL, 2111 + }; 2112 + 2113 + static const struct attribute_group touchpad_attr_group = { 2114 + .name = "touchpad", 2115 + .attrs = touchpad_attrs, 2116 + }; 2117 + 2118 + static const struct attribute_group *top_level_attr_groups[] = { 2119 + &mcu_attr_group, &tx_dongle_attr_group, 2120 + &left_gamepad_attr_group, &right_gamepad_attr_group, 2121 + &touchpad_attr_group, NULL, 2122 + }; 2123 + 2124 + /* RGB */ 2125 + static struct go_cfg_attr rgb_enabled = { FEATURE_LIGHT_ENABLE }; 2126 + 2127 + LEGO_DEVICE_ATTR_RW(rgb_enabled, "enabled", UNSPECIFIED, index, feature_status); 2128 + static DEVICE_ATTR_RO_NAMED(rgb_effect_index, "effect_index"); 2129 + static DEVICE_ATTR_RO_NAMED(rgb_enabled_index, "enabled_index"); 2130 + static DEVICE_ATTR_RO_NAMED(rgb_mode_index, "mode_index"); 2131 + static DEVICE_ATTR_RO_NAMED(rgb_profile_range, "profile_range"); 2132 + static DEVICE_ATTR_RO_NAMED(rgb_speed_range, "speed_range"); 2133 + static DEVICE_ATTR_RW_NAMED(rgb_effect, "effect"); 2134 + static DEVICE_ATTR_RW_NAMED(rgb_mode, "mode"); 2135 + static DEVICE_ATTR_RW_NAMED(rgb_profile, "profile"); 2136 + static DEVICE_ATTR_RW_NAMED(rgb_speed, "speed"); 2137 + 2138 + static struct attribute *go_rgb_attrs[] = { 2139 + &dev_attr_rgb_effect.attr, 2140 + &dev_attr_rgb_effect_index.attr, 2141 + &dev_attr_rgb_enabled.attr, 2142 + &dev_attr_rgb_enabled_index.attr, 2143 + &dev_attr_rgb_mode.attr, 2144 + &dev_attr_rgb_mode_index.attr, 2145 + &dev_attr_rgb_profile.attr, 2146 + &dev_attr_rgb_profile_range.attr, 2147 + &dev_attr_rgb_speed.attr, 2148 + &dev_attr_rgb_speed_range.attr, 2149 + NULL, 2150 + }; 2151 + 2152 + static struct attribute_group rgb_attr_group = { 2153 + .attrs = go_rgb_attrs, 2154 + }; 2155 + 2156 + static struct mc_subled go_rgb_subled_info[] = { 2157 + { 2158 + .color_index = LED_COLOR_ID_RED, 2159 + .brightness = 0x50, 2160 + .intensity = 0x24, 2161 + .channel = 0x1, 2162 + }, 2163 + { 2164 + .color_index = LED_COLOR_ID_GREEN, 2165 + .brightness = 0x50, 2166 + .intensity = 0x22, 2167 + .channel = 0x2, 2168 + }, 2169 + { 2170 + .color_index = LED_COLOR_ID_BLUE, 2171 + .brightness = 0x50, 2172 + .intensity = 0x99, 2173 + .channel = 0x3, 2174 + }, 2175 + }; 2176 + 2177 + static struct led_classdev_mc go_cdev_rgb = { 2178 + .led_cdev = { 2179 + .name = "go:rgb:joystick_rings", 2180 + .color = LED_COLOR_ID_RGB, 2181 + .brightness = 0x50, 2182 + .max_brightness = 0x64, 2183 + .brightness_set = hid_go_brightness_set, 2184 + }, 2185 + .num_colors = ARRAY_SIZE(go_rgb_subled_info), 2186 + .subled_info = go_rgb_subled_info, 2187 + }; 2188 + 2189 + static void cfg_setup(struct work_struct *work) 2190 + { 2191 + int ret; 2192 + 2193 + /* MCU Version Attrs */ 2194 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, 2195 + PRODUCT_VERSION, USB_MCU, NULL, 0); 2196 + if (ret < 0) { 2197 + dev_err(&drvdata.hdev->dev, 2198 + "Failed to retrieve USB_MCU Product Version: %i\n", ret); 2199 + return; 2200 + } 2201 + 2202 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, 2203 + PROTOCOL_VERSION, USB_MCU, NULL, 0); 2204 + if (ret < 0) { 2205 + dev_err(&drvdata.hdev->dev, 2206 + "Failed to retrieve USB_MCU Protocol Version: %i\n", ret); 2207 + return; 2208 + } 2209 + 2210 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, 2211 + FIRMWARE_VERSION, USB_MCU, NULL, 0); 2212 + if (ret < 0) { 2213 + dev_err(&drvdata.hdev->dev, 2214 + "Failed to retrieve USB_MCU Firmware Version: %i\n", ret); 2215 + return; 2216 + } 2217 + 2218 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, 2219 + HARDWARE_VERSION, USB_MCU, NULL, 0); 2220 + if (ret < 0) { 2221 + dev_err(&drvdata.hdev->dev, 2222 + "Failed to retrieve USB_MCU Hardware Version: %i\n", ret); 2223 + return; 2224 + } 2225 + 2226 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, 2227 + HARDWARE_GENERATION, USB_MCU, NULL, 0); 2228 + if (ret < 0) { 2229 + dev_err(&drvdata.hdev->dev, 2230 + "Failed to retrieve USB_MCU Hardware Generation: %i\n", ret); 2231 + return; 2232 + } 2233 + 2234 + /* TX Dongle Version Attrs */ 2235 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, 2236 + PRODUCT_VERSION, TX_DONGLE, NULL, 0); 2237 + if (ret < 0) { 2238 + dev_err(&drvdata.hdev->dev, 2239 + "Failed to retrieve TX_DONGLE Product Version: %i\n", ret); 2240 + return; 2241 + } 2242 + 2243 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, 2244 + PROTOCOL_VERSION, TX_DONGLE, NULL, 0); 2245 + if (ret < 0) { 2246 + dev_err(&drvdata.hdev->dev, 2247 + "Failed to retrieve TX_DONGLE Protocol Version: %i\n", ret); 2248 + return; 2249 + } 2250 + 2251 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, 2252 + FIRMWARE_VERSION, TX_DONGLE, NULL, 0); 2253 + if (ret < 0) { 2254 + dev_err(&drvdata.hdev->dev, 2255 + "Failed to retrieve TX_DONGLE Firmware Version: %i\n", ret); 2256 + return; 2257 + } 2258 + 2259 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, 2260 + HARDWARE_VERSION, TX_DONGLE, NULL, 0); 2261 + if (ret < 0) { 2262 + dev_err(&drvdata.hdev->dev, 2263 + "Failed to retrieve TX_DONGLE Hardware Version: %i\n", ret); 2264 + return; 2265 + } 2266 + 2267 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, 2268 + HARDWARE_GENERATION, TX_DONGLE, NULL, 0); 2269 + if (ret < 0) { 2270 + dev_err(&drvdata.hdev->dev, 2271 + "Failed to retrieve TX_DONGLE Hardware Generation: %i\n", ret); 2272 + return; 2273 + } 2274 + 2275 + /* Left Handle Version Attrs */ 2276 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, 2277 + PRODUCT_VERSION, LEFT_CONTROLLER, NULL, 0); 2278 + if (ret < 0) { 2279 + dev_err(&drvdata.hdev->dev, 2280 + "Failed to retrieve LEFT_CONTROLLER Product Version: %i\n", ret); 2281 + return; 2282 + } 2283 + 2284 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, 2285 + PROTOCOL_VERSION, LEFT_CONTROLLER, NULL, 0); 2286 + if (ret < 0) { 2287 + dev_err(&drvdata.hdev->dev, 2288 + "Failed to retrieve LEFT_CONTROLLER Protocol Version: %i\n", ret); 2289 + return; 2290 + } 2291 + 2292 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, 2293 + FIRMWARE_VERSION, LEFT_CONTROLLER, NULL, 0); 2294 + if (ret < 0) { 2295 + dev_err(&drvdata.hdev->dev, 2296 + "Failed to retrieve LEFT_CONTROLLER Firmware Version: %i\n", ret); 2297 + return; 2298 + } 2299 + 2300 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, 2301 + HARDWARE_VERSION, LEFT_CONTROLLER, NULL, 0); 2302 + if (ret < 0) { 2303 + dev_err(&drvdata.hdev->dev, 2304 + "Failed to retrieve LEFT_CONTROLLER Hardware Version: %i\n", ret); 2305 + return; 2306 + } 2307 + 2308 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, 2309 + HARDWARE_GENERATION, LEFT_CONTROLLER, NULL, 0); 2310 + if (ret < 0) { 2311 + dev_err(&drvdata.hdev->dev, 2312 + "Failed to retrieve LEFT_CONTROLLER Hardware Generation: %i\n", ret); 2313 + return; 2314 + } 2315 + 2316 + /* Right Handle Version Attrs */ 2317 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, 2318 + PRODUCT_VERSION, RIGHT_CONTROLLER, NULL, 0); 2319 + if (ret < 0) { 2320 + dev_err(&drvdata.hdev->dev, 2321 + "Failed to retrieve RIGHT_CONTROLLER Product Version: %i\n", ret); 2322 + return; 2323 + } 2324 + 2325 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, 2326 + PROTOCOL_VERSION, RIGHT_CONTROLLER, NULL, 0); 2327 + if (ret < 0) { 2328 + dev_err(&drvdata.hdev->dev, 2329 + "Failed to retrieve RIGHT_CONTROLLER Protocol Version: %i\n", ret); 2330 + return; 2331 + } 2332 + 2333 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, 2334 + FIRMWARE_VERSION, RIGHT_CONTROLLER, NULL, 0); 2335 + if (ret < 0) { 2336 + dev_err(&drvdata.hdev->dev, 2337 + "Failed to retrieve RIGHT_CONTROLLER Firmware Version: %i\n", ret); 2338 + return; 2339 + } 2340 + 2341 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, 2342 + HARDWARE_VERSION, RIGHT_CONTROLLER, NULL, 0); 2343 + if (ret < 0) { 2344 + dev_err(&drvdata.hdev->dev, 2345 + "Failed to retrieve RIGHT_CONTROLLER Hardware Version: %i\n", ret); 2346 + return; 2347 + } 2348 + 2349 + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, 2350 + HARDWARE_GENERATION, RIGHT_CONTROLLER, NULL, 0); 2351 + if (ret < 0) { 2352 + dev_err(&drvdata.hdev->dev, 2353 + "Failed to retrieve RIGHT_CONTROLLER Hardware Generation: %i\n", ret); 2354 + return; 2355 + } 2356 + } 2357 + 2358 + static int hid_go_cfg_probe(struct hid_device *hdev, 2359 + const struct hid_device_id *_id) 2360 + { 2361 + unsigned char *buf; 2362 + int ret; 2363 + 2364 + buf = devm_kzalloc(&hdev->dev, GO_PACKET_SIZE, GFP_KERNEL); 2365 + if (!buf) 2366 + return -ENOMEM; 2367 + 2368 + hid_set_drvdata(hdev, &drvdata); 2369 + drvdata.hdev = hdev; 2370 + mutex_init(&drvdata.cfg_mutex); 2371 + 2372 + ret = sysfs_create_groups(&hdev->dev.kobj, top_level_attr_groups); 2373 + if (ret) { 2374 + dev_err_probe(&hdev->dev, ret, 2375 + "Failed to create gamepad configuration attributes\n"); 2376 + return ret; 2377 + } 2378 + 2379 + ret = devm_led_classdev_multicolor_register(&hdev->dev, &go_cdev_rgb); 2380 + if (ret) { 2381 + dev_err_probe(&hdev->dev, ret, "Failed to create RGB device\n"); 2382 + return ret; 2383 + } 2384 + 2385 + ret = devm_device_add_group(go_cdev_rgb.led_cdev.dev, &rgb_attr_group); 2386 + if (ret) { 2387 + dev_err_probe(&hdev->dev, ret, 2388 + "Failed to create RGB configuration attributes\n"); 2389 + return ret; 2390 + } 2391 + 2392 + drvdata.led_cdev = &go_cdev_rgb.led_cdev; 2393 + 2394 + init_completion(&drvdata.send_cmd_complete); 2395 + 2396 + /* Executing calls prior to returning from probe will lock the MCU. Schedule 2397 + * initial data call after probe has completed and MCU can accept calls. 2398 + */ 2399 + INIT_DELAYED_WORK(&drvdata.go_cfg_setup, &cfg_setup); 2400 + ret = schedule_delayed_work(&drvdata.go_cfg_setup, msecs_to_jiffies(2)); 2401 + if (!ret) { 2402 + dev_err(&hdev->dev, 2403 + "Failed to schedule startup delayed work\n"); 2404 + return -ENODEV; 2405 + } 2406 + return 0; 2407 + } 2408 + 2409 + static void hid_go_cfg_remove(struct hid_device *hdev) 2410 + { 2411 + guard(mutex)(&drvdata.cfg_mutex); 2412 + sysfs_remove_groups(&hdev->dev.kobj, top_level_attr_groups); 2413 + hid_hw_close(hdev); 2414 + hid_hw_stop(hdev); 2415 + hid_set_drvdata(hdev, NULL); 2416 + } 2417 + 2418 + static int hid_go_probe(struct hid_device *hdev, const struct hid_device_id *id) 2419 + { 2420 + int ret, ep; 2421 + 2422 + hdev->quirks |= HID_QUIRK_INPUT_PER_APP | HID_QUIRK_MULTI_INPUT; 2423 + 2424 + ret = hid_parse(hdev); 2425 + if (ret) { 2426 + hid_err(hdev, "Parse failed\n"); 2427 + return ret; 2428 + } 2429 + 2430 + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 2431 + if (ret) { 2432 + hid_err(hdev, "Failed to start HID device\n"); 2433 + return ret; 2434 + } 2435 + 2436 + ret = hid_hw_open(hdev); 2437 + if (ret) { 2438 + hid_err(hdev, "Failed to open HID device\n"); 2439 + hid_hw_stop(hdev); 2440 + return ret; 2441 + } 2442 + 2443 + ep = get_endpoint_address(hdev); 2444 + if (ep != GO_GP_INTF_IN) { 2445 + dev_dbg(&hdev->dev, "Started interface %x as generic HID device\n", ep); 2446 + return 0; 2447 + } 2448 + 2449 + ret = hid_go_cfg_probe(hdev, id); 2450 + if (ret) 2451 + dev_err_probe(&hdev->dev, ret, "Failed to start configuration interface\n"); 2452 + 2453 + dev_dbg(&hdev->dev, "Started Legion Go HID Device: %x\n", ep); 2454 + 2455 + return ret; 2456 + } 2457 + 2458 + static void hid_go_remove(struct hid_device *hdev) 2459 + { 2460 + int ep = get_endpoint_address(hdev); 2461 + 2462 + if (ep <= 0) 2463 + return; 2464 + 2465 + switch (ep) { 2466 + case GO_GP_INTF_IN: 2467 + hid_go_cfg_remove(hdev); 2468 + break; 2469 + default: 2470 + hid_hw_close(hdev); 2471 + hid_hw_stop(hdev); 2472 + break; 2473 + } 2474 + } 2475 + 2476 + static const struct hid_device_id hid_go_devices[] = { 2477 + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, 2478 + USB_DEVICE_ID_LENOVO_LEGION_GO2_XINPUT) }, 2479 + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, 2480 + USB_DEVICE_ID_LENOVO_LEGION_GO2_DINPUT) }, 2481 + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, 2482 + USB_DEVICE_ID_LENOVO_LEGION_GO2_DUAL_DINPUT) }, 2483 + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, 2484 + USB_DEVICE_ID_LENOVO_LEGION_GO2_FPS) }, 2485 + {} 2486 + }; 2487 + MODULE_DEVICE_TABLE(hid, hid_go_devices); 2488 + 2489 + static struct hid_driver hid_lenovo_go = { 2490 + .name = "hid-lenovo-go", 2491 + .id_table = hid_go_devices, 2492 + .probe = hid_go_probe, 2493 + .remove = hid_go_remove, 2494 + .raw_event = hid_go_raw_event, 2495 + }; 2496 + module_hid_driver(hid_lenovo_go); 2497 + 2498 + MODULE_AUTHOR("Derek J. Clark"); 2499 + MODULE_DESCRIPTION("HID Driver for Lenovo Legion Go Series Gamepads."); 2500 + MODULE_LICENSE("GPL");
+46
include/linux/device.h
··· 190 190 struct device_attribute dev_attr_##_name = __ATTR_RW_MODE(_name, 0600) 191 191 192 192 /** 193 + * DEVICE_ATTR_RW_NAMED - Define a read-write device attribute with a sysfs name 194 + * that differs from the function name. 195 + * @_name: Attribute function preface 196 + * @_attrname: Attribute name as it wil be exposed in the sysfs. 197 + * 198 + * Like DEVICE_ATTR_RW(), but allows for reusing names under separate paths in 199 + * the same driver. 200 + */ 201 + #define DEVICE_ATTR_RW_NAMED(_name, _attrname) \ 202 + struct device_attribute dev_attr_##_name = { \ 203 + .attr = { .name = _attrname, .mode = 0644 }, \ 204 + .show = _name##_show, \ 205 + .store = _name##_store, \ 206 + } 207 + 208 + /** 193 209 * DEVICE_ATTR_RO - Define a readable device attribute. 194 210 * @_name: Attribute name. 195 211 * ··· 224 208 struct device_attribute dev_attr_##_name = __ATTR_RO_MODE(_name, 0400) 225 209 226 210 /** 211 + * DEVICE_ATTR_RO_NAMED - Define a read-only device attribute with a sysfs name 212 + * that differs from the function name. 213 + * @_name: Attribute function preface 214 + * @_attrname: Attribute name as it wil be exposed in the sysfs. 215 + * 216 + * Like DEVICE_ATTR_RO(), but allows for reusing names under separate paths in 217 + * the same driver. 218 + */ 219 + #define DEVICE_ATTR_RO_NAMED(_name, _attrname) \ 220 + struct device_attribute dev_attr_##_name = { \ 221 + .attr = { .name = _attrname, .mode = 0444 }, \ 222 + .show = _name##_show, \ 223 + } 224 + 225 + /** 227 226 * DEVICE_ATTR_WO - Define an admin-only writable device attribute. 228 227 * @_name: Attribute name. 229 228 * ··· 246 215 */ 247 216 #define DEVICE_ATTR_WO(_name) \ 248 217 struct device_attribute dev_attr_##_name = __ATTR_WO(_name) 218 + 219 + /** 220 + * DEVICE_ATTR_WO_NAMED - Define a read-only device attribute with a sysfs name 221 + * that differs from the function name. 222 + * @_name: Attribute function preface 223 + * @_attrname: Attribute name as it wil be exposed in the sysfs. 224 + * 225 + * Like DEVICE_ATTR_WO(), but allows for reusing names under separate paths in 226 + * the same driver. 227 + */ 228 + #define DEVICE_ATTR_WO_NAMED(_name, _attrname) \ 229 + struct device_attribute dev_attr_##_name = { \ 230 + .attr = { .name = _attrname, .mode = 0200 }, \ 231 + .store = _name##_store, \ 232 + } 249 233 250 234 /** 251 235 * DEVICE_ULONG_ATTR - Define a device attribute backed by an unsigned long.
+1
include/linux/hid.h
··· 721 721 char name[128]; /* Device name */ 722 722 char phys[64]; /* Device physical location */ 723 723 char uniq[64]; /* Device unique identifier (serial #) */ 724 + u64 firmware_version; /* Firmware version */ 724 725 725 726 void *driver_data; 726 727