emcfanctlutil.c revision 1.1 1 /* $NetBSD: emcfanctlutil.c,v 1.1 2025/03/11 13:56:48 brad Exp $ */
2
3 /*
4 * Copyright (c) 2025 Brad Spencer <brad (at) anduin.eldar.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #ifdef __RCSID
20 __RCSID("$NetBSD: emcfanctlutil.c,v 1.1 2025/03/11 13:56:48 brad Exp $");
21 #endif
22
23 #include <inttypes.h>
24 #include <stdbool.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <err.h>
29 #include <fcntl.h>
30 #include <string.h>
31 #include <limits.h>
32 #include <errno.h>
33
34 #include <dev/i2c/emcfanreg.h>
35 #include <dev/i2c/emcfaninfo.h>
36
37 #define EXTERN
38 #include "emcfanctl.h"
39 #include "emcfanctlconst.h"
40 #include "emcfanctlutil.h"
41
42 int
43 emcfan_read_register(int fd, uint8_t reg, uint8_t *res, bool debug)
44 {
45 int err;
46
47 err = lseek(fd, reg, SEEK_SET);
48 if (err != -1) {
49 err = read(fd, res, 1);
50 if (err == -1)
51 err = errno;
52 else
53 err = 0;
54 } else {
55 err = errno;
56 }
57
58 if (debug)
59 fprintf(stderr,"emcfan_read_register: reg=0x%02X, res=0x%02x, return err: %d\n",reg, *res, err);
60
61 return err;
62 }
63
64 int
65 emcfan_write_register(int fd, uint8_t reg, uint8_t value, bool debug)
66 {
67 int err;
68
69 err = lseek(fd, reg, SEEK_SET);
70 if (err != -1) {
71 err = write(fd, &value, 1);
72 if (err == -1)
73 err = errno;
74 else
75 err = 0;
76 } else {
77 err = errno;
78 }
79
80 if (debug)
81 fprintf(stderr,"emcfan_write_register: reg=0x%02X, value=0x%02X, return err: %d\n",reg, value, err);
82
83 return err;
84 }
85
86 int
87 emcfan_rmw_register(int fd, uint8_t reg, uint8_t value,
88 const struct emcfan_bits_translate translation[],
89 long unsigned int translation_size,
90 int tindex,
91 bool debug)
92 {
93 int err = 0;
94 uint8_t current, oldcurrent;
95
96 err = emcfan_read_register(fd, reg, &oldcurrent, debug);
97 if (err != 0)
98 return(err);
99
100
101 current = oldcurrent & ~translation[tindex].clear_mask;
102 current = current | translation[tindex].bit_mask;
103
104 if (debug)
105 fprintf(stderr,"tindex=%d, clear_mask=0x%02X 0x%02X, value=%d (0x%02X), bit_mask=0x%02X 0x%02X, oldcurrent=%d (0x%02X), new current=%d (0x%02X)\n",tindex,
106 translation[tindex].clear_mask,
107 (uint8_t)~translation[tindex].clear_mask,
108 value,value,
109 translation[tindex].bit_mask,
110 (uint8_t)~translation[tindex].bit_mask,
111 oldcurrent,oldcurrent,current,current);
112
113 err = emcfan_write_register(fd, reg, current, debug);
114
115 return(err);
116 }
117
118 char *
119 emcfan_product_to_name(uint8_t product_id)
120 {
121 for(long unsigned int i = 0;i < __arraycount(emcfan_chip_infos); i++)
122 if (product_id == emcfan_chip_infos[i].product_id)
123 return(__UNCONST(emcfan_chip_infos[i].name));
124 return(NULL);
125 }
126
127 void
128 emcfan_family_to_name(int family, char *name, int len)
129 {
130 switch(family) {
131 case EMCFAN_FAMILY_210X:
132 snprintf(name, len, "%s", "EMC210x");
133 break;
134 case EMCFAN_FAMILY_230X:
135 snprintf(name, len, "%s", "EMC230x");
136 break;
137 case EMCFAN_FAMILY_UNKNOWN:
138 default:
139 snprintf(name, len, "%s", "UNKNOWN");
140 break;
141 }
142
143 return;
144 }
145
146 int
147 emcfan_find_info(uint8_t product)
148 {
149 for(long unsigned int i = 0;i < __arraycount(emcfan_chip_infos); i++)
150 if (product == emcfan_chip_infos[i].product_id)
151 return(i);
152
153 return(-1);
154 }
155
156 bool
157 emcfan_reg_is_real(int iindex, uint8_t reg)
158 {
159 int segment;
160 uint64_t index;
161
162 segment = reg / 64;
163 index = reg % 64;
164
165 return(emcfan_chip_infos[iindex].register_void[segment] & ((uint64_t)1 << index));
166 }
167
168 static int
169 emcfan_hunt_by_name(const struct emcfan_registers the_registers[], long unsigned int the_registers_size, char *the_name)
170 {
171 int r = -1;
172
173 for(long unsigned int i = 0;i < the_registers_size;i++) {
174 if (strcmp(the_name, the_registers[i].name) == 0) {
175 r = the_registers[i].reg;
176 break;
177 }
178 }
179
180 return(r);
181 }
182
183 int
184 emcfan_reg_by_name(uint8_t product_id, int product_family, char *name)
185 {
186 int r = -1;
187
188 switch(product_family) {
189 case EMCFAN_FAMILY_210X:
190 switch(product_id) {
191 case EMCFAN_PRODUCT_2101:
192 case EMCFAN_PRODUCT_2101R:
193 r = emcfan_hunt_by_name(emcfanctl_2101_registers,__arraycount(emcfanctl_2101_registers),name);
194 break;
195 case EMCFAN_PRODUCT_2103_1:
196 r = emcfan_hunt_by_name(emcfanctl_2103_1_registers,__arraycount(emcfanctl_2103_1_registers),name);
197 break;
198 case EMCFAN_PRODUCT_2103_24:
199 r = emcfan_hunt_by_name(emcfanctl_2103_24_registers,__arraycount(emcfanctl_2103_24_registers),name);
200 break;
201 case EMCFAN_PRODUCT_2104:
202 r = emcfan_hunt_by_name(emcfanctl_2104_registers,__arraycount(emcfanctl_2104_registers),name);
203 break;
204 case EMCFAN_PRODUCT_2106:
205 r = emcfan_hunt_by_name(emcfanctl_2106_registers,__arraycount(emcfanctl_2106_registers),name);
206 break;
207 default:
208 printf("UNSUPPORTED YET %d\n",product_id);
209 exit(99);
210 break;
211 };
212 break;
213 case EMCFAN_FAMILY_230X:
214 r = emcfan_hunt_by_name(emcfanctl_230x_registers,__arraycount(emcfanctl_230x_registers),name);
215 break;
216 };
217
218 return(r);
219 }
220
221 static const char *
222 emcfan_hunt_by_reg(const struct emcfan_registers the_registers[], long unsigned int the_registers_size, uint8_t the_reg)
223 {
224 const char *r = NULL;
225
226 for(long unsigned int i = 0;i < the_registers_size;i++) {
227 if (the_reg == the_registers[i].reg) {
228 r = the_registers[i].name;
229 break;
230 }
231 }
232
233 return(r);
234 }
235
236 const char *
237 emcfan_regname_by_reg(uint8_t product_id, int product_family, uint8_t reg)
238 {
239 const char *r = NULL;
240
241 switch(product_family) {
242 case EMCFAN_FAMILY_210X:
243 switch(product_id) {
244 case EMCFAN_PRODUCT_2101:
245 case EMCFAN_PRODUCT_2101R:
246 r = emcfan_hunt_by_reg(emcfanctl_2101_registers,__arraycount(emcfanctl_2101_registers),reg);
247 break;
248 case EMCFAN_PRODUCT_2103_1:
249 r = emcfan_hunt_by_reg(emcfanctl_2103_1_registers,__arraycount(emcfanctl_2103_1_registers),reg);
250 break;
251 case EMCFAN_PRODUCT_2103_24:
252 r = emcfan_hunt_by_reg(emcfanctl_2103_24_registers,__arraycount(emcfanctl_2103_24_registers),reg);
253 break;
254 case EMCFAN_PRODUCT_2104:
255 r = emcfan_hunt_by_reg(emcfanctl_2104_registers,__arraycount(emcfanctl_2104_registers),reg);
256 break;
257 case EMCFAN_PRODUCT_2106:
258 r = emcfan_hunt_by_reg(emcfanctl_2106_registers,__arraycount(emcfanctl_2106_registers),reg);
259 break;
260 default:
261 printf("UNSUPPORTED YET %d\n",product_id);
262 exit(99);
263 break;
264 };
265 break;
266 case EMCFAN_FAMILY_230X:
267 r = emcfan_hunt_by_reg(emcfanctl_230x_registers,__arraycount(emcfanctl_230x_registers),reg);
268 break;
269 };
270
271 return(r);
272 }
273
274 int
275 find_translated_blob_by_bits_instance(const struct emcfan_bits_translate translation[],
276 long unsigned int translation_size,
277 uint8_t bits, int instance)
278 {
279 int r = -10191;
280 uint8_t clear_mask;
281 uint8_t b;
282
283 for(long unsigned int i = 0;i < translation_size;i++) {
284 if (instance == translation[i].instance) {
285 clear_mask = translation[i].clear_mask;
286 b = bits & clear_mask;
287 if (b == translation[i].bit_mask) {
288 r = i;
289 break;
290 }
291 }
292
293 }
294
295 return(r);
296 }
297
298 int
299 find_translated_bits_by_hint_instance(const struct emcfan_bits_translate translation[],
300 long unsigned int translation_size,
301 int human_value, int instance)
302 {
303 int r = -10191;
304
305 for(long unsigned int i = 0;i < translation_size;i++) {
306 if (instance == translation[i].instance &&
307 human_value == translation[i].human_int) {
308 r = i;
309 break;
310 }
311 }
312
313 return(r);
314 }
315
316 int
317 find_translated_bits_by_hint(const struct emcfan_bits_translate translation[],
318 long unsigned int translation_size,
319 int human_value)
320 {
321 int r = -10191;
322
323 for(long unsigned int i = 0;i < translation_size;i++) {
324 if (human_value == translation[i].human_int) {
325 r = i;
326 break;
327 }
328 }
329
330 return(r);
331 }
332
333 int
334 find_translated_bits_by_str(const struct emcfan_bits_translate translation[],
335 long unsigned int translation_size,
336 char *human_str)
337 {
338 int r = -10191;
339
340 for(long unsigned int i = 0;i < translation_size;i++) {
341 if (strcmp(human_str,translation[i].human_str) == 0) {
342 r = i;
343 break;
344 }
345 }
346
347 return(r);
348 }
349
350 int
351 find_translated_bits_by_str_instance(const struct emcfan_bits_translate translation[],
352 long unsigned int translation_size,
353 char *human_str, int instance)
354 {
355 int r = -10191;
356
357 for(long unsigned int i = 0;i < translation_size;i++) {
358 if (instance == translation[i].instance &&
359 strcmp(human_str,translation[i].human_str) == 0) {
360 r = i;
361 break;
362 }
363 }
364
365 return(r);
366 }
367
368 int
369 find_human_int(const struct emcfan_bits_translate translation[],
370 long unsigned int translation_size,
371 uint8_t bits)
372 {
373 int r = -10191;
374
375 for(long unsigned int i = 0;i < translation_size;i++) {
376 if (bits == translation[i].bit_mask) {
377 r = translation[i].human_int;
378 break;
379 }
380 }
381
382 return(r);
383 }
384
385 char *
386 find_human_str(const struct emcfan_bits_translate translation[],
387 long unsigned int translation_size,
388 uint8_t bits)
389 {
390 char *r = NULL;
391
392 for(long unsigned int i = 0;i < translation_size;i++) {
393 if (bits == translation[i].bit_mask) {
394 r = __UNCONST(translation[i].human_str);
395 break;
396 }
397 }
398
399 return(r);
400 }
401