2 * Copyright (c) 2004 Joerg Sonnenberger <joerg@bec.de>
4 * Copyright (c) 1997 Michael Smith
5 * Copyright (c) 1998 Jonathan Lemon
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
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
31 * Code for dealing with the PnP-BIOS in x86 PC systems.
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/malloc.h>
43 #include <machine/md_var.h>
44 #include <machine/pc/bios.h>
46 #include <bus/isa/pnpreg.h>
47 #include <bus/isa/isavar.h>
50 * PnP BIOS interface; enumerate devices only known to the system
51 * BIOS and save information about them for later use.
61 /* device-specific data comes here */
63 } __attribute__((__packed__));
65 #define PNPATTR_NODISABLE (1<<0) /* can't be disabled */
66 #define PNPATTR_NOCONFIG (1<<1) /* can't be configured */
67 #define PNPATTR_OUTPUT (1<<2) /* can be primary output */
68 #define PNPATTR_INPUT (1<<3) /* can be primary input */
69 #define PNPATTR_BOOTABLE (1<<4) /* can be booted from */
70 #define PNPATTR_DOCK (1<<5) /* is a docking station */
71 #define PNPATTR_REMOVEABLE (1<<6) /* device is removeable */
73 #define PNPATTR_CONFIG(a) (((a) >> 7) & 0x03)
74 #define PNPATTR_CONFIG_STATIC 0x00
75 #define PNPATTR_CONFIG_DYNAMIC 0x01
76 #define PNPATTR_CONFIG_DYNONLY 0x03
78 /* We have to cluster arguments within a 64k range for the bios16 call */
83 struct pnp_sysdev node;
87 * This function is called after the bus has assigned resource
88 * locations for a logical device.
91 pnpbios_set_config(void *arg, struct isa_config *config, int enable)
96 * Quiz the PnP BIOS, build a list of PNP IDs and resource data.
99 pnpbios_identify(driver_t *driver, device_t parent)
101 struct PnPBIOS_table *pt = PnPBIOStable;
102 struct bios_args args;
103 struct pnp_sysdev *pd;
104 struct pnp_sysdevargs *pda;
105 uint16_t ndevs, bigdev;
107 uint8_t *devnodebuf, tag;
108 uint32_t *devid, *compid;
113 * Umm, we aren't going to rescan the PnP BIOS to look for new additions.
115 if (device_get_state(parent) == DS_ATTACHED)
118 /* no PnP BIOS information */
122 /* ACPI already active */
123 if (devclass_get_softc(devclass_find("ACPI"), 0) != NULL)
126 bzero(&args, sizeof(args));
127 args.seg.code16.base = BIOS_PADDRTOVADDR(pt->pmentrybase);
128 args.seg.code16.limit = 0xffff; /* XXX ? */
129 args.seg.data.base = BIOS_PADDRTOVADDR(pt->pmdataseg);
130 args.seg.data.limit = 0xffff;
131 args.entry = pt->pmentryoffset;
133 if ((error = bios16(&args, PNP_COUNT_DEVNODES, &ndevs, &bigdev)) || (args.r.eax & 0xff))
134 kprintf("pnpbios: error %d/%x getting device count/size limit\n", error, args.r.eax);
135 ndevs &= 0xff; /* clear high byte garbage */
137 kprintf("pnpbios: %d devices, largest %d bytes\n", ndevs, bigdev);
139 devnodebuf = kmalloc(bigdev + (sizeof(struct pnp_sysdevargs) - sizeof(struct pnp_sysdev)), M_DEVBUF, M_INTWAIT);
140 pda = (struct pnp_sysdevargs *)devnodebuf;
143 for (currdev = 0, left = ndevs; (currdev != 0xff) && (left > 0); left--) {
147 /* get current configuration */
148 if ((error = bios16(&args, PNP_GET_DEVNODE, &pda->next, &pda->node, 1))) {
149 kprintf("pnpbios: error %d making BIOS16 call\n", error);
153 kprintf("pnp_get_devnode cd=%d nxt=%d size=%d handle=%d devid=%08x type=%02x%02x%02x, attrib=%04x\n", currdev, pda->next, pd->size, pd->handle, pd->devid, pd->type[0], pd->type[1], pd->type[2], pd->attrib);
155 if ((error = (args.r.eax & 0xff))) {
157 kprintf("pnpbios: %s 0x%x fetching node %d\n", error & 0x80 ? "error" : "warning", error, currdev);
162 if (pd->size < sizeof(struct pnp_sysdev)) {
163 kprintf("pnpbios: bogus system node data, aborting scan\n");
168 * Ignore PICs so that we don't have to worry about the PICs
169 * claiming IRQs to prevent their use. The PIC drivers
170 * already ensure that invalid IRQs are not used.
172 if (!strcmp(pnp_eisaformat(pd->devid), "PNP0000")) /* ISA PIC */
174 if (!strcmp(pnp_eisaformat(pd->devid), "PNP0003")) /* APIC */
177 /* Add the device and parse its resources */
178 dev = BUS_ADD_CHILD(parent, parent, ISA_ORDER_PNP, NULL, -1);
179 isa_set_vendorid(dev, pd->devid);
180 isa_set_logicalid(dev, pd->devid);
183 * It appears that some PnP BIOS doesn't allow us to re-enable
184 * the embedded system device once it is disabled. We shall
185 * mark all system device nodes as "cannot be disabled", regardless
186 * of actual settings in the device attribute byte. XXX
189 isa_set_configattr(dev,
190 ((pd->attrib & PNPATTR_NODISABLE) ? 0 : ISACFGATTR_CANDISABLE) |
191 ((!(pd->attrib & PNPATTR_NOCONFIG) &&
192 PNPATTR_CONFIG(pd->attrib) != PNPATTR_CONFIG_STATIC)
193 ? ISACFGATTR_DYNAMIC : 0));
195 isa_set_configattr(dev,
196 (!(pd->attrib & PNPATTR_NOCONFIG) &&
197 PNPATTR_CONFIG(pd->attrib) != PNPATTR_CONFIG_STATIC)
198 ? ISACFGATTR_DYNAMIC : 0);
200 ISA_SET_CONFIG_CALLBACK(parent, dev, pnpbios_set_config, 0);
201 pnp_parse_resources(dev, &pd->devdata[0],
202 pd->size - sizeof(struct pnp_sysdev), 0);
203 if (!device_get_desc(dev))
204 device_set_desc_copy(dev, pnp_eisaformat(pd->devid));
206 /* Find device IDs */
210 /* look for a compatible device ID too */
211 left = pd->size - sizeof(struct pnp_sysdev);
214 tag = pd->devdata[idx++];
215 if (PNP_RES_TYPE(tag) == 0) {
217 switch (PNP_SRES_NUM(tag)) {
218 case PNP_TAG_COMPAT_DEVICE:
219 compid = (uint32_t *)(pd->devdata + idx);
221 kprintf("pnpbios: node %d compat ID 0x%08x\n", pd->handle, *compid);
227 idx += PNP_SRES_LEN(tag);
231 /* Large resource, skip it */
232 idx += *(uint16_t *)(pd->devdata + idx) + 2;
235 kprintf("pnpbios: handle %d device ID %s (%08x)",
236 pd->handle, pnp_eisaformat(*devid), *devid);
238 kprintf(" compat ID %s (%08x)",
239 pnp_eisaformat(*compid), *compid);
246 static device_method_t pnpbios_methods[] = {
247 /* Device interface */
248 DEVMETHOD(device_identify, pnpbios_identify),
253 static driver_t pnpbios_driver = {
259 static devclass_t pnpbios_devclass;
261 DRIVER_MODULE(pnpbios, isa, pnpbios_driver, pnpbios_devclass, NULL, NULL);