/*
 * DF-5490 rig: attach pcf0 via the same newbus API isahint.c:53-91 uses
 * (BUS_ADD_CHILD + bus_set_resource + probe/attach), then dump the
 * iicbus child state and fire the exact pcfintr sink (pcf.c:475).
 */
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/bus.h>
#include <sys/bus_resource.h>
#include <sys/machintr.h>

#define DF_INTR_RECEIVE 0x4
#define DF_IOBASE 0x320
#define DF_IRQ 5

extern void iicbus_intr(device_t, int, char *);

static int
df5490_attach_pcf(void)
{
	devclass_t dc;
	device_t isa, child;
	int error;

	dc = devclass_find("isa");
	if (dc == NULL) {
		kprintf("df5490: no isa devclass\n");
		return (ENXIO);
	}
	isa = devclass_get_device(dc, 1);
	if (isa == NULL) {
		isa = devclass_get_device(dc, 0);
		kprintf("df5490: isa1 missing, using isa0=%p\n", isa);
	}
	if (isa == NULL) {
		kprintf("df5490: no isa bus\n");
		return (ENXIO);
	}

	child = BUS_ADD_CHILD(isa, isa, 100, "pcf", 0);
	if (child == NULL) {
		kprintf("df5490: BUS_ADD_CHILD failed\n");
		return (ENXIO);
	}
	bus_set_resource(child, SYS_RES_IOPORT, 0, DF_IOBASE, 2, -1);
	bus_set_resource(child, SYS_RES_IRQ, 0, DF_IRQ, 1,
	    machintr_legacy_intr_cpuid(DF_IRQ));
	kprintf("df5490: added pcf child %s, probing+attaching\n",
		device_get_nameunit(child));
	error = device_probe_and_attach(child);
	kprintf("df5490: device_probe_and_attach -> %d\n", error);
	return (error);
}

static void
df5490_fire(void)
{
	devclass_t dc;
	device_t pcf0, *kids;
	char c = 0x41;
	int nk, i;

	dc = devclass_find("pcf");
	if (dc == NULL || (pcf0 = devclass_get_device(dc, 0)) == NULL) {
		kprintf("df5490: no pcf0 device found\n");
		return;
	}
	if (device_get_children(pcf0, &kids, &nk) != 0) {
		kprintf("df5490: device_get_children failed\n");
		return;
	}
	kprintf("df5490: pcf0=%s state=%d children=%d\n",
		device_get_nameunit(pcf0), device_get_state(pcf0), nk);
	for (i = 0; i < nk; i++) {
		kprintf("df5490: child[%d]=%s state=%d softc=%p devclass=%s\n",
		    i, device_get_nameunit(kids[i]),
		    device_get_state(kids[i]), device_get_softc(kids[i]),
		    (device_get_devclass(kids[i]) ?
		     devclass_get_name(device_get_devclass(kids[i])) : "(null)"));
	}
	kprintf("df5490: calling iicbus_intr(child0, INTR_RECEIVE, &c) == pcfintr pcf.c:475\n");
	iicbus_intr(kids[0], DF_INTR_RECEIVE, &c);
	kprintf("df5490: iicbus_intr RETURNED (no fault)\n");
	kfree(kids, M_TEMP);
}

static int
df5490_modevent(module_t m, int what, void *arg)
{
	if (what == MOD_LOAD) {
		if (df5490_attach_pcf() == 0)
			df5490_fire();
	}
	return (0);
}

static moduledata_t df5490_mod = { "df5490_rig", df5490_modevent, NULL };
DECLARE_MODULE(df5490_rig, df5490_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
