acpibat.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. /* $OpenBSD: acpibat.c,v 1.62 2015/03/14 03:38:46 jsg 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/systm.h>
  19. #include <sys/device.h>
  20. #include <sys/malloc.h>
  21. #include <sys/sensors.h>
  22. #include <machine/apmvar.h>
  23. #include <dev/acpi/acpireg.h>
  24. #include <dev/acpi/acpivar.h>
  25. #include <dev/acpi/acpidev.h>
  26. #include <dev/acpi/amltypes.h>
  27. #include <dev/acpi/dsdt.h>
  28. int acpibat_match(struct device *, void *, void *);
  29. void acpibat_attach(struct device *, struct device *, void *);
  30. struct cfattach acpibat_ca = {
  31. sizeof(struct acpibat_softc), acpibat_match, acpibat_attach
  32. };
  33. struct cfdriver acpibat_cd = {
  34. NULL, "acpibat", DV_DULL
  35. };
  36. const char *acpibat_hids[] = { ACPI_DEV_CMB, 0 };
  37. void acpibat_monitor(struct acpibat_softc *);
  38. void acpibat_refresh(void *);
  39. int acpibat_getbif(struct acpibat_softc *);
  40. int acpibat_getbst(struct acpibat_softc *);
  41. int acpibat_notify(struct aml_node *, int, void *);
  42. int
  43. acpibat_match(struct device *parent, void *match, void *aux)
  44. {
  45. struct acpi_attach_args *aa = aux;
  46. struct cfdata *cf = match;
  47. /* sanity */
  48. return (acpi_matchhids(aa, acpibat_hids, cf->cf_driver->cd_name));
  49. }
  50. void
  51. acpibat_attach(struct device *parent, struct device *self, void *aux)
  52. {
  53. struct acpibat_softc *sc = (struct acpibat_softc *)self;
  54. struct acpi_attach_args *aa = aux;
  55. int64_t sta;
  56. sc->sc_acpi = (struct acpi_softc *)parent;
  57. sc->sc_devnode = aa->aaa_node;
  58. if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, &sta)) {
  59. dnprintf(10, "%s: no _STA\n", DEVNAME(sc));
  60. return;
  61. }
  62. if ((sta & STA_BATTERY) != 0) {
  63. sc->sc_bat_present = 1;
  64. acpibat_getbif(sc);
  65. acpibat_getbst(sc);
  66. printf(": %s", sc->sc_devnode->name);
  67. if (sc->sc_bif.bif_model[0])
  68. printf(" model \"%s\"", sc->sc_bif.bif_model);
  69. if (sc->sc_bif.bif_serial[0])
  70. printf(" serial %s", sc->sc_bif.bif_serial);
  71. if (sc->sc_bif.bif_type[0])
  72. printf(" type %s", sc->sc_bif.bif_type);
  73. if (sc->sc_bif.bif_oem[0])
  74. printf(" oem \"%s\"", sc->sc_bif.bif_oem);
  75. printf("\n");
  76. } else {
  77. sc->sc_bat_present = 0;
  78. printf(": %s not present\n", sc->sc_devnode->name);
  79. }
  80. /* create sensors */
  81. acpibat_monitor(sc);
  82. /* populate sensors */
  83. acpibat_refresh(sc);
  84. aml_register_notify(sc->sc_devnode, aa->aaa_dev,
  85. acpibat_notify, sc, ACPIDEV_POLL);
  86. }
  87. void
  88. acpibat_monitor(struct acpibat_softc *sc)
  89. {
  90. int type;
  91. /* assume _BIF and _BST have been called */
  92. strlcpy(sc->sc_sensdev.xname, DEVNAME(sc),
  93. sizeof(sc->sc_sensdev.xname));
  94. type = sc->sc_bif.bif_power_unit ? SENSOR_AMPHOUR : SENSOR_WATTHOUR;
  95. strlcpy(sc->sc_sens[0].desc, "last full capacity",
  96. sizeof(sc->sc_sens[0].desc));
  97. sc->sc_sens[0].type = type;
  98. sensor_attach(&sc->sc_sensdev, &sc->sc_sens[0]);
  99. sc->sc_sens[0].value = sc->sc_bif.bif_last_capacity * 1000;
  100. strlcpy(sc->sc_sens[1].desc, "warning capacity",
  101. sizeof(sc->sc_sens[1].desc));
  102. sc->sc_sens[1].type = type;
  103. sensor_attach(&sc->sc_sensdev, &sc->sc_sens[1]);
  104. sc->sc_sens[1].value = sc->sc_bif.bif_warning * 1000;
  105. strlcpy(sc->sc_sens[2].desc, "low capacity",
  106. sizeof(sc->sc_sens[2].desc));
  107. sc->sc_sens[2].type = type;
  108. sensor_attach(&sc->sc_sensdev, &sc->sc_sens[2]);
  109. sc->sc_sens[2].value = sc->sc_bif.bif_low * 1000;
  110. strlcpy(sc->sc_sens[3].desc, "voltage", sizeof(sc->sc_sens[3].desc));
  111. sc->sc_sens[3].type = SENSOR_VOLTS_DC;
  112. sensor_attach(&sc->sc_sensdev, &sc->sc_sens[3]);
  113. sc->sc_sens[3].value = sc->sc_bif.bif_voltage * 1000;
  114. strlcpy(sc->sc_sens[4].desc, "battery unknown",
  115. sizeof(sc->sc_sens[4].desc));
  116. sc->sc_sens[4].type = SENSOR_INTEGER;
  117. sensor_attach(&sc->sc_sensdev, &sc->sc_sens[4]);
  118. sc->sc_sens[4].value = sc->sc_bst.bst_state;
  119. strlcpy(sc->sc_sens[5].desc, "rate", sizeof(sc->sc_sens[5].desc));
  120. sc->sc_sens[5].type =
  121. sc->sc_bif.bif_power_unit ? SENSOR_AMPS : SENSOR_WATTS;
  122. sensor_attach(&sc->sc_sensdev, &sc->sc_sens[5]);
  123. sc->sc_sens[5].value = sc->sc_bst.bst_rate * 1000;
  124. strlcpy(sc->sc_sens[6].desc, "remaining capacity",
  125. sizeof(sc->sc_sens[6].desc));
  126. sc->sc_sens[6].type = type;
  127. sensor_attach(&sc->sc_sensdev, &sc->sc_sens[6]);
  128. sc->sc_sens[6].value = sc->sc_bst.bst_capacity * 1000;
  129. strlcpy(sc->sc_sens[7].desc, "current voltage",
  130. sizeof(sc->sc_sens[7].desc));
  131. sc->sc_sens[7].type = SENSOR_VOLTS_DC;
  132. sensor_attach(&sc->sc_sensdev, &sc->sc_sens[7]);
  133. sc->sc_sens[7].value = sc->sc_bst.bst_voltage * 1000;
  134. strlcpy(sc->sc_sens[8].desc, "design capacity",
  135. sizeof(sc->sc_sens[8].desc));
  136. sc->sc_sens[8].type = type;
  137. sensor_attach(&sc->sc_sensdev, &sc->sc_sens[8]);
  138. sc->sc_sens[8].value = sc->sc_bif.bif_capacity * 1000;
  139. sensordev_install(&sc->sc_sensdev);
  140. }
  141. void
  142. acpibat_refresh(void *arg)
  143. {
  144. struct acpibat_softc *sc = arg;
  145. int i;
  146. dnprintf(30, "%s: %s: refresh\n", DEVNAME(sc),
  147. sc->sc_devnode->name);
  148. if (!sc->sc_bat_present) {
  149. for (i = 0; i < 9; i++) {
  150. sc->sc_sens[i].value = 0;
  151. sc->sc_sens[i].status = SENSOR_S_UNSPEC;
  152. sc->sc_sens[i].flags = SENSOR_FINVALID;
  153. }
  154. /* override state */
  155. strlcpy(sc->sc_sens[4].desc, "battery removed",
  156. sizeof(sc->sc_sens[4].desc));
  157. return;
  158. }
  159. /* _BIF values are static, sensor 0..3 */
  160. if (sc->sc_bif.bif_last_capacity == BIF_UNKNOWN) {
  161. sc->sc_sens[0].value = 0;
  162. sc->sc_sens[0].status = SENSOR_S_UNKNOWN;
  163. sc->sc_sens[0].flags = SENSOR_FUNKNOWN;
  164. } else {
  165. sc->sc_sens[0].value = sc->sc_bif.bif_last_capacity * 1000;
  166. sc->sc_sens[0].status = SENSOR_S_UNSPEC;
  167. sc->sc_sens[0].flags = 0;
  168. }
  169. sc->sc_sens[1].value = sc->sc_bif.bif_warning * 1000;
  170. sc->sc_sens[1].flags = 0;
  171. sc->sc_sens[2].value = sc->sc_bif.bif_low * 1000;
  172. sc->sc_sens[2].flags = 0;
  173. if (sc->sc_bif.bif_voltage == BIF_UNKNOWN) {
  174. sc->sc_sens[3].value = 0;
  175. sc->sc_sens[3].status = SENSOR_S_UNKNOWN;
  176. sc->sc_sens[3].flags = SENSOR_FUNKNOWN;
  177. } else {
  178. sc->sc_sens[3].value = sc->sc_bif.bif_voltage * 1000;
  179. sc->sc_sens[3].status = SENSOR_S_UNSPEC;
  180. sc->sc_sens[3].flags = 0;
  181. }
  182. /* _BST values are dynamic, sensor 4..7 */
  183. sc->sc_sens[4].status = SENSOR_S_OK;
  184. sc->sc_sens[4].flags = 0;
  185. if (sc->sc_bif.bif_last_capacity == BIF_UNKNOWN ||
  186. sc->sc_bst.bst_capacity == BST_UNKNOWN) {
  187. sc->sc_sens[4].status = SENSOR_S_UNKNOWN;
  188. sc->sc_sens[4].flags = SENSOR_FUNKNOWN;
  189. strlcpy(sc->sc_sens[4].desc, "battery unknown",
  190. sizeof(sc->sc_sens[4].desc));
  191. } else if (sc->sc_bst.bst_capacity >= sc->sc_bif.bif_last_capacity)
  192. strlcpy(sc->sc_sens[4].desc, "battery full",
  193. sizeof(sc->sc_sens[4].desc));
  194. else if (sc->sc_bst.bst_state & BST_DISCHARGE)
  195. strlcpy(sc->sc_sens[4].desc, "battery discharging",
  196. sizeof(sc->sc_sens[4].desc));
  197. else if (sc->sc_bst.bst_state & BST_CHARGE)
  198. strlcpy(sc->sc_sens[4].desc, "battery charging",
  199. sizeof(sc->sc_sens[4].desc));
  200. else if (sc->sc_bst.bst_state & BST_CRITICAL) {
  201. strlcpy(sc->sc_sens[4].desc, "battery critical",
  202. sizeof(sc->sc_sens[4].desc));
  203. sc->sc_sens[4].status = SENSOR_S_CRIT;
  204. } else
  205. strlcpy(sc->sc_sens[4].desc, "battery idle",
  206. sizeof(sc->sc_sens[4].desc));
  207. sc->sc_sens[4].value = sc->sc_bst.bst_state;
  208. if (sc->sc_bst.bst_rate == BST_UNKNOWN) {
  209. sc->sc_sens[5].value = 0;
  210. sc->sc_sens[5].status = SENSOR_S_UNKNOWN;
  211. sc->sc_sens[5].flags = SENSOR_FUNKNOWN;
  212. } else {
  213. sc->sc_sens[5].value = sc->sc_bst.bst_rate * 1000;
  214. sc->sc_sens[5].status = SENSOR_S_UNSPEC;
  215. sc->sc_sens[5].flags = 0;
  216. }
  217. if (sc->sc_bst.bst_capacity == BST_UNKNOWN) {
  218. sc->sc_sens[6].value = 0;
  219. sc->sc_sens[6].status = SENSOR_S_UNKNOWN;
  220. sc->sc_sens[6].flags = SENSOR_FUNKNOWN;
  221. } else {
  222. sc->sc_sens[6].value = sc->sc_bst.bst_capacity * 1000;
  223. sc->sc_sens[6].flags = 0;
  224. if (sc->sc_bst.bst_capacity < sc->sc_bif.bif_low)
  225. /* XXX we should shutdown the system */
  226. sc->sc_sens[6].status = SENSOR_S_CRIT;
  227. else if (sc->sc_bst.bst_capacity < sc->sc_bif.bif_warning)
  228. sc->sc_sens[6].status = SENSOR_S_WARN;
  229. else
  230. sc->sc_sens[6].status = SENSOR_S_OK;
  231. }
  232. if (sc->sc_bst.bst_voltage == BST_UNKNOWN) {
  233. sc->sc_sens[7].value = 0;
  234. sc->sc_sens[7].status = SENSOR_S_UNKNOWN;
  235. sc->sc_sens[7].flags = SENSOR_FUNKNOWN;
  236. } else {
  237. sc->sc_sens[7].value = sc->sc_bst.bst_voltage * 1000;
  238. sc->sc_sens[7].status = SENSOR_S_UNSPEC;
  239. sc->sc_sens[7].flags = 0;
  240. }
  241. if (sc->sc_bif.bif_capacity == BIF_UNKNOWN) {
  242. sc->sc_sens[8].value = 0;
  243. sc->sc_sens[8].status = SENSOR_S_UNKNOWN;
  244. sc->sc_sens[8].flags = SENSOR_FUNKNOWN;
  245. } else {
  246. sc->sc_sens[8].value = sc->sc_bif.bif_capacity * 1000;
  247. sc->sc_sens[8].status = SENSOR_S_UNSPEC;
  248. sc->sc_sens[8].flags = 0;
  249. }
  250. acpi_record_event(sc->sc_acpi, APM_POWER_CHANGE);
  251. }
  252. int
  253. acpibat_getbif(struct acpibat_softc *sc)
  254. {
  255. struct aml_value res;
  256. int rv = EINVAL;
  257. if (!sc->sc_bat_present) {
  258. memset(&sc->sc_bif, 0, sizeof(sc->sc_bif));
  259. return (0);
  260. }
  261. if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_BIF", 0, NULL, &res)) {
  262. dnprintf(10, "%s: no _BIF\n", DEVNAME(sc));
  263. goto out;
  264. }
  265. if (res.length != 13) {
  266. dnprintf(10, "%s: invalid _BIF, battery info not saved\n",
  267. DEVNAME(sc));
  268. goto out;
  269. }
  270. sc->sc_bif.bif_power_unit = aml_val2int(res.v_package[0]);
  271. sc->sc_bif.bif_capacity = aml_val2int(res.v_package[1]);
  272. sc->sc_bif.bif_last_capacity = aml_val2int(res.v_package[2]);
  273. sc->sc_bif.bif_technology = aml_val2int(res.v_package[3]);
  274. sc->sc_bif.bif_voltage = aml_val2int(res.v_package[4]);
  275. sc->sc_bif.bif_warning = aml_val2int(res.v_package[5]);
  276. sc->sc_bif.bif_low = aml_val2int(res.v_package[6]);
  277. sc->sc_bif.bif_cap_granu1 = aml_val2int(res.v_package[7]);
  278. sc->sc_bif.bif_cap_granu2 = aml_val2int(res.v_package[8]);
  279. strlcpy(sc->sc_bif.bif_model, aml_val_to_string(res.v_package[9]),
  280. sizeof(sc->sc_bif.bif_model));
  281. strlcpy(sc->sc_bif.bif_serial, aml_val_to_string(res.v_package[10]),
  282. sizeof(sc->sc_bif.bif_serial));
  283. strlcpy(sc->sc_bif.bif_type, aml_val_to_string(res.v_package[11]),
  284. sizeof(sc->sc_bif.bif_type));
  285. strlcpy(sc->sc_bif.bif_oem, aml_val_to_string(res.v_package[12]),
  286. sizeof(sc->sc_bif.bif_oem));
  287. dnprintf(60, "power_unit: %u capacity: %u last_cap: %u tech: %u "
  288. "volt: %u warn: %u low: %u gran1: %u gran2: %d model: %s "
  289. "serial: %s type: %s oem: %s\n",
  290. sc->sc_bif.bif_power_unit,
  291. sc->sc_bif.bif_capacity,
  292. sc->sc_bif.bif_last_capacity,
  293. sc->sc_bif.bif_technology,
  294. sc->sc_bif.bif_voltage,
  295. sc->sc_bif.bif_warning,
  296. sc->sc_bif.bif_low,
  297. sc->sc_bif.bif_cap_granu1,
  298. sc->sc_bif.bif_cap_granu2,
  299. sc->sc_bif.bif_model,
  300. sc->sc_bif.bif_serial,
  301. sc->sc_bif.bif_type,
  302. sc->sc_bif.bif_oem);
  303. rv = 0;
  304. out:
  305. aml_freevalue(&res);
  306. return (rv);
  307. }
  308. int
  309. acpibat_getbst(struct acpibat_softc *sc)
  310. {
  311. struct aml_value res;
  312. int rv = EINVAL;
  313. if (!sc->sc_bat_present) {
  314. memset(&sc->sc_bst, 0, sizeof(sc->sc_bst));
  315. return (0);
  316. }
  317. if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_BST", 0, NULL, &res)) {
  318. dnprintf(10, "%s: no _BST\n", DEVNAME(sc));
  319. goto out;
  320. }
  321. if (res.length != 4) {
  322. dnprintf(10, "%s: invalid _BST, battery status not saved\n",
  323. DEVNAME(sc));
  324. goto out;
  325. }
  326. sc->sc_bst.bst_state = aml_val2int(res.v_package[0]);
  327. sc->sc_bst.bst_rate = aml_val2int(res.v_package[1]);
  328. sc->sc_bst.bst_capacity = aml_val2int(res.v_package[2]);
  329. sc->sc_bst.bst_voltage = aml_val2int(res.v_package[3]);
  330. dnprintf(60, "state: %u rate: %u cap: %u volt: %u ",
  331. sc->sc_bst.bst_state,
  332. sc->sc_bst.bst_rate,
  333. sc->sc_bst.bst_capacity,
  334. sc->sc_bst.bst_voltage);
  335. rv = 0;
  336. out:
  337. aml_freevalue(&res);
  338. return (rv);
  339. }
  340. /*
  341. * XXX it has been observed that some systems do not propagate battery
  342. * insertion events up to the driver. What seems to happen is that DSDT
  343. * does receive an interrupt however the originator bit is not set.
  344. * This seems to happen when one inserts a 100% full battery. Removal
  345. * of the power cord or insertion of a not 100% full battery breaks this
  346. * behavior and all events will then be sent upwards. Currently there
  347. * is no known work-around for it.
  348. */
  349. int
  350. acpibat_notify(struct aml_node *node, int notify_type, void *arg)
  351. {
  352. struct acpibat_softc *sc = arg;
  353. int64_t sta;
  354. dnprintf(10, "acpibat_notify: %.2x %s\n", notify_type,
  355. sc->sc_devnode->name);
  356. /* Check if installed state of battery has changed */
  357. if (aml_evalinteger(sc->sc_acpi, node, "_STA", 0, NULL, &sta) == 0) {
  358. if (sta & STA_BATTERY)
  359. sc->sc_bat_present = 1;
  360. else
  361. sc->sc_bat_present = 0;
  362. }
  363. switch (notify_type) {
  364. case 0x00: /* Poll sensors */
  365. case 0x80: /* _BST changed */
  366. acpibat_getbst(sc);
  367. break;
  368. case 0x81: /* _BIF changed */
  369. acpibat_getbif(sc);
  370. break;
  371. default:
  372. break;
  373. }
  374. acpibat_refresh(sc);
  375. return (0);
  376. }