1 /* $OpenBSD: kern_sensors.c,v 1.19 2007/06/04 18:42:05 deraadt Exp $ */
2 /* $DragonFly: src/sys/kern/kern_sensors.c,v 1.2 2008/01/05 14:02:38 swildner Exp $ */
5 * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
6 * Copyright (c) 2006 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru>
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 #include <sys/cdefs.h>
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>
32 #include <sys/sysctl.h>
33 #include <sys/sensors.h>
35 int sensordev_count
= 0;
36 SLIST_HEAD(, ksensordev
) sensordev_list
= SLIST_HEAD_INITIALIZER(sensordev_list
);
38 struct ksensordev
*sensordev_get(int);
39 struct ksensor
*sensor_find(struct ksensordev
*, enum sensor_type
, int);
48 TAILQ_ENTRY(sensor_task
) entry
;
51 void sensor_task_thread(void *);
52 void sensor_task_schedule(struct sensor_task
*);
54 TAILQ_HEAD(, sensor_task
) tasklist
= TAILQ_HEAD_INITIALIZER(tasklist
);
57 void sensor_sysctl8magic_install(struct ksensordev
*);
58 void sensor_sysctl8magic_deinstall(struct ksensordev
*);
62 sensordev_install(struct ksensordev
*sensdev
)
64 struct ksensordev
*v
, *nv
;
66 /* mtx_lock(&Giant); */
67 if (sensordev_count
== 0) {
69 SLIST_INSERT_HEAD(&sensordev_list
, sensdev
, list
);
71 for (v
= SLIST_FIRST(&sensordev_list
);
72 (nv
= SLIST_NEXT(v
, list
)) != NULL
; v
= nv
)
73 if (nv
->num
- v
->num
> 1)
75 sensdev
->num
= v
->num
+ 1;
76 SLIST_INSERT_AFTER(v
, sensdev
, list
);
79 /* mtx_unlock(&Giant); */
82 sensor_sysctl8magic_install(sensdev
);
87 sensor_attach(struct ksensordev
*sensdev
, struct ksensor
*sens
)
89 struct ksensor
*v
, *nv
;
90 struct ksensors_head
*sh
;
93 /* mtx_lock(&Giant); */
94 sh
= &sensdev
->sensors_list
;
95 if (sensdev
->sensors_count
== 0) {
96 for (i
= 0; i
< SENSOR_MAX_TYPES
; i
++)
97 sensdev
->maxnumt
[i
] = 0;
99 SLIST_INSERT_HEAD(sh
, sens
, list
);
101 for (v
= SLIST_FIRST(sh
);
102 (nv
= SLIST_NEXT(v
, list
)) != NULL
; v
= nv
)
103 if (v
->type
== sens
->type
&& (v
->type
!= nv
->type
||
104 (v
->type
== nv
->type
&& nv
->numt
- v
->numt
> 1)))
106 /* sensors of the same type go after each other */
107 if (v
->type
== sens
->type
)
108 sens
->numt
= v
->numt
+ 1;
111 SLIST_INSERT_AFTER(v
, sens
, list
);
113 /* we only increment maxnumt[] if the sensor was added
114 * to the last position of sensors of this type
116 if (sensdev
->maxnumt
[sens
->type
] == sens
->numt
)
117 sensdev
->maxnumt
[sens
->type
]++;
118 sensdev
->sensors_count
++;
119 /* mtx_unlock(&Giant); */
123 sensordev_deinstall(struct ksensordev
*sensdev
)
125 /* mtx_lock(&Giant); */
127 SLIST_REMOVE(&sensordev_list
, sensdev
, ksensordev
, list
);
128 /* mtx_unlock(&Giant); */
130 #ifndef NOSYSCTL8HACK
131 sensor_sysctl8magic_deinstall(sensdev
);
136 sensor_detach(struct ksensordev
*sensdev
, struct ksensor
*sens
)
138 struct ksensors_head
*sh
;
140 /* mtx_lock(&Giant); */
141 sh
= &sensdev
->sensors_list
;
142 sensdev
->sensors_count
--;
143 SLIST_REMOVE(sh
, sens
, ksensor
, list
);
144 /* we only decrement maxnumt[] if this is the tail
145 * sensor of this type
147 if (sens
->numt
== sensdev
->maxnumt
[sens
->type
] - 1)
148 sensdev
->maxnumt
[sens
->type
]--;
149 /* mtx_unlock(&Giant); */
153 sensordev_get(int num
)
155 struct ksensordev
*sd
;
157 SLIST_FOREACH(sd
, &sensordev_list
, list
)
165 sensor_find(struct ksensordev
*sensdev
, enum sensor_type type
, int numt
)
168 struct ksensors_head
*sh
;
170 sh
= &sensdev
->sensors_list
;
171 SLIST_FOREACH(s
, sh
, list
)
172 if (s
->type
== type
&& s
->numt
== numt
)
179 sensor_task_register(void *arg
, void (*func
)(void *), int period
)
181 struct sensor_task
*st
;
182 int create_thread
= 0;
184 st
= kmalloc(sizeof(struct sensor_task
), M_DEVBUF
, M_NOWAIT
);
194 if (TAILQ_EMPTY(&tasklist
))
198 TAILQ_INSERT_HEAD(&tasklist
, st
, entry
);
201 if (kthread_create(sensor_task_thread
, NULL
, NULL
, 0, 0,
203 panic("sensors kthread");
211 sensor_task_unregister(void *arg
)
213 struct sensor_task
*st
;
215 TAILQ_FOREACH(st
, &tasklist
, entry
)
221 sensor_task_thread(void *arg
)
223 struct sensor_task
*st
, *nst
;
226 while (!TAILQ_EMPTY(&tasklist
)) {
227 while ((nst
= TAILQ_FIRST(&tasklist
))->nextrun
>
229 tsleep(&tasklist
, 0, "timeout",
230 (nst
->nextrun
- now
) * hz
);
232 while ((st
= nst
) != NULL
) {
233 nst
= TAILQ_NEXT(st
, entry
);
235 if (st
->nextrun
> now
)
238 /* take it out while we work on it */
239 TAILQ_REMOVE(&tasklist
, st
, entry
);
248 /* stick it back in the tasklist */
249 sensor_task_schedule(st
);
257 sensor_task_schedule(struct sensor_task
*st
)
259 struct sensor_task
*cst
;
261 st
->nextrun
= time_second
+ st
->period
;
263 TAILQ_FOREACH(cst
, &tasklist
, entry
) {
264 if (cst
->nextrun
> st
->nextrun
) {
265 TAILQ_INSERT_BEFORE(cst
, st
, entry
);
270 /* must be an empty list, or at the end of the list */
271 TAILQ_INSERT_TAIL(&tasklist
, st
, entry
);
277 int sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS
);
278 int sysctl_handle_sensor(SYSCTL_HANDLER_ARGS
);
279 int sysctl_sensors_handler(SYSCTL_HANDLER_ARGS
);
281 #ifndef NOSYSCTL8HACK
283 SYSCTL_NODE(_hw
, OID_AUTO
, sensors
, CTLFLAG_RD
, NULL
,
284 "Hardware Sensors sysctl internal magic");
285 SYSCTL_NODE(_hw
, HW_SENSORS
, _sensors
, CTLFLAG_RD
, sysctl_sensors_handler
,
286 "Hardware Sensors XP MIB interface");
288 #else /* NOSYSCTL8HACK */
290 SYSCTL_NODE(_hw
, HW_SENSORS
, sensors
, CTLFLAG_RD
, sysctl_sensors_handler
,
292 int sensors_debug
= 1;
293 SYSCTL_INT(_hw_sensors
, OID_AUTO
, debug
, CTLFLAG_RD
, &sensors_debug
, 0, "sensors debug");
295 #endif /* !NOSYSCTL8HACK */
298 #ifndef NOSYSCTL8HACK
302 * FreeBSD's sysctl(9) .oid_handler functionality is not accustomed
303 * for the CTLTYPE_NODE handler to handle the undocumented sysctl
304 * magic calls. As soon as such functionality is developed,
305 * sysctl_sensors_handler() should be converted to handle all such
306 * calls, and these sysctl_add_oid(9) calls should be removed
307 * "with a big axe". This whole sysctl_add_oid(9) business is solely
308 * to please sysctl(8).
312 sensor_sysctl8magic_install(struct ksensordev
*sensdev
)
314 struct sysctl_oid_list
*ol
;
315 struct sysctl_ctx_list
*cl
= &sensdev
->clist
;
317 struct ksensors_head
*sh
= &sensdev
->sensors_list
;
320 ol
= SYSCTL_CHILDREN(SYSCTL_ADD_NODE(cl
, (&SYSCTL_NODE_CHILDREN(_hw
,
321 sensors
)), sensdev
->num
, sensdev
->xname
, CTLFLAG_RD
, NULL
, ""));
322 SLIST_FOREACH(s
, sh
, list
) {
325 ksnprintf(n
, sizeof(n
), "%s%d", sensor_type_s
[s
->type
], s
->numt
);
326 SYSCTL_ADD_PROC(cl
, ol
, OID_AUTO
, n
, CTLTYPE_STRUCT
|
327 CTLFLAG_RD
, s
, 0, sysctl_handle_sensor
, "S,sensor", "");
332 sensor_sysctl8magic_deinstall(struct ksensordev
*sensdev
)
334 struct sysctl_ctx_list
*cl
= &sensdev
->clist
;
339 #endif /* !NOSYSCTL8HACK */
343 sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS
)
345 struct ksensordev
*ksd
= arg1
;
346 struct sensordev
*usd
;
352 /* Grab a copy, to clear the kernel pointers */
353 usd
= kmalloc(sizeof(*usd
), M_TEMP
, M_WAITOK
| M_ZERO
);
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
;
359 error
= SYSCTL_OUT(req
, usd
, sizeof(struct sensordev
));
367 sysctl_handle_sensor(SYSCTL_HANDLER_ARGS
)
369 struct ksensor
*ks
= arg1
;
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
));
380 us
->value
= ks
->value
;
382 us
->status
= ks
->status
;
384 us
->flags
= ks
->flags
;
386 error
= SYSCTL_OUT(req
, us
, sizeof(struct sensor
));
393 sysctl_sensors_handler(SYSCTL_HANDLER_ARGS
)
396 u_int namelen
= arg2
;
397 struct ksensordev
*ksd
;
400 enum sensor_type type
;
402 if (namelen
!= 1 && namelen
!= 3)
406 if ((ksd
= sensordev_get(dev
)) == NULL
)
410 return (sysctl_handle_sensordev(NULL
, ksd
, 0, req
));
415 if ((ks
= sensor_find(ksd
, type
, numt
)) == NULL
)
417 return (sysctl_handle_sensor(NULL
, ks
, 0, req
));