root/kern/kern_sensors.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sensordev_install
  2. sensor_attach
  3. sensordev_deinstall
  4. sensor_detach
  5. sensordev_get
  6. sensor_find
  7. sensor_task_register
  8. sensor_task_unregister
  9. sensor_task_tick
  10. sensor_task_work

    1 /*      $OpenBSD: kern_sensors.c,v 1.21 2007/07/03 03:22:34 cnst Exp $  */
    2 
    3 /*
    4  * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
    5  * Copyright (c) 2006 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru>
    6  *
    7  * Permission to use, copy, modify, and distribute this software for any
    8  * purpose with or without fee is hereby granted, provided that the above
    9  * copyright notice and this permission notice appear in all copies.
   10  *
   11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   18  */
   19 
   20 #include <sys/param.h>
   21 #include <sys/proc.h>
   22 #include <sys/systm.h>
   23 #include <sys/kernel.h>
   24 #include <sys/malloc.h>
   25 #include <sys/queue.h>
   26 #include <sys/types.h>
   27 #include <sys/device.h>
   28 #include <sys/hotplug.h>
   29 #include <sys/timeout.h>
   30 #include <sys/workq.h>
   31 
   32 #include <sys/sensors.h>
   33 #include "hotplug.h"
   34 
   35 int                     sensordev_count = 0;
   36 SLIST_HEAD(, ksensordev) sensordev_list =
   37     SLIST_HEAD_INITIALIZER(sensordev_list);
   38 
   39 void
   40 sensordev_install(struct ksensordev *sensdev)
   41 {
   42         struct ksensordev *v, *nv;
   43         int s;
   44 
   45         s = splhigh();
   46         if (sensordev_count == 0) {
   47                 sensdev->num = 0;
   48                 SLIST_INSERT_HEAD(&sensordev_list, sensdev, list);
   49         } else {
   50                 for (v = SLIST_FIRST(&sensordev_list);
   51                     (nv = SLIST_NEXT(v, list)) != NULL; v = nv)
   52                         if (nv->num - v->num > 1)
   53                                 break;
   54                 sensdev->num = v->num + 1;
   55                 SLIST_INSERT_AFTER(v, sensdev, list);
   56         }
   57         sensordev_count++;
   58         splx(s);
   59 
   60 #if NHOTPLUG > 0
   61         hotplug_device_attach(DV_DULL, "sensordev");
   62 #endif
   63 }
   64 
   65 void
   66 sensor_attach(struct ksensordev *sensdev, struct ksensor *sens)
   67 {
   68         struct ksensor *v, *nv;
   69         struct ksensors_head *sh;
   70         int s, i;
   71 
   72         s = splhigh();
   73         sh = &sensdev->sensors_list;
   74         if (sensdev->sensors_count == 0) {
   75                 for (i = 0; i < SENSOR_MAX_TYPES; i++)
   76                         sensdev->maxnumt[i] = 0;
   77                 sens->numt = 0;
   78                 SLIST_INSERT_HEAD(sh, sens, list);
   79         } else {
   80                 for (v = SLIST_FIRST(sh);
   81                     (nv = SLIST_NEXT(v, list)) != NULL; v = nv)
   82                         if (v->type == sens->type && (v->type != nv->type || 
   83                             (v->type == nv->type && nv->numt - v->numt > 1)))
   84                                 break;
   85                 /* sensors of the same type go after each other */
   86                 if (v->type == sens->type)
   87                         sens->numt = v->numt + 1;
   88                 else
   89                         sens->numt = 0;
   90                 SLIST_INSERT_AFTER(v, sens, list);
   91         }
   92         /* we only increment maxnumt[] if the sensor was added
   93          * to the last position of sensors of this type
   94          */
   95         if (sensdev->maxnumt[sens->type] == sens->numt)
   96                 sensdev->maxnumt[sens->type]++;
   97         sensdev->sensors_count++;
   98         splx(s);
   99 }
  100 
  101 void
  102 sensordev_deinstall(struct ksensordev *sensdev)
  103 {
  104         int s;
  105 
  106         s = splhigh();
  107         sensordev_count--;
  108         SLIST_REMOVE(&sensordev_list, sensdev, ksensordev, list);
  109         splx(s);
  110 
  111 #if NHOTPLUG > 0
  112         hotplug_device_detach(DV_DULL, "sensordev");
  113 #endif
  114 }
  115 
  116 void
  117 sensor_detach(struct ksensordev *sensdev, struct ksensor *sens)
  118 {
  119         struct ksensors_head *sh;
  120         int s;
  121 
  122         s = splhigh();
  123         sh = &sensdev->sensors_list;
  124         sensdev->sensors_count--;
  125         SLIST_REMOVE(sh, sens, ksensor, list);
  126         /* we only decrement maxnumt[] if this is the tail 
  127          * sensor of this type
  128          */
  129         if (sens->numt == sensdev->maxnumt[sens->type] - 1)
  130                 sensdev->maxnumt[sens->type]--;
  131         splx(s);
  132 }
  133 
  134 struct ksensordev *
  135 sensordev_get(int num)
  136 {
  137         struct ksensordev *sd;
  138 
  139         SLIST_FOREACH(sd, &sensordev_list, list)
  140                 if (sd->num == num)
  141                         return (sd);
  142 
  143         return (NULL);
  144 }
  145 
  146 struct ksensor *
  147 sensor_find(int dev, enum sensor_type type, int numt)
  148 {
  149         struct ksensor *s;
  150         struct ksensordev *sensdev;
  151         struct ksensors_head *sh;
  152 
  153         sensdev = sensordev_get(dev);
  154         if (sensdev == NULL)
  155                 return (NULL);
  156 
  157         sh = &sensdev->sensors_list;
  158         SLIST_FOREACH(s, sh, list)
  159                 if (s->type == type && s->numt == numt)
  160                         return (s);
  161 
  162         return (NULL);
  163 }
  164 
  165 struct sensor_task {
  166         void                            (*func)(void *);
  167         void                            *arg;
  168 
  169         int                             period;
  170         struct timeout                  timeout;
  171         volatile enum {
  172                 ST_TICKING,
  173                 ST_WORKQ,
  174                 ST_RUNNING,
  175                 ST_DYING,
  176                 ST_DEAD
  177         }                               state;
  178 };
  179 
  180 void    sensor_task_tick(void *);
  181 void    sensor_task_work(void *, void *);
  182 
  183 struct sensor_task *
  184 sensor_task_register(void *arg, void (*func)(void *), int period)
  185 {
  186         struct sensor_task *st;
  187 
  188         st = malloc(sizeof(struct sensor_task), M_DEVBUF, M_NOWAIT);
  189         if (st == NULL)
  190                 return (NULL);
  191 
  192         st->func = func;
  193         st->arg = arg;
  194         st->period = period;
  195         timeout_set(&st->timeout, sensor_task_tick, st);
  196 
  197         sensor_task_tick(st);
  198 
  199         return (st);
  200 }
  201 
  202 void
  203 sensor_task_unregister(struct sensor_task *st)
  204 {
  205         timeout_del(&st->timeout);
  206 
  207         switch (st->state) {
  208         case ST_TICKING:
  209                 free(st, M_DEVBUF);
  210                 break;
  211 
  212         case ST_WORKQ:
  213                 st->state = ST_DYING;
  214                 break;
  215 
  216         case ST_RUNNING:
  217                 st->state = ST_DYING;
  218                 while (st->state != ST_DEAD)
  219                         tsleep(st, 0, "stunr", 0);
  220                 free(st, M_DEVBUF);
  221                 break;
  222         default:
  223                 panic("sensor_task_unregister: unexpected state %d",
  224                     st->state);
  225         }
  226 }
  227 
  228 void
  229 sensor_task_tick(void *arg)
  230 {
  231         struct sensor_task *st = arg;
  232 
  233         /* try to schedule the task */
  234         if (workq_add_task(NULL, 0, sensor_task_work, st, NULL) != 0)
  235                 timeout_add(&st->timeout, hz/2);
  236 
  237         st->state = ST_WORKQ;
  238 }
  239 
  240 void
  241 sensor_task_work(void *xst, void *arg)
  242 {
  243         struct sensor_task *st = xst;
  244 
  245         if (st->state == ST_DYING) {
  246                 free(st, M_DEVBUF);
  247                 return;
  248         }
  249 
  250         st->state = ST_RUNNING;
  251         st->func(st->arg);
  252 
  253         if (st->state == ST_DYING) {
  254                 st->state = ST_DEAD;
  255                 wakeup(st);
  256         } else {
  257                 st->state = ST_TICKING;
  258                 timeout_add(&st->timeout, hz * st->period);
  259         }
  260 }

/* [<][>][^][v][top][bottom][index][help] */