kern_sensors.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /* $OpenBSD: kern_sensors.c,v 1.36 2015/03/14 03:38:50 jsg Exp $ */
  2. /*
  3. * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
  4. * Copyright (c) 2006 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru>
  5. *
  6. * Permission to use, copy, modify, and distribute this software for any
  7. * purpose with or without fee is hereby granted, provided that the above
  8. * copyright notice and this permission notice appear in all copies.
  9. *
  10. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17. */
  18. #include <sys/param.h>
  19. #include <sys/systm.h>
  20. #include <sys/malloc.h>
  21. #include <sys/queue.h>
  22. #include <sys/device.h>
  23. #include <sys/hotplug.h>
  24. #include <sys/timeout.h>
  25. #include <sys/task.h>
  26. #include <sys/rwlock.h>
  27. #include <sys/sensors.h>
  28. #include "hotplug.h"
  29. struct taskq *sensors_taskq;
  30. int sensordev_count;
  31. SLIST_HEAD(, ksensordev) sensordev_list =
  32. SLIST_HEAD_INITIALIZER(sensordev_list);
  33. void
  34. sensordev_install(struct ksensordev *sensdev)
  35. {
  36. struct ksensordev *v, *nv;
  37. int s;
  38. s = splhigh();
  39. if (sensordev_count == 0) {
  40. sensdev->num = 0;
  41. SLIST_INSERT_HEAD(&sensordev_list, sensdev, list);
  42. } else {
  43. for (v = SLIST_FIRST(&sensordev_list);
  44. (nv = SLIST_NEXT(v, list)) != NULL; v = nv)
  45. if (nv->num - v->num > 1)
  46. break;
  47. sensdev->num = v->num + 1;
  48. SLIST_INSERT_AFTER(v, sensdev, list);
  49. }
  50. sensordev_count++;
  51. splx(s);
  52. #if NHOTPLUG > 0
  53. hotplug_device_attach(DV_DULL, "sensordev");
  54. #endif
  55. }
  56. void
  57. sensor_attach(struct ksensordev *sensdev, struct ksensor *sens)
  58. {
  59. struct ksensor *v, *nv;
  60. struct ksensors_head *sh;
  61. int s, i;
  62. s = splhigh();
  63. sh = &sensdev->sensors_list;
  64. if (sensdev->sensors_count == 0) {
  65. for (i = 0; i < SENSOR_MAX_TYPES; i++)
  66. sensdev->maxnumt[i] = 0;
  67. sens->numt = 0;
  68. SLIST_INSERT_HEAD(sh, sens, list);
  69. } else {
  70. for (v = SLIST_FIRST(sh);
  71. (nv = SLIST_NEXT(v, list)) != NULL; v = nv)
  72. if (v->type == sens->type && (v->type != nv->type ||
  73. (v->type == nv->type && nv->numt - v->numt > 1)))
  74. break;
  75. /* sensors of the same type go after each other */
  76. if (v->type == sens->type)
  77. sens->numt = v->numt + 1;
  78. else
  79. sens->numt = 0;
  80. SLIST_INSERT_AFTER(v, sens, list);
  81. }
  82. /* we only increment maxnumt[] if the sensor was added
  83. * to the last position of sensors of this type
  84. */
  85. if (sensdev->maxnumt[sens->type] == sens->numt)
  86. sensdev->maxnumt[sens->type]++;
  87. sensdev->sensors_count++;
  88. splx(s);
  89. }
  90. void
  91. sensordev_deinstall(struct ksensordev *sensdev)
  92. {
  93. int s;
  94. s = splhigh();
  95. sensordev_count--;
  96. SLIST_REMOVE(&sensordev_list, sensdev, ksensordev, list);
  97. splx(s);
  98. #if NHOTPLUG > 0
  99. hotplug_device_detach(DV_DULL, "sensordev");
  100. #endif
  101. }
  102. void
  103. sensor_detach(struct ksensordev *sensdev, struct ksensor *sens)
  104. {
  105. struct ksensors_head *sh;
  106. int s;
  107. s = splhigh();
  108. sh = &sensdev->sensors_list;
  109. sensdev->sensors_count--;
  110. SLIST_REMOVE(sh, sens, ksensor, list);
  111. /* we only decrement maxnumt[] if this is the tail
  112. * sensor of this type
  113. */
  114. if (sens->numt == sensdev->maxnumt[sens->type] - 1)
  115. sensdev->maxnumt[sens->type]--;
  116. splx(s);
  117. }
  118. int
  119. sensordev_get(int num, struct ksensordev **sensdev)
  120. {
  121. struct ksensordev *sd;
  122. SLIST_FOREACH(sd, &sensordev_list, list) {
  123. if (sd->num == num) {
  124. *sensdev = sd;
  125. return (0);
  126. }
  127. if (sd->num > num)
  128. return (ENXIO);
  129. }
  130. return (ENOENT);
  131. }
  132. int
  133. sensor_find(int dev, enum sensor_type type, int numt, struct ksensor **ksensorp)
  134. {
  135. struct ksensor *s;
  136. struct ksensordev *sensdev;
  137. struct ksensors_head *sh;
  138. int ret;
  139. ret = sensordev_get(dev, &sensdev);
  140. if (ret)
  141. return (ret);
  142. sh = &sensdev->sensors_list;
  143. SLIST_FOREACH(s, sh, list)
  144. if (s->type == type && s->numt == numt) {
  145. *ksensorp = s;
  146. return (0);
  147. }
  148. return (ENOENT);
  149. }
  150. struct sensor_task {
  151. void (*func)(void *);
  152. void *arg;
  153. unsigned int period;
  154. struct timeout timeout;
  155. struct task task;
  156. struct rwlock lock;
  157. };
  158. void sensor_task_tick(void *);
  159. void sensor_task_work(void *);
  160. struct sensor_task *
  161. sensor_task_register(void *arg, void (*func)(void *), unsigned int period)
  162. {
  163. struct sensor_task *st;
  164. #ifdef DIAGNOSTIC
  165. if (period == 0)
  166. panic("sensor_task_register: period is 0");
  167. #endif
  168. if (sensors_taskq == NULL &&
  169. (sensors_taskq = taskq_create("sensors", 1, IPL_HIGH, 0)) == NULL)
  170. sensors_taskq = systq;
  171. st = malloc(sizeof(*st), M_DEVBUF, M_NOWAIT);
  172. if (st == NULL)
  173. return (NULL);
  174. st->func = func;
  175. st->arg = arg;
  176. st->period = period;
  177. timeout_set(&st->timeout, sensor_task_tick, st);
  178. task_set(&st->task, sensor_task_work, st);
  179. rw_init(&st->lock, "sensor");
  180. sensor_task_tick(st);
  181. return (st);
  182. }
  183. void
  184. sensor_task_unregister(struct sensor_task *st)
  185. {
  186. /*
  187. * we can't reliably timeout_del or task_del because there's a window
  188. * between when they come off the lists and the timeout or task code
  189. * actually runs the respective handlers for them. mark the sensor_task
  190. * as dying by setting period to 0 and let sensor_task_work mop up.
  191. */
  192. rw_enter_write(&st->lock);
  193. st->period = 0;
  194. rw_exit_write(&st->lock);
  195. }
  196. void
  197. sensor_task_tick(void *arg)
  198. {
  199. struct sensor_task *st = arg;
  200. task_add(sensors_taskq, &st->task);
  201. }
  202. void
  203. sensor_task_work(void *xst)
  204. {
  205. struct sensor_task *st = xst;
  206. unsigned int period = 0;
  207. rw_enter_write(&st->lock);
  208. period = st->period;
  209. if (period > 0)
  210. st->func(st->arg);
  211. rw_exit_write(&st->lock);
  212. if (period == 0)
  213. free(st, M_DEVBUF, sizeof(*st));
  214. else
  215. timeout_add_sec(&st->timeout, period);
  216. }