2 * MSI GT683R led driver
4 * Copyright (c) 2014 Janne Kanniainen <janne.kanniainen@gmail.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of
9 * the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
18 #include <linux/device.h>
19 #include <linux/hid.h>
20 #include <linux/kernel.h>
21 #include <linux/leds.h>
22 #include <linux/module.h>
26 #define GT683R_BUFFER_SIZE 8
29 * GT683R_LED_OFF: all LEDs are off
30 * GT683R_LED_AUDIO: LEDs brightness depends on sound level
31 * GT683R_LED_BREATHING: LEDs brightness varies at human breathing rate
32 * GT683R_LED_NORMAL: LEDs are fully on when enabled
34 enum gt683r_led_mode
{
37 GT683R_LED_BREATHING
= 3,
48 static const char * const gt683r_panel_names
[] = {
55 struct hid_device
*hdev
;
56 struct led_classdev led_devs
[GT683R_LED_COUNT
];
58 struct work_struct work
;
59 enum led_brightness brightnesses
[GT683R_LED_COUNT
];
60 enum gt683r_led_mode mode
;
63 static const struct hid_device_id gt683r_led_id
[] = {
64 { HID_USB_DEVICE(USB_VENDOR_ID_MSI
, USB_DEVICE_ID_MSI_GT683R_LED_PANEL
) },
68 static void gt683r_brightness_set(struct led_classdev
*led_cdev
,
69 enum led_brightness brightness
)
72 struct device
*dev
= led_cdev
->dev
->parent
;
73 struct hid_device
*hdev
= to_hid_device(dev
);
74 struct gt683r_led
*led
= hid_get_drvdata(hdev
);
76 for (i
= 0; i
< GT683R_LED_COUNT
; i
++) {
77 if (led_cdev
== &led
->led_devs
[i
])
81 if (i
< GT683R_LED_COUNT
) {
82 led
->brightnesses
[i
] = brightness
;
83 schedule_work(&led
->work
);
87 static ssize_t
mode_show(struct device
*dev
,
88 struct device_attribute
*attr
,
92 struct hid_device
*hdev
= to_hid_device(dev
->parent
);
93 struct gt683r_led
*led
= hid_get_drvdata(hdev
);
95 if (led
->mode
== GT683R_LED_NORMAL
)
97 else if (led
->mode
== GT683R_LED_AUDIO
)
102 return scnprintf(buf
, PAGE_SIZE
, "%u\n", sysfs_mode
);
105 static ssize_t
mode_store(struct device
*dev
,
106 struct device_attribute
*attr
,
107 const char *buf
, size_t count
)
110 struct hid_device
*hdev
= to_hid_device(dev
->parent
);
111 struct gt683r_led
*led
= hid_get_drvdata(hdev
);
114 if (kstrtou8(buf
, 10, &sysfs_mode
) || sysfs_mode
> 2)
117 mutex_lock(&led
->lock
);
120 led
->mode
= GT683R_LED_NORMAL
;
121 else if (sysfs_mode
== 1)
122 led
->mode
= GT683R_LED_AUDIO
;
124 led
->mode
= GT683R_LED_BREATHING
;
126 mutex_unlock(&led
->lock
);
127 schedule_work(&led
->work
);
132 static int gt683r_led_snd_msg(struct gt683r_led
*led
, u8
*msg
)
136 ret
= hid_hw_raw_request(led
->hdev
, msg
[0], msg
, GT683R_BUFFER_SIZE
,
137 HID_FEATURE_REPORT
, HID_REQ_SET_REPORT
);
138 if (ret
!= GT683R_BUFFER_SIZE
) {
140 "failed to send set report request: %i\n", ret
);
149 static int gt683r_leds_set(struct gt683r_led
*led
, u8 leds
)
154 buffer
= kzalloc(GT683R_BUFFER_SIZE
, GFP_KERNEL
);
162 ret
= gt683r_led_snd_msg(led
, buffer
);
168 static int gt683r_mode_set(struct gt683r_led
*led
, u8 mode
)
173 buffer
= kzalloc(GT683R_BUFFER_SIZE
, GFP_KERNEL
);
182 ret
= gt683r_led_snd_msg(led
, buffer
);
188 static void gt683r_led_work(struct work_struct
*work
)
193 struct gt683r_led
*led
= container_of(work
, struct gt683r_led
, work
);
195 mutex_lock(&led
->lock
);
197 for (i
= 0; i
< GT683R_LED_COUNT
; i
++) {
198 if (led
->brightnesses
[i
])
202 if (gt683r_leds_set(led
, leds
))
208 mode
= GT683R_LED_OFF
;
210 gt683r_mode_set(led
, mode
);
212 mutex_unlock(&led
->lock
);
215 static DEVICE_ATTR_RW(mode
);
217 static struct attribute
*gt683r_led_attrs
[] = {
222 static const struct attribute_group gt683r_led_group
= {
224 .attrs
= gt683r_led_attrs
,
227 static const struct attribute_group
*gt683r_led_groups
[] = {
232 static int gt683r_led_probe(struct hid_device
*hdev
,
233 const struct hid_device_id
*id
)
239 struct gt683r_led
*led
;
241 led
= devm_kzalloc(&hdev
->dev
, sizeof(*led
), GFP_KERNEL
);
245 mutex_init(&led
->lock
);
246 INIT_WORK(&led
->work
, gt683r_led_work
);
248 led
->mode
= GT683R_LED_NORMAL
;
250 hid_set_drvdata(hdev
, led
);
252 ret
= hid_parse(hdev
);
254 hid_err(hdev
, "hid parsing failed\n");
258 ret
= hid_hw_start(hdev
, HID_CONNECT_HIDRAW
);
260 hid_err(hdev
, "hw start failed\n");
264 for (i
= 0; i
< GT683R_LED_COUNT
; i
++) {
265 name_sz
= strlen(dev_name(&hdev
->dev
)) +
266 strlen(gt683r_panel_names
[i
]) + 3;
268 name
= devm_kzalloc(&hdev
->dev
, name_sz
, GFP_KERNEL
);
274 snprintf(name
, name_sz
, "%s::%s",
275 dev_name(&hdev
->dev
), gt683r_panel_names
[i
]);
276 led
->led_devs
[i
].name
= name
;
277 led
->led_devs
[i
].max_brightness
= 1;
278 led
->led_devs
[i
].brightness_set
= gt683r_brightness_set
;
279 led
->led_devs
[i
].groups
= gt683r_led_groups
;
281 ret
= led_classdev_register(&hdev
->dev
, &led
->led_devs
[i
]);
283 hid_err(hdev
, "could not register led device\n");
291 for (i
= i
- 1; i
>= 0; i
--)
292 led_classdev_unregister(&led
->led_devs
[i
]);
297 static void gt683r_led_remove(struct hid_device
*hdev
)
300 struct gt683r_led
*led
= hid_get_drvdata(hdev
);
302 for (i
= 0; i
< GT683R_LED_COUNT
; i
++)
303 led_classdev_unregister(&led
->led_devs
[i
]);
304 flush_work(&led
->work
);
308 static struct hid_driver gt683r_led_driver
= {
309 .probe
= gt683r_led_probe
,
310 .remove
= gt683r_led_remove
,
311 .name
= "gt683r_led",
312 .id_table
= gt683r_led_id
,
315 module_hid_driver(gt683r_led_driver
);
317 MODULE_AUTHOR("Janne Kanniainen");
318 MODULE_DESCRIPTION("MSI GT683R led driver");
319 MODULE_LICENSE("GPL");