xref: /dragonfly/sys/kern/kern_sensors.c (revision c93b565c)
1 /* $OpenBSD: kern_sensors.c,v 1.19 2007/06/04 18:42:05 deraadt Exp $ */
2 
3 /*
4  * (MPSAFE)
5  *
6  * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
7  * Copyright (c) 2006 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru>
8  *
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.
12  *
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.
20  */
21 
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>
33 
34 #include <sys/sysctl.h>
35 #include <sys/sensors.h>
36 
37 #include <sys/mplock2.h>
38 
39 static int		sensordev_idmax;
40 static TAILQ_HEAD(sensordev_list, ksensordev) sensordev_list =
41     TAILQ_HEAD_INITIALIZER(sensordev_list);
42 
43 static struct ksensordev *sensordev_get(int);
44 static struct ksensor	*sensor_find(struct ksensordev *, enum sensor_type,
45 			    int);
46 
47 struct sensor_task {
48 	void				*arg;
49 	void				(*func)(void *);
50 
51 	int				period;
52 	time_t				nextrun;	/* time_uptime */
53 	int				running;
54 	TAILQ_ENTRY(sensor_task)	entry;
55 };
56 
57 static void		sensor_task_thread(void *);
58 static void		sensor_task_schedule(struct sensor_task *);
59 
60 static TAILQ_HEAD(, sensor_task) sensor_tasklist =
61     TAILQ_HEAD_INITIALIZER(sensor_tasklist);
62 
63 static struct lock	sensor_task_lock =
64     LOCK_INITIALIZER("ksensor_task", 0, LK_CANRECURSE);
65 
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 *);
72 
73 void
74 sensordev_install(struct ksensordev *sensdev)
75 {
76 	struct ksensordev *v, *after = NULL;
77 	int num = 0;
78 
79 	SYSCTL_XLOCK();
80 
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;
87 		}
88 	}
89 
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);
96 	}
97 
98 	/* Save max sensor device id */
99 	sensordev_idmax = TAILQ_LAST(&sensordev_list, sensordev_list)->num + 1;
100 
101 	/* Install sysctl node for this sensor device */
102 	sensordev_sysctl_install(sensdev);
103 
104 	SYSCTL_XUNLOCK();
105 }
106 
107 void
108 sensor_attach(struct ksensordev *sensdev, struct ksensor *sens)
109 {
110 	struct ksensor *v, *nv;
111 	struct ksensors_head *sh;
112 	int i;
113 
114 	SYSCTL_XLOCK();
115 
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);
134 	}
135 	/*
136 	 * We only increment maxnumt[] if the sensor was added
137 	 * to the last position of sensors of this type
138 	 */
139 	if (sensdev->maxnumt[sens->type] == sens->numt)
140 		sensdev->maxnumt[sens->type]++;
141 	sensdev->sensors_count++;
142 
143 	/* Install sysctl node for this sensor */
144 	sensor_sysctl_install(sensdev, sens);
145 
146 	SYSCTL_XUNLOCK();
147 }
148 
149 void
150 sensordev_deinstall(struct ksensordev *sensdev)
151 {
152 	struct ksensordev *last;
153 
154 	SYSCTL_XLOCK();
155 
156 	TAILQ_REMOVE(&sensordev_list, sensdev, list);
157 
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;
164 
165 	/*
166 	 * Deinstall sensor device's sysctl node; this also
167 	 * removes all attached sensors' sysctl nodes.
168 	 */
169 	sensordev_sysctl_deinstall(sensdev);
170 
171 	SYSCTL_XUNLOCK();
172 }
173 
174 void
175 sensor_detach(struct ksensordev *sensdev, struct ksensor *sens)
176 {
177 	struct ksensors_head *sh;
178 
179 	SYSCTL_XLOCK();
180 
181 	sh = &sensdev->sensors_list;
182 	sensdev->sensors_count--;
183 	SLIST_REMOVE(sh, sens, ksensor, list);
184 	/*
185 	 * We only decrement maxnumt[] if this is the tail
186 	 * sensor of this type
187 	 */
188 	if (sens->numt == sensdev->maxnumt[sens->type] - 1)
189 		sensdev->maxnumt[sens->type]--;
190 
191 	/* Deinstall sensor's sysctl node */
192 	sensor_sysctl_deinstall(sensdev, sens);
193 
194 	SYSCTL_XUNLOCK();
195 }
196 
197 static struct ksensordev *
198 sensordev_get(int num)
199 {
200 	struct ksensordev *sd;
201 
202 	SYSCTL_ASSERT_XLOCKED();
203 
204 	TAILQ_FOREACH(sd, &sensordev_list, list) {
205 		if (sd->num == num)
206 			return (sd);
207 	}
208 	return (NULL);
209 }
210 
211 static struct ksensor *
212 sensor_find(struct ksensordev *sensdev, enum sensor_type type, int numt)
213 {
214 	struct ksensor *s;
215 	struct ksensors_head *sh;
216 
217 	SYSCTL_ASSERT_XLOCKED();
218 
219 	sh = &sensdev->sensors_list;
220 	SLIST_FOREACH(s, sh, list) {
221 		if (s->type == type && s->numt == numt)
222 			return (s);
223 	}
224 	return (NULL);
225 }
226 
227 void
228 sensor_task_register(void *arg, void (*func)(void *), int period)
229 {
230 	struct sensor_task	*st;
231 
232 	st = kmalloc(sizeof(struct sensor_task), M_DEVBUF, M_WAITOK);
233 
234 	lockmgr(&sensor_task_lock, LK_EXCLUSIVE);
235 	st->arg = arg;
236 	st->func = func;
237 	st->period = period;
238 
239 	st->running = 1;
240 
241 	st->nextrun = 0;
242 	TAILQ_INSERT_HEAD(&sensor_tasklist, st, entry);
243 
244 	wakeup(&sensor_tasklist);
245 
246 	lockmgr(&sensor_task_lock, LK_RELEASE);
247 }
248 
249 void
250 sensor_task_unregister(void *arg)
251 {
252 	struct sensor_task	*st;
253 
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);
259 }
260 
261 static void
262 sensor_task_thread(void *arg)
263 {
264 	struct sensor_task	*st, *nst;
265 	time_t			now;
266 
267 	lockmgr(&sensor_task_lock, LK_EXCLUSIVE);
268 
269 	for (;;) {
270 		while (TAILQ_EMPTY(&sensor_tasklist)) {
271 			lksleep(&sensor_tasklist, &sensor_task_lock, 0,
272 			    "waittask", 0);
273 		}
274 
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);
279 		}
280 
281 		while ((st = nst) != NULL) {
282 			nst = TAILQ_NEXT(st, entry);
283 
284 			if (st->nextrun > now)
285 				break;
286 
287 			/* take it out while we work on it */
288 			TAILQ_REMOVE(&sensor_tasklist, st, entry);
289 
290 			if (!st->running) {
291 				kfree(st, M_DEVBUF);
292 				continue;
293 			}
294 
295 			/* run the task */
296 			st->func(st->arg);
297 			/* stick it back in the tasklist */
298 			sensor_task_schedule(st);
299 		}
300 	}
301 
302 	lockmgr(&sensor_task_lock, LK_RELEASE);
303 }
304 
305 static void
306 sensor_task_schedule(struct sensor_task *st)
307 {
308 	struct sensor_task 	*cst;
309 
310 	KASSERT(lockstatus(&sensor_task_lock, curthread) == LK_EXCLUSIVE,
311 	    ("sensor task lock is not held"));
312 
313 	st->nextrun = time_uptime + st->period;
314 
315 	TAILQ_FOREACH(cst, &sensor_tasklist, entry) {
316 		if (cst->nextrun > st->nextrun) {
317 			TAILQ_INSERT_BEFORE(cst, st, entry);
318 			return;
319 		}
320 	}
321 
322 	/* must be an empty list, or at the end of the list */
323 	TAILQ_INSERT_TAIL(&sensor_tasklist, st, entry);
324 }
325 
326 /*
327  * sysctl glue code
328  */
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);
332 
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");
337 
338 SYSCTL_INT(_hw_sensors, OID_AUTO, dev_idmax, CTLFLAG_RD,
339     &sensordev_idmax, 0, "Max sensor device id");
340 
341 static void
342 sensordev_sysctl_install(struct ksensordev *sensdev)
343 {
344 	struct sysctl_ctx_list *cl = &sensdev->clist;
345 	struct ksensor *s;
346 	struct ksensors_head *sh = &sensdev->sensors_list;
347 
348 	SYSCTL_ASSERT_XLOCKED();
349 
350 	KASSERT(sensdev->oid == NULL,
351 	    ("sensor device %s sysctl node already installed", sensdev->xname));
352 
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;
360 	}
361 
362 	/* Install sysctl nodes for sensors attached to this sensor device */
363 	SLIST_FOREACH(s, sh, list)
364 		sensor_sysctl_install(sensdev, s);
365 }
366 
367 static void
368 sensor_sysctl_install(struct ksensordev *sensdev, struct ksensor *sens)
369 {
370 	char n[32];
371 
372 	SYSCTL_ASSERT_XLOCKED();
373 
374 	if (sensdev->oid == NULL) {
375 		/* Sensor device sysctl node is not installed yet */
376 		return;
377 	}
378 
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));
382 
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", "");
387 }
388 
389 static void
390 sensordev_sysctl_deinstall(struct ksensordev *sensdev)
391 {
392 	SYSCTL_ASSERT_XLOCKED();
393 
394 	if (sensdev->oid != NULL) {
395 		sysctl_ctx_free(&sensdev->clist);
396 		sensdev->oid = NULL;
397 	}
398 }
399 
400 static void
401 sensor_sysctl_deinstall(struct ksensordev *sensdev, struct ksensor *sens)
402 {
403 	SYSCTL_ASSERT_XLOCKED();
404 
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);
408 	}
409 	sens->oid = NULL;
410 }
411 
412 static int
413 sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS)
414 {
415 	struct ksensordev *ksd = arg1;
416 	struct sensordev *usd;
417 	int error;
418 
419 	if (req->newptr)
420 		return (EPERM);
421 
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;
428 
429 	error = SYSCTL_OUT(req, usd, sizeof(struct sensordev));
430 
431 	kfree(usd, M_TEMP);
432 	return (error);
433 }
434 
435 static int
436 sysctl_handle_sensor(SYSCTL_HANDLER_ARGS)
437 {
438 	struct ksensor *ks = arg1;
439 	struct sensor *us;
440 	int error;
441 
442 	if (req->newptr)
443 		return (EPERM);
444 
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;
454 
455 	error = SYSCTL_OUT(req, us, sizeof(struct sensor));
456 
457 	kfree(us, M_TEMP);
458 	return (error);
459 }
460 
461 static int
462 sysctl_sensors_handler(SYSCTL_HANDLER_ARGS)
463 {
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;
470 
471 	if (namelen != 1 && namelen != 3)
472 		return (ENOTDIR);
473 
474 	dev = name[0];
475 	if ((ksd = sensordev_get(dev)) == NULL)
476 		return (ENOENT);
477 
478 	if (namelen == 1)
479 		return (sysctl_handle_sensordev(NULL, ksd, 0, req));
480 
481 	type = name[1];
482 	numt = name[2];
483 
484 	if ((ks = sensor_find(ksd, type, numt)) == NULL)
485 		return (ENOENT);
486 	return (sysctl_handle_sensor(NULL, ks, 0, req));
487 }
488 
489 static void
490 sensor_sysinit(void *arg __unused)
491 {
492 	int error, cpu;
493 
494 	cpu = ncpus - 1; /* stick to the last CPU */
495 	error = kthread_create_cpu(sensor_task_thread, NULL, NULL, cpu,
496 	    "sensors");
497 	if (error)
498 		panic("sensors kthread on cpu%d failed: %d", cpu, error);
499 }
500 SYSINIT(sensor, SI_SUB_PRE_DRIVERS, SI_ORDER_ANY, sensor_sysinit, NULL);
501