xref: /freebsd/sys/dev/pci/vga_pci.c (revision 2259d74c68f5e61add44f0f4483ab455ca945d41)
18e8e46ccSJohn Baldwin /*-
28e8e46ccSJohn Baldwin  * Copyright (c) 2005 John Baldwin <jhb@FreeBSD.org>
38e8e46ccSJohn Baldwin  * All rights reserved.
48e8e46ccSJohn Baldwin  *
58e8e46ccSJohn Baldwin  * Redistribution and use in source and binary forms, with or without
68e8e46ccSJohn Baldwin  * modification, are permitted provided that the following conditions
78e8e46ccSJohn Baldwin  * are met:
88e8e46ccSJohn Baldwin  * 1. Redistributions of source code must retain the above copyright
98e8e46ccSJohn Baldwin  *    notice, this list of conditions and the following disclaimer.
108e8e46ccSJohn Baldwin  * 2. Redistributions in binary form must reproduce the above copyright
118e8e46ccSJohn Baldwin  *    notice, this list of conditions and the following disclaimer in the
128e8e46ccSJohn Baldwin  *    documentation and/or other materials provided with the distribution.
138e8e46ccSJohn Baldwin  * 3. Neither the name of the author nor the names of any co-contributors
148e8e46ccSJohn Baldwin  *    may be used to endorse or promote products derived from this software
158e8e46ccSJohn Baldwin  *    without specific prior written permission.
168e8e46ccSJohn Baldwin  *
178e8e46ccSJohn Baldwin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
188e8e46ccSJohn Baldwin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
198e8e46ccSJohn Baldwin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
208e8e46ccSJohn Baldwin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
218e8e46ccSJohn Baldwin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
228e8e46ccSJohn Baldwin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
238e8e46ccSJohn Baldwin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
248e8e46ccSJohn Baldwin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
258e8e46ccSJohn Baldwin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
268e8e46ccSJohn Baldwin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
278e8e46ccSJohn Baldwin  * SUCH DAMAGE.
288e8e46ccSJohn Baldwin  */
298e8e46ccSJohn Baldwin 
308e8e46ccSJohn Baldwin #include <sys/cdefs.h>
318e8e46ccSJohn Baldwin __FBSDID("$FreeBSD$");
328e8e46ccSJohn Baldwin 
338e8e46ccSJohn Baldwin /*
348e8e46ccSJohn Baldwin  * Simple driver for PCI VGA display devices.  Drivers such as agp(4) and
358e8e46ccSJohn Baldwin  * drm(4) should attach as children of this device.
368e8e46ccSJohn Baldwin  *
378e8e46ccSJohn Baldwin  * XXX: The vgapci name is a hack until we somehow merge the isa vga driver
388e8e46ccSJohn Baldwin  * in or rename it.
398e8e46ccSJohn Baldwin  */
408e8e46ccSJohn Baldwin 
418e8e46ccSJohn Baldwin #include <sys/param.h>
428e8e46ccSJohn Baldwin #include <sys/bus.h>
432259d74cSJung-uk Kim #include <sys/fbio.h>
448e8e46ccSJohn Baldwin #include <sys/kernel.h>
452259d74cSJung-uk Kim #include <sys/malloc.h>
468e8e46ccSJohn Baldwin #include <sys/module.h>
47e8b145c2SJohn Baldwin #include <sys/rman.h>
483219f535SJung-uk Kim #include <sys/sysctl.h>
49e8b145c2SJohn Baldwin #include <sys/systm.h>
508e8e46ccSJohn Baldwin 
512259d74cSJung-uk Kim #include <dev/fb/fbreg.h>
522259d74cSJung-uk Kim #include <dev/fb/vgareg.h>
532259d74cSJung-uk Kim 
548e8e46ccSJohn Baldwin #include <dev/pci/pcireg.h>
558e8e46ccSJohn Baldwin #include <dev/pci/pcivar.h>
568e8e46ccSJohn Baldwin 
57e8b145c2SJohn Baldwin struct vga_resource {
58e8b145c2SJohn Baldwin 	struct resource	*vr_res;
59e8b145c2SJohn Baldwin 	int	vr_refs;
60e8b145c2SJohn Baldwin };
61e8b145c2SJohn Baldwin 
62e7e2941bSJohn Baldwin struct vga_pci_softc {
63e7e2941bSJohn Baldwin 	device_t	vga_msi_child;	/* Child driver using MSI. */
64e8b145c2SJohn Baldwin 	struct vga_resource vga_res[PCIR_MAX_BAR_0 + 1];
65e7e2941bSJohn Baldwin };
66e7e2941bSJohn Baldwin 
673219f535SJung-uk Kim SYSCTL_DECL(_hw_pci);
683219f535SJung-uk Kim 
693219f535SJung-uk Kim int vga_pci_default_unit = -1;
703219f535SJung-uk Kim TUNABLE_INT("hw.pci.default_vgapci_unit", &vga_pci_default_unit);
712259d74cSJung-uk Kim SYSCTL_INT(_hw_pci, OID_AUTO, default_vgapci_unit, CTLFLAG_RDTUN,
723219f535SJung-uk Kim     &vga_pci_default_unit, -1, "Default VGA-compatible display");
733219f535SJung-uk Kim 
748e8e46ccSJohn Baldwin static int
758e8e46ccSJohn Baldwin vga_pci_probe(device_t dev)
768e8e46ccSJohn Baldwin {
773219f535SJung-uk Kim 	device_t bdev;
783219f535SJung-uk Kim 	int unit;
793219f535SJung-uk Kim 	uint16_t bctl;
808e8e46ccSJohn Baldwin 
818e8e46ccSJohn Baldwin 	switch (pci_get_class(dev)) {
828e8e46ccSJohn Baldwin 	case PCIC_DISPLAY:
838e8e46ccSJohn Baldwin 		break;
848e8e46ccSJohn Baldwin 	case PCIC_OLD:
858e8e46ccSJohn Baldwin 		if (pci_get_subclass(dev) != PCIS_OLD_VGA)
868e8e46ccSJohn Baldwin 			return (ENXIO);
878e8e46ccSJohn Baldwin 		break;
888e8e46ccSJohn Baldwin 	default:
898e8e46ccSJohn Baldwin 		return (ENXIO);
908e8e46ccSJohn Baldwin 	}
913219f535SJung-uk Kim 
923219f535SJung-uk Kim 	/* Probe default display. */
933219f535SJung-uk Kim 	unit = device_get_unit(dev);
943219f535SJung-uk Kim 	bdev = device_get_parent(device_get_parent(dev));
953219f535SJung-uk Kim 	bctl = pci_read_config(bdev, PCIR_BRIDGECTL_1, 2);
963219f535SJung-uk Kim 	if (vga_pci_default_unit < 0 && (bctl & PCIB_BCR_VGA_ENABLE) != 0)
973219f535SJung-uk Kim 		vga_pci_default_unit = unit;
983219f535SJung-uk Kim 	if (vga_pci_default_unit == unit)
993219f535SJung-uk Kim 		device_set_flags(dev, 1);
1003219f535SJung-uk Kim 
1018e8e46ccSJohn Baldwin 	device_set_desc(dev, "VGA-compatible display");
102be7ccc4bSJohn Baldwin 	return (BUS_PROBE_GENERIC);
1038e8e46ccSJohn Baldwin }
1048e8e46ccSJohn Baldwin 
1058e8e46ccSJohn Baldwin static int
1068e8e46ccSJohn Baldwin vga_pci_attach(device_t dev)
1078e8e46ccSJohn Baldwin {
1088e8e46ccSJohn Baldwin 
1098e8e46ccSJohn Baldwin 	bus_generic_probe(dev);
1108e8e46ccSJohn Baldwin 
1118e8e46ccSJohn Baldwin 	/* Always create a drm child for now to make it easier on drm. */
1128e8e46ccSJohn Baldwin 	device_add_child(dev, "drm", -1);
1138e8e46ccSJohn Baldwin 	bus_generic_attach(dev);
1148e8e46ccSJohn Baldwin 	return (0);
1158e8e46ccSJohn Baldwin }
1168e8e46ccSJohn Baldwin 
1178e8e46ccSJohn Baldwin static int
1188e8e46ccSJohn Baldwin vga_pci_suspend(device_t dev)
1198e8e46ccSJohn Baldwin {
1202259d74cSJung-uk Kim 	vga_softc_t *sc;
1212259d74cSJung-uk Kim 	devclass_t dc;
1222259d74cSJung-uk Kim 	int err, nbytes;
1238e8e46ccSJohn Baldwin 
1242259d74cSJung-uk Kim 	err = bus_generic_suspend(dev);
1252259d74cSJung-uk Kim 	if (err)
1262259d74cSJung-uk Kim 		return (err);
1272259d74cSJung-uk Kim 
1282259d74cSJung-uk Kim 	sc = NULL;
1292259d74cSJung-uk Kim 	if (device_get_unit(dev) == vga_pci_default_unit) {
1302259d74cSJung-uk Kim 		dc = devclass_find(VGA_DRIVER_NAME);
1312259d74cSJung-uk Kim 		if (dc != NULL)
1322259d74cSJung-uk Kim 			sc = devclass_get_softc(dc, 0);
1332259d74cSJung-uk Kim 	}
1342259d74cSJung-uk Kim 	if (sc == NULL)
1352259d74cSJung-uk Kim 		return (0);
1362259d74cSJung-uk Kim 
1372259d74cSJung-uk Kim 	/* Save the video state across the suspend. */
1382259d74cSJung-uk Kim 	if (sc->state_buf != NULL)
1392259d74cSJung-uk Kim 		goto save_palette;
1402259d74cSJung-uk Kim 	nbytes = vidd_save_state(sc->adp, NULL, 0);
1412259d74cSJung-uk Kim 	if (nbytes <= 0)
1422259d74cSJung-uk Kim 		goto save_palette;
1432259d74cSJung-uk Kim 	sc->state_buf = malloc(nbytes, M_TEMP, M_NOWAIT);
1442259d74cSJung-uk Kim 	if (sc->state_buf == NULL)
1452259d74cSJung-uk Kim 		goto save_palette;
1462259d74cSJung-uk Kim 	if (bootverbose)
1472259d74cSJung-uk Kim 		device_printf(dev, "saving %d bytes of video state\n", nbytes);
1482259d74cSJung-uk Kim 	if (vidd_save_state(sc->adp, sc->state_buf, nbytes) != 0) {
1492259d74cSJung-uk Kim 		device_printf(dev, "failed to save state (nbytes=%d)\n",
1502259d74cSJung-uk Kim 		    nbytes);
1512259d74cSJung-uk Kim 		free(sc->state_buf, M_TEMP);
1522259d74cSJung-uk Kim 		sc->state_buf = NULL;
1532259d74cSJung-uk Kim 	}
1542259d74cSJung-uk Kim 
1552259d74cSJung-uk Kim save_palette:
1562259d74cSJung-uk Kim 	/* Save the color palette across the suspend. */
1572259d74cSJung-uk Kim 	if (sc->pal_buf != NULL)
1582259d74cSJung-uk Kim 		return (0);
1592259d74cSJung-uk Kim 	sc->pal_buf = malloc(256 * 3, M_TEMP, M_NOWAIT);
1602259d74cSJung-uk Kim 	if (sc->pal_buf != NULL) {
1612259d74cSJung-uk Kim 		if (bootverbose)
1622259d74cSJung-uk Kim 			device_printf(dev, "saving color palette\n");
1632259d74cSJung-uk Kim 		if (vidd_save_palette(sc->adp, sc->pal_buf) != 0) {
1642259d74cSJung-uk Kim 			device_printf(dev, "failed to save palette\n");
1652259d74cSJung-uk Kim 			free(sc->pal_buf, M_TEMP);
1662259d74cSJung-uk Kim 			sc->pal_buf = NULL;
1672259d74cSJung-uk Kim 		}
1682259d74cSJung-uk Kim 	}
1692259d74cSJung-uk Kim 
1702259d74cSJung-uk Kim 	return (0);
1718e8e46ccSJohn Baldwin }
1728e8e46ccSJohn Baldwin 
1738e8e46ccSJohn Baldwin static int
1748e8e46ccSJohn Baldwin vga_pci_resume(device_t dev)
1758e8e46ccSJohn Baldwin {
1762259d74cSJung-uk Kim 	vga_softc_t *sc;
1772259d74cSJung-uk Kim 	devclass_t dc;
1782259d74cSJung-uk Kim 
1792259d74cSJung-uk Kim 	sc = NULL;
1802259d74cSJung-uk Kim 	if (device_get_unit(dev) == vga_pci_default_unit) {
1812259d74cSJung-uk Kim 		dc = devclass_find(VGA_DRIVER_NAME);
1822259d74cSJung-uk Kim 		if (dc != NULL)
1832259d74cSJung-uk Kim 			sc = devclass_get_softc(dc, 0);
1842259d74cSJung-uk Kim 	}
1852259d74cSJung-uk Kim 	if (sc == NULL)
1862259d74cSJung-uk Kim 		return (bus_generic_resume(dev));
1872259d74cSJung-uk Kim 
1882259d74cSJung-uk Kim 	if (sc->state_buf != NULL) {
1892259d74cSJung-uk Kim 		if (vidd_load_state(sc->adp, sc->state_buf) != 0)
1902259d74cSJung-uk Kim 			device_printf(dev, "failed to reload state\n");
1912259d74cSJung-uk Kim 		free(sc->state_buf, M_TEMP);
1922259d74cSJung-uk Kim 		sc->state_buf = NULL;
1932259d74cSJung-uk Kim 	}
1942259d74cSJung-uk Kim 	if (sc->pal_buf != NULL) {
1952259d74cSJung-uk Kim 		if (vidd_load_palette(sc->adp, sc->pal_buf) != 0)
1962259d74cSJung-uk Kim 			device_printf(dev, "failed to reload palette\n");
1972259d74cSJung-uk Kim 		free(sc->pal_buf, M_TEMP);
1982259d74cSJung-uk Kim 		sc->pal_buf = NULL;
1992259d74cSJung-uk Kim 	}
2008e8e46ccSJohn Baldwin 
2018e8e46ccSJohn Baldwin 	return (bus_generic_resume(dev));
2028e8e46ccSJohn Baldwin }
2038e8e46ccSJohn Baldwin 
2048e8e46ccSJohn Baldwin /* Bus interface. */
2058e8e46ccSJohn Baldwin 
2068e8e46ccSJohn Baldwin static int
2078e8e46ccSJohn Baldwin vga_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
2088e8e46ccSJohn Baldwin {
2098e8e46ccSJohn Baldwin 
2108e8e46ccSJohn Baldwin 	return (BUS_READ_IVAR(device_get_parent(dev), dev, which, result));
2118e8e46ccSJohn Baldwin }
2128e8e46ccSJohn Baldwin 
2138e8e46ccSJohn Baldwin static int
2148e8e46ccSJohn Baldwin vga_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
2158e8e46ccSJohn Baldwin {
2168e8e46ccSJohn Baldwin 
2178e8e46ccSJohn Baldwin 	return (EINVAL);
2188e8e46ccSJohn Baldwin }
2198e8e46ccSJohn Baldwin 
2206be0323dSRobert Noland static int
2216be0323dSRobert Noland vga_pci_setup_intr(device_t dev, device_t child, struct resource *irq,
2226be0323dSRobert Noland     int flags, driver_filter_t *filter, driver_intr_t *intr, void *arg,
2236be0323dSRobert Noland     void **cookiep)
2246be0323dSRobert Noland {
2256be0323dSRobert Noland 	return (BUS_SETUP_INTR(device_get_parent(dev), dev, irq, flags,
2266be0323dSRobert Noland 	    filter, intr, arg, cookiep));
2276be0323dSRobert Noland }
2286be0323dSRobert Noland 
2296be0323dSRobert Noland static int
2306be0323dSRobert Noland vga_pci_teardown_intr(device_t dev, device_t child, struct resource *irq,
2316be0323dSRobert Noland     void *cookie)
2326be0323dSRobert Noland {
2336be0323dSRobert Noland 	return (BUS_TEARDOWN_INTR(device_get_parent(dev), dev, irq, cookie));
2346be0323dSRobert Noland }
2356be0323dSRobert Noland 
2368e8e46ccSJohn Baldwin static struct resource *
2378e8e46ccSJohn Baldwin vga_pci_alloc_resource(device_t dev, device_t child, int type, int *rid,
2388e8e46ccSJohn Baldwin     u_long start, u_long end, u_long count, u_int flags)
2398e8e46ccSJohn Baldwin {
240e8b145c2SJohn Baldwin 	struct vga_pci_softc *sc;
241e8b145c2SJohn Baldwin 	int bar;
2428e8e46ccSJohn Baldwin 
243e8b145c2SJohn Baldwin 	switch (type) {
244e8b145c2SJohn Baldwin 	case SYS_RES_MEMORY:
245e8b145c2SJohn Baldwin 	case SYS_RES_IOPORT:
246e8b145c2SJohn Baldwin 		/*
247e8b145c2SJohn Baldwin 		 * For BARs, we cache the resource so that we only allocate it
248e8b145c2SJohn Baldwin 		 * from the PCI bus once.
249e8b145c2SJohn Baldwin 		 */
250e8b145c2SJohn Baldwin 		bar = PCI_RID2BAR(*rid);
251e8b145c2SJohn Baldwin 		if (bar < 0 || bar > PCIR_MAX_BAR_0)
252e8b145c2SJohn Baldwin 			return (NULL);
253e8b145c2SJohn Baldwin 		sc = device_get_softc(dev);
254e8b145c2SJohn Baldwin 		if (sc->vga_res[bar].vr_res == NULL)
255e8b145c2SJohn Baldwin 			sc->vga_res[bar].vr_res = bus_alloc_resource(dev, type,
256e8b145c2SJohn Baldwin 			    rid, start, end, count, flags);
257e8b145c2SJohn Baldwin 		if (sc->vga_res[bar].vr_res != NULL)
258e8b145c2SJohn Baldwin 			sc->vga_res[bar].vr_refs++;
259e8b145c2SJohn Baldwin 		return (sc->vga_res[bar].vr_res);
260e8b145c2SJohn Baldwin 	}
2618e8e46ccSJohn Baldwin 	return (bus_alloc_resource(dev, type, rid, start, end, count, flags));
2628e8e46ccSJohn Baldwin }
2638e8e46ccSJohn Baldwin 
2648e8e46ccSJohn Baldwin static int
2658e8e46ccSJohn Baldwin vga_pci_release_resource(device_t dev, device_t child, int type, int rid,
2668e8e46ccSJohn Baldwin     struct resource *r)
2678e8e46ccSJohn Baldwin {
268e8b145c2SJohn Baldwin 	struct vga_pci_softc *sc;
269e8b145c2SJohn Baldwin 	int bar, error;
270e8b145c2SJohn Baldwin 
271e8b145c2SJohn Baldwin 	switch (type) {
272e8b145c2SJohn Baldwin 	case SYS_RES_MEMORY:
273e8b145c2SJohn Baldwin 	case SYS_RES_IOPORT:
274e8b145c2SJohn Baldwin 		/*
275e8b145c2SJohn Baldwin 		 * For BARs, we release the resource from the PCI bus
276e8b145c2SJohn Baldwin 		 * when the last child reference goes away.
277e8b145c2SJohn Baldwin 		 */
278e8b145c2SJohn Baldwin 		bar = PCI_RID2BAR(rid);
279e8b145c2SJohn Baldwin 		if (bar < 0 || bar > PCIR_MAX_BAR_0)
280e8b145c2SJohn Baldwin 			return (EINVAL);
281e8b145c2SJohn Baldwin 		sc = device_get_softc(dev);
282e8b145c2SJohn Baldwin 		if (sc->vga_res[bar].vr_res == NULL)
283e8b145c2SJohn Baldwin 			return (EINVAL);
284e8b145c2SJohn Baldwin 		KASSERT(sc->vga_res[bar].vr_res == r,
285e8b145c2SJohn Baldwin 		    ("vga_pci resource mismatch"));
286e8b145c2SJohn Baldwin 		if (sc->vga_res[bar].vr_refs > 1) {
287e8b145c2SJohn Baldwin 			sc->vga_res[bar].vr_refs--;
288e8b145c2SJohn Baldwin 			return (0);
289e8b145c2SJohn Baldwin 		}
290e8b145c2SJohn Baldwin 		KASSERT(sc->vga_res[bar].vr_refs > 0,
291e8b145c2SJohn Baldwin 		    ("vga_pci resource reference count underflow"));
292e8b145c2SJohn Baldwin 		error = bus_release_resource(dev, type, rid, r);
293e8b145c2SJohn Baldwin 		if (error == 0) {
294e8b145c2SJohn Baldwin 			sc->vga_res[bar].vr_res = NULL;
295e8b145c2SJohn Baldwin 			sc->vga_res[bar].vr_refs = 0;
296e8b145c2SJohn Baldwin 		}
297e8b145c2SJohn Baldwin 		return (error);
298e8b145c2SJohn Baldwin 	}
2998e8e46ccSJohn Baldwin 
3008e8e46ccSJohn Baldwin 	return (bus_release_resource(dev, type, rid, r));
3018e8e46ccSJohn Baldwin }
3028e8e46ccSJohn Baldwin 
3038e8e46ccSJohn Baldwin /* PCI interface. */
3048e8e46ccSJohn Baldwin 
3058e8e46ccSJohn Baldwin static uint32_t
3068e8e46ccSJohn Baldwin vga_pci_read_config(device_t dev, device_t child, int reg, int width)
3078e8e46ccSJohn Baldwin {
3088e8e46ccSJohn Baldwin 
3098e8e46ccSJohn Baldwin 	return (pci_read_config(dev, reg, width));
3108e8e46ccSJohn Baldwin }
3118e8e46ccSJohn Baldwin 
3128e8e46ccSJohn Baldwin static void
3138e8e46ccSJohn Baldwin vga_pci_write_config(device_t dev, device_t child, int reg,
3148e8e46ccSJohn Baldwin     uint32_t val, int width)
3158e8e46ccSJohn Baldwin {
3168e8e46ccSJohn Baldwin 
3178e8e46ccSJohn Baldwin 	pci_write_config(dev, reg, val, width);
3188e8e46ccSJohn Baldwin }
3198e8e46ccSJohn Baldwin 
3208e8e46ccSJohn Baldwin static int
3218e8e46ccSJohn Baldwin vga_pci_enable_busmaster(device_t dev, device_t child)
3228e8e46ccSJohn Baldwin {
3238e8e46ccSJohn Baldwin 
3248e8e46ccSJohn Baldwin 	device_printf(dev, "child %s requested pci_enable_busmaster\n",
3258e8e46ccSJohn Baldwin 	    device_get_nameunit(child));
3268e8e46ccSJohn Baldwin 	return (pci_enable_busmaster(dev));
3278e8e46ccSJohn Baldwin }
3288e8e46ccSJohn Baldwin 
3298e8e46ccSJohn Baldwin static int
3308e8e46ccSJohn Baldwin vga_pci_disable_busmaster(device_t dev, device_t child)
3318e8e46ccSJohn Baldwin {
3328e8e46ccSJohn Baldwin 
3338e8e46ccSJohn Baldwin 	device_printf(dev, "child %s requested pci_disable_busmaster\n",
3348e8e46ccSJohn Baldwin 	    device_get_nameunit(child));
3358e8e46ccSJohn Baldwin 	return (pci_disable_busmaster(dev));
3368e8e46ccSJohn Baldwin }
3378e8e46ccSJohn Baldwin 
3388e8e46ccSJohn Baldwin static int
3398e8e46ccSJohn Baldwin vga_pci_enable_io(device_t dev, device_t child, int space)
3408e8e46ccSJohn Baldwin {
3418e8e46ccSJohn Baldwin 
3428e8e46ccSJohn Baldwin 	device_printf(dev, "child %s requested pci_enable_io\n",
3438e8e46ccSJohn Baldwin 	    device_get_nameunit(child));
3448e8e46ccSJohn Baldwin 	return (pci_enable_io(dev, space));
3458e8e46ccSJohn Baldwin }
3468e8e46ccSJohn Baldwin 
3478e8e46ccSJohn Baldwin static int
3488e8e46ccSJohn Baldwin vga_pci_disable_io(device_t dev, device_t child, int space)
3498e8e46ccSJohn Baldwin {
3508e8e46ccSJohn Baldwin 
3518e8e46ccSJohn Baldwin 	device_printf(dev, "child %s requested pci_disable_io\n",
3528e8e46ccSJohn Baldwin 	    device_get_nameunit(child));
3538e8e46ccSJohn Baldwin 	return (pci_disable_io(dev, space));
3548e8e46ccSJohn Baldwin }
3558e8e46ccSJohn Baldwin 
3568e8e46ccSJohn Baldwin static int
357e7e2941bSJohn Baldwin vga_pci_get_vpd_ident(device_t dev, device_t child, const char **identptr)
358e7e2941bSJohn Baldwin {
359e7e2941bSJohn Baldwin 
360e7e2941bSJohn Baldwin 	return (pci_get_vpd_ident(dev, identptr));
361e7e2941bSJohn Baldwin }
362e7e2941bSJohn Baldwin 
363e7e2941bSJohn Baldwin static int
364e7e2941bSJohn Baldwin vga_pci_get_vpd_readonly(device_t dev, device_t child, const char *kw,
365e7e2941bSJohn Baldwin     const char **vptr)
366e7e2941bSJohn Baldwin {
367e7e2941bSJohn Baldwin 
368e7e2941bSJohn Baldwin 	return (pci_get_vpd_readonly(dev, kw, vptr));
369e7e2941bSJohn Baldwin }
370e7e2941bSJohn Baldwin 
371e7e2941bSJohn Baldwin static int
3728e8e46ccSJohn Baldwin vga_pci_set_powerstate(device_t dev, device_t child, int state)
3738e8e46ccSJohn Baldwin {
3748e8e46ccSJohn Baldwin 
3758e8e46ccSJohn Baldwin 	device_printf(dev, "child %s requested pci_set_powerstate\n",
3768e8e46ccSJohn Baldwin 	    device_get_nameunit(child));
3778e8e46ccSJohn Baldwin 	return (pci_set_powerstate(dev, state));
3788e8e46ccSJohn Baldwin }
3798e8e46ccSJohn Baldwin 
3808e8e46ccSJohn Baldwin static int
3818e8e46ccSJohn Baldwin vga_pci_get_powerstate(device_t dev, device_t child)
3828e8e46ccSJohn Baldwin {
3838e8e46ccSJohn Baldwin 
3848e8e46ccSJohn Baldwin 	device_printf(dev, "child %s requested pci_get_powerstate\n",
3858e8e46ccSJohn Baldwin 	    device_get_nameunit(child));
3868e8e46ccSJohn Baldwin 	return (pci_get_powerstate(dev));
3878e8e46ccSJohn Baldwin }
3888e8e46ccSJohn Baldwin 
3898e8e46ccSJohn Baldwin static int
3908e8e46ccSJohn Baldwin vga_pci_assign_interrupt(device_t dev, device_t child)
3918e8e46ccSJohn Baldwin {
3928e8e46ccSJohn Baldwin 
3938e8e46ccSJohn Baldwin 	device_printf(dev, "child %s requested pci_assign_interrupt\n",
3948e8e46ccSJohn Baldwin 	    device_get_nameunit(child));
3958e8e46ccSJohn Baldwin 	return (PCI_ASSIGN_INTERRUPT(device_get_parent(dev), dev));
3968e8e46ccSJohn Baldwin }
3978e8e46ccSJohn Baldwin 
3988e8e46ccSJohn Baldwin static int
3998e8e46ccSJohn Baldwin vga_pci_find_extcap(device_t dev, device_t child, int capability,
4008e8e46ccSJohn Baldwin     int *capreg)
4018e8e46ccSJohn Baldwin {
4028e8e46ccSJohn Baldwin 
4038e8e46ccSJohn Baldwin 	return (pci_find_extcap(dev, capability, capreg));
4048e8e46ccSJohn Baldwin }
4058e8e46ccSJohn Baldwin 
406e7e2941bSJohn Baldwin static int
407e7e2941bSJohn Baldwin vga_pci_alloc_msi(device_t dev, device_t child, int *count)
408e7e2941bSJohn Baldwin {
409e7e2941bSJohn Baldwin 	struct vga_pci_softc *sc;
410e7e2941bSJohn Baldwin 	int error;
411e7e2941bSJohn Baldwin 
412e7e2941bSJohn Baldwin 	sc = device_get_softc(dev);
413e7e2941bSJohn Baldwin 	if (sc->vga_msi_child != NULL)
414e7e2941bSJohn Baldwin 		return (EBUSY);
415e7e2941bSJohn Baldwin 	error = pci_alloc_msi(dev, count);
416e7e2941bSJohn Baldwin 	if (error == 0)
417e7e2941bSJohn Baldwin 		sc->vga_msi_child = child;
418e7e2941bSJohn Baldwin 	return (error);
419e7e2941bSJohn Baldwin }
420e7e2941bSJohn Baldwin 
421e7e2941bSJohn Baldwin static int
422e7e2941bSJohn Baldwin vga_pci_alloc_msix(device_t dev, device_t child, int *count)
423e7e2941bSJohn Baldwin {
424e7e2941bSJohn Baldwin 	struct vga_pci_softc *sc;
425e7e2941bSJohn Baldwin 	int error;
426e7e2941bSJohn Baldwin 
427e7e2941bSJohn Baldwin 	sc = device_get_softc(dev);
428e7e2941bSJohn Baldwin 	if (sc->vga_msi_child != NULL)
429e7e2941bSJohn Baldwin 		return (EBUSY);
430e7e2941bSJohn Baldwin 	error = pci_alloc_msix(dev, count);
431e7e2941bSJohn Baldwin 	if (error == 0)
432e7e2941bSJohn Baldwin 		sc->vga_msi_child = child;
433e7e2941bSJohn Baldwin 	return (error);
434e7e2941bSJohn Baldwin }
435e7e2941bSJohn Baldwin 
436e7e2941bSJohn Baldwin static int
437e7e2941bSJohn Baldwin vga_pci_remap_msix(device_t dev, device_t child, int count,
438e7e2941bSJohn Baldwin     const u_int *vectors)
439e7e2941bSJohn Baldwin {
440e7e2941bSJohn Baldwin 	struct vga_pci_softc *sc;
441e7e2941bSJohn Baldwin 
442e7e2941bSJohn Baldwin 	sc = device_get_softc(dev);
443e7e2941bSJohn Baldwin 	if (sc->vga_msi_child != child)
444e7e2941bSJohn Baldwin 		return (ENXIO);
445e7e2941bSJohn Baldwin 	return (pci_remap_msix(dev, count, vectors));
446e7e2941bSJohn Baldwin }
447e7e2941bSJohn Baldwin 
448e7e2941bSJohn Baldwin static int
449e7e2941bSJohn Baldwin vga_pci_release_msi(device_t dev, device_t child)
450e7e2941bSJohn Baldwin {
451e7e2941bSJohn Baldwin 	struct vga_pci_softc *sc;
452e7e2941bSJohn Baldwin 	int error;
453e7e2941bSJohn Baldwin 
454e7e2941bSJohn Baldwin 	sc = device_get_softc(dev);
455e7e2941bSJohn Baldwin 	if (sc->vga_msi_child != child)
456e7e2941bSJohn Baldwin 		return (ENXIO);
457e7e2941bSJohn Baldwin 	error = pci_release_msi(dev);
458e7e2941bSJohn Baldwin 	if (error == 0)
459e7e2941bSJohn Baldwin 		sc->vga_msi_child = NULL;
460e7e2941bSJohn Baldwin 	return (error);
461e7e2941bSJohn Baldwin }
462e7e2941bSJohn Baldwin 
463e7e2941bSJohn Baldwin static int
464e7e2941bSJohn Baldwin vga_pci_msi_count(device_t dev, device_t child)
465e7e2941bSJohn Baldwin {
466e7e2941bSJohn Baldwin 
467e7e2941bSJohn Baldwin 	return (pci_msi_count(dev));
468e7e2941bSJohn Baldwin }
469e7e2941bSJohn Baldwin 
470e7e2941bSJohn Baldwin static int
471e7e2941bSJohn Baldwin vga_pci_msix_count(device_t dev, device_t child)
472e7e2941bSJohn Baldwin {
473e7e2941bSJohn Baldwin 
474e7e2941bSJohn Baldwin 	return (pci_msix_count(dev));
475e7e2941bSJohn Baldwin }
476e7e2941bSJohn Baldwin 
4778e8e46ccSJohn Baldwin static device_method_t vga_pci_methods[] = {
4788e8e46ccSJohn Baldwin 	/* Device interface */
4798e8e46ccSJohn Baldwin 	DEVMETHOD(device_probe,		vga_pci_probe),
4808e8e46ccSJohn Baldwin 	DEVMETHOD(device_attach,	vga_pci_attach),
4818e8e46ccSJohn Baldwin 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
4828e8e46ccSJohn Baldwin 	DEVMETHOD(device_suspend,	vga_pci_suspend),
4838e8e46ccSJohn Baldwin 	DEVMETHOD(device_resume,	vga_pci_resume),
4848e8e46ccSJohn Baldwin 
4858e8e46ccSJohn Baldwin 	/* Bus interface */
4868e8e46ccSJohn Baldwin 	DEVMETHOD(bus_read_ivar,	vga_pci_read_ivar),
4878e8e46ccSJohn Baldwin 	DEVMETHOD(bus_write_ivar,	vga_pci_write_ivar),
4886be0323dSRobert Noland 	DEVMETHOD(bus_setup_intr,	vga_pci_setup_intr),
4896be0323dSRobert Noland 	DEVMETHOD(bus_teardown_intr,	vga_pci_teardown_intr),
4908e8e46ccSJohn Baldwin 
4918e8e46ccSJohn Baldwin 	DEVMETHOD(bus_alloc_resource,	vga_pci_alloc_resource),
4928e8e46ccSJohn Baldwin 	DEVMETHOD(bus_release_resource,	vga_pci_release_resource),
4938e8e46ccSJohn Baldwin 	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
4948e8e46ccSJohn Baldwin 	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
4958e8e46ccSJohn Baldwin 
4968e8e46ccSJohn Baldwin 	/* PCI interface */
4978e8e46ccSJohn Baldwin 	DEVMETHOD(pci_read_config,	vga_pci_read_config),
4988e8e46ccSJohn Baldwin 	DEVMETHOD(pci_write_config,	vga_pci_write_config),
4998e8e46ccSJohn Baldwin 	DEVMETHOD(pci_enable_busmaster,	vga_pci_enable_busmaster),
5008e8e46ccSJohn Baldwin 	DEVMETHOD(pci_disable_busmaster, vga_pci_disable_busmaster),
5018e8e46ccSJohn Baldwin 	DEVMETHOD(pci_enable_io,	vga_pci_enable_io),
5028e8e46ccSJohn Baldwin 	DEVMETHOD(pci_disable_io,	vga_pci_disable_io),
503e7e2941bSJohn Baldwin 	DEVMETHOD(pci_get_vpd_ident,	vga_pci_get_vpd_ident),
504e7e2941bSJohn Baldwin 	DEVMETHOD(pci_get_vpd_readonly,	vga_pci_get_vpd_readonly),
5058e8e46ccSJohn Baldwin 	DEVMETHOD(pci_get_powerstate,	vga_pci_get_powerstate),
5068e8e46ccSJohn Baldwin 	DEVMETHOD(pci_set_powerstate,	vga_pci_set_powerstate),
5078e8e46ccSJohn Baldwin 	DEVMETHOD(pci_assign_interrupt,	vga_pci_assign_interrupt),
5088e8e46ccSJohn Baldwin 	DEVMETHOD(pci_find_extcap,	vga_pci_find_extcap),
509e7e2941bSJohn Baldwin 	DEVMETHOD(pci_alloc_msi,	vga_pci_alloc_msi),
510e7e2941bSJohn Baldwin 	DEVMETHOD(pci_alloc_msix,	vga_pci_alloc_msix),
511e7e2941bSJohn Baldwin 	DEVMETHOD(pci_remap_msix,	vga_pci_remap_msix),
512e7e2941bSJohn Baldwin 	DEVMETHOD(pci_release_msi,	vga_pci_release_msi),
513e7e2941bSJohn Baldwin 	DEVMETHOD(pci_msi_count,	vga_pci_msi_count),
514e7e2941bSJohn Baldwin 	DEVMETHOD(pci_msix_count,	vga_pci_msix_count),
5158e8e46ccSJohn Baldwin 
5168e8e46ccSJohn Baldwin 	{ 0, 0 }
5178e8e46ccSJohn Baldwin };
5188e8e46ccSJohn Baldwin 
5198e8e46ccSJohn Baldwin static driver_t vga_pci_driver = {
5208e8e46ccSJohn Baldwin 	"vgapci",
5218e8e46ccSJohn Baldwin 	vga_pci_methods,
522e7e2941bSJohn Baldwin 	sizeof(struct vga_pci_softc),
5238e8e46ccSJohn Baldwin };
5248e8e46ccSJohn Baldwin 
5258e8e46ccSJohn Baldwin static devclass_t vga_devclass;
5268e8e46ccSJohn Baldwin 
5278e8e46ccSJohn Baldwin DRIVER_MODULE(vgapci, pci, vga_pci_driver, vga_devclass, 0, 0);
528