]> Git Repo - linux.git/blob - drivers/hwmon/corsair-cpro.c
crypto: akcipher - Drop sign/verify operations
[linux.git] / drivers / hwmon / corsair-cpro.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * corsair-cpro.c - Linux driver for Corsair Commander Pro
4  * Copyright (C) 2020 Marius Zachmann <[email protected]>
5  *
6  * This driver uses hid reports to communicate with the device to allow hidraw userspace drivers
7  * still being used. The device does not use report ids. When using hidraw and this driver
8  * simultaniously, reports could be switched.
9  */
10
11 #include <linux/bitops.h>
12 #include <linux/completion.h>
13 #include <linux/debugfs.h>
14 #include <linux/hid.h>
15 #include <linux/hwmon.h>
16 #include <linux/kernel.h>
17 #include <linux/module.h>
18 #include <linux/mutex.h>
19 #include <linux/seq_file.h>
20 #include <linux/slab.h>
21 #include <linux/spinlock.h>
22 #include <linux/types.h>
23
24 #define USB_VENDOR_ID_CORSAIR                   0x1b1c
25 #define USB_PRODUCT_ID_CORSAIR_COMMANDERPRO     0x0c10
26 #define USB_PRODUCT_ID_CORSAIR_1000D            0x1d00
27
28 #define OUT_BUFFER_SIZE         63
29 #define IN_BUFFER_SIZE          16
30 #define LABEL_LENGTH            11
31 #define REQ_TIMEOUT             300
32
33 #define CTL_GET_FW_VER          0x02    /* returns the firmware version in bytes 1-3 */
34 #define CTL_GET_BL_VER          0x06    /* returns the bootloader version in bytes 1-2 */
35 #define CTL_GET_TMP_CNCT        0x10    /*
36                                          * returns in bytes 1-4 for each temp sensor:
37                                          * 0 not connected
38                                          * 1 connected
39                                          */
40 #define CTL_GET_TMP             0x11    /*
41                                          * send: byte 1 is channel, rest zero
42                                          * rcv:  returns temp for channel in centi-degree celsius
43                                          * in bytes 1 and 2
44                                          * returns 0x11 in byte 0 if no sensor is connected
45                                          */
46 #define CTL_GET_VOLT            0x12    /*
47                                          * send: byte 1 is rail number: 0 = 12v, 1 = 5v, 2 = 3.3v
48                                          * rcv:  returns millivolt in bytes 1,2
49                                          * returns error 0x10 if request is invalid
50                                          */
51 #define CTL_GET_FAN_CNCT        0x20    /*
52                                          * returns in bytes 1-6 for each fan:
53                                          * 0 not connected
54                                          * 1 3pin
55                                          * 2 4pin
56                                          */
57 #define CTL_GET_FAN_RPM         0x21    /*
58                                          * send: byte 1 is channel, rest zero
59                                          * rcv:  returns rpm in bytes 1,2
60                                          */
61 #define CTL_GET_FAN_PWM         0x22    /*
62                                          * send: byte 1 is channel, rest zero
63                                          * rcv:  returns pwm in byte 1 if it was set
64                                          *       returns error 0x12 if fan is controlled via
65                                          *       fan_target or fan curve
66                                          */
67 #define CTL_SET_FAN_FPWM        0x23    /*
68                                          * set fixed pwm
69                                          * send: byte 1 is fan number
70                                          * send: byte 2 is percentage from 0 - 100
71                                          */
72 #define CTL_SET_FAN_TARGET      0x24    /*
73                                          * set target rpm
74                                          * send: byte 1 is fan number
75                                          * send: byte 2-3 is target
76                                          * device accepts all values from 0x00 - 0xFFFF
77                                          */
78
79 #define NUM_FANS                6
80 #define NUM_TEMP_SENSORS        4
81
82 struct ccp_device {
83         struct hid_device *hdev;
84         struct device *hwmon_dev;
85         struct dentry *debugfs;
86         /* For reinitializing the completion below */
87         spinlock_t wait_input_report_lock;
88         struct completion wait_input_report;
89         struct mutex mutex; /* whenever buffer is used, lock before send_usb_cmd */
90         u8 *cmd_buffer;
91         u8 *buffer;
92         int target[6];
93         DECLARE_BITMAP(temp_cnct, NUM_TEMP_SENSORS);
94         DECLARE_BITMAP(fan_cnct, NUM_FANS);
95         char fan_label[6][LABEL_LENGTH];
96         u8 firmware_ver[3];
97         u8 bootloader_ver[2];
98 };
99
100 /* converts response error in buffer to errno */
101 static int ccp_get_errno(struct ccp_device *ccp)
102 {
103         switch (ccp->buffer[0]) {
104         case 0x00: /* success */
105                 return 0;
106         case 0x01: /* called invalid command */
107                 return -EOPNOTSUPP;
108         case 0x10: /* called GET_VOLT / GET_TMP with invalid arguments */
109                 return -EINVAL;
110         case 0x11: /* requested temps of disconnected sensors */
111         case 0x12: /* requested pwm of not pwm controlled channels */
112                 return -ENODATA;
113         default:
114                 hid_dbg(ccp->hdev, "unknown device response error: %d", ccp->buffer[0]);
115                 return -EIO;
116         }
117 }
118
119 /* send command, check for error in response, response in ccp->buffer */
120 static int send_usb_cmd(struct ccp_device *ccp, u8 command, u8 byte1, u8 byte2, u8 byte3)
121 {
122         unsigned long t;
123         int ret;
124
125         memset(ccp->cmd_buffer, 0x00, OUT_BUFFER_SIZE);
126         ccp->cmd_buffer[0] = command;
127         ccp->cmd_buffer[1] = byte1;
128         ccp->cmd_buffer[2] = byte2;
129         ccp->cmd_buffer[3] = byte3;
130
131         /*
132          * Disable raw event parsing for a moment to safely reinitialize the
133          * completion. Reinit is done because hidraw could have triggered
134          * the raw event parsing and marked the ccp->wait_input_report
135          * completion as done.
136          */
137         spin_lock_bh(&ccp->wait_input_report_lock);
138         reinit_completion(&ccp->wait_input_report);
139         spin_unlock_bh(&ccp->wait_input_report_lock);
140
141         ret = hid_hw_output_report(ccp->hdev, ccp->cmd_buffer, OUT_BUFFER_SIZE);
142         if (ret < 0)
143                 return ret;
144
145         t = wait_for_completion_timeout(&ccp->wait_input_report, msecs_to_jiffies(REQ_TIMEOUT));
146         if (!t)
147                 return -ETIMEDOUT;
148
149         return ccp_get_errno(ccp);
150 }
151
152 static int ccp_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size)
153 {
154         struct ccp_device *ccp = hid_get_drvdata(hdev);
155
156         /* only copy buffer when requested */
157         spin_lock(&ccp->wait_input_report_lock);
158         if (!completion_done(&ccp->wait_input_report)) {
159                 memcpy(ccp->buffer, data, min(IN_BUFFER_SIZE, size));
160                 complete_all(&ccp->wait_input_report);
161         }
162         spin_unlock(&ccp->wait_input_report_lock);
163
164         return 0;
165 }
166
167 /* requests and returns single data values depending on channel */
168 static int get_data(struct ccp_device *ccp, int command, int channel, bool two_byte_data)
169 {
170         int ret;
171
172         mutex_lock(&ccp->mutex);
173
174         ret = send_usb_cmd(ccp, command, channel, 0, 0);
175         if (ret)
176                 goto out_unlock;
177
178         ret = ccp->buffer[1];
179         if (two_byte_data)
180                 ret = (ret << 8) + ccp->buffer[2];
181
182 out_unlock:
183         mutex_unlock(&ccp->mutex);
184         return ret;
185 }
186
187 static int set_pwm(struct ccp_device *ccp, int channel, long val)
188 {
189         int ret;
190
191         if (val < 0 || val > 255)
192                 return -EINVAL;
193
194         /* The Corsair Commander Pro uses values from 0-100 */
195         val = DIV_ROUND_CLOSEST(val * 100, 255);
196
197         mutex_lock(&ccp->mutex);
198
199         ret = send_usb_cmd(ccp, CTL_SET_FAN_FPWM, channel, val, 0);
200         if (!ret)
201                 ccp->target[channel] = -ENODATA;
202
203         mutex_unlock(&ccp->mutex);
204         return ret;
205 }
206
207 static int set_target(struct ccp_device *ccp, int channel, long val)
208 {
209         int ret;
210
211         val = clamp_val(val, 0, 0xFFFF);
212         ccp->target[channel] = val;
213
214         mutex_lock(&ccp->mutex);
215         ret = send_usb_cmd(ccp, CTL_SET_FAN_TARGET, channel, val >> 8, val);
216
217         mutex_unlock(&ccp->mutex);
218         return ret;
219 }
220
221 static int ccp_read_string(struct device *dev, enum hwmon_sensor_types type,
222                            u32 attr, int channel, const char **str)
223 {
224         struct ccp_device *ccp = dev_get_drvdata(dev);
225
226         switch (type) {
227         case hwmon_fan:
228                 switch (attr) {
229                 case hwmon_fan_label:
230                         *str = ccp->fan_label[channel];
231                         return 0;
232                 default:
233                         break;
234                 }
235                 break;
236         default:
237                 break;
238         }
239
240         return -EOPNOTSUPP;
241 }
242
243 static int ccp_read(struct device *dev, enum hwmon_sensor_types type,
244                     u32 attr, int channel, long *val)
245 {
246         struct ccp_device *ccp = dev_get_drvdata(dev);
247         int ret;
248
249         switch (type) {
250         case hwmon_temp:
251                 switch (attr) {
252                 case hwmon_temp_input:
253                         ret = get_data(ccp, CTL_GET_TMP, channel, true);
254                         if (ret < 0)
255                                 return ret;
256                         *val = ret * 10;
257                         return 0;
258                 default:
259                         break;
260                 }
261                 break;
262         case hwmon_fan:
263                 switch (attr) {
264                 case hwmon_fan_input:
265                         ret = get_data(ccp, CTL_GET_FAN_RPM, channel, true);
266                         if (ret < 0)
267                                 return ret;
268                         *val = ret;
269                         return 0;
270                 case hwmon_fan_target:
271                         /* how to read target values from the device is unknown */
272                         /* driver returns last set value or 0                   */
273                         if (ccp->target[channel] < 0)
274                                 return -ENODATA;
275                         *val = ccp->target[channel];
276                         return 0;
277                 default:
278                         break;
279                 }
280                 break;
281         case hwmon_pwm:
282                 switch (attr) {
283                 case hwmon_pwm_input:
284                         ret = get_data(ccp, CTL_GET_FAN_PWM, channel, false);
285                         if (ret < 0)
286                                 return ret;
287                         *val = DIV_ROUND_CLOSEST(ret * 255, 100);
288                         return 0;
289                 default:
290                         break;
291                 }
292                 break;
293         case hwmon_in:
294                 switch (attr) {
295                 case hwmon_in_input:
296                         ret = get_data(ccp, CTL_GET_VOLT, channel, true);
297                         if (ret < 0)
298                                 return ret;
299                         *val = ret;
300                         return 0;
301                 default:
302                         break;
303                 }
304                 break;
305         default:
306                 break;
307         }
308
309         return -EOPNOTSUPP;
310 };
311
312 static int ccp_write(struct device *dev, enum hwmon_sensor_types type,
313                      u32 attr, int channel, long val)
314 {
315         struct ccp_device *ccp = dev_get_drvdata(dev);
316
317         switch (type) {
318         case hwmon_pwm:
319                 switch (attr) {
320                 case hwmon_pwm_input:
321                         return set_pwm(ccp, channel, val);
322                 default:
323                         break;
324                 }
325                 break;
326         case hwmon_fan:
327                 switch (attr) {
328                 case hwmon_fan_target:
329                         return set_target(ccp, channel, val);
330                 default:
331                         break;
332                 }
333                 break;
334         default:
335                 break;
336         }
337
338         return -EOPNOTSUPP;
339 };
340
341 static umode_t ccp_is_visible(const void *data, enum hwmon_sensor_types type,
342                               u32 attr, int channel)
343 {
344         const struct ccp_device *ccp = data;
345
346         switch (type) {
347         case hwmon_temp:
348                 if (!test_bit(channel, ccp->temp_cnct))
349                         break;
350
351                 switch (attr) {
352                 case hwmon_temp_input:
353                         return 0444;
354                 case hwmon_temp_label:
355                         return 0444;
356                 default:
357                         break;
358                 }
359                 break;
360         case hwmon_fan:
361                 if (!test_bit(channel, ccp->fan_cnct))
362                         break;
363
364                 switch (attr) {
365                 case hwmon_fan_input:
366                         return 0444;
367                 case hwmon_fan_label:
368                         return 0444;
369                 case hwmon_fan_target:
370                         return 0644;
371                 default:
372                         break;
373                 }
374                 break;
375         case hwmon_pwm:
376                 if (!test_bit(channel, ccp->fan_cnct))
377                         break;
378
379                 switch (attr) {
380                 case hwmon_pwm_input:
381                         return 0644;
382                 default:
383                         break;
384                 }
385                 break;
386         case hwmon_in:
387                 switch (attr) {
388                 case hwmon_in_input:
389                         return 0444;
390                 default:
391                         break;
392                 }
393                 break;
394         default:
395                 break;
396         }
397
398         return 0;
399 };
400
401 static const struct hwmon_ops ccp_hwmon_ops = {
402         .is_visible = ccp_is_visible,
403         .read = ccp_read,
404         .read_string = ccp_read_string,
405         .write = ccp_write,
406 };
407
408 static const struct hwmon_channel_info * const ccp_info[] = {
409         HWMON_CHANNEL_INFO(chip,
410                            HWMON_C_REGISTER_TZ),
411         HWMON_CHANNEL_INFO(temp,
412                            HWMON_T_INPUT,
413                            HWMON_T_INPUT,
414                            HWMON_T_INPUT,
415                            HWMON_T_INPUT
416                            ),
417         HWMON_CHANNEL_INFO(fan,
418                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_TARGET,
419                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_TARGET,
420                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_TARGET,
421                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_TARGET,
422                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_TARGET,
423                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_TARGET
424                            ),
425         HWMON_CHANNEL_INFO(pwm,
426                            HWMON_PWM_INPUT,
427                            HWMON_PWM_INPUT,
428                            HWMON_PWM_INPUT,
429                            HWMON_PWM_INPUT,
430                            HWMON_PWM_INPUT,
431                            HWMON_PWM_INPUT
432                            ),
433         HWMON_CHANNEL_INFO(in,
434                            HWMON_I_INPUT,
435                            HWMON_I_INPUT,
436                            HWMON_I_INPUT
437                            ),
438         NULL
439 };
440
441 static const struct hwmon_chip_info ccp_chip_info = {
442         .ops = &ccp_hwmon_ops,
443         .info = ccp_info,
444 };
445
446 /* read fan connection status and set labels */
447 static int get_fan_cnct(struct ccp_device *ccp)
448 {
449         int channel;
450         int mode;
451         int ret;
452
453         ret = send_usb_cmd(ccp, CTL_GET_FAN_CNCT, 0, 0, 0);
454         if (ret)
455                 return ret;
456
457         for (channel = 0; channel < NUM_FANS; channel++) {
458                 mode = ccp->buffer[channel + 1];
459                 if (mode == 0)
460                         continue;
461
462                 set_bit(channel, ccp->fan_cnct);
463                 ccp->target[channel] = -ENODATA;
464
465                 switch (mode) {
466                 case 1:
467                         scnprintf(ccp->fan_label[channel], LABEL_LENGTH,
468                                   "fan%d 3pin", channel + 1);
469                         break;
470                 case 2:
471                         scnprintf(ccp->fan_label[channel], LABEL_LENGTH,
472                                   "fan%d 4pin", channel + 1);
473                         break;
474                 default:
475                         scnprintf(ccp->fan_label[channel], LABEL_LENGTH,
476                                   "fan%d other", channel + 1);
477                         break;
478                 }
479         }
480
481         return 0;
482 }
483
484 /* read temp sensor connection status */
485 static int get_temp_cnct(struct ccp_device *ccp)
486 {
487         int channel;
488         int mode;
489         int ret;
490
491         ret = send_usb_cmd(ccp, CTL_GET_TMP_CNCT, 0, 0, 0);
492         if (ret)
493                 return ret;
494
495         for (channel = 0; channel < NUM_TEMP_SENSORS; channel++) {
496                 mode = ccp->buffer[channel + 1];
497                 if (mode == 0)
498                         continue;
499
500                 set_bit(channel, ccp->temp_cnct);
501         }
502
503         return 0;
504 }
505
506 /* read firmware version */
507 static int get_fw_version(struct ccp_device *ccp)
508 {
509         int ret;
510
511         ret = send_usb_cmd(ccp, CTL_GET_FW_VER, 0, 0, 0);
512         if (ret) {
513                 hid_notice(ccp->hdev, "Failed to read firmware version.\n");
514                 return ret;
515         }
516         ccp->firmware_ver[0] = ccp->buffer[1];
517         ccp->firmware_ver[1] = ccp->buffer[2];
518         ccp->firmware_ver[2] = ccp->buffer[3];
519
520         return 0;
521 }
522
523 /* read bootloader version */
524 static int get_bl_version(struct ccp_device *ccp)
525 {
526         int ret;
527
528         ret = send_usb_cmd(ccp, CTL_GET_BL_VER, 0, 0, 0);
529         if (ret) {
530                 hid_notice(ccp->hdev, "Failed to read bootloader version.\n");
531                 return ret;
532         }
533         ccp->bootloader_ver[0] = ccp->buffer[1];
534         ccp->bootloader_ver[1] = ccp->buffer[2];
535
536         return 0;
537 }
538
539 static int firmware_show(struct seq_file *seqf, void *unused)
540 {
541         struct ccp_device *ccp = seqf->private;
542
543         seq_printf(seqf, "%d.%d.%d\n",
544                    ccp->firmware_ver[0],
545                    ccp->firmware_ver[1],
546                    ccp->firmware_ver[2]);
547
548         return 0;
549 }
550 DEFINE_SHOW_ATTRIBUTE(firmware);
551
552 static int bootloader_show(struct seq_file *seqf, void *unused)
553 {
554         struct ccp_device *ccp = seqf->private;
555
556         seq_printf(seqf, "%d.%d\n",
557                    ccp->bootloader_ver[0],
558                    ccp->bootloader_ver[1]);
559
560         return 0;
561 }
562 DEFINE_SHOW_ATTRIBUTE(bootloader);
563
564 static void ccp_debugfs_init(struct ccp_device *ccp)
565 {
566         char name[32];
567         int ret;
568
569         scnprintf(name, sizeof(name), "corsaircpro-%s", dev_name(&ccp->hdev->dev));
570         ccp->debugfs = debugfs_create_dir(name, NULL);
571
572         ret = get_fw_version(ccp);
573         if (!ret)
574                 debugfs_create_file("firmware_version", 0444,
575                                     ccp->debugfs, ccp, &firmware_fops);
576
577         ret = get_bl_version(ccp);
578         if (!ret)
579                 debugfs_create_file("bootloader_version", 0444,
580                                     ccp->debugfs, ccp, &bootloader_fops);
581 }
582
583 static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id)
584 {
585         struct ccp_device *ccp;
586         int ret;
587
588         ccp = devm_kzalloc(&hdev->dev, sizeof(*ccp), GFP_KERNEL);
589         if (!ccp)
590                 return -ENOMEM;
591
592         ccp->cmd_buffer = devm_kmalloc(&hdev->dev, OUT_BUFFER_SIZE, GFP_KERNEL);
593         if (!ccp->cmd_buffer)
594                 return -ENOMEM;
595
596         ccp->buffer = devm_kmalloc(&hdev->dev, IN_BUFFER_SIZE, GFP_KERNEL);
597         if (!ccp->buffer)
598                 return -ENOMEM;
599
600         ret = hid_parse(hdev);
601         if (ret)
602                 return ret;
603
604         ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
605         if (ret)
606                 return ret;
607
608         ret = hid_hw_open(hdev);
609         if (ret)
610                 goto out_hw_stop;
611
612         ccp->hdev = hdev;
613         hid_set_drvdata(hdev, ccp);
614
615         mutex_init(&ccp->mutex);
616         spin_lock_init(&ccp->wait_input_report_lock);
617         init_completion(&ccp->wait_input_report);
618
619         hid_device_io_start(hdev);
620
621         /* temp and fan connection status only updates when device is powered on */
622         ret = get_temp_cnct(ccp);
623         if (ret)
624                 goto out_hw_close;
625
626         ret = get_fan_cnct(ccp);
627         if (ret)
628                 goto out_hw_close;
629
630         ccp_debugfs_init(ccp);
631
632         ccp->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "corsaircpro",
633                                                          ccp, &ccp_chip_info, NULL);
634         if (IS_ERR(ccp->hwmon_dev)) {
635                 ret = PTR_ERR(ccp->hwmon_dev);
636                 goto out_hw_close;
637         }
638
639         return 0;
640
641 out_hw_close:
642         hid_hw_close(hdev);
643 out_hw_stop:
644         hid_hw_stop(hdev);
645         return ret;
646 }
647
648 static void ccp_remove(struct hid_device *hdev)
649 {
650         struct ccp_device *ccp = hid_get_drvdata(hdev);
651
652         debugfs_remove_recursive(ccp->debugfs);
653         hwmon_device_unregister(ccp->hwmon_dev);
654         hid_hw_close(hdev);
655         hid_hw_stop(hdev);
656 }
657
658 static const struct hid_device_id ccp_devices[] = {
659         { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_PRODUCT_ID_CORSAIR_COMMANDERPRO) },
660         { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_PRODUCT_ID_CORSAIR_1000D) },
661         { }
662 };
663
664 static struct hid_driver ccp_driver = {
665         .name = "corsair-cpro",
666         .id_table = ccp_devices,
667         .probe = ccp_probe,
668         .remove = ccp_remove,
669         .raw_event = ccp_raw_event,
670 };
671
672 MODULE_DEVICE_TABLE(hid, ccp_devices);
673 MODULE_DESCRIPTION("Corsair Commander Pro controller driver");
674 MODULE_LICENSE("GPL");
675
676 static int __init ccp_init(void)
677 {
678         return hid_register_driver(&ccp_driver);
679 }
680
681 static void __exit ccp_exit(void)
682 {
683         hid_unregister_driver(&ccp_driver);
684 }
685
686 /*
687  * When compiling this driver as built-in, hwmon initcalls will get called before the
688  * hid driver and this driver would fail to register. late_initcall solves this.
689  */
690 late_initcall(ccp_init);
691 module_exit(ccp_exit);
This page took 0.069939 seconds and 4 git commands to generate.