1 /* $OpenBSD: kern_sensors.c,v 1.39 2019/12/19 17:40:11 mpi 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 sensordev_install(struct ksensordev *sensdev) 41 { 42 struct ksensordev *v, *nv; 43 int s; 44 45 s = splhigh(); 46 if (sensordev_count == 0) { 47 sensdev->num = 0; 48 SLIST_INSERT_HEAD(&sensordev_list, sensdev, list); 49 } else { 50 for (v = SLIST_FIRST(&sensordev_list); 51 (nv = SLIST_NEXT(v, list)) != NULL; v = nv) 52 if (nv->num - v->num > 1) 53 break; 54 sensdev->num = v->num + 1; 55 SLIST_INSERT_AFTER(v, sensdev, list); 56 } 57 sensordev_count++; 58 splx(s); 59 60 #if NHOTPLUG > 0 61 hotplug_device_attach(DV_DULL, "sensordev"); 62 #endif 63 } 64 65 void 66 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 s = splhigh(); 73 sh = &sensdev->sensors_list; 74 if (sensdev->sensors_count == 0) { 75 for (i = 0; i < SENSOR_MAX_TYPES; i++) 76 sensdev->maxnumt[i] = 0; 77 sens->numt = 0; 78 SLIST_INSERT_HEAD(sh, sens, list); 79 } else { 80 for (v = SLIST_FIRST(sh); 81 (nv = SLIST_NEXT(v, list)) != NULL; v = nv) 82 if (v->type == sens->type && (v->type != nv->type || 83 (v->type == nv->type && nv->numt - v->numt > 1))) 84 break; 85 /* sensors of the same type go after each other */ 86 if (v->type == sens->type) 87 sens->numt = v->numt + 1; 88 else 89 sens->numt = 0; 90 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 if (sensdev->maxnumt[sens->type] == sens->numt) 96 sensdev->maxnumt[sens->type]++; 97 sensdev->sensors_count++; 98 splx(s); 99 } 100 101 void 102 sensordev_deinstall(struct ksensordev *sensdev) 103 { 104 int s; 105 106 s = splhigh(); 107 sensordev_count--; 108 SLIST_REMOVE(&sensordev_list, sensdev, ksensordev, list); 109 splx(s); 110 111 #if NHOTPLUG > 0 112 hotplug_device_detach(DV_DULL, "sensordev"); 113 #endif 114 } 115 116 void 117 sensor_detach(struct ksensordev *sensdev, struct ksensor *sens) 118 { 119 struct ksensors_head *sh; 120 int s; 121 122 s = splhigh(); 123 sh = &sensdev->sensors_list; 124 sensdev->sensors_count--; 125 SLIST_REMOVE(sh, sens, ksensor, list); 126 /* we only decrement maxnumt[] if this is the tail 127 * sensor of this type 128 */ 129 if (sens->numt == sensdev->maxnumt[sens->type] - 1) 130 sensdev->maxnumt[sens->type]--; 131 splx(s); 132 } 133 134 int 135 sensordev_get(int num, struct ksensordev **sensdev) 136 { 137 struct ksensordev *sd; 138 139 SLIST_FOREACH(sd, &sensordev_list, list) { 140 if (sd->num == num) { 141 *sensdev = sd; 142 return (0); 143 } 144 if (sd->num > num) 145 return (ENXIO); 146 } 147 return (ENOENT); 148 } 149 150 int 151 sensor_find(int dev, enum sensor_type type, int numt, struct ksensor **ksensorp) 152 { 153 struct ksensor *s; 154 struct ksensordev *sensdev; 155 struct ksensors_head *sh; 156 int ret; 157 158 ret = sensordev_get(dev, &sensdev); 159 if (ret) 160 return (ret); 161 162 sh = &sensdev->sensors_list; 163 SLIST_FOREACH(s, sh, list) 164 if (s->type == type && s->numt == numt) { 165 *ksensorp = s; 166 return (0); 167 } 168 169 return (ENOENT); 170 } 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 sensor_task_register(void *arg, void (*func)(void *), unsigned int period) 187 { 188 struct sensor_task *st; 189 190 #ifdef DIAGNOSTIC 191 if (period == 0) 192 panic("sensor_task_register: period is 0"); 193 #endif 194 195 if (sensors_taskq == NULL && 196 (sensors_taskq = taskq_create("sensors", 1, IPL_HIGH, 0)) == NULL) 197 sensors_taskq = systq; 198 199 st = malloc(sizeof(*st), M_DEVBUF, M_NOWAIT); 200 if (st == NULL) 201 return (NULL); 202 203 st->func = func; 204 st->arg = arg; 205 st->period = period; 206 timeout_set(&st->timeout, sensor_task_tick, st); 207 task_set(&st->task, sensor_task_work, st); 208 rw_init(&st->lock, "sensor"); 209 210 sensor_task_tick(st); 211 212 return (st); 213 } 214 215 void 216 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 rw_enter_write(&st->lock); 226 st->period = 0; 227 rw_exit_write(&st->lock); 228 } 229 230 void 231 sensor_task_tick(void *arg) 232 { 233 struct sensor_task *st = arg; 234 task_add(sensors_taskq, &st->task); 235 } 236 237 static int sensors_quiesced; 238 static int sensors_running; 239 240 void 241 sensor_quiesce(void) 242 { 243 sensors_quiesced = 1; 244 while (sensors_running > 0) 245 tsleep_nsec(&sensors_running, PZERO, "sensorpause", INFSLP); 246 247 } 248 void 249 sensor_restart(void) 250 { 251 sensors_quiesced = 0; 252 } 253 254 void 255 sensor_task_work(void *xst) 256 { 257 struct sensor_task *st = xst; 258 unsigned int period = 0; 259 260 atomic_inc_int(&sensors_running); 261 rw_enter_write(&st->lock); 262 period = st->period; 263 if (period > 0 && !sensors_quiesced) 264 st->func(st->arg); 265 rw_exit_write(&st->lock); 266 if (atomic_dec_int_nv(&sensors_running) == 0) { 267 if (sensors_quiesced) 268 wakeup(&sensors_running); 269 } 270 271 if (period == 0) 272 free(st, M_DEVBUF, sizeof(*st)); 273 else 274 timeout_add_sec(&st->timeout, period); 275 } 276