0001
0002
0003
0004
0005
0006
0007 #include <linux/completion.h>
0008 #include <linux/debugfs.h>
0009 #include <linux/errno.h>
0010 #include <linux/hid.h>
0011 #include <linux/hwmon.h>
0012 #include <linux/hwmon-sysfs.h>
0013 #include <linux/jiffies.h>
0014 #include <linux/kernel.h>
0015 #include <linux/module.h>
0016 #include <linux/mutex.h>
0017 #include <linux/slab.h>
0018 #include <linux/types.h>
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049 #define DRIVER_NAME "corsair-psu"
0050
0051 #define REPLY_SIZE 16
0052 #define CMD_BUFFER_SIZE 64
0053 #define CMD_TIMEOUT_MS 250
0054 #define SECONDS_PER_HOUR (60 * 60)
0055 #define SECONDS_PER_DAY (SECONDS_PER_HOUR * 24)
0056 #define RAIL_COUNT 3
0057 #define TEMP_COUNT 2
0058
0059 #define PSU_CMD_SELECT_RAIL 0x00
0060 #define PSU_CMD_RAIL_VOLTS_HCRIT 0x40
0061 #define PSU_CMD_RAIL_VOLTS_LCRIT 0x44
0062 #define PSU_CMD_RAIL_AMPS_HCRIT 0x46
0063 #define PSU_CMD_TEMP_HCRIT 0x4F
0064 #define PSU_CMD_IN_VOLTS 0x88
0065 #define PSU_CMD_IN_AMPS 0x89
0066 #define PSU_CMD_RAIL_VOLTS 0x8B
0067 #define PSU_CMD_RAIL_AMPS 0x8C
0068 #define PSU_CMD_TEMP0 0x8D
0069 #define PSU_CMD_TEMP1 0x8E
0070 #define PSU_CMD_FAN 0x90
0071 #define PSU_CMD_RAIL_WATTS 0x96
0072 #define PSU_CMD_VEND_STR 0x99
0073 #define PSU_CMD_PROD_STR 0x9A
0074 #define PSU_CMD_TOTAL_WATTS 0xEE
0075 #define PSU_CMD_TOTAL_UPTIME 0xD1
0076 #define PSU_CMD_UPTIME 0xD2
0077 #define PSU_CMD_INIT 0xFE
0078
0079 #define L_IN_VOLTS "v_in"
0080 #define L_OUT_VOLTS_12V "v_out +12v"
0081 #define L_OUT_VOLTS_5V "v_out +5v"
0082 #define L_OUT_VOLTS_3_3V "v_out +3.3v"
0083 #define L_IN_AMPS "curr in"
0084 #define L_AMPS_12V "curr +12v"
0085 #define L_AMPS_5V "curr +5v"
0086 #define L_AMPS_3_3V "curr +3.3v"
0087 #define L_FAN "psu fan"
0088 #define L_TEMP0 "vrm temp"
0089 #define L_TEMP1 "case temp"
0090 #define L_WATTS "power total"
0091 #define L_WATTS_12V "power +12v"
0092 #define L_WATTS_5V "power +5v"
0093 #define L_WATTS_3_3V "power +3.3v"
0094
0095 static const char *const label_watts[] = {
0096 L_WATTS,
0097 L_WATTS_12V,
0098 L_WATTS_5V,
0099 L_WATTS_3_3V
0100 };
0101
0102 static const char *const label_volts[] = {
0103 L_IN_VOLTS,
0104 L_OUT_VOLTS_12V,
0105 L_OUT_VOLTS_5V,
0106 L_OUT_VOLTS_3_3V
0107 };
0108
0109 static const char *const label_amps[] = {
0110 L_IN_AMPS,
0111 L_AMPS_12V,
0112 L_AMPS_5V,
0113 L_AMPS_3_3V
0114 };
0115
0116 struct corsairpsu_data {
0117 struct hid_device *hdev;
0118 struct device *hwmon_dev;
0119 struct dentry *debugfs;
0120 struct completion wait_completion;
0121 struct mutex lock;
0122 u8 *cmd_buffer;
0123 char vendor[REPLY_SIZE];
0124 char product[REPLY_SIZE];
0125 long temp_crit[TEMP_COUNT];
0126 long in_crit[RAIL_COUNT];
0127 long in_lcrit[RAIL_COUNT];
0128 long curr_crit[RAIL_COUNT];
0129 u8 temp_crit_support;
0130 u8 in_crit_support;
0131 u8 in_lcrit_support;
0132 u8 curr_crit_support;
0133 bool in_curr_cmd_support;
0134 };
0135
0136
0137 static int corsairpsu_linear11_to_int(const u16 val, const int scale)
0138 {
0139 const int exp = ((s16)val) >> 11;
0140 const int mant = (((s16)(val & 0x7ff)) << 5) >> 5;
0141 const int result = mant * scale;
0142
0143 return (exp >= 0) ? (result << exp) : (result >> -exp);
0144 }
0145
0146 static int corsairpsu_usb_cmd(struct corsairpsu_data *priv, u8 p0, u8 p1, u8 p2, void *data)
0147 {
0148 unsigned long time;
0149 int ret;
0150
0151 memset(priv->cmd_buffer, 0, CMD_BUFFER_SIZE);
0152 priv->cmd_buffer[0] = p0;
0153 priv->cmd_buffer[1] = p1;
0154 priv->cmd_buffer[2] = p2;
0155
0156 reinit_completion(&priv->wait_completion);
0157
0158 ret = hid_hw_output_report(priv->hdev, priv->cmd_buffer, CMD_BUFFER_SIZE);
0159 if (ret < 0)
0160 return ret;
0161
0162 time = wait_for_completion_timeout(&priv->wait_completion,
0163 msecs_to_jiffies(CMD_TIMEOUT_MS));
0164 if (!time)
0165 return -ETIMEDOUT;
0166
0167
0168
0169
0170
0171
0172 if (p0 != priv->cmd_buffer[0] || p1 != priv->cmd_buffer[1])
0173 return -EOPNOTSUPP;
0174
0175 if (data)
0176 memcpy(data, priv->cmd_buffer + 2, REPLY_SIZE);
0177
0178 return 0;
0179 }
0180
0181 static int corsairpsu_init(struct corsairpsu_data *priv)
0182 {
0183
0184
0185
0186
0187 return corsairpsu_usb_cmd(priv, PSU_CMD_INIT, 3, 0, NULL);
0188 }
0189
0190 static int corsairpsu_fwinfo(struct corsairpsu_data *priv)
0191 {
0192 int ret;
0193
0194 ret = corsairpsu_usb_cmd(priv, 3, PSU_CMD_VEND_STR, 0, priv->vendor);
0195 if (ret < 0)
0196 return ret;
0197
0198 ret = corsairpsu_usb_cmd(priv, 3, PSU_CMD_PROD_STR, 0, priv->product);
0199 if (ret < 0)
0200 return ret;
0201
0202 return 0;
0203 }
0204
0205 static int corsairpsu_request(struct corsairpsu_data *priv, u8 cmd, u8 rail, void *data)
0206 {
0207 int ret;
0208
0209 mutex_lock(&priv->lock);
0210 switch (cmd) {
0211 case PSU_CMD_RAIL_VOLTS_HCRIT:
0212 case PSU_CMD_RAIL_VOLTS_LCRIT:
0213 case PSU_CMD_RAIL_AMPS_HCRIT:
0214 case PSU_CMD_RAIL_VOLTS:
0215 case PSU_CMD_RAIL_AMPS:
0216 case PSU_CMD_RAIL_WATTS:
0217 ret = corsairpsu_usb_cmd(priv, 2, PSU_CMD_SELECT_RAIL, rail, NULL);
0218 if (ret < 0)
0219 goto cmd_fail;
0220 break;
0221 default:
0222 break;
0223 }
0224
0225 ret = corsairpsu_usb_cmd(priv, 3, cmd, 0, data);
0226
0227 cmd_fail:
0228 mutex_unlock(&priv->lock);
0229 return ret;
0230 }
0231
0232 static int corsairpsu_get_value(struct corsairpsu_data *priv, u8 cmd, u8 rail, long *val)
0233 {
0234 u8 data[REPLY_SIZE];
0235 long tmp;
0236 int ret;
0237
0238 ret = corsairpsu_request(priv, cmd, rail, data);
0239 if (ret < 0)
0240 return ret;
0241
0242
0243
0244
0245
0246
0247
0248 tmp = ((long)data[3] << 24) + (data[2] << 16) + (data[1] << 8) + data[0];
0249 switch (cmd) {
0250 case PSU_CMD_RAIL_VOLTS_HCRIT:
0251 case PSU_CMD_RAIL_VOLTS_LCRIT:
0252 case PSU_CMD_RAIL_AMPS_HCRIT:
0253 case PSU_CMD_TEMP_HCRIT:
0254 case PSU_CMD_IN_VOLTS:
0255 case PSU_CMD_IN_AMPS:
0256 case PSU_CMD_RAIL_VOLTS:
0257 case PSU_CMD_RAIL_AMPS:
0258 case PSU_CMD_TEMP0:
0259 case PSU_CMD_TEMP1:
0260 *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1000);
0261 break;
0262 case PSU_CMD_FAN:
0263 *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1);
0264 break;
0265 case PSU_CMD_RAIL_WATTS:
0266 case PSU_CMD_TOTAL_WATTS:
0267 *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1000000);
0268 break;
0269 case PSU_CMD_TOTAL_UPTIME:
0270 case PSU_CMD_UPTIME:
0271 *val = tmp;
0272 break;
0273 default:
0274 ret = -EOPNOTSUPP;
0275 break;
0276 }
0277
0278 return ret;
0279 }
0280
0281 static void corsairpsu_get_criticals(struct corsairpsu_data *priv)
0282 {
0283 long tmp;
0284 int rail;
0285
0286 for (rail = 0; rail < TEMP_COUNT; ++rail) {
0287 if (!corsairpsu_get_value(priv, PSU_CMD_TEMP_HCRIT, rail, &tmp)) {
0288 priv->temp_crit_support |= BIT(rail);
0289 priv->temp_crit[rail] = tmp;
0290 }
0291 }
0292
0293 for (rail = 0; rail < RAIL_COUNT; ++rail) {
0294 if (!corsairpsu_get_value(priv, PSU_CMD_RAIL_VOLTS_HCRIT, rail, &tmp)) {
0295 priv->in_crit_support |= BIT(rail);
0296 priv->in_crit[rail] = tmp;
0297 }
0298
0299 if (!corsairpsu_get_value(priv, PSU_CMD_RAIL_VOLTS_LCRIT, rail, &tmp)) {
0300 priv->in_lcrit_support |= BIT(rail);
0301 priv->in_lcrit[rail] = tmp;
0302 }
0303
0304 if (!corsairpsu_get_value(priv, PSU_CMD_RAIL_AMPS_HCRIT, rail, &tmp)) {
0305 priv->curr_crit_support |= BIT(rail);
0306 priv->curr_crit[rail] = tmp;
0307 }
0308 }
0309 }
0310
0311 static void corsairpsu_check_cmd_support(struct corsairpsu_data *priv)
0312 {
0313 long tmp;
0314
0315 priv->in_curr_cmd_support = !corsairpsu_get_value(priv, PSU_CMD_IN_AMPS, 0, &tmp);
0316 }
0317
0318 static umode_t corsairpsu_hwmon_temp_is_visible(const struct corsairpsu_data *priv, u32 attr,
0319 int channel)
0320 {
0321 umode_t res = 0444;
0322
0323 switch (attr) {
0324 case hwmon_temp_input:
0325 case hwmon_temp_label:
0326 case hwmon_temp_crit:
0327 if (channel > 0 && !(priv->temp_crit_support & BIT(channel - 1)))
0328 res = 0;
0329 break;
0330 default:
0331 break;
0332 }
0333
0334 return res;
0335 }
0336
0337 static umode_t corsairpsu_hwmon_fan_is_visible(const struct corsairpsu_data *priv, u32 attr,
0338 int channel)
0339 {
0340 switch (attr) {
0341 case hwmon_fan_input:
0342 case hwmon_fan_label:
0343 return 0444;
0344 default:
0345 return 0;
0346 }
0347 }
0348
0349 static umode_t corsairpsu_hwmon_power_is_visible(const struct corsairpsu_data *priv, u32 attr,
0350 int channel)
0351 {
0352 switch (attr) {
0353 case hwmon_power_input:
0354 case hwmon_power_label:
0355 return 0444;
0356 default:
0357 return 0;
0358 }
0359 }
0360
0361 static umode_t corsairpsu_hwmon_in_is_visible(const struct corsairpsu_data *priv, u32 attr,
0362 int channel)
0363 {
0364 umode_t res = 0444;
0365
0366 switch (attr) {
0367 case hwmon_in_input:
0368 case hwmon_in_label:
0369 case hwmon_in_crit:
0370 if (channel > 0 && !(priv->in_crit_support & BIT(channel - 1)))
0371 res = 0;
0372 break;
0373 case hwmon_in_lcrit:
0374 if (channel > 0 && !(priv->in_lcrit_support & BIT(channel - 1)))
0375 res = 0;
0376 break;
0377 default:
0378 break;
0379 }
0380
0381 return res;
0382 }
0383
0384 static umode_t corsairpsu_hwmon_curr_is_visible(const struct corsairpsu_data *priv, u32 attr,
0385 int channel)
0386 {
0387 umode_t res = 0444;
0388
0389 switch (attr) {
0390 case hwmon_curr_input:
0391 if (channel == 0 && !priv->in_curr_cmd_support)
0392 res = 0;
0393 break;
0394 case hwmon_curr_label:
0395 case hwmon_curr_crit:
0396 if (channel > 0 && !(priv->curr_crit_support & BIT(channel - 1)))
0397 res = 0;
0398 break;
0399 default:
0400 break;
0401 }
0402
0403 return res;
0404 }
0405
0406 static umode_t corsairpsu_hwmon_ops_is_visible(const void *data, enum hwmon_sensor_types type,
0407 u32 attr, int channel)
0408 {
0409 const struct corsairpsu_data *priv = data;
0410
0411 switch (type) {
0412 case hwmon_temp:
0413 return corsairpsu_hwmon_temp_is_visible(priv, attr, channel);
0414 case hwmon_fan:
0415 return corsairpsu_hwmon_fan_is_visible(priv, attr, channel);
0416 case hwmon_power:
0417 return corsairpsu_hwmon_power_is_visible(priv, attr, channel);
0418 case hwmon_in:
0419 return corsairpsu_hwmon_in_is_visible(priv, attr, channel);
0420 case hwmon_curr:
0421 return corsairpsu_hwmon_curr_is_visible(priv, attr, channel);
0422 default:
0423 return 0;
0424 }
0425 }
0426
0427 static int corsairpsu_hwmon_temp_read(struct corsairpsu_data *priv, u32 attr, int channel,
0428 long *val)
0429 {
0430 int err = -EOPNOTSUPP;
0431
0432 switch (attr) {
0433 case hwmon_temp_input:
0434 return corsairpsu_get_value(priv, channel ? PSU_CMD_TEMP1 : PSU_CMD_TEMP0,
0435 channel, val);
0436 case hwmon_temp_crit:
0437 *val = priv->temp_crit[channel];
0438 err = 0;
0439 break;
0440 default:
0441 break;
0442 }
0443
0444 return err;
0445 }
0446
0447 static int corsairpsu_hwmon_power_read(struct corsairpsu_data *priv, u32 attr, int channel,
0448 long *val)
0449 {
0450 if (attr == hwmon_power_input) {
0451 switch (channel) {
0452 case 0:
0453 return corsairpsu_get_value(priv, PSU_CMD_TOTAL_WATTS, 0, val);
0454 case 1 ... 3:
0455 return corsairpsu_get_value(priv, PSU_CMD_RAIL_WATTS, channel - 1, val);
0456 default:
0457 break;
0458 }
0459 }
0460
0461 return -EOPNOTSUPP;
0462 }
0463
0464 static int corsairpsu_hwmon_in_read(struct corsairpsu_data *priv, u32 attr, int channel, long *val)
0465 {
0466 int err = -EOPNOTSUPP;
0467
0468 switch (attr) {
0469 case hwmon_in_input:
0470 switch (channel) {
0471 case 0:
0472 return corsairpsu_get_value(priv, PSU_CMD_IN_VOLTS, 0, val);
0473 case 1 ... 3:
0474 return corsairpsu_get_value(priv, PSU_CMD_RAIL_VOLTS, channel - 1, val);
0475 default:
0476 break;
0477 }
0478 break;
0479 case hwmon_in_crit:
0480 *val = priv->in_crit[channel - 1];
0481 err = 0;
0482 break;
0483 case hwmon_in_lcrit:
0484 *val = priv->in_lcrit[channel - 1];
0485 err = 0;
0486 break;
0487 }
0488
0489 return err;
0490 }
0491
0492 static int corsairpsu_hwmon_curr_read(struct corsairpsu_data *priv, u32 attr, int channel,
0493 long *val)
0494 {
0495 int err = -EOPNOTSUPP;
0496
0497 switch (attr) {
0498 case hwmon_curr_input:
0499 switch (channel) {
0500 case 0:
0501 return corsairpsu_get_value(priv, PSU_CMD_IN_AMPS, 0, val);
0502 case 1 ... 3:
0503 return corsairpsu_get_value(priv, PSU_CMD_RAIL_AMPS, channel - 1, val);
0504 default:
0505 break;
0506 }
0507 break;
0508 case hwmon_curr_crit:
0509 *val = priv->curr_crit[channel - 1];
0510 err = 0;
0511 break;
0512 default:
0513 break;
0514 }
0515
0516 return err;
0517 }
0518
0519 static int corsairpsu_hwmon_ops_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
0520 int channel, long *val)
0521 {
0522 struct corsairpsu_data *priv = dev_get_drvdata(dev);
0523
0524 switch (type) {
0525 case hwmon_temp:
0526 return corsairpsu_hwmon_temp_read(priv, attr, channel, val);
0527 case hwmon_fan:
0528 if (attr == hwmon_fan_input)
0529 return corsairpsu_get_value(priv, PSU_CMD_FAN, 0, val);
0530 return -EOPNOTSUPP;
0531 case hwmon_power:
0532 return corsairpsu_hwmon_power_read(priv, attr, channel, val);
0533 case hwmon_in:
0534 return corsairpsu_hwmon_in_read(priv, attr, channel, val);
0535 case hwmon_curr:
0536 return corsairpsu_hwmon_curr_read(priv, attr, channel, val);
0537 default:
0538 return -EOPNOTSUPP;
0539 }
0540 }
0541
0542 static int corsairpsu_hwmon_ops_read_string(struct device *dev, enum hwmon_sensor_types type,
0543 u32 attr, int channel, const char **str)
0544 {
0545 if (type == hwmon_temp && attr == hwmon_temp_label) {
0546 *str = channel ? L_TEMP1 : L_TEMP0;
0547 return 0;
0548 } else if (type == hwmon_fan && attr == hwmon_fan_label) {
0549 *str = L_FAN;
0550 return 0;
0551 } else if (type == hwmon_power && attr == hwmon_power_label && channel < 4) {
0552 *str = label_watts[channel];
0553 return 0;
0554 } else if (type == hwmon_in && attr == hwmon_in_label && channel < 4) {
0555 *str = label_volts[channel];
0556 return 0;
0557 } else if (type == hwmon_curr && attr == hwmon_curr_label && channel < 4) {
0558 *str = label_amps[channel];
0559 return 0;
0560 }
0561
0562 return -EOPNOTSUPP;
0563 }
0564
0565 static const struct hwmon_ops corsairpsu_hwmon_ops = {
0566 .is_visible = corsairpsu_hwmon_ops_is_visible,
0567 .read = corsairpsu_hwmon_ops_read,
0568 .read_string = corsairpsu_hwmon_ops_read_string,
0569 };
0570
0571 static const struct hwmon_channel_info *corsairpsu_info[] = {
0572 HWMON_CHANNEL_INFO(chip,
0573 HWMON_C_REGISTER_TZ),
0574 HWMON_CHANNEL_INFO(temp,
0575 HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT,
0576 HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT),
0577 HWMON_CHANNEL_INFO(fan,
0578 HWMON_F_INPUT | HWMON_F_LABEL),
0579 HWMON_CHANNEL_INFO(power,
0580 HWMON_P_INPUT | HWMON_P_LABEL,
0581 HWMON_P_INPUT | HWMON_P_LABEL,
0582 HWMON_P_INPUT | HWMON_P_LABEL,
0583 HWMON_P_INPUT | HWMON_P_LABEL),
0584 HWMON_CHANNEL_INFO(in,
0585 HWMON_I_INPUT | HWMON_I_LABEL,
0586 HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_LCRIT | HWMON_I_CRIT,
0587 HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_LCRIT | HWMON_I_CRIT,
0588 HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_LCRIT | HWMON_I_CRIT),
0589 HWMON_CHANNEL_INFO(curr,
0590 HWMON_C_INPUT | HWMON_C_LABEL,
0591 HWMON_C_INPUT | HWMON_C_LABEL | HWMON_C_CRIT,
0592 HWMON_C_INPUT | HWMON_C_LABEL | HWMON_C_CRIT,
0593 HWMON_C_INPUT | HWMON_C_LABEL | HWMON_C_CRIT),
0594 NULL
0595 };
0596
0597 static const struct hwmon_chip_info corsairpsu_chip_info = {
0598 .ops = &corsairpsu_hwmon_ops,
0599 .info = corsairpsu_info,
0600 };
0601
0602 #ifdef CONFIG_DEBUG_FS
0603
0604 static void print_uptime(struct seq_file *seqf, u8 cmd)
0605 {
0606 struct corsairpsu_data *priv = seqf->private;
0607 long val;
0608 int ret;
0609
0610 ret = corsairpsu_get_value(priv, cmd, 0, &val);
0611 if (ret < 0) {
0612 seq_puts(seqf, "N/A\n");
0613 return;
0614 }
0615
0616 if (val > SECONDS_PER_DAY) {
0617 seq_printf(seqf, "%ld day(s), %02ld:%02ld:%02ld\n", val / SECONDS_PER_DAY,
0618 val % SECONDS_PER_DAY / SECONDS_PER_HOUR, val % SECONDS_PER_HOUR / 60,
0619 val % 60);
0620 return;
0621 }
0622
0623 seq_printf(seqf, "%02ld:%02ld:%02ld\n", val % SECONDS_PER_DAY / SECONDS_PER_HOUR,
0624 val % SECONDS_PER_HOUR / 60, val % 60);
0625 }
0626
0627 static int uptime_show(struct seq_file *seqf, void *unused)
0628 {
0629 print_uptime(seqf, PSU_CMD_UPTIME);
0630
0631 return 0;
0632 }
0633 DEFINE_SHOW_ATTRIBUTE(uptime);
0634
0635 static int uptime_total_show(struct seq_file *seqf, void *unused)
0636 {
0637 print_uptime(seqf, PSU_CMD_TOTAL_UPTIME);
0638
0639 return 0;
0640 }
0641 DEFINE_SHOW_ATTRIBUTE(uptime_total);
0642
0643 static int vendor_show(struct seq_file *seqf, void *unused)
0644 {
0645 struct corsairpsu_data *priv = seqf->private;
0646
0647 seq_printf(seqf, "%s\n", priv->vendor);
0648
0649 return 0;
0650 }
0651 DEFINE_SHOW_ATTRIBUTE(vendor);
0652
0653 static int product_show(struct seq_file *seqf, void *unused)
0654 {
0655 struct corsairpsu_data *priv = seqf->private;
0656
0657 seq_printf(seqf, "%s\n", priv->product);
0658
0659 return 0;
0660 }
0661 DEFINE_SHOW_ATTRIBUTE(product);
0662
0663 static void corsairpsu_debugfs_init(struct corsairpsu_data *priv)
0664 {
0665 char name[32];
0666
0667 scnprintf(name, sizeof(name), "%s-%s", DRIVER_NAME, dev_name(&priv->hdev->dev));
0668
0669 priv->debugfs = debugfs_create_dir(name, NULL);
0670 debugfs_create_file("uptime", 0444, priv->debugfs, priv, &uptime_fops);
0671 debugfs_create_file("uptime_total", 0444, priv->debugfs, priv, &uptime_total_fops);
0672 debugfs_create_file("vendor", 0444, priv->debugfs, priv, &vendor_fops);
0673 debugfs_create_file("product", 0444, priv->debugfs, priv, &product_fops);
0674 }
0675
0676 #else
0677
0678 static void corsairpsu_debugfs_init(struct corsairpsu_data *priv)
0679 {
0680 }
0681
0682 #endif
0683
0684 static int corsairpsu_probe(struct hid_device *hdev, const struct hid_device_id *id)
0685 {
0686 struct corsairpsu_data *priv;
0687 int ret;
0688
0689 priv = devm_kzalloc(&hdev->dev, sizeof(struct corsairpsu_data), GFP_KERNEL);
0690 if (!priv)
0691 return -ENOMEM;
0692
0693 priv->cmd_buffer = devm_kmalloc(&hdev->dev, CMD_BUFFER_SIZE, GFP_KERNEL);
0694 if (!priv->cmd_buffer)
0695 return -ENOMEM;
0696
0697 ret = hid_parse(hdev);
0698 if (ret)
0699 return ret;
0700
0701 ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
0702 if (ret)
0703 return ret;
0704
0705 ret = hid_hw_open(hdev);
0706 if (ret)
0707 goto fail_and_stop;
0708
0709 priv->hdev = hdev;
0710 hid_set_drvdata(hdev, priv);
0711 mutex_init(&priv->lock);
0712 init_completion(&priv->wait_completion);
0713
0714 hid_device_io_start(hdev);
0715
0716 ret = corsairpsu_init(priv);
0717 if (ret < 0) {
0718 dev_err(&hdev->dev, "unable to initialize device (%d)\n", ret);
0719 goto fail_and_stop;
0720 }
0721
0722 ret = corsairpsu_fwinfo(priv);
0723 if (ret < 0) {
0724 dev_err(&hdev->dev, "unable to query firmware (%d)\n", ret);
0725 goto fail_and_stop;
0726 }
0727
0728 corsairpsu_get_criticals(priv);
0729 corsairpsu_check_cmd_support(priv);
0730
0731 priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "corsairpsu", priv,
0732 &corsairpsu_chip_info, NULL);
0733
0734 if (IS_ERR(priv->hwmon_dev)) {
0735 ret = PTR_ERR(priv->hwmon_dev);
0736 goto fail_and_close;
0737 }
0738
0739 corsairpsu_debugfs_init(priv);
0740
0741 return 0;
0742
0743 fail_and_close:
0744 hid_hw_close(hdev);
0745 fail_and_stop:
0746 hid_hw_stop(hdev);
0747 return ret;
0748 }
0749
0750 static void corsairpsu_remove(struct hid_device *hdev)
0751 {
0752 struct corsairpsu_data *priv = hid_get_drvdata(hdev);
0753
0754 debugfs_remove_recursive(priv->debugfs);
0755 hwmon_device_unregister(priv->hwmon_dev);
0756 hid_hw_close(hdev);
0757 hid_hw_stop(hdev);
0758 }
0759
0760 static int corsairpsu_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data,
0761 int size)
0762 {
0763 struct corsairpsu_data *priv = hid_get_drvdata(hdev);
0764
0765 if (completion_done(&priv->wait_completion))
0766 return 0;
0767
0768 memcpy(priv->cmd_buffer, data, min(CMD_BUFFER_SIZE, size));
0769 complete(&priv->wait_completion);
0770
0771 return 0;
0772 }
0773
0774 #ifdef CONFIG_PM
0775 static int corsairpsu_resume(struct hid_device *hdev)
0776 {
0777 struct corsairpsu_data *priv = hid_get_drvdata(hdev);
0778
0779
0780 return corsairpsu_init(priv);
0781 }
0782 #endif
0783
0784 static const struct hid_device_id corsairpsu_idtable[] = {
0785 { HID_USB_DEVICE(0x1b1c, 0x1c03) },
0786 { HID_USB_DEVICE(0x1b1c, 0x1c04) },
0787 { HID_USB_DEVICE(0x1b1c, 0x1c05) },
0788 { HID_USB_DEVICE(0x1b1c, 0x1c06) },
0789 { HID_USB_DEVICE(0x1b1c, 0x1c07) },
0790 { HID_USB_DEVICE(0x1b1c, 0x1c08) },
0791 { HID_USB_DEVICE(0x1b1c, 0x1c09) },
0792 { HID_USB_DEVICE(0x1b1c, 0x1c0a) },
0793 { HID_USB_DEVICE(0x1b1c, 0x1c0b) },
0794 { HID_USB_DEVICE(0x1b1c, 0x1c0c) },
0795 { HID_USB_DEVICE(0x1b1c, 0x1c0d) },
0796 { },
0797 };
0798 MODULE_DEVICE_TABLE(hid, corsairpsu_idtable);
0799
0800 static struct hid_driver corsairpsu_driver = {
0801 .name = DRIVER_NAME,
0802 .id_table = corsairpsu_idtable,
0803 .probe = corsairpsu_probe,
0804 .remove = corsairpsu_remove,
0805 .raw_event = corsairpsu_raw_event,
0806 #ifdef CONFIG_PM
0807 .resume = corsairpsu_resume,
0808 .reset_resume = corsairpsu_resume,
0809 #endif
0810 };
0811 module_hid_driver(corsairpsu_driver);
0812
0813 MODULE_LICENSE("GPL");
0814 MODULE_AUTHOR("Wilken Gottwalt <wilken.gottwalt@posteo.net>");
0815 MODULE_DESCRIPTION("Linux driver for Corsair power supplies with HID sensors interface");