1 /* $OpenBSD: kern_sensors.c,v 1.19 2007/06/04 18:42:05 deraadt Exp $ */
4 * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
5 * Copyright (c) 2006 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru>
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.
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.
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>
30 #include <sys/sysctl.h>
31 #include <sys/sensors.h>
33 int sensordev_count
= 0;
34 SLIST_HEAD(, ksensordev
) sensordev_list
= SLIST_HEAD_INITIALIZER(sensordev_list
);
36 struct ksensordev
*sensordev_get(int);
37 struct ksensor
*sensor_find(struct ksensordev
*, enum sensor_type
, int);
46 TAILQ_ENTRY(sensor_task
) entry
;
49 void sensor_task_thread(void *);
50 void sensor_task_schedule(struct sensor_task
*);
52 TAILQ_HEAD(, sensor_task
) tasklist
= TAILQ_HEAD_INITIALIZER(tasklist
);
55 void sensor_sysctl8magic_install(struct ksensordev
*);
56 void sensor_sysctl8magic_deinstall(struct ksensordev
*);
60 sensordev_install(struct ksensordev
*sensdev
)
62 struct ksensordev
*v
, *nv
;
64 /* mtx_lock(&Giant); */
65 if (sensordev_count
== 0) {
67 SLIST_INSERT_HEAD(&sensordev_list
, sensdev
, list
);
69 for (v
= SLIST_FIRST(&sensordev_list
);
70 (nv
= SLIST_NEXT(v
, list
)) != NULL
; v
= nv
)
71 if (nv
->num
- v
->num
> 1)
73 sensdev
->num
= v
->num
+ 1;
74 SLIST_INSERT_AFTER(v
, sensdev
, list
);
77 /* mtx_unlock(&Giant); */
80 sensor_sysctl8magic_install(sensdev
);
85 sensor_attach(struct ksensordev
*sensdev
, struct ksensor
*sens
)
87 struct ksensor
*v
, *nv
;
88 struct ksensors_head
*sh
;
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;
97 SLIST_INSERT_HEAD(sh
, sens
, list
);
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)))
104 /* sensors of the same type go after each other */
105 if (v
->type
== sens
->type
)
106 sens
->numt
= v
->numt
+ 1;
109 SLIST_INSERT_AFTER(v
, sens
, list
);
111 /* we only increment maxnumt[] if the sensor was added
112 * to the last position of sensors of this type
114 if (sensdev
->maxnumt
[sens
->type
] == sens
->numt
)
115 sensdev
->maxnumt
[sens
->type
]++;
116 sensdev
->sensors_count
++;
117 /* mtx_unlock(&Giant); */
121 sensordev_deinstall(struct ksensordev
*sensdev
)
123 /* mtx_lock(&Giant); */
125 SLIST_REMOVE(&sensordev_list
, sensdev
, ksensordev
, list
);
126 /* mtx_unlock(&Giant); */
128 #ifndef NOSYSCTL8HACK
129 sensor_sysctl8magic_deinstall(sensdev
);
134 sensor_detach(struct ksensordev
*sensdev
, struct ksensor
*sens
)
136 struct ksensors_head
*sh
;
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
145 if (sens
->numt
== sensdev
->maxnumt
[sens
->type
] - 1)
146 sensdev
->maxnumt
[sens
->type
]--;
147 /* mtx_unlock(&Giant); */
151 sensordev_get(int num
)
153 struct ksensordev
*sd
;
155 SLIST_FOREACH(sd
, &sensordev_list
, list
)
163 sensor_find(struct ksensordev
*sensdev
, enum sensor_type type
, int numt
)
166 struct ksensors_head
*sh
;
168 sh
= &sensdev
->sensors_list
;
169 SLIST_FOREACH(s
, sh
, list
)
170 if (s
->type
== type
&& s
->numt
== numt
)
177 sensor_task_register(void *arg
, void (*func
)(void *), int period
)
179 struct sensor_task
*st
;
180 int create_thread
= 0;
182 st
= kmalloc(sizeof(struct sensor_task
), M_DEVBUF
, M_NOWAIT
);
192 if (TAILQ_EMPTY(&tasklist
))
196 TAILQ_INSERT_HEAD(&tasklist
, st
, entry
);
199 if (kthread_create(sensor_task_thread
, NULL
, NULL
, 0, 0,
201 panic("sensors kthread");
209 sensor_task_unregister(void *arg
)
211 struct sensor_task
*st
;
213 TAILQ_FOREACH(st
, &tasklist
, entry
)
219 sensor_task_thread(void *arg
)
221 struct sensor_task
*st
, *nst
;
224 while (!TAILQ_EMPTY(&tasklist
)) {
225 while ((nst
= TAILQ_FIRST(&tasklist
))->nextrun
>
227 tsleep(&tasklist
, 0, "timeout",
228 (nst
->nextrun
- now
) * hz
);
230 while ((st
= nst
) != NULL
) {
231 nst
= TAILQ_NEXT(st
, entry
);
233 if (st
->nextrun
> now
)
236 /* take it out while we work on it */
237 TAILQ_REMOVE(&tasklist
, st
, entry
);
246 /* stick it back in the tasklist */
247 sensor_task_schedule(st
);
255 sensor_task_schedule(struct sensor_task
*st
)
257 struct sensor_task
*cst
;
259 st
->nextrun
= time_second
+ st
->period
;
261 TAILQ_FOREACH(cst
, &tasklist
, entry
) {
262 if (cst
->nextrun
> st
->nextrun
) {
263 TAILQ_INSERT_BEFORE(cst
, st
, entry
);
268 /* must be an empty list, or at the end of the list */
269 TAILQ_INSERT_TAIL(&tasklist
, st
, entry
);
275 int sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS
);
276 int sysctl_handle_sensor(SYSCTL_HANDLER_ARGS
);
277 int sysctl_sensors_handler(SYSCTL_HANDLER_ARGS
);
279 #ifndef NOSYSCTL8HACK
281 SYSCTL_NODE(_hw
, OID_AUTO
, sensors
, CTLFLAG_RD
, NULL
,
282 "Hardware Sensors sysctl internal magic");
283 SYSCTL_NODE(_hw
, HW_SENSORS
, _sensors
, CTLFLAG_RD
, sysctl_sensors_handler
,
284 "Hardware Sensors XP MIB interface");
286 #else /* NOSYSCTL8HACK */
288 SYSCTL_NODE(_hw
, HW_SENSORS
, sensors
, CTLFLAG_RD
, sysctl_sensors_handler
,
290 int sensors_debug
= 1;
291 SYSCTL_INT(_hw_sensors
, OID_AUTO
, debug
, CTLFLAG_RD
, &sensors_debug
, 0, "sensors debug");
293 #endif /* !NOSYSCTL8HACK */
296 #ifndef NOSYSCTL8HACK
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).
310 sensor_sysctl8magic_install(struct ksensordev
*sensdev
)
312 struct sysctl_oid_list
*ol
;
313 struct sysctl_ctx_list
*cl
= &sensdev
->clist
;
315 struct ksensors_head
*sh
= &sensdev
->sensors_list
;
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
) {
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", "");
330 sensor_sysctl8magic_deinstall(struct ksensordev
*sensdev
)
332 struct sysctl_ctx_list
*cl
= &sensdev
->clist
;
337 #endif /* !NOSYSCTL8HACK */
341 sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS
)
343 struct ksensordev
*ksd
= arg1
;
344 struct sensordev
*usd
;
350 /* Grab a copy, to clear the kernel pointers */
351 usd
= kmalloc(sizeof(*usd
), M_TEMP
, M_WAITOK
| M_ZERO
);
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
;
357 error
= SYSCTL_OUT(req
, usd
, sizeof(struct sensordev
));
365 sysctl_handle_sensor(SYSCTL_HANDLER_ARGS
)
367 struct ksensor
*ks
= arg1
;
374 /* Grab a copy, to clear the kernel pointers */
375 us
= kmalloc(sizeof(*us
), M_TEMP
, M_WAITOK
| M_ZERO
);
376 memcpy(us
->desc
, ks
->desc
, sizeof(ks
->desc
));
378 us
->value
= ks
->value
;
380 us
->status
= ks
->status
;
382 us
->flags
= ks
->flags
;
384 error
= SYSCTL_OUT(req
, us
, sizeof(struct sensor
));
391 sysctl_sensors_handler(SYSCTL_HANDLER_ARGS
)
394 u_int namelen
= arg2
;
395 struct ksensordev
*ksd
;
398 enum sensor_type type
;
400 if (namelen
!= 1 && namelen
!= 3)
404 if ((ksd
= sensordev_get(dev
)) == NULL
)
408 return (sysctl_handle_sensordev(NULL
, ksd
, 0, req
));
413 if ((ks
= sensor_find(ksd
, type
, numt
)) == NULL
)
415 return (sysctl_handle_sensor(NULL
, ks
, 0, req
));