The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_sensors.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 9f7fb4cfbc69821fed7d16026a91540f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.