1 /* $OpenBSD: kern_sensors.c,v 1.19 2007/06/04 18:42:05 deraadt Exp $ */
6 * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
7 * Copyright (c) 2006 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru>
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 #include <sys/param.h>
23 #include <sys/systm.h>
24 #include <sys/kernel.h>
25 #include <sys/malloc.h>
26 #include <sys/kthread.h>
27 #include <sys/queue.h>
28 #include <sys/types.h>
30 #include <sys/spinlock.h>
31 #include <sys/spinlock2.h>
34 #include <sys/sysctl.h>
35 #include <sys/sensors.h>
37 #include <sys/mplock2.h>
39 static struct lock sensor_task_lock =
40 LOCK_INITIALIZER("ksensor_task", 0, LK_CANRECURSE);
41 static struct spinlock sensor_dev_lock =
42 SPINLOCK_INITIALIZER(sensor_dev_lock, "sensor_dev_lock");
44 static int sensordev_count;
45 static SLIST_HEAD(, ksensordev) sensordev_list =
46 SLIST_HEAD_INITIALIZER(sensordev_list);
48 static struct ksensordev *sensordev_get(int);
49 static struct ksensor *sensor_find(struct ksensordev *, enum sensor_type,
57 time_t nextrun; /* time_uptime */
59 TAILQ_ENTRY(sensor_task) entry;
62 static void sensor_task_thread(void *);
63 static void sensor_task_schedule(struct sensor_task *);
65 static TAILQ_HEAD(, sensor_task) sensor_tasklist =
66 TAILQ_HEAD_INITIALIZER(sensor_tasklist);
68 static void sensor_sysctl8magic_install(struct ksensordev *);
69 static void sensor_sysctl8magic_deinstall(struct ksensordev *);
72 sensordev_install(struct ksensordev *sensdev)
74 struct ksensordev *v, *nv;
76 /* mtx_lock(&Giant); */
77 spin_lock(&sensor_dev_lock);
78 if (sensordev_count == 0) {
80 SLIST_INSERT_HEAD(&sensordev_list, sensdev, list);
82 for (v = SLIST_FIRST(&sensordev_list);
83 (nv = SLIST_NEXT(v, list)) != NULL; v = nv)
84 if (nv->num - v->num > 1)
86 sensdev->num = v->num + 1;
87 SLIST_INSERT_AFTER(v, sensdev, list);
90 /* mtx_unlock(&Giant); */
91 spin_unlock(&sensor_dev_lock);
93 sensor_sysctl8magic_install(sensdev);
97 sensor_attach(struct ksensordev *sensdev, struct ksensor *sens)
99 struct ksensor *v, *nv;
100 struct ksensors_head *sh;
103 /* mtx_lock(&Giant); */
104 spin_lock(&sensor_dev_lock);
105 sh = &sensdev->sensors_list;
106 if (sensdev->sensors_count == 0) {
107 for (i = 0; i < SENSOR_MAX_TYPES; i++)
108 sensdev->maxnumt[i] = 0;
110 SLIST_INSERT_HEAD(sh, sens, list);
112 for (v = SLIST_FIRST(sh);
113 (nv = SLIST_NEXT(v, list)) != NULL; v = nv)
114 if (v->type == sens->type && (v->type != nv->type ||
115 (v->type == nv->type && nv->numt - v->numt > 1)))
117 /* sensors of the same type go after each other */
118 if (v->type == sens->type)
119 sens->numt = v->numt + 1;
122 SLIST_INSERT_AFTER(v, sens, list);
124 /* we only increment maxnumt[] if the sensor was added
125 * to the last position of sensors of this type
127 if (sensdev->maxnumt[sens->type] == sens->numt)
128 sensdev->maxnumt[sens->type]++;
129 sensdev->sensors_count++;
130 spin_unlock(&sensor_dev_lock);
131 /* mtx_unlock(&Giant); */
135 sensordev_deinstall(struct ksensordev *sensdev)
137 /* mtx_lock(&Giant); */
138 spin_lock(&sensor_dev_lock);
140 SLIST_REMOVE(&sensordev_list, sensdev, ksensordev, list);
141 /* mtx_unlock(&Giant); */
142 spin_unlock(&sensor_dev_lock);
144 sensor_sysctl8magic_deinstall(sensdev);
148 sensor_detach(struct ksensordev *sensdev, struct ksensor *sens)
150 struct ksensors_head *sh;
152 /* mtx_lock(&Giant); */
153 sh = &sensdev->sensors_list;
154 sensdev->sensors_count--;
155 SLIST_REMOVE(sh, sens, ksensor, list);
156 /* we only decrement maxnumt[] if this is the tail
157 * sensor of this type
159 if (sens->numt == sensdev->maxnumt[sens->type] - 1)
160 sensdev->maxnumt[sens->type]--;
161 /* mtx_unlock(&Giant); */
164 static struct ksensordev *
165 sensordev_get(int num)
167 struct ksensordev *sd;
169 spin_lock(&sensor_dev_lock);
170 SLIST_FOREACH(sd, &sensordev_list, list)
171 if (sd->num == num) {
172 spin_unlock(&sensor_dev_lock);
176 spin_unlock(&sensor_dev_lock);
180 static struct ksensor *
181 sensor_find(struct ksensordev *sensdev, enum sensor_type type, int numt)
184 struct ksensors_head *sh;
186 spin_lock(&sensor_dev_lock);
187 sh = &sensdev->sensors_list;
188 SLIST_FOREACH(s, sh, list) {
189 if (s->type == type && s->numt == numt) {
190 spin_unlock(&sensor_dev_lock);
195 spin_unlock(&sensor_dev_lock);
200 sensor_task_register(void *arg, void (*func)(void *), int period)
202 struct sensor_task *st;
203 int create_thread = 0;
205 st = kmalloc(sizeof(struct sensor_task), M_DEVBUF, M_NOWAIT);
209 lockmgr(&sensor_task_lock, LK_EXCLUSIVE);
216 if (TAILQ_EMPTY(&sensor_tasklist))
220 TAILQ_INSERT_HEAD(&sensor_tasklist, st, entry);
223 if (kthread_create(sensor_task_thread, NULL, NULL,
225 panic("sensors kthread");
227 wakeup(&sensor_tasklist);
229 lockmgr(&sensor_task_lock, LK_RELEASE);
234 sensor_task_unregister(void *arg)
236 struct sensor_task *st;
238 lockmgr(&sensor_task_lock, LK_EXCLUSIVE);
239 TAILQ_FOREACH(st, &sensor_tasklist, entry)
242 lockmgr(&sensor_task_lock, LK_RELEASE);
246 sensor_task_thread(void *arg)
248 struct sensor_task *st, *nst;
251 lockmgr(&sensor_task_lock, LK_EXCLUSIVE);
253 while (!TAILQ_EMPTY(&sensor_tasklist)) {
254 while ((nst = TAILQ_FIRST(&sensor_tasklist))->nextrun >
255 (now = time_uptime)) {
256 lksleep(&sensor_tasklist, &sensor_task_lock, 0,
257 "timeout", (nst->nextrun - now) * hz);
260 while ((st = nst) != NULL) {
261 nst = TAILQ_NEXT(st, entry);
263 if (st->nextrun > now)
266 /* take it out while we work on it */
267 TAILQ_REMOVE(&sensor_tasklist, st, entry);
276 /* stick it back in the tasklist */
277 sensor_task_schedule(st);
281 lockmgr(&sensor_task_lock, LK_RELEASE);
285 sensor_task_schedule(struct sensor_task *st)
287 struct sensor_task *cst;
289 lockmgr(&sensor_task_lock, LK_EXCLUSIVE);
290 st->nextrun = time_uptime + st->period;
292 TAILQ_FOREACH(cst, &sensor_tasklist, entry) {
293 if (cst->nextrun > st->nextrun) {
294 TAILQ_INSERT_BEFORE(cst, st, entry);
295 lockmgr(&sensor_task_lock, LK_RELEASE);
300 /* must be an empty list, or at the end of the list */
301 TAILQ_INSERT_TAIL(&sensor_tasklist, st, entry);
302 lockmgr(&sensor_task_lock, LK_RELEASE);
308 static int sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS);
309 static int sysctl_handle_sensor(SYSCTL_HANDLER_ARGS);
310 static int sysctl_sensors_handler(SYSCTL_HANDLER_ARGS);
312 SYSCTL_NODE(_hw, OID_AUTO, sensors, CTLFLAG_RD, NULL,
313 "Hardware Sensors sysctl internal magic");
314 SYSCTL_NODE(_hw, HW_SENSORS, _sensors, CTLFLAG_RD, sysctl_sensors_handler,
315 "Hardware Sensors XP MIB interface");
319 * FreeBSD's sysctl(9) .oid_handler functionality is not accustomed
320 * for the CTLTYPE_NODE handler to handle the undocumented sysctl
321 * magic calls. As soon as such functionality is developed,
322 * sysctl_sensors_handler() should be converted to handle all such
323 * calls, and these sysctl_add_oid(9) calls should be removed
324 * "with a big axe". This whole sysctl_add_oid(9) business is solely
325 * to please sysctl(8).
329 sensor_sysctl8magic_install(struct ksensordev *sensdev)
331 struct sysctl_oid_list *ol;
332 struct sysctl_ctx_list *cl = &sensdev->clist;
334 struct ksensors_head *sh = &sensdev->sensors_list;
337 ol = SYSCTL_CHILDREN(SYSCTL_ADD_NODE(cl, (&SYSCTL_NODE_CHILDREN(_hw,
338 sensors)), sensdev->num, sensdev->xname, CTLFLAG_RD, NULL, ""));
339 SLIST_FOREACH(s, sh, list) {
342 ksnprintf(n, sizeof(n), "%s%d", sensor_type_s[s->type], s->numt);
343 SYSCTL_ADD_PROC(cl, ol, OID_AUTO, n, CTLTYPE_STRUCT |
344 CTLFLAG_RD, s, 0, sysctl_handle_sensor, "S,sensor", "");
349 sensor_sysctl8magic_deinstall(struct ksensordev *sensdev)
351 struct sysctl_ctx_list *cl = &sensdev->clist;
357 sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS)
359 struct ksensordev *ksd = arg1;
360 struct sensordev *usd;
366 /* Grab a copy, to clear the kernel pointers */
367 usd = kmalloc(sizeof(*usd), M_TEMP, M_WAITOK | M_ZERO);
369 strlcpy(usd->xname, ksd->xname, sizeof(usd->xname));
370 memcpy(usd->maxnumt, ksd->maxnumt, sizeof(usd->maxnumt));
371 usd->sensors_count = ksd->sensors_count;
373 error = SYSCTL_OUT(req, usd, sizeof(struct sensordev));
381 sysctl_handle_sensor(SYSCTL_HANDLER_ARGS)
383 struct ksensor *ks = arg1;
390 /* Grab a copy, to clear the kernel pointers */
391 us = kmalloc(sizeof(*us), M_TEMP, M_WAITOK | M_ZERO);
392 memcpy(us->desc, ks->desc, sizeof(ks->desc));
394 us->value = ks->value;
396 us->status = ks->status;
398 us->flags = ks->flags;
400 error = SYSCTL_OUT(req, us, sizeof(struct sensor));
407 sysctl_sensors_handler(SYSCTL_HANDLER_ARGS)
410 u_int namelen = arg2;
411 struct ksensordev *ksd;
414 enum sensor_type type;
416 if (namelen != 1 && namelen != 3)
420 if ((ksd = sensordev_get(dev)) == NULL)
424 return (sysctl_handle_sensordev(NULL, ksd, 0, req));
429 if ((ks = sensor_find(ksd, type, numt)) == NULL)
431 return (sysctl_handle_sensor(NULL, ks, 0, req));