1 /* $OpenBSD: kern_sensors.c,v 1.9 2006/05/27 23:51:27 mk Exp $ */ 2 3 /* 4 * Copyright (c) 2005 David Gwynne <dlg@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/kernel.h> 22 #include <sys/malloc.h> 23 #include <sys/kthread.h> 24 #include <sys/queue.h> 25 #include <sys/types.h> 26 #include <sys/time.h> 27 28 #include <sys/sensors.h> 29 #include "hotplug.h" 30 31 int sensors_count = 0; 32 SLIST_HEAD(, sensor) sensors_list = SLIST_HEAD_INITIALIZER(&sensors_list); 33 34 struct sensor_task { 35 void *arg; 36 void (*func)(void *); 37 38 int period; 39 time_t nextrun; 40 volatile int running; 41 TAILQ_ENTRY(sensor_task) entry; 42 }; 43 44 void sensor_task_create(void *); 45 void sensor_task_thread(void *); 46 void sensor_task_schedule(struct sensor_task *); 47 48 TAILQ_HEAD(, sensor_task) tasklist = TAILQ_HEAD_INITIALIZER(tasklist); 49 50 void 51 sensor_add(struct sensor *sens) 52 { 53 struct sensor *v, *nv; 54 int s; 55 56 s = splhigh(); 57 if (sensors_count == 0) { 58 sens->num = 0; 59 SLIST_INSERT_HEAD(&sensors_list, sens, list); 60 } else { 61 for (v = SLIST_FIRST(&sensors_list); 62 (nv = SLIST_NEXT(v, list)) != NULL; v = nv) 63 if (nv->num - v->num > 1) 64 break; 65 sens->num = v->num + 1; 66 SLIST_INSERT_AFTER(v, sens, list); 67 } 68 sensors_count++; 69 splx(s); 70 71 #if NHOTPLUG > 0 72 hotplug_device_attach(DV_SENSOR, sens->device); 73 #endif 74 } 75 76 void 77 sensor_del(struct sensor *sens) 78 { 79 int s; 80 81 s = splhigh(); 82 sensors_count--; 83 SLIST_REMOVE(&sensors_list, sens, sensor, list); 84 splx(s); 85 86 #if NHOTPLUG > 0 87 hotplug_device_detach(DV_SENSOR, sens->device); 88 #endif 89 } 90 91 struct sensor * 92 sensor_get(int num) 93 { 94 struct sensor *s; 95 96 SLIST_FOREACH(s, &sensors_list, list) { 97 if (s->num == num) 98 return (s); 99 } 100 101 return (NULL); 102 } 103 104 int 105 sensor_task_register(void *arg, void (*func)(void *), int period) 106 { 107 struct sensor_task *st; 108 109 st = malloc(sizeof(struct sensor_task), M_DEVBUF, M_NOWAIT); 110 if (st == NULL) 111 return (1); 112 113 st->arg = arg; 114 st->func = func; 115 st->period = period; 116 117 st->running = 1; 118 119 if (TAILQ_EMPTY(&tasklist)) 120 kthread_create_deferred(sensor_task_create, NULL); 121 122 sensor_task_schedule(st); 123 wakeup(&tasklist); 124 125 return (0); 126 } 127 128 void 129 sensor_task_unregister(void *arg) 130 { 131 struct sensor_task *st; 132 133 TAILQ_FOREACH(st, &tasklist, entry) { 134 if (st->arg == arg) 135 st->running = 0; 136 } 137 } 138 139 void 140 sensor_task_create(void *arg) 141 { 142 if (kthread_create(sensor_task_thread, NULL, NULL, "sensors") != 0) 143 panic("sensors kthread"); 144 } 145 146 void 147 sensor_task_thread(void *arg) 148 { 149 struct sensor_task *st, *nst; 150 time_t now; 151 152 while (!TAILQ_EMPTY(&tasklist)) { 153 while ((nst = TAILQ_FIRST(&tasklist))->nextrun > 154 (now = time_uptime)) 155 tsleep(&tasklist, PWAIT, "timeout", 156 (nst->nextrun - now) * hz); 157 158 while ((st = nst) != NULL) { 159 nst = TAILQ_NEXT(st, entry); 160 161 if (st->nextrun > now) 162 break; 163 164 /* take it out while we work on it */ 165 TAILQ_REMOVE(&tasklist, st, entry); 166 167 if (!st->running) { 168 free(st, M_DEVBUF); 169 continue; 170 } 171 172 /* run the task */ 173 st->func(st->arg); 174 /* stick it back in the tasklist */ 175 sensor_task_schedule(st); 176 } 177 } 178 179 kthread_exit(0); 180 } 181 182 void 183 sensor_task_schedule(struct sensor_task *st) 184 { 185 struct sensor_task *cst; 186 187 st->nextrun = time_uptime + st->period; 188 189 TAILQ_FOREACH(cst, &tasklist, entry) { 190 if (cst->nextrun > st->nextrun) { 191 TAILQ_INSERT_BEFORE(cst, st, entry); 192 return; 193 } 194 } 195 196 /* must be an empty list, or at the end of the list */ 197 TAILQ_INSERT_TAIL(&tasklist, st, entry); 198 } 199 200