xref: /dflybsd-src/stand/boot/pc32/libi386/biospci.c (revision 479ab7f0492f2a51b48e8537e4f1dc686fc6014b)
1*479ab7f0SSascha Wildner /*-
2*479ab7f0SSascha Wildner  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3*479ab7f0SSascha Wildner  * All rights reserved.
4*479ab7f0SSascha Wildner  *
5*479ab7f0SSascha Wildner  * Redistribution and use in source and binary forms, with or without
6*479ab7f0SSascha Wildner  * modification, are permitted provided that the following conditions
7*479ab7f0SSascha Wildner  * are met:
8*479ab7f0SSascha Wildner  * 1. Redistributions of source code must retain the above copyright
9*479ab7f0SSascha Wildner  *    notice, this list of conditions and the following disclaimer.
10*479ab7f0SSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
11*479ab7f0SSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
12*479ab7f0SSascha Wildner  *    documentation and/or other materials provided with the distribution.
13*479ab7f0SSascha Wildner  *
14*479ab7f0SSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*479ab7f0SSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*479ab7f0SSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*479ab7f0SSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*479ab7f0SSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*479ab7f0SSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*479ab7f0SSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*479ab7f0SSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*479ab7f0SSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*479ab7f0SSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*479ab7f0SSascha Wildner  * SUCH DAMAGE.
25*479ab7f0SSascha Wildner  *
26*479ab7f0SSascha Wildner  * $FreeBSD: src/sys/boot/i386/libi386/biospci.c,v 1.4 2003/08/25 23:28:31 obrien Exp $
27*479ab7f0SSascha Wildner  */
28*479ab7f0SSascha Wildner 
29*479ab7f0SSascha Wildner /*
30*479ab7f0SSascha Wildner  * PnP enumerator using the PCI BIOS.
31*479ab7f0SSascha Wildner  */
32*479ab7f0SSascha Wildner 
33*479ab7f0SSascha Wildner #include <stand.h>
34*479ab7f0SSascha Wildner #include <machine/stdarg.h>
35*479ab7f0SSascha Wildner #include <machine/psl.h>
36*479ab7f0SSascha Wildner #include <bootstrap.h>
37*479ab7f0SSascha Wildner #include <isapnp.h>
38*479ab7f0SSascha Wildner #include <btxv86.h>
39*479ab7f0SSascha Wildner 
40*479ab7f0SSascha Wildner /*
41*479ab7f0SSascha Wildner  * Stupid PCI BIOS interface doesn't let you simply enumerate everything
42*479ab7f0SSascha Wildner  * that's there, instead you have to ask it if it has something.
43*479ab7f0SSascha Wildner  *
44*479ab7f0SSascha Wildner  * So we have to scan by class code, subclass code and sometimes programming
45*479ab7f0SSascha Wildner  * interface.
46*479ab7f0SSascha Wildner  */
47*479ab7f0SSascha Wildner 
48*479ab7f0SSascha Wildner struct pci_progif
49*479ab7f0SSascha Wildner {
50*479ab7f0SSascha Wildner     int		pi_code;
51*479ab7f0SSascha Wildner     const char	*pi_name;
52*479ab7f0SSascha Wildner };
53*479ab7f0SSascha Wildner 
54*479ab7f0SSascha Wildner static struct pci_progif progif_null[] = {
55*479ab7f0SSascha Wildner     {0x0,	NULL},
56*479ab7f0SSascha Wildner     {-1,	NULL}
57*479ab7f0SSascha Wildner };
58*479ab7f0SSascha Wildner 
59*479ab7f0SSascha Wildner static struct pci_progif progif_display[] = {
60*479ab7f0SSascha Wildner     {0x0,	"VGA"},
61*479ab7f0SSascha Wildner     {0x1,	"8514"},
62*479ab7f0SSascha Wildner     {-1,	NULL}
63*479ab7f0SSascha Wildner };
64*479ab7f0SSascha Wildner 
65*479ab7f0SSascha Wildner static struct pci_progif progif_ide[] = {
66*479ab7f0SSascha Wildner     {0x00,	NULL},
67*479ab7f0SSascha Wildner     {0x01,	NULL},
68*479ab7f0SSascha Wildner     {0x02,	NULL},
69*479ab7f0SSascha Wildner     {0x03,	NULL},
70*479ab7f0SSascha Wildner     {0x04,	NULL},
71*479ab7f0SSascha Wildner     {0x05,	NULL},
72*479ab7f0SSascha Wildner     {0x06,	NULL},
73*479ab7f0SSascha Wildner     {0x07,	NULL},
74*479ab7f0SSascha Wildner     {0x08,	NULL},
75*479ab7f0SSascha Wildner     {0x09,	NULL},
76*479ab7f0SSascha Wildner     {0x0a,	NULL},
77*479ab7f0SSascha Wildner     {0x0b,	NULL},
78*479ab7f0SSascha Wildner     {0x0c,	NULL},
79*479ab7f0SSascha Wildner     {0x0d,	NULL},
80*479ab7f0SSascha Wildner     {0x0e,	NULL},
81*479ab7f0SSascha Wildner     {0x0f,	NULL},
82*479ab7f0SSascha Wildner     {0x80,	NULL},
83*479ab7f0SSascha Wildner     {0x81,	NULL},
84*479ab7f0SSascha Wildner     {0x82,	NULL},
85*479ab7f0SSascha Wildner     {0x83,	NULL},
86*479ab7f0SSascha Wildner     {0x84,	NULL},
87*479ab7f0SSascha Wildner     {0x85,	NULL},
88*479ab7f0SSascha Wildner     {0x86,	NULL},
89*479ab7f0SSascha Wildner     {0x87,	NULL},
90*479ab7f0SSascha Wildner     {0x88,	NULL},
91*479ab7f0SSascha Wildner     {0x89,	NULL},
92*479ab7f0SSascha Wildner     {0x8a,	NULL},
93*479ab7f0SSascha Wildner     {0x8b,	NULL},
94*479ab7f0SSascha Wildner     {0x8c,	NULL},
95*479ab7f0SSascha Wildner     {0x8d,	NULL},
96*479ab7f0SSascha Wildner     {0x8e,	NULL},
97*479ab7f0SSascha Wildner     {0x8f,	NULL},
98*479ab7f0SSascha Wildner     {-1,	NULL}
99*479ab7f0SSascha Wildner };
100*479ab7f0SSascha Wildner 
101*479ab7f0SSascha Wildner static struct pci_progif progif_serial[] = {
102*479ab7f0SSascha Wildner     {0x0,	"8250"},
103*479ab7f0SSascha Wildner     {0x1,	"16450"},
104*479ab7f0SSascha Wildner     {0x2,	"16550"},
105*479ab7f0SSascha Wildner     {-1,	NULL}
106*479ab7f0SSascha Wildner };
107*479ab7f0SSascha Wildner 
108*479ab7f0SSascha Wildner static struct pci_progif progif_parallel[] = {
109*479ab7f0SSascha Wildner     {0x0,	"Standard"},
110*479ab7f0SSascha Wildner     {0x1,	"Bidirectional"},
111*479ab7f0SSascha Wildner     {0x2,	"ECP"},
112*479ab7f0SSascha Wildner     {-1,	NULL}
113*479ab7f0SSascha Wildner };
114*479ab7f0SSascha Wildner 
115*479ab7f0SSascha Wildner 
116*479ab7f0SSascha Wildner struct pci_subclass
117*479ab7f0SSascha Wildner {
118*479ab7f0SSascha Wildner     int			ps_subclass;
119*479ab7f0SSascha Wildner     const char		*ps_name;
120*479ab7f0SSascha Wildner     struct pci_progif	*ps_progif;	/* if set, use for programming interface value(s) */
121*479ab7f0SSascha Wildner };
122*479ab7f0SSascha Wildner 
123*479ab7f0SSascha Wildner static struct pci_subclass subclass_old[] = {
124*479ab7f0SSascha Wildner     {0x0,	"Old non-VGA",		progif_null},
125*479ab7f0SSascha Wildner     {0x1,	"Old VGA",		progif_null},
126*479ab7f0SSascha Wildner     {-1,	NULL,			NULL}
127*479ab7f0SSascha Wildner };
128*479ab7f0SSascha Wildner 
129*479ab7f0SSascha Wildner static struct pci_subclass subclass_mass[] = {
130*479ab7f0SSascha Wildner     {0x0,	"SCSI",			progif_null},
131*479ab7f0SSascha Wildner     {0x1,	"IDE",			progif_ide},
132*479ab7f0SSascha Wildner     {0x2,	"Floppy disk",		progif_null},
133*479ab7f0SSascha Wildner     {0x3,	"IPI",			progif_null},
134*479ab7f0SSascha Wildner     {0x4,	"RAID",			progif_null},
135*479ab7f0SSascha Wildner     {0x80,	"mass storage",		progif_null},
136*479ab7f0SSascha Wildner     {-1,	NULL,			NULL}
137*479ab7f0SSascha Wildner };
138*479ab7f0SSascha Wildner 
139*479ab7f0SSascha Wildner static struct pci_subclass subclass_net[] = {
140*479ab7f0SSascha Wildner     {0x0,	"Ethernet",		progif_null},
141*479ab7f0SSascha Wildner     {0x1,	"Token ring",		progif_null},
142*479ab7f0SSascha Wildner     {0x2,	"FDDI",			progif_null},
143*479ab7f0SSascha Wildner     {0x3,	"ATM",			progif_null},
144*479ab7f0SSascha Wildner     {0x80,	"network",		progif_null},
145*479ab7f0SSascha Wildner     {-1,	NULL,			NULL}
146*479ab7f0SSascha Wildner };
147*479ab7f0SSascha Wildner 
148*479ab7f0SSascha Wildner static struct pci_subclass subclass_display[] = {
149*479ab7f0SSascha Wildner     {0x0,	NULL,			progif_display},
150*479ab7f0SSascha Wildner     {0x1,	"XGA",			progif_null},
151*479ab7f0SSascha Wildner     {0x80,	"other",		progif_null},
152*479ab7f0SSascha Wildner     {-1,	NULL,			NULL}
153*479ab7f0SSascha Wildner };
154*479ab7f0SSascha Wildner 
155*479ab7f0SSascha Wildner static struct pci_subclass subclass_comms[] = {
156*479ab7f0SSascha Wildner     {0x0,	"serial",		progif_serial},
157*479ab7f0SSascha Wildner     {0x1,	"parallel",		progif_parallel},
158*479ab7f0SSascha Wildner     {0x80,	"communications",	progif_null},
159*479ab7f0SSascha Wildner     {-1,	NULL,			NULL}
160*479ab7f0SSascha Wildner };
161*479ab7f0SSascha Wildner 
162*479ab7f0SSascha Wildner static struct pci_subclass subclass_serial[] = {
163*479ab7f0SSascha Wildner     {0x0,	"Firewire",		progif_null},
164*479ab7f0SSascha Wildner     {0x1,	"ACCESS.bus",		progif_null},
165*479ab7f0SSascha Wildner     {0x2,	"SSA",			progif_null},
166*479ab7f0SSascha Wildner     {0x3,	"USB",			progif_null},
167*479ab7f0SSascha Wildner     {0x4,	"Fibrechannel",		progif_null},
168*479ab7f0SSascha Wildner     {-1,	NULL,			NULL}
169*479ab7f0SSascha Wildner };
170*479ab7f0SSascha Wildner 
171*479ab7f0SSascha Wildner static struct pci_class
172*479ab7f0SSascha Wildner {
173*479ab7f0SSascha Wildner     int			pc_class;
174*479ab7f0SSascha Wildner     const char		*pc_name;
175*479ab7f0SSascha Wildner     struct pci_subclass	*pc_subclass;
176*479ab7f0SSascha Wildner } pci_classes[] = {
177*479ab7f0SSascha Wildner     {0x0,	"device",	subclass_old},
178*479ab7f0SSascha Wildner     {0x1,	"controller",	subclass_mass},
179*479ab7f0SSascha Wildner     {0x2,	"controller",	subclass_net},
180*479ab7f0SSascha Wildner     {0x3,	"display",	subclass_display},
181*479ab7f0SSascha Wildner     {0x7,	"controller",	subclass_comms},
182*479ab7f0SSascha Wildner     {0xc,	"controller",	subclass_serial},
183*479ab7f0SSascha Wildner     {-1,	NULL,		NULL}
184*479ab7f0SSascha Wildner };
185*479ab7f0SSascha Wildner 
186*479ab7f0SSascha Wildner 
187*479ab7f0SSascha Wildner static void	biospci_enumerate(void);
188*479ab7f0SSascha Wildner static void	biospci_addinfo(int devid, struct pci_class *pc, struct pci_subclass *psc, struct pci_progif *ppi);
189*479ab7f0SSascha Wildner 
190*479ab7f0SSascha Wildner static int	biospci_version;
191*479ab7f0SSascha Wildner static int	biospci_hwcap;
192*479ab7f0SSascha Wildner 
193*479ab7f0SSascha Wildner struct pnphandler biospcihandler =
194*479ab7f0SSascha Wildner {
195*479ab7f0SSascha Wildner     "PCI BIOS",
196*479ab7f0SSascha Wildner     biospci_enumerate
197*479ab7f0SSascha Wildner };
198*479ab7f0SSascha Wildner 
199*479ab7f0SSascha Wildner static void
biospci_enumerate(void)200*479ab7f0SSascha Wildner biospci_enumerate(void)
201*479ab7f0SSascha Wildner {
202*479ab7f0SSascha Wildner     int			device_index, locator, devid;
203*479ab7f0SSascha Wildner     struct pci_class	*pc;
204*479ab7f0SSascha Wildner     struct pci_subclass *psc;
205*479ab7f0SSascha Wildner     struct pci_progif	*ppi;
206*479ab7f0SSascha Wildner 
207*479ab7f0SSascha Wildner     /* Find the PCI BIOS */
208*479ab7f0SSascha Wildner     v86.ctl = V86_FLAGS;
209*479ab7f0SSascha Wildner     v86.addr = 0x1a;
210*479ab7f0SSascha Wildner     v86.eax = 0xb101;
211*479ab7f0SSascha Wildner     v86.edi = 0x0;
212*479ab7f0SSascha Wildner     v86int();
213*479ab7f0SSascha Wildner 
214*479ab7f0SSascha Wildner     /* Check for OK response */
215*479ab7f0SSascha Wildner     if ((v86.efl & PSL_C) || ((v86.eax & 0xff00) != 0) || (v86.edx != 0x20494350))
216*479ab7f0SSascha Wildner 	return;
217*479ab7f0SSascha Wildner 
218*479ab7f0SSascha Wildner     biospci_version = v86.ebx & 0xffff;
219*479ab7f0SSascha Wildner     biospci_hwcap = v86.eax & 0xff;
220*479ab7f0SSascha Wildner #if 0
221*479ab7f0SSascha Wildner     printf("PCI BIOS %d.%d%s%s\n",
222*479ab7f0SSascha Wildner 	   bcd2bin((biospci_version >> 8) & 0xf), bcd2bin(biospci_version & 0xf),
223*479ab7f0SSascha Wildner 	   (biospci_hwcap & 1) ? " config1" : "", (biospci_hwcap & 2) ? " config2" : "");
224*479ab7f0SSascha Wildner #endif
225*479ab7f0SSascha Wildner     /* Iterate over known classes */
226*479ab7f0SSascha Wildner     for (pc = pci_classes; pc->pc_class >= 0; pc++) {
227*479ab7f0SSascha Wildner 	/* Iterate over subclasses */
228*479ab7f0SSascha Wildner 	for (psc = pc->pc_subclass; psc->ps_subclass >= 0; psc++) {
229*479ab7f0SSascha Wildner 	    /* Iterate over programming interfaces */
230*479ab7f0SSascha Wildner 	    for (ppi = psc->ps_progif; ppi->pi_code >= 0; ppi++) {
231*479ab7f0SSascha Wildner 
232*479ab7f0SSascha Wildner 		/* Scan for matches */
233*479ab7f0SSascha Wildner 		for (device_index = 0; ; device_index++) {
234*479ab7f0SSascha Wildner 
235*479ab7f0SSascha Wildner 		    /* Look for a match */
236*479ab7f0SSascha Wildner 		    v86.ctl = V86_FLAGS;
237*479ab7f0SSascha Wildner 		    v86.addr = 0x1a;
238*479ab7f0SSascha Wildner 		    v86.eax = 0xb103;
239*479ab7f0SSascha Wildner 		    v86.ecx = (pc->pc_class << 16) + (psc->ps_subclass << 8) + ppi->pi_code;
240*479ab7f0SSascha Wildner 		    v86.esi = device_index;
241*479ab7f0SSascha Wildner 		    v86int();
242*479ab7f0SSascha Wildner 		    /* error/end of matches */
243*479ab7f0SSascha Wildner 		    if ((v86.efl & PSL_C) || (v86.eax & 0xff00))
244*479ab7f0SSascha Wildner 			break;
245*479ab7f0SSascha Wildner 
246*479ab7f0SSascha Wildner 		    /* Got something */
247*479ab7f0SSascha Wildner 		    locator = v86.ebx;
248*479ab7f0SSascha Wildner 
249*479ab7f0SSascha Wildner 		    /* Read the device identifier from the nominated device */
250*479ab7f0SSascha Wildner 		    v86.ctl = V86_FLAGS;
251*479ab7f0SSascha Wildner 		    v86.addr = 0x1a;
252*479ab7f0SSascha Wildner 		    v86.eax = 0xb10a;
253*479ab7f0SSascha Wildner 		    v86.ebx = locator;
254*479ab7f0SSascha Wildner 		    v86.edi = 0x0;
255*479ab7f0SSascha Wildner 		    v86int();
256*479ab7f0SSascha Wildner 		    /* error */
257*479ab7f0SSascha Wildner 		    if ((v86.efl & PSL_C) || (v86.eax & 0xff00))
258*479ab7f0SSascha Wildner 			break;
259*479ab7f0SSascha Wildner 
260*479ab7f0SSascha Wildner 		    /* We have the device ID, create a PnP object and save everything */
261*479ab7f0SSascha Wildner 		    devid = v86.ecx;
262*479ab7f0SSascha Wildner 		    biospci_addinfo(devid, pc, psc, ppi);
263*479ab7f0SSascha Wildner 		}
264*479ab7f0SSascha Wildner 	    }
265*479ab7f0SSascha Wildner 	}
266*479ab7f0SSascha Wildner     }
267*479ab7f0SSascha Wildner }
268*479ab7f0SSascha Wildner 
269*479ab7f0SSascha Wildner static void
biospci_addinfo(int devid,struct pci_class * pc,struct pci_subclass * psc,struct pci_progif * ppi)270*479ab7f0SSascha Wildner biospci_addinfo(int devid, struct pci_class *pc, struct pci_subclass *psc, struct pci_progif *ppi)
271*479ab7f0SSascha Wildner {
272*479ab7f0SSascha Wildner     struct pnpinfo	*pi;
273*479ab7f0SSascha Wildner     char		desc[80];
274*479ab7f0SSascha Wildner 
275*479ab7f0SSascha Wildner 
276*479ab7f0SSascha Wildner     /* build the description */
277*479ab7f0SSascha Wildner     desc[0] = 0;
278*479ab7f0SSascha Wildner     if (ppi->pi_name != NULL) {
279*479ab7f0SSascha Wildner 	strcat(desc, ppi->pi_name);
280*479ab7f0SSascha Wildner 	strcat(desc, " ");
281*479ab7f0SSascha Wildner     }
282*479ab7f0SSascha Wildner     if (psc->ps_name != NULL) {
283*479ab7f0SSascha Wildner 	strcat(desc, psc->ps_name);
284*479ab7f0SSascha Wildner 	strcat(desc, " ");
285*479ab7f0SSascha Wildner     }
286*479ab7f0SSascha Wildner     if (pc->pc_name != NULL)
287*479ab7f0SSascha Wildner 	strcat(desc, pc->pc_name);
288*479ab7f0SSascha Wildner 
289*479ab7f0SSascha Wildner     pi = pnp_allocinfo();
290*479ab7f0SSascha Wildner     pi->pi_desc = strdup(desc);
291*479ab7f0SSascha Wildner     sprintf(desc,"0x%08x", devid);
292*479ab7f0SSascha Wildner     pnp_addident(pi, desc);
293*479ab7f0SSascha Wildner     pnp_addinfo(pi);
294*479ab7f0SSascha Wildner }
295