vga_pci.c revision 183095
1/*-
2 * Copyright (c) 2005 John Baldwin <jhb@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the author nor the names of any co-contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: head/sys/dev/pci/vga_pci.c 183095 2008-09-16 19:52:02Z jhb $");
32
33/*
34 * Simple driver for PCI VGA display devices.  Drivers such as agp(4) and
35 * drm(4) should attach as children of this device.
36 *
37 * XXX: The vgapci name is a hack until we somehow merge the isa vga driver
38 * in or rename it.
39 */
40
41#include <sys/param.h>
42#include <sys/bus.h>
43#include <sys/kernel.h>
44#include <sys/module.h>
45
46#include <dev/pci/pcireg.h>
47#include <dev/pci/pcivar.h>
48
49struct vga_pci_softc {
50	device_t	vga_msi_child;	/* Child driver using MSI. */
51};
52
53static int
54vga_pci_probe(device_t dev)
55{
56
57	switch (pci_get_class(dev)) {
58	case PCIC_DISPLAY:
59		break;
60	case PCIC_OLD:
61		if (pci_get_subclass(dev) != PCIS_OLD_VGA)
62			return (ENXIO);
63		break;
64	default:
65		return (ENXIO);
66	}
67	device_set_desc(dev, "VGA-compatible display");
68	return (BUS_PROBE_GENERIC);
69}
70
71static int
72vga_pci_attach(device_t dev)
73{
74
75	bus_generic_probe(dev);
76
77	/* Always create a drm child for now to make it easier on drm. */
78	device_add_child(dev, "drm", -1);
79	bus_generic_attach(dev);
80	return (0);
81}
82
83static int
84vga_pci_suspend(device_t dev)
85{
86
87	return (bus_generic_suspend(dev));
88}
89
90static int
91vga_pci_resume(device_t dev)
92{
93
94	return (bus_generic_resume(dev));
95}
96
97/* Bus interface. */
98
99static int
100vga_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
101{
102
103	return (BUS_READ_IVAR(device_get_parent(dev), dev, which, result));
104}
105
106static int
107vga_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
108{
109
110	return (EINVAL);
111}
112
113static struct resource *
114vga_pci_alloc_resource(device_t dev, device_t child, int type, int *rid,
115    u_long start, u_long end, u_long count, u_int flags)
116{
117
118	return (bus_alloc_resource(dev, type, rid, start, end, count, flags));
119}
120
121static int
122vga_pci_release_resource(device_t dev, device_t child, int type, int rid,
123    struct resource *r)
124{
125
126	return (bus_release_resource(dev, type, rid, r));
127}
128
129/* PCI interface. */
130
131static uint32_t
132vga_pci_read_config(device_t dev, device_t child, int reg, int width)
133{
134
135	return (pci_read_config(dev, reg, width));
136}
137
138static void
139vga_pci_write_config(device_t dev, device_t child, int reg,
140    uint32_t val, int width)
141{
142
143	pci_write_config(dev, reg, val, width);
144}
145
146static int
147vga_pci_enable_busmaster(device_t dev, device_t child)
148{
149
150	device_printf(dev, "child %s requested pci_enable_busmaster\n",
151	    device_get_nameunit(child));
152	return (pci_enable_busmaster(dev));
153}
154
155static int
156vga_pci_disable_busmaster(device_t dev, device_t child)
157{
158
159	device_printf(dev, "child %s requested pci_disable_busmaster\n",
160	    device_get_nameunit(child));
161	return (pci_disable_busmaster(dev));
162}
163
164static int
165vga_pci_enable_io(device_t dev, device_t child, int space)
166{
167
168	device_printf(dev, "child %s requested pci_enable_io\n",
169	    device_get_nameunit(child));
170	return (pci_enable_io(dev, space));
171}
172
173static int
174vga_pci_disable_io(device_t dev, device_t child, int space)
175{
176
177	device_printf(dev, "child %s requested pci_disable_io\n",
178	    device_get_nameunit(child));
179	return (pci_disable_io(dev, space));
180}
181
182static int
183vga_pci_get_vpd_ident(device_t dev, device_t child, const char **identptr)
184{
185
186	return (pci_get_vpd_ident(dev, identptr));
187}
188
189static int
190vga_pci_get_vpd_readonly(device_t dev, device_t child, const char *kw,
191    const char **vptr)
192{
193
194	return (pci_get_vpd_readonly(dev, kw, vptr));
195}
196
197static int
198vga_pci_set_powerstate(device_t dev, device_t child, int state)
199{
200
201	device_printf(dev, "child %s requested pci_set_powerstate\n",
202	    device_get_nameunit(child));
203	return (pci_set_powerstate(dev, state));
204}
205
206static int
207vga_pci_get_powerstate(device_t dev, device_t child)
208{
209
210	device_printf(dev, "child %s requested pci_get_powerstate\n",
211	    device_get_nameunit(child));
212	return (pci_get_powerstate(dev));
213}
214
215static int
216vga_pci_assign_interrupt(device_t dev, device_t child)
217{
218
219	device_printf(dev, "child %s requested pci_assign_interrupt\n",
220	    device_get_nameunit(child));
221	return (PCI_ASSIGN_INTERRUPT(device_get_parent(dev), dev));
222}
223
224static int
225vga_pci_find_extcap(device_t dev, device_t child, int capability,
226    int *capreg)
227{
228
229	return (pci_find_extcap(dev, capability, capreg));
230}
231
232static int
233vga_pci_alloc_msi(device_t dev, device_t child, int *count)
234{
235	struct vga_pci_softc *sc;
236	int error;
237
238	sc = device_get_softc(dev);
239	if (sc->vga_msi_child != NULL)
240		return (EBUSY);
241	error = pci_alloc_msi(dev, count);
242	if (error == 0)
243		sc->vga_msi_child = child;
244	return (error);
245}
246
247static int
248vga_pci_alloc_msix(device_t dev, device_t child, int *count)
249{
250	struct vga_pci_softc *sc;
251	int error;
252
253	sc = device_get_softc(dev);
254	if (sc->vga_msi_child != NULL)
255		return (EBUSY);
256	error = pci_alloc_msix(dev, count);
257	if (error == 0)
258		sc->vga_msi_child = child;
259	return (error);
260}
261
262static int
263vga_pci_remap_msix(device_t dev, device_t child, int count,
264    const u_int *vectors)
265{
266	struct vga_pci_softc *sc;
267
268	sc = device_get_softc(dev);
269	if (sc->vga_msi_child != child)
270		return (ENXIO);
271	return (pci_remap_msix(dev, count, vectors));
272}
273
274static int
275vga_pci_release_msi(device_t dev, device_t child)
276{
277	struct vga_pci_softc *sc;
278	int error;
279
280	sc = device_get_softc(dev);
281	if (sc->vga_msi_child != child)
282		return (ENXIO);
283	error = pci_release_msi(dev);
284	if (error == 0)
285		sc->vga_msi_child = NULL;
286	return (error);
287}
288
289static int
290vga_pci_msi_count(device_t dev, device_t child)
291{
292
293	return (pci_msi_count(dev));
294}
295
296static int
297vga_pci_msix_count(device_t dev, device_t child)
298{
299
300	return (pci_msix_count(dev));
301}
302
303static device_method_t vga_pci_methods[] = {
304	/* Device interface */
305	DEVMETHOD(device_probe,		vga_pci_probe),
306	DEVMETHOD(device_attach,	vga_pci_attach),
307	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
308	DEVMETHOD(device_suspend,	vga_pci_suspend),
309	DEVMETHOD(device_resume,	vga_pci_resume),
310
311	/* Bus interface */
312	DEVMETHOD(bus_read_ivar,	vga_pci_read_ivar),
313	DEVMETHOD(bus_write_ivar,	vga_pci_write_ivar),
314	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
315	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
316
317	DEVMETHOD(bus_alloc_resource,	vga_pci_alloc_resource),
318	DEVMETHOD(bus_release_resource,	vga_pci_release_resource),
319	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
320	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
321
322	/* PCI interface */
323	DEVMETHOD(pci_read_config,	vga_pci_read_config),
324	DEVMETHOD(pci_write_config,	vga_pci_write_config),
325	DEVMETHOD(pci_enable_busmaster,	vga_pci_enable_busmaster),
326	DEVMETHOD(pci_disable_busmaster, vga_pci_disable_busmaster),
327	DEVMETHOD(pci_enable_io,	vga_pci_enable_io),
328	DEVMETHOD(pci_disable_io,	vga_pci_disable_io),
329	DEVMETHOD(pci_get_vpd_ident,	vga_pci_get_vpd_ident),
330	DEVMETHOD(pci_get_vpd_readonly,	vga_pci_get_vpd_readonly),
331	DEVMETHOD(pci_get_powerstate,	vga_pci_get_powerstate),
332	DEVMETHOD(pci_set_powerstate,	vga_pci_set_powerstate),
333	DEVMETHOD(pci_assign_interrupt,	vga_pci_assign_interrupt),
334	DEVMETHOD(pci_find_extcap,	vga_pci_find_extcap),
335	DEVMETHOD(pci_alloc_msi,	vga_pci_alloc_msi),
336	DEVMETHOD(pci_alloc_msix,	vga_pci_alloc_msix),
337	DEVMETHOD(pci_remap_msix,	vga_pci_remap_msix),
338	DEVMETHOD(pci_release_msi,	vga_pci_release_msi),
339	DEVMETHOD(pci_msi_count,	vga_pci_msi_count),
340	DEVMETHOD(pci_msix_count,	vga_pci_msix_count),
341
342	{ 0, 0 }
343};
344
345static driver_t vga_pci_driver = {
346	"vgapci",
347	vga_pci_methods,
348	sizeof(struct vga_pci_softc),
349};
350
351static devclass_t vga_devclass;
352
353DRIVER_MODULE(vgapci, pci, vga_pci_driver, vga_devclass, 0, 0);
354