123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- /* $OpenBSD: kern_sensors.c,v 1.36 2015/03/14 03:38:50 jsg Exp $ */
- /*
- * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
- * Copyright (c) 2006 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- #include <sys/param.h>
- #include <sys/systm.h>
- #include <sys/malloc.h>
- #include <sys/queue.h>
- #include <sys/device.h>
- #include <sys/hotplug.h>
- #include <sys/timeout.h>
- #include <sys/task.h>
- #include <sys/rwlock.h>
- #include <sys/sensors.h>
- #include "hotplug.h"
- struct taskq *sensors_taskq;
- int sensordev_count;
- SLIST_HEAD(, ksensordev) sensordev_list =
- SLIST_HEAD_INITIALIZER(sensordev_list);
- void
- sensordev_install(struct ksensordev *sensdev)
- {
- struct ksensordev *v, *nv;
- int s;
- s = splhigh();
- if (sensordev_count == 0) {
- sensdev->num = 0;
- SLIST_INSERT_HEAD(&sensordev_list, sensdev, list);
- } else {
- for (v = SLIST_FIRST(&sensordev_list);
- (nv = SLIST_NEXT(v, list)) != NULL; v = nv)
- if (nv->num - v->num > 1)
- break;
- sensdev->num = v->num + 1;
- SLIST_INSERT_AFTER(v, sensdev, list);
- }
- sensordev_count++;
- splx(s);
- #if NHOTPLUG > 0
- hotplug_device_attach(DV_DULL, "sensordev");
- #endif
- }
- void
- sensor_attach(struct ksensordev *sensdev, struct ksensor *sens)
- {
- struct ksensor *v, *nv;
- struct ksensors_head *sh;
- int s, i;
- s = splhigh();
- sh = &sensdev->sensors_list;
- if (sensdev->sensors_count == 0) {
- for (i = 0; i < SENSOR_MAX_TYPES; i++)
- sensdev->maxnumt[i] = 0;
- sens->numt = 0;
- SLIST_INSERT_HEAD(sh, sens, list);
- } else {
- for (v = SLIST_FIRST(sh);
- (nv = SLIST_NEXT(v, list)) != NULL; v = nv)
- if (v->type == sens->type && (v->type != nv->type ||
- (v->type == nv->type && nv->numt - v->numt > 1)))
- break;
- /* sensors of the same type go after each other */
- if (v->type == sens->type)
- sens->numt = v->numt + 1;
- else
- sens->numt = 0;
- SLIST_INSERT_AFTER(v, sens, list);
- }
- /* we only increment maxnumt[] if the sensor was added
- * to the last position of sensors of this type
- */
- if (sensdev->maxnumt[sens->type] == sens->numt)
- sensdev->maxnumt[sens->type]++;
- sensdev->sensors_count++;
- splx(s);
- }
- void
- sensordev_deinstall(struct ksensordev *sensdev)
- {
- int s;
- s = splhigh();
- sensordev_count--;
- SLIST_REMOVE(&sensordev_list, sensdev, ksensordev, list);
- splx(s);
- #if NHOTPLUG > 0
- hotplug_device_detach(DV_DULL, "sensordev");
- #endif
- }
- void
- sensor_detach(struct ksensordev *sensdev, struct ksensor *sens)
- {
- struct ksensors_head *sh;
- int s;
- s = splhigh();
- sh = &sensdev->sensors_list;
- sensdev->sensors_count--;
- SLIST_REMOVE(sh, sens, ksensor, list);
- /* we only decrement maxnumt[] if this is the tail
- * sensor of this type
- */
- if (sens->numt == sensdev->maxnumt[sens->type] - 1)
- sensdev->maxnumt[sens->type]--;
- splx(s);
- }
- int
- sensordev_get(int num, struct ksensordev **sensdev)
- {
- struct ksensordev *sd;
- SLIST_FOREACH(sd, &sensordev_list, list) {
- if (sd->num == num) {
- *sensdev = sd;
- return (0);
- }
- if (sd->num > num)
- return (ENXIO);
- }
- return (ENOENT);
- }
- int
- sensor_find(int dev, enum sensor_type type, int numt, struct ksensor **ksensorp)
- {
- struct ksensor *s;
- struct ksensordev *sensdev;
- struct ksensors_head *sh;
- int ret;
- ret = sensordev_get(dev, &sensdev);
- if (ret)
- return (ret);
- sh = &sensdev->sensors_list;
- SLIST_FOREACH(s, sh, list)
- if (s->type == type && s->numt == numt) {
- *ksensorp = s;
- return (0);
- }
- return (ENOENT);
- }
- struct sensor_task {
- void (*func)(void *);
- void *arg;
- unsigned int period;
- struct timeout timeout;
- struct task task;
- struct rwlock lock;
- };
- void sensor_task_tick(void *);
- void sensor_task_work(void *);
- struct sensor_task *
- sensor_task_register(void *arg, void (*func)(void *), unsigned int period)
- {
- struct sensor_task *st;
- #ifdef DIAGNOSTIC
- if (period == 0)
- panic("sensor_task_register: period is 0");
- #endif
- if (sensors_taskq == NULL &&
- (sensors_taskq = taskq_create("sensors", 1, IPL_HIGH, 0)) == NULL)
- sensors_taskq = systq;
- st = malloc(sizeof(*st), M_DEVBUF, M_NOWAIT);
- if (st == NULL)
- return (NULL);
- st->func = func;
- st->arg = arg;
- st->period = period;
- timeout_set(&st->timeout, sensor_task_tick, st);
- task_set(&st->task, sensor_task_work, st);
- rw_init(&st->lock, "sensor");
- sensor_task_tick(st);
- return (st);
- }
- void
- sensor_task_unregister(struct sensor_task *st)
- {
- /*
- * we can't reliably timeout_del or task_del because there's a window
- * between when they come off the lists and the timeout or task code
- * actually runs the respective handlers for them. mark the sensor_task
- * as dying by setting period to 0 and let sensor_task_work mop up.
- */
- rw_enter_write(&st->lock);
- st->period = 0;
- rw_exit_write(&st->lock);
- }
- void
- sensor_task_tick(void *arg)
- {
- struct sensor_task *st = arg;
- task_add(sensors_taskq, &st->task);
- }
- void
- sensor_task_work(void *xst)
- {
- struct sensor_task *st = xst;
- unsigned int period = 0;
- rw_enter_write(&st->lock);
- period = st->period;
- if (period > 0)
- st->func(st->arg);
- rw_exit_write(&st->lock);
- if (period == 0)
- free(st, M_DEVBUF, sizeof(*st));
- else
- timeout_add_sec(&st->timeout, period);
- }
|