1 1.18 riastrad /* $NetBSD: smbus_acpi.c,v 1.18 2022/10/24 10:17:27 riastradh Exp $ */ 2 1.1 pgoyette 3 1.1 pgoyette /*- 4 1.1 pgoyette * Copyright (c) 2009 The NetBSD Foundation, Inc. 5 1.1 pgoyette * All rights reserved. 6 1.1 pgoyette * 7 1.1 pgoyette * This code is derived from software contributed to The NetBSD Foundation 8 1.1 pgoyette * by Paul Goyette 9 1.1 pgoyette * 10 1.1 pgoyette * Redistribution and use in source and binary forms, with or without 11 1.1 pgoyette * modification, are permitted provided that the following conditions 12 1.1 pgoyette * are met: 13 1.1 pgoyette * 1. Redistributions of source code must retain the above copyright 14 1.1 pgoyette * notice, this list of conditions and the following disclaimer. 15 1.1 pgoyette * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 pgoyette * notice, this list of conditions and the following disclaimer in the 17 1.1 pgoyette * documentation and/or other materials provided with the distribution. 18 1.1 pgoyette * 19 1.1 pgoyette * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 pgoyette * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 pgoyette * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 pgoyette * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 pgoyette * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 pgoyette * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 pgoyette * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 pgoyette * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 pgoyette * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 pgoyette * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 pgoyette * POSSIBILITY OF SUCH DAMAGE. 30 1.1 pgoyette */ 31 1.1 pgoyette 32 1.1 pgoyette /* 33 1.1 pgoyette * ACPI SMBus Controller driver 34 1.1 pgoyette * 35 1.1 pgoyette * See http://smbus.org/specs/smbus_cmi10.pdf for specifications 36 1.1 pgoyette */ 37 1.1 pgoyette 38 1.1 pgoyette #include <sys/cdefs.h> 39 1.18 riastrad __KERNEL_RCSID(0, "$NetBSD: smbus_acpi.c,v 1.18 2022/10/24 10:17:27 riastradh Exp $"); 40 1.1 pgoyette 41 1.1 pgoyette #include <sys/param.h> 42 1.1 pgoyette #include <sys/device.h> 43 1.1 pgoyette #include <sys/callout.h> 44 1.9 jruoho #include <sys/kernel.h> 45 1.1 pgoyette #include <sys/mutex.h> 46 1.9 jruoho #include <sys/systm.h> 47 1.1 pgoyette 48 1.1 pgoyette #include <dev/acpi/acpireg.h> 49 1.1 pgoyette #include <dev/acpi/acpivar.h> 50 1.1 pgoyette 51 1.1 pgoyette #include <dev/i2c/i2cvar.h> 52 1.1 pgoyette 53 1.7 jruoho #define _COMPONENT ACPI_BUS_COMPONENT 54 1.7 jruoho ACPI_MODULE_NAME ("smbus_acpi") 55 1.7 jruoho 56 1.1 pgoyette /* 57 1.13 jruoho * ACPI SMBus CMI protocol codes. 58 1.1 pgoyette */ 59 1.1 pgoyette #define ACPI_SMBUS_RD_QUICK 0x03 60 1.1 pgoyette #define ACPI_SMBUS_RCV_BYTE 0x05 61 1.1 pgoyette #define ACPI_SMBUS_RD_BYTE 0x07 62 1.1 pgoyette #define ACPI_SMBUS_RD_WORD 0x09 63 1.1 pgoyette #define ACPI_SMBUS_RD_BLOCK 0x0B 64 1.1 pgoyette #define ACPI_SMBUS_WR_QUICK 0x02 65 1.1 pgoyette #define ACPI_SMBUS_SND_BYTE 0x04 66 1.1 pgoyette #define ACPI_SMBUS_WR_BYTE 0x06 67 1.1 pgoyette #define ACPI_SMBUS_WR_WORD 0x08 68 1.1 pgoyette #define ACPI_SMBUS_WR_BLOCK 0x0A 69 1.1 pgoyette #define ACPI_SMBUS_PROCESS_CALL 0x0C 70 1.1 pgoyette 71 1.1 pgoyette struct acpi_smbus_softc { 72 1.1 pgoyette struct acpi_devnode *sc_devnode; 73 1.1 pgoyette struct callout sc_callout; 74 1.1 pgoyette struct i2c_controller sc_i2c_tag; 75 1.1 pgoyette device_t sc_dv; 76 1.1 pgoyette int sc_poll_alert; 77 1.1 pgoyette }; 78 1.1 pgoyette 79 1.1 pgoyette static int acpi_smbus_match(device_t, cfdata_t, void *); 80 1.1 pgoyette static void acpi_smbus_attach(device_t, device_t, void *); 81 1.2 jruoho static int acpi_smbus_detach(device_t, int); 82 1.13 jruoho static int acpi_smbus_poll_alert(ACPI_HANDLE, int *); 83 1.1 pgoyette static int acpi_smbus_exec(void *, i2c_op_t, i2c_addr_t, const void *, 84 1.1 pgoyette size_t, void *, size_t, int); 85 1.1 pgoyette static void acpi_smbus_alerts(struct acpi_smbus_softc *); 86 1.1 pgoyette static void acpi_smbus_tick(void *); 87 1.2 jruoho static void acpi_smbus_notify_handler(ACPI_HANDLE, uint32_t, void *); 88 1.1 pgoyette 89 1.1 pgoyette struct SMB_UDID { 90 1.1 pgoyette uint8_t dev_cap; 91 1.1 pgoyette uint8_t vers_rev; 92 1.1 pgoyette uint16_t vendor; 93 1.1 pgoyette uint16_t device; 94 1.1 pgoyette uint16_t interface; 95 1.1 pgoyette uint16_t subsys_vendor; 96 1.1 pgoyette uint16_t subsys_device; 97 1.1 pgoyette uint8_t reserved[4]; 98 1.1 pgoyette }; 99 1.1 pgoyette 100 1.1 pgoyette struct SMB_DEVICE { 101 1.1 pgoyette uint8_t slave_addr; 102 1.1 pgoyette uint8_t reserved; 103 1.1 pgoyette struct SMB_UDID dev_id; 104 1.1 pgoyette }; 105 1.1 pgoyette 106 1.1 pgoyette struct SMB_INFO { 107 1.1 pgoyette uint8_t struct_ver; 108 1.1 pgoyette uint8_t spec_ver; 109 1.1 pgoyette uint8_t hw_cap; 110 1.1 pgoyette uint8_t poll_int; 111 1.1 pgoyette uint8_t dev_count; 112 1.1 pgoyette struct SMB_DEVICE device[1]; 113 1.1 pgoyette }; 114 1.1 pgoyette 115 1.15 thorpej static const struct device_compatible_entry compat_data[] = { 116 1.15 thorpej { .compat = "SMBUS01" }, /* SMBus CMI v1.0 */ 117 1.15 thorpej DEVICE_COMPAT_EOL 118 1.1 pgoyette }; 119 1.1 pgoyette 120 1.1 pgoyette CFATTACH_DECL_NEW(acpismbus, sizeof(struct acpi_smbus_softc), 121 1.1 pgoyette acpi_smbus_match, acpi_smbus_attach, acpi_smbus_detach, NULL); 122 1.1 pgoyette 123 1.1 pgoyette static int 124 1.1 pgoyette acpi_smbus_match(device_t parent, cfdata_t match, void *aux) 125 1.1 pgoyette { 126 1.1 pgoyette struct acpi_attach_args *aa = aux; 127 1.15 thorpej int ret; 128 1.1 pgoyette 129 1.15 thorpej ret = acpi_compatible_match(aa, compat_data); 130 1.15 thorpej if (ret == 0) 131 1.1 pgoyette return 0; 132 1.1 pgoyette 133 1.15 thorpej return acpi_smbus_poll_alert(aa->aa_node->ad_handle, NULL) ? ret : 0; 134 1.1 pgoyette } 135 1.1 pgoyette 136 1.1 pgoyette static void 137 1.1 pgoyette acpi_smbus_attach(device_t parent, device_t self, void *aux) 138 1.1 pgoyette { 139 1.1 pgoyette struct acpi_smbus_softc *sc = device_private(self); 140 1.1 pgoyette struct acpi_attach_args *aa = aux; 141 1.1 pgoyette struct i2cbus_attach_args iba; 142 1.1 pgoyette 143 1.1 pgoyette aprint_naive("\n"); 144 1.1 pgoyette 145 1.1 pgoyette sc->sc_devnode = aa->aa_node; 146 1.1 pgoyette sc->sc_dv = self; 147 1.1 pgoyette sc->sc_poll_alert = 2; 148 1.1 pgoyette 149 1.13 jruoho /* Attach I2C bus. */ 150 1.14 thorpej iic_tag_init(&sc->sc_i2c_tag); 151 1.1 pgoyette sc->sc_i2c_tag.ic_cookie = sc; 152 1.1 pgoyette sc->sc_i2c_tag.ic_exec = acpi_smbus_exec; 153 1.1 pgoyette 154 1.13 jruoho (void)acpi_smbus_poll_alert(aa->aa_node->ad_handle,&sc->sc_poll_alert); 155 1.1 pgoyette 156 1.10 jruoho /* If failed, fall-back to polling. */ 157 1.10 jruoho if (acpi_register_notify(sc->sc_devnode, 158 1.10 jruoho acpi_smbus_notify_handler) != true) 159 1.10 jruoho sc->sc_poll_alert = 2; 160 1.1 pgoyette 161 1.1 pgoyette callout_init(&sc->sc_callout, 0); 162 1.1 pgoyette callout_setfunc(&sc->sc_callout, acpi_smbus_tick, self); 163 1.1 pgoyette 164 1.1 pgoyette if (sc->sc_poll_alert != 0) { 165 1.13 jruoho aprint_debug(": alert_poll %d sec", sc->sc_poll_alert); 166 1.1 pgoyette callout_schedule(&sc->sc_callout, sc->sc_poll_alert * hz); 167 1.1 pgoyette } 168 1.13 jruoho 169 1.1 pgoyette aprint_normal("\n"); 170 1.1 pgoyette 171 1.13 jruoho (void)memset(&iba, 0, sizeof(iba)); 172 1.13 jruoho (void)pmf_device_register(self, NULL, NULL); 173 1.13 jruoho 174 1.1 pgoyette iba.iba_tag = &sc->sc_i2c_tag; 175 1.13 jruoho 176 1.17 thorpej config_found(self, &iba, iicbus_print, CFARGS_NONE); 177 1.1 pgoyette } 178 1.1 pgoyette 179 1.1 pgoyette static int 180 1.2 jruoho acpi_smbus_detach(device_t self, int flags) 181 1.1 pgoyette { 182 1.1 pgoyette struct acpi_smbus_softc *sc = device_private(self); 183 1.3 jruoho 184 1.1 pgoyette pmf_device_deregister(self); 185 1.10 jruoho acpi_deregister_notify(sc->sc_devnode); 186 1.1 pgoyette 187 1.1 pgoyette callout_halt(&sc->sc_callout, NULL); 188 1.3 jruoho callout_destroy(&sc->sc_callout); 189 1.1 pgoyette 190 1.14 thorpej iic_tag_fini(&sc->sc_i2c_tag); 191 1.2 jruoho 192 1.1 pgoyette return 0; 193 1.1 pgoyette } 194 1.1 pgoyette 195 1.1 pgoyette static int 196 1.13 jruoho acpi_smbus_poll_alert(ACPI_HANDLE hdl, int *alert) 197 1.13 jruoho { 198 1.13 jruoho struct SMB_INFO *info; 199 1.13 jruoho ACPI_BUFFER smi_buf; 200 1.13 jruoho ACPI_OBJECT *e, *p; 201 1.13 jruoho ACPI_STATUS rv; 202 1.13 jruoho 203 1.13 jruoho /* 204 1.13 jruoho * Retrieve polling interval for SMBus Alerts. 205 1.13 jruoho */ 206 1.13 jruoho rv = acpi_eval_struct(hdl, "_SBI", &smi_buf); 207 1.13 jruoho 208 1.13 jruoho if (ACPI_FAILURE(rv)) 209 1.13 jruoho return 0; 210 1.13 jruoho 211 1.13 jruoho p = smi_buf.Pointer; 212 1.13 jruoho 213 1.13 jruoho if (p->Type != ACPI_TYPE_PACKAGE) { 214 1.13 jruoho rv = AE_TYPE; 215 1.13 jruoho goto out; 216 1.13 jruoho } 217 1.13 jruoho 218 1.13 jruoho if (p->Package.Count == 0) { 219 1.13 jruoho rv = AE_LIMIT; 220 1.13 jruoho goto out; 221 1.13 jruoho } 222 1.13 jruoho 223 1.13 jruoho e = p->Package.Elements; 224 1.13 jruoho 225 1.13 jruoho if (e[0].Type != ACPI_TYPE_INTEGER) { 226 1.13 jruoho rv = AE_TYPE; 227 1.13 jruoho goto out; 228 1.13 jruoho } 229 1.13 jruoho 230 1.13 jruoho /* Verify CMI version. */ 231 1.13 jruoho if (e[0].Integer.Value != 0x10) { 232 1.13 jruoho rv = AE_SUPPORT; 233 1.13 jruoho goto out; 234 1.13 jruoho } 235 1.13 jruoho 236 1.13 jruoho if (alert != NULL) { 237 1.13 jruoho 238 1.13 jruoho if (p->Package.Count < 2) 239 1.13 jruoho goto out; 240 1.13 jruoho 241 1.13 jruoho if (e[1].Type != ACPI_TYPE_BUFFER) 242 1.13 jruoho goto out; 243 1.13 jruoho 244 1.13 jruoho info = (struct SMB_INFO *)(e[1].Buffer.Pointer); 245 1.13 jruoho *alert = info->poll_int; 246 1.13 jruoho } 247 1.13 jruoho 248 1.13 jruoho out: 249 1.13 jruoho if (smi_buf.Pointer != NULL) 250 1.13 jruoho ACPI_FREE(smi_buf.Pointer); 251 1.13 jruoho 252 1.13 jruoho return (ACPI_FAILURE(rv)) ? 0 : 1; 253 1.13 jruoho } 254 1.13 jruoho 255 1.13 jruoho static int 256 1.1 pgoyette acpi_smbus_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, 257 1.1 pgoyette const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) 258 1.1 pgoyette { 259 1.1 pgoyette struct acpi_smbus_softc *sc = cookie; 260 1.1 pgoyette const uint8_t *c = cmdbuf; 261 1.1 pgoyette uint8_t *b = buf, *xb; 262 1.13 jruoho const char *path; 263 1.1 pgoyette ACPI_OBJECT_LIST args; 264 1.1 pgoyette ACPI_OBJECT arg[5]; 265 1.1 pgoyette ACPI_OBJECT *p, *e; 266 1.13 jruoho ACPI_BUFFER smbuf; 267 1.13 jruoho ACPI_STATUS rv; 268 1.13 jruoho int i, r, xlen; 269 1.13 jruoho 270 1.13 jruoho /* 271 1.13 jruoho * arg[0] : protocol 272 1.13 jruoho * arg[1] : slave address 273 1.13 jruoho * arg[2] : command 274 1.13 jruoho * arg[3] : data length 275 1.13 jruoho * arg[4] : data 276 1.13 jruoho */ 277 1.13 jruoho for (i = r = 0; i < __arraycount(arg); i++) 278 1.13 jruoho arg[i].Type = ACPI_TYPE_INTEGER; 279 1.13 jruoho 280 1.13 jruoho args.Pointer = arg; 281 1.1 pgoyette 282 1.1 pgoyette smbuf.Pointer = NULL; 283 1.1 pgoyette smbuf.Length = ACPI_ALLOCATE_LOCAL_BUFFER; 284 1.13 jruoho 285 1.1 pgoyette arg[1].Integer.Value = addr; 286 1.13 jruoho 287 1.1 pgoyette if (I2C_OP_READ_P(op)) { 288 1.13 jruoho 289 1.13 jruoho path = "_SBR"; 290 1.1 pgoyette args.Count = 3; 291 1.13 jruoho 292 1.13 jruoho switch (len) { 293 1.13 jruoho 294 1.13 jruoho case 0: 295 1.13 jruoho arg[0].Integer.Value = (cmdlen != 0) ? 296 1.13 jruoho ACPI_SMBUS_RCV_BYTE : ACPI_SMBUS_RD_QUICK; 297 1.13 jruoho 298 1.1 pgoyette arg[2].Integer.Value = 0; 299 1.13 jruoho break; 300 1.13 jruoho 301 1.13 jruoho case 1: 302 1.13 jruoho arg[0].Integer.Value = ACPI_SMBUS_RD_BYTE; 303 1.1 pgoyette arg[2].Integer.Value = *c; 304 1.13 jruoho break; 305 1.13 jruoho 306 1.13 jruoho case 2: 307 1.1 pgoyette arg[0].Integer.Value = ACPI_SMBUS_RD_WORD; 308 1.13 jruoho arg[2].Integer.Value = *c; 309 1.13 jruoho break; 310 1.13 jruoho 311 1.13 jruoho default: 312 1.1 pgoyette arg[0].Integer.Value = ACPI_SMBUS_RD_BLOCK; 313 1.13 jruoho arg[2].Integer.Value = *c; 314 1.13 jruoho break; 315 1.13 jruoho } 316 1.13 jruoho 317 1.1 pgoyette } else { 318 1.13 jruoho 319 1.13 jruoho path = "_SBW"; 320 1.1 pgoyette args.Count = 5; 321 1.13 jruoho 322 1.1 pgoyette arg[3].Integer.Value = len; 323 1.13 jruoho 324 1.13 jruoho switch (len) { 325 1.13 jruoho 326 1.13 jruoho case 0: 327 1.1 pgoyette if (cmdlen == 0) { 328 1.1 pgoyette arg[2].Integer.Value = 0; 329 1.1 pgoyette arg[0].Integer.Value = ACPI_SMBUS_WR_QUICK; 330 1.1 pgoyette } else { 331 1.1 pgoyette arg[2].Integer.Value = *c; 332 1.1 pgoyette arg[0].Integer.Value = ACPI_SMBUS_SND_BYTE; 333 1.1 pgoyette } 334 1.13 jruoho 335 1.13 jruoho arg[4].Integer.Value = 0; 336 1.13 jruoho break; 337 1.13 jruoho 338 1.13 jruoho case 1: 339 1.13 jruoho arg[0].Integer.Value = ACPI_SMBUS_WR_BYTE; 340 1.1 pgoyette arg[2].Integer.Value = *c; 341 1.1 pgoyette arg[4].Integer.Value = *b; 342 1.13 jruoho break; 343 1.13 jruoho 344 1.13 jruoho case 2: 345 1.1 pgoyette arg[0].Integer.Value = ACPI_SMBUS_WR_WORD; 346 1.13 jruoho arg[2].Integer.Value = *c; 347 1.1 pgoyette arg[4].Integer.Value = *b++; 348 1.1 pgoyette arg[4].Integer.Value += (*b--) << 8; 349 1.13 jruoho break; 350 1.13 jruoho 351 1.13 jruoho default: 352 1.1 pgoyette arg[0].Integer.Value = ACPI_SMBUS_WR_BLOCK; 353 1.13 jruoho arg[2].Integer.Value = *c; 354 1.1 pgoyette arg[4].Type = ACPI_TYPE_BUFFER; 355 1.1 pgoyette arg[4].Buffer.Pointer = buf; 356 1.13 jruoho arg[4].Buffer.Length = (len < 32) ? len : 32; 357 1.13 jruoho break; 358 1.1 pgoyette } 359 1.1 pgoyette } 360 1.13 jruoho 361 1.13 jruoho rv = AcpiEvaluateObject(sc->sc_devnode->ad_handle, path, &args,&smbuf); 362 1.13 jruoho 363 1.1 pgoyette if (ACPI_FAILURE(rv)) 364 1.13 jruoho goto out; 365 1.13 jruoho 366 1.13 jruoho p = smbuf.Pointer; 367 1.13 jruoho 368 1.13 jruoho if (p->Type != ACPI_TYPE_PACKAGE) { 369 1.13 jruoho rv = AE_TYPE; 370 1.13 jruoho goto out; 371 1.13 jruoho } 372 1.13 jruoho 373 1.13 jruoho if (p->Package.Count < 1) { 374 1.13 jruoho rv = AE_LIMIT; 375 1.13 jruoho goto out; 376 1.13 jruoho } 377 1.13 jruoho 378 1.13 jruoho e = p->Package.Elements; 379 1.13 jruoho 380 1.13 jruoho if (e->Type != ACPI_TYPE_INTEGER) { 381 1.13 jruoho rv = AE_TYPE; 382 1.13 jruoho goto out; 383 1.13 jruoho } 384 1.13 jruoho 385 1.13 jruoho ACPI_DEBUG_PRINT((ACPI_DB_DEBUG_OBJECT, 386 1.13 jruoho "return status: %"PRIu64"\n", e[0].Integer.Value)); 387 1.13 jruoho 388 1.13 jruoho if (e[0].Integer.Value != 0) { 389 1.13 jruoho rv = AE_BAD_VALUE; 390 1.13 jruoho goto out; 391 1.13 jruoho } 392 1.13 jruoho 393 1.13 jruoho /* 394 1.13 jruoho * For read operations, copy data to user buffer. 395 1.13 jruoho */ 396 1.13 jruoho if (I2C_OP_READ_P(op)) { 397 1.13 jruoho 398 1.13 jruoho if (p->Package.Count < 3) { 399 1.13 jruoho rv = AE_LIMIT; 400 1.13 jruoho goto out; 401 1.13 jruoho } 402 1.13 jruoho 403 1.13 jruoho if (e[1].Type != ACPI_TYPE_INTEGER) { 404 1.13 jruoho rv = AE_TYPE; 405 1.13 jruoho goto out; 406 1.1 pgoyette } 407 1.1 pgoyette 408 1.13 jruoho xlen = e[1].Integer.Value; 409 1.13 jruoho 410 1.13 jruoho if (xlen > len) 411 1.13 jruoho xlen = len; 412 1.13 jruoho 413 1.13 jruoho switch (e[2].Type) { 414 1.13 jruoho 415 1.13 jruoho case ACPI_TYPE_BUFFER: 416 1.13 jruoho 417 1.13 jruoho if (xlen == 0) { 418 1.13 jruoho rv = AE_LIMIT; 419 1.13 jruoho goto out; 420 1.13 jruoho } 421 1.13 jruoho 422 1.13 jruoho xb = e[2].Buffer.Pointer; 423 1.13 jruoho 424 1.13 jruoho if (xb == NULL) { 425 1.13 jruoho rv = AE_NULL_OBJECT; 426 1.13 jruoho goto out; 427 1.13 jruoho } 428 1.13 jruoho 429 1.13 jruoho (void)memcpy(b, xb, xlen); 430 1.13 jruoho break; 431 1.13 jruoho 432 1.13 jruoho case ACPI_TYPE_INTEGER: 433 1.13 jruoho 434 1.13 jruoho if (xlen > 0) 435 1.13 jruoho *b++ = e[2].Integer.Value & 0xff; 436 1.13 jruoho 437 1.13 jruoho if (xlen > 1) 438 1.13 jruoho *b = e[2].Integer.Value >> 8; 439 1.13 jruoho 440 1.13 jruoho break; 441 1.13 jruoho 442 1.13 jruoho default: 443 1.13 jruoho rv = AE_TYPE; 444 1.13 jruoho goto out; 445 1.1 pgoyette } 446 1.1 pgoyette } 447 1.13 jruoho 448 1.13 jruoho out: 449 1.13 jruoho if (smbuf.Pointer != NULL) 450 1.5 pgoyette ACPI_FREE(smbuf.Pointer); 451 1.1 pgoyette 452 1.13 jruoho if (ACPI_SUCCESS(rv)) 453 1.13 jruoho return 0; 454 1.13 jruoho 455 1.13 jruoho ACPI_DEBUG_PRINT((ACPI_DB_DEBUG_OBJECT, "failed to " 456 1.13 jruoho "evaluate %s: %s\n", path, AcpiFormatException(rv))); 457 1.13 jruoho 458 1.13 jruoho return 1; 459 1.1 pgoyette } 460 1.1 pgoyette 461 1.1 pgoyette /* 462 1.13 jruoho * Whether triggered by periodic polling or a Notify(), 463 1.13 jruoho * retrieve all pending SMBus device alerts. 464 1.1 pgoyette */ 465 1.1 pgoyette static void 466 1.1 pgoyette acpi_smbus_alerts(struct acpi_smbus_softc *sc) 467 1.1 pgoyette { 468 1.13 jruoho const ACPI_HANDLE hdl = sc->sc_devnode->ad_handle; 469 1.13 jruoho ACPI_OBJECT *e, *p; 470 1.13 jruoho ACPI_BUFFER alert; 471 1.13 jruoho ACPI_STATUS rv; 472 1.1 pgoyette int status = 0; 473 1.13 jruoho uint8_t addr; 474 1.1 pgoyette 475 1.1 pgoyette do { 476 1.13 jruoho rv = acpi_eval_struct(hdl, "_SBA", &alert); 477 1.13 jruoho 478 1.1 pgoyette if (ACPI_FAILURE(rv)) { 479 1.1 pgoyette status = 1; 480 1.1 pgoyette goto done; 481 1.1 pgoyette } 482 1.1 pgoyette 483 1.1 pgoyette p = alert.Pointer; 484 1.13 jruoho 485 1.13 jruoho if (p->Type == ACPI_TYPE_PACKAGE && p->Package.Count >= 2) { 486 1.13 jruoho 487 1.13 jruoho status = 1; 488 1.13 jruoho 489 1.1 pgoyette e = p->Package.Elements; 490 1.13 jruoho 491 1.1 pgoyette if (e[0].Type == ACPI_TYPE_INTEGER) 492 1.1 pgoyette status = e[0].Integer.Value; 493 1.13 jruoho 494 1.13 jruoho if (status == 0 && e[1].Type == ACPI_TYPE_INTEGER) { 495 1.13 jruoho addr = e[1].Integer.Value; 496 1.13 jruoho 497 1.13 jruoho aprint_debug_dev(sc->sc_dv, 498 1.13 jruoho "alert for 0x%x\n", addr); 499 1.1 pgoyette } 500 1.1 pgoyette } 501 1.1 pgoyette done: 502 1.1 pgoyette if (alert.Pointer != NULL) 503 1.5 pgoyette ACPI_FREE(alert.Pointer); 504 1.13 jruoho 505 1.1 pgoyette } while (status == 0); 506 1.1 pgoyette } 507 1.1 pgoyette 508 1.1 pgoyette static void 509 1.1 pgoyette acpi_smbus_tick(void *opaque) 510 1.1 pgoyette { 511 1.1 pgoyette device_t dv = opaque; 512 1.1 pgoyette struct acpi_smbus_softc *sc = device_private(dv); 513 1.1 pgoyette 514 1.1 pgoyette acpi_smbus_alerts(sc); 515 1.1 pgoyette 516 1.1 pgoyette callout_schedule(&sc->sc_callout, sc->sc_poll_alert * hz); 517 1.1 pgoyette } 518 1.1 pgoyette 519 1.1 pgoyette static void 520 1.2 jruoho acpi_smbus_notify_handler(ACPI_HANDLE hdl, uint32_t notify, void *opaque) 521 1.1 pgoyette { 522 1.1 pgoyette device_t dv = opaque; 523 1.1 pgoyette struct acpi_smbus_softc *sc = device_private(dv); 524 1.1 pgoyette 525 1.1 pgoyette aprint_debug_dev(dv, "received notify message 0x%x\n", notify); 526 1.13 jruoho 527 1.1 pgoyette acpi_smbus_alerts(sc); 528 1.1 pgoyette } 529