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 /* the address is expected to need shifting */ 258 sb->SlaveAddress <<= 1; 259 260 switch (Function) { 261 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_SEND_RECEIVE, ACPI_READ): 262 val = acpi_iicbus_recvb(dev, sb->SlaveAddress, gsb->data); 263 break; 264 265 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_SEND_RECEIVE, ACPI_WRITE): 266 val = acpi_iicbus_sendb(dev, sb->SlaveAddress, gsb->data[0]); 267 break; 268 269 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BYTE, ACPI_READ): 270 val = acpi_iicbus_read(dev, sb->SlaveAddress, Address, 271 gsb->data, 1); 272 break; 273 274 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BYTE, ACPI_WRITE): 275 val = acpi_iicbus_write(dev, sb->SlaveAddress, Address, 276 gsb->data, 1); 277 break; 278 279 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_WORD, ACPI_READ): 280 val = acpi_iicbus_read(dev, sb->SlaveAddress, Address, 281 gsb->data, 2); 282 break; 283 284 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_WORD, ACPI_WRITE): 285 val = acpi_iicbus_write(dev, sb->SlaveAddress, Address, 286 gsb->data, 2); 287 break; 288 289 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BLOCK, ACPI_READ): 290 val = acpi_iicbus_bread(dev, sb->SlaveAddress, Address, 291 &gsb->len, gsb->data); 292 break; 293 294 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BLOCK, ACPI_WRITE): 295 val = acpi_iicbus_bwrite(dev, sb->SlaveAddress, Address, 296 gsb->len, gsb->data); 297 break; 298 299 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BYTES, ACPI_READ): 300 val = acpi_iicbus_read(dev, sb->SlaveAddress, Address, 301 gsb->data, info->AccessLength); 302 break; 303 304 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BYTES, ACPI_WRITE): 305 val = acpi_iicbus_write(dev, sb->SlaveAddress, Address, 306 gsb->data, info->AccessLength); 307 break; 308 309 default: 310 device_printf(dev, "protocol(0x%04x) is not supported.\n", 311 Function); 312 s = AE_BAD_PARAMETER; 313 goto err; 314 } 315 316 gsb->status = val; 317 318 err: 319 ACPI_FREE(res); 320 321 return (s); 322 } 323 324 static int 325 acpi_iicbus_install_address_space_handler(struct acpi_iicbus_softc *sc) 326 { 327 ACPI_HANDLE handle; 328 ACPI_STATUS s; 329 330 handle = acpi_get_handle(device_get_parent(sc->super_sc.dev)); 331 s = AcpiInstallAddressSpaceHandler(handle, ACPI_ADR_SPACE_GSBUS, 332 &acpi_iicbus_space_handler, NULL, &sc->space_handler_info); 333 if (ACPI_FAILURE(s)) { 334 device_printf(sc->super_sc.dev, 335 "Failed to install GSBUS Address Space Handler in ACPI\n"); 336 return (ENXIO); 337 } 338 339 return (0); 340 } 341 342 static int 343 acpi_iicbus_remove_address_space_handler(struct acpi_iicbus_softc *sc) 344 { 345 ACPI_HANDLE handle; 346 ACPI_STATUS s; 347 348 handle = acpi_get_handle(device_get_parent(sc->super_sc.dev)); 349 s = AcpiRemoveAddressSpaceHandler(handle, ACPI_ADR_SPACE_GSBUS, 350 &acpi_iicbus_space_handler); 351 if (ACPI_FAILURE(s)) { 352 device_printf(sc->super_sc.dev, 353 "Failed to remove GSBUS Address Space Handler from ACPI\n"); 354 return (ENXIO); 355 } 356 357 return (0); 358 } 359 360 static ACPI_STATUS 361 acpi_iicbus_get_i2cres_cb(ACPI_RESOURCE *res, void *context) 362 { 363 ACPI_IICBUS_RESOURCE_I2C_SERIALBUS *sb = context; 364 ACPI_STATUS status; 365 ACPI_HANDLE handle; 366 367 if (acpi_resource_is_i2c_serialbus(res)) { 368 status = AcpiGetHandle(ACPI_ROOT_OBJECT, 369 res->Data.I2cSerialBus.ResourceSource.StringPtr, &handle); 370 if (ACPI_FAILURE(status)) 371 return (status); 372 memcpy(sb, &res->Data.I2cSerialBus, 373 sizeof(ACPI_IICBUS_RESOURCE_I2C_SERIALBUS)); 374 /* 375 * replace "pointer to ACPI object name string" field 376 * with pointer to ACPI object itself. 377 */ 378 sb->ResourceSource_Handle = handle; 379 return (AE_CTRL_TERMINATE); 380 } else if (res->Type == ACPI_RESOURCE_TYPE_END_TAG) 381 return (AE_NOT_FOUND); 382 383 return (AE_OK); 384 } 385 386 static ACPI_STATUS 387 acpi_iicbus_get_i2cres(ACPI_HANDLE handle, ACPI_RESOURCE_I2C_SERIALBUS *sb) 388 { 389 390 return (AcpiWalkResources(handle, "_CRS", 391 acpi_iicbus_get_i2cres_cb, sb)); 392 } 393 394 static ACPI_STATUS 395 acpi_iicbus_parse_resources_cb(ACPI_RESOURCE *res, void *context) 396 { 397 device_t dev = context; 398 struct iicbus_ivar *super_devi = device_get_ivars(dev); 399 struct resource_list *rl = &super_devi->rl; 400 int irq, gpio_pin; 401 402 switch(res->Type) { 403 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 404 if (res->Data.ExtendedIrq.InterruptCount > 0) { 405 irq = res->Data.ExtendedIrq.Interrupts[0]; 406 if (bootverbose) 407 printf(" IRQ: %d\n", irq); 408 resource_list_add_next(rl, SYS_RES_IRQ, irq, irq, 1); 409 return (AE_CTRL_TERMINATE); 410 } 411 break; 412 case ACPI_RESOURCE_TYPE_GPIO: 413 if (res->Data.Gpio.ConnectionType == 414 ACPI_RESOURCE_GPIO_TYPE_INT) { 415 /* Not supported by FreeBSD yet */ 416 gpio_pin = res->Data.Gpio.PinTable[0]; 417 if (bootverbose) 418 printf(" GPIO IRQ pin: %d\n", gpio_pin); 419 return (AE_CTRL_TERMINATE); 420 } 421 break; 422 default: 423 break; 424 } 425 426 return (AE_OK); 427 } 428 429 static ACPI_STATUS 430 acpi_iicbus_parse_resources(ACPI_HANDLE handle, device_t dev) 431 { 432 433 return (AcpiWalkResources(handle, "_CRS", 434 acpi_iicbus_parse_resources_cb, dev)); 435 } 436 437 static void 438 acpi_iicbus_dump_res(device_t dev, ACPI_IICBUS_RESOURCE_I2C_SERIALBUS *sb) 439 { 440 device_printf(dev, "found ACPI child\n"); 441 printf(" SlaveAddress: 0x%04hx\n", sb->SlaveAddress); 442 printf(" ConnectionSpeed: %uHz\n", sb->ConnectionSpeed); 443 printf(" SlaveMode: %s\n", 444 sb->SlaveMode == ACPI_CONTROLLER_INITIATED ? 445 "ControllerInitiated" : "DeviceInitiated"); 446 printf(" AddressingMode: %uBit\n", sb->AccessMode == 0 ? 7 : 10); 447 printf(" ConnectionSharing: %s\n", sb->ConnectionSharing == 0 ? 448 "Exclusive" : "Shared"); 449 } 450 451 static device_t 452 acpi_iicbus_add_child(device_t dev, u_int order, const char *name, int unit) 453 { 454 455 return (iicbus_add_child_common( 456 dev, order, name, unit, sizeof(struct acpi_iicbus_ivars))); 457 } 458 459 static ACPI_STATUS 460 acpi_iicbus_enumerate_child(ACPI_HANDLE handle, UINT32 level, 461 void *context, void **result) 462 { 463 device_t iicbus, child, acpi_child, acpi0; 464 struct iicbus_softc *super_sc; 465 ACPI_IICBUS_RESOURCE_I2C_SERIALBUS sb; 466 ACPI_STATUS status; 467 UINT32 sta; 468 469 iicbus = context; 470 super_sc = device_get_softc(iicbus); 471 472 /* 473 * If no _STA method or if it failed, then assume that 474 * the device is present. 475 */ 476 if (!ACPI_FAILURE(acpi_GetInteger(handle, "_STA", &sta)) && 477 !ACPI_DEVICE_PRESENT(sta)) 478 return (AE_OK); 479 480 if (!acpi_has_hid(handle)) 481 return (AE_OK); 482 483 /* 484 * Read "I2C Serial Bus Connection Resource Descriptor" 485 * described in p.19.6.57 of ACPI specification. 486 */ 487 bzero(&sb, sizeof(ACPI_IICBUS_RESOURCE_I2C_SERIALBUS)); 488 if (ACPI_FAILURE(acpi_iicbus_get_i2cres(handle, &sb)) || 489 sb.SlaveAddress == 0) 490 return (AE_OK); 491 if (sb.ResourceSource_Handle != 492 acpi_get_handle(device_get_parent(iicbus))) 493 return (AE_OK); 494 if (bootverbose) 495 acpi_iicbus_dump_res(iicbus, &sb); 496 497 /* Find out speed of the slowest slave */ 498 if (super_sc->bus_freq == 0 || super_sc->bus_freq > sb.ConnectionSpeed) 499 super_sc->bus_freq = sb.ConnectionSpeed; 500 501 /* Delete existing child of acpi bus */ 502 acpi_child = acpi_get_device(handle); 503 if (acpi_child != NULL) { 504 acpi0 = devclass_get_device(devclass_find("acpi"), 0); 505 if (device_get_parent(acpi_child) != acpi0) 506 return (AE_OK); 507 508 if (device_is_attached(acpi_child)) 509 return (AE_OK); 510 511 if (device_delete_child(acpi0, acpi_child) != 0) 512 return (AE_OK); 513 } 514 515 child = BUS_ADD_CHILD(iicbus, 0, NULL, DEVICE_UNIT_ANY); 516 if (child == NULL) { 517 device_printf(iicbus, "add child failed\n"); 518 return (AE_OK); 519 } 520 521 iicbus_set_addr(child, sb.SlaveAddress); 522 acpi_set_handle(child, handle); 523 (void)acpi_iicbus_parse_resources(handle, child); 524 525 /* 526 * Update ACPI-CA to use the IIC enumerated device_t for this handle. 527 */ 528 status = AcpiAttachData(handle, acpi_fake_objhandler, child); 529 if (ACPI_FAILURE(status)) 530 printf("WARNING: Unable to attach object data to %s - %s\n", 531 acpi_name(handle), AcpiFormatException(status)); 532 533 return (AE_OK); 534 } 535 536 static ACPI_STATUS 537 acpi_iicbus_enumerate_children(device_t dev) 538 { 539 540 return (AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 541 ACPI_UINT32_MAX, acpi_iicbus_enumerate_child, NULL, dev, NULL)); 542 } 543 544 static void 545 acpi_iicbus_set_power_children(device_t dev, int state, bool all_children) 546 { 547 device_t *devlist; 548 int i, numdevs; 549 550 if (device_get_children(dev, &devlist, &numdevs) != 0) 551 return; 552 553 for (i = 0; i < numdevs; i++) 554 if (all_children || device_is_attached(devlist[i]) != 0) 555 acpi_set_powerstate(devlist[i], state); 556 557 free(devlist, M_TEMP); 558 } 559 560 static int 561 acpi_iicbus_probe(device_t dev) 562 { 563 ACPI_HANDLE handle; 564 device_t controller; 565 566 if (acpi_disabled("iicbus")) 567 return (ENXIO); 568 569 controller = device_get_parent(dev); 570 if (controller == NULL) 571 return (ENXIO); 572 573 handle = acpi_get_handle(controller); 574 if (handle == NULL) 575 return (ENXIO); 576 577 device_set_desc(dev, "Philips I2C bus (ACPI-hinted)"); 578 return (BUS_PROBE_DEFAULT); 579 } 580 581 static int 582 acpi_iicbus_attach(device_t dev) 583 { 584 struct acpi_iicbus_softc *sc = device_get_softc(dev); 585 int error; 586 587 if (ACPI_FAILURE(acpi_iicbus_enumerate_children(dev))) 588 device_printf(dev, "children enumeration failed\n"); 589 590 acpi_iicbus_set_power_children(dev, ACPI_STATE_D0, true); 591 error = iicbus_attach_common(dev, sc->super_sc.bus_freq); 592 if (error == 0 && install_space_handler != 0 && 593 acpi_iicbus_install_address_space_handler(sc) == 0) 594 sc->space_handler_installed = true; 595 596 return (error); 597 } 598 599 static int 600 acpi_iicbus_detach(device_t dev) 601 { 602 struct acpi_iicbus_softc *sc = device_get_softc(dev); 603 604 if (sc->space_handler_installed) 605 acpi_iicbus_remove_address_space_handler(sc); 606 acpi_iicbus_set_power_children(dev, ACPI_STATE_D3, false); 607 608 return (iicbus_detach(dev)); 609 } 610 611 static int 612 acpi_iicbus_suspend(device_t dev) 613 { 614 int error; 615 616 error = bus_generic_suspend(dev); 617 if (error == 0) 618 acpi_iicbus_set_power_children(dev, ACPI_STATE_D3, false); 619 620 return (error); 621 } 622 623 static int 624 acpi_iicbus_resume(device_t dev) 625 { 626 627 acpi_iicbus_set_power_children(dev, ACPI_STATE_D0, false); 628 629 return (bus_generic_resume(dev)); 630 } 631 632 /* 633 * If this device is an ACPI child but no one claimed it, attempt 634 * to power it off. We'll power it back up when a driver is added. 635 */ 636 static void 637 acpi_iicbus_probe_nomatch(device_t bus, device_t child) 638 { 639 640 iicbus_probe_nomatch(bus, child); 641 acpi_set_powerstate(child, ACPI_STATE_D3); 642 } 643 644 /* 645 * If a new driver has a chance to probe a child, first power it up. 646 */ 647 static void 648 acpi_iicbus_driver_added(device_t dev, driver_t *driver) 649 { 650 device_t child, *devlist; 651 int i, numdevs; 652 653 DEVICE_IDENTIFY(driver, dev); 654 if (device_get_children(dev, &devlist, &numdevs) != 0) 655 return; 656 657 for (i = 0; i < numdevs; i++) { 658 child = devlist[i]; 659 if (device_get_state(child) == DS_NOTPRESENT) { 660 acpi_set_powerstate(child, ACPI_STATE_D0); 661 if (device_probe_and_attach(child) != 0) 662 acpi_set_powerstate(child, ACPI_STATE_D3); 663 } 664 } 665 free(devlist, M_TEMP); 666 } 667 668 static void 669 acpi_iicbus_child_deleted(device_t bus, device_t child) 670 { 671 struct acpi_iicbus_ivars *devi = device_get_ivars(child); 672 673 if (acpi_get_device(devi->handle) == child) 674 AcpiDetachData(devi->handle, acpi_fake_objhandler); 675 } 676 677 static int 678 acpi_iicbus_read_ivar(device_t bus, device_t child, int which, uintptr_t *res) 679 { 680 struct acpi_iicbus_ivars *devi = device_get_ivars(child); 681 682 switch (which) { 683 case ACPI_IVAR_HANDLE: 684 *res = (uintptr_t)devi->handle; 685 break; 686 default: 687 return (iicbus_read_ivar(bus, child, which, res)); 688 } 689 690 return (0); 691 } 692 693 static int 694 acpi_iicbus_write_ivar(device_t bus, device_t child, int which, uintptr_t val) 695 { 696 struct acpi_iicbus_ivars *devi = device_get_ivars(child); 697 698 switch (which) { 699 case ACPI_IVAR_HANDLE: 700 if (devi->handle != NULL) 701 return (EINVAL); 702 devi->handle = (ACPI_HANDLE)val; 703 break; 704 default: 705 return (iicbus_write_ivar(bus, child, which, val)); 706 } 707 708 return (0); 709 } 710 711 /* Location hint for devctl(8). Concatenate IIC and ACPI hints. */ 712 static int 713 acpi_iicbus_child_location(device_t bus, device_t child, struct sbuf *sb) 714 { 715 struct acpi_iicbus_ivars *devi = device_get_ivars(child); 716 int error; 717 718 /* read IIC location hint string into the buffer. */ 719 error = iicbus_child_location(bus, child, sb); 720 if (error != 0) 721 return (error); 722 723 /* Place ACPI string right after IIC one's terminating NUL. */ 724 if (devi->handle != NULL) 725 sbuf_printf(sb, " handle=%s", acpi_name(devi->handle)); 726 727 return (0); 728 } 729 730 /* PnP information for devctl(8). Concatenate IIC and ACPI info strings. */ 731 static int 732 acpi_iicbus_child_pnpinfo(device_t bus, device_t child, struct sbuf *sb) 733 { 734 struct acpi_iicbus_ivars *devi = device_get_ivars(child); 735 int error; 736 737 /* read IIC PnP string into the buffer. */ 738 error = iicbus_child_pnpinfo(bus, child, sb); 739 if (error != 0) 740 return (error); 741 742 if (devi->handle == NULL) 743 return (0); 744 745 error = acpi_pnpinfo(devi->handle, sb); 746 747 return (error); 748 } 749 750 static device_method_t acpi_iicbus_methods[] = { 751 /* Device interface */ 752 DEVMETHOD(device_probe, acpi_iicbus_probe), 753 DEVMETHOD(device_attach, acpi_iicbus_attach), 754 DEVMETHOD(device_detach, acpi_iicbus_detach), 755 DEVMETHOD(device_suspend, acpi_iicbus_suspend), 756 DEVMETHOD(device_resume, acpi_iicbus_resume), 757 758 /* Bus interface */ 759 DEVMETHOD(bus_add_child, acpi_iicbus_add_child), 760 DEVMETHOD(bus_probe_nomatch, acpi_iicbus_probe_nomatch), 761 DEVMETHOD(bus_driver_added, acpi_iicbus_driver_added), 762 DEVMETHOD(bus_child_deleted, acpi_iicbus_child_deleted), 763 DEVMETHOD(bus_read_ivar, acpi_iicbus_read_ivar), 764 DEVMETHOD(bus_write_ivar, acpi_iicbus_write_ivar), 765 DEVMETHOD(bus_child_location, acpi_iicbus_child_location), 766 DEVMETHOD(bus_child_pnpinfo, acpi_iicbus_child_pnpinfo), 767 DEVMETHOD(bus_get_device_path, acpi_get_acpi_device_path), 768 769 DEVMETHOD_END, 770 }; 771 772 DEFINE_CLASS_1(iicbus, acpi_iicbus_driver, acpi_iicbus_methods, 773 sizeof(struct acpi_iicbus_softc), iicbus_driver); 774 MODULE_VERSION(acpi_iicbus, 1); 775 MODULE_DEPEND(acpi_iicbus, acpi, 1, 1, 1); 776