xref: /netbsd-src/sys/arch/macppc/dev/lmu.c (revision 5178a7ba18b5359002fd0144c7aed0b719dbcd94)
1*5178a7baSmacallan /* $NetBSD: lmu.c,v 1.9 2021/06/18 22:52:04 macallan Exp $ */
22abd9a46Smacallan 
32abd9a46Smacallan /*-
42abd9a46Smacallan  * Copyright (c) 2020 Michael Lorenz
52abd9a46Smacallan  * All rights reserved.
62abd9a46Smacallan  *
72abd9a46Smacallan  * Redistribution and use in source and binary forms, with or without
82abd9a46Smacallan  * modification, are permitted provided that the following conditions
92abd9a46Smacallan  * are met:
102abd9a46Smacallan  * 1. Redistributions of source code must retain the above copyright
112abd9a46Smacallan  *    notice, this list of conditions and the following disclaimer.
122abd9a46Smacallan  * 2. Redistributions in binary form must reproduce the above copyright
132abd9a46Smacallan  *    notice, this list of conditions and the following disclaimer in the
142abd9a46Smacallan  *    documentation and/or other materials provided with the distribution.
152abd9a46Smacallan  *
162abd9a46Smacallan  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
172abd9a46Smacallan  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
182abd9a46Smacallan  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
192abd9a46Smacallan  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
202abd9a46Smacallan  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
212abd9a46Smacallan  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
222abd9a46Smacallan  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
232abd9a46Smacallan  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
242abd9a46Smacallan  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
252abd9a46Smacallan  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
262abd9a46Smacallan  * POSSIBILITY OF SUCH DAMAGE.
272abd9a46Smacallan  */
282abd9a46Smacallan 
292abd9a46Smacallan /*
302abd9a46Smacallan  * ambient light controller found in PowerBook5,6
312abd9a46Smacallan  */
322abd9a46Smacallan 
332abd9a46Smacallan #include <sys/cdefs.h>
34*5178a7baSmacallan __KERNEL_RCSID(0, "$NetBSD: lmu.c,v 1.9 2021/06/18 22:52:04 macallan Exp $");
352abd9a46Smacallan 
362abd9a46Smacallan #include <sys/param.h>
372abd9a46Smacallan #include <sys/systm.h>
382abd9a46Smacallan #include <sys/device.h>
392abd9a46Smacallan #include <sys/conf.h>
402abd9a46Smacallan #include <sys/bus.h>
412abd9a46Smacallan #include <sys/time.h>
422abd9a46Smacallan #include <sys/callout.h>
43b4b09679Smacallan #include <sys/sysctl.h>
442abd9a46Smacallan 
452abd9a46Smacallan #include <dev/i2c/i2cvar.h>
462abd9a46Smacallan 
472abd9a46Smacallan #include <dev/sysmon/sysmonvar.h>
48*5178a7baSmacallan #include "opt_lmu.h"
492abd9a46Smacallan 
50b4b09679Smacallan #ifdef LMU_DEBUG
51b4b09679Smacallan #define DPRINTF printf
52b4b09679Smacallan #else
53b4b09679Smacallan #define DPRINTF if (0) printf
54b4b09679Smacallan #endif
55b4b09679Smacallan 
562abd9a46Smacallan struct lmu_softc {
572abd9a46Smacallan 	device_t	sc_dev;
582abd9a46Smacallan 	i2c_tag_t	sc_i2c;
592abd9a46Smacallan 	i2c_addr_t	sc_addr;
602abd9a46Smacallan 	int		sc_node;
612abd9a46Smacallan 
622abd9a46Smacallan 	struct sysmon_envsys *sc_sme;
632abd9a46Smacallan 	envsys_data_t	sc_sensors[2];
642abd9a46Smacallan 	callout_t	sc_adjust;
65b4b09679Smacallan 	int		sc_thresh, sc_hyst, sc_level, sc_target, sc_current;
66b4b09679Smacallan 	int		sc_lux[2];
67b4b09679Smacallan 	time_t		sc_last;
680ab295ffSmacallan 	int		sc_lid_state, sc_video_state;
692abd9a46Smacallan };
702abd9a46Smacallan 
712abd9a46Smacallan static int	lmu_match(device_t, cfdata_t, void *);
722abd9a46Smacallan static void	lmu_attach(device_t, device_t, void *);
732abd9a46Smacallan 
742abd9a46Smacallan static void	lmu_sensors_refresh(struct sysmon_envsys *, envsys_data_t *);
752abd9a46Smacallan static void	lmu_set_brightness(struct lmu_softc *, int);
762abd9a46Smacallan static int	lmu_get_brightness(struct lmu_softc *, int);
772abd9a46Smacallan static void	lmu_adjust(void *);
78b4b09679Smacallan static int 	lmu_sysctl(SYSCTLFN_ARGS);
79b4b09679Smacallan static int 	lmu_sysctl_thresh(SYSCTLFN_ARGS);
802abd9a46Smacallan 
812abd9a46Smacallan CFATTACH_DECL_NEW(lmu, sizeof(struct lmu_softc),
822abd9a46Smacallan     lmu_match, lmu_attach, NULL, NULL);
832abd9a46Smacallan 
842abd9a46Smacallan static const struct device_compatible_entry compat_data[] = {
8556caee62Sthorpej 	{ .compat = "lmu-micro" },
8656caee62Sthorpej 	{ .compat = "lmu-controller" },
87ec189949Sthorpej 	DEVICE_COMPAT_EOL
882abd9a46Smacallan };
892abd9a46Smacallan 
90b4b09679Smacallan /* time between polling the light sensors */
91b4b09679Smacallan #define LMU_POLL	(hz * 2)
92b4b09679Smacallan /* time between updates to keyboard brightness */
93b4b09679Smacallan #define LMU_FADE	(hz / 16)
94b4b09679Smacallan 
950ab295ffSmacallan static void
lmu_lid_open(device_t dev)960ab295ffSmacallan lmu_lid_open(device_t dev)
970ab295ffSmacallan {
980ab295ffSmacallan 	struct lmu_softc * const sc = device_private(dev);
990ab295ffSmacallan 
1000ab295ffSmacallan 	sc->sc_lid_state = true;
1010ab295ffSmacallan }
1020ab295ffSmacallan 
1030ab295ffSmacallan static void
lmu_lid_close(device_t dev)1040ab295ffSmacallan lmu_lid_close(device_t dev)
1050ab295ffSmacallan {
1060ab295ffSmacallan 	struct lmu_softc * const sc = device_private(dev);
1070ab295ffSmacallan 
1080ab295ffSmacallan 	sc->sc_lid_state = false;
1090ab295ffSmacallan }
1100ab295ffSmacallan 
1110ab295ffSmacallan static void
lmu_video_on(device_t dev)1120ab295ffSmacallan lmu_video_on(device_t dev)
1130ab295ffSmacallan {
1140ab295ffSmacallan 	struct lmu_softc * const sc = device_private(dev);
1150ab295ffSmacallan 
1160ab295ffSmacallan 	sc->sc_video_state = true;
1170ab295ffSmacallan }
1180ab295ffSmacallan 
1190ab295ffSmacallan static void
lmu_video_off(device_t dev)1200ab295ffSmacallan lmu_video_off(device_t dev)
1210ab295ffSmacallan {
1220ab295ffSmacallan 	struct lmu_softc * const sc = device_private(dev);
1230ab295ffSmacallan 
1240ab295ffSmacallan 	sc->sc_video_state = false;
1250ab295ffSmacallan }
1260ab295ffSmacallan 
12714d389afSmacallan static void
lmu_kbd_brightness_up(device_t dev)12814d389afSmacallan lmu_kbd_brightness_up(device_t dev)
12914d389afSmacallan {
13014d389afSmacallan 	struct lmu_softc * const sc = device_private(dev);
13114d389afSmacallan 
13214d389afSmacallan 	sc->sc_level = __MIN(16, sc->sc_level + 2);
13314d389afSmacallan 	sc->sc_target = sc->sc_level;
13414d389afSmacallan 	callout_schedule(&sc->sc_adjust, LMU_FADE);
13514d389afSmacallan }
13614d389afSmacallan 
13714d389afSmacallan static void
lmu_kbd_brightness_down(device_t dev)13814d389afSmacallan lmu_kbd_brightness_down(device_t dev)
13914d389afSmacallan {
14014d389afSmacallan 	struct lmu_softc * const sc = device_private(dev);
14114d389afSmacallan 
14214d389afSmacallan 	sc->sc_level = __MAX(0, sc->sc_level - 2);
14314d389afSmacallan 	sc->sc_target = sc->sc_level;
14414d389afSmacallan 	callout_schedule(&sc->sc_adjust, LMU_FADE);
14514d389afSmacallan }
14614d389afSmacallan 
1472abd9a46Smacallan static int
lmu_match(device_t parent,cfdata_t match,void * aux)1482abd9a46Smacallan lmu_match(device_t parent, cfdata_t match, void *aux)
1492abd9a46Smacallan {
1502abd9a46Smacallan 	struct i2c_attach_args *ia = aux;
1512abd9a46Smacallan 	int match_result;
1522abd9a46Smacallan 
1532abd9a46Smacallan 	if (iic_use_direct_match(ia, match, compat_data, &match_result))
1542abd9a46Smacallan 		return match_result;
1552abd9a46Smacallan 
1562abd9a46Smacallan 	return 0;
1572abd9a46Smacallan }
1582abd9a46Smacallan 
1592abd9a46Smacallan static void
lmu_attach(device_t parent,device_t self,void * aux)1602abd9a46Smacallan lmu_attach(device_t parent, device_t self, void *aux)
1612abd9a46Smacallan {
1622abd9a46Smacallan 	struct lmu_softc *sc = device_private(self);
1632abd9a46Smacallan 	struct i2c_attach_args *ia = aux;
1642abd9a46Smacallan 	envsys_data_t *s;
165b4b09679Smacallan 	const struct sysctlnode *me;
1662abd9a46Smacallan 
1672abd9a46Smacallan 	sc->sc_dev = self;
1682abd9a46Smacallan 	sc->sc_i2c = ia->ia_tag;
1692abd9a46Smacallan 	sc->sc_addr = ia->ia_addr;
1702abd9a46Smacallan 	sc->sc_node = ia->ia_cookie;
171b4b09679Smacallan 	sc->sc_last = 0;
1722abd9a46Smacallan 
1732abd9a46Smacallan 	aprint_naive("\n");
1742abd9a46Smacallan 	aprint_normal(": ambient light sensor\n");
1752abd9a46Smacallan 
1760ab295ffSmacallan 	sc->sc_lid_state = true;
1770ab295ffSmacallan 	pmf_event_register(sc->sc_dev, PMFE_CHASSIS_LID_OPEN,
1780ab295ffSmacallan 	    lmu_lid_open, true);
1790ab295ffSmacallan 	pmf_event_register(sc->sc_dev, PMFE_CHASSIS_LID_CLOSE,
1800ab295ffSmacallan 	    lmu_lid_close, true);
1810ab295ffSmacallan 	sc->sc_video_state = true;
1820ab295ffSmacallan 	pmf_event_register(sc->sc_dev, PMFE_DISPLAY_ON,
1830ab295ffSmacallan 	    lmu_video_on, true);
1840ab295ffSmacallan 	pmf_event_register(sc->sc_dev, PMFE_DISPLAY_OFF,
1850ab295ffSmacallan 	    lmu_video_off, true);
18614d389afSmacallan 	pmf_event_register(sc->sc_dev, PMFE_KEYBOARD_BRIGHTNESS_UP,
18714d389afSmacallan 	    lmu_kbd_brightness_up, true);
18814d389afSmacallan 	pmf_event_register(sc->sc_dev, PMFE_KEYBOARD_BRIGHTNESS_DOWN,
18914d389afSmacallan 	    lmu_kbd_brightness_down, true);
1900ab295ffSmacallan 
1912abd9a46Smacallan 	sc->sc_sme = sysmon_envsys_create();
1922abd9a46Smacallan 	sc->sc_sme->sme_name = device_xname(self);
1932abd9a46Smacallan 	sc->sc_sme->sme_cookie = sc;
1942abd9a46Smacallan 	sc->sc_sme->sme_refresh = lmu_sensors_refresh;
1952abd9a46Smacallan 
1962abd9a46Smacallan 	s = &sc->sc_sensors[0];
1972abd9a46Smacallan 	s->state = ENVSYS_SINVALID;
1982abd9a46Smacallan 	s->units = ENVSYS_LUX;
1992abd9a46Smacallan 	strcpy(s->desc, "right");
2002abd9a46Smacallan 	s->private = 0;
2012abd9a46Smacallan 	sysmon_envsys_sensor_attach(sc->sc_sme, s);
2022abd9a46Smacallan 
2032abd9a46Smacallan 	s = &sc->sc_sensors[1];
2042abd9a46Smacallan 	s->state = ENVSYS_SINVALID;
2052abd9a46Smacallan 	s->units = ENVSYS_LUX;
2062abd9a46Smacallan 	strcpy(s->desc, "left");
207b4b09679Smacallan 	s->private = 1;
2082abd9a46Smacallan 	sysmon_envsys_sensor_attach(sc->sc_sme, s);
2092abd9a46Smacallan 
2102abd9a46Smacallan 	sysmon_envsys_register(sc->sc_sme);
2112abd9a46Smacallan 
2122abd9a46Smacallan 	sc->sc_thresh = 300;
2132abd9a46Smacallan 	sc->sc_hyst = 30;
214b4b09679Smacallan 	sc->sc_level = 16;
215b4b09679Smacallan 	sc->sc_target = 0;
216b4b09679Smacallan 	sc->sc_current = 0;
217b4b09679Smacallan 
218b4b09679Smacallan 	sysctl_createv(NULL, 0, NULL, &me,
219b4b09679Smacallan 		CTLFLAG_READWRITE,
220b4b09679Smacallan 		CTLTYPE_NODE, "lmu",
221b4b09679Smacallan 		SYSCTL_DESCR("LMU driver"),
222b4b09679Smacallan 		NULL, 0, NULL, 0,
223b4b09679Smacallan 		CTL_HW, CTL_CREATE, CTL_EOL);
224b4b09679Smacallan 
225b4b09679Smacallan 	sysctl_createv(NULL, 0, NULL, NULL,
226b4b09679Smacallan 		CTLFLAG_READWRITE,
227b4b09679Smacallan 		CTLTYPE_INT, "level",
228b4b09679Smacallan 		SYSCTL_DESCR("keyboard brightness"),
229b4b09679Smacallan 		lmu_sysctl, 0, (void *)sc, 0,
230b4b09679Smacallan 		CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL);
231b4b09679Smacallan 
232b4b09679Smacallan 	sysctl_createv(NULL, 0, NULL, NULL,
233b4b09679Smacallan 		CTLFLAG_READWRITE,
234b4b09679Smacallan 		CTLTYPE_INT, "threshold",
235b4b09679Smacallan 		SYSCTL_DESCR("environmental light threshold"),
236b4b09679Smacallan 		lmu_sysctl_thresh, 1, (void *)sc, 0,
237b4b09679Smacallan 		CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL);
2382abd9a46Smacallan 
2392abd9a46Smacallan 	callout_init(&sc->sc_adjust, 0);
2402abd9a46Smacallan 	callout_setfunc(&sc->sc_adjust, lmu_adjust, sc);
2412abd9a46Smacallan 	callout_schedule(&sc->sc_adjust, 0);
2422abd9a46Smacallan }
2432abd9a46Smacallan 
2442abd9a46Smacallan static void
lmu_sensors_refresh(struct sysmon_envsys * sme,envsys_data_t * edata)2452abd9a46Smacallan lmu_sensors_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
2462abd9a46Smacallan {
2472abd9a46Smacallan 	struct lmu_softc *sc = sme->sme_cookie;
2482abd9a46Smacallan 	int ret;
2492abd9a46Smacallan 
2502abd9a46Smacallan 	if ( edata->private < 3) {
2512abd9a46Smacallan 		ret = lmu_get_brightness(sc, edata->private);
2522abd9a46Smacallan 		if (ret == -1) return;
2532abd9a46Smacallan 		edata->value_cur = ret;
2542abd9a46Smacallan 	}
2552abd9a46Smacallan 	edata->state = ENVSYS_SVALID;
2562abd9a46Smacallan }
2572abd9a46Smacallan 
2582abd9a46Smacallan static int
lmu_get_brightness(struct lmu_softc * sc,int reg)2592abd9a46Smacallan lmu_get_brightness(struct lmu_softc *sc, int reg)
2602abd9a46Smacallan {
261b4b09679Smacallan 	int error, i;
262b4b09679Smacallan 	uint16_t buf[2];
263b4b09679Smacallan 	uint8_t cmd = 0;
264b4b09679Smacallan 
265b4b09679Smacallan 	if (reg > 1) return -1;
266b4b09679Smacallan 	if (time_second == sc->sc_last)
267b4b09679Smacallan 		return sc->sc_lux[reg];
2682abd9a46Smacallan 
2692abd9a46Smacallan 	iic_acquire_bus(sc->sc_i2c, 0);
2702abd9a46Smacallan 	error = iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP,
271b4b09679Smacallan 		sc->sc_addr, &cmd, 1, buf, 4, 0);
2722abd9a46Smacallan 	iic_release_bus(sc->sc_i2c, 0);
2732abd9a46Smacallan 	if (error) return -1;
274b4b09679Smacallan 	sc->sc_last = time_second;
275b4b09679Smacallan 
276b4b09679Smacallan 	for (i = 0; i < 2; i++)
277b4b09679Smacallan 		sc->sc_lux[i] = be16toh(buf[i]);
278b4b09679Smacallan 
279b4b09679Smacallan 	DPRINTF("<%d %04x %04x>", reg, buf[0], buf[1]);
280b4b09679Smacallan 
281b4b09679Smacallan 	return (sc->sc_lux[reg]);
2822abd9a46Smacallan }
2832abd9a46Smacallan 
2842abd9a46Smacallan static void
lmu_set_brightness(struct lmu_softc * sc,int b)2852abd9a46Smacallan lmu_set_brightness(struct lmu_softc *sc, int b)
2862abd9a46Smacallan {
2872abd9a46Smacallan 	uint8_t cmd[3];
2882abd9a46Smacallan 
2892abd9a46Smacallan 	cmd[0] = 1;
290b4b09679Smacallan 
291b4b09679Smacallan 	cmd[1] = (b & 0xff);
292b4b09679Smacallan 	cmd[2] = (b & 0xff) >> 8;
2932abd9a46Smacallan 
2942abd9a46Smacallan 	iic_acquire_bus(sc->sc_i2c, 0);
2952abd9a46Smacallan 	iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP,
2962abd9a46Smacallan 		sc->sc_addr, &cmd, 3, NULL, 0, 0);
2972abd9a46Smacallan 	iic_release_bus(sc->sc_i2c, 0);
2982abd9a46Smacallan }
2992abd9a46Smacallan 
3002abd9a46Smacallan static void
lmu_adjust(void * cookie)3012abd9a46Smacallan lmu_adjust(void *cookie)
3022abd9a46Smacallan {
3032abd9a46Smacallan 	struct lmu_softc *sc = cookie;
304b4b09679Smacallan 	int left, right, b, offset;
3052abd9a46Smacallan 
306b4b09679Smacallan 	left = lmu_get_brightness(sc, 1);
3072abd9a46Smacallan 	right = lmu_get_brightness(sc, 0);
3082abd9a46Smacallan 	b = left > right ? left : right;
3092abd9a46Smacallan 
3100ab295ffSmacallan 	if ((b > (sc->sc_thresh + sc->sc_hyst)) ||
3110ab295ffSmacallan 	   !(sc->sc_lid_state && sc->sc_video_state)) {
312b4b09679Smacallan 		sc->sc_target = 0;
3132abd9a46Smacallan 	} else if (b < sc->sc_thresh) {
314b4b09679Smacallan 		sc->sc_target = sc->sc_level;
3152abd9a46Smacallan 	}
3162abd9a46Smacallan 
317b4b09679Smacallan 	if (sc->sc_target == sc->sc_current) {
318b4b09679Smacallan 		/* no update needed, check again later */
319b4b09679Smacallan 		callout_schedule(&sc->sc_adjust, LMU_POLL);
320b4b09679Smacallan 		return;
321b4b09679Smacallan 	}
322b4b09679Smacallan 
323b4b09679Smacallan 
324b4b09679Smacallan 	offset = ((sc->sc_target - sc->sc_current) > 0) ? 2 : -2;
325b4b09679Smacallan 	sc->sc_current += offset;
326b4b09679Smacallan 	if (sc->sc_current > sc->sc_level) sc->sc_current = sc->sc_level;
327b4b09679Smacallan 	if (sc->sc_current < 0) sc->sc_current = 0;
328b4b09679Smacallan 
329b4b09679Smacallan 	DPRINTF("[%d]", sc->sc_current);
330b4b09679Smacallan 
331b4b09679Smacallan 	lmu_set_brightness(sc, sc->sc_current);
332b4b09679Smacallan 
333b4b09679Smacallan 	if (sc->sc_target == sc->sc_current) {
334b4b09679Smacallan 		/* no update needed, check again later */
335b4b09679Smacallan 		callout_schedule(&sc->sc_adjust, LMU_POLL);
336b4b09679Smacallan 		return;
337b4b09679Smacallan 	}
338b4b09679Smacallan 
339b4b09679Smacallan 	/* more updates upcoming */
340b4b09679Smacallan 	callout_schedule(&sc->sc_adjust, LMU_FADE);
341b4b09679Smacallan }
342b4b09679Smacallan 
343b4b09679Smacallan static int
lmu_sysctl(SYSCTLFN_ARGS)344b4b09679Smacallan lmu_sysctl(SYSCTLFN_ARGS)
345b4b09679Smacallan {
346b4b09679Smacallan 	struct sysctlnode node = *rnode;
347b4b09679Smacallan 	struct lmu_softc *sc = node.sysctl_data;
348b4b09679Smacallan 	int target;
349b4b09679Smacallan 
350b4b09679Smacallan 	target = sc->sc_level;
351b4b09679Smacallan 	node.sysctl_data = &target;
352b4b09679Smacallan 	if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) {
353b4b09679Smacallan 		int new_reg;
354b4b09679Smacallan 
355b4b09679Smacallan 		new_reg = *(int *)node.sysctl_data;
356b4b09679Smacallan 		if (new_reg != sc->sc_target) {
357b4b09679Smacallan 			sc->sc_level = target;
358b4b09679Smacallan 			sc->sc_target = target;
359b4b09679Smacallan 
360b4b09679Smacallan 		}
361b4b09679Smacallan 		return 0;
362b4b09679Smacallan 	}
363b4b09679Smacallan 	return EINVAL;
364b4b09679Smacallan }
365b4b09679Smacallan 
366b4b09679Smacallan static int
lmu_sysctl_thresh(SYSCTLFN_ARGS)367b4b09679Smacallan lmu_sysctl_thresh(SYSCTLFN_ARGS)
368b4b09679Smacallan {
369b4b09679Smacallan 	struct sysctlnode node = *rnode;
370b4b09679Smacallan 	struct lmu_softc *sc = node.sysctl_data;
371b4b09679Smacallan 	int thresh;
372b4b09679Smacallan 
373b4b09679Smacallan 	thresh = sc->sc_thresh;
374b4b09679Smacallan 	node.sysctl_data = &thresh;
375b4b09679Smacallan 	if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) {
376b4b09679Smacallan 		int new_reg;
377b4b09679Smacallan 
378b4b09679Smacallan 		new_reg = *(int *)node.sysctl_data;
379b4b09679Smacallan 		if (new_reg != sc->sc_thresh && new_reg > 0) {
380b4b09679Smacallan 			sc->sc_thresh = new_reg;
381b4b09679Smacallan 		}
382b4b09679Smacallan 		return 0;
383b4b09679Smacallan 	}
384b4b09679Smacallan 	return EINVAL;
3852abd9a46Smacallan }
386