1 /* $NetBSD: lm75.c,v 1.36 2020/08/21 20:41:43 macallan Exp $ */ 2 3 /* 4 * Copyright (c) 2003 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #include <sys/cdefs.h> 39 __KERNEL_RCSID(0, "$NetBSD: lm75.c,v 1.36 2020/08/21 20:41:43 macallan Exp $"); 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/device.h> 44 #include <sys/kernel.h> 45 #include <sys/sysctl.h> 46 47 #include <dev/sysmon/sysmonvar.h> 48 49 #include <dev/i2c/i2cvar.h> 50 #include <dev/i2c/lm75reg.h> 51 52 struct lmtemp_softc { 53 device_t sc_dev; 54 i2c_tag_t sc_tag; 55 int sc_address; 56 prop_dictionary_t sc_prop; 57 58 struct sysmon_envsys *sc_sme; 59 envsys_data_t sc_sensor; 60 int sc_tmax; 61 uint32_t sc_smax, sc_smin, sc_scrit; 62 63 uint32_t (*sc_lmtemp_decode)(const uint8_t *, int); 64 void (*sc_lmtemp_encode)(const uint32_t, uint8_t *, int); 65 }; 66 67 static int lmtemp_match(device_t, cfdata_t, void *); 68 static void lmtemp_attach(device_t, device_t, void *); 69 70 CFATTACH_DECL_NEW(lmtemp, sizeof(struct lmtemp_softc), 71 lmtemp_match, lmtemp_attach, NULL, NULL); 72 73 static void lmtemp_refresh(struct sysmon_envsys *, envsys_data_t *); 74 static int lmtemp_config_write(struct lmtemp_softc *, uint8_t); 75 static int lmtemp_temp_write(struct lmtemp_softc *, uint8_t, uint32_t, 76 int); 77 static int lmtemp_temp_read(struct lmtemp_softc *, uint8_t, uint32_t *, 78 int); 79 static uint32_t lmtemp_decode_lm75(const uint8_t *, int); 80 static uint32_t lmtemp_decode_ds75(const uint8_t *, int); 81 static uint32_t lmtemp_decode_lm77(const uint8_t *, int); 82 static void lmtemp_encode_lm75(const uint32_t, uint8_t *, int); 83 static void lmtemp_encode_ds75(const uint32_t, uint8_t *, int); 84 static void lmtemp_encode_lm77(const uint32_t, uint8_t *, int); 85 static void lmtemp_getlim_lm75(struct sysmon_envsys *, envsys_data_t *, 86 sysmon_envsys_lim_t *, uint32_t *); 87 static void lmtemp_getlim_lm77(struct sysmon_envsys *, envsys_data_t *, 88 sysmon_envsys_lim_t *, uint32_t *); 89 static void lmtemp_setlim_lm75(struct sysmon_envsys *, envsys_data_t *, 90 sysmon_envsys_lim_t *, uint32_t *); 91 static void lmtemp_setlim_lm77(struct sysmon_envsys *, envsys_data_t *, 92 sysmon_envsys_lim_t *, uint32_t *); 93 94 static void lmtemp_setup_sysctl(struct lmtemp_softc *); 95 static int sysctl_lm75_temp(SYSCTLFN_ARGS); 96 97 static const struct device_compatible_entry compat_data[] = { 98 { "i2c-lm75", 0 }, 99 { "lm75", 0 }, 100 { "ds1775", 0 }, 101 /* 102 * see XXX in _attach() below: add code once non-lm75 matches are 103 * added here! 104 */ 105 { NULL, 0 } 106 }; 107 108 enum { 109 lmtemp_lm75 = 0, 110 lmtemp_ds75, 111 lmtemp_lm77, 112 }; 113 static const struct { 114 int lmtemp_type; 115 const char *lmtemp_name; 116 int lmtemp_addrmask; 117 int lmtemp_addr; 118 uint32_t (*lmtemp_decode)(const uint8_t *, int); 119 void (*lmtemp_encode)(const uint32_t, uint8_t *, int); 120 void (*lmtemp_getlim)(struct sysmon_envsys *, envsys_data_t *, 121 sysmon_envsys_lim_t *, uint32_t *); 122 void (*lmtemp_setlim)(struct sysmon_envsys *, envsys_data_t *, 123 sysmon_envsys_lim_t *, uint32_t *); 124 } lmtemptbl[] = { 125 { lmtemp_lm75, "LM75", LM75_ADDRMASK, LM75_ADDR, 126 lmtemp_decode_lm75, lmtemp_encode_lm75, 127 lmtemp_getlim_lm75, lmtemp_setlim_lm75 }, 128 { lmtemp_ds75, "DS75", LM75_ADDRMASK, LM75_ADDR, 129 lmtemp_decode_ds75, lmtemp_encode_ds75, 130 lmtemp_getlim_lm75, lmtemp_setlim_lm75 }, 131 { lmtemp_lm77, "LM77", LM77_ADDRMASK, LM77_ADDR, 132 lmtemp_decode_lm77, lmtemp_encode_lm77, 133 lmtemp_getlim_lm77, lmtemp_setlim_lm77 }, 134 { -1, NULL, 0, 0, 135 NULL, NULL, 136 NULL, NULL } 137 }; 138 139 static int 140 lmtemp_match(device_t parent, cfdata_t cf, void *aux) 141 { 142 struct i2c_attach_args *ia = aux; 143 int i, match_result; 144 145 if (iic_use_direct_match(ia, cf, compat_data, &match_result)) 146 return match_result; 147 148 /* 149 * Indirect config - not much we can do! 150 */ 151 for (i = 0; lmtemptbl[i].lmtemp_type != -1 ; i++) 152 if (lmtemptbl[i].lmtemp_type == cf->cf_flags) 153 break; 154 if (lmtemptbl[i].lmtemp_type == -1) 155 return 0; 156 157 if ((ia->ia_addr & lmtemptbl[i].lmtemp_addrmask) == 158 lmtemptbl[i].lmtemp_addr) 159 return I2C_MATCH_ADDRESS_ONLY; 160 161 return 0; 162 } 163 164 static void 165 lmtemp_attach(device_t parent, device_t self, void *aux) 166 { 167 struct lmtemp_softc *sc = device_private(self); 168 struct i2c_attach_args *ia = aux; 169 char name[64]; 170 const char *desc; 171 int i; 172 173 sc->sc_dev = self; 174 if (ia->ia_name == NULL) { 175 for (i = 0; lmtemptbl[i].lmtemp_type != -1 ; i++) 176 if (lmtemptbl[i].lmtemp_type == 177 device_cfdata(self)->cf_flags) 178 break; 179 } else { 180 if (strcmp(ia->ia_name, "ds1775") == 0) { 181 i = 1; /* LMTYPE_DS75 */ 182 } else { 183 /* XXX - add code when adding other direct matches! */ 184 i = 0; 185 } 186 } 187 188 sc->sc_tag = ia->ia_tag; 189 sc->sc_address = ia->ia_addr; 190 sc->sc_prop = ia->ia_prop; 191 192 aprint_naive(": Temperature Sensor\n"); 193 if (ia->ia_name) { 194 aprint_normal(": %s %s Temperature Sensor\n", ia->ia_name, 195 lmtemptbl[i].lmtemp_name); 196 } else { 197 aprint_normal(": %s Temperature Sensor\n", 198 lmtemptbl[i].lmtemp_name); 199 } 200 201 sc->sc_lmtemp_decode = lmtemptbl[i].lmtemp_decode; 202 sc->sc_lmtemp_encode = lmtemptbl[i].lmtemp_encode; 203 204 iic_acquire_bus(sc->sc_tag, 0); 205 206 /* Read temperature limit(s) and remember initial value(s). */ 207 if (i == lmtemp_lm77) { 208 if (lmtemp_temp_read(sc, LM77_REG_TCRIT_SET_POINT, 209 &sc->sc_scrit, 1) != 0) { 210 aprint_error_dev(self, 211 "unable to read low register\n"); 212 iic_release_bus(sc->sc_tag, 0); 213 return; 214 } 215 if (lmtemp_temp_read(sc, LM77_REG_TLOW_SET_POINT, 216 &sc->sc_smin, 1) != 0) { 217 aprint_error_dev(self, 218 "unable to read low register\n"); 219 iic_release_bus(sc->sc_tag, 0); 220 return; 221 } 222 if (lmtemp_temp_read(sc, LM77_REG_THIGH_SET_POINT, 223 &sc->sc_smax, 1) != 0) { 224 aprint_error_dev(self, 225 "unable to read high register\n"); 226 iic_release_bus(sc->sc_tag, 0); 227 return; 228 } 229 } else { /* LM75 or compatible */ 230 if (lmtemp_temp_read(sc, LM75_REG_TOS_SET_POINT, 231 &sc->sc_smax, 1) != 0) { 232 aprint_error_dev(self, "unable to read Tos register\n"); 233 iic_release_bus(sc->sc_tag, 0); 234 return; 235 } 236 } 237 sc->sc_tmax = sc->sc_smax; 238 239 if (i == lmtemp_lm75) 240 lmtemp_setup_sysctl(sc); 241 242 /* Set the configuration of the LM75 to defaults. */ 243 if (lmtemp_config_write(sc, LM75_CONFIG_FAULT_QUEUE_4) != 0) { 244 aprint_error_dev(self, "unable to write config register\n"); 245 iic_release_bus(sc->sc_tag, 0); 246 return; 247 } 248 iic_release_bus(sc->sc_tag, 0); 249 250 sc->sc_sme = sysmon_envsys_create(); 251 /* Initialize sensor data. */ 252 sc->sc_sensor.units = ENVSYS_STEMP; 253 sc->sc_sensor.state = ENVSYS_SINVALID; 254 sc->sc_sensor.flags = ENVSYS_FMONLIMITS; 255 256 (void)strlcpy(name, 257 ia->ia_name? ia->ia_name : device_xname(self), 258 sizeof(sc->sc_sensor.desc)); 259 260 if (prop_dictionary_get_cstring_nocopy(sc->sc_prop, "s00", &desc)) { 261 strncpy(name, desc, 64); 262 } 263 264 (void)strlcpy(sc->sc_sensor.desc, name, 265 sizeof(sc->sc_sensor.desc)); 266 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor)) { 267 sysmon_envsys_destroy(sc->sc_sme); 268 return; 269 } 270 271 /* Hook into system monitor. */ 272 sc->sc_sme->sme_name = device_xname(self); 273 sc->sc_sme->sme_cookie = sc; 274 sc->sc_sme->sme_refresh = lmtemp_refresh; 275 sc->sc_sme->sme_get_limits = lmtemptbl[i].lmtemp_getlim; 276 sc->sc_sme->sme_set_limits = lmtemptbl[i].lmtemp_setlim; 277 278 if (sysmon_envsys_register(sc->sc_sme)) { 279 aprint_error_dev(self, "unable to register with sysmon\n"); 280 sysmon_envsys_destroy(sc->sc_sme); 281 } 282 } 283 284 static int 285 lmtemp_config_write(struct lmtemp_softc *sc, uint8_t val) 286 { 287 uint8_t cmdbuf[2]; 288 289 cmdbuf[0] = LM75_REG_CONFIG; 290 cmdbuf[1] = val; 291 292 return iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 293 sc->sc_address, cmdbuf, 1, &cmdbuf[1], 1, 0); 294 } 295 296 static int 297 lmtemp_temp_write(struct lmtemp_softc *sc, uint8_t reg, uint32_t val, int degc) 298 { 299 uint8_t cmdbuf[3]; 300 301 cmdbuf[0] = reg; 302 sc->sc_lmtemp_encode(val, &cmdbuf[1], degc); 303 304 return iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 305 sc->sc_address, cmdbuf, 1, &cmdbuf[1], 2, 0); 306 } 307 308 static int 309 lmtemp_temp_read(struct lmtemp_softc *sc, uint8_t which, uint32_t *valp, 310 int degc) 311 { 312 int error; 313 uint8_t cmdbuf[1]; 314 uint8_t buf[LM75_TEMP_LEN]; 315 316 cmdbuf[0] = which; 317 318 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 319 sc->sc_address, cmdbuf, 1, buf, LM75_TEMP_LEN, 0); 320 if (error) 321 return error; 322 323 *valp = sc->sc_lmtemp_decode(buf, degc); 324 return 0; 325 } 326 327 static void 328 lmtemp_refresh_sensor_data(struct lmtemp_softc *sc) 329 { 330 uint32_t val; 331 int error; 332 333 error = lmtemp_temp_read(sc, LM75_REG_TEMP, &val, 0); 334 if (error) { 335 #if 0 336 aprint_error_dev(sc->sc_dev, "unable to read temperature, error = %d\n", 337 error); 338 #endif 339 sc->sc_sensor.state = ENVSYS_SINVALID; 340 return; 341 } 342 343 sc->sc_sensor.value_cur = val; 344 sc->sc_sensor.state = ENVSYS_SVALID; 345 } 346 347 static void 348 lmtemp_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 349 { 350 struct lmtemp_softc *sc = sme->sme_cookie; 351 352 iic_acquire_bus(sc->sc_tag, 0); /* also locks our instance */ 353 lmtemp_refresh_sensor_data(sc); 354 iic_release_bus(sc->sc_tag, 0); /* also unlocks our instance */ 355 } 356 357 static void 358 lmtemp_getlim_lm75(struct sysmon_envsys *sme, envsys_data_t *edata, 359 sysmon_envsys_lim_t *limits, uint32_t *props) 360 { 361 struct lmtemp_softc *sc = sme->sme_cookie; 362 uint32_t val; 363 364 *props &= ~(PROP_CRITMAX); 365 366 iic_acquire_bus(sc->sc_tag, 0); 367 if (lmtemp_temp_read(sc, LM75_REG_TOS_SET_POINT, &val, 0) == 0) { 368 limits->sel_critmax = val; 369 *props |= PROP_CRITMAX; 370 } 371 iic_release_bus(sc->sc_tag, 0); 372 } 373 374 static void 375 lmtemp_getlim_lm77(struct sysmon_envsys *sme, envsys_data_t *edata, 376 sysmon_envsys_lim_t *limits, uint32_t *props) 377 { 378 struct lmtemp_softc *sc = sme->sme_cookie; 379 uint32_t val; 380 381 *props &= ~(PROP_CRITMAX | PROP_WARNMAX | PROP_WARNMIN); 382 383 iic_acquire_bus(sc->sc_tag, 0); 384 if (lmtemp_temp_read(sc, LM77_REG_TCRIT_SET_POINT, &val, 0) == 0) { 385 limits->sel_critmax = val; 386 *props |= PROP_CRITMAX; 387 } 388 if (lmtemp_temp_read(sc, LM77_REG_THIGH_SET_POINT, &val, 0) == 0) { 389 limits->sel_warnmax = val; 390 *props |= PROP_WARNMAX; 391 } 392 if (lmtemp_temp_read(sc, LM77_REG_TLOW_SET_POINT, &val, 0) == 0) { 393 limits->sel_warnmin = val; 394 *props |= PROP_WARNMIN; 395 } 396 iic_release_bus(sc->sc_tag, 0); 397 } 398 399 static void 400 lmtemp_setlim_lm75(struct sysmon_envsys *sme, envsys_data_t *edata, 401 sysmon_envsys_lim_t *limits, uint32_t *props) 402 { 403 struct lmtemp_softc *sc = sme->sme_cookie; 404 int32_t limit; 405 406 if (*props & PROP_CRITMAX) { 407 if (limits == NULL) /* Restore defaults */ 408 limit = sc->sc_smax; 409 else 410 limit = limits->sel_critmax; 411 iic_acquire_bus(sc->sc_tag, 0); 412 lmtemp_temp_write(sc, LM75_REG_THYST_SET_POINT, 413 limit - 5000000, 0); 414 lmtemp_temp_write(sc, LM75_REG_TOS_SET_POINT, limit, 0); 415 iic_release_bus(sc->sc_tag, 0); 416 417 /* Synchronise sysctl */ 418 sc->sc_tmax = (limit - 273150000) / 1000000; 419 } 420 } 421 422 static void 423 lmtemp_setlim_lm77(struct sysmon_envsys *sme, envsys_data_t *edata, 424 sysmon_envsys_lim_t *limits, uint32_t *props) 425 { 426 struct lmtemp_softc *sc = sme->sme_cookie; 427 int32_t limit; 428 429 iic_acquire_bus(sc->sc_tag, 0); 430 if (*props & PROP_CRITMAX) { 431 if (limits == NULL) /* Restore defaults */ 432 limit = sc->sc_scrit; 433 else 434 limit = limits->sel_critmax; 435 lmtemp_temp_write(sc, LM77_REG_TCRIT_SET_POINT, limit, 0); 436 } 437 if (*props & PROP_WARNMAX) { 438 if (limits == NULL) /* Restore defaults */ 439 limit = sc->sc_smax; 440 else 441 limit = limits->sel_warnmax; 442 lmtemp_temp_write(sc, LM77_REG_THIGH_SET_POINT, limit, 0); 443 } 444 if (*props & PROP_WARNMIN) { 445 if (limits == NULL) /* Restore defaults */ 446 limit = sc->sc_smin; 447 else 448 limit = limits->sel_warnmin; 449 lmtemp_temp_write(sc, LM77_REG_TLOW_SET_POINT, limit, 0); 450 } 451 iic_release_bus(sc->sc_tag, 0); 452 } 453 454 static uint32_t 455 lmtemp_decode_lm75(const uint8_t *buf, int degc) 456 { 457 int temp; 458 uint32_t val; 459 460 /* 461 * LM75 temps are the most-significant 9 bits of a 16-bit reg. 462 * sign-extend the MSB and add in the 0.5 from the LSB 463 */ 464 temp = (int8_t) buf[0]; 465 temp = (temp << 1) + ((buf[1] >> 7) & 0x1); 466 467 /* Temp is given in 1/2 deg. C, we convert to C or uK. */ 468 if (degc) 469 val = temp / 2; 470 else 471 val = temp * 500000 + 273150000; 472 473 return val; 474 } 475 476 static uint32_t 477 lmtemp_decode_ds75(const uint8_t *buf, int degc) 478 { 479 int temp; 480 481 /* 482 * Sign-extend the MSB byte, and add in the fractions of a 483 * degree contained in the LSB (precision 1/16th DegC). 484 */ 485 temp = (int8_t)buf[0]; 486 temp = (temp << 4) | ((buf[1] >> 4) & 0xf); 487 488 /* 489 * Conversion to C or uK is simple. 490 */ 491 if (degc) 492 return temp / 16; 493 else 494 return (temp * 62500 + 273150000); 495 } 496 497 static uint32_t 498 lmtemp_decode_lm77(const uint8_t *buf, int degc) 499 { 500 int temp; 501 uint32_t val; 502 503 /* 504 * Describe each bits of temperature registers on LM77. 505 * D15 - D12: Sign 506 * D11 - D3 : Bit8(MSB) - Bit0 507 */ 508 temp = (int8_t)buf[0]; 509 temp = (temp << 5) | ((buf[1] >> 3) & 0x1f); 510 511 /* Temp is given in 1/2 deg. C, we convert to C or uK. */ 512 if (degc) 513 val = temp / 2; 514 else 515 val = temp * 500000 + 273150000; 516 517 return val; 518 } 519 520 static void lmtemp_encode_lm75(const uint32_t val, uint8_t *buf, int degc) 521 { 522 int temp; 523 524 /* Convert from C or uK to register format */ 525 if (degc) 526 temp = val * 2; 527 else 528 temp = (val - 273150000) / 500000; 529 buf[0] = (temp >> 1) & 0xff; 530 buf[1] = (temp & 1) << 7; 531 } 532 533 static void lmtemp_encode_ds75(const uint32_t val, uint8_t *buf, int degc) 534 { 535 int temp; 536 537 /* Convert from C or uK to register format */ 538 if (degc) 539 temp = val * 16; 540 else 541 temp = (val - 273150000) / 62500; 542 buf[0] = (temp >> 4) & 0xff; 543 buf[1] = (temp & 0xf) << 4; 544 } 545 546 static void lmtemp_encode_lm77(const uint32_t val, uint8_t *buf, int degc) 547 { 548 int temp; 549 550 /* Convert from C or uK to register format */ 551 if (degc) 552 temp = val * 2; 553 else 554 temp = (val - 273150000) / 500000; 555 buf[0] = (temp >> 5) & 0xff; 556 buf[1] = (temp & 0x1f) << 3; 557 } 558 559 static void 560 lmtemp_setup_sysctl(struct lmtemp_softc *sc) 561 { 562 const struct sysctlnode *me = NULL, *node = NULL; 563 564 sysctl_createv(NULL, 0, NULL, &me, 565 CTLFLAG_READWRITE, 566 CTLTYPE_NODE, device_xname(sc->sc_dev), NULL, 567 NULL, 0, NULL, 0, 568 CTL_MACHDEP, CTL_CREATE, CTL_EOL); 569 570 sysctl_createv(NULL, 0, NULL, &node, 571 CTLFLAG_READWRITE | CTLFLAG_OWNDESC, 572 CTLTYPE_INT, "temp", "Threshold temperature", 573 sysctl_lm75_temp, 1, (void *)sc, 0, 574 CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL); 575 } 576 577 static int 578 sysctl_lm75_temp(SYSCTLFN_ARGS) 579 { 580 struct sysctlnode node = *rnode; 581 struct lmtemp_softc *sc = node.sysctl_data; 582 int temp; 583 584 if (newp) { 585 586 /* we're asked to write */ 587 node.sysctl_data = &sc->sc_tmax; 588 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) { 589 590 temp = *(int *)node.sysctl_data; 591 sc->sc_tmax = temp; 592 iic_acquire_bus(sc->sc_tag, 0); 593 lmtemp_temp_write(sc, LM75_REG_THYST_SET_POINT, 594 sc->sc_tmax - 5, 1); 595 lmtemp_temp_write(sc, LM75_REG_TOS_SET_POINT, 596 sc->sc_tmax, 1); 597 iic_release_bus(sc->sc_tag, 0); 598 599 /* Synchronise envsys - calls lmtemp_getlim_lm75() */ 600 sysmon_envsys_update_limits(sc->sc_sme, &sc->sc_sensor); 601 return 0; 602 } 603 return EINVAL; 604 } else { 605 606 node.sysctl_data = &sc->sc_tmax; 607 node.sysctl_size = 4; 608 return (sysctl_lookup(SYSCTLFN_CALL(&node))); 609 } 610 611 return 0; 612 } 613 614 SYSCTL_SETUP(sysctl_lmtemp_setup, "sysctl lmtemp subtree setup") 615 { 616 617 sysctl_createv(NULL, 0, NULL, NULL, 618 CTLFLAG_PERMANENT, 619 CTLTYPE_NODE, "machdep", NULL, 620 NULL, 0, NULL, 0, 621 CTL_MACHDEP, CTL_EOL); 622 } 623 624 625