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