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