/* Sensor data */
s32 temp_input[1];
u16 speed_input[6]; /* Pump, internal fan and four controller fan speeds in RPM */
u8 duty_input[3]; /* Pump, internal fan and controller fan duty in PWM */
static umode_t rog_ryujin_is_visible(constvoid *data, enum hwmon_sensor_types type, u32 attr, int channel)
{ switch (type) { case hwmon_temp: switch (attr) { case hwmon_temp_label: case hwmon_temp_input: return 0444; default: break;
} break; case hwmon_fan: switch (attr) { case hwmon_fan_label: case hwmon_fan_input: return 0444; default: break;
} break; case hwmon_pwm: switch (attr) { case hwmon_pwm_input: return 0644; default: break;
} break; default: break;
}
return 0;
}
/* Writes the command to the device with the rest of the report filled with zeroes */ staticint rog_ryujin_write_expanded(struct rog_ryujin_data *priv, const u8 *cmd, int cmd_length)
{ int ret;
mutex_lock(&priv->buffer_lock);
memcpy_and_pad(priv->buffer, MAX_REPORT_LENGTH, cmd, cmd_length, 0x00);
ret = hid_hw_output_report(priv->hdev, priv->buffer, MAX_REPORT_LENGTH);
mutex_unlock(&priv->buffer_lock); return ret;
}
/* Assumes priv->status_report_request_mutex is locked */ staticint rog_ryujin_execute_cmd(struct rog_ryujin_data *priv, const u8 *cmd, int cmd_length, struct completion *status_completion)
{ int ret;
/* * Disable raw event parsing for a moment to safely reinitialize the * completion. Reinit is done because hidraw could have triggered * the raw event parsing and marked the passed in completion as done.
*/
spin_lock_bh(&priv->status_report_request_lock);
reinit_completion(status_completion);
spin_unlock_bh(&priv->status_report_request_lock);
/* Send command for getting data */
ret = rog_ryujin_write_expanded(priv, cmd, cmd_length); if (ret < 0) return ret;
ret = wait_for_completion_interruptible_timeout(status_completion,
msecs_to_jiffies(STATUS_VALIDITY)); if (ret == 0) return -ETIMEDOUT; elseif (ret < 0) return ret;
return 0;
}
staticint rog_ryujin_get_status(struct rog_ryujin_data *priv)
{ int ret = mutex_lock_interruptible(&priv->status_report_request_mutex);
if (ret < 0) return ret;
if (!time_after(jiffies, priv->updated + msecs_to_jiffies(STATUS_VALIDITY))) { /* Data is up to date */ goto unlock_and_return;
}
/* Retrieve cooler status */
ret =
rog_ryujin_execute_cmd(priv, get_cooler_status_cmd, GET_CMD_LENGTH,
&priv->cooler_status_received); if (ret < 0) goto unlock_and_return;
/* Retrieve controller status (speeds) */
ret =
rog_ryujin_execute_cmd(priv, get_controller_speed_cmd, GET_CMD_LENGTH,
&priv->controller_status_received); if (ret < 0) goto unlock_and_return;
/* Retrieve cooler duty */
ret =
rog_ryujin_execute_cmd(priv, get_cooler_duty_cmd, GET_CMD_LENGTH,
&priv->cooler_duty_received); if (ret < 0) goto unlock_and_return;
/* Retrieve controller duty */
ret =
rog_ryujin_execute_cmd(priv, get_controller_duty_cmd, GET_CMD_LENGTH,
&priv->controller_duty_received); if (ret < 0) goto unlock_and_return;
priv->updated = jiffies;
unlock_and_return:
mutex_unlock(&priv->status_report_request_mutex); if (ret < 0) return ret;
return 0;
}
staticint rog_ryujin_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{ struct rog_ryujin_data *priv = dev_get_drvdata(dev); int ret = rog_ryujin_get_status(priv);
if (ret < 0) return ret;
switch (type) { case hwmon_temp:
*val = priv->temp_input[channel]; break; case hwmon_fan:
*val = priv->speed_input[channel]; break; case hwmon_pwm: switch (attr) { case hwmon_pwm_input:
*val = priv->duty_input[channel]; break; default: return -EOPNOTSUPP;
} break; default: return -EOPNOTSUPP; /* unreachable */
}
staticint rog_ryujin_write_fixed_duty(struct rog_ryujin_data *priv, int channel, int val)
{
u8 set_cmd[SET_CMD_LENGTH]; int ret;
if (channel < 2) { /* * Retrieve cooler duty since both pump and internal fan are set * together, then write back with one of them modified.
*/
ret = mutex_lock_interruptible(&priv->status_report_request_mutex); if (ret < 0) return ret;
ret =
rog_ryujin_execute_cmd(priv, get_cooler_duty_cmd, GET_CMD_LENGTH,
&priv->cooler_duty_received); if (ret < 0) goto unlock_and_return;
ret = rog_ryujin_execute_cmd(priv, set_cmd, SET_CMD_LENGTH, &priv->cooler_duty_set);
unlock_and_return:
mutex_unlock(&priv->status_report_request_mutex); if (ret < 0) return ret;
} else { /* * Controller fan duty (channel == 2). No need to retrieve current * duty, so just send the command.
*/
memcpy(set_cmd, set_controller_duty_cmd, SET_CMD_LENGTH);
set_cmd[RYUJIN_SET_CONTROLLER_FAN_DUTY_OFFSET] = val;
ret =
rog_ryujin_execute_cmd(priv, set_cmd, SET_CMD_LENGTH,
&priv->controller_duty_set); if (ret < 0) return ret;
}
/* Lock onto this value until next refresh cycle */
priv->duty_input[channel] = val;
return 0;
}
staticint rog_ryujin_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long val)
{ struct rog_ryujin_data *priv = dev_get_drvdata(dev); int ret;
switch (type) { case hwmon_pwm: switch (attr) { case hwmon_pwm_input: if (val < 0 || val > 255) return -EINVAL;
if (data[1] == RYUJIN_GET_COOLER_STATUS_CMD_RESPONSE) { /* Received coolant temp and speeds of pump and internal fan */
priv->temp_input[0] =
data[RYUJIN_TEMP_SENSOR_1] * 1000 + data[RYUJIN_TEMP_SENSOR_2] * 100;
priv->speed_input[0] = get_unaligned_le16(data + RYUJIN_PUMP_SPEED);
priv->speed_input[1] = get_unaligned_le16(data + RYUJIN_INTERNAL_FAN_SPEED);
if (!completion_done(&priv->cooler_status_received))
complete_all(&priv->cooler_status_received);
} elseif (data[1] == RYUJIN_GET_CONTROLLER_SPEED_CMD_RESPONSE) { /* Received speeds of four fans attached to the controller */
priv->speed_input[2] = get_unaligned_le16(data + RYUJIN_CONTROLLER_SPEED_1);
priv->speed_input[3] = get_unaligned_le16(data + RYUJIN_CONTROLLER_SPEED_2);
priv->speed_input[4] = get_unaligned_le16(data + RYUJIN_CONTROLLER_SPEED_3);
priv->speed_input[5] = get_unaligned_le16(data + RYUJIN_CONTROLLER_SPEED_4);
if (!completion_done(&priv->controller_status_received))
complete_all(&priv->controller_status_received);
} elseif (data[1] == RYUJIN_GET_COOLER_DUTY_CMD_RESPONSE) { /* Received report for pump and internal fan duties (in %) */ if (data[RYUJIN_PUMP_DUTY] == 0 && data[RYUJIN_INTERNAL_FAN_DUTY] == 0) { /* * We received a report with zeroes for duty in both places. * The device returns this as a confirmation that setting values * is successful. If we initiated a write, mark it as complete.
*/ if (!completion_done(&priv->cooler_duty_set))
complete_all(&priv->cooler_duty_set); elseif (!completion_done(&priv->cooler_duty_received)) /* * We didn't initiate a write, but received both zeroes. * This means that either both duties are actually zero, * or that we received a success report caused by userspace. * We're expecting a report, so parse it.
*/ goto read_cooler_duty; return 0;
}
read_cooler_duty:
priv->duty_input[0] = rog_ryujin_percent_to_pwm(data[RYUJIN_PUMP_DUTY]);
priv->duty_input[1] = rog_ryujin_percent_to_pwm(data[RYUJIN_INTERNAL_FAN_DUTY]);
if (!completion_done(&priv->cooler_duty_received))
complete_all(&priv->cooler_duty_received);
} elseif (data[1] == RYUJIN_GET_CONTROLLER_DUTY_CMD_RESPONSE) { /* Received report for controller duty for fans (in PWM) */ if (data[RYUJIN_CONTROLLER_DUTY] == 0) { /* * We received a report with a zero for duty. The device returns this as * a confirmation that setting the controller duty value was successful. * If we initiated a write, mark it as complete.
*/ if (!completion_done(&priv->controller_duty_set))
complete_all(&priv->controller_duty_set); elseif (!completion_done(&priv->controller_duty_received)) /* * We didn't initiate a write, but received a zero for duty. * This means that either the duty is actually zero, or that * we received a success report caused by userspace. * We're expecting a report, so parse it.
*/ goto read_controller_duty; return 0;
}
read_controller_duty:
priv->duty_input[2] = data[RYUJIN_CONTROLLER_DUTY];
if (!completion_done(&priv->controller_duty_received))
complete_all(&priv->controller_duty_received);
}
priv = devm_kzalloc(&hdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM;
priv->hdev = hdev;
hid_set_drvdata(hdev, priv);
/* * Initialize priv->updated to STATUS_VALIDITY seconds in the past, making * the initial empty data invalid for rog_ryujin_read() without the need for * a special case there.
*/
priv->updated = jiffies - msecs_to_jiffies(STATUS_VALIDITY);
ret = hid_parse(hdev); if (ret) {
hid_err(hdev, "hid parse failed with %d\n", ret); return ret;
}
/* Enable hidraw so existing user-space tools can continue to work */
ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); if (ret) {
hid_err(hdev, "hid hw start failed with %d\n", ret); return ret;
}
ret = hid_hw_open(hdev); if (ret) {
hid_err(hdev, "hid hw open failed with %d\n", ret); goto fail_and_stop;
}
priv->buffer = devm_kzalloc(&hdev->dev, MAX_REPORT_LENGTH, GFP_KERNEL); if (!priv->buffer) {
ret = -ENOMEM; goto fail_and_close;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.