1 /* $OpenBSD: kern_sensors.c,v 1.10 2006/05/28 00:24:00 henning 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 #include <sys/hotplug.h> 28 29 #include <sys/sensors.h> 30 #include "hotplug.h" 31 32 int sensors_count = 0; 33 SLIST_HEAD(, sensor) sensors_list = SLIST_HEAD_INITIALIZER(&sensors_list); 34 35 struct sensor_task { 36 void *arg; 37 void (*func)(void *); 38 39 int period; 40 time_t nextrun; 41 volatile int running; 42 TAILQ_ENTRY(sensor_task) entry; 43 }; 44 45 void sensor_task_create(void *); 46 void sensor_task_thread(void *); 47 void sensor_task_schedule(struct sensor_task *); 48 49 TAILQ_HEAD(, sensor_task) tasklist = TAILQ_HEAD_INITIALIZER(tasklist); 50 51 void 52 sensor_add(struct sensor *sens) 53 { 54 struct sensor *v, *nv; 55 int s; 56 57 s = splhigh(); 58 if (sensors_count == 0) { 59 sens->num = 0; 60 SLIST_INSERT_HEAD(&sensors_list, sens, list); 61 } else { 62 for (v = SLIST_FIRST(&sensors_list); 63 (nv = SLIST_NEXT(v, list)) != NULL; v = nv) 64 if (nv->num - v->num > 1) 65 break; 66 sens->num = v->num + 1; 67 SLIST_INSERT_AFTER(v, sens, list); 68 } 69 sensors_count++; 70 splx(s); 71 72 #if NHOTPLUG > 0 73 hotplug_device_attach(DV_SENSOR, sens->device); 74 #endif 75 } 76 77 void 78 sensor_del(struct sensor *sens) 79 { 80 int s; 81 82 s = splhigh(); 83 sensors_count--; 84 SLIST_REMOVE(&sensors_list, sens, sensor, list); 85 splx(s); 86 87 #if NHOTPLUG > 0 88 hotplug_device_detach(DV_SENSOR, sens->device); 89 #endif 90 } 91 92 struct sensor * 93 sensor_get(int num) 94 { 95 struct sensor *s; 96 97 SLIST_FOREACH(s, &sensors_list, list) { 98 if (s->num == num) 99 return (s); 100 } 101 102 return (NULL); 103 } 104 105 int 106 sensor_task_register(void *arg, void (*func)(void *), int period) 107 { 108 struct sensor_task *st; 109 110 st = malloc(sizeof(struct sensor_task), M_DEVBUF, M_NOWAIT); 111 if (st == NULL) 112 return (1); 113 114 st->arg = arg; 115 st->func = func; 116 st->period = period; 117 118 st->running = 1; 119 120 if (TAILQ_EMPTY(&tasklist)) 121 kthread_create_deferred(sensor_task_create, NULL); 122 123 sensor_task_schedule(st); 124 wakeup(&tasklist); 125 126 return (0); 127 } 128 129 void 130 sensor_task_unregister(void *arg) 131 { 132 struct sensor_task *st; 133 134 TAILQ_FOREACH(st, &tasklist, entry) { 135 if (st->arg == arg) 136 st->running = 0; 137 } 138 } 139 140 void 141 sensor_task_create(void *arg) 142 { 143 if (kthread_create(sensor_task_thread, NULL, NULL, "sensors") != 0) 144 panic("sensors kthread"); 145 } 146 147 void 148 sensor_task_thread(void *arg) 149 { 150 struct sensor_task *st, *nst; 151 time_t now; 152 153 while (!TAILQ_EMPTY(&tasklist)) { 154 while ((nst = TAILQ_FIRST(&tasklist))->nextrun > 155 (now = time_uptime)) 156 tsleep(&tasklist, PWAIT, "timeout", 157 (nst->nextrun - now) * hz); 158 159 while ((st = nst) != NULL) { 160 nst = TAILQ_NEXT(st, entry); 161 162 if (st->nextrun > now) 163 break; 164 165 /* take it out while we work on it */ 166 TAILQ_REMOVE(&tasklist, st, entry); 167 168 if (!st->running) { 169 free(st, M_DEVBUF); 170 continue; 171 } 172 173 /* run the task */ 174 st->func(st->arg); 175 /* stick it back in the tasklist */ 176 sensor_task_schedule(st); 177 } 178 } 179 180 kthread_exit(0); 181 } 182 183 void 184 sensor_task_schedule(struct sensor_task *st) 185 { 186 struct sensor_task *cst; 187 188 st->nextrun = time_uptime + st->period; 189 190 TAILQ_FOREACH(cst, &tasklist, entry) { 191 if (cst->nextrun > st->nextrun) { 192 TAILQ_INSERT_BEFORE(cst, st, entry); 193 return; 194 } 195 } 196 197 /* must be an empty list, or at the end of the list */ 198 TAILQ_INSERT_TAIL(&tasklist, st, entry); 199 } 200 201