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