1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2019-2020 Vladimir Kondratyev <wulf@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/param.h> 29 #include <sys/bus.h> 30 #include <sys/endian.h> 31 #include <sys/kernel.h> 32 #include <sys/malloc.h> 33 #include <sys/module.h> 34 #include <sys/rman.h> 35 #include <sys/sbuf.h> 36 37 #include <machine/resource.h> 38 39 #include <contrib/dev/acpica/include/acpi.h> 40 #include <contrib/dev/acpica/include/accommon.h> 41 #include <contrib/dev/acpica/include/amlcode.h> 42 #include <dev/acpica/acpivar.h> 43 44 #include <dev/iicbus/iiconf.h> 45 #include <dev/iicbus/iicbus.h> 46 47 #define ACPI_IICBUS_LOCAL_BUFSIZE 32 /* Fits max SMBUS block size */ 48 49 /* 50 * Make a copy of ACPI_RESOURCE_I2C_SERIALBUS type and replace "pointer to ACPI 51 * object name string" field with pointer to ACPI object itself. 52 * This saves us extra strdup()/free() pair on acpi_iicbus_get_i2cres call. 53 */ 54 typedef ACPI_RESOURCE_I2C_SERIALBUS ACPI_IICBUS_RESOURCE_I2C_SERIALBUS; 55 #define ResourceSource_Handle ResourceSource.StringPtr 56 57 /* Hooks for the ACPI CA debugging infrastructure. */ 58 #define _COMPONENT ACPI_BUS 59 ACPI_MODULE_NAME("IIC") 60 61 struct gsb_buffer { 62 UINT8 status; 63 UINT8 len; 64 UINT8 data[]; 65 } __packed; 66 67 struct acpi_iicbus_softc { 68 struct iicbus_softc super_sc; 69 ACPI_CONNECTION_INFO space_handler_info; 70 bool space_handler_installed; 71 }; 72 73 struct acpi_iicbus_ivars { 74 struct iicbus_ivar super_ivar; 75 ACPI_HANDLE handle; 76 }; 77 78 static int install_space_handler = 0; 79 TUNABLE_INT("hw.iicbus.enable_acpi_space_handler", &install_space_handler); 80 81 static inline bool 82 acpi_resource_is_i2c_serialbus(ACPI_RESOURCE *res) 83 { 84 85 return (res->Type == ACPI_RESOURCE_TYPE_SERIAL_BUS && 86 res->Data.CommonSerialBus.Type == ACPI_RESOURCE_SERIAL_TYPE_I2C); 87 } 88 89 /* 90 * IICBUS Address space handler 91 */ 92 static int 93 acpi_iicbus_sendb(device_t dev, u_char slave, char byte) 94 { 95 struct iic_msg msgs[] = { 96 { slave, IIC_M_WR, 1, &byte }, 97 }; 98 99 return (iicbus_transfer(dev, msgs, nitems(msgs))); 100 } 101 102 static int 103 acpi_iicbus_recvb(device_t dev, u_char slave, char *byte) 104 { 105 char buf; 106 struct iic_msg msgs[] = { 107 { slave, IIC_M_RD, 1, &buf }, 108 }; 109 int error; 110 111 error = iicbus_transfer(dev, msgs, nitems(msgs)); 112 if (error == 0) 113 *byte = buf; 114 115 return (error); 116 } 117 118 static int 119 acpi_iicbus_write(device_t dev, u_char slave, char cmd, void *buf, 120 uint16_t buflen) 121 { 122 struct iic_msg msgs[] = { 123 { slave, IIC_M_WR | IIC_M_NOSTOP, 1, &cmd }, 124 { slave, IIC_M_WR | IIC_M_NOSTART, buflen, buf }, 125 }; 126 127 return (iicbus_transfer(dev, msgs, nitems(msgs))); 128 } 129 130 static int 131 acpi_iicbus_read(device_t dev, u_char slave, char cmd, void *buf, 132 uint16_t buflen) 133 { 134 uint8_t local_buffer[ACPI_IICBUS_LOCAL_BUFSIZE]; 135 struct iic_msg msgs[] = { 136 { slave, IIC_M_WR | IIC_M_NOSTOP, 1, &cmd }, 137 { slave, IIC_M_RD, buflen, NULL }, 138 }; 139 int error; 140 141 if (buflen <= sizeof(local_buffer)) 142 msgs[1].buf = local_buffer; 143 else 144 msgs[1].buf = malloc(buflen, M_DEVBUF, M_WAITOK); 145 error = iicbus_transfer(dev, msgs, nitems(msgs)); 146 if (error == 0) 147 memcpy(buf, msgs[1].buf, buflen); 148 if (msgs[1].buf != local_buffer) 149 free(msgs[1].buf, M_DEVBUF); 150 151 return (error); 152 } 153 154 static int 155 acpi_iicbus_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 156 { 157 uint8_t bytes[2] = { cmd, count }; 158 struct iic_msg msgs[] = { 159 { slave, IIC_M_WR | IIC_M_NOSTOP, nitems(bytes), bytes }, 160 { slave, IIC_M_WR | IIC_M_NOSTART, count, buf }, 161 }; 162 163 if (count == 0) 164 return (errno2iic(EINVAL)); 165 166 return (iicbus_transfer(dev, msgs, nitems(msgs))); 167 } 168 169 static int 170 acpi_iicbus_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) 171 { 172 uint8_t local_buffer[ACPI_IICBUS_LOCAL_BUFSIZE]; 173 u_char len; 174 struct iic_msg msgs[] = { 175 { slave, IIC_M_WR | IIC_M_NOSTOP, 1, &cmd }, 176 { slave, IIC_M_RD | IIC_M_NOSTOP, 1, &len }, 177 }; 178 struct iic_msg block_msg[] = { 179 { slave, IIC_M_RD | IIC_M_NOSTART, 0, NULL }, 180 }; 181 device_t parent = device_get_parent(dev); 182 int error; 183 184 /* Have to do this because the command is split in two transfers. */ 185 error = iicbus_request_bus(parent, dev, IIC_WAIT); 186 if (error == 0) 187 error = iicbus_transfer(dev, msgs, nitems(msgs)); 188 if (error == 0) { 189 /* 190 * If the slave offers an empty reply, 191 * read one byte to generate the stop or abort. 192 */ 193 if (len == 0) 194 block_msg[0].len = 1; 195 else 196 block_msg[0].len = len; 197 if (len <= sizeof(local_buffer)) 198 block_msg[0].buf = local_buffer; 199 else 200 block_msg[0].buf = malloc(len, M_DEVBUF, M_WAITOK); 201 error = iicbus_transfer(dev, block_msg, nitems(block_msg)); 202 if (len == 0) 203 error = errno2iic(EBADMSG); 204 if (error == 0) { 205 *count = len; 206 memcpy(buf, block_msg[0].buf, len); 207 } 208 if (block_msg[0].buf != local_buffer) 209 free(block_msg[0].buf, M_DEVBUF); 210 } 211 (void)iicbus_release_bus(parent, dev); 212 return (error); 213 } 214 215 static ACPI_STATUS 216 acpi_iicbus_space_handler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, 217 UINT32 BitWidth, UINT64 *Value, void *HandlerContext, void *RegionContext) 218 { 219 struct gsb_buffer *gsb; 220 struct acpi_iicbus_softc *sc; 221 device_t dev; 222 ACPI_CONNECTION_INFO *info; 223 ACPI_RESOURCE_I2C_SERIALBUS *sb; 224 ACPI_RESOURCE *res; 225 ACPI_STATUS s; 226 int val; 227 228 gsb = (struct gsb_buffer *)Value; 229 if (gsb == NULL) 230 return (AE_BAD_PARAMETER); 231 232 info = HandlerContext; 233 s = AcpiBufferToResource(info->Connection, info->Length, &res); 234 if (ACPI_FAILURE(s)) 235 return (s); 236 237 if (!acpi_resource_is_i2c_serialbus(res)) { 238 s = AE_BAD_PARAMETER; 239 goto err; 240 } 241 242 sb = &res->Data.I2cSerialBus; 243 244 /* XXX Ignore 10bit addressing for now */ 245 if (sb->AccessMode == ACPI_I2C_10BIT_MODE) { 246 s = AE_BAD_PARAMETER; 247 goto err; 248 } 249 250 #define AML_FIELD_ATTRIB_MASK 0x0F 251 #define AML_FIELD_ATTRIO(attr, io) (((attr) << 16) | (io)) 252 253 Function &= AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_MASK, ACPI_IO_MASK); 254 sc = __containerof(info, struct acpi_iicbus_softc, space_handler_info); 255 dev = sc->super_sc.dev; 256 257 switch (Function) { 258 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_SEND_RECEIVE, ACPI_READ): 259 val = acpi_iicbus_recvb(dev, sb->SlaveAddress, gsb->data); 260 break; 261 262 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_SEND_RECEIVE, ACPI_WRITE): 263 val = acpi_iicbus_sendb(dev, sb->SlaveAddress, gsb->data[0]); 264 break; 265 266 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BYTE, ACPI_READ): 267 val = acpi_iicbus_read(dev, sb->SlaveAddress, Address, 268 gsb->data, 1); 269 break; 270 271 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BYTE, ACPI_WRITE): 272 val = acpi_iicbus_write(dev, sb->SlaveAddress, Address, 273 gsb->data, 1); 274 break; 275 276 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_WORD, ACPI_READ): 277 val = acpi_iicbus_read(dev, sb->SlaveAddress, Address, 278 gsb->data, 2); 279 break; 280 281 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_WORD, ACPI_WRITE): 282 val = acpi_iicbus_write(dev, sb->SlaveAddress, Address, 283 gsb->data, 2); 284 break; 285 286 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BLOCK, ACPI_READ): 287 val = acpi_iicbus_bread(dev, sb->SlaveAddress, Address, 288 &gsb->len, gsb->data); 289 break; 290 291 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BLOCK, ACPI_WRITE): 292 val = acpi_iicbus_bwrite(dev, sb->SlaveAddress, Address, 293 gsb->len, gsb->data); 294 break; 295 296 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BYTES, ACPI_READ): 297 val = acpi_iicbus_read(dev, sb->SlaveAddress, Address, 298 gsb->data, info->AccessLength); 299 break; 300 301 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BYTES, ACPI_WRITE): 302 val = acpi_iicbus_write(dev, sb->SlaveAddress, Address, 303 gsb->data, info->AccessLength); 304 break; 305 306 default: 307 device_printf(dev, "protocol(0x%04x) is not supported.\n", 308 Function); 309 s = AE_BAD_PARAMETER; 310 goto err; 311 } 312 313 gsb->status = val; 314 315 err: 316 ACPI_FREE(res); 317 318 return (s); 319 } 320 321 static int 322 acpi_iicbus_install_address_space_handler(struct acpi_iicbus_softc *sc) 323 { 324 ACPI_HANDLE handle; 325 ACPI_STATUS s; 326 327 handle = acpi_get_handle(device_get_parent(sc->super_sc.dev)); 328 s = AcpiInstallAddressSpaceHandler(handle, ACPI_ADR_SPACE_GSBUS, 329 &acpi_iicbus_space_handler, NULL, &sc->space_handler_info); 330 if (ACPI_FAILURE(s)) { 331 device_printf(sc->super_sc.dev, 332 "Failed to install GSBUS Address Space Handler in ACPI\n"); 333 return (ENXIO); 334 } 335 336 return (0); 337 } 338 339 static int 340 acpi_iicbus_remove_address_space_handler(struct acpi_iicbus_softc *sc) 341 { 342 ACPI_HANDLE handle; 343 ACPI_STATUS s; 344 345 handle = acpi_get_handle(device_get_parent(sc->super_sc.dev)); 346 s = AcpiRemoveAddressSpaceHandler(handle, ACPI_ADR_SPACE_GSBUS, 347 &acpi_iicbus_space_handler); 348 if (ACPI_FAILURE(s)) { 349 device_printf(sc->super_sc.dev, 350 "Failed to remove GSBUS Address Space Handler from ACPI\n"); 351 return (ENXIO); 352 } 353 354 return (0); 355 } 356 357 static ACPI_STATUS 358 acpi_iicbus_get_i2cres_cb(ACPI_RESOURCE *res, void *context) 359 { 360 ACPI_IICBUS_RESOURCE_I2C_SERIALBUS *sb = context; 361 ACPI_STATUS status; 362 ACPI_HANDLE handle; 363 364 if (acpi_resource_is_i2c_serialbus(res)) { 365 status = AcpiGetHandle(ACPI_ROOT_OBJECT, 366 res->Data.I2cSerialBus.ResourceSource.StringPtr, &handle); 367 if (ACPI_FAILURE(status)) 368 return (status); 369 memcpy(sb, &res->Data.I2cSerialBus, 370 sizeof(ACPI_IICBUS_RESOURCE_I2C_SERIALBUS)); 371 /* 372 * replace "pointer to ACPI object name string" field 373 * with pointer to ACPI object itself. 374 */ 375 sb->ResourceSource_Handle = handle; 376 return (AE_CTRL_TERMINATE); 377 } else if (res->Type == ACPI_RESOURCE_TYPE_END_TAG) 378 return (AE_NOT_FOUND); 379 380 return (AE_OK); 381 } 382 383 static ACPI_STATUS 384 acpi_iicbus_get_i2cres(ACPI_HANDLE handle, ACPI_RESOURCE_I2C_SERIALBUS *sb) 385 { 386 387 return (AcpiWalkResources(handle, "_CRS", 388 acpi_iicbus_get_i2cres_cb, sb)); 389 } 390 391 static ACPI_STATUS 392 acpi_iicbus_parse_resources_cb(ACPI_RESOURCE *res, void *context) 393 { 394 device_t dev = context; 395 struct iicbus_ivar *super_devi = device_get_ivars(dev); 396 struct resource_list *rl = &super_devi->rl; 397 int irq, gpio_pin; 398 399 switch(res->Type) { 400 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 401 if (res->Data.ExtendedIrq.InterruptCount > 0) { 402 irq = res->Data.ExtendedIrq.Interrupts[0]; 403 if (bootverbose) 404 printf(" IRQ: %d\n", irq); 405 resource_list_add_next(rl, SYS_RES_IRQ, irq, irq, 1); 406 return (AE_CTRL_TERMINATE); 407 } 408 break; 409 case ACPI_RESOURCE_TYPE_GPIO: 410 if (res->Data.Gpio.ConnectionType == 411 ACPI_RESOURCE_GPIO_TYPE_INT) { 412 /* Not supported by FreeBSD yet */ 413 gpio_pin = res->Data.Gpio.PinTable[0]; 414 if (bootverbose) 415 printf(" GPIO IRQ pin: %d\n", gpio_pin); 416 return (AE_CTRL_TERMINATE); 417 } 418 break; 419 default: 420 break; 421 } 422 423 return (AE_OK); 424 } 425 426 static ACPI_STATUS 427 acpi_iicbus_parse_resources(ACPI_HANDLE handle, device_t dev) 428 { 429 430 return (AcpiWalkResources(handle, "_CRS", 431 acpi_iicbus_parse_resources_cb, dev)); 432 } 433 434 static void 435 acpi_iicbus_dump_res(device_t dev, ACPI_IICBUS_RESOURCE_I2C_SERIALBUS *sb) 436 { 437 device_printf(dev, "found ACPI child\n"); 438 printf(" SlaveAddress: 0x%04hx\n", sb->SlaveAddress); 439 printf(" ConnectionSpeed: %uHz\n", sb->ConnectionSpeed); 440 printf(" SlaveMode: %s\n", 441 sb->SlaveMode == ACPI_CONTROLLER_INITIATED ? 442 "ControllerInitiated" : "DeviceInitiated"); 443 printf(" AddressingMode: %uBit\n", sb->AccessMode == 0 ? 7 : 10); 444 printf(" ConnectionSharing: %s\n", sb->ConnectionSharing == 0 ? 445 "Exclusive" : "Shared"); 446 } 447 448 static device_t 449 acpi_iicbus_add_child(device_t dev, u_int order, const char *name, int unit) 450 { 451 452 return (iicbus_add_child_common( 453 dev, order, name, unit, sizeof(struct acpi_iicbus_ivars))); 454 } 455 456 static ACPI_STATUS 457 acpi_iicbus_enumerate_child(ACPI_HANDLE handle, UINT32 level, 458 void *context, void **result) 459 { 460 device_t iicbus, child, acpi_child, acpi0; 461 struct iicbus_softc *super_sc; 462 ACPI_IICBUS_RESOURCE_I2C_SERIALBUS sb; 463 ACPI_STATUS status; 464 UINT32 sta; 465 466 iicbus = context; 467 super_sc = device_get_softc(iicbus); 468 469 /* 470 * If no _STA method or if it failed, then assume that 471 * the device is present. 472 */ 473 if (!ACPI_FAILURE(acpi_GetInteger(handle, "_STA", &sta)) && 474 !ACPI_DEVICE_PRESENT(sta)) 475 return (AE_OK); 476 477 if (!acpi_has_hid(handle)) 478 return (AE_OK); 479 480 /* 481 * Read "I2C Serial Bus Connection Resource Descriptor" 482 * described in p.19.6.57 of ACPI specification. 483 */ 484 bzero(&sb, sizeof(ACPI_IICBUS_RESOURCE_I2C_SERIALBUS)); 485 if (ACPI_FAILURE(acpi_iicbus_get_i2cres(handle, &sb)) || 486 sb.SlaveAddress == 0) 487 return (AE_OK); 488 if (sb.ResourceSource_Handle != 489 acpi_get_handle(device_get_parent(iicbus))) 490 return (AE_OK); 491 if (bootverbose) 492 acpi_iicbus_dump_res(iicbus, &sb); 493 494 /* Find out speed of the slowest slave */ 495 if (super_sc->bus_freq == 0 || super_sc->bus_freq > sb.ConnectionSpeed) 496 super_sc->bus_freq = sb.ConnectionSpeed; 497 498 /* Delete existing child of acpi bus */ 499 acpi_child = acpi_get_device(handle); 500 if (acpi_child != NULL) { 501 acpi0 = devclass_get_device(devclass_find("acpi"), 0); 502 if (device_get_parent(acpi_child) != acpi0) 503 return (AE_OK); 504 505 if (device_is_attached(acpi_child)) 506 return (AE_OK); 507 508 if (device_delete_child(acpi0, acpi_child) != 0) 509 return (AE_OK); 510 } 511 512 child = BUS_ADD_CHILD(iicbus, 0, NULL, -1); 513 if (child == NULL) { 514 device_printf(iicbus, "add child failed\n"); 515 return (AE_OK); 516 } 517 518 iicbus_set_addr(child, sb.SlaveAddress); 519 acpi_set_handle(child, handle); 520 (void)acpi_iicbus_parse_resources(handle, child); 521 522 /* 523 * Update ACPI-CA to use the IIC enumerated device_t for this handle. 524 */ 525 status = AcpiAttachData(handle, acpi_fake_objhandler, child); 526 if (ACPI_FAILURE(status)) 527 printf("WARNING: Unable to attach object data to %s - %s\n", 528 acpi_name(handle), AcpiFormatException(status)); 529 530 return (AE_OK); 531 } 532 533 static ACPI_STATUS 534 acpi_iicbus_enumerate_children(device_t dev) 535 { 536 537 return (AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 538 ACPI_UINT32_MAX, acpi_iicbus_enumerate_child, NULL, dev, NULL)); 539 } 540 541 static void 542 acpi_iicbus_set_power_children(device_t dev, int state, bool all_children) 543 { 544 device_t *devlist; 545 int i, numdevs; 546 547 if (device_get_children(dev, &devlist, &numdevs) != 0) 548 return; 549 550 for (i = 0; i < numdevs; i++) 551 if (all_children || device_is_attached(devlist[i]) != 0) 552 acpi_set_powerstate(devlist[i], state); 553 554 free(devlist, M_TEMP); 555 } 556 557 static int 558 acpi_iicbus_probe(device_t dev) 559 { 560 ACPI_HANDLE handle; 561 device_t controller; 562 563 if (acpi_disabled("iicbus")) 564 return (ENXIO); 565 566 controller = device_get_parent(dev); 567 if (controller == NULL) 568 return (ENXIO); 569 570 handle = acpi_get_handle(controller); 571 if (handle == NULL) 572 return (ENXIO); 573 574 device_set_desc(dev, "Philips I2C bus (ACPI-hinted)"); 575 return (BUS_PROBE_DEFAULT); 576 } 577 578 static int 579 acpi_iicbus_attach(device_t dev) 580 { 581 struct acpi_iicbus_softc *sc = device_get_softc(dev); 582 int error; 583 584 if (ACPI_FAILURE(acpi_iicbus_enumerate_children(dev))) 585 device_printf(dev, "children enumeration failed\n"); 586 587 acpi_iicbus_set_power_children(dev, ACPI_STATE_D0, true); 588 error = iicbus_attach_common(dev, sc->super_sc.bus_freq); 589 if (error == 0 && install_space_handler != 0 && 590 acpi_iicbus_install_address_space_handler(sc) == 0) 591 sc->space_handler_installed = true; 592 593 return (error); 594 } 595 596 static int 597 acpi_iicbus_detach(device_t dev) 598 { 599 struct acpi_iicbus_softc *sc = device_get_softc(dev); 600 601 if (sc->space_handler_installed) 602 acpi_iicbus_remove_address_space_handler(sc); 603 acpi_iicbus_set_power_children(dev, ACPI_STATE_D3, false); 604 605 return (iicbus_detach(dev)); 606 } 607 608 static int 609 acpi_iicbus_suspend(device_t dev) 610 { 611 int error; 612 613 error = bus_generic_suspend(dev); 614 if (error == 0) 615 acpi_iicbus_set_power_children(dev, ACPI_STATE_D3, false); 616 617 return (error); 618 } 619 620 static int 621 acpi_iicbus_resume(device_t dev) 622 { 623 624 acpi_iicbus_set_power_children(dev, ACPI_STATE_D0, false); 625 626 return (bus_generic_resume(dev)); 627 } 628 629 /* 630 * If this device is an ACPI child but no one claimed it, attempt 631 * to power it off. We'll power it back up when a driver is added. 632 */ 633 static void 634 acpi_iicbus_probe_nomatch(device_t bus, device_t child) 635 { 636 637 iicbus_probe_nomatch(bus, child); 638 acpi_set_powerstate(child, ACPI_STATE_D3); 639 } 640 641 /* 642 * If a new driver has a chance to probe a child, first power it up. 643 */ 644 static void 645 acpi_iicbus_driver_added(device_t dev, driver_t *driver) 646 { 647 device_t child, *devlist; 648 int i, numdevs; 649 650 DEVICE_IDENTIFY(driver, dev); 651 if (device_get_children(dev, &devlist, &numdevs) != 0) 652 return; 653 654 for (i = 0; i < numdevs; i++) { 655 child = devlist[i]; 656 if (device_get_state(child) == DS_NOTPRESENT) { 657 acpi_set_powerstate(child, ACPI_STATE_D0); 658 if (device_probe_and_attach(child) != 0) 659 acpi_set_powerstate(child, ACPI_STATE_D3); 660 } 661 } 662 free(devlist, M_TEMP); 663 } 664 665 static void 666 acpi_iicbus_child_deleted(device_t bus, device_t child) 667 { 668 struct acpi_iicbus_ivars *devi = device_get_ivars(child); 669 670 if (acpi_get_device(devi->handle) == child) 671 AcpiDetachData(devi->handle, acpi_fake_objhandler); 672 } 673 674 static int 675 acpi_iicbus_read_ivar(device_t bus, device_t child, int which, uintptr_t *res) 676 { 677 struct acpi_iicbus_ivars *devi = device_get_ivars(child); 678 679 switch (which) { 680 case ACPI_IVAR_HANDLE: 681 *res = (uintptr_t)devi->handle; 682 break; 683 default: 684 return (iicbus_read_ivar(bus, child, which, res)); 685 } 686 687 return (0); 688 } 689 690 static int 691 acpi_iicbus_write_ivar(device_t bus, device_t child, int which, uintptr_t val) 692 { 693 struct acpi_iicbus_ivars *devi = device_get_ivars(child); 694 695 switch (which) { 696 case ACPI_IVAR_HANDLE: 697 if (devi->handle != NULL) 698 return (EINVAL); 699 devi->handle = (ACPI_HANDLE)val; 700 break; 701 default: 702 return (iicbus_write_ivar(bus, child, which, val)); 703 } 704 705 return (0); 706 } 707 708 /* Location hint for devctl(8). Concatenate IIC and ACPI hints. */ 709 static int 710 acpi_iicbus_child_location(device_t bus, device_t child, struct sbuf *sb) 711 { 712 struct acpi_iicbus_ivars *devi = device_get_ivars(child); 713 int error; 714 715 /* read IIC location hint string into the buffer. */ 716 error = iicbus_child_location(bus, child, sb); 717 if (error != 0) 718 return (error); 719 720 /* Place ACPI string right after IIC one's terminating NUL. */ 721 if (devi->handle != NULL) 722 sbuf_printf(sb, " handle=%s", acpi_name(devi->handle)); 723 724 return (0); 725 } 726 727 /* PnP information for devctl(8). Concatenate IIC and ACPI info strings. */ 728 static int 729 acpi_iicbus_child_pnpinfo(device_t bus, device_t child, struct sbuf *sb) 730 { 731 struct acpi_iicbus_ivars *devi = device_get_ivars(child); 732 int error; 733 734 /* read IIC PnP string into the buffer. */ 735 error = iicbus_child_pnpinfo(bus, child, sb); 736 if (error != 0) 737 return (error); 738 739 if (devi->handle == NULL) 740 return (0); 741 742 error = acpi_pnpinfo(devi->handle, sb); 743 744 return (error); 745 } 746 747 static device_method_t acpi_iicbus_methods[] = { 748 /* Device interface */ 749 DEVMETHOD(device_probe, acpi_iicbus_probe), 750 DEVMETHOD(device_attach, acpi_iicbus_attach), 751 DEVMETHOD(device_detach, acpi_iicbus_detach), 752 DEVMETHOD(device_suspend, acpi_iicbus_suspend), 753 DEVMETHOD(device_resume, acpi_iicbus_resume), 754 755 /* Bus interface */ 756 DEVMETHOD(bus_add_child, acpi_iicbus_add_child), 757 DEVMETHOD(bus_probe_nomatch, acpi_iicbus_probe_nomatch), 758 DEVMETHOD(bus_driver_added, acpi_iicbus_driver_added), 759 DEVMETHOD(bus_child_deleted, acpi_iicbus_child_deleted), 760 DEVMETHOD(bus_read_ivar, acpi_iicbus_read_ivar), 761 DEVMETHOD(bus_write_ivar, acpi_iicbus_write_ivar), 762 DEVMETHOD(bus_child_location, acpi_iicbus_child_location), 763 DEVMETHOD(bus_child_pnpinfo, acpi_iicbus_child_pnpinfo), 764 DEVMETHOD(bus_get_device_path, acpi_get_acpi_device_path), 765 766 DEVMETHOD_END, 767 }; 768 769 DEFINE_CLASS_1(iicbus, acpi_iicbus_driver, acpi_iicbus_methods, 770 sizeof(struct acpi_iicbus_softc), iicbus_driver); 771 MODULE_VERSION(acpi_iicbus, 1); 772 MODULE_DEPEND(acpi_iicbus, acpi, 1, 1, 1); 773