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 */
54typedef	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
59ACPI_MODULE_NAME("IIC")
60
61struct gsb_buffer {
62	UINT8 status;
63	UINT8 len;
64	UINT8 data[];
65} __packed;
66
67struct acpi_iicbus_softc {
68	struct iicbus_softc	super_sc;
69	ACPI_CONNECTION_INFO	space_handler_info;
70	bool			space_handler_installed;
71};
72
73struct acpi_iicbus_ivars {
74	struct iicbus_ivar	super_ivar;
75	ACPI_HANDLE		handle;
76};
77
78static int install_space_handler = 0;
79TUNABLE_INT("hw.iicbus.enable_acpi_space_handler", &install_space_handler);
80
81static inline bool
82acpi_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 */
92static int
93acpi_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
102static int
103acpi_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
118static int
119acpi_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
130static int
131acpi_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
154static int
155acpi_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
169static int
170acpi_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
215static ACPI_STATUS
216acpi_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
318err:
319	ACPI_FREE(res);
320
321	return (s);
322}
323
324static int
325acpi_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
342static int
343acpi_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
360static ACPI_STATUS
361acpi_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
386static ACPI_STATUS
387acpi_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
394static ACPI_STATUS
395acpi_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
429static ACPI_STATUS
430acpi_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
437static void
438acpi_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
451static device_t
452acpi_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
459static ACPI_STATUS
460acpi_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, -1);
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
536static ACPI_STATUS
537acpi_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
544static void
545acpi_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
560static int
561acpi_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
581static int
582acpi_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
599static int
600acpi_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
611static int
612acpi_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
623static int
624acpi_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 */
636static void
637acpi_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 */
647static void
648acpi_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
668static void
669acpi_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
677static int
678acpi_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
693static int
694acpi_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. */
712static int
713acpi_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. */
731static int
732acpi_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
750static 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
772DEFINE_CLASS_1(iicbus, acpi_iicbus_driver, acpi_iicbus_methods,
773    sizeof(struct acpi_iicbus_softc), iicbus_driver);
774MODULE_VERSION(acpi_iicbus, 1);
775MODULE_DEPEND(acpi_iicbus, acpi, 1, 1, 1);
776