xref: /openbsd-src/sys/kern/kern_sensors.c (revision 04652f9ac20972e6b8cc12170810b5ec9a426975)
1 /*	$OpenBSD: kern_sensors.c,v 1.10 2006/05/28 00:24:00 henning Exp $	*/
2 
3 /*
4  * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/kernel.h>
22 #include <sys/malloc.h>
23 #include <sys/kthread.h>
24 #include <sys/queue.h>
25 #include <sys/types.h>
26 #include <sys/time.h>
27 #include <sys/hotplug.h>
28 
29 #include <sys/sensors.h>
30 #include "hotplug.h"
31 
32 int			sensors_count = 0;
33 SLIST_HEAD(, sensor)	sensors_list = SLIST_HEAD_INITIALIZER(&sensors_list);
34 
35 struct sensor_task {
36 	void				*arg;
37 	void				(*func)(void *);
38 
39 	int				period;
40 	time_t				nextrun;
41 	volatile int			running;
42 	TAILQ_ENTRY(sensor_task)	entry;
43 };
44 
45 void	sensor_task_create(void *);
46 void	sensor_task_thread(void *);
47 void	sensor_task_schedule(struct sensor_task *);
48 
49 TAILQ_HEAD(, sensor_task) tasklist = TAILQ_HEAD_INITIALIZER(tasklist);
50 
51 void
52 sensor_add(struct sensor *sens)
53 {
54 	struct sensor *v, *nv;
55 	int s;
56 
57 	s = splhigh();
58 	if (sensors_count == 0) {
59 		sens->num = 0;
60 		SLIST_INSERT_HEAD(&sensors_list, sens, list);
61 	} else {
62 		for (v = SLIST_FIRST(&sensors_list);
63 		    (nv = SLIST_NEXT(v, list)) != NULL; v = nv)
64 			if (nv->num - v->num > 1)
65 				break;
66 		sens->num = v->num + 1;
67 		SLIST_INSERT_AFTER(v, sens, list);
68 	}
69 	sensors_count++;
70 	splx(s);
71 
72 #if NHOTPLUG > 0
73 	hotplug_device_attach(DV_SENSOR, sens->device);
74 #endif
75 }
76 
77 void
78 sensor_del(struct sensor *sens)
79 {
80 	int s;
81 
82 	s = splhigh();
83 	sensors_count--;
84 	SLIST_REMOVE(&sensors_list, sens, sensor, list);
85 	splx(s);
86 
87 #if NHOTPLUG > 0
88 	hotplug_device_detach(DV_SENSOR, sens->device);
89 #endif
90 }
91 
92 struct sensor *
93 sensor_get(int num)
94 {
95 	struct sensor *s;
96 
97 	SLIST_FOREACH(s, &sensors_list, list) {
98 		if (s->num == num)
99 			return (s);
100 	}
101 
102 	return (NULL);
103 }
104 
105 int
106 sensor_task_register(void *arg, void (*func)(void *), int period)
107 {
108 	struct sensor_task	*st;
109 
110 	st = malloc(sizeof(struct sensor_task), M_DEVBUF, M_NOWAIT);
111 	if (st == NULL)
112 		return (1);
113 
114 	st->arg = arg;
115 	st->func = func;
116 	st->period = period;
117 
118 	st->running = 1;
119 
120 	if (TAILQ_EMPTY(&tasklist))
121 		kthread_create_deferred(sensor_task_create, NULL);
122 
123 	sensor_task_schedule(st);
124 	wakeup(&tasklist);
125 
126 	return (0);
127 }
128 
129 void
130 sensor_task_unregister(void *arg)
131 {
132 	struct sensor_task	*st;
133 
134 	TAILQ_FOREACH(st, &tasklist, entry) {
135 		if (st->arg == arg)
136 			st->running = 0;
137 	}
138 }
139 
140 void
141 sensor_task_create(void *arg)
142 {
143 	if (kthread_create(sensor_task_thread, NULL, NULL, "sensors") != 0)
144 		panic("sensors kthread");
145 }
146 
147 void
148 sensor_task_thread(void *arg)
149 {
150 	struct sensor_task	*st, *nst;
151 	time_t			now;
152 
153 	while (!TAILQ_EMPTY(&tasklist)) {
154 		while ((nst = TAILQ_FIRST(&tasklist))->nextrun >
155 		    (now = time_uptime))
156 			tsleep(&tasklist, PWAIT, "timeout",
157 			    (nst->nextrun - now) * hz);
158 
159 		while ((st = nst) != NULL) {
160 			nst = TAILQ_NEXT(st, entry);
161 
162 			if (st->nextrun > now)
163 				break;
164 
165 			/* take it out while we work on it */
166 			TAILQ_REMOVE(&tasklist, st, entry);
167 
168 			if (!st->running) {
169 				free(st, M_DEVBUF);
170 				continue;
171 			}
172 
173 			/* run the task */
174 			st->func(st->arg);
175 			/* stick it back in the tasklist */
176 			sensor_task_schedule(st);
177 		}
178 	}
179 
180 	kthread_exit(0);
181 }
182 
183 void
184 sensor_task_schedule(struct sensor_task *st)
185 {
186 	struct sensor_task 	*cst;
187 
188 	st->nextrun = time_uptime + st->period;
189 
190 	TAILQ_FOREACH(cst, &tasklist, entry) {
191 		if (cst->nextrun > st->nextrun) {
192 			TAILQ_INSERT_BEFORE(cst, st, entry);
193 			return;
194 		}
195 	}
196 
197 	/* must be an empty list, or at the end of the list */
198 	TAILQ_INSERT_TAIL(&tasklist, st, entry);
199 }
200 
201