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