sensor: Remove the NOSYSCTL8HACK ifndef test
[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 lock      sensor_task_lock =
40     LOCK_INITIALIZER("ksensor_task", 0, LK_CANRECURSE);
41 static struct spinlock  sensor_dev_lock =
42     SPINLOCK_INITIALIZER(sensor_dev_lock, "sensor_dev_lock");
43
44 static int              sensordev_count;
45 static SLIST_HEAD(, ksensordev) sensordev_list =
46     SLIST_HEAD_INITIALIZER(sensordev_list);
47
48 static struct ksensordev *sensordev_get(int);
49 static struct ksensor   *sensor_find(struct ksensordev *, enum sensor_type,
50                             int);
51
52 struct sensor_task {
53         void                            *arg;
54         void                            (*func)(void *);
55
56         int                             period;
57         time_t                          nextrun;        /* time_uptime */
58         int                             running;
59         TAILQ_ENTRY(sensor_task)        entry;
60 };
61
62 static void             sensor_task_thread(void *);
63 static void             sensor_task_schedule(struct sensor_task *);
64
65 static TAILQ_HEAD(, sensor_task) sensor_tasklist =
66     TAILQ_HEAD_INITIALIZER(sensor_tasklist);
67
68 static void             sensor_sysctl8magic_install(struct ksensordev *);
69 static void             sensor_sysctl8magic_deinstall(struct ksensordev *);
70
71 void
72 sensordev_install(struct ksensordev *sensdev)
73 {
74         struct ksensordev *v, *nv;
75
76         /* mtx_lock(&Giant); */
77         spin_lock(&sensor_dev_lock);
78         if (sensordev_count == 0) {
79                 sensdev->num = 0;
80                 SLIST_INSERT_HEAD(&sensordev_list, sensdev, list);
81         } else {
82                 for (v = SLIST_FIRST(&sensordev_list);
83                     (nv = SLIST_NEXT(v, list)) != NULL; v = nv)
84                         if (nv->num - v->num > 1)
85                                 break;
86                 sensdev->num = v->num + 1;
87                 SLIST_INSERT_AFTER(v, sensdev, list);
88         }
89         sensordev_count++;
90         /* mtx_unlock(&Giant); */
91         spin_unlock(&sensor_dev_lock);
92
93         sensor_sysctl8magic_install(sensdev);
94 }
95
96 void
97 sensor_attach(struct ksensordev *sensdev, struct ksensor *sens)
98 {
99         struct ksensor *v, *nv;
100         struct ksensors_head *sh;
101         int i;
102
103         /* mtx_lock(&Giant); */
104         spin_lock(&sensor_dev_lock);
105         sh = &sensdev->sensors_list;
106         if (sensdev->sensors_count == 0) {
107                 for (i = 0; i < SENSOR_MAX_TYPES; i++)
108                         sensdev->maxnumt[i] = 0;
109                 sens->numt = 0;
110                 SLIST_INSERT_HEAD(sh, sens, list);
111         } else {
112                 for (v = SLIST_FIRST(sh);
113                     (nv = SLIST_NEXT(v, list)) != NULL; v = nv)
114                         if (v->type == sens->type && (v->type != nv->type || 
115                             (v->type == nv->type && nv->numt - v->numt > 1)))
116                                 break;
117                 /* sensors of the same type go after each other */
118                 if (v->type == sens->type)
119                         sens->numt = v->numt + 1;
120                 else
121                         sens->numt = 0;
122                 SLIST_INSERT_AFTER(v, sens, list);
123         }
124         /* we only increment maxnumt[] if the sensor was added
125          * to the last position of sensors of this type
126          */
127         if (sensdev->maxnumt[sens->type] == sens->numt)
128                 sensdev->maxnumt[sens->type]++;
129         sensdev->sensors_count++;
130         spin_unlock(&sensor_dev_lock);
131         /* mtx_unlock(&Giant); */
132 }
133
134 void
135 sensordev_deinstall(struct ksensordev *sensdev)
136 {
137         /* mtx_lock(&Giant); */
138         spin_lock(&sensor_dev_lock);
139         sensordev_count--;
140         SLIST_REMOVE(&sensordev_list, sensdev, ksensordev, list);
141         /* mtx_unlock(&Giant); */
142         spin_unlock(&sensor_dev_lock);
143
144         sensor_sysctl8magic_deinstall(sensdev);
145 }
146
147 void
148 sensor_detach(struct ksensordev *sensdev, struct ksensor *sens)
149 {
150         struct ksensors_head *sh;
151
152         /* mtx_lock(&Giant); */
153         sh = &sensdev->sensors_list;
154         sensdev->sensors_count--;
155         SLIST_REMOVE(sh, sens, ksensor, list);
156         /* we only decrement maxnumt[] if this is the tail 
157          * sensor of this type
158          */
159         if (sens->numt == sensdev->maxnumt[sens->type] - 1)
160                 sensdev->maxnumt[sens->type]--;
161         /* mtx_unlock(&Giant); */
162 }
163
164 static struct ksensordev *
165 sensordev_get(int num)
166 {
167         struct ksensordev *sd;
168
169         spin_lock(&sensor_dev_lock);
170         SLIST_FOREACH(sd, &sensordev_list, list)
171                 if (sd->num == num) {
172                         spin_unlock(&sensor_dev_lock);
173                         return (sd);
174                 }
175
176         spin_unlock(&sensor_dev_lock);
177         return (NULL);
178 }
179
180 static struct ksensor *
181 sensor_find(struct ksensordev *sensdev, enum sensor_type type, int numt)
182 {
183         struct ksensor *s;
184         struct ksensors_head *sh;
185
186         spin_lock(&sensor_dev_lock);
187         sh = &sensdev->sensors_list;
188         SLIST_FOREACH(s, sh, list) {
189                 if (s->type == type && s->numt == numt) {
190                         spin_unlock(&sensor_dev_lock);
191                         return (s);
192                 }
193         }
194
195         spin_unlock(&sensor_dev_lock);
196         return (NULL);
197 }
198
199 int
200 sensor_task_register(void *arg, void (*func)(void *), int period)
201 {
202         struct sensor_task      *st;
203         int                      create_thread = 0;
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         if (TAILQ_EMPTY(&sensor_tasklist))
217                 create_thread = 1;
218
219         st->nextrun = 0;
220         TAILQ_INSERT_HEAD(&sensor_tasklist, st, entry);
221
222         if (create_thread)
223                 if (kthread_create(sensor_task_thread, NULL, NULL,
224                     "sensors") != 0)
225                         panic("sensors kthread");
226         
227         wakeup(&sensor_tasklist);
228
229         lockmgr(&sensor_task_lock, LK_RELEASE);
230         return (0);
231 }
232
233 void
234 sensor_task_unregister(void *arg)
235 {
236         struct sensor_task      *st;
237
238         lockmgr(&sensor_task_lock, LK_EXCLUSIVE);
239         TAILQ_FOREACH(st, &sensor_tasklist, entry)
240                 if (st->arg == arg)
241                         st->running = 0;
242         lockmgr(&sensor_task_lock, LK_RELEASE);
243 }
244
245 static void
246 sensor_task_thread(void *arg)
247 {
248         struct sensor_task      *st, *nst;
249         time_t                  now;
250
251         lockmgr(&sensor_task_lock, LK_EXCLUSIVE);
252
253         while (!TAILQ_EMPTY(&sensor_tasklist)) {
254                 while ((nst = TAILQ_FIRST(&sensor_tasklist))->nextrun >
255                     (now = time_uptime)) {
256                         lksleep(&sensor_tasklist, &sensor_task_lock, 0,
257                             "timeout", (nst->nextrun - now) * hz);
258                 }
259
260                 while ((st = nst) != NULL) {
261                         nst = TAILQ_NEXT(st, entry);
262
263                         if (st->nextrun > now)
264                                 break;
265
266                         /* take it out while we work on it */
267                         TAILQ_REMOVE(&sensor_tasklist, st, entry);
268
269                         if (!st->running) {
270                                 kfree(st, M_DEVBUF);
271                                 continue;
272                         }
273
274                         /* run the task */
275                         st->func(st->arg);
276                         /* stick it back in the tasklist */
277                         sensor_task_schedule(st);
278                 }
279         }
280
281         lockmgr(&sensor_task_lock, LK_RELEASE);
282 }
283
284 static void
285 sensor_task_schedule(struct sensor_task *st)
286 {
287         struct sensor_task      *cst;
288
289         lockmgr(&sensor_task_lock, LK_EXCLUSIVE);
290         st->nextrun = time_uptime + st->period;
291
292         TAILQ_FOREACH(cst, &sensor_tasklist, entry) {
293                 if (cst->nextrun > st->nextrun) {
294                         TAILQ_INSERT_BEFORE(cst, st, entry);
295                         lockmgr(&sensor_task_lock, LK_RELEASE);
296                         return;
297                 }
298         }
299
300         /* must be an empty list, or at the end of the list */
301         TAILQ_INSERT_TAIL(&sensor_tasklist, st, entry);
302         lockmgr(&sensor_task_lock, LK_RELEASE);
303 }
304
305 /*
306  * sysctl glue code
307  */
308 static int      sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS);
309 static int      sysctl_handle_sensor(SYSCTL_HANDLER_ARGS);
310 static int      sysctl_sensors_handler(SYSCTL_HANDLER_ARGS);
311
312 SYSCTL_NODE(_hw, OID_AUTO, sensors, CTLFLAG_RD, NULL,
313     "Hardware Sensors sysctl internal magic");
314 SYSCTL_NODE(_hw, HW_SENSORS, _sensors, CTLFLAG_RD, sysctl_sensors_handler,
315     "Hardware Sensors XP MIB interface");
316
317 /*
318  * XXX:
319  * FreeBSD's sysctl(9) .oid_handler functionality is not accustomed
320  * for the CTLTYPE_NODE handler to handle the undocumented sysctl
321  * magic calls.  As soon as such functionality is developed, 
322  * sysctl_sensors_handler() should be converted to handle all such
323  * calls, and these sysctl_add_oid(9) calls should be removed 
324  * "with a big axe".  This whole sysctl_add_oid(9) business is solely
325  * to please sysctl(8).
326  */
327
328 static void
329 sensor_sysctl8magic_install(struct ksensordev *sensdev)
330 {
331         struct sysctl_oid_list *ol;     
332         struct sysctl_ctx_list *cl = &sensdev->clist;
333         struct ksensor *s;
334         struct ksensors_head *sh = &sensdev->sensors_list;
335
336         sysctl_ctx_init(cl);
337         ol = SYSCTL_CHILDREN(SYSCTL_ADD_NODE(cl, (&SYSCTL_NODE_CHILDREN(_hw,
338             sensors)), sensdev->num, sensdev->xname, CTLFLAG_RD, NULL, ""));
339         SLIST_FOREACH(s, sh, list) {
340                 char n[32];
341
342                 ksnprintf(n, sizeof(n), "%s%d", sensor_type_s[s->type], s->numt);
343                 SYSCTL_ADD_PROC(cl, ol, OID_AUTO, n, CTLTYPE_STRUCT |
344                     CTLFLAG_RD, s, 0, sysctl_handle_sensor, "S,sensor", "");
345         }
346 }
347
348 static void
349 sensor_sysctl8magic_deinstall(struct ksensordev *sensdev)
350 {
351         struct sysctl_ctx_list *cl = &sensdev->clist;
352
353         sysctl_ctx_free(cl);
354 }
355
356 static int
357 sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS)
358 {
359         struct ksensordev *ksd = arg1;
360         struct sensordev *usd;
361         int error;
362
363         if (req->newptr)
364                 return (EPERM);
365
366         /* Grab a copy, to clear the kernel pointers */
367         usd = kmalloc(sizeof(*usd), M_TEMP, M_WAITOK | M_ZERO);
368         usd->num = ksd->num;
369         strlcpy(usd->xname, ksd->xname, sizeof(usd->xname));
370         memcpy(usd->maxnumt, ksd->maxnumt, sizeof(usd->maxnumt));
371         usd->sensors_count = ksd->sensors_count;
372
373         error = SYSCTL_OUT(req, usd, sizeof(struct sensordev));
374
375         kfree(usd, M_TEMP);
376         return (error);
377
378 }
379
380 static int
381 sysctl_handle_sensor(SYSCTL_HANDLER_ARGS)
382 {
383         struct ksensor *ks = arg1;
384         struct sensor *us;
385         int error;
386
387         if (req->newptr)
388                 return (EPERM);
389
390         /* Grab a copy, to clear the kernel pointers */
391         us = kmalloc(sizeof(*us), M_TEMP, M_WAITOK | M_ZERO);
392         memcpy(us->desc, ks->desc, sizeof(ks->desc));
393         us->tv = ks->tv;
394         us->value = ks->value;
395         us->type = ks->type;
396         us->status = ks->status;
397         us->numt = ks->numt;
398         us->flags = ks->flags;
399
400         error = SYSCTL_OUT(req, us, sizeof(struct sensor));
401
402         kfree(us, M_TEMP);
403         return (error);
404 }
405
406 static int
407 sysctl_sensors_handler(SYSCTL_HANDLER_ARGS)
408 {
409         int *name = arg1;
410         u_int namelen = arg2;
411         struct ksensordev *ksd;
412         struct ksensor *ks;
413         int dev, numt;
414         enum sensor_type type;
415
416         if (namelen != 1 && namelen != 3)
417                 return (ENOTDIR);
418
419         dev = name[0];
420         if ((ksd = sensordev_get(dev)) == NULL)
421                 return (ENOENT);
422
423         if (namelen == 1)
424                 return (sysctl_handle_sensordev(NULL, ksd, 0, req));
425
426         type = name[1];
427         numt = name[2];
428
429         if ((ks = sensor_find(ksd, type, numt)) == NULL)
430                 return (ENOENT);
431         return (sysctl_handle_sensor(NULL, ks, 0, req));
432 }