lm75.c revision 1.37 1 /* $NetBSD: lm75.c,v 1.37 2021/01/17 21:42:35 thorpej 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.37 2021/01/17 21:42:35 thorpej 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 { .compat = "i2c-lm75" },
99 { .compat = "lm75" },
100 { .compat = "ds1775" },
101 /*
102 * see XXX in _attach() below: add code once non-lm75 matches are
103 * added here!
104 */
105 { 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