1 /* $OpenBSD: kern_sensors.c,v 1.16 2006/12/23 17:41:26 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/kernel.h> 23 #include <sys/malloc.h> 24 #include <sys/kthread.h> 25 #include <sys/queue.h> 26 #include <sys/types.h> 27 #include <sys/time.h> 28 #include <sys/device.h> 29 #include <sys/hotplug.h> 30 31 #include <sys/sensors.h> 32 #include "hotplug.h" 33 34 int sensordev_count = 0; 35 SLIST_HEAD(, sensordev) sensordev_list = SLIST_HEAD_INITIALIZER(sensordev_list); 36 37 struct sensor_task { 38 void *arg; 39 void (*func)(void *); 40 41 int period; 42 time_t nextrun; 43 volatile int running; 44 TAILQ_ENTRY(sensor_task) entry; 45 }; 46 47 void sensor_task_create(void *); 48 void sensor_task_thread(void *); 49 void sensor_task_schedule(struct sensor_task *); 50 51 TAILQ_HEAD(, sensor_task) tasklist = TAILQ_HEAD_INITIALIZER(tasklist); 52 53 void 54 sensordev_install(struct sensordev *sensdev) 55 { 56 struct sensordev *v, *nv; 57 int s; 58 59 s = splhigh(); 60 if (sensordev_count == 0) { 61 sensdev->num = 0; 62 SLIST_INSERT_HEAD(&sensordev_list, sensdev, list); 63 } else { 64 for (v = SLIST_FIRST(&sensordev_list); 65 (nv = SLIST_NEXT(v, list)) != NULL; v = nv) 66 if (nv->num - v->num > 1) 67 break; 68 sensdev->num = v->num + 1; 69 SLIST_INSERT_AFTER(v, sensdev, list); 70 } 71 sensordev_count++; 72 splx(s); 73 74 #if NHOTPLUG > 0 75 hotplug_device_attach(DV_DULL, "sensordev"); 76 #endif 77 } 78 79 void 80 sensor_attach(struct sensordev *sensdev, struct sensor *sens) 81 { 82 struct sensor *v, *nv; 83 struct sensors_head *sh; 84 int s, i; 85 86 s = splhigh(); 87 sh = &sensdev->sensors_list; 88 if (sensdev->sensors_count == 0) { 89 for (i = 0; i < SENSOR_MAX_TYPES; i++) 90 sensdev->maxnumt[i] = 0; 91 sens->numt = 0; 92 SLIST_INSERT_HEAD(sh, sens, list); 93 } else { 94 for (v = SLIST_FIRST(sh); 95 (nv = SLIST_NEXT(v, list)) != NULL; v = nv) 96 if (v->type == sens->type && (v->type != nv->type || 97 (v->type == nv->type && nv->numt - v->numt > 1))) 98 break; 99 /* sensors of the same type go after each other */ 100 if (v->type == sens->type) 101 sens->numt = v->numt + 1; 102 else 103 sens->numt = 0; 104 SLIST_INSERT_AFTER(v, sens, list); 105 } 106 /* we only increment maxnumt[] if the sensor was added 107 * to the last position of sensors of this type 108 */ 109 if (sensdev->maxnumt[sens->type] == sens->numt) 110 sensdev->maxnumt[sens->type]++; 111 sensdev->sensors_count++; 112 splx(s); 113 } 114 115 void 116 sensordev_deinstall(struct sensordev *sensdev) 117 { 118 int s; 119 120 s = splhigh(); 121 sensordev_count--; 122 SLIST_REMOVE(&sensordev_list, sensdev, sensordev, list); 123 splx(s); 124 125 #if NHOTPLUG > 0 126 hotplug_device_detach(DV_DULL, "sensordev"); 127 #endif 128 } 129 130 void 131 sensor_detach(struct sensordev *sensdev, struct sensor *sens) 132 { 133 struct sensors_head *sh; 134 int s; 135 136 s = splhigh(); 137 sh = &sensdev->sensors_list; 138 sensdev->sensors_count--; 139 SLIST_REMOVE(sh, sens, sensor, list); 140 /* we only decrement maxnumt[] if this is the tail 141 * sensor of this type 142 */ 143 if (sens->numt == sensdev->maxnumt[sens->type] - 1) 144 sensdev->maxnumt[sens->type]--; 145 splx(s); 146 } 147 148 struct sensordev * 149 sensordev_get(int num) 150 { 151 struct sensordev *sd; 152 153 SLIST_FOREACH(sd, &sensordev_list, list) 154 if (sd->num == num) 155 return (sd); 156 157 return (NULL); 158 } 159 160 struct sensor * 161 sensor_find(int dev, enum sensor_type type, int numt) 162 { 163 struct sensor *s; 164 struct sensordev *sensdev; 165 struct sensors_head *sh; 166 167 sensdev = sensordev_get(dev); 168 if (sensdev == NULL) 169 return (NULL); 170 171 sh = &sensdev->sensors_list; 172 SLIST_FOREACH(s, sh, list) 173 if (s->type == type && s->numt == numt) 174 return (s); 175 176 return (NULL); 177 } 178 179 int 180 sensor_task_register(void *arg, void (*func)(void *), int period) 181 { 182 struct sensor_task *st; 183 184 st = malloc(sizeof(struct sensor_task), M_DEVBUF, M_NOWAIT); 185 if (st == NULL) 186 return (1); 187 188 st->arg = arg; 189 st->func = func; 190 st->period = period; 191 192 st->running = 1; 193 194 if (TAILQ_EMPTY(&tasklist)) 195 kthread_create_deferred(sensor_task_create, NULL); 196 197 st->nextrun = 0; 198 TAILQ_INSERT_HEAD(&tasklist, st, entry); 199 wakeup(&tasklist); 200 201 return (0); 202 } 203 204 void 205 sensor_task_unregister(void *arg) 206 { 207 struct sensor_task *st; 208 209 TAILQ_FOREACH(st, &tasklist, entry) { 210 if (st->arg == arg) 211 st->running = 0; 212 } 213 } 214 215 void 216 sensor_task_create(void *arg) 217 { 218 if (kthread_create(sensor_task_thread, NULL, NULL, "sensors") != 0) 219 panic("sensors kthread"); 220 } 221 222 void 223 sensor_task_thread(void *arg) 224 { 225 struct sensor_task *st, *nst; 226 time_t now; 227 228 while (!TAILQ_EMPTY(&tasklist)) { 229 while ((nst = TAILQ_FIRST(&tasklist))->nextrun > 230 (now = time_uptime)) 231 tsleep(&tasklist, PWAIT, "timeout", 232 (nst->nextrun - now) * hz); 233 234 while ((st = nst) != NULL) { 235 nst = TAILQ_NEXT(st, entry); 236 237 if (st->nextrun > now) 238 break; 239 240 /* take it out while we work on it */ 241 TAILQ_REMOVE(&tasklist, st, entry); 242 243 if (!st->running) { 244 free(st, M_DEVBUF); 245 continue; 246 } 247 248 /* run the task */ 249 st->func(st->arg); 250 /* stick it back in the tasklist */ 251 sensor_task_schedule(st); 252 } 253 } 254 255 kthread_exit(0); 256 } 257 258 void 259 sensor_task_schedule(struct sensor_task *st) 260 { 261 struct sensor_task *cst; 262 263 st->nextrun = time_uptime + st->period; 264 265 TAILQ_FOREACH(cst, &tasklist, entry) { 266 if (cst->nextrun > st->nextrun) { 267 TAILQ_INSERT_BEFORE(cst, st, entry); 268 return; 269 } 270 } 271 272 /* must be an empty list, or at the end of the list */ 273 TAILQ_INSERT_TAIL(&tasklist, st, entry); 274 } 275 276