Commit | Line | Data |
---|---|---|
53e68c20 AM |
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(&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(&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(&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(&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(&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(&report->fan_voltage.fan_in[i]); | |
297 | drvdata->fan_curr[i] = | |
298 | get_unaligned_le16(&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(&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(&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(drvdata->fan_duty_percent[channel], | |
393 | 100, 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(&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(drvdata->hid, drvdata->output_buffer, | |
460 | 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, 255, 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, &report, 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(&drvdata->wq.lock); | |
496 | drvdata->fan_duty_percent[channel] = duty_percent; | |
497 | spin_unlock_bh(&drvdata->wq.lock); | |
498 | ||
499 | unlock: | |
500 | mutex_unlock(&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(&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(&drvdata->wq.lock); | |
520 | return res; | |
521 | } | |
522 | ||
523 | expected_val = drvdata->fan_type[channel] != FAN_TYPE_NONE; | |
524 | ||
525 | spin_unlock_irq(&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(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, report, sizeof(report)); | |
576 | if (ret) | |
577 | return ret; | |
578 | ||
579 | drvdata->update_interval = control_byte_to_update_interval(control); | |
580 | return 0; | |
581 | } | |
582 | ||
583 | static int init_device(struct drvdata *drvdata, long update_interval) | |
584 | { | |
585 | int ret; | |
00f5117c | 586 | static const u8 detect_fans_report[] = { |
53e68c20 AM |
587 | OUTPUT_REPORT_ID_INIT_COMMAND, |
588 | INIT_COMMAND_DETECT_FANS, | |
589 | }; | |
590 | ||
591 | ret = send_output_report(drvdata, detect_fans_report, | |
592 | sizeof(detect_fans_report)); | |
593 | if (ret) | |
594 | return ret; | |
595 | ||
596 | return set_update_interval(drvdata, 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(&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 | ||
98ce1fc1 | 666 | static const struct hwmon_channel_info * const nzxt_smart2_channel_info[] = { |
53e68c20 AM |
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 | ||
f103b2e5 | 707 | static int __maybe_unused nzxt_smart2_hid_reset_resume(struct hid_device *hdev) |
53e68c20 AM |
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(&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(&drvdata->wq.lock); | |
720 | ||
721 | return init_device(drvdata, drvdata->update_interval); | |
722 | } | |
723 | ||
dbfeafda KC |
724 | static void mutex_fini(void *lock) |
725 | { | |
726 | mutex_destroy(lock); | |
727 | } | |
728 | ||
53e68c20 AM |
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(&hdev->dev, sizeof(struct drvdata), GFP_KERNEL); | |
736 | if (!drvdata) | |
737 | return -ENOMEM; | |
738 | ||
739 | drvdata->hid = hdev; | |
740 | hid_set_drvdata(hdev, drvdata); | |
741 | ||
742 | init_waitqueue_head(&drvdata->wq); | |
743 | ||
744 | mutex_init(&drvdata->mutex); | |
dbfeafda KC |
745 | ret = devm_add_action_or_reset(&hdev->dev, mutex_fini, &drvdata->mutex); |
746 | if (ret) | |
747 | return ret; | |
53e68c20 AM |
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(hdev); | |
762 | ||
763 | init_device(drvdata, UPDATE_INTERVAL_DEFAULT_MS); | |
764 | ||
765 | drvdata->hwmon = | |
766 | hwmon_device_register_with_info(&hdev->dev, "nzxtsmart2", drvdata, | |
767 | &nzxt_smart2_chip_info, NULL); | |
768 | if (IS_ERR(drvdata->hwmon)) { | |
769 | ret = PTR_ERR(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(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 */ | |
887b22ec | 796 | { HID_USB_DEVICE(0x1e71, 0x200f) }, /* NZXT Smart Device V2 */ |
53e68c20 AM |
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 */ | |
4a148e9b AM |
800 | { HID_USB_DEVICE(0x1e71, 0x2011) }, /* NZXT RGB & Fan Controller (6 RGB) */ |
801 | { HID_USB_DEVICE(0x1e71, 0x2019) }, /* NZXT RGB & Fan Controller (6 RGB) */ | |
53e68c20 AM |
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); |