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 int sensordev_idmax; 40 static TAILQ_HEAD(sensordev_list, ksensordev) sensordev_list = 41 TAILQ_HEAD_INITIALIZER(sensordev_list); 42 43 static struct ksensordev *sensordev_get(int); 44 static struct ksensor *sensor_find(struct ksensordev *, enum sensor_type, 45 int); 46 47 struct sensor_task { 48 void *arg; 49 void (*func)(void *); 50 51 int period; 52 time_t nextrun; /* time_uptime */ 53 int running; 54 TAILQ_ENTRY(sensor_task) entry; 55 }; 56 57 static void sensor_task_thread(void *); 58 static void sensor_task_schedule(struct sensor_task *); 59 60 static TAILQ_HEAD(, sensor_task) sensor_tasklist = 61 TAILQ_HEAD_INITIALIZER(sensor_tasklist); 62 63 static struct lock sensor_task_lock = 64 LOCK_INITIALIZER("ksensor_task", 0, LK_CANRECURSE); 65 66 static void sensordev_sysctl_install(struct ksensordev *); 67 static void sensordev_sysctl_deinstall(struct ksensordev *); 68 static void sensor_sysctl_install(struct ksensordev *, 69 struct ksensor *); 70 static void sensor_sysctl_deinstall(struct ksensordev *, 71 struct ksensor *); 72 73 void 74 sensordev_install(struct ksensordev *sensdev) 75 { 76 struct ksensordev *v, *after = NULL; 77 int num = 0; 78 79 SYSCTL_XLOCK(); 80 81 TAILQ_FOREACH(v, &sensordev_list, list) { 82 if (v->num == num) { 83 ++num; 84 after = v; 85 } else if (v->num > num) { 86 break; 87 } 88 } 89 90 sensdev->num = num; 91 if (after == NULL) { 92 KKASSERT(sensdev->num == 0); 93 TAILQ_INSERT_HEAD(&sensordev_list, sensdev, list); 94 } else { 95 TAILQ_INSERT_AFTER(&sensordev_list, after, sensdev, list); 96 } 97 98 /* Save max sensor device id */ 99 sensordev_idmax = TAILQ_LAST(&sensordev_list, sensordev_list)->num + 1; 100 101 /* Install sysctl node for this sensor device */ 102 sensordev_sysctl_install(sensdev); 103 104 SYSCTL_XUNLOCK(); 105 } 106 107 void 108 sensor_attach(struct ksensordev *sensdev, struct ksensor *sens) 109 { 110 struct ksensor *v, *nv; 111 struct ksensors_head *sh; 112 int i; 113 114 SYSCTL_XLOCK(); 115 116 sh = &sensdev->sensors_list; 117 if (sensdev->sensors_count == 0) { 118 for (i = 0; i < SENSOR_MAX_TYPES; i++) 119 sensdev->maxnumt[i] = 0; 120 sens->numt = 0; 121 SLIST_INSERT_HEAD(sh, sens, list); 122 } else { 123 for (v = SLIST_FIRST(sh); 124 (nv = SLIST_NEXT(v, list)) != NULL; v = nv) 125 if (v->type == sens->type && (v->type != nv->type || 126 (v->type == nv->type && nv->numt - v->numt > 1))) 127 break; 128 /* sensors of the same type go after each other */ 129 if (v->type == sens->type) 130 sens->numt = v->numt + 1; 131 else 132 sens->numt = 0; 133 SLIST_INSERT_AFTER(v, sens, list); 134 } 135 /* 136 * We only increment maxnumt[] if the sensor was added 137 * to the last position of sensors of this type 138 */ 139 if (sensdev->maxnumt[sens->type] == sens->numt) 140 sensdev->maxnumt[sens->type]++; 141 sensdev->sensors_count++; 142 143 /* Install sysctl node for this sensor */ 144 sensor_sysctl_install(sensdev, sens); 145 146 SYSCTL_XUNLOCK(); 147 } 148 149 void 150 sensordev_deinstall(struct ksensordev *sensdev) 151 { 152 struct ksensordev *last; 153 154 SYSCTL_XLOCK(); 155 156 TAILQ_REMOVE(&sensordev_list, sensdev, list); 157 158 /* Adjust max sensor device id */ 159 last = TAILQ_LAST(&sensordev_list, sensordev_list); 160 if (last != NULL) 161 sensordev_idmax = last->num + 1; 162 else 163 sensordev_idmax = 0; 164 165 /* 166 * Deinstall sensor device's sysctl node; this also 167 * removes all attached sensors' sysctl nodes. 168 */ 169 sensordev_sysctl_deinstall(sensdev); 170 171 SYSCTL_XUNLOCK(); 172 } 173 174 void 175 sensor_detach(struct ksensordev *sensdev, struct ksensor *sens) 176 { 177 struct ksensors_head *sh; 178 179 SYSCTL_XLOCK(); 180 181 sh = &sensdev->sensors_list; 182 sensdev->sensors_count--; 183 SLIST_REMOVE(sh, sens, ksensor, list); 184 /* 185 * We only decrement maxnumt[] if this is the tail 186 * sensor of this type 187 */ 188 if (sens->numt == sensdev->maxnumt[sens->type] - 1) 189 sensdev->maxnumt[sens->type]--; 190 191 /* Deinstall sensor's sysctl node */ 192 sensor_sysctl_deinstall(sensdev, sens); 193 194 SYSCTL_XUNLOCK(); 195 } 196 197 static struct ksensordev * 198 sensordev_get(int num) 199 { 200 struct ksensordev *sd; 201 202 SYSCTL_ASSERT_XLOCKED(); 203 204 TAILQ_FOREACH(sd, &sensordev_list, list) { 205 if (sd->num == num) 206 return (sd); 207 } 208 return (NULL); 209 } 210 211 static struct ksensor * 212 sensor_find(struct ksensordev *sensdev, enum sensor_type type, int numt) 213 { 214 struct ksensor *s; 215 struct ksensors_head *sh; 216 217 SYSCTL_ASSERT_XLOCKED(); 218 219 sh = &sensdev->sensors_list; 220 SLIST_FOREACH(s, sh, list) { 221 if (s->type == type && s->numt == numt) 222 return (s); 223 } 224 return (NULL); 225 } 226 227 void 228 sensor_task_register(void *arg, void (*func)(void *), int period) 229 { 230 struct sensor_task *st; 231 232 st = kmalloc(sizeof(struct sensor_task), M_DEVBUF, M_WAITOK); 233 234 lockmgr(&sensor_task_lock, LK_EXCLUSIVE); 235 st->arg = arg; 236 st->func = func; 237 st->period = period; 238 239 st->running = 1; 240 241 st->nextrun = 0; 242 TAILQ_INSERT_HEAD(&sensor_tasklist, st, entry); 243 244 wakeup(&sensor_tasklist); 245 246 lockmgr(&sensor_task_lock, LK_RELEASE); 247 } 248 249 void 250 sensor_task_unregister(void *arg) 251 { 252 struct sensor_task *st; 253 254 lockmgr(&sensor_task_lock, LK_EXCLUSIVE); 255 TAILQ_FOREACH(st, &sensor_tasklist, entry) 256 if (st->arg == arg) 257 st->running = 0; 258 lockmgr(&sensor_task_lock, LK_RELEASE); 259 } 260 261 static void 262 sensor_task_thread(void *arg) 263 { 264 struct sensor_task *st, *nst; 265 time_t now; 266 267 lockmgr(&sensor_task_lock, LK_EXCLUSIVE); 268 269 for (;;) { 270 while (TAILQ_EMPTY(&sensor_tasklist)) { 271 lksleep(&sensor_tasklist, &sensor_task_lock, 0, 272 "waittask", 0); 273 } 274 275 while ((nst = TAILQ_FIRST(&sensor_tasklist))->nextrun > 276 (now = time_uptime)) { 277 lksleep(&sensor_tasklist, &sensor_task_lock, 0, 278 "timeout", (nst->nextrun - now) * hz); 279 } 280 281 while ((st = nst) != NULL) { 282 nst = TAILQ_NEXT(st, entry); 283 284 if (st->nextrun > now) 285 break; 286 287 /* take it out while we work on it */ 288 TAILQ_REMOVE(&sensor_tasklist, st, entry); 289 290 if (!st->running) { 291 kfree(st, M_DEVBUF); 292 continue; 293 } 294 295 /* run the task */ 296 st->func(st->arg); 297 /* stick it back in the tasklist */ 298 sensor_task_schedule(st); 299 } 300 } 301 302 lockmgr(&sensor_task_lock, LK_RELEASE); 303 } 304 305 static void 306 sensor_task_schedule(struct sensor_task *st) 307 { 308 struct sensor_task *cst; 309 310 KASSERT(lockstatus(&sensor_task_lock, curthread) == LK_EXCLUSIVE, 311 ("sensor task lock is not held")); 312 313 st->nextrun = time_uptime + st->period; 314 315 TAILQ_FOREACH(cst, &sensor_tasklist, entry) { 316 if (cst->nextrun > st->nextrun) { 317 TAILQ_INSERT_BEFORE(cst, st, entry); 318 return; 319 } 320 } 321 322 /* must be an empty list, or at the end of the list */ 323 TAILQ_INSERT_TAIL(&sensor_tasklist, st, entry); 324 } 325 326 /* 327 * sysctl glue code 328 */ 329 static int sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS); 330 static int sysctl_handle_sensor(SYSCTL_HANDLER_ARGS); 331 static int sysctl_sensors_handler(SYSCTL_HANDLER_ARGS); 332 333 SYSCTL_NODE(_hw, OID_AUTO, sensors, CTLFLAG_RD, NULL, 334 "Hardware Sensors sysctl internal magic"); 335 SYSCTL_NODE(_hw, HW_SENSORS, _sensors, CTLFLAG_RD, sysctl_sensors_handler, 336 "Hardware Sensors XP MIB interface"); 337 338 SYSCTL_INT(_hw_sensors, OID_AUTO, dev_idmax, CTLFLAG_RD, 339 &sensordev_idmax, 0, "Max sensor device id"); 340 341 static void 342 sensordev_sysctl_install(struct ksensordev *sensdev) 343 { 344 struct sysctl_ctx_list *cl = &sensdev->clist; 345 struct ksensor *s; 346 struct ksensors_head *sh = &sensdev->sensors_list; 347 348 SYSCTL_ASSERT_XLOCKED(); 349 350 KASSERT(sensdev->oid == NULL, 351 ("sensor device %s sysctl node already installed", sensdev->xname)); 352 353 sysctl_ctx_init(cl); 354 sensdev->oid = SYSCTL_ADD_NODE(cl, SYSCTL_STATIC_CHILDREN(_hw_sensors), 355 sensdev->num, sensdev->xname, CTLFLAG_RD, NULL, ""); 356 if (sensdev->oid == NULL) { 357 kprintf("sensor: add sysctl tree for %s failed\n", 358 sensdev->xname); 359 return; 360 } 361 362 /* Install sysctl nodes for sensors attached to this sensor device */ 363 SLIST_FOREACH(s, sh, list) 364 sensor_sysctl_install(sensdev, s); 365 } 366 367 static void 368 sensor_sysctl_install(struct ksensordev *sensdev, struct ksensor *sens) 369 { 370 char n[32]; 371 372 SYSCTL_ASSERT_XLOCKED(); 373 374 if (sensdev->oid == NULL) { 375 /* Sensor device sysctl node is not installed yet */ 376 return; 377 } 378 379 ksnprintf(n, sizeof(n), "%s%d", sensor_type_s[sens->type], sens->numt); 380 KASSERT(sens->oid == NULL, 381 ("sensor %s:%s sysctl node already installed", sensdev->xname, n)); 382 383 sens->oid = SYSCTL_ADD_PROC(&sensdev->clist, 384 SYSCTL_CHILDREN(sensdev->oid), OID_AUTO, n, 385 CTLTYPE_STRUCT | CTLFLAG_RD, sens, 0, sysctl_handle_sensor, 386 "S,sensor", ""); 387 } 388 389 static void 390 sensordev_sysctl_deinstall(struct ksensordev *sensdev) 391 { 392 SYSCTL_ASSERT_XLOCKED(); 393 394 if (sensdev->oid != NULL) { 395 sysctl_ctx_free(&sensdev->clist); 396 sensdev->oid = NULL; 397 } 398 } 399 400 static void 401 sensor_sysctl_deinstall(struct ksensordev *sensdev, struct ksensor *sens) 402 { 403 SYSCTL_ASSERT_XLOCKED(); 404 405 if (sensdev->oid != NULL && sens->oid != NULL) { 406 sysctl_ctx_entry_del(&sensdev->clist, sens->oid); 407 sysctl_remove_oid(sens->oid, 1, 0); 408 } 409 sens->oid = NULL; 410 } 411 412 static int 413 sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS) 414 { 415 struct ksensordev *ksd = arg1; 416 struct sensordev *usd; 417 int error; 418 419 if (req->newptr) 420 return (EPERM); 421 422 /* Grab a copy, to clear the kernel pointers */ 423 usd = kmalloc(sizeof(*usd), M_TEMP, M_WAITOK | M_ZERO); 424 usd->num = ksd->num; 425 strlcpy(usd->xname, ksd->xname, sizeof(usd->xname)); 426 memcpy(usd->maxnumt, ksd->maxnumt, sizeof(usd->maxnumt)); 427 usd->sensors_count = ksd->sensors_count; 428 429 error = SYSCTL_OUT(req, usd, sizeof(struct sensordev)); 430 431 kfree(usd, M_TEMP); 432 return (error); 433 } 434 435 static int 436 sysctl_handle_sensor(SYSCTL_HANDLER_ARGS) 437 { 438 struct ksensor *ks = arg1; 439 struct sensor *us; 440 int error; 441 442 if (req->newptr) 443 return (EPERM); 444 445 /* Grab a copy, to clear the kernel pointers */ 446 us = kmalloc(sizeof(*us), M_TEMP, M_WAITOK | M_ZERO); 447 memcpy(us->desc, ks->desc, sizeof(ks->desc)); 448 us->tv = ks->tv; 449 us->value = ks->value; 450 us->type = ks->type; 451 us->status = ks->status; 452 us->numt = ks->numt; 453 us->flags = ks->flags; 454 455 error = SYSCTL_OUT(req, us, sizeof(struct sensor)); 456 457 kfree(us, M_TEMP); 458 return (error); 459 } 460 461 static int 462 sysctl_sensors_handler(SYSCTL_HANDLER_ARGS) 463 { 464 int *name = arg1; 465 u_int namelen = arg2; 466 struct ksensordev *ksd; 467 struct ksensor *ks; 468 int dev, numt; 469 enum sensor_type type; 470 471 if (namelen != 1 && namelen != 3) 472 return (ENOTDIR); 473 474 dev = name[0]; 475 if ((ksd = sensordev_get(dev)) == NULL) 476 return (ENOENT); 477 478 if (namelen == 1) 479 return (sysctl_handle_sensordev(NULL, ksd, 0, req)); 480 481 type = name[1]; 482 numt = name[2]; 483 484 if ((ks = sensor_find(ksd, type, numt)) == NULL) 485 return (ENOENT); 486 return (sysctl_handle_sensor(NULL, ks, 0, req)); 487 } 488 489 static void 490 sensor_sysinit(void *arg __unused) 491 { 492 int error, cpu; 493 494 cpu = ncpus - 1; /* stick to the last CPU */ 495 error = kthread_create_cpu(sensor_task_thread, NULL, NULL, cpu, 496 "sensors"); 497 if (error) 498 panic("sensors kthread on cpu%d failed: %d", cpu, error); 499 } 500 SYSINIT(sensor, SI_SUB_PRE_DRIVERS, SI_ORDER_ANY, sensor_sysinit, NULL); 501