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
= container_of(dev
, struct 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
= container_of(dev
->parent
,
93 struct hid_device
, dev
);
94 struct gt683r_led
*led
= hid_get_drvdata(hdev
);
96 if (led
->mode
== GT683R_LED_NORMAL
)
98 else if (led
->mode
== GT683R_LED_AUDIO
)
103 return scnprintf(buf
, PAGE_SIZE
, "%u\n", sysfs_mode
);
106 static ssize_t
mode_store(struct device
*dev
,
107 struct device_attribute
*attr
,
108 const char *buf
, size_t count
)
111 struct hid_device
*hdev
= container_of(dev
->parent
,
112 struct hid_device
, dev
);
113 struct gt683r_led
*led
= hid_get_drvdata(hdev
);
116 if (kstrtou8(buf
, 10, &sysfs_mode
) || sysfs_mode
> 2)
119 mutex_lock(&led
->lock
);
122 led
->mode
= GT683R_LED_NORMAL
;
123 else if (sysfs_mode
== 1)
124 led
->mode
= GT683R_LED_AUDIO
;
126 led
->mode
= GT683R_LED_BREATHING
;
128 mutex_unlock(&led
->lock
);
129 schedule_work(&led
->work
);
134 static int gt683r_led_snd_msg(struct gt683r_led
*led
, u8
*msg
)
138 ret
= hid_hw_raw_request(led
->hdev
, msg
[0], msg
, GT683R_BUFFER_SIZE
,
139 HID_FEATURE_REPORT
, HID_REQ_SET_REPORT
);
140 if (ret
!= GT683R_BUFFER_SIZE
) {
142 "failed to send set report request: %i\n", ret
);
151 static int gt683r_leds_set(struct gt683r_led
*led
, u8 leds
)
156 buffer
= kzalloc(GT683R_BUFFER_SIZE
, GFP_KERNEL
);
164 ret
= gt683r_led_snd_msg(led
, buffer
);
170 static int gt683r_mode_set(struct gt683r_led
*led
, u8 mode
)
175 buffer
= kzalloc(GT683R_BUFFER_SIZE
, GFP_KERNEL
);
184 ret
= gt683r_led_snd_msg(led
, buffer
);
190 static void gt683r_led_work(struct work_struct
*work
)
195 struct gt683r_led
*led
= container_of(work
, struct gt683r_led
, work
);
197 mutex_lock(&led
->lock
);
199 for (i
= 0; i
< GT683R_LED_COUNT
; i
++) {
200 if (led
->brightnesses
[i
])
204 if (gt683r_leds_set(led
, leds
))
210 mode
= GT683R_LED_OFF
;
212 gt683r_mode_set(led
, mode
);
214 mutex_unlock(&led
->lock
);
217 static DEVICE_ATTR_RW(mode
);
219 static struct attribute
*gt683r_led_attrs
[] = {
224 static const struct attribute_group gt683r_led_group
= {
226 .attrs
= gt683r_led_attrs
,
229 static const struct attribute_group
*gt683r_led_groups
[] = {
234 static int gt683r_led_probe(struct hid_device
*hdev
,
235 const struct hid_device_id
*id
)
241 struct gt683r_led
*led
;
243 led
= devm_kzalloc(&hdev
->dev
, sizeof(*led
), GFP_KERNEL
);
247 mutex_init(&led
->lock
);
248 INIT_WORK(&led
->work
, gt683r_led_work
);
250 led
->mode
= GT683R_LED_NORMAL
;
252 hid_set_drvdata(hdev
, led
);
254 ret
= hid_parse(hdev
);
256 hid_err(hdev
, "hid parsing failed\n");
260 ret
= hid_hw_start(hdev
, HID_CONNECT_HIDRAW
);
262 hid_err(hdev
, "hw start failed\n");
266 for (i
= 0; i
< GT683R_LED_COUNT
; i
++) {
267 name_sz
= strlen(dev_name(&hdev
->dev
)) +
268 strlen(gt683r_panel_names
[i
]) + 3;
270 name
= devm_kzalloc(&hdev
->dev
, name_sz
, GFP_KERNEL
);
276 snprintf(name
, name_sz
, "%s::%s",
277 dev_name(&hdev
->dev
), gt683r_panel_names
[i
]);
278 led
->led_devs
[i
].name
= name
;
279 led
->led_devs
[i
].max_brightness
= 1;
280 led
->led_devs
[i
].brightness_set
= gt683r_brightness_set
;
281 led
->led_devs
[i
].groups
= gt683r_led_groups
;
283 ret
= led_classdev_register(&hdev
->dev
, &led
->led_devs
[i
]);
285 hid_err(hdev
, "could not register led device\n");
293 for (i
= i
- 1; i
>= 0; i
--)
294 led_classdev_unregister(&led
->led_devs
[i
]);
299 static void gt683r_led_remove(struct hid_device
*hdev
)
302 struct gt683r_led
*led
= hid_get_drvdata(hdev
);
304 for (i
= 0; i
< GT683R_LED_COUNT
; i
++)
305 led_classdev_unregister(&led
->led_devs
[i
]);
306 flush_work(&led
->work
);
310 static struct hid_driver gt683r_led_driver
= {
311 .probe
= gt683r_led_probe
,
312 .remove
= gt683r_led_remove
,
313 .name
= "gt683r_led",
314 .id_table
= gt683r_led_id
,
317 module_hid_driver(gt683r_led_driver
);
319 MODULE_AUTHOR("Janne Kanniainen");
320 MODULE_DESCRIPTION("MSI GT683R led driver");
321 MODULE_LICENSE("GPL");