sensor: Create task thread through SYSINIT
[dragonfly.git] / sys / kern / kern_sensors.c
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 int
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_NOWAIT);
206         if (st == NULL)
207                 return (1);
208
209         lockmgr(&sensor_task_lock, LK_EXCLUSIVE);
210         st->arg = arg;
211         st->func = func;
212         st->period = period;
213
214         st->running = 1;
215
216         st->nextrun = 0;
217         TAILQ_INSERT_HEAD(&sensor_tasklist, st, entry);
218
219         wakeup(&sensor_tasklist);
220
221         lockmgr(&sensor_task_lock, LK_RELEASE);
222         return (0);
223 }
224
225 void
226 sensor_task_unregister(void *arg)
227 {
228         struct sensor_task      *st;
229
230         lockmgr(&sensor_task_lock, LK_EXCLUSIVE);
231         TAILQ_FOREACH(st, &sensor_tasklist, entry)
232                 if (st->arg == arg)
233                         st->running = 0;
234         lockmgr(&sensor_task_lock, LK_RELEASE);
235 }
236
237 static void
238 sensor_task_thread(void *arg)
239 {
240         struct sensor_task      *st, *nst;
241         time_t                  now;
242
243         lockmgr(&sensor_task_lock, LK_EXCLUSIVE);
244
245         for (;;) {
246                 while (TAILQ_EMPTY(&sensor_tasklist)) {
247                         lksleep(&sensor_tasklist, &sensor_task_lock, 0,
248                             "waittask", 0);
249                 }
250
251                 while ((nst = TAILQ_FIRST(&sensor_tasklist))->nextrun >
252                     (now = time_uptime)) {
253                         lksleep(&sensor_tasklist, &sensor_task_lock, 0,
254                             "timeout", (nst->nextrun - now) * hz);
255                 }
256
257                 while ((st = nst) != NULL) {
258                         nst = TAILQ_NEXT(st, entry);
259
260                         if (st->nextrun > now)
261                                 break;
262
263                         /* take it out while we work on it */
264                         TAILQ_REMOVE(&sensor_tasklist, st, entry);
265
266                         if (!st->running) {
267                                 kfree(st, M_DEVBUF);
268                                 continue;
269                         }
270
271                         /* run the task */
272                         st->func(st->arg);
273                         /* stick it back in the tasklist */
274                         sensor_task_schedule(st);
275                 }
276         }
277
278         lockmgr(&sensor_task_lock, LK_RELEASE);
279 }
280
281 static void
282 sensor_task_schedule(struct sensor_task *st)
283 {
284         struct sensor_task      *cst;
285
286         lockmgr(&sensor_task_lock, LK_EXCLUSIVE);
287         st->nextrun = time_uptime + st->period;
288
289         TAILQ_FOREACH(cst, &sensor_tasklist, entry) {
290                 if (cst->nextrun > st->nextrun) {
291                         TAILQ_INSERT_BEFORE(cst, st, entry);
292                         lockmgr(&sensor_task_lock, LK_RELEASE);
293                         return;
294                 }
295         }
296
297         /* must be an empty list, or at the end of the list */
298         TAILQ_INSERT_TAIL(&sensor_tasklist, st, entry);
299         lockmgr(&sensor_task_lock, LK_RELEASE);
300 }
301
302 /*
303  * sysctl glue code
304  */
305 static int      sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS);
306 static int      sysctl_handle_sensor(SYSCTL_HANDLER_ARGS);
307 static int      sysctl_sensors_handler(SYSCTL_HANDLER_ARGS);
308
309 SYSCTL_NODE(_hw, OID_AUTO, sensors, CTLFLAG_RD, NULL,
310     "Hardware Sensors sysctl internal magic");
311 SYSCTL_NODE(_hw, HW_SENSORS, _sensors, CTLFLAG_RD, sysctl_sensors_handler,
312     "Hardware Sensors XP MIB interface");
313
314 static void
315 sensor_sysctl_install(struct ksensordev *sensdev)
316 {
317         struct sysctl_oid_list *ol;     
318         struct sysctl_ctx_list *cl = &sensdev->clist;
319         struct ksensor *s;
320         struct ksensors_head *sh = &sensdev->sensors_list;
321
322         sysctl_ctx_init(cl);
323         ol = SYSCTL_CHILDREN(SYSCTL_ADD_NODE(cl, (&SYSCTL_NODE_CHILDREN(_hw,
324             sensors)), sensdev->num, sensdev->xname, CTLFLAG_RD, NULL, ""));
325         SLIST_FOREACH(s, sh, list) {
326                 char n[32];
327
328                 ksnprintf(n, sizeof(n), "%s%d", sensor_type_s[s->type], s->numt);
329                 SYSCTL_ADD_PROC(cl, ol, OID_AUTO, n, CTLTYPE_STRUCT |
330                     CTLFLAG_RD, s, 0, sysctl_handle_sensor, "S,sensor", "");
331         }
332 }
333
334 static void
335 sensor_sysctl_deinstall(struct ksensordev *sensdev)
336 {
337         struct sysctl_ctx_list *cl = &sensdev->clist;
338
339         sysctl_ctx_free(cl);
340 }
341
342 static int
343 sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS)
344 {
345         struct ksensordev *ksd = arg1;
346         struct sensordev *usd;
347         int error;
348
349         if (req->newptr)
350                 return (EPERM);
351
352         /* Grab a copy, to clear the kernel pointers */
353         usd = kmalloc(sizeof(*usd), M_TEMP, M_WAITOK | M_ZERO);
354         usd->num = ksd->num;
355         strlcpy(usd->xname, ksd->xname, sizeof(usd->xname));
356         memcpy(usd->maxnumt, ksd->maxnumt, sizeof(usd->maxnumt));
357         usd->sensors_count = ksd->sensors_count;
358
359         error = SYSCTL_OUT(req, usd, sizeof(struct sensordev));
360
361         kfree(usd, M_TEMP);
362         return (error);
363
364 }
365
366 static int
367 sysctl_handle_sensor(SYSCTL_HANDLER_ARGS)
368 {
369         struct ksensor *ks = arg1;
370         struct sensor *us;
371         int error;
372
373         if (req->newptr)
374                 return (EPERM);
375
376         /* Grab a copy, to clear the kernel pointers */
377         us = kmalloc(sizeof(*us), M_TEMP, M_WAITOK | M_ZERO);
378         memcpy(us->desc, ks->desc, sizeof(ks->desc));
379         us->tv = ks->tv;
380         us->value = ks->value;
381         us->type = ks->type;
382         us->status = ks->status;
383         us->numt = ks->numt;
384         us->flags = ks->flags;
385
386         error = SYSCTL_OUT(req, us, sizeof(struct sensor));
387
388         kfree(us, M_TEMP);
389         return (error);
390 }
391
392 static int
393 sysctl_sensors_handler(SYSCTL_HANDLER_ARGS)
394 {
395         int *name = arg1;
396         u_int namelen = arg2;
397         struct ksensordev *ksd;
398         struct ksensor *ks;
399         int dev, numt;
400         enum sensor_type type;
401
402         if (namelen != 1 && namelen != 3)
403                 return (ENOTDIR);
404
405         dev = name[0];
406         if ((ksd = sensordev_get(dev)) == NULL)
407                 return (ENOENT);
408
409         if (namelen == 1)
410                 return (sysctl_handle_sensordev(NULL, ksd, 0, req));
411
412         type = name[1];
413         numt = name[2];
414
415         if ((ks = sensor_find(ksd, type, numt)) == NULL)
416                 return (ENOENT);
417         return (sysctl_handle_sensor(NULL, ks, 0, req));
418 }
419
420 static void
421 sensor_sysinit(void *arg __unused)
422 {
423         int error;
424
425         error = kthread_create(sensor_task_thread, NULL, NULL, "sensors");
426         if (error)
427                 panic("sensors kthread failed: %d", error);
428 }
429 SYSINIT(sensor, SI_SUB_PRE_DRIVERS, SI_ORDER_ANY, sensor_sysinit, NULL);