2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2019-2020 Vladimir Kondratyev <wulf@FreeBSD.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include <sys/param.h>
33 #include <sys/endian.h>
34 #include <sys/kernel.h>
35 #include <sys/malloc.h>
36 #include <sys/module.h>
39 #include <machine/resource.h>
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>
46 #include <dev/iicbus/iiconf.h>
47 #include <dev/iicbus/iicbus.h>
49 #define ACPI_IICBUS_LOCAL_BUFSIZE 32 /* Fits max SMBUS block size */
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.
56 typedef ACPI_RESOURCE_I2C_SERIALBUS ACPI_IICBUS_RESOURCE_I2C_SERIALBUS;
57 #define ResourceSource_Handle ResourceSource.StringPtr
59 /* Hooks for the ACPI CA debugging infrastructure. */
60 #define _COMPONENT ACPI_BUS
61 ACPI_MODULE_NAME("IIC")
69 struct acpi_iicbus_softc {
70 struct iicbus_softc super_sc;
71 ACPI_CONNECTION_INFO space_handler_info;
72 bool space_handler_installed;
75 struct acpi_iicbus_ivars {
76 struct iicbus_ivar super_ivar;
80 static int install_space_handler = 0;
81 TUNABLE_INT("hw.iicbus.enable_acpi_space_handler", &install_space_handler);
84 acpi_resource_is_i2c_serialbus(ACPI_RESOURCE *res)
87 return (res->Type == ACPI_RESOURCE_TYPE_SERIAL_BUS &&
88 res->Data.CommonSerialBus.Type == ACPI_RESOURCE_SERIAL_TYPE_I2C);
92 * IICBUS Address space handler
95 acpi_iicbus_sendb(device_t dev, u_char slave, char byte)
97 struct iic_msg msgs[] = {
98 { slave, IIC_M_WR, 1, &byte },
101 return (iicbus_transfer(dev, msgs, nitems(msgs)));
105 acpi_iicbus_recvb(device_t dev, u_char slave, char *byte)
108 struct iic_msg msgs[] = {
109 { slave, IIC_M_RD, 1, &buf },
113 error = iicbus_transfer(dev, msgs, nitems(msgs));
121 acpi_iicbus_write(device_t dev, u_char slave, char cmd, void *buf,
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 },
129 return (iicbus_transfer(dev, msgs, nitems(msgs)));
133 acpi_iicbus_read(device_t dev, u_char slave, char cmd, void *buf,
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 },
143 if (buflen <= sizeof(local_buffer))
144 msgs[1].buf = local_buffer;
146 msgs[1].buf = malloc(buflen, M_DEVBUF, M_WAITOK);
147 error = iicbus_transfer(dev, msgs, nitems(msgs));
149 memcpy(buf, msgs[1].buf, buflen);
150 if (msgs[1].buf != local_buffer)
151 free(msgs[1].buf, M_DEVBUF);
157 acpi_iicbus_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
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 },
166 return (errno2iic(EINVAL));
168 return (iicbus_transfer(dev, msgs, nitems(msgs)));
172 acpi_iicbus_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
174 uint8_t local_buffer[ACPI_IICBUS_LOCAL_BUFSIZE];
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 },
180 struct iic_msg block_msg[] = {
181 { slave, IIC_M_RD | IIC_M_NOSTART, 0, NULL },
183 device_t parent = device_get_parent(dev);
186 /* Have to do this because the command is split in two transfers. */
187 error = iicbus_request_bus(parent, dev, IIC_WAIT);
189 error = iicbus_transfer(dev, msgs, nitems(msgs));
192 * If the slave offers an empty reply,
193 * read one byte to generate the stop or abort.
196 block_msg[0].len = 1;
198 block_msg[0].len = len;
199 if (len <= sizeof(local_buffer))
200 block_msg[0].buf = local_buffer;
202 block_msg[0].buf = malloc(len, M_DEVBUF, M_WAITOK);
203 error = iicbus_transfer(dev, block_msg, nitems(block_msg));
205 error = errno2iic(EBADMSG);
208 memcpy(buf, block_msg[0].buf, len);
210 if (block_msg[0].buf != local_buffer)
211 free(block_msg[0].buf, M_DEVBUF);
213 (void)iicbus_release_bus(parent, dev);
218 acpi_iicbus_space_handler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address,
219 UINT32 BitWidth, UINT64 *Value, void *HandlerContext, void *RegionContext)
221 struct gsb_buffer *gsb;
222 struct acpi_iicbus_softc *sc;
224 ACPI_CONNECTION_INFO *info;
225 ACPI_RESOURCE_I2C_SERIALBUS *sb;
230 gsb = (struct gsb_buffer *)Value;
232 return (AE_BAD_PARAMETER);
234 info = HandlerContext;
235 s = AcpiBufferToResource(info->Connection, info->Length, &res);
239 if (!acpi_resource_is_i2c_serialbus(res)) {
240 s = AE_BAD_PARAMETER;
244 sb = &res->Data.I2cSerialBus;
246 /* XXX Ignore 10bit addressing for now */
247 if (sb->AccessMode == ACPI_I2C_10BIT_MODE) {
248 s = AE_BAD_PARAMETER;
252 #define AML_FIELD_ATTRIB_MASK 0x0F
253 #define AML_FIELD_ATTRIO(attr, io) (((attr) << 16) | (io))
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;
260 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_SEND_RECEIVE, ACPI_READ):
261 val = acpi_iicbus_recvb(dev, sb->SlaveAddress, gsb->data);
264 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_SEND_RECEIVE, ACPI_WRITE):
265 val = acpi_iicbus_sendb(dev, sb->SlaveAddress, gsb->data[0]);
268 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BYTE, ACPI_READ):
269 val = acpi_iicbus_read(dev, sb->SlaveAddress, Address,
273 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BYTE, ACPI_WRITE):
274 val = acpi_iicbus_write(dev, sb->SlaveAddress, Address,
278 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_WORD, ACPI_READ):
279 val = acpi_iicbus_read(dev, sb->SlaveAddress, Address,
283 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_WORD, ACPI_WRITE):
284 val = acpi_iicbus_write(dev, sb->SlaveAddress, Address,
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);
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);
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);
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);
309 device_printf(dev, "protocol(0x%04x) is not supported.\n",
311 s = AE_BAD_PARAMETER;
324 acpi_iicbus_install_address_space_handler(struct acpi_iicbus_softc *sc)
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");
342 acpi_iicbus_remove_address_space_handler(struct acpi_iicbus_softc *sc)
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");
360 acpi_iicbus_get_i2cres_cb(ACPI_RESOURCE *res, void *context)
362 ACPI_IICBUS_RESOURCE_I2C_SERIALBUS *sb = context;
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))
371 memcpy(sb, &res->Data.I2cSerialBus,
372 sizeof(ACPI_IICBUS_RESOURCE_I2C_SERIALBUS));
374 * replace "pointer to ACPI object name string" field
375 * with pointer to ACPI object itself.
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);
386 acpi_iicbus_get_i2cres(ACPI_HANDLE handle, ACPI_RESOURCE_I2C_SERIALBUS *sb)
389 return (AcpiWalkResources(handle, "_CRS",
390 acpi_iicbus_get_i2cres_cb, sb));
394 acpi_iicbus_parse_resources_cb(ACPI_RESOURCE *res, void *context)
396 device_t dev = context;
397 struct iicbus_ivar *super_devi = device_get_ivars(dev);
398 struct resource_list *rl = &super_devi->rl;
402 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
403 if (res->Data.ExtendedIrq.InterruptCount > 0) {
404 irq = res->Data.ExtendedIrq.Interrupts[0];
406 printf(" IRQ: %d\n", irq);
407 resource_list_add_next(rl, SYS_RES_IRQ, irq, irq, 1);
408 return (AE_CTRL_TERMINATE);
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];
417 printf(" GPIO IRQ pin: %d\n", gpio_pin);
418 return (AE_CTRL_TERMINATE);
429 acpi_iicbus_parse_resources(ACPI_HANDLE handle, device_t dev)
432 return (AcpiWalkResources(handle, "_CRS",
433 acpi_iicbus_parse_resources_cb, dev));
437 acpi_iicbus_dump_res(device_t dev, ACPI_IICBUS_RESOURCE_I2C_SERIALBUS *sb)
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");
451 acpi_iicbus_add_child(device_t dev, u_int order, const char *name, int unit)
454 return (iicbus_add_child_common(
455 dev, order, name, unit, sizeof(struct acpi_iicbus_ivars)));
459 acpi_iicbus_enumerate_child(ACPI_HANDLE handle, UINT32 level,
460 void *context, void **result)
462 device_t iicbus, child, acpi_child, acpi0;
463 struct iicbus_softc *super_sc;
464 ACPI_IICBUS_RESOURCE_I2C_SERIALBUS sb;
469 super_sc = device_get_softc(iicbus);
472 * If no _STA method or if it failed, then assume that
473 * the device is present.
475 if (!ACPI_FAILURE(acpi_GetInteger(handle, "_STA", &sta)) &&
476 !ACPI_DEVICE_PRESENT(sta))
479 if (!acpi_has_hid(handle))
483 * Read "I2C Serial Bus Connection Resource Descriptor"
484 * described in p.19.6.57 of ACPI specification.
486 bzero(&sb, sizeof(ACPI_IICBUS_RESOURCE_I2C_SERIALBUS));
487 if (ACPI_FAILURE(acpi_iicbus_get_i2cres(handle, &sb)) ||
488 sb.SlaveAddress == 0)
490 if (sb.ResourceSource_Handle !=
491 acpi_get_handle(device_get_parent(iicbus)))
494 acpi_iicbus_dump_res(iicbus, &sb);
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;
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)
507 if (device_is_attached(acpi_child))
510 if (device_delete_child(acpi0, acpi_child) != 0)
514 child = BUS_ADD_CHILD(iicbus, 0, NULL, -1);
516 device_printf(iicbus, "add child failed\n");
520 iicbus_set_addr(child, sb.SlaveAddress);
521 acpi_set_handle(child, handle);
522 (void)acpi_iicbus_parse_resources(handle, child);
525 * Update ACPI-CA to use the IIC enumerated device_t for this handle.
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));
536 acpi_iicbus_enumerate_children(device_t dev)
539 return (AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
540 ACPI_UINT32_MAX, acpi_iicbus_enumerate_child, NULL, dev, NULL));
544 acpi_iicbus_set_power_children(device_t dev, int state, bool all_children)
549 if (device_get_children(dev, &devlist, &numdevs) != 0)
552 for (i = 0; i < numdevs; i++)
553 if (all_children || device_is_attached(devlist[i]) != 0)
554 acpi_set_powerstate(devlist[i], state);
556 free(devlist, M_TEMP);
560 acpi_iicbus_probe(device_t dev)
565 if (acpi_disabled("iicbus"))
568 controller = device_get_parent(dev);
569 if (controller == NULL)
572 handle = acpi_get_handle(controller);
576 device_set_desc(dev, "Philips I2C bus (ACPI-hinted)");
577 return (BUS_PROBE_DEFAULT);
581 acpi_iicbus_attach(device_t dev)
583 struct acpi_iicbus_softc *sc = device_get_softc(dev);
586 if (ACPI_FAILURE(acpi_iicbus_enumerate_children(dev)))
587 device_printf(dev, "children enumeration failed\n");
589 acpi_iicbus_set_power_children(dev, ACPI_STATE_D0, true);
590 error = iicbus_attach_common(dev, sc->super_sc.bus_freq);
591 if (error == 0 && install_space_handler != 0 &&
592 acpi_iicbus_install_address_space_handler(sc) == 0)
593 sc->space_handler_installed = true;
599 acpi_iicbus_detach(device_t dev)
601 struct acpi_iicbus_softc *sc = device_get_softc(dev);
603 if (sc->space_handler_installed)
604 acpi_iicbus_remove_address_space_handler(sc);
605 acpi_iicbus_set_power_children(dev, ACPI_STATE_D3, false);
607 return (iicbus_detach(dev));
611 acpi_iicbus_suspend(device_t dev)
615 error = bus_generic_suspend(dev);
617 acpi_iicbus_set_power_children(dev, ACPI_STATE_D3, false);
623 acpi_iicbus_resume(device_t dev)
626 acpi_iicbus_set_power_children(dev, ACPI_STATE_D0, false);
628 return (bus_generic_resume(dev));
632 * If this device is an ACPI child but no one claimed it, attempt
633 * to power it off. We'll power it back up when a driver is added.
636 acpi_iicbus_probe_nomatch(device_t bus, device_t child)
639 iicbus_probe_nomatch(bus, child);
640 acpi_set_powerstate(child, ACPI_STATE_D3);
644 * If a new driver has a chance to probe a child, first power it up.
647 acpi_iicbus_driver_added(device_t dev, driver_t *driver)
649 device_t child, *devlist;
652 DEVICE_IDENTIFY(driver, dev);
653 if (device_get_children(dev, &devlist, &numdevs) != 0)
656 for (i = 0; i < numdevs; i++) {
658 if (device_get_state(child) == DS_NOTPRESENT) {
659 acpi_set_powerstate(child, ACPI_STATE_D0);
660 if (device_probe_and_attach(child) != 0)
661 acpi_set_powerstate(child, ACPI_STATE_D3);
664 free(devlist, M_TEMP);
668 acpi_iicbus_child_deleted(device_t bus, device_t child)
670 struct acpi_iicbus_ivars *devi = device_get_ivars(child);
672 if (acpi_get_device(devi->handle) == child)
673 AcpiDetachData(devi->handle, acpi_fake_objhandler);
677 acpi_iicbus_read_ivar(device_t bus, device_t child, int which, uintptr_t *res)
679 struct acpi_iicbus_ivars *devi = device_get_ivars(child);
682 case ACPI_IVAR_HANDLE:
683 *res = (uintptr_t)devi->handle;
686 return (iicbus_read_ivar(bus, child, which, res));
693 acpi_iicbus_write_ivar(device_t bus, device_t child, int which, uintptr_t val)
695 struct acpi_iicbus_ivars *devi = device_get_ivars(child);
698 case ACPI_IVAR_HANDLE:
699 if (devi->handle != NULL)
701 devi->handle = (ACPI_HANDLE)val;
704 return (iicbus_write_ivar(bus, child, which, val));
710 /* Location hint for devctl(8). Concatenate IIC and ACPI hints. */
712 acpi_iicbus_child_location_str(device_t bus, device_t child,
713 char *buf, size_t buflen)
715 struct acpi_iicbus_ivars *devi = device_get_ivars(child);
718 /* read IIC location hint string into the buffer. */
719 error = iicbus_child_location_str(bus, child, buf, buflen);
723 /* Place ACPI string right after IIC one's terminating NUL. */
724 if (devi->handle != NULL &&
725 ((buf[0] != '\0' && strlcat(buf, " ", buflen) >= buflen) ||
726 strlcat(buf, "handle=", buflen) >= buflen ||
727 strlcat(buf, acpi_name(devi->handle), buflen) >= buflen))
733 /* PnP information for devctl(8). Concatenate IIC and ACPI info strings. */
735 acpi_iicbus_child_pnpinfo_str(device_t bus, device_t child, char *buf,
738 struct acpi_iicbus_ivars *devi = device_get_ivars(child);
742 /* read IIC PnP string into the buffer. */
743 error = iicbus_child_pnpinfo_str(bus, child, buf, buflen);
747 if (devi->handle == NULL)
750 /* Place ACPI string right after IIC one's terminating NUL. */
751 acpi_offset = strlen(buf);
752 if (acpi_offset != 0)
754 error = acpi_pnpinfo_str(devi->handle, buf + acpi_offset,
755 buflen - acpi_offset);
757 /* Coalesce both strings if they are not empty. */
758 if (acpi_offset > 0 && acpi_offset < buflen && buf[acpi_offset] != 0)
759 buf[acpi_offset - 1] = ' ';
764 static device_method_t acpi_iicbus_methods[] = {
765 /* Device interface */
766 DEVMETHOD(device_probe, acpi_iicbus_probe),
767 DEVMETHOD(device_attach, acpi_iicbus_attach),
768 DEVMETHOD(device_detach, acpi_iicbus_detach),
769 DEVMETHOD(device_suspend, acpi_iicbus_suspend),
770 DEVMETHOD(device_resume, acpi_iicbus_resume),
773 DEVMETHOD(bus_add_child, acpi_iicbus_add_child),
774 DEVMETHOD(bus_probe_nomatch, acpi_iicbus_probe_nomatch),
775 DEVMETHOD(bus_driver_added, acpi_iicbus_driver_added),
776 DEVMETHOD(bus_child_deleted, acpi_iicbus_child_deleted),
777 DEVMETHOD(bus_read_ivar, acpi_iicbus_read_ivar),
778 DEVMETHOD(bus_write_ivar, acpi_iicbus_write_ivar),
779 DEVMETHOD(bus_child_location_str,acpi_iicbus_child_location_str),
780 DEVMETHOD(bus_child_pnpinfo_str,acpi_iicbus_child_pnpinfo_str),
785 DEFINE_CLASS_1(iicbus, acpi_iicbus_driver, acpi_iicbus_methods,
786 sizeof(struct acpi_iicbus_softc), iicbus_driver);
787 MODULE_VERSION(acpi_iicbus, 1);
788 MODULE_DEPEND(acpi_iicbus, acpi, 1, 1, 1);