| 1 | /* |
|---|
| 2 | data.c - Part of libsensors, a Linux library for reading sensor data. |
|---|
| 3 | Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> |
|---|
| 4 | |
|---|
| 5 | This program 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 | (at your option) any later version. |
|---|
| 9 | |
|---|
| 10 | This program 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 this program; if not, write to the Free Software |
|---|
| 17 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|---|
| 18 | */ |
|---|
| 19 | |
|---|
| 20 | #include <stdlib.h> |
|---|
| 21 | #include <string.h> |
|---|
| 22 | |
|---|
| 23 | #include "error.h" |
|---|
| 24 | #include "data.h" |
|---|
| 25 | #include "sensors.h" |
|---|
| 26 | #include "../version.h" |
|---|
| 27 | |
|---|
| 28 | const char *libsensors_version = LM_VERSION; |
|---|
| 29 | |
|---|
| 30 | sensors_chip *sensors_config_chips = NULL; |
|---|
| 31 | int sensors_config_chips_count = 0; |
|---|
| 32 | int sensors_config_chips_max = 0; |
|---|
| 33 | |
|---|
| 34 | sensors_bus *sensors_config_busses = NULL; |
|---|
| 35 | int sensors_config_busses_count = 0; |
|---|
| 36 | int sensors_config_busses_max = 0; |
|---|
| 37 | |
|---|
| 38 | sensors_chip_features *sensors_proc_chips = NULL; |
|---|
| 39 | int sensors_proc_chips_count = 0; |
|---|
| 40 | int sensors_proc_chips_max = 0; |
|---|
| 41 | |
|---|
| 42 | sensors_bus *sensors_proc_bus = NULL; |
|---|
| 43 | int sensors_proc_bus_count = 0; |
|---|
| 44 | int sensors_proc_bus_max = 0; |
|---|
| 45 | |
|---|
| 46 | static int sensors_substitute_chip(sensors_chip_name *name,int lineno); |
|---|
| 47 | |
|---|
| 48 | /* Wow, this must be one of the ugliest functions I have ever written. |
|---|
| 49 | The idea is that it parses a chip name. These are valid names: |
|---|
| 50 | |
|---|
| 51 | lm78-i2c-10-5e *-i2c-10-5e |
|---|
| 52 | lm78-i2c-10-* *-i2c-10-* |
|---|
| 53 | lm78-i2c-*-5e *-i2c-*-5e |
|---|
| 54 | lm78-i2c-*-* *-i2c-*-* |
|---|
| 55 | lm78-isa-10dd *-isa-10dd |
|---|
| 56 | lm78-isa-* *-isa-* |
|---|
| 57 | lm78-* *-* |
|---|
| 58 | * |
|---|
| 59 | Here 'lm78' can be any prefix. To complicate matters, such a prefix |
|---|
| 60 | can also contain dashes (like lm78-j, for example!). 'i2c' and 'isa' are |
|---|
| 61 | literal strings, just like all dashes '-' and wildcards '*'. '10' can |
|---|
| 62 | be any decimal i2c bus number. '5e' can be any hexadecimal i2c device |
|---|
| 63 | address, and '10dd' any hexadecimal isa address. |
|---|
| 64 | |
|---|
| 65 | If '*' is used in prefixes, together with dashes, ambigious parses are |
|---|
| 66 | introduced. In that case, the prefix is kept as small as possible. |
|---|
| 67 | |
|---|
| 68 | The 'prefix' part in the result is freshly allocated. All old contents |
|---|
| 69 | of res is overwritten. res itself is not allocated. In case of an error |
|---|
| 70 | return (ie. != 0), res is undefined, but all allocations are undone. |
|---|
| 71 | |
|---|
| 72 | Don't tell me there are bugs in here, because I'll start screaming :-) |
|---|
| 73 | */ |
|---|
| 74 | |
|---|
| 75 | int sensors_parse_chip_name(const char *orig_name, sensors_chip_name *res) |
|---|
| 76 | { |
|---|
| 77 | char *part2, *part3, *part4; |
|---|
| 78 | char *name = strdup(orig_name); |
|---|
| 79 | int i; |
|---|
| 80 | |
|---|
| 81 | if (! name) |
|---|
| 82 | sensors_fatal_error("sensors_parse_chip_name","Allocating new name"); |
|---|
| 83 | /* First split name in upto four pieces. */ |
|---|
| 84 | if ((part4 = strrchr(name,'-'))) |
|---|
| 85 | *part4++ = '\0'; |
|---|
| 86 | if ((part3 = strrchr(name,'-'))) |
|---|
| 87 | *part3++ = '\0'; |
|---|
| 88 | if ((part2 = strrchr(name,'-'))) |
|---|
| 89 | *part2++ = '\0'; |
|---|
| 90 | |
|---|
| 91 | /* No dashes found? */ |
|---|
| 92 | if (! part4) { |
|---|
| 93 | if (!strcmp(name,"*")) { |
|---|
| 94 | res->prefix = SENSORS_CHIP_NAME_PREFIX_ANY; |
|---|
| 95 | res->bus = SENSORS_CHIP_NAME_BUS_ANY; |
|---|
| 96 | res->addr = SENSORS_CHIP_NAME_ADDR_ANY; |
|---|
| 97 | goto SUCCES; |
|---|
| 98 | } else |
|---|
| 99 | goto ERROR; |
|---|
| 100 | } |
|---|
| 101 | |
|---|
| 102 | /* At least one dash found. Now part4 is either '*', or an address */ |
|---|
| 103 | if (!strcmp(part4,"*")) |
|---|
| 104 | res->addr = SENSORS_CHIP_NAME_ADDR_ANY; |
|---|
| 105 | else { |
|---|
| 106 | if ((strlen(part4) > 4) || (strlen(part4) == 0)) |
|---|
| 107 | goto ERROR; |
|---|
| 108 | res->addr = 0; |
|---|
| 109 | for (i = 0; ; i++) { |
|---|
| 110 | switch (part4[i]) { |
|---|
| 111 | case '0': case '1': case '2': case '3': case '4': |
|---|
| 112 | case '5': case '6': case '7': case '8': case '9': |
|---|
| 113 | res->addr = res->addr * 16 + part4[i] - '0'; |
|---|
| 114 | break; |
|---|
| 115 | case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': |
|---|
| 116 | res->addr = res->addr * 16 + part4[i] - 'a' + 10; |
|---|
| 117 | break; |
|---|
| 118 | case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': |
|---|
| 119 | res->addr = res->addr * 16 + part4[i] - 'A' + 10; |
|---|
| 120 | break; |
|---|
| 121 | case 0: |
|---|
| 122 | goto DONE; |
|---|
| 123 | default: |
|---|
| 124 | goto ERROR; |
|---|
| 125 | } |
|---|
| 126 | } |
|---|
| 127 | DONE:; |
|---|
| 128 | } |
|---|
| 129 | |
|---|
| 130 | /* OK. So let's look at part3. It must either be the number of the |
|---|
| 131 | i2c bus (and then part2 *must* be "i2c"), or it must be "isa", |
|---|
| 132 | or, if part4 was "*", it belongs to 'prefix'. Or no second dash |
|---|
| 133 | was found at all, of course. */ |
|---|
| 134 | if (! part3) { |
|---|
| 135 | if (res->addr == SENSORS_CHIP_NAME_ADDR_ANY) { |
|---|
| 136 | res->bus = SENSORS_CHIP_NAME_BUS_ANY; |
|---|
| 137 | } else |
|---|
| 138 | goto ERROR; |
|---|
| 139 | } else if (!strcmp(part3,"isa")) { |
|---|
| 140 | res->bus = SENSORS_CHIP_NAME_BUS_ISA; |
|---|
| 141 | if (part2) |
|---|
| 142 | *(part2-1) = '-'; |
|---|
| 143 | } else if (!strcmp(part3,"pci")) { |
|---|
| 144 | res->bus = SENSORS_CHIP_NAME_BUS_PCI; |
|---|
| 145 | if (part2) |
|---|
| 146 | *(part2-1) = '-'; |
|---|
| 147 | } else if (part2 && !strcmp(part2,"i2c") && !strcmp(part3,"*")) |
|---|
| 148 | res->bus = SENSORS_CHIP_NAME_BUS_ANY_I2C; |
|---|
| 149 | else if (part2 && !strcmp(part2,"i2c")) { |
|---|
| 150 | if ((strlen(part3) > 3) || (strlen(part3) == 0)) |
|---|
| 151 | goto ERROR; |
|---|
| 152 | res->bus = 0; |
|---|
| 153 | for (i = 0; ; i++) { |
|---|
| 154 | switch (part3[i]) { |
|---|
| 155 | case '0': case '1': case '2': case '3': case '4': |
|---|
| 156 | case '5': case '6': case '7': case '8': case '9': |
|---|
| 157 | res->bus = res->bus * 10 + part3[i] - '0'; |
|---|
| 158 | break; |
|---|
| 159 | case 0: |
|---|
| 160 | goto DONE2; |
|---|
| 161 | default: |
|---|
| 162 | goto ERROR; |
|---|
| 163 | } |
|---|
| 164 | } |
|---|
| 165 | DONE2:; |
|---|
| 166 | } else if (res->addr == SENSORS_CHIP_NAME_ADDR_ANY) { |
|---|
| 167 | res->bus = SENSORS_CHIP_NAME_BUS_ANY; |
|---|
| 168 | if (part2) |
|---|
| 169 | *(part2-1) = '-'; |
|---|
| 170 | *(part3-1) = '-'; |
|---|
| 171 | } else |
|---|
| 172 | goto ERROR; |
|---|
| 173 | |
|---|
| 174 | if (!strcmp(name,"*")) |
|---|
| 175 | res->prefix = SENSORS_CHIP_NAME_PREFIX_ANY; |
|---|
| 176 | else if (! (res->prefix = strdup(name))) |
|---|
| 177 | sensors_fatal_error("sensors_parse_chip_name","Allocating new name"); |
|---|
| 178 | goto SUCCES; |
|---|
| 179 | |
|---|
| 180 | SUCCES: |
|---|
| 181 | free(name); |
|---|
| 182 | return 0; |
|---|
| 183 | |
|---|
| 184 | ERROR: |
|---|
| 185 | free(name); |
|---|
| 186 | return -SENSORS_ERR_CHIP_NAME; |
|---|
| 187 | } |
|---|
| 188 | |
|---|
| 189 | int sensors_parse_i2cbus_name(const char *name, int *res) |
|---|
| 190 | { |
|---|
| 191 | int i; |
|---|
| 192 | |
|---|
| 193 | if (! strcmp(name,"isa")) { |
|---|
| 194 | *res = SENSORS_CHIP_NAME_BUS_ISA; |
|---|
| 195 | return 0; |
|---|
| 196 | } |
|---|
| 197 | if (strncmp(name,"i2c-",4)) { |
|---|
| 198 | return -SENSORS_ERR_BUS_NAME; |
|---|
| 199 | } |
|---|
| 200 | name += 4; |
|---|
| 201 | if ((strlen(name) > 3) || (strlen(name) == 0)) |
|---|
| 202 | return -SENSORS_ERR_BUS_NAME; |
|---|
| 203 | *res = 0; |
|---|
| 204 | for (i = 0; ; i++) { |
|---|
| 205 | switch (name[i]) { |
|---|
| 206 | case '0': case '1': case '2': case '3': case '4': |
|---|
| 207 | case '5': case '6': case '7': case '8': case '9': |
|---|
| 208 | *res = *res * 10 + name[i] - '0'; |
|---|
| 209 | break; |
|---|
| 210 | case 0: |
|---|
| 211 | return 0; |
|---|
| 212 | default: |
|---|
| 213 | return -SENSORS_ERR_BUS_NAME; |
|---|
| 214 | } |
|---|
| 215 | } |
|---|
| 216 | } |
|---|
| 217 | |
|---|
| 218 | |
|---|
| 219 | int sensors_substitute_chip(sensors_chip_name *name,int lineno) |
|---|
| 220 | { |
|---|
| 221 | int i,j; |
|---|
| 222 | for (i = 0; i < sensors_config_busses_count; i++) |
|---|
| 223 | if (sensors_config_busses[i].number == name->bus) |
|---|
| 224 | break; |
|---|
| 225 | |
|---|
| 226 | if (i == sensors_config_busses_count) { |
|---|
| 227 | sensors_parse_error("Undeclared i2c bus referenced",lineno); |
|---|
| 228 | name->bus = sensors_proc_bus_count; |
|---|
| 229 | return -SENSORS_ERR_BUS_NAME; |
|---|
| 230 | } |
|---|
| 231 | |
|---|
| 232 | /* Compare the adapter names */ |
|---|
| 233 | for (j = 0; j < sensors_proc_bus_count; j++) { |
|---|
| 234 | if (!strcmp(sensors_config_busses[i].adapter, |
|---|
| 235 | sensors_proc_bus[j].adapter)) { |
|---|
| 236 | name->bus = sensors_proc_bus[j].number; |
|---|
| 237 | return 0; |
|---|
| 238 | } |
|---|
| 239 | } |
|---|
| 240 | |
|---|
| 241 | /* We did not find anything. sensors_proc_bus_count is not a valid |
|---|
| 242 | bus number, so it will never be matched. Good. */ |
|---|
| 243 | name->bus = sensors_proc_bus_count; |
|---|
| 244 | return 0; |
|---|
| 245 | } |
|---|
| 246 | |
|---|
| 247 | |
|---|
| 248 | int sensors_substitute_busses(void) |
|---|
| 249 | { |
|---|
| 250 | int err,i,j,lineno; |
|---|
| 251 | sensors_chip_name_list *chips; |
|---|
| 252 | int res=0; |
|---|
| 253 | |
|---|
| 254 | for(i = 0; i < sensors_config_chips_count; i++) { |
|---|
| 255 | lineno = sensors_config_chips[i].lineno; |
|---|
| 256 | chips = &sensors_config_chips[i].chips; |
|---|
| 257 | for(j = 0; j < chips->fits_count; j++) |
|---|
| 258 | if ((chips->fits[j].bus != SENSORS_CHIP_NAME_BUS_ISA) && |
|---|
| 259 | (chips->fits[j].bus != SENSORS_CHIP_NAME_BUS_PCI) && |
|---|
| 260 | (chips->fits[j].bus != SENSORS_CHIP_NAME_BUS_ANY) && |
|---|
| 261 | (chips->fits[j].bus != SENSORS_CHIP_NAME_BUS_ANY_I2C)) |
|---|
| 262 | if ((err = sensors_substitute_chip(chips->fits+j, lineno))) |
|---|
| 263 | res = err; |
|---|
| 264 | } |
|---|
| 265 | return res; |
|---|
| 266 | } |
|---|