acpibtn.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /* $OpenBSD: acpibtn.c,v 1.41 2015/01/27 19:40:14 kettenis Exp $ */
  2. /*
  3. * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include <sys/param.h>
  18. #include <sys/signalvar.h>
  19. #include <sys/systm.h>
  20. #include <sys/device.h>
  21. #include <sys/malloc.h>
  22. #include <machine/bus.h>
  23. #include <machine/apmvar.h>
  24. #include <dev/acpi/acpireg.h>
  25. #include <dev/acpi/acpivar.h>
  26. #include <dev/acpi/acpidev.h>
  27. #include <dev/acpi/amltypes.h>
  28. #include <dev/acpi/dsdt.h>
  29. #include <sys/sensors.h>
  30. int acpibtn_match(struct device *, void *, void *);
  31. void acpibtn_attach(struct device *, struct device *, void *);
  32. int acpibtn_notify(struct aml_node *, int, void *);
  33. struct acpibtn_softc {
  34. struct device sc_dev;
  35. bus_space_tag_t sc_iot;
  36. bus_space_handle_t sc_ioh;
  37. struct acpi_softc *sc_acpi;
  38. struct aml_node *sc_devnode;
  39. struct ksensor sc_sens;
  40. struct ksensordev sc_sensdev;
  41. int sc_btn_type;
  42. #define ACPIBTN_UNKNOWN 0
  43. #define ACPIBTN_LID 1
  44. #define ACPIBTN_POWER 2
  45. #define ACPIBTN_SLEEP 3
  46. };
  47. int acpibtn_setpsw(struct acpibtn_softc *, int);
  48. struct acpi_lid {
  49. struct acpibtn_softc *abl_softc;
  50. SLIST_ENTRY(acpi_lid) abl_link;
  51. };
  52. SLIST_HEAD(acpi_lid_head, acpi_lid) acpibtn_lids =
  53. SLIST_HEAD_INITIALIZER(acpibtn_lids);
  54. struct cfattach acpibtn_ca = {
  55. sizeof(struct acpibtn_softc), acpibtn_match, acpibtn_attach
  56. };
  57. struct cfdriver acpibtn_cd = {
  58. NULL, "acpibtn", DV_DULL
  59. };
  60. const char *acpibtn_hids[] = { ACPI_DEV_LD, ACPI_DEV_PBD, ACPI_DEV_SBD, 0 };
  61. /*
  62. * acpibtn_numopenlids
  63. *
  64. * Return the number of _LID devices that are in the "open" state.
  65. * Used to determine if we should go back to sleep/hibernate if we
  66. * woke up with the all the lids still closed for some reason. If
  67. * the machine has no lids, returns -1.
  68. */
  69. int
  70. acpibtn_numopenlids(void)
  71. {
  72. struct acpi_lid *lid;
  73. int64_t val;
  74. int ct = 0;
  75. /* If we have no lids ... */
  76. if (SLIST_EMPTY(&acpibtn_lids))
  77. return (-1);
  78. /*
  79. * Determine how many lids are open. Assumes _LID evals to
  80. * non-0 or 0, for on / off (which is what the spec says).
  81. */
  82. SLIST_FOREACH(lid, &acpibtn_lids, abl_link)
  83. if (!aml_evalinteger(lid->abl_softc->sc_acpi,
  84. lid->abl_softc->sc_devnode, "_LID", 0, NULL, &val) &&
  85. val != 0)
  86. ct++;
  87. return (ct);
  88. }
  89. int
  90. acpibtn_setpsw(struct acpibtn_softc *sc, int psw)
  91. {
  92. struct aml_value val;
  93. bzero(&val, sizeof val);
  94. val.type = AML_OBJTYPE_INTEGER;
  95. val.v_integer = psw;
  96. val.length = 1;
  97. return (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PSW", 1, &val,
  98. NULL));
  99. }
  100. void
  101. acpibtn_disable_psw(void)
  102. {
  103. struct acpi_lid *lid;
  104. /* disable _LID for wakeup */
  105. SLIST_FOREACH(lid, &acpibtn_lids, abl_link)
  106. acpibtn_setpsw(lid->abl_softc, 0);
  107. }
  108. void
  109. acpibtn_enable_psw(void)
  110. {
  111. struct acpi_lid *lid;
  112. /* enable _LID for wakeup */
  113. SLIST_FOREACH(lid, &acpibtn_lids, abl_link)
  114. acpibtn_setpsw(lid->abl_softc, 1);
  115. }
  116. int
  117. acpibtn_match(struct device *parent, void *match, void *aux)
  118. {
  119. struct acpi_attach_args *aa = aux;
  120. struct cfdata *cf = match;
  121. /* sanity */
  122. return (acpi_matchhids(aa, acpibtn_hids, cf->cf_driver->cd_name));
  123. }
  124. void
  125. acpibtn_attach(struct device *parent, struct device *self, void *aux)
  126. {
  127. struct acpibtn_softc *sc = (struct acpibtn_softc *)self;
  128. struct acpi_attach_args *aa = aux;
  129. struct acpi_lid *lid;
  130. int64_t lid_open;
  131. int64_t st;
  132. sc->sc_acpi = (struct acpi_softc *)parent;
  133. sc->sc_devnode = aa->aaa_node;
  134. printf(": %s\n", sc->sc_devnode->name);
  135. if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, &st))
  136. st = STA_PRESENT | STA_ENABLED | STA_DEV_OK;
  137. if ((st & (STA_PRESENT | STA_ENABLED | STA_DEV_OK)) !=
  138. (STA_PRESENT | STA_ENABLED | STA_DEV_OK))
  139. return;
  140. if (!strcmp(aa->aaa_dev, ACPI_DEV_LD)) {
  141. sc->sc_btn_type = ACPIBTN_LID;
  142. /* Set PSW (if present) to disable wake on this LID */
  143. (void)acpibtn_setpsw(sc, 0);
  144. lid = malloc(sizeof(*lid), M_DEVBUF, M_WAITOK | M_ZERO);
  145. lid->abl_softc = sc;
  146. SLIST_INSERT_HEAD(&acpibtn_lids, lid, abl_link);
  147. } else if (!strcmp(aa->aaa_dev, ACPI_DEV_PBD))
  148. sc->sc_btn_type = ACPIBTN_POWER;
  149. else if (!strcmp(aa->aaa_dev, ACPI_DEV_SBD))
  150. sc->sc_btn_type = ACPIBTN_SLEEP;
  151. if (sc->sc_btn_type == ACPIBTN_LID) {
  152. strlcpy(sc->sc_sensdev.xname, DEVNAME(sc),
  153. sizeof(sc->sc_sensdev.xname));
  154. strlcpy(sc->sc_sens.desc, "lid open",
  155. sizeof(sc->sc_sens.desc));
  156. sc->sc_sens.type = SENSOR_INDICATOR;
  157. sensor_attach(&sc->sc_sensdev, &sc->sc_sens);
  158. sensordev_install(&sc->sc_sensdev);
  159. aml_evalinteger(sc->sc_acpi, sc->sc_devnode,
  160. "_LID", 0, NULL, &lid_open);
  161. sc->sc_sens.value = lid_open;
  162. }
  163. aml_register_notify(sc->sc_devnode, aa->aaa_dev, acpibtn_notify,
  164. sc, ACPIDEV_NOPOLL);
  165. }
  166. int
  167. acpibtn_notify(struct aml_node *node, int notify_type, void *arg)
  168. {
  169. struct acpibtn_softc *sc = arg;
  170. #ifndef SMALL_KERNEL
  171. extern int lid_suspend;
  172. int64_t lid;
  173. #endif
  174. dnprintf(10, "acpibtn_notify: %.2x %s\n", notify_type,
  175. sc->sc_devnode->name);
  176. switch (sc->sc_btn_type) {
  177. case ACPIBTN_LID:
  178. #ifndef SMALL_KERNEL
  179. /*
  180. * Notification of 0x80 for lid opens or closes. We
  181. * need to check the current status by calling the
  182. * _LID method. 0 means the lid is closed and we
  183. * should go to sleep.
  184. */
  185. if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode,
  186. "_LID", 0, NULL, &lid))
  187. return (0);
  188. sc->sc_sens.value = lid;
  189. if (lid_suspend == 0)
  190. break;
  191. if (lid == 0)
  192. goto sleep;
  193. #endif /* SMALL_KERNEL */
  194. break;
  195. case ACPIBTN_SLEEP:
  196. #ifndef SMALL_KERNEL
  197. switch (notify_type) {
  198. case 0x02:
  199. /* "something" has been taken care of by the system */
  200. break;
  201. case 0x80:
  202. sleep:
  203. /* Request to go to sleep */
  204. if (acpi_record_event(sc->sc_acpi, APM_USER_SUSPEND_REQ))
  205. acpi_addtask(sc->sc_acpi, acpi_sleep_task,
  206. sc->sc_acpi, ACPI_STATE_S3);
  207. break;
  208. }
  209. #endif /* SMALL_KERNEL */
  210. break;
  211. case ACPIBTN_POWER:
  212. if (notify_type == 0x80)
  213. acpi_addtask(sc->sc_acpi, acpi_powerdown_task,
  214. sc->sc_acpi, 0);
  215. break;
  216. default:
  217. printf("%s: spurious acpi button interrupt %i\n", DEVNAME(sc),
  218. sc->sc_btn_type);
  219. break;
  220. }
  221. return (0);
  222. }