Fix kthread_create() in kern_sensors.c.
[dragonfly.git] / sys / kern / kern_sensors.c
CommitLineData
eb3a3472 1/* $OpenBSD: kern_sensors.c,v 1.19 2007/06/04 18:42:05 deraadt Exp $ */
eb3a3472
HT
2
3/*
4 * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
5 * Copyright (c) 2006 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
eb3a3472
HT
20#include <sys/param.h>
21#include <sys/systm.h>
22#include <sys/kernel.h>
23#include <sys/malloc.h>
24#include <sys/kthread.h>
25#include <sys/queue.h>
26#include <sys/types.h>
27#include <sys/time.h>
28#include <sys/lock.h>
29
30#include <sys/sysctl.h>
31#include <sys/sensors.h>
32
33int sensordev_count = 0;
34SLIST_HEAD(, ksensordev) sensordev_list = SLIST_HEAD_INITIALIZER(sensordev_list);
35
36struct ksensordev *sensordev_get(int);
37struct ksensor *sensor_find(struct ksensordev *, enum sensor_type, int);
38
39struct sensor_task {
40 void *arg;
41 void (*func)(void *);
42
43 int period;
44 time_t nextrun;
45 volatile int running;
46 TAILQ_ENTRY(sensor_task) entry;
47};
48
49void sensor_task_thread(void *);
50void sensor_task_schedule(struct sensor_task *);
51
52TAILQ_HEAD(, sensor_task) tasklist = TAILQ_HEAD_INITIALIZER(tasklist);
53
54#ifndef NOSYSCTL8HACK
55void sensor_sysctl8magic_install(struct ksensordev *);
56void sensor_sysctl8magic_deinstall(struct ksensordev *);
57#endif
58
59void
60sensordev_install(struct ksensordev *sensdev)
61{
62 struct ksensordev *v, *nv;
63
64 /* mtx_lock(&Giant); */
65 if (sensordev_count == 0) {
66 sensdev->num = 0;
67 SLIST_INSERT_HEAD(&sensordev_list, sensdev, list);
68 } else {
69 for (v = SLIST_FIRST(&sensordev_list);
70 (nv = SLIST_NEXT(v, list)) != NULL; v = nv)
71 if (nv->num - v->num > 1)
72 break;
73 sensdev->num = v->num + 1;
74 SLIST_INSERT_AFTER(v, sensdev, list);
75 }
76 sensordev_count++;
77 /* mtx_unlock(&Giant); */
78
79#ifndef NOSYSCTL8HACK
80 sensor_sysctl8magic_install(sensdev);
81#endif
82}
83
84void
85sensor_attach(struct ksensordev *sensdev, struct ksensor *sens)
86{
87 struct ksensor *v, *nv;
88 struct ksensors_head *sh;
89 int i;
90
91 /* mtx_lock(&Giant); */
92 sh = &sensdev->sensors_list;
93 if (sensdev->sensors_count == 0) {
94 for (i = 0; i < SENSOR_MAX_TYPES; i++)
95 sensdev->maxnumt[i] = 0;
96 sens->numt = 0;
97 SLIST_INSERT_HEAD(sh, sens, list);
98 } else {
99 for (v = SLIST_FIRST(sh);
100 (nv = SLIST_NEXT(v, list)) != NULL; v = nv)
101 if (v->type == sens->type && (v->type != nv->type ||
102 (v->type == nv->type && nv->numt - v->numt > 1)))
103 break;
104 /* sensors of the same type go after each other */
105 if (v->type == sens->type)
106 sens->numt = v->numt + 1;
107 else
108 sens->numt = 0;
109 SLIST_INSERT_AFTER(v, sens, list);
110 }
111 /* we only increment maxnumt[] if the sensor was added
112 * to the last position of sensors of this type
113 */
114 if (sensdev->maxnumt[sens->type] == sens->numt)
115 sensdev->maxnumt[sens->type]++;
116 sensdev->sensors_count++;
117 /* mtx_unlock(&Giant); */
118}
119
120void
121sensordev_deinstall(struct ksensordev *sensdev)
122{
123 /* mtx_lock(&Giant); */
124 sensordev_count--;
125 SLIST_REMOVE(&sensordev_list, sensdev, ksensordev, list);
126 /* mtx_unlock(&Giant); */
127
128#ifndef NOSYSCTL8HACK
129 sensor_sysctl8magic_deinstall(sensdev);
130#endif
131}
132
133void
134sensor_detach(struct ksensordev *sensdev, struct ksensor *sens)
135{
136 struct ksensors_head *sh;
137
138 /* mtx_lock(&Giant); */
139 sh = &sensdev->sensors_list;
140 sensdev->sensors_count--;
141 SLIST_REMOVE(sh, sens, ksensor, list);
142 /* we only decrement maxnumt[] if this is the tail
143 * sensor of this type
144 */
145 if (sens->numt == sensdev->maxnumt[sens->type] - 1)
146 sensdev->maxnumt[sens->type]--;
147 /* mtx_unlock(&Giant); */
148}
149
150struct ksensordev *
151sensordev_get(int num)
152{
153 struct ksensordev *sd;
154
155 SLIST_FOREACH(sd, &sensordev_list, list)
156 if (sd->num == num)
157 return (sd);
158
159 return (NULL);
160}
161
162struct ksensor *
163sensor_find(struct ksensordev *sensdev, enum sensor_type type, int numt)
164{
165 struct ksensor *s;
166 struct ksensors_head *sh;
167
168 sh = &sensdev->sensors_list;
169 SLIST_FOREACH(s, sh, list)
170 if (s->type == type && s->numt == numt)
171 return (s);
172
173 return (NULL);
174}
175
176int
177sensor_task_register(void *arg, void (*func)(void *), int period)
178{
179 struct sensor_task *st;
180 int create_thread = 0;
181
182 st = kmalloc(sizeof(struct sensor_task), M_DEVBUF, M_NOWAIT);
183 if (st == NULL)
184 return (1);
185
186 st->arg = arg;
187 st->func = func;
188 st->period = period;
189
190 st->running = 1;
191
192 if (TAILQ_EMPTY(&tasklist))
193 create_thread = 1;
194
195 st->nextrun = 0;
196 TAILQ_INSERT_HEAD(&tasklist, st, entry);
197
198 if (create_thread)
b56d7db6 199 if (kthread_create(sensor_task_thread, NULL, NULL,
eb3a3472
HT
200 "sensors") != 0)
201 panic("sensors kthread");
202
203 wakeup(&tasklist);
204
205 return (0);
206}
207
208void
209sensor_task_unregister(void *arg)
210{
211 struct sensor_task *st;
212
213 TAILQ_FOREACH(st, &tasklist, entry)
214 if (st->arg == arg)
215 st->running = 0;
216}
217
218void
219sensor_task_thread(void *arg)
220{
221 struct sensor_task *st, *nst;
222 time_t now;
223
224 while (!TAILQ_EMPTY(&tasklist)) {
225 while ((nst = TAILQ_FIRST(&tasklist))->nextrun >
226 (now = time_second))
227 tsleep(&tasklist, 0, "timeout",
228 (nst->nextrun - now) * hz);
229
230 while ((st = nst) != NULL) {
231 nst = TAILQ_NEXT(st, entry);
232
233 if (st->nextrun > now)
234 break;
235
236 /* take it out while we work on it */
237 TAILQ_REMOVE(&tasklist, st, entry);
238
239 if (!st->running) {
240 kfree(st, M_DEVBUF);
241 continue;
242 }
243
244 /* run the task */
245 st->func(st->arg);
246 /* stick it back in the tasklist */
247 sensor_task_schedule(st);
248 }
249 }
250
251 kthread_exit();
252}
253
254void
255sensor_task_schedule(struct sensor_task *st)
256{
257 struct sensor_task *cst;
258
259 st->nextrun = time_second + st->period;
260
261 TAILQ_FOREACH(cst, &tasklist, entry) {
262 if (cst->nextrun > st->nextrun) {
263 TAILQ_INSERT_BEFORE(cst, st, entry);
264 return;
265 }
266 }
267
268 /* must be an empty list, or at the end of the list */
269 TAILQ_INSERT_TAIL(&tasklist, st, entry);
270}
271
272/*
273 * sysctl glue code
274 */
275int sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS);
276int sysctl_handle_sensor(SYSCTL_HANDLER_ARGS);
277int sysctl_sensors_handler(SYSCTL_HANDLER_ARGS);
278
279#ifndef NOSYSCTL8HACK
280
281SYSCTL_NODE(_hw, OID_AUTO, sensors, CTLFLAG_RD, NULL,
282 "Hardware Sensors sysctl internal magic");
283SYSCTL_NODE(_hw, HW_SENSORS, _sensors, CTLFLAG_RD, sysctl_sensors_handler,
284 "Hardware Sensors XP MIB interface");
285
286#else /* NOSYSCTL8HACK */
287
288SYSCTL_NODE(_hw, HW_SENSORS, sensors, CTLFLAG_RD, sysctl_sensors_handler,
289 "Hardware Sensors");
290int sensors_debug = 1;
291SYSCTL_INT(_hw_sensors, OID_AUTO, debug, CTLFLAG_RD, &sensors_debug, 0, "sensors debug");
292
293#endif /* !NOSYSCTL8HACK */
294
295
296#ifndef NOSYSCTL8HACK
297
298/*
299 * XXX:
300 * FreeBSD's sysctl(9) .oid_handler functionality is not accustomed
301 * for the CTLTYPE_NODE handler to handle the undocumented sysctl
302 * magic calls. As soon as such functionality is developed,
303 * sysctl_sensors_handler() should be converted to handle all such
304 * calls, and these sysctl_add_oid(9) calls should be removed
305 * "with a big axe". This whole sysctl_add_oid(9) business is solely
306 * to please sysctl(8).
307 */
308
309void
310sensor_sysctl8magic_install(struct ksensordev *sensdev)
311{
312 struct sysctl_oid_list *ol;
313 struct sysctl_ctx_list *cl = &sensdev->clist;
314 struct ksensor *s;
315 struct ksensors_head *sh = &sensdev->sensors_list;
316
317 sysctl_ctx_init(cl);
318 ol = SYSCTL_CHILDREN(SYSCTL_ADD_NODE(cl, (&SYSCTL_NODE_CHILDREN(_hw,
319 sensors)), sensdev->num, sensdev->xname, CTLFLAG_RD, NULL, ""));
320 SLIST_FOREACH(s, sh, list) {
321 char n[32];
322
323 ksnprintf(n, sizeof(n), "%s%d", sensor_type_s[s->type], s->numt);
324 SYSCTL_ADD_PROC(cl, ol, OID_AUTO, n, CTLTYPE_STRUCT |
325 CTLFLAG_RD, s, 0, sysctl_handle_sensor, "S,sensor", "");
326 }
327}
328
329void
330sensor_sysctl8magic_deinstall(struct ksensordev *sensdev)
331{
332 struct sysctl_ctx_list *cl = &sensdev->clist;
333
334 sysctl_ctx_free(cl);
335}
336
337#endif /* !NOSYSCTL8HACK */
338
339
340int
341sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS)
342{
343 struct ksensordev *ksd = arg1;
344 struct sensordev *usd;
345 int error;
346
347 if (req->newptr)
348 return (EPERM);
349
350 /* Grab a copy, to clear the kernel pointers */
e7b4468c 351 usd = kmalloc(sizeof(*usd), M_TEMP, M_WAITOK | M_ZERO);
eb3a3472
HT
352 usd->num = ksd->num;
353 strlcpy(usd->xname, ksd->xname, sizeof(usd->xname));
354 memcpy(usd->maxnumt, ksd->maxnumt, sizeof(usd->maxnumt));
355 usd->sensors_count = ksd->sensors_count;
356
357 error = SYSCTL_OUT(req, usd, sizeof(struct sensordev));
358
359 kfree(usd, M_TEMP);
360 return (error);
361
362}
363
364int
365sysctl_handle_sensor(SYSCTL_HANDLER_ARGS)
366{
367 struct ksensor *ks = arg1;
368 struct sensor *us;
369 int error;
370
371 if (req->newptr)
372 return (EPERM);
373
374 /* Grab a copy, to clear the kernel pointers */
e7b4468c 375 us = kmalloc(sizeof(*us), M_TEMP, M_WAITOK | M_ZERO);
eb3a3472
HT
376 memcpy(us->desc, ks->desc, sizeof(ks->desc));
377 us->tv = ks->tv;
378 us->value = ks->value;
379 us->type = ks->type;
380 us->status = ks->status;
381 us->numt = ks->numt;
382 us->flags = ks->flags;
383
384 error = SYSCTL_OUT(req, us, sizeof(struct sensor));
385
386 kfree(us, M_TEMP);
387 return (error);
388}
389
390int
391sysctl_sensors_handler(SYSCTL_HANDLER_ARGS)
392{
393 int *name = arg1;
394 u_int namelen = arg2;
395 struct ksensordev *ksd;
396 struct ksensor *ks;
397 int dev, numt;
398 enum sensor_type type;
399
400 if (namelen != 1 && namelen != 3)
401 return (ENOTDIR);
402
403 dev = name[0];
404 if ((ksd = sensordev_get(dev)) == NULL)
405 return (ENOENT);
406
407 if (namelen == 1)
408 return (sysctl_handle_sensordev(NULL, ksd, 0, req));
409
410 type = name[1];
411 numt = name[2];
412
413 if ((ks = sensor_find(ksd, type, numt)) == NULL)
414 return (ENOENT);
415 return (sysctl_handle_sensor(NULL, ks, 0, req));
416}