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