hid-gt683r.c (6428B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * MSI GT683R led driver 4 * 5 * Copyright (c) 2014 Janne Kanniainen <janne.kanniainen@gmail.com> 6 */ 7 8#include <linux/device.h> 9#include <linux/hid.h> 10#include <linux/kernel.h> 11#include <linux/leds.h> 12#include <linux/module.h> 13 14#include "hid-ids.h" 15 16#define GT683R_BUFFER_SIZE 8 17 18/* 19 * GT683R_LED_OFF: all LEDs are off 20 * GT683R_LED_AUDIO: LEDs brightness depends on sound level 21 * GT683R_LED_BREATHING: LEDs brightness varies at human breathing rate 22 * GT683R_LED_NORMAL: LEDs are fully on when enabled 23 */ 24enum gt683r_led_mode { 25 GT683R_LED_OFF = 0, 26 GT683R_LED_AUDIO = 2, 27 GT683R_LED_BREATHING = 3, 28 GT683R_LED_NORMAL = 5 29}; 30 31enum gt683r_panels { 32 GT683R_LED_BACK = 0, 33 GT683R_LED_SIDE = 1, 34 GT683R_LED_FRONT = 2, 35 GT683R_LED_COUNT, 36}; 37 38static const char * const gt683r_panel_names[] = { 39 "back", 40 "side", 41 "front", 42}; 43 44struct gt683r_led { 45 struct hid_device *hdev; 46 struct led_classdev led_devs[GT683R_LED_COUNT]; 47 struct mutex lock; 48 struct work_struct work; 49 enum led_brightness brightnesses[GT683R_LED_COUNT]; 50 enum gt683r_led_mode mode; 51}; 52 53static const struct hid_device_id gt683r_led_id[] = { 54 { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, 55 { } 56}; 57MODULE_DEVICE_TABLE(hid, gt683r_led_id); 58 59static void gt683r_brightness_set(struct led_classdev *led_cdev, 60 enum led_brightness brightness) 61{ 62 int i; 63 struct device *dev = led_cdev->dev->parent; 64 struct hid_device *hdev = to_hid_device(dev); 65 struct gt683r_led *led = hid_get_drvdata(hdev); 66 67 for (i = 0; i < GT683R_LED_COUNT; i++) { 68 if (led_cdev == &led->led_devs[i]) 69 break; 70 } 71 72 if (i < GT683R_LED_COUNT) { 73 led->brightnesses[i] = brightness; 74 schedule_work(&led->work); 75 } 76} 77 78static ssize_t mode_show(struct device *dev, 79 struct device_attribute *attr, 80 char *buf) 81{ 82 u8 sysfs_mode; 83 struct hid_device *hdev = to_hid_device(dev->parent); 84 struct gt683r_led *led = hid_get_drvdata(hdev); 85 86 if (led->mode == GT683R_LED_NORMAL) 87 sysfs_mode = 0; 88 else if (led->mode == GT683R_LED_AUDIO) 89 sysfs_mode = 1; 90 else 91 sysfs_mode = 2; 92 93 return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode); 94} 95 96static ssize_t mode_store(struct device *dev, 97 struct device_attribute *attr, 98 const char *buf, size_t count) 99{ 100 u8 sysfs_mode; 101 struct hid_device *hdev = to_hid_device(dev->parent); 102 struct gt683r_led *led = hid_get_drvdata(hdev); 103 104 105 if (kstrtou8(buf, 10, &sysfs_mode) || sysfs_mode > 2) 106 return -EINVAL; 107 108 mutex_lock(&led->lock); 109 110 if (sysfs_mode == 0) 111 led->mode = GT683R_LED_NORMAL; 112 else if (sysfs_mode == 1) 113 led->mode = GT683R_LED_AUDIO; 114 else 115 led->mode = GT683R_LED_BREATHING; 116 117 mutex_unlock(&led->lock); 118 schedule_work(&led->work); 119 120 return count; 121} 122 123static int gt683r_led_snd_msg(struct gt683r_led *led, u8 *msg) 124{ 125 int ret; 126 127 ret = hid_hw_raw_request(led->hdev, msg[0], msg, GT683R_BUFFER_SIZE, 128 HID_FEATURE_REPORT, HID_REQ_SET_REPORT); 129 if (ret != GT683R_BUFFER_SIZE) { 130 hid_err(led->hdev, 131 "failed to send set report request: %i\n", ret); 132 if (ret < 0) 133 return ret; 134 return -EIO; 135 } 136 137 return 0; 138} 139 140static int gt683r_leds_set(struct gt683r_led *led, u8 leds) 141{ 142 int ret; 143 u8 *buffer; 144 145 buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); 146 if (!buffer) 147 return -ENOMEM; 148 149 buffer[0] = 0x01; 150 buffer[1] = 0x02; 151 buffer[2] = 0x30; 152 buffer[3] = leds; 153 ret = gt683r_led_snd_msg(led, buffer); 154 155 kfree(buffer); 156 return ret; 157} 158 159static int gt683r_mode_set(struct gt683r_led *led, u8 mode) 160{ 161 int ret; 162 u8 *buffer; 163 164 buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); 165 if (!buffer) 166 return -ENOMEM; 167 168 buffer[0] = 0x01; 169 buffer[1] = 0x02; 170 buffer[2] = 0x20; 171 buffer[3] = mode; 172 buffer[4] = 0x01; 173 ret = gt683r_led_snd_msg(led, buffer); 174 175 kfree(buffer); 176 return ret; 177} 178 179static void gt683r_led_work(struct work_struct *work) 180{ 181 int i; 182 u8 leds = 0; 183 u8 mode; 184 struct gt683r_led *led = container_of(work, struct gt683r_led, work); 185 186 mutex_lock(&led->lock); 187 188 for (i = 0; i < GT683R_LED_COUNT; i++) { 189 if (led->brightnesses[i]) 190 leds |= BIT(i); 191 } 192 193 if (gt683r_leds_set(led, leds)) 194 goto fail; 195 196 if (leds) 197 mode = led->mode; 198 else 199 mode = GT683R_LED_OFF; 200 201 gt683r_mode_set(led, mode); 202fail: 203 mutex_unlock(&led->lock); 204} 205 206static DEVICE_ATTR_RW(mode); 207 208static struct attribute *gt683r_led_attrs[] = { 209 &dev_attr_mode.attr, 210 NULL 211}; 212 213static const struct attribute_group gt683r_led_group = { 214 .name = "gt683r", 215 .attrs = gt683r_led_attrs, 216}; 217 218static const struct attribute_group *gt683r_led_groups[] = { 219 >683r_led_group, 220 NULL 221}; 222 223static int gt683r_led_probe(struct hid_device *hdev, 224 const struct hid_device_id *id) 225{ 226 int i; 227 int ret; 228 int name_sz; 229 char *name; 230 struct gt683r_led *led; 231 232 led = devm_kzalloc(&hdev->dev, sizeof(*led), GFP_KERNEL); 233 if (!led) 234 return -ENOMEM; 235 236 mutex_init(&led->lock); 237 INIT_WORK(&led->work, gt683r_led_work); 238 239 led->mode = GT683R_LED_NORMAL; 240 led->hdev = hdev; 241 hid_set_drvdata(hdev, led); 242 243 ret = hid_parse(hdev); 244 if (ret) { 245 hid_err(hdev, "hid parsing failed\n"); 246 return ret; 247 } 248 249 ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); 250 if (ret) { 251 hid_err(hdev, "hw start failed\n"); 252 return ret; 253 } 254 255 for (i = 0; i < GT683R_LED_COUNT; i++) { 256 name_sz = strlen(dev_name(&hdev->dev)) + 257 strlen(gt683r_panel_names[i]) + 3; 258 259 name = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL); 260 if (!name) { 261 ret = -ENOMEM; 262 goto fail; 263 } 264 265 snprintf(name, name_sz, "%s::%s", 266 dev_name(&hdev->dev), gt683r_panel_names[i]); 267 led->led_devs[i].name = name; 268 led->led_devs[i].max_brightness = 1; 269 led->led_devs[i].brightness_set = gt683r_brightness_set; 270 led->led_devs[i].groups = gt683r_led_groups; 271 272 ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); 273 if (ret) { 274 hid_err(hdev, "could not register led device\n"); 275 goto fail; 276 } 277 } 278 279 return 0; 280 281fail: 282 for (i = i - 1; i >= 0; i--) 283 led_classdev_unregister(&led->led_devs[i]); 284 hid_hw_stop(hdev); 285 return ret; 286} 287 288static void gt683r_led_remove(struct hid_device *hdev) 289{ 290 int i; 291 struct gt683r_led *led = hid_get_drvdata(hdev); 292 293 for (i = 0; i < GT683R_LED_COUNT; i++) 294 led_classdev_unregister(&led->led_devs[i]); 295 flush_work(&led->work); 296 hid_hw_stop(hdev); 297} 298 299static struct hid_driver gt683r_led_driver = { 300 .probe = gt683r_led_probe, 301 .remove = gt683r_led_remove, 302 .name = "gt683r_led", 303 .id_table = gt683r_led_id, 304}; 305 306module_hid_driver(gt683r_led_driver); 307 308MODULE_AUTHOR("Janne Kanniainen"); 309MODULE_DESCRIPTION("MSI GT683R led driver"); 310MODULE_LICENSE("GPL");