1 /* $OpenBSD: kern_sensors.c,v 1.19 2007/06/04 18:42:05 deraadt Exp $ */ 2 3 /* 4 * (MPSAFE) 5 * 6 * Copyright (c) 2005 David Gwynne <dlg@openbsd.org> 7 * Copyright (c) 2006 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru> 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 */ 21 22 #include <sys/param.h> 23 #include <sys/systm.h> 24 #include <sys/kernel.h> 25 #include <sys/malloc.h> 26 #include <sys/kthread.h> 27 #include <sys/queue.h> 28 #include <sys/types.h> 29 #include <sys/time.h> 30 #include <sys/spinlock.h> 31 #include <sys/spinlock2.h> 32 #include <sys/lock.h> 33 34 #include <sys/sysctl.h> 35 #include <sys/sensors.h> 36 37 #include <sys/mplock2.h> 38 39 static struct spinlock sensor_dev_lock = 40 SPINLOCK_INITIALIZER(sensor_dev_lock, "sensor_dev_lock"); 41 42 static int sensordev_count; 43 static SLIST_HEAD(, ksensordev) sensordev_list = 44 SLIST_HEAD_INITIALIZER(sensordev_list); 45 46 static struct ksensordev *sensordev_get(int); 47 static struct ksensor *sensor_find(struct ksensordev *, enum sensor_type, 48 int); 49 50 struct sensor_task { 51 void *arg; 52 void (*func)(void *); 53 54 int period; 55 time_t nextrun; /* time_uptime */ 56 int running; 57 TAILQ_ENTRY(sensor_task) entry; 58 }; 59 60 static void sensor_task_thread(void *); 61 static void sensor_task_schedule(struct sensor_task *); 62 63 static TAILQ_HEAD(, sensor_task) sensor_tasklist = 64 TAILQ_HEAD_INITIALIZER(sensor_tasklist); 65 66 static struct lock sensor_task_lock = 67 LOCK_INITIALIZER("ksensor_task", 0, LK_CANRECURSE); 68 69 static void sensor_sysctl_install(struct ksensordev *); 70 static void sensor_sysctl_deinstall(struct ksensordev *); 71 72 void 73 sensordev_install(struct ksensordev *sensdev) 74 { 75 struct ksensordev *v, *nv; 76 77 /* mtx_lock(&Giant); */ 78 spin_lock(&sensor_dev_lock); 79 if (sensordev_count == 0) { 80 sensdev->num = 0; 81 SLIST_INSERT_HEAD(&sensordev_list, sensdev, list); 82 } else { 83 for (v = SLIST_FIRST(&sensordev_list); 84 (nv = SLIST_NEXT(v, list)) != NULL; v = nv) 85 if (nv->num - v->num > 1) 86 break; 87 sensdev->num = v->num + 1; 88 SLIST_INSERT_AFTER(v, sensdev, list); 89 } 90 sensordev_count++; 91 /* mtx_unlock(&Giant); */ 92 spin_unlock(&sensor_dev_lock); 93 94 sensor_sysctl_install(sensdev); 95 } 96 97 void 98 sensor_attach(struct ksensordev *sensdev, struct ksensor *sens) 99 { 100 struct ksensor *v, *nv; 101 struct ksensors_head *sh; 102 int i; 103 104 /* mtx_lock(&Giant); */ 105 spin_lock(&sensor_dev_lock); 106 sh = &sensdev->sensors_list; 107 if (sensdev->sensors_count == 0) { 108 for (i = 0; i < SENSOR_MAX_TYPES; i++) 109 sensdev->maxnumt[i] = 0; 110 sens->numt = 0; 111 SLIST_INSERT_HEAD(sh, sens, list); 112 } else { 113 for (v = SLIST_FIRST(sh); 114 (nv = SLIST_NEXT(v, list)) != NULL; v = nv) 115 if (v->type == sens->type && (v->type != nv->type || 116 (v->type == nv->type && nv->numt - v->numt > 1))) 117 break; 118 /* sensors of the same type go after each other */ 119 if (v->type == sens->type) 120 sens->numt = v->numt + 1; 121 else 122 sens->numt = 0; 123 SLIST_INSERT_AFTER(v, sens, list); 124 } 125 /* we only increment maxnumt[] if the sensor was added 126 * to the last position of sensors of this type 127 */ 128 if (sensdev->maxnumt[sens->type] == sens->numt) 129 sensdev->maxnumt[sens->type]++; 130 sensdev->sensors_count++; 131 spin_unlock(&sensor_dev_lock); 132 /* mtx_unlock(&Giant); */ 133 } 134 135 void 136 sensordev_deinstall(struct ksensordev *sensdev) 137 { 138 /* mtx_lock(&Giant); */ 139 spin_lock(&sensor_dev_lock); 140 sensordev_count--; 141 SLIST_REMOVE(&sensordev_list, sensdev, ksensordev, list); 142 /* mtx_unlock(&Giant); */ 143 spin_unlock(&sensor_dev_lock); 144 145 sensor_sysctl_deinstall(sensdev); 146 } 147 148 void 149 sensor_detach(struct ksensordev *sensdev, struct ksensor *sens) 150 { 151 struct ksensors_head *sh; 152 153 /* mtx_lock(&Giant); */ 154 sh = &sensdev->sensors_list; 155 sensdev->sensors_count--; 156 SLIST_REMOVE(sh, sens, ksensor, list); 157 /* we only decrement maxnumt[] if this is the tail 158 * sensor of this type 159 */ 160 if (sens->numt == sensdev->maxnumt[sens->type] - 1) 161 sensdev->maxnumt[sens->type]--; 162 /* mtx_unlock(&Giant); */ 163 } 164 165 static struct ksensordev * 166 sensordev_get(int num) 167 { 168 struct ksensordev *sd; 169 170 spin_lock(&sensor_dev_lock); 171 SLIST_FOREACH(sd, &sensordev_list, list) 172 if (sd->num == num) { 173 spin_unlock(&sensor_dev_lock); 174 return (sd); 175 } 176 177 spin_unlock(&sensor_dev_lock); 178 return (NULL); 179 } 180 181 static struct ksensor * 182 sensor_find(struct ksensordev *sensdev, enum sensor_type type, int numt) 183 { 184 struct ksensor *s; 185 struct ksensors_head *sh; 186 187 spin_lock(&sensor_dev_lock); 188 sh = &sensdev->sensors_list; 189 SLIST_FOREACH(s, sh, list) { 190 if (s->type == type && s->numt == numt) { 191 spin_unlock(&sensor_dev_lock); 192 return (s); 193 } 194 } 195 196 spin_unlock(&sensor_dev_lock); 197 return (NULL); 198 } 199 200 void 201 sensor_task_register(void *arg, void (*func)(void *), int period) 202 { 203 struct sensor_task *st; 204 205 st = kmalloc(sizeof(struct sensor_task), M_DEVBUF, M_WAITOK); 206 207 lockmgr(&sensor_task_lock, LK_EXCLUSIVE); 208 st->arg = arg; 209 st->func = func; 210 st->period = period; 211 212 st->running = 1; 213 214 st->nextrun = 0; 215 TAILQ_INSERT_HEAD(&sensor_tasklist, st, entry); 216 217 wakeup(&sensor_tasklist); 218 219 lockmgr(&sensor_task_lock, LK_RELEASE); 220 } 221 222 void 223 sensor_task_unregister(void *arg) 224 { 225 struct sensor_task *st; 226 227 lockmgr(&sensor_task_lock, LK_EXCLUSIVE); 228 TAILQ_FOREACH(st, &sensor_tasklist, entry) 229 if (st->arg == arg) 230 st->running = 0; 231 lockmgr(&sensor_task_lock, LK_RELEASE); 232 } 233 234 static void 235 sensor_task_thread(void *arg) 236 { 237 struct sensor_task *st, *nst; 238 time_t now; 239 240 lockmgr(&sensor_task_lock, LK_EXCLUSIVE); 241 242 for (;;) { 243 while (TAILQ_EMPTY(&sensor_tasklist)) { 244 lksleep(&sensor_tasklist, &sensor_task_lock, 0, 245 "waittask", 0); 246 } 247 248 while ((nst = TAILQ_FIRST(&sensor_tasklist))->nextrun > 249 (now = time_uptime)) { 250 lksleep(&sensor_tasklist, &sensor_task_lock, 0, 251 "timeout", (nst->nextrun - now) * hz); 252 } 253 254 while ((st = nst) != NULL) { 255 nst = TAILQ_NEXT(st, entry); 256 257 if (st->nextrun > now) 258 break; 259 260 /* take it out while we work on it */ 261 TAILQ_REMOVE(&sensor_tasklist, st, entry); 262 263 if (!st->running) { 264 kfree(st, M_DEVBUF); 265 continue; 266 } 267 268 /* run the task */ 269 st->func(st->arg); 270 /* stick it back in the tasklist */ 271 sensor_task_schedule(st); 272 } 273 } 274 275 lockmgr(&sensor_task_lock, LK_RELEASE); 276 } 277 278 static void 279 sensor_task_schedule(struct sensor_task *st) 280 { 281 struct sensor_task *cst; 282 283 lockmgr(&sensor_task_lock, LK_EXCLUSIVE); 284 st->nextrun = time_uptime + st->period; 285 286 TAILQ_FOREACH(cst, &sensor_tasklist, entry) { 287 if (cst->nextrun > st->nextrun) { 288 TAILQ_INSERT_BEFORE(cst, st, entry); 289 lockmgr(&sensor_task_lock, LK_RELEASE); 290 return; 291 } 292 } 293 294 /* must be an empty list, or at the end of the list */ 295 TAILQ_INSERT_TAIL(&sensor_tasklist, st, entry); 296 lockmgr(&sensor_task_lock, LK_RELEASE); 297 } 298 299 /* 300 * sysctl glue code 301 */ 302 static int sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS); 303 static int sysctl_handle_sensor(SYSCTL_HANDLER_ARGS); 304 static int sysctl_sensors_handler(SYSCTL_HANDLER_ARGS); 305 306 SYSCTL_NODE(_hw, OID_AUTO, sensors, CTLFLAG_RD, NULL, 307 "Hardware Sensors sysctl internal magic"); 308 SYSCTL_NODE(_hw, HW_SENSORS, _sensors, CTLFLAG_RD, sysctl_sensors_handler, 309 "Hardware Sensors XP MIB interface"); 310 311 static void 312 sensor_sysctl_install(struct ksensordev *sensdev) 313 { 314 struct sysctl_oid_list *ol; 315 struct sysctl_ctx_list *cl = &sensdev->clist; 316 struct ksensor *s; 317 struct ksensors_head *sh = &sensdev->sensors_list; 318 319 sysctl_ctx_init(cl); 320 ol = SYSCTL_CHILDREN(SYSCTL_ADD_NODE(cl, (&SYSCTL_NODE_CHILDREN(_hw, 321 sensors)), sensdev->num, sensdev->xname, CTLFLAG_RD, NULL, "")); 322 SLIST_FOREACH(s, sh, list) { 323 char n[32]; 324 325 ksnprintf(n, sizeof(n), "%s%d", sensor_type_s[s->type], s->numt); 326 SYSCTL_ADD_PROC(cl, ol, OID_AUTO, n, CTLTYPE_STRUCT | 327 CTLFLAG_RD, s, 0, sysctl_handle_sensor, "S,sensor", ""); 328 } 329 } 330 331 static void 332 sensor_sysctl_deinstall(struct ksensordev *sensdev) 333 { 334 struct sysctl_ctx_list *cl = &sensdev->clist; 335 336 sysctl_ctx_free(cl); 337 } 338 339 static int 340 sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS) 341 { 342 struct ksensordev *ksd = arg1; 343 struct sensordev *usd; 344 int error; 345 346 if (req->newptr) 347 return (EPERM); 348 349 /* Grab a copy, to clear the kernel pointers */ 350 usd = kmalloc(sizeof(*usd), M_TEMP, M_WAITOK | M_ZERO); 351 usd->num = ksd->num; 352 strlcpy(usd->xname, ksd->xname, sizeof(usd->xname)); 353 memcpy(usd->maxnumt, ksd->maxnumt, sizeof(usd->maxnumt)); 354 usd->sensors_count = ksd->sensors_count; 355 356 error = SYSCTL_OUT(req, usd, sizeof(struct sensordev)); 357 358 kfree(usd, M_TEMP); 359 return (error); 360 361 } 362 363 static int 364 sysctl_handle_sensor(SYSCTL_HANDLER_ARGS) 365 { 366 struct ksensor *ks = arg1; 367 struct sensor *us; 368 int error; 369 370 if (req->newptr) 371 return (EPERM); 372 373 /* Grab a copy, to clear the kernel pointers */ 374 us = kmalloc(sizeof(*us), M_TEMP, M_WAITOK | M_ZERO); 375 memcpy(us->desc, ks->desc, sizeof(ks->desc)); 376 us->tv = ks->tv; 377 us->value = ks->value; 378 us->type = ks->type; 379 us->status = ks->status; 380 us->numt = ks->numt; 381 us->flags = ks->flags; 382 383 error = SYSCTL_OUT(req, us, sizeof(struct sensor)); 384 385 kfree(us, M_TEMP); 386 return (error); 387 } 388 389 static int 390 sysctl_sensors_handler(SYSCTL_HANDLER_ARGS) 391 { 392 int *name = arg1; 393 u_int namelen = arg2; 394 struct ksensordev *ksd; 395 struct ksensor *ks; 396 int dev, numt; 397 enum sensor_type type; 398 399 if (namelen != 1 && namelen != 3) 400 return (ENOTDIR); 401 402 dev = name[0]; 403 if ((ksd = sensordev_get(dev)) == NULL) 404 return (ENOENT); 405 406 if (namelen == 1) 407 return (sysctl_handle_sensordev(NULL, ksd, 0, req)); 408 409 type = name[1]; 410 numt = name[2]; 411 412 if ((ks = sensor_find(ksd, type, numt)) == NULL) 413 return (ENOENT); 414 return (sysctl_handle_sensor(NULL, ks, 0, req)); 415 } 416 417 static void 418 sensor_sysinit(void *arg __unused) 419 { 420 int error; 421 422 error = kthread_create(sensor_task_thread, NULL, NULL, "sensors"); 423 if (error) 424 panic("sensors kthread failed: %d", error); 425 } 426 SYSINIT(sensor, SI_SUB_PRE_DRIVERS, SI_ORDER_ANY, sensor_sysinit, NULL); 427