Line data Source code
1 : /* $OpenBSD: kern_sensors.c,v 1.38 2017/04/09 15:47:18 deraadt Exp $ */
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 :
20 : #include <sys/param.h>
21 : #include <sys/systm.h>
22 : #include <sys/malloc.h>
23 : #include <sys/queue.h>
24 : #include <sys/device.h>
25 : #include <sys/hotplug.h>
26 : #include <sys/timeout.h>
27 : #include <sys/task.h>
28 : #include <sys/rwlock.h>
29 : #include <sys/atomic.h>
30 :
31 : #include <sys/sensors.h>
32 : #include "hotplug.h"
33 :
34 : struct taskq *sensors_taskq;
35 : int sensordev_count;
36 : SLIST_HEAD(, ksensordev) sensordev_list =
37 : SLIST_HEAD_INITIALIZER(sensordev_list);
38 :
39 : void
40 0 : sensordev_install(struct ksensordev *sensdev)
41 : {
42 : struct ksensordev *v, *nv;
43 : int s;
44 :
45 0 : s = splhigh();
46 0 : if (sensordev_count == 0) {
47 0 : sensdev->num = 0;
48 0 : SLIST_INSERT_HEAD(&sensordev_list, sensdev, list);
49 0 : } else {
50 0 : for (v = SLIST_FIRST(&sensordev_list);
51 0 : (nv = SLIST_NEXT(v, list)) != NULL; v = nv)
52 0 : if (nv->num - v->num > 1)
53 : break;
54 0 : sensdev->num = v->num + 1;
55 0 : SLIST_INSERT_AFTER(v, sensdev, list);
56 : }
57 0 : sensordev_count++;
58 0 : splx(s);
59 :
60 : #if NHOTPLUG > 0
61 0 : hotplug_device_attach(DV_DULL, "sensordev");
62 : #endif
63 0 : }
64 :
65 : void
66 0 : sensor_attach(struct ksensordev *sensdev, struct ksensor *sens)
67 : {
68 : struct ksensor *v, *nv;
69 : struct ksensors_head *sh;
70 : int s, i;
71 :
72 0 : s = splhigh();
73 0 : sh = &sensdev->sensors_list;
74 0 : if (sensdev->sensors_count == 0) {
75 0 : for (i = 0; i < SENSOR_MAX_TYPES; i++)
76 0 : sensdev->maxnumt[i] = 0;
77 0 : sens->numt = 0;
78 0 : SLIST_INSERT_HEAD(sh, sens, list);
79 0 : } else {
80 0 : for (v = SLIST_FIRST(sh);
81 0 : (nv = SLIST_NEXT(v, list)) != NULL; v = nv)
82 0 : if (v->type == sens->type && (v->type != nv->type ||
83 0 : (v->type == nv->type && nv->numt - v->numt > 1)))
84 : break;
85 : /* sensors of the same type go after each other */
86 0 : if (v->type == sens->type)
87 0 : sens->numt = v->numt + 1;
88 : else
89 0 : sens->numt = 0;
90 0 : SLIST_INSERT_AFTER(v, sens, list);
91 : }
92 : /* we only increment maxnumt[] if the sensor was added
93 : * to the last position of sensors of this type
94 : */
95 0 : if (sensdev->maxnumt[sens->type] == sens->numt)
96 0 : sensdev->maxnumt[sens->type]++;
97 0 : sensdev->sensors_count++;
98 0 : splx(s);
99 0 : }
100 :
101 : void
102 0 : sensordev_deinstall(struct ksensordev *sensdev)
103 : {
104 : int s;
105 :
106 0 : s = splhigh();
107 0 : sensordev_count--;
108 0 : SLIST_REMOVE(&sensordev_list, sensdev, ksensordev, list);
109 0 : splx(s);
110 :
111 : #if NHOTPLUG > 0
112 0 : hotplug_device_detach(DV_DULL, "sensordev");
113 : #endif
114 0 : }
115 :
116 : void
117 0 : sensor_detach(struct ksensordev *sensdev, struct ksensor *sens)
118 : {
119 : struct ksensors_head *sh;
120 : int s;
121 :
122 0 : s = splhigh();
123 0 : sh = &sensdev->sensors_list;
124 0 : sensdev->sensors_count--;
125 0 : SLIST_REMOVE(sh, sens, ksensor, list);
126 : /* we only decrement maxnumt[] if this is the tail
127 : * sensor of this type
128 : */
129 0 : if (sens->numt == sensdev->maxnumt[sens->type] - 1)
130 0 : sensdev->maxnumt[sens->type]--;
131 0 : splx(s);
132 0 : }
133 :
134 : int
135 0 : sensordev_get(int num, struct ksensordev **sensdev)
136 : {
137 : struct ksensordev *sd;
138 :
139 0 : SLIST_FOREACH(sd, &sensordev_list, list) {
140 0 : if (sd->num == num) {
141 0 : *sensdev = sd;
142 0 : return (0);
143 : }
144 0 : if (sd->num > num)
145 0 : return (ENXIO);
146 : }
147 0 : return (ENOENT);
148 0 : }
149 :
150 : int
151 0 : sensor_find(int dev, enum sensor_type type, int numt, struct ksensor **ksensorp)
152 : {
153 : struct ksensor *s;
154 0 : struct ksensordev *sensdev;
155 : struct ksensors_head *sh;
156 : int ret;
157 :
158 0 : ret = sensordev_get(dev, &sensdev);
159 0 : if (ret)
160 0 : return (ret);
161 :
162 0 : sh = &sensdev->sensors_list;
163 0 : SLIST_FOREACH(s, sh, list)
164 0 : if (s->type == type && s->numt == numt) {
165 0 : *ksensorp = s;
166 0 : return (0);
167 : }
168 :
169 0 : return (ENOENT);
170 0 : }
171 :
172 : struct sensor_task {
173 : void (*func)(void *);
174 : void *arg;
175 :
176 : unsigned int period;
177 : struct timeout timeout;
178 : struct task task;
179 : struct rwlock lock;
180 : };
181 :
182 : void sensor_task_tick(void *);
183 : void sensor_task_work(void *);
184 :
185 : struct sensor_task *
186 0 : sensor_task_register(void *arg, void (*func)(void *), unsigned int period)
187 : {
188 : struct sensor_task *st;
189 :
190 : #ifdef DIAGNOSTIC
191 0 : if (period == 0)
192 0 : panic("sensor_task_register: period is 0");
193 : #endif
194 :
195 0 : if (sensors_taskq == NULL &&
196 0 : (sensors_taskq = taskq_create("sensors", 1, IPL_HIGH, 0)) == NULL)
197 0 : sensors_taskq = systq;
198 :
199 0 : st = malloc(sizeof(*st), M_DEVBUF, M_NOWAIT);
200 0 : if (st == NULL)
201 0 : return (NULL);
202 :
203 0 : st->func = func;
204 0 : st->arg = arg;
205 0 : st->period = period;
206 0 : timeout_set(&st->timeout, sensor_task_tick, st);
207 0 : task_set(&st->task, sensor_task_work, st);
208 0 : rw_init(&st->lock, "sensor");
209 :
210 0 : sensor_task_tick(st);
211 :
212 0 : return (st);
213 0 : }
214 :
215 : void
216 0 : sensor_task_unregister(struct sensor_task *st)
217 : {
218 : /*
219 : * we can't reliably timeout_del or task_del because there's a window
220 : * between when they come off the lists and the timeout or task code
221 : * actually runs the respective handlers for them. mark the sensor_task
222 : * as dying by setting period to 0 and let sensor_task_work mop up.
223 : */
224 :
225 0 : rw_enter_write(&st->lock);
226 0 : st->period = 0;
227 0 : rw_exit_write(&st->lock);
228 0 : }
229 :
230 : void
231 0 : sensor_task_tick(void *arg)
232 : {
233 0 : struct sensor_task *st = arg;
234 0 : task_add(sensors_taskq, &st->task);
235 0 : }
236 :
237 : static int sensors_quiesced;
238 : static int sensors_running;
239 :
240 : void
241 0 : sensor_quiesce(void)
242 : {
243 0 : sensors_quiesced = 1;
244 0 : while (sensors_running > 0)
245 0 : tsleep(&sensors_running, PZERO, "sensorpause", 0);
246 :
247 0 : }
248 : void
249 0 : sensor_restart(void)
250 : {
251 0 : sensors_quiesced = 0;
252 0 : }
253 :
254 : void
255 0 : sensor_task_work(void *xst)
256 : {
257 0 : struct sensor_task *st = xst;
258 : unsigned int period = 0;
259 :
260 0 : atomic_inc_int(&sensors_running);
261 0 : rw_enter_write(&st->lock);
262 0 : period = st->period;
263 0 : if (period > 0 && !sensors_quiesced)
264 0 : st->func(st->arg);
265 0 : rw_exit_write(&st->lock);
266 0 : if (atomic_dec_int_nv(&sensors_running) == 0) {
267 0 : if (sensors_quiesced)
268 0 : wakeup(&sensors_running);
269 : }
270 :
271 0 : if (period == 0)
272 0 : free(st, M_DEVBUF, sizeof(*st));
273 : else
274 0 : timeout_add_sec(&st->timeout, period);
275 0 : }
|