| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: thinkpad_acpi.c,v 1.56 2024/04/27 14:45:11 christos Exp $ */ | | 1 | /* $NetBSD: thinkpad_acpi.c,v 1.57 2024/04/27 14:50:18 christos Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca> | | 4 | * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca> |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -17,52 +17,70 @@ | | | @@ -17,52 +17,70 @@ |
17 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 17 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
20 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 20 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
26 | * POSSIBILITY OF SUCH DAMAGE. | | 26 | * POSSIBILITY OF SUCH DAMAGE. |
27 | */ | | 27 | */ |
28 | | | 28 | |
29 | #include <sys/cdefs.h> | | 29 | #include <sys/cdefs.h> |
30 | __KERNEL_RCSID(0, "$NetBSD: thinkpad_acpi.c,v 1.56 2024/04/27 14:45:11 christos Exp $"); | | 30 | __KERNEL_RCSID(0, "$NetBSD: thinkpad_acpi.c,v 1.57 2024/04/27 14:50:18 christos Exp $"); |
31 | | | 31 | |
32 | #include <sys/param.h> | | 32 | #include <sys/param.h> |
33 | #include <sys/device.h> | | 33 | #include <sys/device.h> |
34 | #include <sys/module.h> | | 34 | #include <sys/module.h> |
35 | #include <sys/sdt.h> | | 35 | #include <sys/sdt.h> |
36 | #include <sys/systm.h> | | 36 | #include <sys/systm.h> |
| | | 37 | #include <sys/sysctl.h> |
37 | | | 38 | |
38 | #include <dev/acpi/acpireg.h> | | 39 | #include <dev/acpi/acpireg.h> |
39 | #include <dev/acpi/acpivar.h> | | 40 | #include <dev/acpi/acpivar.h> |
40 | #include <dev/acpi/acpi_ecvar.h> | | 41 | #include <dev/acpi/acpi_ecvar.h> |
41 | #include <dev/acpi/acpi_power.h> | | 42 | #include <dev/acpi/acpi_power.h> |
42 | | | 43 | |
43 | #include <dev/isa/isareg.h> | | 44 | #include <dev/isa/isareg.h> |
44 | | | 45 | |
45 | #define _COMPONENT ACPI_RESOURCE_COMPONENT | | 46 | #define _COMPONENT ACPI_RESOURCE_COMPONENT |
46 | ACPI_MODULE_NAME ("thinkpad_acpi") | | 47 | ACPI_MODULE_NAME ("thinkpad_acpi") |
47 | | | 48 | |
48 | #define THINKPAD_NTEMPSENSORS 8 | | 49 | #define THINKPAD_NTEMPSENSORS 8 |
49 | #define THINKPAD_NFANSENSORS 1 | | 50 | #define THINKPAD_NFANSENSORS 1 |
50 | #define THINKPAD_NSENSORS (THINKPAD_NTEMPSENSORS + THINKPAD_NFANSENSORS) | | 51 | #define THINKPAD_NSENSORS (THINKPAD_NTEMPSENSORS + THINKPAD_NFANSENSORS) |
51 | | | 52 | |
| | | 53 | typedef struct tp_sysctl_param { |
| | | 54 | device_t sp_dev; |
| | | 55 | int sp_bat; |
| | | 56 | } tp_sysctl_param_t; |
| | | 57 | |
| | | 58 | typedef union tp_batctl { |
| | | 59 | int have_any; |
| | | 60 | struct { |
| | | 61 | int charge_start:1; |
| | | 62 | int charge_stop:1; |
| | | 63 | int charge_inhibit:1; |
| | | 64 | int force_discharge:1; |
| | | 65 | int individual_control:1; |
| | | 66 | } have; |
| | | 67 | } tp_batctl_t; |
| | | 68 | |
52 | typedef struct thinkpad_softc { | | 69 | typedef struct thinkpad_softc { |
53 | device_t sc_dev; | | 70 | device_t sc_dev; |
54 | device_t sc_ecdev; | | 71 | device_t sc_ecdev; |
55 | struct acpi_devnode *sc_node; | | 72 | struct acpi_devnode *sc_node; |
| | | 73 | struct sysctllog *sc_log; |
56 | ACPI_HANDLE sc_powhdl; | | 74 | ACPI_HANDLE sc_powhdl; |
57 | ACPI_HANDLE sc_cmoshdl; | | 75 | ACPI_HANDLE sc_cmoshdl; |
58 | ACPI_INTEGER sc_ver; | | 76 | ACPI_INTEGER sc_ver; |
59 | | | 77 | |
60 | #define TP_PSW_SLEEP 0 /* FnF4 */ | | 78 | #define TP_PSW_SLEEP 0 /* FnF4 */ |
61 | #define TP_PSW_HIBERNATE 1 /* FnF12 */ | | 79 | #define TP_PSW_HIBERNATE 1 /* FnF12 */ |
62 | #define TP_PSW_DISPLAY_CYCLE 2 /* FnF7 */ | | 80 | #define TP_PSW_DISPLAY_CYCLE 2 /* FnF7 */ |
63 | #define TP_PSW_LOCK_SCREEN 3 /* FnF2 */ | | 81 | #define TP_PSW_LOCK_SCREEN 3 /* FnF2 */ |
64 | #define TP_PSW_BATTERY_INFO 4 /* FnF3 */ | | 82 | #define TP_PSW_BATTERY_INFO 4 /* FnF3 */ |
65 | #define TP_PSW_EJECT_BUTTON 5 /* FnF9 */ | | 83 | #define TP_PSW_EJECT_BUTTON 5 /* FnF9 */ |
66 | #define TP_PSW_ZOOM_BUTTON 6 /* FnSPACE */ | | 84 | #define TP_PSW_ZOOM_BUTTON 6 /* FnSPACE */ |
67 | #define TP_PSW_VENDOR_BUTTON 7 /* ThinkVantage */ | | 85 | #define TP_PSW_VENDOR_BUTTON 7 /* ThinkVantage */ |
68 | #define TP_PSW_FNF1_BUTTON 8 /* FnF1 */ | | 86 | #define TP_PSW_FNF1_BUTTON 8 /* FnF1 */ |
| @@ -80,26 +98,34 @@ typedef struct thinkpad_softc { | | | @@ -80,26 +98,34 @@ typedef struct thinkpad_softc { |
80 | #define TP_PSW_STAR_BUTTON 20 | | 98 | #define TP_PSW_STAR_BUTTON 20 |
81 | #define TP_PSW_SCISSORS_BUTTON 21 | | 99 | #define TP_PSW_SCISSORS_BUTTON 21 |
82 | #define TP_PSW_BLUETOOTH_BUTTON 22 | | 100 | #define TP_PSW_BLUETOOTH_BUTTON 22 |
83 | #define TP_PSW_KEYBOARD_BUTTON 23 | | 101 | #define TP_PSW_KEYBOARD_BUTTON 23 |
84 | #define TP_PSW_LAST 24 | | 102 | #define TP_PSW_LAST 24 |
85 | | | 103 | |
86 | struct sysmon_pswitch sc_smpsw[TP_PSW_LAST]; | | 104 | struct sysmon_pswitch sc_smpsw[TP_PSW_LAST]; |
87 | bool sc_smpsw_valid; | | 105 | bool sc_smpsw_valid; |
88 | | | 106 | |
89 | struct sysmon_envsys *sc_sme; | | 107 | struct sysmon_envsys *sc_sme; |
90 | envsys_data_t sc_sensor[THINKPAD_NSENSORS]; | | 108 | envsys_data_t sc_sensor[THINKPAD_NSENSORS]; |
91 | | | 109 | |
92 | int sc_display_state; | | 110 | int sc_display_state; |
| | | 111 | |
| | | 112 | #define THINKPAD_BAT_ANY 0 |
| | | 113 | #define THINKPAD_BAT_PRIMARY 1 |
| | | 114 | #define THINKPAD_BAT_SECONDARY 2 |
| | | 115 | #define THINKPAD_BAT_LAST 3 |
| | | 116 | |
| | | 117 | tp_batctl_t sc_batctl; |
| | | 118 | tp_sysctl_param_t sc_scparam[THINKPAD_BAT_LAST]; |
93 | } thinkpad_softc_t; | | 119 | } thinkpad_softc_t; |
94 | | | 120 | |
95 | /* Hotkey events */ | | 121 | /* Hotkey events */ |
96 | #define THINKPAD_NOTIFY_FnF1 0x001 | | 122 | #define THINKPAD_NOTIFY_FnF1 0x001 |
97 | #define THINKPAD_NOTIFY_LockScreen 0x002 | | 123 | #define THINKPAD_NOTIFY_LockScreen 0x002 |
98 | #define THINKPAD_NOTIFY_BatteryInfo 0x003 | | 124 | #define THINKPAD_NOTIFY_BatteryInfo 0x003 |
99 | #define THINKPAD_NOTIFY_SleepButton 0x004 | | 125 | #define THINKPAD_NOTIFY_SleepButton 0x004 |
100 | #define THINKPAD_NOTIFY_WirelessSwitch 0x005 | | 126 | #define THINKPAD_NOTIFY_WirelessSwitch 0x005 |
101 | #define THINKPAD_NOTIFY_wWANSwitch 0x006 | | 127 | #define THINKPAD_NOTIFY_wWANSwitch 0x006 |
102 | #define THINKPAD_NOTIFY_DisplayCycle 0x007 | | 128 | #define THINKPAD_NOTIFY_DisplayCycle 0x007 |
103 | #define THINKPAD_NOTIFY_PointerSwitch 0x008 | | 129 | #define THINKPAD_NOTIFY_PointerSwitch 0x008 |
104 | #define THINKPAD_NOTIFY_EjectButton 0x009 | | 130 | #define THINKPAD_NOTIFY_EjectButton 0x009 |
105 | #define THINKPAD_NOTIFY_FnF10 0x00a /* XXX: Not seen on T61 */ | | 131 | #define THINKPAD_NOTIFY_FnF10 0x00a /* XXX: Not seen on T61 */ |
| @@ -120,26 +146,37 @@ typedef struct thinkpad_softc { | | | @@ -120,26 +146,37 @@ typedef struct thinkpad_softc { |
120 | | | 146 | |
121 | #define THINKPAD_CMOS_BRIGHTNESS_UP 0x04 | | 147 | #define THINKPAD_CMOS_BRIGHTNESS_UP 0x04 |
122 | #define THINKPAD_CMOS_BRIGHTNESS_DOWN 0x05 | | 148 | #define THINKPAD_CMOS_BRIGHTNESS_DOWN 0x05 |
123 | | | 149 | |
124 | #define THINKPAD_HKEY_VERSION_1 0x0100 | | 150 | #define THINKPAD_HKEY_VERSION_1 0x0100 |
125 | #define THINKPAD_HKEY_VERSION_2 0x0200 | | 151 | #define THINKPAD_HKEY_VERSION_2 0x0200 |
126 | | | 152 | |
127 | #define THINKPAD_DISPLAY_LCD 0x01 | | 153 | #define THINKPAD_DISPLAY_LCD 0x01 |
128 | #define THINKPAD_DISPLAY_CRT 0x02 | | 154 | #define THINKPAD_DISPLAY_CRT 0x02 |
129 | #define THINKPAD_DISPLAY_DVI 0x08 | | 155 | #define THINKPAD_DISPLAY_DVI 0x08 |
130 | #define THINKPAD_DISPLAY_ALL \ | | 156 | #define THINKPAD_DISPLAY_ALL \ |
131 | (THINKPAD_DISPLAY_LCD | THINKPAD_DISPLAY_CRT | THINKPAD_DISPLAY_DVI) | | 157 | (THINKPAD_DISPLAY_LCD | THINKPAD_DISPLAY_CRT | THINKPAD_DISPLAY_DVI) |
132 | | | 158 | |
| | | 159 | #define THINKPAD_GET_CHARGE_START "BCTG" |
| | | 160 | #define THINKPAD_SET_CHARGE_START "BCCS" |
| | | 161 | #define THINKPAD_GET_CHARGE_STOP "BCSG" |
| | | 162 | #define THINKPAD_SET_CHARGE_STOP "BCSS" |
| | | 163 | #define THINKPAD_GET_FORCE_DISCHARGE "BDSG" |
| | | 164 | #define THINKPAD_SET_FORCE_DISCHARGE "BDSS" |
| | | 165 | #define THINKPAD_GET_CHARGE_INHIBIT "BICG" |
| | | 166 | #define THINKPAD_SET_CHARGE_INHIBIT "BICS" |
| | | 167 | |
| | | 168 | #define THINKPAD_CALL_ERROR 0x80000000 |
| | | 169 | |
133 | #define THINKPAD_BLUETOOTH_HWPRESENT 0x01 | | 170 | #define THINKPAD_BLUETOOTH_HWPRESENT 0x01 |
134 | #define THINKPAD_BLUETOOTH_RADIOSSW 0x02 | | 171 | #define THINKPAD_BLUETOOTH_RADIOSSW 0x02 |
135 | #define THINKPAD_BLUETOOTH_RESUMECTRL 0x04 | | 172 | #define THINKPAD_BLUETOOTH_RESUMECTRL 0x04 |
136 | | | 173 | |
137 | #define THINKPAD_WWAN_HWPRESENT 0x01 | | 174 | #define THINKPAD_WWAN_HWPRESENT 0x01 |
138 | #define THINKPAD_WWAN_RADIOSSW 0x02 | | 175 | #define THINKPAD_WWAN_RADIOSSW 0x02 |
139 | #define THINKPAD_WWAN_RESUMECTRL 0x04 | | 176 | #define THINKPAD_WWAN_RESUMECTRL 0x04 |
140 | | | 177 | |
141 | #define THINKPAD_UWB_HWPRESENT 0x01 | | 178 | #define THINKPAD_UWB_HWPRESENT 0x01 |
142 | #define THINKPAD_UWB_RADIOSSW 0x02 | | 179 | #define THINKPAD_UWB_RADIOSSW 0x02 |
143 | | | 180 | |
144 | #define THINKPAD_RFK_BLUETOOTH 0 | | 181 | #define THINKPAD_RFK_BLUETOOTH 0 |
145 | #define THINKPAD_RFK_WWAN 1 | | 182 | #define THINKPAD_RFK_WWAN 1 |
| @@ -158,26 +195,29 @@ static void thinkpad_sensors_refresh(str | | | @@ -158,26 +195,29 @@ static void thinkpad_sensors_refresh(str |
158 | static void thinkpad_temp_refresh(struct sysmon_envsys *, envsys_data_t *); | | 195 | static void thinkpad_temp_refresh(struct sysmon_envsys *, envsys_data_t *); |
159 | static void thinkpad_fan_refresh(struct sysmon_envsys *, envsys_data_t *); | | 196 | static void thinkpad_fan_refresh(struct sysmon_envsys *, envsys_data_t *); |
160 | | | 197 | |
161 | static void thinkpad_uwb_toggle(thinkpad_softc_t *); | | 198 | static void thinkpad_uwb_toggle(thinkpad_softc_t *); |
162 | static void thinkpad_wwan_toggle(thinkpad_softc_t *); | | 199 | static void thinkpad_wwan_toggle(thinkpad_softc_t *); |
163 | static void thinkpad_bluetooth_toggle(thinkpad_softc_t *); | | 200 | static void thinkpad_bluetooth_toggle(thinkpad_softc_t *); |
164 | | | 201 | |
165 | static bool thinkpad_resume(device_t, const pmf_qual_t *); | | 202 | static bool thinkpad_resume(device_t, const pmf_qual_t *); |
166 | static void thinkpad_brightness_up(device_t); | | 203 | static void thinkpad_brightness_up(device_t); |
167 | static void thinkpad_brightness_down(device_t); | | 204 | static void thinkpad_brightness_down(device_t); |
168 | static uint8_t thinkpad_brightness_read(thinkpad_softc_t *); | | 205 | static uint8_t thinkpad_brightness_read(thinkpad_softc_t *); |
169 | static void thinkpad_cmos(thinkpad_softc_t *, uint8_t); | | 206 | static void thinkpad_cmos(thinkpad_softc_t *, uint8_t); |
170 | | | 207 | |
| | | 208 | static void thinkpad_battery_probe_support(device_t); |
| | | 209 | static void thinkpad_battery_sysctl_setup(device_t); |
| | | 210 | |
171 | CFATTACH_DECL3_NEW(thinkpad, sizeof(thinkpad_softc_t), | | 211 | CFATTACH_DECL3_NEW(thinkpad, sizeof(thinkpad_softc_t), |
172 | thinkpad_match, thinkpad_attach, thinkpad_detach, NULL, NULL, NULL, | | 212 | thinkpad_match, thinkpad_attach, thinkpad_detach, NULL, NULL, NULL, |
173 | 0); | | 213 | 0); |
174 | | | 214 | |
175 | static const struct device_compatible_entry compat_data[] = { | | 215 | static const struct device_compatible_entry compat_data[] = { |
176 | { .compat = "IBM0068" }, | | 216 | { .compat = "IBM0068" }, |
177 | { .compat = "LEN0068" }, | | 217 | { .compat = "LEN0068" }, |
178 | { .compat = "LEN0268" }, | | 218 | { .compat = "LEN0268" }, |
179 | DEVICE_COMPAT_EOL | | 219 | DEVICE_COMPAT_EOL |
180 | }; | | 220 | }; |
181 | | | 221 | |
182 | static int | | 222 | static int |
183 | thinkpad_match(device_t parent, cfdata_t match, void *opaque) | | 223 | thinkpad_match(device_t parent, cfdata_t match, void *opaque) |
| @@ -210,26 +250,27 @@ thinkpad_match(device_t parent, cfdata_t | | | @@ -210,26 +250,27 @@ thinkpad_match(device_t parent, cfdata_t |
210 | static void | | 250 | static void |
211 | thinkpad_attach(device_t parent, device_t self, void *opaque) | | 251 | thinkpad_attach(device_t parent, device_t self, void *opaque) |
212 | { | | 252 | { |
213 | thinkpad_softc_t *sc = device_private(self); | | 253 | thinkpad_softc_t *sc = device_private(self); |
214 | struct acpi_attach_args *aa = (struct acpi_attach_args *)opaque; | | 254 | struct acpi_attach_args *aa = (struct acpi_attach_args *)opaque; |
215 | struct sysmon_pswitch *psw; | | 255 | struct sysmon_pswitch *psw; |
216 | device_t curdev; | | 256 | device_t curdev; |
217 | deviter_t di; | | 257 | deviter_t di; |
218 | ACPI_STATUS rv; | | 258 | ACPI_STATUS rv; |
219 | ACPI_INTEGER val; | | 259 | ACPI_INTEGER val; |
220 | int i; | | 260 | int i; |
221 | | | 261 | |
222 | sc->sc_dev = self; | | 262 | sc->sc_dev = self; |
| | | 263 | sc->sc_log = NULL; |
223 | sc->sc_powhdl = NULL; | | 264 | sc->sc_powhdl = NULL; |
224 | sc->sc_cmoshdl = NULL; | | 265 | sc->sc_cmoshdl = NULL; |
225 | sc->sc_node = aa->aa_node; | | 266 | sc->sc_node = aa->aa_node; |
226 | sc->sc_display_state = THINKPAD_DISPLAY_LCD; | | 267 | sc->sc_display_state = THINKPAD_DISPLAY_LCD; |
227 | | | 268 | |
228 | aprint_naive("\n"); | | 269 | aprint_naive("\n"); |
229 | aprint_normal("\n"); | | 270 | aprint_normal("\n"); |
230 | | | 271 | |
231 | sc->sc_ecdev = NULL; | | 272 | sc->sc_ecdev = NULL; |
232 | for (curdev = deviter_first(&di, DEVITER_F_ROOT_FIRST); | | 273 | for (curdev = deviter_first(&di, DEVITER_F_ROOT_FIRST); |
233 | curdev != NULL; curdev = deviter_next(&di)) | | 274 | curdev != NULL; curdev = deviter_next(&di)) |
234 | if (device_is_a(curdev, "acpiecdt") || | | 275 | if (device_is_a(curdev, "acpiecdt") || |
235 | device_is_a(curdev, "acpiec")) { | | 276 | device_is_a(curdev, "acpiec")) { |
| @@ -361,51 +402,65 @@ thinkpad_attach(device_t parent, device_ | | | @@ -361,51 +402,65 @@ thinkpad_attach(device_t parent, device_ |
361 | if (i == TP_PSW_HIBERNATE) | | 402 | if (i == TP_PSW_HIBERNATE) |
362 | continue; | | 403 | continue; |
363 | if (sysmon_pswitch_register(&sc->sc_smpsw[i]) != 0) { | | 404 | if (sysmon_pswitch_register(&sc->sc_smpsw[i]) != 0) { |
364 | aprint_error_dev(self, | | 405 | aprint_error_dev(self, |
365 | "couldn't register with sysmon\n"); | | 406 | "couldn't register with sysmon\n"); |
366 | sc->sc_smpsw_valid = false; | | 407 | sc->sc_smpsw_valid = false; |
367 | break; | | 408 | break; |
368 | } | | 409 | } |
369 | } | | 410 | } |
370 | | | 411 | |
371 | /* Register temperature and fan sensors with envsys */ | | 412 | /* Register temperature and fan sensors with envsys */ |
372 | thinkpad_sensors_init(sc); | | 413 | thinkpad_sensors_init(sc); |
373 | | | 414 | |
| | | 415 | /* Probe supported battery charge/control operations */ |
| | | 416 | thinkpad_battery_probe_support(self); |
| | | 417 | |
| | | 418 | if (sc->sc_batctl.have_any) { |
| | | 419 | for (i = 0; i < THINKPAD_BAT_LAST; i++) { |
| | | 420 | sc->sc_scparam[i].sp_dev = self; |
| | | 421 | sc->sc_scparam[i].sp_bat = i; |
| | | 422 | } |
| | | 423 | thinkpad_battery_sysctl_setup(self); |
| | | 424 | } |
| | | 425 | |
374 | fail: | | 426 | fail: |
375 | if (!pmf_device_register(self, NULL, thinkpad_resume)) | | 427 | if (!pmf_device_register(self, NULL, thinkpad_resume)) |
376 | aprint_error_dev(self, "couldn't establish power handler\n"); | | 428 | aprint_error_dev(self, "couldn't establish power handler\n"); |
377 | if (!pmf_event_register(self, PMFE_DISPLAY_BRIGHTNESS_UP, | | 429 | if (!pmf_event_register(self, PMFE_DISPLAY_BRIGHTNESS_UP, |
378 | thinkpad_brightness_up, true)) | | 430 | thinkpad_brightness_up, true)) |
379 | aprint_error_dev(self, "couldn't register event handler\n"); | | 431 | aprint_error_dev(self, "couldn't register event handler\n"); |
380 | if (!pmf_event_register(self, PMFE_DISPLAY_BRIGHTNESS_DOWN, | | 432 | if (!pmf_event_register(self, PMFE_DISPLAY_BRIGHTNESS_DOWN, |
381 | thinkpad_brightness_down, true)) | | 433 | thinkpad_brightness_down, true)) |
382 | aprint_error_dev(self, "couldn't register event handler\n"); | | 434 | aprint_error_dev(self, "couldn't register event handler\n"); |
383 | } | | 435 | } |
384 | | | 436 | |
385 | static int | | 437 | static int |
386 | thinkpad_detach(device_t self, int flags) | | 438 | thinkpad_detach(device_t self, int flags) |
387 | { | | 439 | { |
388 | struct thinkpad_softc *sc = device_private(self); | | 440 | struct thinkpad_softc *sc = device_private(self); |
389 | int i; | | 441 | int i; |
390 | | | 442 | |
391 | acpi_deregister_notify(sc->sc_node); | | 443 | acpi_deregister_notify(sc->sc_node); |
392 | | | 444 | |
393 | for (i = 0; i < TP_PSW_LAST; i++) | | 445 | for (i = 0; i < TP_PSW_LAST; i++) |
394 | sysmon_pswitch_unregister(&sc->sc_smpsw[i]); | | 446 | sysmon_pswitch_unregister(&sc->sc_smpsw[i]); |
395 | | | 447 | |
396 | if (sc->sc_sme != NULL) | | 448 | if (sc->sc_sme != NULL) |
397 | sysmon_envsys_unregister(sc->sc_sme); | | 449 | sysmon_envsys_unregister(sc->sc_sme); |
398 | | | 450 | |
| | | 451 | if (sc->sc_log != NULL) |
| | | 452 | sysctl_teardown(&sc->sc_log); |
| | | 453 | |
399 | pmf_device_deregister(self); | | 454 | pmf_device_deregister(self); |
400 | | | 455 | |
401 | pmf_event_deregister(self, PMFE_DISPLAY_BRIGHTNESS_UP, | | 456 | pmf_event_deregister(self, PMFE_DISPLAY_BRIGHTNESS_UP, |
402 | thinkpad_brightness_up, true); | | 457 | thinkpad_brightness_up, true); |
403 | | | 458 | |
404 | pmf_event_deregister(self, PMFE_DISPLAY_BRIGHTNESS_DOWN, | | 459 | pmf_event_deregister(self, PMFE_DISPLAY_BRIGHTNESS_DOWN, |
405 | thinkpad_brightness_down, true); | | 460 | thinkpad_brightness_down, true); |
406 | | | 461 | |
407 | return 0; | | 462 | return 0; |
408 | } | | 463 | } |
409 | | | 464 | |
410 | static void | | 465 | static void |
411 | thinkpad_notify_handler(ACPI_HANDLE hdl, uint32_t notify, void *opaque) | | 466 | thinkpad_notify_handler(ACPI_HANDLE hdl, uint32_t notify, void *opaque) |
| @@ -938,26 +993,310 @@ thinkpad_cmos(thinkpad_softc_t *sc, uint | | | @@ -938,26 +993,310 @@ thinkpad_cmos(thinkpad_softc_t *sc, uint |
938 | { | | 993 | { |
939 | ACPI_STATUS rv; | | 994 | ACPI_STATUS rv; |
940 | | | 995 | |
941 | if (sc->sc_cmoshdl == NULL) | | 996 | if (sc->sc_cmoshdl == NULL) |
942 | return; | | 997 | return; |
943 | | | 998 | |
944 | rv = acpi_eval_set_integer(sc->sc_cmoshdl, NULL, cmd); | | 999 | rv = acpi_eval_set_integer(sc->sc_cmoshdl, NULL, cmd); |
945 | | | 1000 | |
946 | if (ACPI_FAILURE(rv)) | | 1001 | if (ACPI_FAILURE(rv)) |
947 | aprint_error_dev(sc->sc_dev, "couldn't evaluate CMOS: %s\n", | | 1002 | aprint_error_dev(sc->sc_dev, "couldn't evaluate CMOS: %s\n", |
948 | AcpiFormatException(rv)); | | 1003 | AcpiFormatException(rv)); |
949 | } | | 1004 | } |
950 | | | 1005 | |
| | | 1006 | static uint32_t |
| | | 1007 | thinkpad_call_method(device_t self, const char *path, uint32_t arg) |
| | | 1008 | { |
| | | 1009 | thinkpad_softc_t *sc = device_private(self); |
| | | 1010 | ACPI_HANDLE handle = sc->sc_node->ad_handle; |
| | | 1011 | ACPI_OBJECT args[1]; |
| | | 1012 | ACPI_OBJECT_LIST arg_list; |
| | | 1013 | ACPI_OBJECT rval; |
| | | 1014 | ACPI_BUFFER buf; |
| | | 1015 | ACPI_STATUS rv; |
| | | 1016 | |
| | | 1017 | args[0].Type = ACPI_TYPE_INTEGER; |
| | | 1018 | args[0].Integer.Value = arg; |
| | | 1019 | arg_list.Pointer = &args[0]; |
| | | 1020 | arg_list.Count = __arraycount(args); |
| | | 1021 | |
| | | 1022 | memset(&rval, 0, sizeof rval); |
| | | 1023 | buf.Pointer = &rval; |
| | | 1024 | buf.Length = sizeof rval; |
| | | 1025 | |
| | | 1026 | rv = AcpiEvaluateObjectTyped(handle, path, &arg_list, &buf, |
| | | 1027 | ACPI_TYPE_INTEGER); |
| | | 1028 | |
| | | 1029 | if (ACPI_FAILURE(rv)) { |
| | | 1030 | aprint_error_dev(self, "call %s.%s(%x) failed: %s\n", |
| | | 1031 | acpi_name(handle), path, (unsigned)arg, |
| | | 1032 | AcpiFormatException(rv)); |
| | | 1033 | return THINKPAD_CALL_ERROR; |
| | | 1034 | } |
| | | 1035 | |
| | | 1036 | return rval.Integer.Value; |
| | | 1037 | } |
| | | 1038 | |
| | | 1039 | static void |
| | | 1040 | thinkpad_battery_probe_support(device_t self) |
| | | 1041 | { |
| | | 1042 | thinkpad_softc_t *sc = device_private(self); |
| | | 1043 | ACPI_HANDLE hdl = sc->sc_node->ad_handle, tmp; |
| | | 1044 | ACPI_STATUS rv; |
| | | 1045 | uint32_t val; |
| | | 1046 | |
| | | 1047 | sc->sc_batctl.have_any = 0; |
| | | 1048 | |
| | | 1049 | rv = AcpiGetHandle(hdl, THINKPAD_GET_CHARGE_START, &tmp); |
| | | 1050 | if (ACPI_SUCCESS(rv)) { |
| | | 1051 | val = thinkpad_call_method(self, THINKPAD_GET_CHARGE_START, |
| | | 1052 | THINKPAD_BAT_PRIMARY); |
| | | 1053 | if (!(val & THINKPAD_CALL_ERROR) && (val & 0x100)) { |
| | | 1054 | sc->sc_batctl.have.charge_start = 1; |
| | | 1055 | if (val & 0x200) |
| | | 1056 | sc->sc_batctl.have.individual_control = 1; |
| | | 1057 | } |
| | | 1058 | } |
| | | 1059 | |
| | | 1060 | rv = AcpiGetHandle(hdl, THINKPAD_GET_CHARGE_STOP, &tmp); |
| | | 1061 | if (ACPI_SUCCESS(rv)) { |
| | | 1062 | val = thinkpad_call_method(self, THINKPAD_GET_CHARGE_STOP, |
| | | 1063 | THINKPAD_BAT_PRIMARY); |
| | | 1064 | if (!(val & THINKPAD_CALL_ERROR) && (val & 0x100)) |
| | | 1065 | sc->sc_batctl.have.charge_stop = 1; |
| | | 1066 | } |
| | | 1067 | |
| | | 1068 | rv = AcpiGetHandle(hdl, THINKPAD_GET_FORCE_DISCHARGE, &tmp); |
| | | 1069 | if (ACPI_SUCCESS(rv)) { |
| | | 1070 | val = thinkpad_call_method(self, THINKPAD_GET_FORCE_DISCHARGE, |
| | | 1071 | THINKPAD_BAT_PRIMARY); |
| | | 1072 | if (!(val & THINKPAD_CALL_ERROR) && (val & 0x100)) |
| | | 1073 | sc->sc_batctl.have.force_discharge = 1; |
| | | 1074 | } |
| | | 1075 | |
| | | 1076 | rv = AcpiGetHandle(hdl, THINKPAD_GET_CHARGE_INHIBIT, &tmp); |
| | | 1077 | if (ACPI_SUCCESS(rv)) { |
| | | 1078 | val = thinkpad_call_method(self, THINKPAD_GET_CHARGE_INHIBIT, |
| | | 1079 | THINKPAD_BAT_PRIMARY); |
| | | 1080 | if (!(val & THINKPAD_CALL_ERROR) && (val & 0x20)) |
| | | 1081 | sc->sc_batctl.have.charge_inhibit = 1; |
| | | 1082 | } |
| | | 1083 | |
| | | 1084 | if (sc->sc_batctl.have_any) |
| | | 1085 | aprint_verbose_dev(self, "battery control capabilities: %x\n", |
| | | 1086 | sc->sc_batctl.have_any); |
| | | 1087 | } |
| | | 1088 | |
| | | 1089 | static int |
| | | 1090 | thinkpad_battery_sysctl_charge_start(SYSCTLFN_ARGS) |
| | | 1091 | { |
| | | 1092 | struct sysctlnode node = *rnode; |
| | | 1093 | tp_sysctl_param_t *sp = node.sysctl_data; |
| | | 1094 | int charge_start; |
| | | 1095 | int err; |
| | | 1096 | |
| | | 1097 | charge_start = thinkpad_call_method(sp->sp_dev, |
| | | 1098 | THINKPAD_GET_CHARGE_START, sp->sp_bat) & 0xff; |
| | | 1099 | |
| | | 1100 | node.sysctl_data = &charge_start; |
| | | 1101 | err = sysctl_lookup(SYSCTLFN_CALL(&node)); |
| | | 1102 | if (err || newp == NULL) |
| | | 1103 | return err; |
| | | 1104 | |
| | | 1105 | if (charge_start < 0 || charge_start > 99) |
| | | 1106 | return EINVAL; |
| | | 1107 | |
| | | 1108 | if (thinkpad_call_method(sp->sp_dev, THINKPAD_SET_CHARGE_START, |
| | | 1109 | charge_start | sp->sp_bat<<8) & THINKPAD_CALL_ERROR) |
| | | 1110 | return EIO; |
| | | 1111 | |
| | | 1112 | return 0; |
| | | 1113 | } |
| | | 1114 | |
| | | 1115 | static int |
| | | 1116 | thinkpad_battery_sysctl_charge_stop(SYSCTLFN_ARGS) |
| | | 1117 | { |
| | | 1118 | struct sysctlnode node = *rnode; |
| | | 1119 | tp_sysctl_param_t *sp = node.sysctl_data; |
| | | 1120 | int charge_stop; |
| | | 1121 | int err; |
| | | 1122 | |
| | | 1123 | charge_stop = thinkpad_call_method(sp->sp_dev, |
| | | 1124 | THINKPAD_GET_CHARGE_STOP, sp->sp_bat) & 0xff; |
| | | 1125 | |
| | | 1126 | if (charge_stop == 0) |
| | | 1127 | charge_stop = 100; |
| | | 1128 | |
| | | 1129 | node.sysctl_data = &charge_stop; |
| | | 1130 | err = sysctl_lookup(SYSCTLFN_CALL(&node)); |
| | | 1131 | if (err || newp == NULL) |
| | | 1132 | return err; |
| | | 1133 | |
| | | 1134 | if (charge_stop < 1 || charge_stop > 100) |
| | | 1135 | return EINVAL; |
| | | 1136 | |
| | | 1137 | if (charge_stop == 100) |
| | | 1138 | charge_stop = 0; |
| | | 1139 | |
| | | 1140 | if (thinkpad_call_method(sp->sp_dev, THINKPAD_SET_CHARGE_STOP, |
| | | 1141 | charge_stop | sp->sp_bat<<8) & THINKPAD_CALL_ERROR) |
| | | 1142 | return EIO; |
| | | 1143 | |
| | | 1144 | return 0; |
| | | 1145 | } |
| | | 1146 | |
| | | 1147 | static int |
| | | 1148 | thinkpad_battery_sysctl_charge_inhibit(SYSCTLFN_ARGS) |
| | | 1149 | { |
| | | 1150 | struct sysctlnode node = *rnode; |
| | | 1151 | tp_sysctl_param_t *sp = node.sysctl_data; |
| | | 1152 | bool charge_inhibit; |
| | | 1153 | int err; |
| | | 1154 | |
| | | 1155 | charge_inhibit = thinkpad_call_method(sp->sp_dev, |
| | | 1156 | THINKPAD_GET_CHARGE_INHIBIT, sp->sp_bat) & 0x01; |
| | | 1157 | |
| | | 1158 | node.sysctl_data = &charge_inhibit; |
| | | 1159 | err = sysctl_lookup(SYSCTLFN_CALL(&node)); |
| | | 1160 | if (err || newp == NULL) |
| | | 1161 | return err; |
| | | 1162 | |
| | | 1163 | if (thinkpad_call_method(sp->sp_dev, THINKPAD_SET_CHARGE_INHIBIT, |
| | | 1164 | charge_inhibit | sp->sp_bat<<4 | 0xffff<<8) & THINKPAD_CALL_ERROR) |
| | | 1165 | return EIO; |
| | | 1166 | |
| | | 1167 | return 0; |
| | | 1168 | } |
| | | 1169 | |
| | | 1170 | static int |
| | | 1171 | thinkpad_battery_sysctl_force_discharge(SYSCTLFN_ARGS) |
| | | 1172 | { |
| | | 1173 | struct sysctlnode node = *rnode; |
| | | 1174 | tp_sysctl_param_t *sp = node.sysctl_data; |
| | | 1175 | bool force_discharge; |
| | | 1176 | int err; |
| | | 1177 | |
| | | 1178 | force_discharge = thinkpad_call_method(sp->sp_dev, |
| | | 1179 | THINKPAD_GET_FORCE_DISCHARGE, sp->sp_bat) & 0x01; |
| | | 1180 | |
| | | 1181 | node.sysctl_data = &force_discharge; |
| | | 1182 | err = sysctl_lookup(SYSCTLFN_CALL(&node)); |
| | | 1183 | if (err || newp == NULL) |
| | | 1184 | return err; |
| | | 1185 | |
| | | 1186 | if (thinkpad_call_method(sp->sp_dev, THINKPAD_SET_FORCE_DISCHARGE, |
| | | 1187 | force_discharge | sp->sp_bat<<8) & THINKPAD_CALL_ERROR) |
| | | 1188 | return EIO; |
| | | 1189 | |
| | | 1190 | return 0; |
| | | 1191 | } |
| | | 1192 | |
| | | 1193 | static void |
| | | 1194 | thinkpad_battery_sysctl_setup_controls(device_t self, |
| | | 1195 | const struct sysctlnode *rnode, int battery) |
| | | 1196 | { |
| | | 1197 | thinkpad_softc_t *sc = device_private(self); |
| | | 1198 | |
| | | 1199 | if (sc->sc_batctl.have.charge_start) |
| | | 1200 | (void)sysctl_createv(&sc->sc_log, 0, &rnode, NULL, |
| | | 1201 | CTLFLAG_READWRITE, CTLTYPE_INT, "charge_start", |
| | | 1202 | SYSCTL_DESCR("charge start threshold (0-99)"), |
| | | 1203 | thinkpad_battery_sysctl_charge_start, 0, |
| | | 1204 | (void *)&(sc->sc_scparam[battery]), 0, |
| | | 1205 | CTL_CREATE, CTL_EOL); |
| | | 1206 | |
| | | 1207 | if (sc->sc_batctl.have.charge_stop) |
| | | 1208 | (void)sysctl_createv(&sc->sc_log, 0, &rnode, NULL, |
| | | 1209 | CTLFLAG_READWRITE, CTLTYPE_INT, "charge_stop", |
| | | 1210 | SYSCTL_DESCR("charge stop threshold (1-100)"), |
| | | 1211 | thinkpad_battery_sysctl_charge_stop, 0, |
| | | 1212 | (void *)&(sc->sc_scparam[battery]), 0, |
| | | 1213 | CTL_CREATE, CTL_EOL); |
| | | 1214 | |
| | | 1215 | if (sc->sc_batctl.have.charge_inhibit) |
| | | 1216 | (void)sysctl_createv(&sc->sc_log, 0, &rnode, NULL, |
| | | 1217 | CTLFLAG_READWRITE, CTLTYPE_BOOL, "charge_inhibit", |
| | | 1218 | SYSCTL_DESCR("charge inhibit"), |
| | | 1219 | thinkpad_battery_sysctl_charge_inhibit, 0, |
| | | 1220 | (void *)&(sc->sc_scparam[battery]), 0, |
| | | 1221 | CTL_CREATE, CTL_EOL); |
| | | 1222 | |
| | | 1223 | if (sc->sc_batctl.have.force_discharge) |
| | | 1224 | (void)sysctl_createv(&sc->sc_log, 0, &rnode, NULL, |
| | | 1225 | CTLFLAG_READWRITE, CTLTYPE_BOOL, "force_discharge", |
| | | 1226 | SYSCTL_DESCR("force discharge"), |
| | | 1227 | thinkpad_battery_sysctl_force_discharge, 0, |
| | | 1228 | (void *)&(sc->sc_scparam[battery]), 0, |
| | | 1229 | CTL_CREATE, CTL_EOL); |
| | | 1230 | } |
| | | 1231 | |
| | | 1232 | static void |
| | | 1233 | thinkpad_battery_sysctl_setup(device_t self) |
| | | 1234 | { |
| | | 1235 | thinkpad_softc_t *sc = device_private(self); |
| | | 1236 | const struct sysctlnode *rnode, *cnode; |
| | | 1237 | int err; |
| | | 1238 | |
| | | 1239 | err = sysctl_createv(&sc->sc_log, 0, NULL, &rnode, |
| | | 1240 | 0, CTLTYPE_NODE, "acpi", NULL, |
| | | 1241 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); |
| | | 1242 | if (err) |
| | | 1243 | goto fail; |
| | | 1244 | |
| | | 1245 | err = sysctl_createv(&sc->sc_log, 0, &rnode, &rnode, |
| | | 1246 | 0, CTLTYPE_NODE, device_xname(self), |
| | | 1247 | SYSCTL_DESCR("ThinkPad ACPI controls"), |
| | | 1248 | NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); |
| | | 1249 | if (err) |
| | | 1250 | goto fail; |
| | | 1251 | |
| | | 1252 | if (sc->sc_batctl.have.individual_control) { |
| | | 1253 | err = sysctl_createv(&sc->sc_log, 0, &rnode, &cnode, |
| | | 1254 | 0, CTLTYPE_NODE, "bat0", |
| | | 1255 | SYSCTL_DESCR("battery charge controls (primary battery)"), |
| | | 1256 | NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); |
| | | 1257 | if (err) |
| | | 1258 | goto fail; |
| | | 1259 | |
| | | 1260 | thinkpad_battery_sysctl_setup_controls(self, cnode, |
| | | 1261 | THINKPAD_BAT_PRIMARY); |
| | | 1262 | |
| | | 1263 | err = sysctl_createv(&sc->sc_log, 0, &rnode, &cnode, |
| | | 1264 | 0, CTLTYPE_NODE, "bat1", |
| | | 1265 | SYSCTL_DESCR("battery charge controls (secondary battery)"), |
| | | 1266 | NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); |
| | | 1267 | if (err) |
| | | 1268 | goto fail; |
| | | 1269 | |
| | | 1270 | thinkpad_battery_sysctl_setup_controls(self, cnode, |
| | | 1271 | THINKPAD_BAT_SECONDARY); |
| | | 1272 | } else { |
| | | 1273 | err = sysctl_createv(&sc->sc_log, 0, &rnode, &cnode, |
| | | 1274 | 0, CTLTYPE_NODE, "bat", |
| | | 1275 | SYSCTL_DESCR("battery charge controls"), |
| | | 1276 | NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); |
| | | 1277 | if (err) |
| | | 1278 | goto fail; |
| | | 1279 | |
| | | 1280 | thinkpad_battery_sysctl_setup_controls(self, cnode, |
| | | 1281 | THINKPAD_BAT_ANY); |
| | | 1282 | } |
| | | 1283 | |
| | | 1284 | return; |
| | | 1285 | |
| | | 1286 | fail: |
| | | 1287 | aprint_error_dev(self, "unable to add sysctl nodes (%d)\n", err); |
| | | 1288 | } |
| | | 1289 | |
951 | static bool | | 1290 | static bool |
952 | thinkpad_resume(device_t dv, const pmf_qual_t *qual) | | 1291 | thinkpad_resume(device_t dv, const pmf_qual_t *qual) |
953 | { | | 1292 | { |
954 | thinkpad_softc_t *sc = device_private(dv); | | 1293 | thinkpad_softc_t *sc = device_private(dv); |
955 | | | 1294 | |
956 | if (sc->sc_powhdl == NULL) | | 1295 | if (sc->sc_powhdl == NULL) |
957 | return true; | | 1296 | return true; |
958 | | | 1297 | |
959 | (void)acpi_power_res(sc->sc_powhdl, sc->sc_node->ad_handle, true); | | 1298 | (void)acpi_power_res(sc->sc_powhdl, sc->sc_node->ad_handle, true); |
960 | | | 1299 | |
961 | return true; | | 1300 | return true; |
962 | } | | 1301 | } |
963 | | | 1302 | |