linux/drivers/hwmon/nzxt-smart2.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Reverse-engineered NZXT RGB & Fan Controller/Smart Device v2 driver.
 *
 * Copyright (c) 2021 Aleksandr Mezin
 */

#include <linux/hid.h>
#include <linux/hwmon.h>
#include <linux/math.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/wait.h>

#include <asm/byteorder.h>
#include <asm/unaligned.h>

/*
 * The device has only 3 fan channels/connectors. But all HID reports have
 * space reserved for up to 8 channels.
 */
#define FAN_CHANNELS
#define FAN_CHANNELS_MAX

#define UPDATE_INTERVAL_DEFAULT_MS

/* These strings match labels on the device exactly */
static const char *const fan_label[] =;

static const char *const curr_label[] =;

static const char *const in_label[] =;

enum {};

enum {};

enum {};

struct unknown_static_data {} __packed;

/*
 * The device sends this input report in response to "detect fans" command:
 * a 2-byte output report { 0x60, 0x03 }.
 */
struct fan_config_report {} __packed;

/*
 * The device sends these reports at a fixed interval (update interval) -
 * one report with type = FAN_STATUS_REPORT_SPEED, and one report with type =
 * FAN_STATUS_REPORT_VOLTAGE per update interval.
 */
struct fan_status_report {} __packed;

#define OUTPUT_REPORT_SIZE

enum {};

enum {};

/*
 * This output report sets pwm duty cycle/target fan speed for one or more
 * channels.
 */
struct set_fan_speed_report {} __packed;

struct drvdata {};

static long scale_pwm_value(long val, long orig_max, long new_max)
{}

static void handle_fan_config_report(struct drvdata *drvdata, void *data, int size)
{}

static void handle_fan_status_report(struct drvdata *drvdata, void *data, int size)
{}

static umode_t nzxt_smart2_hwmon_is_visible(const void *data,
					    enum hwmon_sensor_types type,
					    u32 attr, int channel)
{}

static int nzxt_smart2_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
				  u32 attr, int channel, long *val)
{}

static int send_output_report(struct drvdata *drvdata, const void *data,
			      size_t data_size)
{}

static int set_pwm(struct drvdata *drvdata, int channel, long val)
{}

/*
 * Workaround for fancontrol/pwmconfig trying to write to pwm*_enable even if it
 * already is 1 and read-only. Otherwise, fancontrol won't restore pwm on
 * shutdown properly.
 */
static int set_pwm_enable(struct drvdata *drvdata, int channel, long val)
{}

/*
 * Control byte	| Actual update interval in seconds
 * 0xff		| 65.5
 * 0xf7		| 63.46
 * 0x7f		| 32.74
 * 0x3f		| 16.36
 * 0x1f		| 8.17
 * 0x0f		| 4.07
 * 0x07		| 2.02
 * 0x03		| 1.00
 * 0x02		| 0.744
 * 0x01		| 0.488
 * 0x00		| 0.25
 */
static u8 update_interval_to_control_byte(long interval)
{}

static long control_byte_to_update_interval(u8 control_byte)
{}

static int set_update_interval(struct drvdata *drvdata, long val)
{}

static int init_device(struct drvdata *drvdata, long update_interval)
{}

static int nzxt_smart2_hwmon_write(struct device *dev,
				   enum hwmon_sensor_types type, u32 attr,
				   int channel, long val)
{}

static int nzxt_smart2_hwmon_read_string(struct device *dev,
					 enum hwmon_sensor_types type, u32 attr,
					 int channel, const char **str)
{}

static const struct hwmon_ops nzxt_smart2_hwmon_ops =;

static const struct hwmon_channel_info * const nzxt_smart2_channel_info[] =;

static const struct hwmon_chip_info nzxt_smart2_chip_info =;

static int nzxt_smart2_hid_raw_event(struct hid_device *hdev,
				     struct hid_report *report, u8 *data, int size)
{}

static int __maybe_unused nzxt_smart2_hid_reset_resume(struct hid_device *hdev)
{}

static void mutex_fini(void *lock)
{}

static int nzxt_smart2_hid_probe(struct hid_device *hdev,
				 const struct hid_device_id *id)
{}

static void nzxt_smart2_hid_remove(struct hid_device *hdev)
{}

static const struct hid_device_id nzxt_smart2_hid_id_table[] =;

static struct hid_driver nzxt_smart2_hid_driver =;

static int __init nzxt_smart2_init(void)
{}

static void __exit nzxt_smart2_exit(void)
{}

MODULE_DEVICE_TABLE(hid, nzxt_smart2_hid_id_table);
MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();

/*
 * With module_init()/module_hid_driver() and the driver built into the kernel:
 *
 * Driver 'nzxt_smart2' was unable to register with bus_type 'hid' because the
 * bus was not initialized.
 */
late_initcall(nzxt_smart2_init);
module_exit(nzxt_smart2_exit);