xref: /openbsd-src/sys/kern/kern_sensors.c (revision bb73aa1fdb99f9c13dafd6c05444e4da51333f7e)
1 /*	$OpenBSD: kern_sensors.c,v 1.9 2006/05/27 23:51:27 mk 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 
28 #include <sys/sensors.h>
29 #include "hotplug.h"
30 
31 int			sensors_count = 0;
32 SLIST_HEAD(, sensor)	sensors_list = SLIST_HEAD_INITIALIZER(&sensors_list);
33 
34 struct sensor_task {
35 	void				*arg;
36 	void				(*func)(void *);
37 
38 	int				period;
39 	time_t				nextrun;
40 	volatile int			running;
41 	TAILQ_ENTRY(sensor_task)	entry;
42 };
43 
44 void	sensor_task_create(void *);
45 void	sensor_task_thread(void *);
46 void	sensor_task_schedule(struct sensor_task *);
47 
48 TAILQ_HEAD(, sensor_task) tasklist = TAILQ_HEAD_INITIALIZER(tasklist);
49 
50 void
51 sensor_add(struct sensor *sens)
52 {
53 	struct sensor *v, *nv;
54 	int s;
55 
56 	s = splhigh();
57 	if (sensors_count == 0) {
58 		sens->num = 0;
59 		SLIST_INSERT_HEAD(&sensors_list, sens, list);
60 	} else {
61 		for (v = SLIST_FIRST(&sensors_list);
62 		    (nv = SLIST_NEXT(v, list)) != NULL; v = nv)
63 			if (nv->num - v->num > 1)
64 				break;
65 		sens->num = v->num + 1;
66 		SLIST_INSERT_AFTER(v, sens, list);
67 	}
68 	sensors_count++;
69 	splx(s);
70 
71 #if NHOTPLUG > 0
72 	hotplug_device_attach(DV_SENSOR, sens->device);
73 #endif
74 }
75 
76 void
77 sensor_del(struct sensor *sens)
78 {
79 	int s;
80 
81 	s = splhigh();
82 	sensors_count--;
83 	SLIST_REMOVE(&sensors_list, sens, sensor, list);
84 	splx(s);
85 
86 #if NHOTPLUG > 0
87 	hotplug_device_detach(DV_SENSOR, sens->device);
88 #endif
89 }
90 
91 struct sensor *
92 sensor_get(int num)
93 {
94 	struct sensor *s;
95 
96 	SLIST_FOREACH(s, &sensors_list, list) {
97 		if (s->num == num)
98 			return (s);
99 	}
100 
101 	return (NULL);
102 }
103 
104 int
105 sensor_task_register(void *arg, void (*func)(void *), int period)
106 {
107 	struct sensor_task	*st;
108 
109 	st = malloc(sizeof(struct sensor_task), M_DEVBUF, M_NOWAIT);
110 	if (st == NULL)
111 		return (1);
112 
113 	st->arg = arg;
114 	st->func = func;
115 	st->period = period;
116 
117 	st->running = 1;
118 
119 	if (TAILQ_EMPTY(&tasklist))
120 		kthread_create_deferred(sensor_task_create, NULL);
121 
122 	sensor_task_schedule(st);
123 	wakeup(&tasklist);
124 
125 	return (0);
126 }
127 
128 void
129 sensor_task_unregister(void *arg)
130 {
131 	struct sensor_task	*st;
132 
133 	TAILQ_FOREACH(st, &tasklist, entry) {
134 		if (st->arg == arg)
135 			st->running = 0;
136 	}
137 }
138 
139 void
140 sensor_task_create(void *arg)
141 {
142 	if (kthread_create(sensor_task_thread, NULL, NULL, "sensors") != 0)
143 		panic("sensors kthread");
144 }
145 
146 void
147 sensor_task_thread(void *arg)
148 {
149 	struct sensor_task	*st, *nst;
150 	time_t			now;
151 
152 	while (!TAILQ_EMPTY(&tasklist)) {
153 		while ((nst = TAILQ_FIRST(&tasklist))->nextrun >
154 		    (now = time_uptime))
155 			tsleep(&tasklist, PWAIT, "timeout",
156 			    (nst->nextrun - now) * hz);
157 
158 		while ((st = nst) != NULL) {
159 			nst = TAILQ_NEXT(st, entry);
160 
161 			if (st->nextrun > now)
162 				break;
163 
164 			/* take it out while we work on it */
165 			TAILQ_REMOVE(&tasklist, st, entry);
166 
167 			if (!st->running) {
168 				free(st, M_DEVBUF);
169 				continue;
170 			}
171 
172 			/* run the task */
173 			st->func(st->arg);
174 			/* stick it back in the tasklist */
175 			sensor_task_schedule(st);
176 		}
177 	}
178 
179 	kthread_exit(0);
180 }
181 
182 void
183 sensor_task_schedule(struct sensor_task *st)
184 {
185 	struct sensor_task 	*cst;
186 
187 	st->nextrun = time_uptime + st->period;
188 
189 	TAILQ_FOREACH(cst, &tasklist, entry) {
190 		if (cst->nextrun > st->nextrun) {
191 			TAILQ_INSERT_BEFORE(cst, st, entry);
192 			return;
193 		}
194 	}
195 
196 	/* must be an empty list, or at the end of the list */
197 	TAILQ_INSERT_TAIL(&tasklist, st, entry);
198 }
199 
200