// SPDX-License-Identifier: GPL-2.0-or-later /* * pnpbios -- PnP BIOS driver * * This driver provides access to Plug-'n'-Play services provided by * the PnP BIOS firmware, described in the following documents: * Plug and Play BIOS Specification, Version 1.0A, 5 May 1994 * Plug and Play BIOS Clarification Paper, 6 October 1994 * Compaq Computer Corporation, Phoenix Technologies Ltd., Intel Corp. * * Originally (C) 1998 Christian Schmidt <schmidt@digadd.de> * Modifications (C) 1998 Tom Lees <tom@lpsg.demon.co.uk> * Minor reorganizations by David Hinds <dahinds@users.sourceforge.net> * Further modifications (C) 2001, 2002 by: * Alan Cox <alan@redhat.com> * Thomas Hood * Brian Gerst <bgerst@didntduck.org> * * Ported to the PnP Layer and several additional improvements (C) 2002 * by Adam Belay <ambx1@neo.rr.com>
*/
/* Change Log * * Adam Belay - <ambx1@neo.rr.com> - March 16, 2003 * rev 1.01 Only call pnp_bios_dev_node_info once * Added pnpbios_print_status * Added several new error messages and info messages * Added pnpbios_interface_attach_device * integrated core and proc init system * Introduced PNPMODE flags * Removed some useless includes
*/
int pnp_bios_present(void)
{ return (pnp_bios_install != NULL);
}
struct pnp_dev_node_info node_info;
/* * * DOCKING FUNCTIONS *
*/
staticstruct completion unload_sem;
/* * (Much of this belongs in a shared routine somewhere)
*/ staticint pnp_dock_event(int dock, struct pnp_docking_station_info *info)
{ staticcharconst sbin_pnpbios[] = "/sbin/pnpbios"; char *argv[3], **envp, *buf, *scratch; int i = 0, value;
if (!(envp = kcalloc(20, sizeof(char *), GFP_KERNEL))) return -ENOMEM; if (!(buf = kzalloc(256, GFP_KERNEL))) {
kfree(envp); return -ENOMEM;
}
/* FIXME: if there are actual users of this, it should be * integrated into the driver core and use the usual infrastructure * like sysfs and uevents
*/
argv[0] = (char *)sbin_pnpbios;
argv[1] = "dock";
argv[2] = NULL;
#ifdef DEBUG /* hint that policy agent should enter no-stdout debug mode */
envp[i++] = "DEBUG=kernel"; #endif /* extensible set of named bus-specific parameters, * supporting multiple driver selection algorithms.
*/
scratch = buf;
while ((char *)p < (char *)end) { if (p[0] & 0x80) { /* large tag */
len = (p[2] << 8) | p[1];
p += 3;
} else { if (((p[0] >> 3) & 0x0f) == 0x0f) return;
len = p[0] & 0x07;
p += 1;
} for (i = 0; i < len; i++)
p[i] = 0;
p += len;
}
printk(KERN_ERR "PnPBIOS: Resource structure did not contain an end tag.\n");
}
/* check if the device is already added */
list_for_each_entry(dev, &pnpbios_protocol.devices, protocol_list) { if (dev->number == node->handle) return -EEXIST;
}
pnp_eisa_id_to_string(node->eisa_id & PNP_EISA_ID_MASK, id);
dev = pnp_alloc_dev(&pnpbios_protocol, node->handle, id); if (!dev) return -ENOMEM;
pnpbios_parse_data_stream(dev, node);
dev->active = pnp_is_active(dev);
dev->flags = node->flags; if (!(dev->flags & PNPBIOS_NO_CONFIG))
dev->capabilities |= PNP_CONFIGURABLE; if (!(dev->flags & PNPBIOS_NO_DISABLE) && pnpbios_is_dynamic(dev))
dev->capabilities |= PNP_DISABLE;
dev->capabilities |= PNP_READ; if (pnpbios_is_dynamic(dev))
dev->capabilities |= PNP_WRITE; if (dev->flags & PNPBIOS_REMOVABLE)
dev->capabilities |= PNP_REMOVABLE;
/* clear out the damaged flags */ if (!dev->active)
pnp_init_resources(dev);
error = pnp_add_device(dev); if (error) {
put_device(&dev->dev); return error;
}
node = kzalloc(node_info.max_node_size, GFP_KERNEL); if (!node) return;
for (nodenum = 0; nodenum < 0xff;) {
u8 thisnodenum = nodenum; /* eventually we will want to use PNPMODE_STATIC here but for now * dynamic will help us catch buggy bioses to add to the blacklist.
*/ if (!pnpbios_dont_use_current_config) { if (pnp_bios_get_dev_node
(&nodenum, (char)PNPMODE_DYNAMIC, node)) break;
} else { if (pnp_bios_get_dev_node
(&nodenum, (char)PNPMODE_STATIC, node)) break;
}
nodes_got++; if (insert_device(node) == 0)
devs++; if (nodenum <= thisnodenum) {
printk(KERN_ERR "PnPBIOS: build_devlist: Node number 0x%x is out of sequence following node 0x%x. Aborting.\n",
(unsignedint)nodenum,
(unsignedint)thisnodenum); break;
}
}
kfree(node);
printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS; %i recorded by driver\n",
nodes_got, nodes_got != 1 ? "s" : "", devs);
}
/* * * INIT AND EXIT *
*/
staticint pnpbios_disabled; int pnpbios_dont_use_current_config;
staticint __init pnpbios_setup(char *str)
{ int invert;
/* scan the system for pnpbios support */ if (!pnpbios_probe_system()) return -ENODEV;
/* make preparations for bios calls */
pnpbios_calls_init(pnp_bios_install);
/* read the node info */
ret = pnp_bios_dev_node_info(&node_info); if (ret) {
printk(KERN_ERR "PnPBIOS: Unable to get node info. Aborting.\n"); return ret;
}
/* register with the pnp layer */
ret = pnp_register_protocol(&pnpbios_protocol); if (ret) {
printk(KERN_ERR "PnPBIOS: Unable to register driver. Aborting.\n"); return ret;
}
/* start the proc interface */
ret = pnpbios_proc_init(); if (ret)
printk(KERN_ERR "PnPBIOS: Failed to create proc interface.\n");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.