fwcontrol(8): Remove an unused variable and raise WARNS to 2.
[dragonfly.git] / sys / kern / kern_sensors.c
blob63faaf4e24d66e9ff3a752107fe65de6b870047b
1 /* $OpenBSD: kern_sensors.c,v 1.19 2007/06/04 18:42:05 deraadt Exp $ */
3 /*
4 * (MPSAFE)
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>
29 #include <sys/time.h>
30 #include <sys/spinlock.h>
31 #include <sys/spinlock2.h>
32 #include <sys/lock.h>
34 #include <sys/sysctl.h>
35 #include <sys/sensors.h>
37 #include <sys/mplock2.h>
39 static int sensor_task_lock_inited = 0;
40 static struct lock sensor_task_lock;
41 static struct spinlock sensor_dev_lock = SPINLOCK_INITIALIZER(sensor_dev_lock);
43 int sensordev_count = 0;
44 SLIST_HEAD(, ksensordev) sensordev_list = SLIST_HEAD_INITIALIZER(sensordev_list);
46 struct ksensordev *sensordev_get(int);
47 struct ksensor *sensor_find(struct ksensordev *, enum sensor_type, int);
49 struct sensor_task {
50 void *arg;
51 void (*func)(void *);
53 int period;
54 time_t nextrun;
55 volatile int running;
56 TAILQ_ENTRY(sensor_task) entry;
59 void sensor_task_thread(void *);
60 void sensor_task_schedule(struct sensor_task *);
62 TAILQ_HEAD(, sensor_task) tasklist = TAILQ_HEAD_INITIALIZER(tasklist);
64 #ifndef NOSYSCTL8HACK
65 void sensor_sysctl8magic_install(struct ksensordev *);
66 void sensor_sysctl8magic_deinstall(struct ksensordev *);
67 #endif
69 void
70 sensordev_install(struct ksensordev *sensdev)
72 struct ksensordev *v, *nv;
74 /* mtx_lock(&Giant); */
75 spin_lock(&sensor_dev_lock);
76 if (sensordev_count == 0) {
77 sensdev->num = 0;
78 SLIST_INSERT_HEAD(&sensordev_list, sensdev, list);
79 } else {
80 for (v = SLIST_FIRST(&sensordev_list);
81 (nv = SLIST_NEXT(v, list)) != NULL; v = nv)
82 if (nv->num - v->num > 1)
83 break;
84 sensdev->num = v->num + 1;
85 SLIST_INSERT_AFTER(v, sensdev, list);
87 sensordev_count++;
88 /* mtx_unlock(&Giant); */
89 spin_unlock(&sensor_dev_lock);
91 #ifndef NOSYSCTL8HACK
92 sensor_sysctl8magic_install(sensdev);
93 #endif
96 void
97 sensor_attach(struct ksensordev *sensdev, struct ksensor *sens)
99 struct ksensor *v, *nv;
100 struct ksensors_head *sh;
101 int i;
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;
109 sens->numt = 0;
110 SLIST_INSERT_HEAD(sh, sens, list);
111 } else {
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)))
116 break;
117 /* sensors of the same type go after each other */
118 if (v->type == sens->type)
119 sens->numt = v->numt + 1;
120 else
121 sens->numt = 0;
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); */
134 void
135 sensordev_deinstall(struct ksensordev *sensdev)
137 /* mtx_lock(&Giant); */
138 spin_lock(&sensor_dev_lock);
139 sensordev_count--;
140 SLIST_REMOVE(&sensordev_list, sensdev, ksensordev, list);
141 /* mtx_unlock(&Giant); */
142 spin_unlock(&sensor_dev_lock);
144 #ifndef NOSYSCTL8HACK
145 sensor_sysctl8magic_deinstall(sensdev);
146 #endif
149 void
150 sensor_detach(struct ksensordev *sensdev, struct ksensor *sens)
152 struct ksensors_head *sh;
154 /* mtx_lock(&Giant); */
155 sh = &sensdev->sensors_list;
156 sensdev->sensors_count--;
157 SLIST_REMOVE(sh, sens, ksensor, list);
158 /* we only decrement maxnumt[] if this is the tail
159 * sensor of this type
161 if (sens->numt == sensdev->maxnumt[sens->type] - 1)
162 sensdev->maxnumt[sens->type]--;
163 /* mtx_unlock(&Giant); */
166 struct ksensordev *
167 sensordev_get(int num)
169 struct ksensordev *sd;
171 spin_lock(&sensor_dev_lock);
172 SLIST_FOREACH(sd, &sensordev_list, list)
173 if (sd->num == num) {
174 spin_unlock(&sensor_dev_lock);
175 return (sd);
178 spin_unlock(&sensor_dev_lock);
179 return (NULL);
182 struct ksensor *
183 sensor_find(struct ksensordev *sensdev, enum sensor_type type, int numt)
185 struct ksensor *s;
186 struct ksensors_head *sh;
188 spin_lock(&sensor_dev_lock);
189 sh = &sensdev->sensors_list;
190 SLIST_FOREACH(s, sh, list) {
191 if (s->type == type && s->numt == numt) {
192 spin_unlock(&sensor_dev_lock);
193 return (s);
197 spin_unlock(&sensor_dev_lock);
198 return (NULL);
202 sensor_task_register(void *arg, void (*func)(void *), int period)
204 struct sensor_task *st;
205 int create_thread = 0;
207 st = kmalloc(sizeof(struct sensor_task), M_DEVBUF, M_NOWAIT);
208 if (st == NULL)
209 return (1);
211 if (atomic_cmpset_int(&sensor_task_lock_inited, 0, 1)) {
212 lockinit(&sensor_task_lock, "ksensor_task", 0, LK_CANRECURSE);
215 lockmgr(&sensor_task_lock, LK_EXCLUSIVE);
216 st->arg = arg;
217 st->func = func;
218 st->period = period;
220 st->running = 1;
222 if (TAILQ_EMPTY(&tasklist))
223 create_thread = 1;
225 st->nextrun = 0;
226 TAILQ_INSERT_HEAD(&tasklist, st, entry);
228 if (create_thread)
229 if (kthread_create(sensor_task_thread, NULL, NULL,
230 "sensors") != 0)
231 panic("sensors kthread");
233 wakeup(&tasklist);
235 lockmgr(&sensor_task_lock, LK_RELEASE);
236 return (0);
239 void
240 sensor_task_unregister(void *arg)
242 struct sensor_task *st;
244 lockmgr(&sensor_task_lock, LK_EXCLUSIVE);
245 TAILQ_FOREACH(st, &tasklist, entry)
246 if (st->arg == arg)
247 st->running = 0;
248 lockmgr(&sensor_task_lock, LK_RELEASE);
251 void
252 sensor_task_thread(void *arg)
254 struct sensor_task *st, *nst;
255 time_t now;
257 lockmgr(&sensor_task_lock, LK_EXCLUSIVE);
259 while (!TAILQ_EMPTY(&tasklist)) {
260 while ((nst = TAILQ_FIRST(&tasklist))->nextrun >
261 (now = time_second))
262 lksleep(&tasklist, &sensor_task_lock, 0, "timeout",
263 (nst->nextrun - now) * hz);
265 while ((st = nst) != NULL) {
266 nst = TAILQ_NEXT(st, entry);
268 if (st->nextrun > now)
269 break;
271 /* take it out while we work on it */
272 TAILQ_REMOVE(&tasklist, st, entry);
274 if (!st->running) {
275 kfree(st, M_DEVBUF);
276 continue;
279 /* run the task */
280 st->func(st->arg);
281 /* stick it back in the tasklist */
282 sensor_task_schedule(st);
286 lockmgr(&sensor_task_lock, LK_RELEASE);
289 void
290 sensor_task_schedule(struct sensor_task *st)
292 struct sensor_task *cst;
294 lockmgr(&sensor_task_lock, LK_EXCLUSIVE);
295 st->nextrun = time_second + st->period;
297 TAILQ_FOREACH(cst, &tasklist, entry) {
298 if (cst->nextrun > st->nextrun) {
299 TAILQ_INSERT_BEFORE(cst, st, entry);
300 lockmgr(&sensor_task_lock, LK_RELEASE);
301 return;
305 /* must be an empty list, or at the end of the list */
306 TAILQ_INSERT_TAIL(&tasklist, st, entry);
307 lockmgr(&sensor_task_lock, LK_RELEASE);
311 * sysctl glue code
313 int sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS);
314 int sysctl_handle_sensor(SYSCTL_HANDLER_ARGS);
315 int sysctl_sensors_handler(SYSCTL_HANDLER_ARGS);
317 #ifndef NOSYSCTL8HACK
319 SYSCTL_NODE(_hw, OID_AUTO, sensors, CTLFLAG_RD, NULL,
320 "Hardware Sensors sysctl internal magic");
321 SYSCTL_NODE(_hw, HW_SENSORS, _sensors, CTLFLAG_RD, sysctl_sensors_handler,
322 "Hardware Sensors XP MIB interface");
324 #else /* NOSYSCTL8HACK */
326 SYSCTL_NODE(_hw, HW_SENSORS, sensors, CTLFLAG_RD, sysctl_sensors_handler,
327 "Hardware Sensors");
328 int sensors_debug = 1;
329 SYSCTL_INT(_hw_sensors, OID_AUTO, debug, CTLFLAG_RD, &sensors_debug, 0, "sensors debug");
331 #endif /* !NOSYSCTL8HACK */
334 #ifndef NOSYSCTL8HACK
337 * XXX:
338 * FreeBSD's sysctl(9) .oid_handler functionality is not accustomed
339 * for the CTLTYPE_NODE handler to handle the undocumented sysctl
340 * magic calls. As soon as such functionality is developed,
341 * sysctl_sensors_handler() should be converted to handle all such
342 * calls, and these sysctl_add_oid(9) calls should be removed
343 * "with a big axe". This whole sysctl_add_oid(9) business is solely
344 * to please sysctl(8).
347 void
348 sensor_sysctl8magic_install(struct ksensordev *sensdev)
350 struct sysctl_oid_list *ol;
351 struct sysctl_ctx_list *cl = &sensdev->clist;
352 struct ksensor *s;
353 struct ksensors_head *sh = &sensdev->sensors_list;
355 sysctl_ctx_init(cl);
356 ol = SYSCTL_CHILDREN(SYSCTL_ADD_NODE(cl, (&SYSCTL_NODE_CHILDREN(_hw,
357 sensors)), sensdev->num, sensdev->xname, CTLFLAG_RD, NULL, ""));
358 SLIST_FOREACH(s, sh, list) {
359 char n[32];
361 ksnprintf(n, sizeof(n), "%s%d", sensor_type_s[s->type], s->numt);
362 SYSCTL_ADD_PROC(cl, ol, OID_AUTO, n, CTLTYPE_STRUCT |
363 CTLFLAG_RD, s, 0, sysctl_handle_sensor, "S,sensor", "");
367 void
368 sensor_sysctl8magic_deinstall(struct ksensordev *sensdev)
370 struct sysctl_ctx_list *cl = &sensdev->clist;
372 sysctl_ctx_free(cl);
375 #endif /* !NOSYSCTL8HACK */
379 sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS)
381 struct ksensordev *ksd = arg1;
382 struct sensordev *usd;
383 int error;
385 if (req->newptr)
386 return (EPERM);
388 /* Grab a copy, to clear the kernel pointers */
389 usd = kmalloc(sizeof(*usd), M_TEMP, M_WAITOK | M_ZERO);
390 usd->num = ksd->num;
391 strlcpy(usd->xname, ksd->xname, sizeof(usd->xname));
392 memcpy(usd->maxnumt, ksd->maxnumt, sizeof(usd->maxnumt));
393 usd->sensors_count = ksd->sensors_count;
395 error = SYSCTL_OUT(req, usd, sizeof(struct sensordev));
397 kfree(usd, M_TEMP);
398 return (error);
403 sysctl_handle_sensor(SYSCTL_HANDLER_ARGS)
405 struct ksensor *ks = arg1;
406 struct sensor *us;
407 int error;
409 if (req->newptr)
410 return (EPERM);
412 /* Grab a copy, to clear the kernel pointers */
413 us = kmalloc(sizeof(*us), M_TEMP, M_WAITOK | M_ZERO);
414 memcpy(us->desc, ks->desc, sizeof(ks->desc));
415 us->tv = ks->tv;
416 us->value = ks->value;
417 us->type = ks->type;
418 us->status = ks->status;
419 us->numt = ks->numt;
420 us->flags = ks->flags;
422 error = SYSCTL_OUT(req, us, sizeof(struct sensor));
424 kfree(us, M_TEMP);
425 return (error);
429 sysctl_sensors_handler(SYSCTL_HANDLER_ARGS)
431 int *name = arg1;
432 u_int namelen = arg2;
433 struct ksensordev *ksd;
434 struct ksensor *ks;
435 int dev, numt;
436 enum sensor_type type;
438 if (namelen != 1 && namelen != 3)
439 return (ENOTDIR);
441 dev = name[0];
442 if ((ksd = sensordev_get(dev)) == NULL)
443 return (ENOENT);
445 if (namelen == 1)
446 return (sysctl_handle_sensordev(NULL, ksd, 0, req));
448 type = name[1];
449 numt = name[2];
451 if ((ks = sensor_find(ksd, type, numt)) == NULL)
452 return (ENOENT);
453 return (sysctl_handle_sensor(NULL, ks, 0, req));