1 /* $OpenBSD: kern_sensors.c,v 1.19 2007/06/04 18:42:05 deraadt Exp $ */
4 * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
5 * Copyright (c) 2006 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru>
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include <sys/param.h>
21 #include <sys/systm.h>
22 #include <sys/kernel.h>
23 #include <sys/malloc.h>
24 #include <sys/kthread.h>
25 #include <sys/queue.h>
26 #include <sys/types.h>
30 #include <sys/sysctl.h>
31 #include <sys/sensors.h>
33 #include <sys/mplock2.h>
35 int sensordev_count = 0;
36 SLIST_HEAD(, ksensordev) sensordev_list = SLIST_HEAD_INITIALIZER(sensordev_list);
38 struct ksensordev *sensordev_get(int);
39 struct ksensor *sensor_find(struct ksensordev *, enum sensor_type, int);
48 TAILQ_ENTRY(sensor_task) entry;
51 void sensor_task_thread(void *);
52 void sensor_task_schedule(struct sensor_task *);
54 TAILQ_HEAD(, sensor_task) tasklist = TAILQ_HEAD_INITIALIZER(tasklist);
57 void sensor_sysctl8magic_install(struct ksensordev *);
58 void sensor_sysctl8magic_deinstall(struct ksensordev *);
62 sensordev_install(struct ksensordev *sensdev)
64 struct ksensordev *v, *nv;
66 /* mtx_lock(&Giant); */
67 if (sensordev_count == 0) {
69 SLIST_INSERT_HEAD(&sensordev_list, sensdev, list);
71 for (v = SLIST_FIRST(&sensordev_list);
72 (nv = SLIST_NEXT(v, list)) != NULL; v = nv)
73 if (nv->num - v->num > 1)
75 sensdev->num = v->num + 1;
76 SLIST_INSERT_AFTER(v, sensdev, list);
79 /* mtx_unlock(&Giant); */
82 sensor_sysctl8magic_install(sensdev);
87 sensor_attach(struct ksensordev *sensdev, struct ksensor *sens)
89 struct ksensor *v, *nv;
90 struct ksensors_head *sh;
93 /* mtx_lock(&Giant); */
94 sh = &sensdev->sensors_list;
95 if (sensdev->sensors_count == 0) {
96 for (i = 0; i < SENSOR_MAX_TYPES; i++)
97 sensdev->maxnumt[i] = 0;
99 SLIST_INSERT_HEAD(sh, sens, list);
101 for (v = SLIST_FIRST(sh);
102 (nv = SLIST_NEXT(v, list)) != NULL; v = nv)
103 if (v->type == sens->type && (v->type != nv->type ||
104 (v->type == nv->type && nv->numt - v->numt > 1)))
106 /* sensors of the same type go after each other */
107 if (v->type == sens->type)
108 sens->numt = v->numt + 1;
111 SLIST_INSERT_AFTER(v, sens, list);
113 /* we only increment maxnumt[] if the sensor was added
114 * to the last position of sensors of this type
116 if (sensdev->maxnumt[sens->type] == sens->numt)
117 sensdev->maxnumt[sens->type]++;
118 sensdev->sensors_count++;
119 /* mtx_unlock(&Giant); */
123 sensordev_deinstall(struct ksensordev *sensdev)
125 /* mtx_lock(&Giant); */
127 SLIST_REMOVE(&sensordev_list, sensdev, ksensordev, list);
128 /* mtx_unlock(&Giant); */
130 #ifndef NOSYSCTL8HACK
131 sensor_sysctl8magic_deinstall(sensdev);
136 sensor_detach(struct ksensordev *sensdev, struct ksensor *sens)
138 struct ksensors_head *sh;
140 /* mtx_lock(&Giant); */
141 sh = &sensdev->sensors_list;
142 sensdev->sensors_count--;
143 SLIST_REMOVE(sh, sens, ksensor, list);
144 /* we only decrement maxnumt[] if this is the tail
145 * sensor of this type
147 if (sens->numt == sensdev->maxnumt[sens->type] - 1)
148 sensdev->maxnumt[sens->type]--;
149 /* mtx_unlock(&Giant); */
153 sensordev_get(int num)
155 struct ksensordev *sd;
157 SLIST_FOREACH(sd, &sensordev_list, list)
165 sensor_find(struct ksensordev *sensdev, enum sensor_type type, int numt)
168 struct ksensors_head *sh;
170 sh = &sensdev->sensors_list;
171 SLIST_FOREACH(s, sh, list)
172 if (s->type == type && s->numt == numt)
179 sensor_task_register(void *arg, void (*func)(void *), int period)
181 struct sensor_task *st;
182 int create_thread = 0;
184 st = kmalloc(sizeof(struct sensor_task), M_DEVBUF, M_NOWAIT);
194 if (TAILQ_EMPTY(&tasklist))
198 TAILQ_INSERT_HEAD(&tasklist, st, entry);
201 if (kthread_create(sensor_task_thread, NULL, NULL,
203 panic("sensors kthread");
211 sensor_task_unregister(void *arg)
213 struct sensor_task *st;
215 TAILQ_FOREACH(st, &tasklist, entry)
221 sensor_task_thread(void *arg)
223 struct sensor_task *st, *nst;
228 while (!TAILQ_EMPTY(&tasklist)) {
229 while ((nst = TAILQ_FIRST(&tasklist))->nextrun >
231 tsleep(&tasklist, 0, "timeout",
232 (nst->nextrun - now) * hz);
234 while ((st = nst) != NULL) {
235 nst = TAILQ_NEXT(st, entry);
237 if (st->nextrun > now)
240 /* take it out while we work on it */
241 TAILQ_REMOVE(&tasklist, st, entry);
250 /* stick it back in the tasklist */
251 sensor_task_schedule(st);
259 sensor_task_schedule(struct sensor_task *st)
261 struct sensor_task *cst;
263 st->nextrun = time_second + st->period;
265 TAILQ_FOREACH(cst, &tasklist, entry) {
266 if (cst->nextrun > st->nextrun) {
267 TAILQ_INSERT_BEFORE(cst, st, entry);
272 /* must be an empty list, or at the end of the list */
273 TAILQ_INSERT_TAIL(&tasklist, st, entry);
279 int sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS);
280 int sysctl_handle_sensor(SYSCTL_HANDLER_ARGS);
281 int sysctl_sensors_handler(SYSCTL_HANDLER_ARGS);
283 #ifndef NOSYSCTL8HACK
285 SYSCTL_NODE(_hw, OID_AUTO, sensors, CTLFLAG_RD, NULL,
286 "Hardware Sensors sysctl internal magic");
287 SYSCTL_NODE(_hw, HW_SENSORS, _sensors, CTLFLAG_RD, sysctl_sensors_handler,
288 "Hardware Sensors XP MIB interface");
290 #else /* NOSYSCTL8HACK */
292 SYSCTL_NODE(_hw, HW_SENSORS, sensors, CTLFLAG_RD, sysctl_sensors_handler,
294 int sensors_debug = 1;
295 SYSCTL_INT(_hw_sensors, OID_AUTO, debug, CTLFLAG_RD, &sensors_debug, 0, "sensors debug");
297 #endif /* !NOSYSCTL8HACK */
300 #ifndef NOSYSCTL8HACK
304 * FreeBSD's sysctl(9) .oid_handler functionality is not accustomed
305 * for the CTLTYPE_NODE handler to handle the undocumented sysctl
306 * magic calls. As soon as such functionality is developed,
307 * sysctl_sensors_handler() should be converted to handle all such
308 * calls, and these sysctl_add_oid(9) calls should be removed
309 * "with a big axe". This whole sysctl_add_oid(9) business is solely
310 * to please sysctl(8).
314 sensor_sysctl8magic_install(struct ksensordev *sensdev)
316 struct sysctl_oid_list *ol;
317 struct sysctl_ctx_list *cl = &sensdev->clist;
319 struct ksensors_head *sh = &sensdev->sensors_list;
322 ol = SYSCTL_CHILDREN(SYSCTL_ADD_NODE(cl, (&SYSCTL_NODE_CHILDREN(_hw,
323 sensors)), sensdev->num, sensdev->xname, CTLFLAG_RD, NULL, ""));
324 SLIST_FOREACH(s, sh, list) {
327 ksnprintf(n, sizeof(n), "%s%d", sensor_type_s[s->type], s->numt);
328 SYSCTL_ADD_PROC(cl, ol, OID_AUTO, n, CTLTYPE_STRUCT |
329 CTLFLAG_RD, s, 0, sysctl_handle_sensor, "S,sensor", "");
334 sensor_sysctl8magic_deinstall(struct ksensordev *sensdev)
336 struct sysctl_ctx_list *cl = &sensdev->clist;
341 #endif /* !NOSYSCTL8HACK */
345 sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS)
347 struct ksensordev *ksd = arg1;
348 struct sensordev *usd;
354 /* Grab a copy, to clear the kernel pointers */
355 usd = kmalloc(sizeof(*usd), M_TEMP, M_WAITOK | M_ZERO);
357 strlcpy(usd->xname, ksd->xname, sizeof(usd->xname));
358 memcpy(usd->maxnumt, ksd->maxnumt, sizeof(usd->maxnumt));
359 usd->sensors_count = ksd->sensors_count;
361 error = SYSCTL_OUT(req, usd, sizeof(struct sensordev));
369 sysctl_handle_sensor(SYSCTL_HANDLER_ARGS)
371 struct ksensor *ks = arg1;
378 /* Grab a copy, to clear the kernel pointers */
379 us = kmalloc(sizeof(*us), M_TEMP, M_WAITOK | M_ZERO);
380 memcpy(us->desc, ks->desc, sizeof(ks->desc));
382 us->value = ks->value;
384 us->status = ks->status;
386 us->flags = ks->flags;
388 error = SYSCTL_OUT(req, us, sizeof(struct sensor));
395 sysctl_sensors_handler(SYSCTL_HANDLER_ARGS)
398 u_int namelen = arg2;
399 struct ksensordev *ksd;
402 enum sensor_type type;
404 if (namelen != 1 && namelen != 3)
408 if ((ksd = sensordev_get(dev)) == NULL)
412 return (sysctl_handle_sensordev(NULL, ksd, 0, req));
417 if ((ks = sensor_find(ksd, type, numt)) == NULL)
419 return (sysctl_handle_sensor(NULL, ks, 0, req));