1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Reverse-engineered NZXT RGB & Fan Controller/Smart Device v2 driver. |
4 | * |
5 | * Copyright (c) 2021 Aleksandr Mezin |
6 | */ |
7 | |
8 | #include <linux/hid.h> |
9 | #include <linux/hwmon.h> |
10 | #include <linux/math.h> |
11 | #include <linux/module.h> |
12 | #include <linux/mutex.h> |
13 | #include <linux/spinlock.h> |
14 | #include <linux/wait.h> |
15 | |
16 | #include <asm/byteorder.h> |
17 | #include <asm/unaligned.h> |
18 | |
19 | /* |
20 | * The device has only 3 fan channels/connectors. But all HID reports have |
21 | * space reserved for up to 8 channels. |
22 | */ |
23 | #define FAN_CHANNELS 3 |
24 | #define FAN_CHANNELS_MAX 8 |
25 | |
26 | #define UPDATE_INTERVAL_DEFAULT_MS 1000 |
27 | |
28 | /* These strings match labels on the device exactly */ |
29 | static const char *const fan_label[] = { |
30 | "FAN 1" , |
31 | "FAN 2" , |
32 | "FAN 3" , |
33 | }; |
34 | |
35 | static const char *const curr_label[] = { |
36 | "FAN 1 Current" , |
37 | "FAN 2 Current" , |
38 | "FAN 3 Current" , |
39 | }; |
40 | |
41 | static const char *const in_label[] = { |
42 | "FAN 1 Voltage" , |
43 | "FAN 2 Voltage" , |
44 | "FAN 3 Voltage" , |
45 | }; |
46 | |
47 | enum { |
48 | INPUT_REPORT_ID_FAN_CONFIG = 0x61, |
49 | INPUT_REPORT_ID_FAN_STATUS = 0x67, |
50 | }; |
51 | |
52 | enum { |
53 | FAN_STATUS_REPORT_SPEED = 0x02, |
54 | FAN_STATUS_REPORT_VOLTAGE = 0x04, |
55 | }; |
56 | |
57 | enum { |
58 | FAN_TYPE_NONE = 0, |
59 | FAN_TYPE_DC = 1, |
60 | FAN_TYPE_PWM = 2, |
61 | }; |
62 | |
63 | struct unknown_static_data { |
64 | /* |
65 | * Some configuration data? Stays the same after fan speed changes, |
66 | * changes in fan configuration, reboots and driver reloads. |
67 | * |
68 | * The same data in multiple report types. |
69 | * |
70 | * Byte 12 seems to be the number of fan channels, but I am not sure. |
71 | */ |
72 | u8 unknown1[14]; |
73 | } __packed; |
74 | |
75 | /* |
76 | * The device sends this input report in response to "detect fans" command: |
77 | * a 2-byte output report { 0x60, 0x03 }. |
78 | */ |
79 | struct fan_config_report { |
80 | /* report_id should be INPUT_REPORT_ID_FAN_CONFIG = 0x61 */ |
81 | u8 report_id; |
82 | /* Always 0x03 */ |
83 | u8 magic; |
84 | struct unknown_static_data unknown_data; |
85 | /* Fan type as detected by the device. See FAN_TYPE_* enum. */ |
86 | u8 fan_type[FAN_CHANNELS_MAX]; |
87 | } __packed; |
88 | |
89 | /* |
90 | * The device sends these reports at a fixed interval (update interval) - |
91 | * one report with type = FAN_STATUS_REPORT_SPEED, and one report with type = |
92 | * FAN_STATUS_REPORT_VOLTAGE per update interval. |
93 | */ |
94 | struct fan_status_report { |
95 | /* report_id should be INPUT_REPORT_ID_STATUS = 0x67 */ |
96 | u8 report_id; |
97 | /* FAN_STATUS_REPORT_SPEED = 0x02 or FAN_STATUS_REPORT_VOLTAGE = 0x04 */ |
98 | u8 type; |
99 | struct unknown_static_data unknown_data; |
100 | /* Fan type as detected by the device. See FAN_TYPE_* enum. */ |
101 | u8 fan_type[FAN_CHANNELS_MAX]; |
102 | |
103 | union { |
104 | /* When type == FAN_STATUS_REPORT_SPEED */ |
105 | struct { |
106 | /* |
107 | * Fan speed, in RPM. Zero for channels without fans |
108 | * connected. |
109 | */ |
110 | __le16 fan_rpm[FAN_CHANNELS_MAX]; |
111 | /* |
112 | * Fan duty cycle, in percent. Non-zero even for |
113 | * channels without fans connected. |
114 | */ |
115 | u8 duty_percent[FAN_CHANNELS_MAX]; |
116 | /* |
117 | * Exactly the same values as duty_percent[], non-zero |
118 | * for disconnected fans too. |
119 | */ |
120 | u8 duty_percent_dup[FAN_CHANNELS_MAX]; |
121 | /* "Case Noise" in db */ |
122 | u8 noise_db; |
123 | } __packed fan_speed; |
124 | /* When type == FAN_STATUS_REPORT_VOLTAGE */ |
125 | struct { |
126 | /* |
127 | * Voltage, in millivolts. Non-zero even when fan is |
128 | * not connected. |
129 | */ |
130 | __le16 fan_in[FAN_CHANNELS_MAX]; |
131 | /* |
132 | * Current, in milliamperes. Near-zero when |
133 | * disconnected. |
134 | */ |
135 | __le16 fan_current[FAN_CHANNELS_MAX]; |
136 | } __packed fan_voltage; |
137 | } __packed; |
138 | } __packed; |
139 | |
140 | #define OUTPUT_REPORT_SIZE 64 |
141 | |
142 | enum { |
143 | OUTPUT_REPORT_ID_INIT_COMMAND = 0x60, |
144 | OUTPUT_REPORT_ID_SET_FAN_SPEED = 0x62, |
145 | }; |
146 | |
147 | enum { |
148 | INIT_COMMAND_SET_UPDATE_INTERVAL = 0x02, |
149 | INIT_COMMAND_DETECT_FANS = 0x03, |
150 | }; |
151 | |
152 | /* |
153 | * This output report sets pwm duty cycle/target fan speed for one or more |
154 | * channels. |
155 | */ |
156 | struct set_fan_speed_report { |
157 | /* report_id should be OUTPUT_REPORT_ID_SET_FAN_SPEED = 0x62 */ |
158 | u8 report_id; |
159 | /* Should be 0x01 */ |
160 | u8 magic; |
161 | /* To change fan speed on i-th channel, set i-th bit here */ |
162 | u8 channel_bit_mask; |
163 | /* |
164 | * Fan duty cycle/target speed in percent. For voltage-controlled fans, |
165 | * the minimal voltage (duty_percent = 1) is about 9V. |
166 | * Setting duty_percent to 0 (if the channel is selected in |
167 | * channel_bit_mask) turns off the fan completely (regardless of the |
168 | * control mode). |
169 | */ |
170 | u8 duty_percent[FAN_CHANNELS_MAX]; |
171 | } __packed; |
172 | |
173 | struct drvdata { |
174 | struct hid_device *hid; |
175 | struct device *hwmon; |
176 | |
177 | u8 fan_duty_percent[FAN_CHANNELS]; |
178 | u16 fan_rpm[FAN_CHANNELS]; |
179 | bool pwm_status_received; |
180 | |
181 | u16 fan_in[FAN_CHANNELS]; |
182 | u16 fan_curr[FAN_CHANNELS]; |
183 | bool voltage_status_received; |
184 | |
185 | u8 fan_type[FAN_CHANNELS]; |
186 | bool fan_config_received; |
187 | |
188 | /* |
189 | * wq is used to wait for *_received flags to become true. |
190 | * All accesses to *_received flags and fan_* arrays are performed with |
191 | * wq.lock held. |
192 | */ |
193 | wait_queue_head_t wq; |
194 | /* |
195 | * mutex is used to: |
196 | * 1) Prevent concurrent conflicting changes to update interval and pwm |
197 | * values (after sending an output hid report, the corresponding field |
198 | * in drvdata must be updated, and only then new output reports can be |
199 | * sent). |
200 | * 2) Synchronize access to output_buffer (well, the buffer is here, |
201 | * because synchronization is necessary anyway - so why not get rid of |
202 | * a kmalloc?). |
203 | */ |
204 | struct mutex mutex; |
205 | long update_interval; |
206 | u8 output_buffer[OUTPUT_REPORT_SIZE]; |
207 | }; |
208 | |
209 | static long scale_pwm_value(long val, long orig_max, long new_max) |
210 | { |
211 | if (val <= 0) |
212 | return 0; |
213 | |
214 | /* |
215 | * Positive values should not become zero: 0 completely turns off the |
216 | * fan. |
217 | */ |
218 | return max(1L, DIV_ROUND_CLOSEST(min(val, orig_max) * new_max, orig_max)); |
219 | } |
220 | |
221 | static void handle_fan_config_report(struct drvdata *drvdata, void *data, int size) |
222 | { |
223 | struct fan_config_report *report = data; |
224 | int i; |
225 | |
226 | if (size < sizeof(struct fan_config_report)) |
227 | return; |
228 | |
229 | if (report->magic != 0x03) |
230 | return; |
231 | |
232 | spin_lock(lock: &drvdata->wq.lock); |
233 | |
234 | for (i = 0; i < FAN_CHANNELS; i++) |
235 | drvdata->fan_type[i] = report->fan_type[i]; |
236 | |
237 | drvdata->fan_config_received = true; |
238 | wake_up_all_locked(&drvdata->wq); |
239 | spin_unlock(lock: &drvdata->wq.lock); |
240 | } |
241 | |
242 | static void handle_fan_status_report(struct drvdata *drvdata, void *data, int size) |
243 | { |
244 | struct fan_status_report *report = data; |
245 | int i; |
246 | |
247 | if (size < sizeof(struct fan_status_report)) |
248 | return; |
249 | |
250 | spin_lock(lock: &drvdata->wq.lock); |
251 | |
252 | /* |
253 | * The device sends INPUT_REPORT_ID_FAN_CONFIG = 0x61 report in response |
254 | * to "detect fans" command. Only accept other data after getting 0x61, |
255 | * to make sure that fan detection is complete. In particular, fan |
256 | * detection resets pwm values. |
257 | */ |
258 | if (!drvdata->fan_config_received) { |
259 | spin_unlock(lock: &drvdata->wq.lock); |
260 | return; |
261 | } |
262 | |
263 | for (i = 0; i < FAN_CHANNELS; i++) { |
264 | if (drvdata->fan_type[i] == report->fan_type[i]) |
265 | continue; |
266 | |
267 | /* |
268 | * This should not happen (if my expectations about the device |
269 | * are correct). |
270 | * |
271 | * Even if the userspace sends fan detect command through |
272 | * hidraw, fan config report should arrive first. |
273 | */ |
274 | hid_warn_once(drvdata->hid, |
275 | "Fan %d type changed unexpectedly from %d to %d" , |
276 | i, drvdata->fan_type[i], report->fan_type[i]); |
277 | drvdata->fan_type[i] = report->fan_type[i]; |
278 | } |
279 | |
280 | switch (report->type) { |
281 | case FAN_STATUS_REPORT_SPEED: |
282 | for (i = 0; i < FAN_CHANNELS; i++) { |
283 | drvdata->fan_rpm[i] = |
284 | get_unaligned_le16(p: &report->fan_speed.fan_rpm[i]); |
285 | drvdata->fan_duty_percent[i] = |
286 | report->fan_speed.duty_percent[i]; |
287 | } |
288 | |
289 | drvdata->pwm_status_received = true; |
290 | wake_up_all_locked(&drvdata->wq); |
291 | break; |
292 | |
293 | case FAN_STATUS_REPORT_VOLTAGE: |
294 | for (i = 0; i < FAN_CHANNELS; i++) { |
295 | drvdata->fan_in[i] = |
296 | get_unaligned_le16(p: &report->fan_voltage.fan_in[i]); |
297 | drvdata->fan_curr[i] = |
298 | get_unaligned_le16(p: &report->fan_voltage.fan_current[i]); |
299 | } |
300 | |
301 | drvdata->voltage_status_received = true; |
302 | wake_up_all_locked(&drvdata->wq); |
303 | break; |
304 | } |
305 | |
306 | spin_unlock(lock: &drvdata->wq.lock); |
307 | } |
308 | |
309 | static umode_t nzxt_smart2_hwmon_is_visible(const void *data, |
310 | enum hwmon_sensor_types type, |
311 | u32 attr, int channel) |
312 | { |
313 | switch (type) { |
314 | case hwmon_pwm: |
315 | switch (attr) { |
316 | case hwmon_pwm_input: |
317 | case hwmon_pwm_enable: |
318 | return 0644; |
319 | |
320 | default: |
321 | return 0444; |
322 | } |
323 | |
324 | case hwmon_chip: |
325 | switch (attr) { |
326 | case hwmon_chip_update_interval: |
327 | return 0644; |
328 | |
329 | default: |
330 | return 0444; |
331 | } |
332 | |
333 | default: |
334 | return 0444; |
335 | } |
336 | } |
337 | |
338 | static int nzxt_smart2_hwmon_read(struct device *dev, enum hwmon_sensor_types type, |
339 | u32 attr, int channel, long *val) |
340 | { |
341 | struct drvdata *drvdata = dev_get_drvdata(dev); |
342 | int res = -EINVAL; |
343 | |
344 | if (type == hwmon_chip) { |
345 | switch (attr) { |
346 | case hwmon_chip_update_interval: |
347 | *val = drvdata->update_interval; |
348 | return 0; |
349 | |
350 | default: |
351 | return -EINVAL; |
352 | } |
353 | } |
354 | |
355 | spin_lock_irq(lock: &drvdata->wq.lock); |
356 | |
357 | switch (type) { |
358 | case hwmon_pwm: |
359 | /* |
360 | * fancontrol: |
361 | * 1) remembers pwm* values when it starts |
362 | * 2) needs pwm*_enable to be 1 on controlled fans |
363 | * So make sure we have correct data before allowing pwm* reads. |
364 | * Returning errors for pwm of fan speed read can even cause |
365 | * fancontrol to shut down. So the wait is unavoidable. |
366 | */ |
367 | switch (attr) { |
368 | case hwmon_pwm_enable: |
369 | res = wait_event_interruptible_locked_irq(drvdata->wq, |
370 | drvdata->fan_config_received); |
371 | if (res) |
372 | goto unlock; |
373 | |
374 | *val = drvdata->fan_type[channel] != FAN_TYPE_NONE; |
375 | break; |
376 | |
377 | case hwmon_pwm_mode: |
378 | res = wait_event_interruptible_locked_irq(drvdata->wq, |
379 | drvdata->fan_config_received); |
380 | if (res) |
381 | goto unlock; |
382 | |
383 | *val = drvdata->fan_type[channel] == FAN_TYPE_PWM; |
384 | break; |
385 | |
386 | case hwmon_pwm_input: |
387 | res = wait_event_interruptible_locked_irq(drvdata->wq, |
388 | drvdata->pwm_status_received); |
389 | if (res) |
390 | goto unlock; |
391 | |
392 | *val = scale_pwm_value(val: drvdata->fan_duty_percent[channel], |
393 | orig_max: 100, new_max: 255); |
394 | break; |
395 | } |
396 | break; |
397 | |
398 | case hwmon_fan: |
399 | /* |
400 | * It's not strictly necessary to wait for *_received in the |
401 | * remaining cases (fancontrol doesn't care about them). But I'm |
402 | * doing it to have consistent behavior. |
403 | */ |
404 | if (attr == hwmon_fan_input) { |
405 | res = wait_event_interruptible_locked_irq(drvdata->wq, |
406 | drvdata->pwm_status_received); |
407 | if (res) |
408 | goto unlock; |
409 | |
410 | *val = drvdata->fan_rpm[channel]; |
411 | } |
412 | break; |
413 | |
414 | case hwmon_in: |
415 | if (attr == hwmon_in_input) { |
416 | res = wait_event_interruptible_locked_irq(drvdata->wq, |
417 | drvdata->voltage_status_received); |
418 | if (res) |
419 | goto unlock; |
420 | |
421 | *val = drvdata->fan_in[channel]; |
422 | } |
423 | break; |
424 | |
425 | case hwmon_curr: |
426 | if (attr == hwmon_curr_input) { |
427 | res = wait_event_interruptible_locked_irq(drvdata->wq, |
428 | drvdata->voltage_status_received); |
429 | if (res) |
430 | goto unlock; |
431 | |
432 | *val = drvdata->fan_curr[channel]; |
433 | } |
434 | break; |
435 | |
436 | default: |
437 | break; |
438 | } |
439 | |
440 | unlock: |
441 | spin_unlock_irq(lock: &drvdata->wq.lock); |
442 | return res; |
443 | } |
444 | |
445 | static int send_output_report(struct drvdata *drvdata, const void *data, |
446 | size_t data_size) |
447 | { |
448 | int ret; |
449 | |
450 | if (data_size > sizeof(drvdata->output_buffer)) |
451 | return -EINVAL; |
452 | |
453 | memcpy(drvdata->output_buffer, data, data_size); |
454 | |
455 | if (data_size < sizeof(drvdata->output_buffer)) |
456 | memset(drvdata->output_buffer + data_size, 0, |
457 | sizeof(drvdata->output_buffer) - data_size); |
458 | |
459 | ret = hid_hw_output_report(hdev: drvdata->hid, buf: drvdata->output_buffer, |
460 | len: sizeof(drvdata->output_buffer)); |
461 | return ret < 0 ? ret : 0; |
462 | } |
463 | |
464 | static int set_pwm(struct drvdata *drvdata, int channel, long val) |
465 | { |
466 | int ret; |
467 | u8 duty_percent = scale_pwm_value(val, orig_max: 255, new_max: 100); |
468 | |
469 | struct set_fan_speed_report report = { |
470 | .report_id = OUTPUT_REPORT_ID_SET_FAN_SPEED, |
471 | .magic = 1, |
472 | .channel_bit_mask = 1 << channel |
473 | }; |
474 | |
475 | ret = mutex_lock_interruptible(&drvdata->mutex); |
476 | if (ret) |
477 | return ret; |
478 | |
479 | report.duty_percent[channel] = duty_percent; |
480 | ret = send_output_report(drvdata, data: &report, data_size: sizeof(report)); |
481 | if (ret) |
482 | goto unlock; |
483 | |
484 | /* |
485 | * pwmconfig and fancontrol scripts expect pwm writes to take effect |
486 | * immediately (i. e. read from pwm* sysfs should return the value |
487 | * written into it). The device seems to always accept pwm values - even |
488 | * when there is no fan connected - so update pwm status without waiting |
489 | * for a report, to make pwmconfig and fancontrol happy. Worst case - |
490 | * if the device didn't accept new pwm value for some reason (never seen |
491 | * this in practice) - it will be reported incorrectly only until next |
492 | * update. This avoids "fan stuck" messages from pwmconfig, and |
493 | * fancontrol setting fan speed to 100% during shutdown. |
494 | */ |
495 | spin_lock_bh(lock: &drvdata->wq.lock); |
496 | drvdata->fan_duty_percent[channel] = duty_percent; |
497 | spin_unlock_bh(lock: &drvdata->wq.lock); |
498 | |
499 | unlock: |
500 | mutex_unlock(lock: &drvdata->mutex); |
501 | return ret; |
502 | } |
503 | |
504 | /* |
505 | * Workaround for fancontrol/pwmconfig trying to write to pwm*_enable even if it |
506 | * already is 1 and read-only. Otherwise, fancontrol won't restore pwm on |
507 | * shutdown properly. |
508 | */ |
509 | static int set_pwm_enable(struct drvdata *drvdata, int channel, long val) |
510 | { |
511 | long expected_val; |
512 | int res; |
513 | |
514 | spin_lock_irq(lock: &drvdata->wq.lock); |
515 | |
516 | res = wait_event_interruptible_locked_irq(drvdata->wq, |
517 | drvdata->fan_config_received); |
518 | if (res) { |
519 | spin_unlock_irq(lock: &drvdata->wq.lock); |
520 | return res; |
521 | } |
522 | |
523 | expected_val = drvdata->fan_type[channel] != FAN_TYPE_NONE; |
524 | |
525 | spin_unlock_irq(lock: &drvdata->wq.lock); |
526 | |
527 | return (val == expected_val) ? 0 : -EOPNOTSUPP; |
528 | } |
529 | |
530 | /* |
531 | * Control byte | Actual update interval in seconds |
532 | * 0xff | 65.5 |
533 | * 0xf7 | 63.46 |
534 | * 0x7f | 32.74 |
535 | * 0x3f | 16.36 |
536 | * 0x1f | 8.17 |
537 | * 0x0f | 4.07 |
538 | * 0x07 | 2.02 |
539 | * 0x03 | 1.00 |
540 | * 0x02 | 0.744 |
541 | * 0x01 | 0.488 |
542 | * 0x00 | 0.25 |
543 | */ |
544 | static u8 update_interval_to_control_byte(long interval) |
545 | { |
546 | if (interval <= 250) |
547 | return 0; |
548 | |
549 | return clamp_val(1 + DIV_ROUND_CLOSEST(interval - 488, 256), 0, 255); |
550 | } |
551 | |
552 | static long control_byte_to_update_interval(u8 control_byte) |
553 | { |
554 | if (control_byte == 0) |
555 | return 250; |
556 | |
557 | return 488 + (control_byte - 1) * 256; |
558 | } |
559 | |
560 | static int set_update_interval(struct drvdata *drvdata, long val) |
561 | { |
562 | u8 control = update_interval_to_control_byte(interval: val); |
563 | u8 report[] = { |
564 | OUTPUT_REPORT_ID_INIT_COMMAND, |
565 | INIT_COMMAND_SET_UPDATE_INTERVAL, |
566 | 0x01, |
567 | 0xe8, |
568 | control, |
569 | 0x01, |
570 | 0xe8, |
571 | control, |
572 | }; |
573 | int ret; |
574 | |
575 | ret = send_output_report(drvdata, data: report, data_size: sizeof(report)); |
576 | if (ret) |
577 | return ret; |
578 | |
579 | drvdata->update_interval = control_byte_to_update_interval(control_byte: control); |
580 | return 0; |
581 | } |
582 | |
583 | static int init_device(struct drvdata *drvdata, long update_interval) |
584 | { |
585 | int ret; |
586 | static const u8 detect_fans_report[] = { |
587 | OUTPUT_REPORT_ID_INIT_COMMAND, |
588 | INIT_COMMAND_DETECT_FANS, |
589 | }; |
590 | |
591 | ret = send_output_report(drvdata, data: detect_fans_report, |
592 | data_size: sizeof(detect_fans_report)); |
593 | if (ret) |
594 | return ret; |
595 | |
596 | return set_update_interval(drvdata, val: update_interval); |
597 | } |
598 | |
599 | static int nzxt_smart2_hwmon_write(struct device *dev, |
600 | enum hwmon_sensor_types type, u32 attr, |
601 | int channel, long val) |
602 | { |
603 | struct drvdata *drvdata = dev_get_drvdata(dev); |
604 | int ret; |
605 | |
606 | switch (type) { |
607 | case hwmon_pwm: |
608 | switch (attr) { |
609 | case hwmon_pwm_enable: |
610 | return set_pwm_enable(drvdata, channel, val); |
611 | |
612 | case hwmon_pwm_input: |
613 | return set_pwm(drvdata, channel, val); |
614 | |
615 | default: |
616 | return -EINVAL; |
617 | } |
618 | |
619 | case hwmon_chip: |
620 | switch (attr) { |
621 | case hwmon_chip_update_interval: |
622 | ret = mutex_lock_interruptible(&drvdata->mutex); |
623 | if (ret) |
624 | return ret; |
625 | |
626 | ret = set_update_interval(drvdata, val); |
627 | |
628 | mutex_unlock(lock: &drvdata->mutex); |
629 | return ret; |
630 | |
631 | default: |
632 | return -EINVAL; |
633 | } |
634 | |
635 | default: |
636 | return -EINVAL; |
637 | } |
638 | } |
639 | |
640 | static int nzxt_smart2_hwmon_read_string(struct device *dev, |
641 | enum hwmon_sensor_types type, u32 attr, |
642 | int channel, const char **str) |
643 | { |
644 | switch (type) { |
645 | case hwmon_fan: |
646 | *str = fan_label[channel]; |
647 | return 0; |
648 | case hwmon_curr: |
649 | *str = curr_label[channel]; |
650 | return 0; |
651 | case hwmon_in: |
652 | *str = in_label[channel]; |
653 | return 0; |
654 | default: |
655 | return -EINVAL; |
656 | } |
657 | } |
658 | |
659 | static const struct hwmon_ops nzxt_smart2_hwmon_ops = { |
660 | .is_visible = nzxt_smart2_hwmon_is_visible, |
661 | .read = nzxt_smart2_hwmon_read, |
662 | .read_string = nzxt_smart2_hwmon_read_string, |
663 | .write = nzxt_smart2_hwmon_write, |
664 | }; |
665 | |
666 | static const struct hwmon_channel_info * const nzxt_smart2_channel_info[] = { |
667 | HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_LABEL, |
668 | HWMON_F_INPUT | HWMON_F_LABEL, |
669 | HWMON_F_INPUT | HWMON_F_LABEL), |
670 | HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_MODE | HWMON_PWM_ENABLE, |
671 | HWMON_PWM_INPUT | HWMON_PWM_MODE | HWMON_PWM_ENABLE, |
672 | HWMON_PWM_INPUT | HWMON_PWM_MODE | HWMON_PWM_ENABLE), |
673 | HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_LABEL, |
674 | HWMON_I_INPUT | HWMON_I_LABEL, |
675 | HWMON_I_INPUT | HWMON_I_LABEL), |
676 | HWMON_CHANNEL_INFO(curr, HWMON_C_INPUT | HWMON_C_LABEL, |
677 | HWMON_C_INPUT | HWMON_C_LABEL, |
678 | HWMON_C_INPUT | HWMON_C_LABEL), |
679 | HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL), |
680 | NULL |
681 | }; |
682 | |
683 | static const struct hwmon_chip_info nzxt_smart2_chip_info = { |
684 | .ops = &nzxt_smart2_hwmon_ops, |
685 | .info = nzxt_smart2_channel_info, |
686 | }; |
687 | |
688 | static int nzxt_smart2_hid_raw_event(struct hid_device *hdev, |
689 | struct hid_report *report, u8 *data, int size) |
690 | { |
691 | struct drvdata *drvdata = hid_get_drvdata(hdev); |
692 | u8 report_id = *data; |
693 | |
694 | switch (report_id) { |
695 | case INPUT_REPORT_ID_FAN_CONFIG: |
696 | handle_fan_config_report(drvdata, data, size); |
697 | break; |
698 | |
699 | case INPUT_REPORT_ID_FAN_STATUS: |
700 | handle_fan_status_report(drvdata, data, size); |
701 | break; |
702 | } |
703 | |
704 | return 0; |
705 | } |
706 | |
707 | static int __maybe_unused nzxt_smart2_hid_reset_resume(struct hid_device *hdev) |
708 | { |
709 | struct drvdata *drvdata = hid_get_drvdata(hdev); |
710 | |
711 | /* |
712 | * Userspace is still frozen (so no concurrent sysfs attribute access |
713 | * is possible), but raw_event can already be called concurrently. |
714 | */ |
715 | spin_lock_bh(lock: &drvdata->wq.lock); |
716 | drvdata->fan_config_received = false; |
717 | drvdata->pwm_status_received = false; |
718 | drvdata->voltage_status_received = false; |
719 | spin_unlock_bh(lock: &drvdata->wq.lock); |
720 | |
721 | return init_device(drvdata, update_interval: drvdata->update_interval); |
722 | } |
723 | |
724 | static void mutex_fini(void *lock) |
725 | { |
726 | mutex_destroy(lock); |
727 | } |
728 | |
729 | static int nzxt_smart2_hid_probe(struct hid_device *hdev, |
730 | const struct hid_device_id *id) |
731 | { |
732 | struct drvdata *drvdata; |
733 | int ret; |
734 | |
735 | drvdata = devm_kzalloc(dev: &hdev->dev, size: sizeof(struct drvdata), GFP_KERNEL); |
736 | if (!drvdata) |
737 | return -ENOMEM; |
738 | |
739 | drvdata->hid = hdev; |
740 | hid_set_drvdata(hdev, data: drvdata); |
741 | |
742 | init_waitqueue_head(&drvdata->wq); |
743 | |
744 | mutex_init(&drvdata->mutex); |
745 | ret = devm_add_action_or_reset(&hdev->dev, mutex_fini, &drvdata->mutex); |
746 | if (ret) |
747 | return ret; |
748 | |
749 | ret = hid_parse(hdev); |
750 | if (ret) |
751 | return ret; |
752 | |
753 | ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); |
754 | if (ret) |
755 | return ret; |
756 | |
757 | ret = hid_hw_open(hdev); |
758 | if (ret) |
759 | goto out_hw_stop; |
760 | |
761 | hid_device_io_start(hid: hdev); |
762 | |
763 | init_device(drvdata, UPDATE_INTERVAL_DEFAULT_MS); |
764 | |
765 | drvdata->hwmon = |
766 | hwmon_device_register_with_info(dev: &hdev->dev, name: "nzxtsmart2" , drvdata, |
767 | info: &nzxt_smart2_chip_info, NULL); |
768 | if (IS_ERR(ptr: drvdata->hwmon)) { |
769 | ret = PTR_ERR(ptr: drvdata->hwmon); |
770 | goto out_hw_close; |
771 | } |
772 | |
773 | return 0; |
774 | |
775 | out_hw_close: |
776 | hid_hw_close(hdev); |
777 | |
778 | out_hw_stop: |
779 | hid_hw_stop(hdev); |
780 | return ret; |
781 | } |
782 | |
783 | static void nzxt_smart2_hid_remove(struct hid_device *hdev) |
784 | { |
785 | struct drvdata *drvdata = hid_get_drvdata(hdev); |
786 | |
787 | hwmon_device_unregister(dev: drvdata->hwmon); |
788 | |
789 | hid_hw_close(hdev); |
790 | hid_hw_stop(hdev); |
791 | } |
792 | |
793 | static const struct hid_device_id nzxt_smart2_hid_id_table[] = { |
794 | { HID_USB_DEVICE(0x1e71, 0x2006) }, /* NZXT Smart Device V2 */ |
795 | { HID_USB_DEVICE(0x1e71, 0x200d) }, /* NZXT Smart Device V2 */ |
796 | { HID_USB_DEVICE(0x1e71, 0x200f) }, /* NZXT Smart Device V2 */ |
797 | { HID_USB_DEVICE(0x1e71, 0x2009) }, /* NZXT RGB & Fan Controller */ |
798 | { HID_USB_DEVICE(0x1e71, 0x200e) }, /* NZXT RGB & Fan Controller */ |
799 | { HID_USB_DEVICE(0x1e71, 0x2010) }, /* NZXT RGB & Fan Controller */ |
800 | { HID_USB_DEVICE(0x1e71, 0x2011) }, /* NZXT RGB & Fan Controller (6 RGB) */ |
801 | { HID_USB_DEVICE(0x1e71, 0x2019) }, /* NZXT RGB & Fan Controller (6 RGB) */ |
802 | {}, |
803 | }; |
804 | |
805 | static struct hid_driver nzxt_smart2_hid_driver = { |
806 | .name = "nzxt-smart2" , |
807 | .id_table = nzxt_smart2_hid_id_table, |
808 | .probe = nzxt_smart2_hid_probe, |
809 | .remove = nzxt_smart2_hid_remove, |
810 | .raw_event = nzxt_smart2_hid_raw_event, |
811 | #ifdef CONFIG_PM |
812 | .reset_resume = nzxt_smart2_hid_reset_resume, |
813 | #endif |
814 | }; |
815 | |
816 | static int __init nzxt_smart2_init(void) |
817 | { |
818 | return hid_register_driver(&nzxt_smart2_hid_driver); |
819 | } |
820 | |
821 | static void __exit nzxt_smart2_exit(void) |
822 | { |
823 | hid_unregister_driver(&nzxt_smart2_hid_driver); |
824 | } |
825 | |
826 | MODULE_DEVICE_TABLE(hid, nzxt_smart2_hid_id_table); |
827 | MODULE_AUTHOR("Aleksandr Mezin <mezin.alexander@gmail.com>" ); |
828 | MODULE_DESCRIPTION("Driver for NZXT RGB & Fan Controller/Smart Device V2" ); |
829 | MODULE_LICENSE("GPL" ); |
830 | |
831 | /* |
832 | * With module_init()/module_hid_driver() and the driver built into the kernel: |
833 | * |
834 | * Driver 'nzxt_smart2' was unable to register with bus_type 'hid' because the |
835 | * bus was not initialized. |
836 | */ |
837 | late_initcall(nzxt_smart2_init); |
838 | module_exit(nzxt_smart2_exit); |
839 | |