sensor: Expose max id of sensor device through hw.sensors.dev_idmax
[dragonfly.git] / sys / kern / kern_sensors.c
blobafddd5330e7176b220194b55d55dbb73604ef7ab
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 sensordev_idmax;
40 static TAILQ_HEAD(sensordev_list, ksensordev) sensordev_list =
41 TAILQ_HEAD_INITIALIZER(sensordev_list);
43 static struct ksensordev *sensordev_get(int);
44 static struct ksensor *sensor_find(struct ksensordev *, enum sensor_type,
45 int);
47 struct sensor_task {
48 void *arg;
49 void (*func)(void *);
51 int period;
52 time_t nextrun; /* time_uptime */
53 int running;
54 TAILQ_ENTRY(sensor_task) entry;
57 static void sensor_task_thread(void *);
58 static void sensor_task_schedule(struct sensor_task *);
60 static TAILQ_HEAD(, sensor_task) sensor_tasklist =
61 TAILQ_HEAD_INITIALIZER(sensor_tasklist);
63 static struct lock sensor_task_lock =
64 LOCK_INITIALIZER("ksensor_task", 0, LK_CANRECURSE);
66 static void sensordev_sysctl_install(struct ksensordev *);
67 static void sensordev_sysctl_deinstall(struct ksensordev *);
68 static void sensor_sysctl_install(struct ksensordev *,
69 struct ksensor *);
70 static void sensor_sysctl_deinstall(struct ksensordev *,
71 struct ksensor *);
73 void
74 sensordev_install(struct ksensordev *sensdev)
76 struct ksensordev *v, *after = NULL;
77 int num = 0;
79 SYSCTL_XLOCK();
81 TAILQ_FOREACH(v, &sensordev_list, list) {
82 if (v->num == num) {
83 ++num;
84 after = v;
85 } else if (v->num > num) {
86 break;
90 sensdev->num = num;
91 if (after == NULL) {
92 KKASSERT(sensdev->num == 0);
93 TAILQ_INSERT_HEAD(&sensordev_list, sensdev, list);
94 } else {
95 TAILQ_INSERT_AFTER(&sensordev_list, after, sensdev, list);
98 /* Save max sensor device id */
99 sensordev_idmax = TAILQ_LAST(&sensordev_list, sensordev_list)->num + 1;
101 /* Install sysctl node for this sensor device */
102 sensordev_sysctl_install(sensdev);
104 SYSCTL_XUNLOCK();
107 void
108 sensor_attach(struct ksensordev *sensdev, struct ksensor *sens)
110 struct ksensor *v, *nv;
111 struct ksensors_head *sh;
112 int i;
114 SYSCTL_XLOCK();
116 sh = &sensdev->sensors_list;
117 if (sensdev->sensors_count == 0) {
118 for (i = 0; i < SENSOR_MAX_TYPES; i++)
119 sensdev->maxnumt[i] = 0;
120 sens->numt = 0;
121 SLIST_INSERT_HEAD(sh, sens, list);
122 } else {
123 for (v = SLIST_FIRST(sh);
124 (nv = SLIST_NEXT(v, list)) != NULL; v = nv)
125 if (v->type == sens->type && (v->type != nv->type ||
126 (v->type == nv->type && nv->numt - v->numt > 1)))
127 break;
128 /* sensors of the same type go after each other */
129 if (v->type == sens->type)
130 sens->numt = v->numt + 1;
131 else
132 sens->numt = 0;
133 SLIST_INSERT_AFTER(v, sens, list);
136 * We only increment maxnumt[] if the sensor was added
137 * to the last position of sensors of this type
139 if (sensdev->maxnumt[sens->type] == sens->numt)
140 sensdev->maxnumt[sens->type]++;
141 sensdev->sensors_count++;
143 /* Install sysctl node for this sensor */
144 sensor_sysctl_install(sensdev, sens);
146 SYSCTL_XUNLOCK();
149 void
150 sensordev_deinstall(struct ksensordev *sensdev)
152 struct ksensordev *last;
154 SYSCTL_XLOCK();
156 TAILQ_REMOVE(&sensordev_list, sensdev, list);
158 /* Adjust max sensor device id */
159 last = TAILQ_LAST(&sensordev_list, sensordev_list);
160 if (last != NULL)
161 sensordev_idmax = last->num + 1;
162 else
163 sensordev_idmax = 0;
166 * Deinstall sensor device's sysctl node; this also
167 * removes all attached sensors' sysctl nodes.
169 sensordev_sysctl_deinstall(sensdev);
171 SYSCTL_XUNLOCK();
174 void
175 sensor_detach(struct ksensordev *sensdev, struct ksensor *sens)
177 struct ksensors_head *sh;
179 SYSCTL_XLOCK();
181 sh = &sensdev->sensors_list;
182 sensdev->sensors_count--;
183 SLIST_REMOVE(sh, sens, ksensor, list);
185 * We only decrement maxnumt[] if this is the tail
186 * sensor of this type
188 if (sens->numt == sensdev->maxnumt[sens->type] - 1)
189 sensdev->maxnumt[sens->type]--;
191 /* Deinstall sensor's sysctl node */
192 sensor_sysctl_deinstall(sensdev, sens);
194 SYSCTL_XUNLOCK();
197 static struct ksensordev *
198 sensordev_get(int num)
200 struct ksensordev *sd;
202 SYSCTL_ASSERT_XLOCKED();
204 TAILQ_FOREACH(sd, &sensordev_list, list) {
205 if (sd->num == num)
206 return (sd);
208 return (NULL);
211 static struct ksensor *
212 sensor_find(struct ksensordev *sensdev, enum sensor_type type, int numt)
214 struct ksensor *s;
215 struct ksensors_head *sh;
217 SYSCTL_ASSERT_XLOCKED();
219 sh = &sensdev->sensors_list;
220 SLIST_FOREACH(s, sh, list) {
221 if (s->type == type && s->numt == numt)
222 return (s);
224 return (NULL);
227 void
228 sensor_task_register(void *arg, void (*func)(void *), int period)
230 struct sensor_task *st;
232 st = kmalloc(sizeof(struct sensor_task), M_DEVBUF, M_WAITOK);
234 lockmgr(&sensor_task_lock, LK_EXCLUSIVE);
235 st->arg = arg;
236 st->func = func;
237 st->period = period;
239 st->running = 1;
241 st->nextrun = 0;
242 TAILQ_INSERT_HEAD(&sensor_tasklist, st, entry);
244 wakeup(&sensor_tasklist);
246 lockmgr(&sensor_task_lock, LK_RELEASE);
249 void
250 sensor_task_unregister(void *arg)
252 struct sensor_task *st;
254 lockmgr(&sensor_task_lock, LK_EXCLUSIVE);
255 TAILQ_FOREACH(st, &sensor_tasklist, entry)
256 if (st->arg == arg)
257 st->running = 0;
258 lockmgr(&sensor_task_lock, LK_RELEASE);
261 static void
262 sensor_task_thread(void *arg)
264 struct sensor_task *st, *nst;
265 time_t now;
267 lockmgr(&sensor_task_lock, LK_EXCLUSIVE);
269 for (;;) {
270 while (TAILQ_EMPTY(&sensor_tasklist)) {
271 lksleep(&sensor_tasklist, &sensor_task_lock, 0,
272 "waittask", 0);
275 while ((nst = TAILQ_FIRST(&sensor_tasklist))->nextrun >
276 (now = time_uptime)) {
277 lksleep(&sensor_tasklist, &sensor_task_lock, 0,
278 "timeout", (nst->nextrun - now) * hz);
281 while ((st = nst) != NULL) {
282 nst = TAILQ_NEXT(st, entry);
284 if (st->nextrun > now)
285 break;
287 /* take it out while we work on it */
288 TAILQ_REMOVE(&sensor_tasklist, st, entry);
290 if (!st->running) {
291 kfree(st, M_DEVBUF);
292 continue;
295 /* run the task */
296 st->func(st->arg);
297 /* stick it back in the tasklist */
298 sensor_task_schedule(st);
302 lockmgr(&sensor_task_lock, LK_RELEASE);
305 static void
306 sensor_task_schedule(struct sensor_task *st)
308 struct sensor_task *cst;
310 KASSERT(lockstatus(&sensor_task_lock, curthread) == LK_EXCLUSIVE,
311 ("sensor task lock is not held"));
313 st->nextrun = time_uptime + st->period;
315 TAILQ_FOREACH(cst, &sensor_tasklist, entry) {
316 if (cst->nextrun > st->nextrun) {
317 TAILQ_INSERT_BEFORE(cst, st, entry);
318 return;
322 /* must be an empty list, or at the end of the list */
323 TAILQ_INSERT_TAIL(&sensor_tasklist, st, entry);
327 * sysctl glue code
329 static int sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS);
330 static int sysctl_handle_sensor(SYSCTL_HANDLER_ARGS);
331 static int sysctl_sensors_handler(SYSCTL_HANDLER_ARGS);
333 SYSCTL_NODE(_hw, OID_AUTO, sensors, CTLFLAG_RD, NULL,
334 "Hardware Sensors sysctl internal magic");
335 SYSCTL_NODE(_hw, HW_SENSORS, _sensors, CTLFLAG_RD, sysctl_sensors_handler,
336 "Hardware Sensors XP MIB interface");
338 SYSCTL_INT(_hw_sensors, OID_AUTO, dev_idmax, CTLFLAG_RD,
339 &sensordev_idmax, 0, "Max sensor device id");
341 static void
342 sensordev_sysctl_install(struct ksensordev *sensdev)
344 struct sysctl_ctx_list *cl = &sensdev->clist;
345 struct ksensor *s;
346 struct ksensors_head *sh = &sensdev->sensors_list;
348 SYSCTL_ASSERT_XLOCKED();
350 KASSERT(sensdev->oid == NULL,
351 ("sensor device %s sysctl node already installed", sensdev->xname));
353 sysctl_ctx_init(cl);
354 sensdev->oid = SYSCTL_ADD_NODE(cl, SYSCTL_STATIC_CHILDREN(_hw_sensors),
355 sensdev->num, sensdev->xname, CTLFLAG_RD, NULL, "");
356 if (sensdev->oid == NULL) {
357 kprintf("sensor: add sysctl tree for %s failed\n",
358 sensdev->xname);
359 return;
362 /* Install sysctl nodes for sensors attached to this sensor device */
363 SLIST_FOREACH(s, sh, list)
364 sensor_sysctl_install(sensdev, s);
367 static void
368 sensor_sysctl_install(struct ksensordev *sensdev, struct ksensor *sens)
370 char n[32];
372 SYSCTL_ASSERT_XLOCKED();
374 if (sensdev->oid == NULL) {
375 /* Sensor device sysctl node is not installed yet */
376 return;
379 ksnprintf(n, sizeof(n), "%s%d", sensor_type_s[sens->type], sens->numt);
380 KASSERT(sens->oid == NULL,
381 ("sensor %s:%s sysctl node already installed", sensdev->xname, n));
383 sens->oid = SYSCTL_ADD_PROC(&sensdev->clist,
384 SYSCTL_CHILDREN(sensdev->oid), OID_AUTO, n,
385 CTLTYPE_STRUCT | CTLFLAG_RD, sens, 0, sysctl_handle_sensor,
386 "S,sensor", "");
389 static void
390 sensordev_sysctl_deinstall(struct ksensordev *sensdev)
392 SYSCTL_ASSERT_XLOCKED();
394 if (sensdev->oid != NULL) {
395 sysctl_ctx_free(&sensdev->clist);
396 sensdev->oid = NULL;
400 static void
401 sensor_sysctl_deinstall(struct ksensordev *sensdev, struct ksensor *sens)
403 SYSCTL_ASSERT_XLOCKED();
405 if (sensdev->oid != NULL && sens->oid != NULL) {
406 sysctl_ctx_entry_del(&sensdev->clist, sens->oid);
407 sysctl_remove_oid(sens->oid, 1, 0);
409 sens->oid = NULL;
412 static int
413 sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS)
415 struct ksensordev *ksd = arg1;
416 struct sensordev *usd;
417 int error;
419 if (req->newptr)
420 return (EPERM);
422 /* Grab a copy, to clear the kernel pointers */
423 usd = kmalloc(sizeof(*usd), M_TEMP, M_WAITOK | M_ZERO);
424 usd->num = ksd->num;
425 strlcpy(usd->xname, ksd->xname, sizeof(usd->xname));
426 memcpy(usd->maxnumt, ksd->maxnumt, sizeof(usd->maxnumt));
427 usd->sensors_count = ksd->sensors_count;
429 error = SYSCTL_OUT(req, usd, sizeof(struct sensordev));
431 kfree(usd, M_TEMP);
432 return (error);
435 static int
436 sysctl_handle_sensor(SYSCTL_HANDLER_ARGS)
438 struct ksensor *ks = arg1;
439 struct sensor *us;
440 int error;
442 if (req->newptr)
443 return (EPERM);
445 /* Grab a copy, to clear the kernel pointers */
446 us = kmalloc(sizeof(*us), M_TEMP, M_WAITOK | M_ZERO);
447 memcpy(us->desc, ks->desc, sizeof(ks->desc));
448 us->tv = ks->tv;
449 us->value = ks->value;
450 us->type = ks->type;
451 us->status = ks->status;
452 us->numt = ks->numt;
453 us->flags = ks->flags;
455 error = SYSCTL_OUT(req, us, sizeof(struct sensor));
457 kfree(us, M_TEMP);
458 return (error);
461 static int
462 sysctl_sensors_handler(SYSCTL_HANDLER_ARGS)
464 int *name = arg1;
465 u_int namelen = arg2;
466 struct ksensordev *ksd;
467 struct ksensor *ks;
468 int dev, numt;
469 enum sensor_type type;
471 if (namelen != 1 && namelen != 3)
472 return (ENOTDIR);
474 dev = name[0];
475 if ((ksd = sensordev_get(dev)) == NULL)
476 return (ENOENT);
478 if (namelen == 1)
479 return (sysctl_handle_sensordev(NULL, ksd, 0, req));
481 type = name[1];
482 numt = name[2];
484 if ((ks = sensor_find(ksd, type, numt)) == NULL)
485 return (ENOENT);
486 return (sysctl_handle_sensor(NULL, ks, 0, req));
489 static void
490 sensor_sysinit(void *arg __unused)
492 int error;
494 error = kthread_create(sensor_task_thread, NULL, NULL, "sensors");
495 if (error)
496 panic("sensors kthread failed: %d", error);
498 SYSINIT(sensor, SI_SUB_PRE_DRIVERS, SI_ORDER_ANY, sensor_sysinit, NULL);