1 /*
2  * This file is part of OpenCorsairLink.
3  * Copyright (C) 2017-2019  Sean Nelson <audiohacked@gmail.com>
4 
5  * OpenCorsairLink is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 2 of the License, or
8  * any later version.
9 
10  * OpenCorsairLink is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14 
15  * You should have received a copy of the GNU General Public License
16  * along with OpenCorsairLink.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "device.h"
20 #include "driver.h"
21 #include "lowlevel/asetek.h"
22 #include "print.h"
23 #include "protocol/asetekpro.h"
24 
25 #include <errno.h>
26 #include <libusb.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 
32 
33 int
corsairlink_asetekpro_fan_count(struct corsair_device_info * dev,struct libusb_device_handle * handle,struct fan_control * ctrl)34 corsairlink_asetekpro_fan_count(
35     struct corsair_device_info* dev, struct libusb_device_handle* handle, struct fan_control* ctrl )
36 {
37     int rr = 0;
38     // undefined, return device value from device.c
39     ctrl->fan_count = dev->fan_control_count;
40     return rr;
41 }
42 
43 int
corsairlink_asetekpro_fan_print_mode(uint8_t mode,uint16_t data,char * modestr,uint8_t modestr_size)44 corsairlink_asetekpro_fan_print_mode(
45     uint8_t mode, uint16_t data, char* modestr, uint8_t modestr_size )
46 {
47     int rr = 0;
48     // undefined, return hex value of mode
49     snprintf( modestr, modestr_size, "Mode 0x%02X", mode );
50     return rr;
51 }
52 
53 int
corsairlink_asetekpro_fan_mode(struct corsair_device_info * dev,struct libusb_device_handle * handle,struct fan_control * ctrl)54 corsairlink_asetekpro_fan_mode(
55     struct corsair_device_info* dev, struct libusb_device_handle* handle, struct fan_control* ctrl )
56 {
57     int rr;
58     if ( ctrl->mode == PERFORMANCE )
59     {
60         ASETEKPRO_FAN_TABLE_EXTREME( ctrl->table );
61     }
62     else if ( ctrl->mode == QUIET )
63     {
64         ASETEKPRO_FAN_TABLE_QUIET( ctrl->table );
65     }
66     rr = dev->driver->fan.profile.write_custom_curve( dev, handle, ctrl );
67 
68     return rr;
69 }
70 
71 int
corsairlink_asetekpro_fan_mode_read(struct corsair_device_info * dev,struct libusb_device_handle * handle,struct fan_control * ctrl)72 corsairlink_asetekpro_fan_mode_read(
73     struct corsair_device_info* dev, struct libusb_device_handle* handle, struct fan_control* ctrl )
74 {
75     int rr;
76     uint8_t response[64];
77     uint8_t commands[64];
78     memset( response, 0, sizeof( response ) );
79     memset( commands, 0, sizeof( commands ) );
80 
81     commands[0] = 0x20;
82 
83     rr = dev->driver->write( handle, dev->write_endpoint, commands, 32 );
84     rr = dev->driver->read( handle, dev->read_endpoint, response, 32 );
85 
86     msg_debug2( "%02X\n", response[0x16] );
87     ctrl->mode = response[0x16];
88 
89     return rr;
90 }
91 
92 int
corsairlink_asetekpro_fan_mode_performance(struct corsair_device_info * dev,struct libusb_device_handle * handle,struct fan_control * ctrl)93 corsairlink_asetekpro_fan_mode_performance(
94     struct corsair_device_info* dev, struct libusb_device_handle* handle, struct fan_control* ctrl )
95 {
96     int rr;
97     ASETEKPRO_FAN_TABLE_EXTREME( ctrl->table );
98     rr = dev->driver->fan.profile.write_custom_curve( dev, handle, ctrl );
99 
100     return rr;
101 }
102 
103 int
corsairlink_asetekpro_fan_mode_balanced(struct corsair_device_info * dev,struct libusb_device_handle * handle,struct fan_control * ctrl)104 corsairlink_asetekpro_fan_mode_balanced(
105     struct corsair_device_info* dev, struct libusb_device_handle* handle, struct fan_control* ctrl )
106 {
107     int rr;
108     ASETEKPRO_FAN_TABLE_BALANCED( ctrl->table );
109     rr = dev->driver->fan.profile.write_custom_curve( dev, handle, ctrl );
110 
111     return rr;
112 }
113 
114 int
corsairlink_asetekpro_fan_mode_quiet(struct corsair_device_info * dev,struct libusb_device_handle * handle,struct fan_control * ctrl)115 corsairlink_asetekpro_fan_mode_quiet(
116     struct corsair_device_info* dev, struct libusb_device_handle* handle, struct fan_control* ctrl )
117 {
118     int rr;
119     ASETEKPRO_FAN_TABLE_QUIET( ctrl->table );
120     rr = dev->driver->fan.profile.write_custom_curve( dev, handle, ctrl );
121 
122     return rr;
123 }
124 
125 int
corsairlink_asetekpro_fan_curve(struct corsair_device_info * dev,struct libusb_device_handle * handle,struct fan_control * ctrl)126 corsairlink_asetekpro_fan_curve(
127     struct corsair_device_info* dev, struct libusb_device_handle* handle, struct fan_control* ctrl )
128 {
129     int rr;
130     uint8_t response[64];
131     uint8_t commands[64];
132     memset( response, 0, sizeof( response ) );
133     memset( commands, 0, sizeof( commands ) );
134 
135     commands[0] = AsetekProFanWrite;
136     commands[1] = ctrl->channel;
137 
138     commands[2] = ctrl->table[0].temperature;
139     commands[3] = ctrl->table[1].temperature;
140     commands[4] = ctrl->table[2].temperature;
141     commands[5] = ctrl->table[3].temperature;
142     commands[6] = ctrl->table[4].temperature;
143     commands[7] = ctrl->table[5].temperature;
144     commands[8] = ctrl->table[6].temperature;
145 
146     commands[9] = ctrl->table[0].speed;
147     commands[10] = ctrl->table[1].speed;
148     commands[11] = ctrl->table[2].speed;
149     commands[12] = ctrl->table[3].speed;
150     commands[13] = ctrl->table[4].speed;
151     commands[14] = ctrl->table[5].speed;
152     commands[15] = ctrl->table[6].speed;
153 
154 
155     msg_debug2( "%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X \n", commands[0], commands[1], commands[2], commands[3], commands[4], commands[5], commands[6], commands[7], commands[8], commands[9], commands[10], commands[11], commands[12], commands[13], commands[14], commands[15]);
156 
157 
158     rr = dev->driver->write( handle, dev->write_endpoint, commands, 16 );
159     rr = dev->driver->read( handle, dev->read_endpoint, response, 32 );
160 
161     return rr;
162 }
163 
164 int
corsairlink_asetekpro_fan_speed(struct corsair_device_info * dev,struct libusb_device_handle * handle,struct fan_control * ctrl)165 corsairlink_asetekpro_fan_speed(
166     struct corsair_device_info* dev, struct libusb_device_handle* handle, struct fan_control* ctrl )
167 {
168     int rr;
169     uint8_t response[64];
170     uint8_t commands[64];
171     memset( response, 0, sizeof( response ) );
172     memset( commands, 0, sizeof( commands ) );
173 
174     commands[0] = AsetekProFanRead; // fan speed query
175     commands[1] = ctrl->channel; // fan port
176 
177     rr = dev->driver->write( handle, dev->write_endpoint, commands, 2 );
178     rr = dev->driver->read( handle, dev->read_endpoint, response, 6 );
179 
180     msg_debug2(
181         "%02X %02X %02X %02X %02X %02X\n", response[0], response[1], response[2], response[3],
182         response[4], response[5] );
183 
184     if ( response[0] != 0x41 || response[1] != 0x12 || response[2] != 0x34
185          || response[3] != ctrl->channel )
186     {
187         msg_debug2( "Bad Response\n" );
188     }
189 
190     ctrl->speed_rpm = ( response[4] << 8 ) + response[5];
191     ctrl->max_speed = 0;
192 
193     return rr;
194 }
195 
196 
197 int
corsairlink_asetekpro_fan_mode_rpm(struct corsair_device_info * dev,struct libusb_device_handle * handle,struct fan_control * ctrl)198 corsairlink_asetekpro_fan_mode_rpm(
199     struct corsair_device_info* dev, struct libusb_device_handle* handle, struct fan_control* ctrl )
200 {
201     int rr;
202     uint8_t response[64];
203     uint8_t commands[64];
204     memset( response, 0, sizeof( response ) );
205     memset( commands, 0, sizeof( commands ) );
206 
207     commands[0] = AsetekProFanFixedRPMWrite;
208     commands[1] = ctrl->channel;
209     commands[2] = ( ctrl->speed_rpm >> 8 );
210     commands[3] = ctrl->speed_rpm;
211 
212     msg_debug2("%02X %02X %02X %02X\n", commands[0], commands[1], commands[2], commands[3]);
213 
214     rr = dev->driver->write( handle, dev->write_endpoint, commands, 4 );
215     rr = dev->driver->read( handle, dev->read_endpoint, response, 64 );
216 
217     return rr;
218 }
219 
220 int
corsairlink_asetekpro_fan_mode_pwm(struct corsair_device_info * dev,struct libusb_device_handle * handle,struct fan_control * ctrl)221 corsairlink_asetekpro_fan_mode_pwm(
222     struct corsair_device_info* dev, struct libusb_device_handle* handle, struct fan_control* ctrl )
223 {
224     int rr;
225     uint8_t response[64];
226     uint8_t commands[64];
227     memset( response, 0, sizeof( response ) );
228     memset( commands, 0, sizeof( commands ) );
229 
230     commands[0] = AsetekProFanFixedPWMWrite;
231     commands[1] = ctrl->channel;
232     commands[2] = ctrl->speed_pwm;
233 
234     msg_debug2("%02X %02X %02X\n", commands[0], commands[1], commands[2]);
235 
236     rr = dev->driver->write( handle, dev->write_endpoint, commands, 3 );
237     rr = dev->driver->read( handle, dev->read_endpoint, response, 32 );
238 
239     return rr;
240 }