1 /* $NetBSD: lm75.c,v 1.29 2016/01/11 18:23:11 jdc 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.29 2016/01/11 18:23:11 jdc 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 57 struct sysmon_envsys *sc_sme; 58 envsys_data_t sc_sensor; 59 int sc_tmax; 60 uint32_t sc_smax, sc_smin, sc_scrit; 61 62 uint32_t (*sc_lmtemp_decode)(const uint8_t *, int); 63 void (*sc_lmtemp_encode)(const uint32_t, uint8_t *, int); 64 }; 65 66 static int lmtemp_match(device_t, cfdata_t, void *); 67 static void lmtemp_attach(device_t, device_t, void *); 68 69 CFATTACH_DECL_NEW(lmtemp, sizeof(struct lmtemp_softc), 70 lmtemp_match, lmtemp_attach, NULL, NULL); 71 72 static void lmtemp_refresh(struct sysmon_envsys *, envsys_data_t *); 73 static int lmtemp_config_write(struct lmtemp_softc *, uint8_t); 74 static int lmtemp_temp_write(struct lmtemp_softc *, uint8_t, uint32_t, 75 int); 76 static int lmtemp_temp_read(struct lmtemp_softc *, uint8_t, uint32_t *, 77 int); 78 static uint32_t lmtemp_decode_lm75(const uint8_t *, int); 79 static uint32_t lmtemp_decode_ds75(const uint8_t *, int); 80 static uint32_t lmtemp_decode_lm77(const uint8_t *, int); 81 static void lmtemp_encode_lm75(const uint32_t, uint8_t *, int); 82 static void lmtemp_encode_ds75(const uint32_t, uint8_t *, int); 83 static void lmtemp_encode_lm77(const uint32_t, uint8_t *, int); 84 static void lmtemp_getlim_lm75(struct sysmon_envsys *, envsys_data_t *, 85 sysmon_envsys_lim_t *, uint32_t *); 86 static void lmtemp_getlim_lm77(struct sysmon_envsys *, envsys_data_t *, 87 sysmon_envsys_lim_t *, uint32_t *); 88 static void lmtemp_setlim_lm75(struct sysmon_envsys *, envsys_data_t *, 89 sysmon_envsys_lim_t *, uint32_t *); 90 static void lmtemp_setlim_lm77(struct sysmon_envsys *, envsys_data_t *, 91 sysmon_envsys_lim_t *, uint32_t *); 92 93 static void lmtemp_setup_sysctl(struct lmtemp_softc *); 94 static int sysctl_lm75_temp(SYSCTLFN_ARGS); 95 96 static const char * lmtemp_compats[] = { 97 "i2c-lm75", 98 /* 99 * see XXX in _attach() below: add code once non-lm75 matches are 100 * added here! 101 */ 102 NULL 103 }; 104 105 enum { 106 lmtemp_lm75 = 0, 107 lmtemp_ds75, 108 lmtemp_lm77, 109 }; 110 static const struct { 111 int lmtemp_type; 112 const char *lmtemp_name; 113 int lmtemp_addrmask; 114 int lmtemp_addr; 115 uint32_t (*lmtemp_decode)(const uint8_t *, int); 116 void (*lmtemp_encode)(const uint32_t, uint8_t *, int); 117 void (*lmtemp_getlim)(struct sysmon_envsys *, envsys_data_t *, 118 sysmon_envsys_lim_t *, uint32_t *); 119 void (*lmtemp_setlim)(struct sysmon_envsys *, envsys_data_t *, 120 sysmon_envsys_lim_t *, uint32_t *); 121 } lmtemptbl[] = { 122 { lmtemp_lm75, "LM75", LM75_ADDRMASK, LM75_ADDR, 123 lmtemp_decode_lm75, lmtemp_encode_lm75, 124 lmtemp_getlim_lm75, lmtemp_setlim_lm75 }, 125 { lmtemp_ds75, "DS75", LM75_ADDRMASK, LM75_ADDR, 126 lmtemp_decode_ds75, lmtemp_encode_ds75, 127 lmtemp_getlim_lm75, lmtemp_setlim_lm75 }, 128 { lmtemp_lm77, "LM77", LM77_ADDRMASK, LM77_ADDR, 129 lmtemp_decode_lm77, lmtemp_encode_lm77, 130 lmtemp_getlim_lm77, lmtemp_setlim_lm77 }, 131 { -1, NULL, 0, 0, 132 NULL, NULL, 133 NULL, NULL } 134 }; 135 136 static int 137 lmtemp_match(device_t parent, cfdata_t cf, void *aux) 138 { 139 struct i2c_attach_args *ia = aux; 140 int i; 141 142 if (ia->ia_name == NULL) { 143 /* 144 * Indirect config - not much we can do! 145 */ 146 for (i = 0; lmtemptbl[i].lmtemp_type != -1 ; i++) 147 if (lmtemptbl[i].lmtemp_type == cf->cf_flags) 148 break; 149 if (lmtemptbl[i].lmtemp_type == -1) 150 return 0; 151 152 if ((ia->ia_addr & lmtemptbl[i].lmtemp_addrmask) == 153 lmtemptbl[i].lmtemp_addr) 154 return 1; 155 } else { 156 /* 157 * Direct config - match via the list of compatible 158 * hardware or simply match the device name. 159 */ 160 if (ia->ia_ncompat > 0) { 161 if (iic_compat_match(ia, lmtemp_compats)) 162 return 1; 163 } else { 164 if (strcmp(ia->ia_name, "lmtemp") == 0) 165 return 1; 166 } 167 } 168 169 170 return 0; 171 } 172 173 static void 174 lmtemp_attach(device_t parent, device_t self, void *aux) 175 { 176 struct lmtemp_softc *sc = device_private(self); 177 struct i2c_attach_args *ia = aux; 178 int i; 179 180 sc->sc_dev = self; 181 if (ia->ia_name == NULL) { 182 for (i = 0; lmtemptbl[i].lmtemp_type != -1 ; i++) 183 if (lmtemptbl[i].lmtemp_type == 184 device_cfdata(self)->cf_flags) 185 break; 186 } else { 187 /* XXX - add code when adding other direct matches! */ 188 i = 0; 189 } 190 191 sc->sc_tag = ia->ia_tag; 192 sc->sc_address = ia->ia_addr; 193 194 aprint_naive(": Temperature Sensor\n"); 195 if (ia->ia_name) { 196 aprint_normal(": %s %s Temperature Sensor\n", ia->ia_name, 197 lmtemptbl[i].lmtemp_name); 198 } else { 199 aprint_normal(": %s Temperature Sensor\n", 200 lmtemptbl[i].lmtemp_name); 201 } 202 203 sc->sc_lmtemp_decode = lmtemptbl[i].lmtemp_decode; 204 sc->sc_lmtemp_encode = lmtemptbl[i].lmtemp_encode; 205 206 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 207 208 /* Read temperature limit(s) and remember initial value(s). */ 209 if (i == lmtemp_lm77) { 210 if (lmtemp_temp_read(sc, LM77_REG_TCRIT_SET_POINT, 211 &sc->sc_scrit, 1) != 0) { 212 aprint_error_dev(self, 213 "unable to read low register\n"); 214 iic_release_bus(sc->sc_tag, I2C_F_POLL); 215 return; 216 } 217 if (lmtemp_temp_read(sc, LM77_REG_TLOW_SET_POINT, 218 &sc->sc_smin, 1) != 0) { 219 aprint_error_dev(self, 220 "unable to read low register\n"); 221 iic_release_bus(sc->sc_tag, I2C_F_POLL); 222 return; 223 } 224 if (lmtemp_temp_read(sc, LM77_REG_THIGH_SET_POINT, 225 &sc->sc_smax, 1) != 0) { 226 aprint_error_dev(self, 227 "unable to read high register\n"); 228 iic_release_bus(sc->sc_tag, I2C_F_POLL); 229 return; 230 } 231 } else { /* LM75 or compatible */ 232 if (lmtemp_temp_read(sc, LM75_REG_TOS_SET_POINT, 233 &sc->sc_smax, 1) != 0) { 234 aprint_error_dev(self, "unable to read Tos register\n"); 235 iic_release_bus(sc->sc_tag, I2C_F_POLL); 236 return; 237 } 238 } 239 sc->sc_tmax = sc->sc_smax; 240 241 if (i == lmtemp_lm75) 242 lmtemp_setup_sysctl(sc); 243 244 /* Set the configuration of the LM75 to defaults. */ 245 if (lmtemp_config_write(sc, LM75_CONFIG_FAULT_QUEUE_4) != 0) { 246 aprint_error_dev(self, "unable to write config register\n"); 247 iic_release_bus(sc->sc_tag, I2C_F_POLL); 248 return; 249 } 250 iic_release_bus(sc->sc_tag, I2C_F_POLL); 251 252 sc->sc_sme = sysmon_envsys_create(); 253 /* Initialize sensor data. */ 254 sc->sc_sensor.units = ENVSYS_STEMP; 255 sc->sc_sensor.state = ENVSYS_SINVALID; 256 sc->sc_sensor.flags = ENVSYS_FMONLIMITS; 257 (void)strlcpy(sc->sc_sensor.desc, 258 ia->ia_name? ia->ia_name : device_xname(self), 259 sizeof(sc->sc_sensor.desc)); 260 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor)) { 261 sysmon_envsys_destroy(sc->sc_sme); 262 return; 263 } 264 265 /* Hook into system monitor. */ 266 sc->sc_sme->sme_name = device_xname(self); 267 sc->sc_sme->sme_cookie = sc; 268 sc->sc_sme->sme_refresh = lmtemp_refresh; 269 sc->sc_sme->sme_get_limits = lmtemptbl[i].lmtemp_getlim; 270 sc->sc_sme->sme_set_limits = lmtemptbl[i].lmtemp_setlim; 271 272 if (sysmon_envsys_register(sc->sc_sme)) { 273 aprint_error_dev(self, "unable to register with sysmon\n"); 274 sysmon_envsys_destroy(sc->sc_sme); 275 } 276 } 277 278 static int 279 lmtemp_config_write(struct lmtemp_softc *sc, uint8_t val) 280 { 281 uint8_t cmdbuf[2]; 282 283 cmdbuf[0] = LM75_REG_CONFIG; 284 cmdbuf[1] = val; 285 286 return iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 287 sc->sc_address, cmdbuf, 1, &cmdbuf[1], 1, I2C_F_POLL); 288 } 289 290 static int 291 lmtemp_temp_write(struct lmtemp_softc *sc, uint8_t reg, uint32_t val, int degc) 292 { 293 uint8_t cmdbuf[3]; 294 295 cmdbuf[0] = reg; 296 sc->sc_lmtemp_encode(val, &cmdbuf[1], degc); 297 298 return iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 299 sc->sc_address, cmdbuf, 1, &cmdbuf[1], 2, I2C_F_POLL); 300 } 301 302 static int 303 lmtemp_temp_read(struct lmtemp_softc *sc, uint8_t which, uint32_t *valp, 304 int degc) 305 { 306 int error; 307 uint8_t cmdbuf[1]; 308 uint8_t buf[LM75_TEMP_LEN]; 309 310 cmdbuf[0] = which; 311 312 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 313 sc->sc_address, cmdbuf, 1, buf, LM75_TEMP_LEN, 0); 314 if (error) 315 return error; 316 317 *valp = sc->sc_lmtemp_decode(buf, degc); 318 return 0; 319 } 320 321 static void 322 lmtemp_refresh_sensor_data(struct lmtemp_softc *sc) 323 { 324 uint32_t val; 325 int error; 326 327 error = lmtemp_temp_read(sc, LM75_REG_TEMP, &val, 0); 328 if (error) { 329 #if 0 330 aprint_error_dev(sc->sc_dev, "unable to read temperature, error = %d\n", 331 error); 332 #endif 333 sc->sc_sensor.state = ENVSYS_SINVALID; 334 return; 335 } 336 337 sc->sc_sensor.value_cur = val; 338 sc->sc_sensor.state = ENVSYS_SVALID; 339 } 340 341 static void 342 lmtemp_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 343 { 344 struct lmtemp_softc *sc = sme->sme_cookie; 345 346 iic_acquire_bus(sc->sc_tag, 0); /* also locks our instance */ 347 lmtemp_refresh_sensor_data(sc); 348 iic_release_bus(sc->sc_tag, 0); /* also unlocks our instance */ 349 } 350 351 static void 352 lmtemp_getlim_lm75(struct sysmon_envsys *sme, envsys_data_t *edata, 353 sysmon_envsys_lim_t *limits, uint32_t *props) 354 { 355 struct lmtemp_softc *sc = sme->sme_cookie; 356 uint32_t val; 357 358 *props &= ~(PROP_CRITMAX); 359 360 iic_acquire_bus(sc->sc_tag, 0); 361 if (lmtemp_temp_read(sc, LM75_REG_TOS_SET_POINT, &val, 0) == 0) { 362 limits->sel_critmax = val; 363 *props |= PROP_CRITMAX; 364 } 365 iic_release_bus(sc->sc_tag, 0); 366 } 367 368 static void 369 lmtemp_getlim_lm77(struct sysmon_envsys *sme, envsys_data_t *edata, 370 sysmon_envsys_lim_t *limits, uint32_t *props) 371 { 372 struct lmtemp_softc *sc = sme->sme_cookie; 373 uint32_t val; 374 375 *props &= ~(PROP_CRITMAX | PROP_WARNMAX | PROP_WARNMIN); 376 377 iic_acquire_bus(sc->sc_tag, 0); 378 if (lmtemp_temp_read(sc, LM77_REG_TCRIT_SET_POINT, &val, 0) == 0) { 379 limits->sel_critmax = val; 380 *props |= PROP_CRITMAX; 381 } 382 if (lmtemp_temp_read(sc, LM77_REG_THIGH_SET_POINT, &val, 0) == 0) { 383 limits->sel_warnmax = val; 384 *props |= PROP_WARNMAX; 385 } 386 if (lmtemp_temp_read(sc, LM77_REG_TLOW_SET_POINT, &val, 0) == 0) { 387 limits->sel_warnmin = val; 388 *props |= PROP_WARNMIN; 389 } 390 iic_release_bus(sc->sc_tag, 0); 391 } 392 393 static void 394 lmtemp_setlim_lm75(struct sysmon_envsys *sme, envsys_data_t *edata, 395 sysmon_envsys_lim_t *limits, uint32_t *props) 396 { 397 struct lmtemp_softc *sc = sme->sme_cookie; 398 int32_t limit; 399 400 if (*props & PROP_CRITMAX) { 401 if (limits == NULL) /* Restore defaults */ 402 limit = sc->sc_smax; 403 else 404 limit = limits->sel_critmax; 405 iic_acquire_bus(sc->sc_tag, 0); 406 lmtemp_temp_write(sc, LM75_REG_THYST_SET_POINT, 407 limit - 5000000, 0); 408 lmtemp_temp_write(sc, LM75_REG_TOS_SET_POINT, limit, 0); 409 iic_release_bus(sc->sc_tag, 0); 410 411 /* Synchronise sysctl */ 412 sc->sc_tmax = (limit - 273150000) / 1000000; 413 } 414 } 415 416 static void 417 lmtemp_setlim_lm77(struct sysmon_envsys *sme, envsys_data_t *edata, 418 sysmon_envsys_lim_t *limits, uint32_t *props) 419 { 420 struct lmtemp_softc *sc = sme->sme_cookie; 421 int32_t limit; 422 423 iic_acquire_bus(sc->sc_tag, 0); 424 if (*props & PROP_CRITMAX) { 425 if (limits == NULL) /* Restore defaults */ 426 limit = sc->sc_scrit; 427 else 428 limit = limits->sel_critmax; 429 lmtemp_temp_write(sc, LM77_REG_TCRIT_SET_POINT, limit, 0); 430 } 431 if (*props & PROP_WARNMAX) { 432 if (limits == NULL) /* Restore defaults */ 433 limit = sc->sc_smax; 434 else 435 limit = limits->sel_warnmax; 436 lmtemp_temp_write(sc, LM77_REG_THIGH_SET_POINT, limit, 0); 437 } 438 if (*props & PROP_WARNMIN) { 439 if (limits == NULL) /* Restore defaults */ 440 limit = sc->sc_smin; 441 else 442 limit = limits->sel_warnmin; 443 lmtemp_temp_write(sc, LM77_REG_TLOW_SET_POINT, limit, 0); 444 } 445 iic_release_bus(sc->sc_tag, 0); 446 } 447 448 static uint32_t 449 lmtemp_decode_lm75(const uint8_t *buf, int degc) 450 { 451 int temp; 452 uint32_t val; 453 454 /* 455 * LM75 temps are the most-significant 9 bits of a 16-bit reg. 456 * sign-extend the MSB and add in the 0.5 from the LSB 457 */ 458 temp = (int8_t) buf[0]; 459 temp = (temp << 1) + ((buf[1] >> 7) & 0x1); 460 461 /* Temp is given in 1/2 deg. C, we convert to C or uK. */ 462 if (degc) 463 val = temp / 2; 464 else 465 val = temp * 500000 + 273150000; 466 467 return val; 468 } 469 470 static uint32_t 471 lmtemp_decode_ds75(const uint8_t *buf, int degc) 472 { 473 int temp; 474 475 /* 476 * Sign-extend the MSB byte, and add in the fractions of a 477 * degree contained in the LSB (precision 1/16th DegC). 478 */ 479 temp = (int8_t)buf[0]; 480 temp = (temp << 4) | ((buf[1] >> 4) & 0xf); 481 482 /* 483 * Conversion to C or uK is simple. 484 */ 485 if (degc) 486 return temp / 16; 487 else 488 return (temp * 62500 + 273150000); 489 } 490 491 static uint32_t 492 lmtemp_decode_lm77(const uint8_t *buf, int degc) 493 { 494 int temp; 495 uint32_t val; 496 497 /* 498 * Describe each bits of temperature registers on LM77. 499 * D15 - D12: Sign 500 * D11 - D3 : Bit8(MSB) - Bit0 501 */ 502 temp = (int8_t)buf[0]; 503 temp = (temp << 5) | ((buf[1] >> 3) & 0x1f); 504 505 /* Temp is given in 1/2 deg. C, we convert to C or uK. */ 506 if (degc) 507 val = temp / 2; 508 else 509 val = temp * 500000 + 273150000; 510 511 return val; 512 } 513 514 static void lmtemp_encode_lm75(const uint32_t val, uint8_t *buf, int degc) 515 { 516 int temp; 517 518 /* Convert from C or uK to register format */ 519 if (degc) 520 temp = val * 2; 521 else 522 temp = (val - 273150000) / 500000; 523 buf[0] = (temp >> 1) & 0xff; 524 buf[1] = (temp & 1) << 7; 525 } 526 527 static void lmtemp_encode_ds75(const uint32_t val, uint8_t *buf, int degc) 528 { 529 int temp; 530 531 /* Convert from C or uK to register format */ 532 if (degc) 533 temp = val * 16; 534 else 535 temp = (val - 273150000) / 62500; 536 buf[0] = (temp >> 4) & 0xff; 537 buf[1] = (temp & 0xf) << 4; 538 } 539 540 static void lmtemp_encode_lm77(const uint32_t val, uint8_t *buf, int degc) 541 { 542 int temp; 543 544 /* Convert from C or uK to register format */ 545 if (degc) 546 temp = val * 2; 547 else 548 temp = (val - 273150000) / 500000; 549 buf[0] = (temp >> 5) & 0xff; 550 buf[1] = (temp & 0x1f) << 3; 551 } 552 553 static void 554 lmtemp_setup_sysctl(struct lmtemp_softc *sc) 555 { 556 const struct sysctlnode *me = NULL, *node = NULL; 557 558 sysctl_createv(NULL, 0, NULL, &me, 559 CTLFLAG_READWRITE, 560 CTLTYPE_NODE, device_xname(sc->sc_dev), NULL, 561 NULL, 0, NULL, 0, 562 CTL_MACHDEP, CTL_CREATE, CTL_EOL); 563 564 sysctl_createv(NULL, 0, NULL, &node, 565 CTLFLAG_READWRITE | CTLFLAG_OWNDESC, 566 CTLTYPE_INT, "temp", "Threshold temperature", 567 sysctl_lm75_temp, 1, (void *)sc, 0, 568 CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL); 569 } 570 571 static int 572 sysctl_lm75_temp(SYSCTLFN_ARGS) 573 { 574 struct sysctlnode node = *rnode; 575 struct lmtemp_softc *sc = node.sysctl_data; 576 int temp; 577 578 if (newp) { 579 580 /* we're asked to write */ 581 node.sysctl_data = &sc->sc_tmax; 582 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) { 583 584 temp = *(int *)node.sysctl_data; 585 sc->sc_tmax = temp; 586 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 587 lmtemp_temp_write(sc, LM75_REG_THYST_SET_POINT, 588 sc->sc_tmax - 5, 1); 589 lmtemp_temp_write(sc, LM75_REG_TOS_SET_POINT, 590 sc->sc_tmax, 1); 591 iic_release_bus(sc->sc_tag, I2C_F_POLL); 592 593 /* Synchronise envsys - calls lmtemp_getlim_lm75() */ 594 sysmon_envsys_update_limits(sc->sc_sme, &sc->sc_sensor); 595 return 0; 596 } 597 return EINVAL; 598 } else { 599 600 node.sysctl_data = &sc->sc_tmax; 601 node.sysctl_size = 4; 602 return (sysctl_lookup(SYSCTLFN_CALL(&node))); 603 } 604 605 return 0; 606 } 607 608 SYSCTL_SETUP(sysctl_lmtemp_setup, "sysctl lmtemp subtree setup") 609 { 610 611 sysctl_createv(NULL, 0, NULL, NULL, 612 CTLFLAG_PERMANENT, 613 CTLTYPE_NODE, "machdep", NULL, 614 NULL, 0, NULL, 0, 615 CTL_MACHDEP, CTL_EOL); 616 } 617 618 619