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