1178173Simp/* $NetBSD: admpci.c,v 1.1 2007/03/20 08:52:02 dyoung Exp $ */
2178173Simp
3178173Simp/*-
4178173Simp * Copyright (c) 2007 David Young.  All rights reserved.
5178173Simp *
6178173Simp * Redistribution and use in source and binary forms, with or
7178173Simp * without modification, are permitted provided that the following
8178173Simp * conditions are met:
9178173Simp * 1. Redistributions of source code must retain the above copyright
10178173Simp *    notice, this list of conditions and the following disclaimer.
11178173Simp * 2. Redistributions in binary form must reproduce the above
12178173Simp *    copyright notice, this list of conditions and the following
13178173Simp *    disclaimer in the documentation and/or other materials provided
14178173Simp *    with the distribution.
15178173Simp * 3. The name of the author may not be used to endorse or promote
16178173Simp *    products derived from this software without specific prior
17178173Simp *    written permission.
18178173Simp *
19178173Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
20178173Simp * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21178173Simp * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22178173Simp * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR
23178173Simp * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
24178173Simp * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25178173Simp * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
26178173Simp * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27178173Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
28178173Simp * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29178173Simp * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30178173Simp * OF SUCH DAMAGE.
31178173Simp */
32178173Simp/*-
33178173Simp * Copyright (c) 2006 Itronix Inc.
34178173Simp * All rights reserved.
35178173Simp *
36178173Simp * Written by Garrett D'Amore for Itronix Inc.
37178173Simp *
38178173Simp * Redistribution and use in source and binary forms, with or without
39178173Simp * modification, are permitted provided that the following conditions
40178173Simp * are met:
41178173Simp * 1. Redistributions of source code must retain the above copyright
42178173Simp *    notice, this list of conditions and the following disclaimer.
43178173Simp * 2. Redistributions in binary form must reproduce the above copyright
44178173Simp *    notice, this list of conditions and the following disclaimer in the
45178173Simp *    documentation and/or other materials provided with the distribution.
46178173Simp * 3. The name of Itronix Inc. may not be used to endorse
47178173Simp *    or promote products derived from this software without specific
48178173Simp *    prior written permission.
49178173Simp *
50178173Simp * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
51178173Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
52178173Simp * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53178173Simp * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
54178173Simp * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
55178173Simp * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
56178173Simp * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
57178173Simp * ON ANY THEORY OF LIABILITY, WHETHER IN
58178173Simp * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
59178173Simp * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
60178173Simp * POSSIBILITY OF SUCH DAMAGE.
61178173Simp */
62178173Simp
63178173Simp#include <sys/cdefs.h>
64178173Simp__FBSDID("$FreeBSD$");
65178173Simp
66178173Simp#include <sys/param.h>
67178173Simp#include <sys/systm.h>
68178173Simp
69178173Simp#include <sys/bus.h>
70178173Simp#include <sys/interrupt.h>
71178173Simp#include <sys/malloc.h>
72178173Simp#include <sys/kernel.h>
73178173Simp#include <sys/module.h>
74178173Simp#include <sys/rman.h>
75178173Simp
76178173Simp#include <vm/vm.h>
77178173Simp#include <vm/pmap.h>
78178173Simp#include <vm/vm_extern.h>
79178173Simp
80178173Simp#include <machine/bus.h>
81178173Simp#include <machine/cpu.h>
82178173Simp#include <machine/pmap.h>
83178173Simp
84178173Simp#include <dev/pci/pcivar.h>
85178173Simp#include <dev/pci/pcireg.h>
86178173Simp
87178173Simp#include <dev/pci/pcib_private.h>
88178173Simp#include "pcib_if.h"
89178173Simp
90182901Sgonzo#include <mips/adm5120/adm5120reg.h>
91178173Simp
92178173Simp#ifdef ADMPCI_DEBUG
93178173Simpint admpci_debug = 1;
94178173Simp#define	ADMPCI_DPRINTF(__fmt, ...)		\
95178173Simpdo {						\
96178173Simp	if (admpci_debug)			\
97178173Simp		printf((__fmt), __VA_ARGS__);	\
98178173Simp} while (/*CONSTCOND*/0)
99178173Simp#else /* !ADMPCI_DEBUG */
100178173Simp#define	ADMPCI_DPRINTF(__fmt, ...)	do { } while (/*CONSTCOND*/0)
101178173Simp#endif /* ADMPCI_DEBUG */
102178173Simp
103178173Simp#define	ADMPCI_TAG_BUS_MASK		__BITS(23, 16)
104178173Simp/* Bit 11 is reserved.	It selects the AHB-PCI bridge.	Let device 0
105178173Simp * be the bridge.  For all other device numbers, let bit[11] == 0.
106178173Simp */
107178173Simp#define	ADMPCI_TAG_DEVICE_MASK		__BITS(15, 11)
108178173Simp#define	ADMPCI_TAG_DEVICE_SUBMASK	__BITS(15, 12)
109178173Simp#define	ADMPCI_TAG_DEVICE_BRIDGE	__BIT(11)
110178173Simp#define	ADMPCI_TAG_FUNCTION_MASK	__BITS(10, 8)
111178173Simp#define	ADMPCI_TAG_REGISTER_MASK	__BITS(7, 0)
112178173Simp
113178173Simp#define	ADMPCI_MAX_DEVICE
114178173Simp
115178173Simpstruct admpci_softc {
116178173Simp	device_t		sc_dev;
117178173Simp	bus_space_tag_t		sc_st;
118178173Simp
119178173Simp	/* Access to PCI config registers */
120178173Simp	bus_space_handle_t	sc_addrh;
121178173Simp	bus_space_handle_t	sc_datah;
122178173Simp
123178173Simp	int			sc_busno;
124178173Simp	struct rman		sc_mem_rman;
125178173Simp	struct rman		sc_io_rman;
126178173Simp	struct rman		sc_irq_rman;
127178173Simp	uint32_t		sc_mem;
128178173Simp	uint32_t		sc_io;
129178173Simp};
130178173Simp
131178173Simpstatic int
132178173Simpadmpci_probe(device_t dev)
133178173Simp{
134178173Simp
135178173Simp	return (0);
136178173Simp}
137178173Simp
138178173Simpstatic int
139178173Simpadmpci_attach(device_t dev)
140178173Simp{
141178173Simp	int busno = 0;
142178173Simp	struct admpci_softc *sc = device_get_softc(dev);
143178173Simp
144178173Simp	sc->sc_dev = dev;
145178173Simp	sc->sc_busno = busno;
146178173Simp
147178173Simp	/* Use KSEG1 to access IO ports for it is uncached */
148178173Simp	sc->sc_io = MIPS_PHYS_TO_KSEG1(ADM5120_BASE_PCI_IO);
149178173Simp	sc->sc_io_rman.rm_type = RMAN_ARRAY;
150178173Simp	sc->sc_io_rman.rm_descr = "ADMPCI I/O Ports";
151178173Simp	if (rman_init(&sc->sc_io_rman) != 0 ||
152178173Simp		rman_manage_region(&sc->sc_io_rman, 0, 0xffff) != 0) {
153178173Simp		panic("admpci_attach: failed to set up I/O rman");
154178173Simp	}
155178173Simp
156178173Simp	/* Use KSEG1 to access PCI memory for it is uncached */
157178173Simp	sc->sc_mem = MIPS_PHYS_TO_KSEG1(ADM5120_BASE_PCI_MEM);
158178173Simp	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
159178173Simp	sc->sc_mem_rman.rm_descr = "ADMPCI PCI Memory";
160178173Simp	if (rman_init(&sc->sc_mem_rman) != 0 ||
161178173Simp	    rman_manage_region(&sc->sc_mem_rman,
162178173Simp	    sc->sc_mem, sc->sc_mem + 0x100000) != 0) {
163178173Simp		panic("admpci_attach: failed to set up memory rman");
164178173Simp	}
165178173Simp
166178173Simp	sc->sc_irq_rman.rm_type = RMAN_ARRAY;
167178173Simp	sc->sc_irq_rman.rm_descr = "ADMPCI PCI IRQs";
168178173Simp	if (rman_init(&sc->sc_irq_rman) != 0 ||
169178173Simp	    rman_manage_region(&sc->sc_irq_rman, 1, 31) != 0)
170178173Simp		panic("admpci_attach: failed to set up IRQ rman");
171178173Simp
172178173Simp	if (bus_space_map(sc->sc_st, ADM5120_BASE_PCI_CONFADDR, 4, 0,
173178173Simp	    &sc->sc_addrh) != 0) {
174178173Simp		device_printf(sc->sc_dev, "unable to address space\n");
175178173Simp		panic("bus_space_map failed");
176178173Simp	}
177178173Simp
178178173Simp	if (bus_space_map(sc->sc_st, ADM5120_BASE_PCI_CONFDATA, 4, 0,
179178173Simp	    &sc->sc_datah) != 0) {
180178173Simp		device_printf(sc->sc_dev, "unable to address space\n");
181178173Simp		panic("bus_space_map failed");
182178173Simp	}
183178173Simp
184178173Simp	device_add_child(dev, "pci", busno);
185178173Simp	return (bus_generic_attach(dev));
186178173Simp}
187178173Simp
188178173Simpstatic int
189178173Simpadmpci_maxslots(device_t dev)
190178173Simp{
191178173Simp
192178173Simp	return (PCI_SLOTMAX);
193178173Simp}
194178173Simp
195178173Simpstatic uint32_t
196178173Simpadmpci_make_addr(int bus, int slot, int func, int reg)
197178173Simp{
198178173Simp
199178173Simp	return (0x80000000 | (bus << 16) | (slot << 11) | (func << 8) | reg);
200178173Simp}
201178173Simp
202178173Simpstatic uint32_t
203178173Simpadmpci_read_config(device_t dev, int bus, int slot, int func, int reg,
204178173Simp    int bytes)
205178173Simp{
206178173Simp	struct admpci_softc *sc = device_get_softc(dev);
207178173Simp	uint32_t data;
208178173Simp	uint32_t shift, mask;
209178173Simp	bus_addr_t addr;
210178173Simp
211178173Simp	ADMPCI_DPRINTF("%s: sc %p tag (%x, %x, %x) reg %d\n", __func__,
212178173Simp			(void *)sc, bus, slot, func, reg);
213178173Simp
214178173Simp	addr = admpci_make_addr(bus, slot, func, reg);
215178173Simp
216178173Simp	ADMPCI_DPRINTF("%s: sc_addrh %p sc_datah %p addr %p\n", __func__,
217178173Simp	    (void *)sc->sc_addrh, (void *)sc->sc_datah, (void *)addr);
218178173Simp
219178173Simp	bus_space_write_4(sc->sc_io, sc->sc_addrh, 0, addr);
220178173Simp	data = bus_space_read_4(sc->sc_io, sc->sc_datah, 0);
221178173Simp
222178173Simp	switch (reg % 4) {
223178173Simp	case 3:
224178173Simp		shift = 24;
225178173Simp		break;
226178173Simp	case 2:
227178173Simp		shift = 16;
228178173Simp		break;
229178173Simp	case 1:
230178173Simp		shift = 8;
231178173Simp		break;
232178173Simp	default:
233178173Simp		shift = 0;
234178173Simp		break;
235178173Simp	}
236178173Simp
237178173Simp	switch (bytes) {
238178173Simp	case 1:
239178173Simp		mask = 0xff;
240178173Simp		data = (data >> shift) & mask;
241178173Simp		break;
242178173Simp	case 2:
243178173Simp		mask = 0xffff;
244178173Simp		if (reg % 4 == 0)
245178173Simp			data = data & mask;
246178173Simp		else
247178173Simp			data = (data >> 16) & mask;
248178173Simp		break;
249178173Simp	case 4:
250178173Simp		break;
251178173Simp	default:
252178173Simp		panic("%s: wrong bytes count", __func__);
253178173Simp		break;
254178173Simp	}
255178173Simp
256178173Simp	ADMPCI_DPRINTF("%s: read 0x%x\n", __func__, data);
257178173Simp	return (data);
258178173Simp}
259178173Simp
260178173Simpstatic void
261178173Simpadmpci_write_config(device_t dev, int bus, int slot, int func, int reg,
262178173Simp    uint32_t data, int bytes)
263178173Simp{
264178173Simp	struct admpci_softc *sc = device_get_softc(dev);
265178173Simp	bus_addr_t addr;
266178173Simp	uint32_t reg_data;
267178173Simp	uint32_t shift, mask;
268178173Simp
269178173Simp	ADMPCI_DPRINTF("%s: sc %p tag (%x, %x, %x) reg %d\n", __func__,
270178173Simp			(void *)sc, bus, slot, func, reg);
271178173Simp
272178173Simp	if (bytes != 4) {
273178173Simp		reg_data = admpci_read_config(dev, bus, slot, func, reg, 4);
274178173Simp
275178173Simp		switch (reg % 4) {
276178173Simp		case 3:
277178173Simp			shift = 24;
278178173Simp			break;
279178173Simp		case 2:
280178173Simp			shift = 16;
281178173Simp			break;
282178173Simp		case 1:
283178173Simp			shift = 8;
284178173Simp			break;
285178173Simp		default:
286178173Simp			shift = 0;
287178173Simp			break;
288178173Simp		}
289178173Simp
290178173Simp		switch (bytes) {
291178173Simp		case 1:
292178173Simp			mask = 0xff;
293178173Simp			data = (reg_data & ~ (mask << shift)) | (data << shift);
294178173Simp			break;
295178173Simp		case 2:
296178173Simp			mask = 0xffff;
297178173Simp			if (reg % 4 == 0)
298178173Simp				data = (reg_data & ~mask) | data;
299178173Simp			else
300178173Simp				data = (reg_data & ~ (mask << shift)) |
301178173Simp				    (data << shift);
302178173Simp			break;
303178173Simp		case 4:
304178173Simp			break;
305178173Simp		default:
306178173Simp			panic("%s: wrong bytes count", __func__);
307178173Simp			break;
308178173Simp		}
309178173Simp	}
310178173Simp
311178173Simp	addr = admpci_make_addr(bus, slot, func, reg);
312178173Simp
313178173Simp	ADMPCI_DPRINTF("%s: sc_addrh %p sc_datah %p addr %p\n", __func__,
314178173Simp	    (void *)sc->sc_addrh, (void *)sc->sc_datah, (void *)addr);
315178173Simp
316178173Simp	bus_space_write_4(sc->sc_io, sc->sc_addrh, 0, addr);
317178173Simp	bus_space_write_4(sc->sc_io, sc->sc_datah, 0, data);
318178173Simp}
319178173Simp
320178173Simpstatic int
321178173Simpadmpci_route_interrupt(device_t pcib, device_t dev, int pin)
322178173Simp{
323178173Simp	/* TODO: implement */
324178173Simp	return (0);
325178173Simp}
326178173Simp
327178173Simpstatic int
328178173Simpadmpci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
329178173Simp{
330178173Simp	struct admpci_softc *sc = device_get_softc(dev);
331178173Simp
332178173Simp	switch (which) {
333178173Simp	case PCIB_IVAR_DOMAIN:
334178173Simp		*result = 0;
335178173Simp		return (0);
336178173Simp	case PCIB_IVAR_BUS:
337178173Simp		*result = sc->sc_busno;
338178173Simp		return (0);
339178173Simp	}
340178173Simp
341178173Simp	return (ENOENT);
342178173Simp}
343178173Simp
344178173Simpstatic int
345178173Simpadmpci_write_ivar(device_t dev, device_t child, int which, uintptr_t result)
346178173Simp{
347178173Simp	struct admpci_softc * sc = device_get_softc(dev);
348178173Simp
349178173Simp	switch (which) {
350178173Simp	case PCIB_IVAR_BUS:
351178173Simp		sc->sc_busno = result;
352178173Simp		return (0);
353178173Simp	}
354178173Simp	return (ENOENT);
355178173Simp}
356178173Simp
357178173Simpstatic struct resource *
358178173Simpadmpci_alloc_resource(device_t bus, device_t child, int type, int *rid,
359178173Simp    u_long start, u_long end, u_long count, u_int flags)
360178173Simp{
361178173Simp
362178173Simp	return (NULL);
363178173Simp#if 0
364178173Simp	struct admpci_softc *sc = device_get_softc(bus);
365178173Simp	struct resource *rv = NULL;
366178173Simp	struct rman *rm;
367178173Simp	bus_space_handle_t bh = 0;
368178173Simp
369178173Simp	switch (type) {
370178173Simp	case SYS_RES_IRQ:
371178173Simp		rm = &sc->sc_irq_rman;
372178173Simp		break;
373178173Simp	case SYS_RES_MEMORY:
374178173Simp		rm = &sc->sc_mem_rman;
375178173Simp		bh = sc->sc_mem;
376178173Simp		break;
377178173Simp	case SYS_RES_IOPORT:
378178173Simp		rm = &sc->sc_io_rman;
379178173Simp		bh = sc->sc_io;
380178173Simp		break;
381178173Simp	default:
382178173Simp		return (NULL);
383178173Simp	}
384178173Simp
385178173Simp	rv = rman_reserve_resource(rm, start, end, count, flags, child);
386178173Simp	if (rv == NULL)
387178173Simp		return (NULL);
388178173Simp	rman_set_rid(rv, *rid);
389178173Simp	if (type != SYS_RES_IRQ) {
390178173Simp		bh += (rman_get_start(rv));
391178173Simp
392178173Simp		rman_set_bustag(rv, sc->sc_st);
393178173Simp		rman_set_bushandle(rv, bh);
394178173Simp		if (flags & RF_ACTIVE) {
395178173Simp			if (bus_activate_resource(child, type, *rid, rv)) {
396178173Simp				rman_release_resource(rv);
397178173Simp				return (NULL);
398178173Simp			}
399178173Simp		}
400178173Simp	}
401178173Simp	return (rv);
402178173Simp#endif
403178173Simp}
404178173Simp
405178173Simpstatic int
406178173Simpadmpci_activate_resource(device_t bus, device_t child, int type, int rid,
407178173Simp    struct resource *r)
408178173Simp{
409178173Simp	bus_space_handle_t p;
410178173Simp	int error;
411178173Simp
412178173Simp	if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) {
413178173Simp		error = bus_space_map(rman_get_bustag(r),
414178173Simp		    rman_get_bushandle(r), rman_get_size(r), 0, &p);
415178173Simp		if (error)
416178173Simp			return (error);
417178173Simp		rman_set_bushandle(r, p);
418178173Simp	}
419178173Simp	return (rman_activate_resource(r));
420178173Simp}
421178173Simp
422178173Simpstatic int
423178173Simpadmpci_setup_intr(device_t dev, device_t child, struct resource *ires,
424178173Simp		int flags, driver_filter_t *filt, driver_intr_t *handler,
425178173Simp		void *arg, void **cookiep)
426178173Simp{
427178173Simp
428178173Simp#if 0
429178173Simp	struct admpci_softc *sc = device_get_softc(dev);
430178173Simp	struct intr_event *event;
431178173Simp	int irq, error;
432178173Simp
433178173Simp	irq = rman_get_start(ires);
434178173Simp	if (irq >= ICU_LEN || irq == 2)
435178173Simp		panic("%s: bad irq or type", __func__);
436178173Simp
437178173Simp	event = sc->sc_eventstab[irq];
438178173Simp	if (event == NULL) {
439178173Simp		error = intr_event_create(&event, (void *)irq, 0,
440178173Simp		    (void (*)(void *))NULL, "admpci intr%d:", irq);
441178173Simp		if (error)
442178173Simp			return 0;
443178173Simp		sc->sc_eventstab[irq] = event;
444178173Simp	}
445178173Simp
446178173Simp	intr_event_add_handler(event, device_get_nameunit(child), filt,
447178173Simp	    handler, arg, intr_priority(flags), flags, cookiep);
448178173Simp
449178173Simp	/* Enable it, set trigger mode. */
450178173Simp	sc->sc_imask &= ~(1 << irq);
451178173Simp	sc->sc_elcr &= ~(1 << irq);
452178173Simp
453178173Simp	admpci_set_icus(sc);
454178173Simp#endif
455178173Simp
456178173Simp	return (0);
457178173Simp}
458178173Simp
459178173Simpstatic int
460178173Simpadmpci_teardown_intr(device_t dev, device_t child, struct resource *res,
461178173Simp    void *cookie)
462178173Simp{
463178173Simp
464178173Simp	return (intr_event_remove_handler(cookie));
465178173Simp}
466178173Simp
467178173Simpstatic device_method_t admpci_methods[] = {
468178173Simp	/* Device interface */
469178173Simp	DEVMETHOD(device_probe,		admpci_probe),
470178173Simp	DEVMETHOD(device_attach,	admpci_attach),
471178173Simp	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
472178173Simp	DEVMETHOD(device_suspend,	bus_generic_suspend),
473178173Simp	DEVMETHOD(device_resume,	bus_generic_resume),
474178173Simp
475178173Simp	/* Bus interface */
476178173Simp	DEVMETHOD(bus_read_ivar,	admpci_read_ivar),
477178173Simp	DEVMETHOD(bus_write_ivar,	admpci_write_ivar),
478178173Simp	DEVMETHOD(bus_alloc_resource,	admpci_alloc_resource),
479178173Simp	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
480178173Simp	DEVMETHOD(bus_activate_resource, admpci_activate_resource),
481178173Simp	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
482178173Simp	DEVMETHOD(bus_setup_intr,	admpci_setup_intr),
483178173Simp	DEVMETHOD(bus_teardown_intr,	admpci_teardown_intr),
484178173Simp
485178173Simp	/* pcib interface */
486178173Simp	DEVMETHOD(pcib_maxslots,	admpci_maxslots),
487178173Simp	DEVMETHOD(pcib_read_config,	admpci_read_config),
488178173Simp	DEVMETHOD(pcib_write_config,	admpci_write_config),
489178173Simp	DEVMETHOD(pcib_route_interrupt,	admpci_route_interrupt),
490178173Simp
491227843Smarius	DEVMETHOD_END
492178173Simp};
493178173Simp
494178173Simpstatic driver_t admpci_driver = {
495178173Simp	"pcib",
496178173Simp	admpci_methods,
497178173Simp	sizeof(struct admpci_softc),
498178173Simp};
499178173Simp
500178173Simpstatic devclass_t admpci_devclass;
501178173Simp
502178173SimpDRIVER_MODULE(admpci, obio, admpci_driver, admpci_devclass, 0, 0);
503