xref: /dflybsd-src/sys/kern/kern_sensors.c (revision c00956260d2704c17e71363516aa1070c5e4e4e8)
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 struct spinlock	sensor_dev_lock =
40     SPINLOCK_INITIALIZER(sensor_dev_lock, "sensor_dev_lock");
41 
42 static int		sensordev_count;
43 static SLIST_HEAD(, ksensordev) sensordev_list =
44     SLIST_HEAD_INITIALIZER(sensordev_list);
45 
46 static struct ksensordev *sensordev_get(int);
47 static struct ksensor	*sensor_find(struct ksensordev *, enum sensor_type,
48 			    int);
49 
50 struct sensor_task {
51 	void				*arg;
52 	void				(*func)(void *);
53 
54 	int				period;
55 	time_t				nextrun;	/* time_uptime */
56 	int				running;
57 	TAILQ_ENTRY(sensor_task)	entry;
58 };
59 
60 static void		sensor_task_thread(void *);
61 static void		sensor_task_schedule(struct sensor_task *);
62 
63 static TAILQ_HEAD(, sensor_task) sensor_tasklist =
64     TAILQ_HEAD_INITIALIZER(sensor_tasklist);
65 
66 static struct lock	sensor_task_lock =
67     LOCK_INITIALIZER("ksensor_task", 0, LK_CANRECURSE);
68 
69 static void		sensor_sysctl_install(struct ksensordev *);
70 static void		sensor_sysctl_deinstall(struct ksensordev *);
71 
72 void
73 sensordev_install(struct ksensordev *sensdev)
74 {
75 	struct ksensordev *v, *nv;
76 
77 	/* mtx_lock(&Giant); */
78 	spin_lock(&sensor_dev_lock);
79 	if (sensordev_count == 0) {
80 		sensdev->num = 0;
81 		SLIST_INSERT_HEAD(&sensordev_list, sensdev, list);
82 	} else {
83 		for (v = SLIST_FIRST(&sensordev_list);
84 		    (nv = SLIST_NEXT(v, list)) != NULL; v = nv)
85 			if (nv->num - v->num > 1)
86 				break;
87 		sensdev->num = v->num + 1;
88 		SLIST_INSERT_AFTER(v, sensdev, list);
89 	}
90 	sensordev_count++;
91 	/* mtx_unlock(&Giant); */
92 	spin_unlock(&sensor_dev_lock);
93 
94 	sensor_sysctl_install(sensdev);
95 }
96 
97 void
98 sensor_attach(struct ksensordev *sensdev, struct ksensor *sens)
99 {
100 	struct ksensor *v, *nv;
101 	struct ksensors_head *sh;
102 	int i;
103 
104 	/* mtx_lock(&Giant); */
105 	spin_lock(&sensor_dev_lock);
106 	sh = &sensdev->sensors_list;
107 	if (sensdev->sensors_count == 0) {
108 		for (i = 0; i < SENSOR_MAX_TYPES; i++)
109 			sensdev->maxnumt[i] = 0;
110 		sens->numt = 0;
111 		SLIST_INSERT_HEAD(sh, sens, list);
112 	} else {
113 		for (v = SLIST_FIRST(sh);
114 		    (nv = SLIST_NEXT(v, list)) != NULL; v = nv)
115 			if (v->type == sens->type && (v->type != nv->type ||
116 			    (v->type == nv->type && nv->numt - v->numt > 1)))
117 				break;
118 		/* sensors of the same type go after each other */
119 		if (v->type == sens->type)
120 			sens->numt = v->numt + 1;
121 		else
122 			sens->numt = 0;
123 		SLIST_INSERT_AFTER(v, sens, list);
124 	}
125 	/* we only increment maxnumt[] if the sensor was added
126 	 * to the last position of sensors of this type
127 	 */
128 	if (sensdev->maxnumt[sens->type] == sens->numt)
129 		sensdev->maxnumt[sens->type]++;
130 	sensdev->sensors_count++;
131 	spin_unlock(&sensor_dev_lock);
132 	/* mtx_unlock(&Giant); */
133 }
134 
135 void
136 sensordev_deinstall(struct ksensordev *sensdev)
137 {
138 	/* mtx_lock(&Giant); */
139 	spin_lock(&sensor_dev_lock);
140 	sensordev_count--;
141 	SLIST_REMOVE(&sensordev_list, sensdev, ksensordev, list);
142 	/* mtx_unlock(&Giant); */
143 	spin_unlock(&sensor_dev_lock);
144 
145 	sensor_sysctl_deinstall(sensdev);
146 }
147 
148 void
149 sensor_detach(struct ksensordev *sensdev, struct ksensor *sens)
150 {
151 	struct ksensors_head *sh;
152 
153 	/* mtx_lock(&Giant); */
154 	sh = &sensdev->sensors_list;
155 	sensdev->sensors_count--;
156 	SLIST_REMOVE(sh, sens, ksensor, list);
157 	/* we only decrement maxnumt[] if this is the tail
158 	 * sensor of this type
159 	 */
160 	if (sens->numt == sensdev->maxnumt[sens->type] - 1)
161 		sensdev->maxnumt[sens->type]--;
162 	/* mtx_unlock(&Giant); */
163 }
164 
165 static struct ksensordev *
166 sensordev_get(int num)
167 {
168 	struct ksensordev *sd;
169 
170 	spin_lock(&sensor_dev_lock);
171 	SLIST_FOREACH(sd, &sensordev_list, list)
172 		if (sd->num == num) {
173 			spin_unlock(&sensor_dev_lock);
174 			return (sd);
175 		}
176 
177 	spin_unlock(&sensor_dev_lock);
178 	return (NULL);
179 }
180 
181 static struct ksensor *
182 sensor_find(struct ksensordev *sensdev, enum sensor_type type, int numt)
183 {
184 	struct ksensor *s;
185 	struct ksensors_head *sh;
186 
187 	spin_lock(&sensor_dev_lock);
188 	sh = &sensdev->sensors_list;
189 	SLIST_FOREACH(s, sh, list) {
190 		if (s->type == type && s->numt == numt) {
191 			spin_unlock(&sensor_dev_lock);
192 			return (s);
193 		}
194 	}
195 
196 	spin_unlock(&sensor_dev_lock);
197 	return (NULL);
198 }
199 
200 void
201 sensor_task_register(void *arg, void (*func)(void *), int period)
202 {
203 	struct sensor_task	*st;
204 
205 	st = kmalloc(sizeof(struct sensor_task), M_DEVBUF, M_WAITOK);
206 
207 	lockmgr(&sensor_task_lock, LK_EXCLUSIVE);
208 	st->arg = arg;
209 	st->func = func;
210 	st->period = period;
211 
212 	st->running = 1;
213 
214 	st->nextrun = 0;
215 	TAILQ_INSERT_HEAD(&sensor_tasklist, st, entry);
216 
217 	wakeup(&sensor_tasklist);
218 
219 	lockmgr(&sensor_task_lock, LK_RELEASE);
220 }
221 
222 void
223 sensor_task_unregister(void *arg)
224 {
225 	struct sensor_task	*st;
226 
227 	lockmgr(&sensor_task_lock, LK_EXCLUSIVE);
228 	TAILQ_FOREACH(st, &sensor_tasklist, entry)
229 		if (st->arg == arg)
230 			st->running = 0;
231 	lockmgr(&sensor_task_lock, LK_RELEASE);
232 }
233 
234 static void
235 sensor_task_thread(void *arg)
236 {
237 	struct sensor_task	*st, *nst;
238 	time_t			now;
239 
240 	lockmgr(&sensor_task_lock, LK_EXCLUSIVE);
241 
242 	for (;;) {
243 		while (TAILQ_EMPTY(&sensor_tasklist)) {
244 			lksleep(&sensor_tasklist, &sensor_task_lock, 0,
245 			    "waittask", 0);
246 		}
247 
248 		while ((nst = TAILQ_FIRST(&sensor_tasklist))->nextrun >
249 		    (now = time_uptime)) {
250 			lksleep(&sensor_tasklist, &sensor_task_lock, 0,
251 			    "timeout", (nst->nextrun - now) * hz);
252 		}
253 
254 		while ((st = nst) != NULL) {
255 			nst = TAILQ_NEXT(st, entry);
256 
257 			if (st->nextrun > now)
258 				break;
259 
260 			/* take it out while we work on it */
261 			TAILQ_REMOVE(&sensor_tasklist, st, entry);
262 
263 			if (!st->running) {
264 				kfree(st, M_DEVBUF);
265 				continue;
266 			}
267 
268 			/* run the task */
269 			st->func(st->arg);
270 			/* stick it back in the tasklist */
271 			sensor_task_schedule(st);
272 		}
273 	}
274 
275 	lockmgr(&sensor_task_lock, LK_RELEASE);
276 }
277 
278 static void
279 sensor_task_schedule(struct sensor_task *st)
280 {
281 	struct sensor_task 	*cst;
282 
283 	lockmgr(&sensor_task_lock, LK_EXCLUSIVE);
284 	st->nextrun = time_uptime + st->period;
285 
286 	TAILQ_FOREACH(cst, &sensor_tasklist, entry) {
287 		if (cst->nextrun > st->nextrun) {
288 			TAILQ_INSERT_BEFORE(cst, st, entry);
289 			lockmgr(&sensor_task_lock, LK_RELEASE);
290 			return;
291 		}
292 	}
293 
294 	/* must be an empty list, or at the end of the list */
295 	TAILQ_INSERT_TAIL(&sensor_tasklist, st, entry);
296 	lockmgr(&sensor_task_lock, LK_RELEASE);
297 }
298 
299 /*
300  * sysctl glue code
301  */
302 static int	sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS);
303 static int	sysctl_handle_sensor(SYSCTL_HANDLER_ARGS);
304 static int	sysctl_sensors_handler(SYSCTL_HANDLER_ARGS);
305 
306 SYSCTL_NODE(_hw, OID_AUTO, sensors, CTLFLAG_RD, NULL,
307     "Hardware Sensors sysctl internal magic");
308 SYSCTL_NODE(_hw, HW_SENSORS, _sensors, CTLFLAG_RD, sysctl_sensors_handler,
309     "Hardware Sensors XP MIB interface");
310 
311 static void
312 sensor_sysctl_install(struct ksensordev *sensdev)
313 {
314 	struct sysctl_oid_list *ol;
315 	struct sysctl_ctx_list *cl = &sensdev->clist;
316 	struct ksensor *s;
317 	struct ksensors_head *sh = &sensdev->sensors_list;
318 
319 	sysctl_ctx_init(cl);
320 	ol = SYSCTL_CHILDREN(SYSCTL_ADD_NODE(cl, (&SYSCTL_NODE_CHILDREN(_hw,
321 	    sensors)), sensdev->num, sensdev->xname, CTLFLAG_RD, NULL, ""));
322 	SLIST_FOREACH(s, sh, list) {
323 		char n[32];
324 
325 		ksnprintf(n, sizeof(n), "%s%d", sensor_type_s[s->type], s->numt);
326 		SYSCTL_ADD_PROC(cl, ol, OID_AUTO, n, CTLTYPE_STRUCT |
327 		    CTLFLAG_RD, s, 0, sysctl_handle_sensor, "S,sensor", "");
328 	}
329 }
330 
331 static void
332 sensor_sysctl_deinstall(struct ksensordev *sensdev)
333 {
334 	struct sysctl_ctx_list *cl = &sensdev->clist;
335 
336 	sysctl_ctx_free(cl);
337 }
338 
339 static int
340 sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS)
341 {
342 	struct ksensordev *ksd = arg1;
343 	struct sensordev *usd;
344 	int error;
345 
346 	if (req->newptr)
347 		return (EPERM);
348 
349 	/* Grab a copy, to clear the kernel pointers */
350 	usd = kmalloc(sizeof(*usd), M_TEMP, M_WAITOK | M_ZERO);
351 	usd->num = ksd->num;
352 	strlcpy(usd->xname, ksd->xname, sizeof(usd->xname));
353 	memcpy(usd->maxnumt, ksd->maxnumt, sizeof(usd->maxnumt));
354 	usd->sensors_count = ksd->sensors_count;
355 
356 	error = SYSCTL_OUT(req, usd, sizeof(struct sensordev));
357 
358 	kfree(usd, M_TEMP);
359 	return (error);
360 
361 }
362 
363 static int
364 sysctl_handle_sensor(SYSCTL_HANDLER_ARGS)
365 {
366 	struct ksensor *ks = arg1;
367 	struct sensor *us;
368 	int error;
369 
370 	if (req->newptr)
371 		return (EPERM);
372 
373 	/* Grab a copy, to clear the kernel pointers */
374 	us = kmalloc(sizeof(*us), M_TEMP, M_WAITOK | M_ZERO);
375 	memcpy(us->desc, ks->desc, sizeof(ks->desc));
376 	us->tv = ks->tv;
377 	us->value = ks->value;
378 	us->type = ks->type;
379 	us->status = ks->status;
380 	us->numt = ks->numt;
381 	us->flags = ks->flags;
382 
383 	error = SYSCTL_OUT(req, us, sizeof(struct sensor));
384 
385 	kfree(us, M_TEMP);
386 	return (error);
387 }
388 
389 static int
390 sysctl_sensors_handler(SYSCTL_HANDLER_ARGS)
391 {
392 	int *name = arg1;
393 	u_int namelen = arg2;
394 	struct ksensordev *ksd;
395 	struct ksensor *ks;
396 	int dev, numt;
397 	enum sensor_type type;
398 
399 	if (namelen != 1 && namelen != 3)
400 		return (ENOTDIR);
401 
402 	dev = name[0];
403 	if ((ksd = sensordev_get(dev)) == NULL)
404 		return (ENOENT);
405 
406 	if (namelen == 1)
407 		return (sysctl_handle_sensordev(NULL, ksd, 0, req));
408 
409 	type = name[1];
410 	numt = name[2];
411 
412 	if ((ks = sensor_find(ksd, type, numt)) == NULL)
413 		return (ENOENT);
414 	return (sysctl_handle_sensor(NULL, ks, 0, req));
415 }
416 
417 static void
418 sensor_sysinit(void *arg __unused)
419 {
420 	int error;
421 
422 	error = kthread_create(sensor_task_thread, NULL, NULL, "sensors");
423 	if (error)
424 		panic("sensors kthread failed: %d", error);
425 }
426 SYSINIT(sensor, SI_SUB_PRE_DRIVERS, SI_ORDER_ANY, sensor_sysinit, NULL);
427