Home | History | Annotate | Line # | Download | only in emcfanctl
      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