2005-04-16 15:20:36 -07:00
/*
* 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.0 A , 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 >
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 , or ( at your option ) any
* later version .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
2007-07-26 10:41:20 -07:00
2005-04-16 15:20:36 -07:00
/* 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
*/
# include <linux/types.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/linkage.h>
# include <linux/kernel.h>
# include <linux/device.h>
# include <linux/pnp.h>
# include <linux/mm.h>
# include <linux/smp.h>
# include <linux/slab.h>
# include <linux/completion.h>
# include <linux/spinlock.h>
# include <linux/dmi.h>
# include <linux/delay.h>
# include <linux/acpi.h>
2006-12-06 20:34:23 -08:00
# include <linux/freezer.h>
2007-05-08 00:30:17 -07:00
# include <linux/kthread.h>
2005-04-16 15:20:36 -07:00
# include <asm/page.h>
# include <asm/desc.h>
# include <asm/byteorder.h>
2008-04-28 16:33:51 -06:00
# include "../base.h"
2005-04-16 15:20:36 -07:00
# include "pnpbios.h"
/*
*
* PnP BIOS INTERFACE
*
*/
2007-07-26 10:41:20 -07:00
static union pnp_bios_install_struct * pnp_bios_install = NULL ;
2005-04-16 15:20:36 -07:00
int pnp_bios_present ( void )
{
return ( pnp_bios_install ! = NULL ) ;
}
struct pnp_dev_node_info node_info ;
/*
*
* DOCKING FUNCTIONS
*
*/
static struct completion unload_sem ;
/*
* ( Much of this belongs in a shared routine somewhere )
*/
static int pnp_dock_event ( int dock , struct pnp_docking_station_info * info )
{
2007-07-26 10:41:20 -07:00
char * argv [ 3 ] , * * envp , * buf , * scratch ;
2005-04-16 15:20:36 -07:00
int i = 0 , value ;
2007-07-26 10:41:21 -07:00
if ( ! ( envp = kcalloc ( 20 , sizeof ( char * ) , GFP_KERNEL ) ) )
2005-04-16 15:20:36 -07:00
return - ENOMEM ;
2006-12-13 00:34:52 -08:00
if ( ! ( buf = kzalloc ( 256 , GFP_KERNEL ) ) ) {
2007-07-26 10:41:20 -07:00
kfree ( envp ) ;
2005-04-16 15:20:36 -07:00
return - ENOMEM ;
}
2007-07-26 10:41:21 -07:00
/* 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
*/
2007-07-26 10:41:20 -07:00
argv [ 0 ] = " /sbin/pnpbios " ;
argv [ 1 ] = " dock " ;
argv [ 2 ] = NULL ;
2005-04-16 15:20:36 -07:00
/* minimal command environment */
2007-07-26 10:41:20 -07:00
envp [ i + + ] = " HOME=/ " ;
envp [ i + + ] = " PATH=/sbin:/bin:/usr/sbin:/usr/bin " ;
2005-04-16 15:20:36 -07:00
# ifdef DEBUG
/* hint that policy agent should enter no-stdout debug mode */
2007-07-26 10:41:20 -07:00
envp [ i + + ] = " DEBUG=kernel " ;
2005-04-16 15:20:36 -07:00
# endif
/* extensible set of named bus-specific parameters,
* supporting multiple driver selection algorithms .
*/
scratch = buf ;
/* action: add, remove */
2007-07-26 10:41:20 -07:00
envp [ i + + ] = scratch ;
scratch + = sprintf ( scratch , " ACTION=%s " , dock ? " add " : " remove " ) + 1 ;
2005-04-16 15:20:36 -07:00
/* Report the ident for the dock */
2007-07-26 10:41:20 -07:00
envp [ i + + ] = scratch ;
scratch + = sprintf ( scratch , " DOCK=%x/%x/%x " ,
info - > location_id , info - > serial , info - > capabilities ) ;
2005-04-16 15:20:36 -07:00
envp [ i ] = NULL ;
2007-07-26 10:41:20 -07:00
2007-07-26 10:41:21 -07:00
value = call_usermodehelper ( argv [ 0 ] , argv , envp , UMH_WAIT_EXEC ) ;
2007-07-26 10:41:20 -07:00
kfree ( buf ) ;
kfree ( envp ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
/*
* Poll the PnP docking at regular intervals
*/
2007-07-26 10:41:20 -07:00
static int pnp_dock_thread ( void * unused )
2005-04-16 15:20:36 -07:00
{
static struct pnp_docking_station_info now ;
int docked = - 1 , d = 0 ;
2007-07-26 10:41:21 -07:00
2007-07-17 04:03:35 -07:00
set_freezable ( ) ;
2009-04-02 16:57:09 -07:00
while ( 1 ) {
2005-04-16 15:20:36 -07:00
int status ;
2007-07-26 10:41:20 -07:00
2005-04-16 15:20:36 -07:00
/*
* Poll every 2 seconds
*/
msleep_interruptible ( 2000 ) ;
2007-05-08 00:30:17 -07:00
if ( try_to_freeze ( ) )
continue ;
2005-04-16 15:20:36 -07:00
status = pnp_bios_dock_station_info ( & now ) ;
2007-07-26 10:41:20 -07:00
switch ( status ) {
2005-04-16 15:20:36 -07:00
/*
* No dock to manage
*/
2007-07-26 10:41:20 -07:00
case PNP_FUNCTION_NOT_SUPPORTED :
complete_and_exit ( & unload_sem , 0 ) ;
case PNP_SYSTEM_NOT_DOCKED :
d = 0 ;
break ;
case PNP_SUCCESS :
d = 1 ;
break ;
default :
pnpbios_print_status ( " pnp_dock_thread " , status ) ;
continue ;
2005-04-16 15:20:36 -07:00
}
2007-07-26 10:41:20 -07:00
if ( d ! = docked ) {
if ( pnp_dock_event ( d , & now ) = = 0 ) {
2005-04-16 15:20:36 -07:00
docked = d ;
#if 0
2007-07-26 10:41:20 -07:00
printk ( KERN_INFO
" PnPBIOS: Docking station %stached \n " ,
docked ? " at " : " de " ) ;
2005-04-16 15:20:36 -07:00
# endif
}
}
}
complete_and_exit ( & unload_sem , 0 ) ;
}
2008-04-28 16:34:05 -06:00
static int pnpbios_get_resources ( struct pnp_dev * dev )
2005-04-16 15:20:36 -07:00
{
u8 nodenum = dev - > number ;
2007-07-26 10:41:20 -07:00
struct pnp_bios_node * node ;
2005-04-16 15:20:36 -07:00
2007-07-26 10:41:20 -07:00
if ( ! pnpbios_is_dynamic ( dev ) )
2005-04-16 15:20:36 -07:00
return - EPERM ;
2008-08-19 16:53:47 -06:00
pnp_dbg ( & dev - > dev , " get resources \n " ) ;
2006-12-13 00:34:52 -08:00
node = kzalloc ( node_info . max_node_size , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! node )
return - 1 ;
2007-07-26 10:41:20 -07:00
if ( pnp_bios_get_dev_node ( & nodenum , ( char ) PNPMODE_DYNAMIC , node ) ) {
2005-04-16 15:20:36 -07:00
kfree ( node ) ;
return - ENODEV ;
}
2008-04-28 16:34:06 -06:00
pnpbios_read_resources_from_node ( dev , node ) ;
2005-04-16 15:20:36 -07:00
dev - > active = pnp_is_active ( dev ) ;
kfree ( node ) ;
return 0 ;
}
2008-04-28 16:34:05 -06:00
static int pnpbios_set_resources ( struct pnp_dev * dev )
2005-04-16 15:20:36 -07:00
{
u8 nodenum = dev - > number ;
2007-07-26 10:41:20 -07:00
struct pnp_bios_node * node ;
2005-04-16 15:20:36 -07:00
int ret ;
if ( ! pnpbios_is_dynamic ( dev ) )
return - EPERM ;
2008-08-19 16:53:47 -06:00
pnp_dbg ( & dev - > dev , " set resources \n " ) ;
2006-12-13 00:34:52 -08:00
node = kzalloc ( node_info . max_node_size , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! node )
return - 1 ;
2007-07-26 10:41:20 -07:00
if ( pnp_bios_get_dev_node ( & nodenum , ( char ) PNPMODE_DYNAMIC , node ) ) {
2005-04-16 15:20:36 -07:00
kfree ( node ) ;
return - ENODEV ;
}
2008-04-28 16:34:06 -06:00
if ( pnpbios_write_resources_to_node ( dev , node ) < 0 ) {
2005-04-16 15:20:36 -07:00
kfree ( node ) ;
return - 1 ;
}
ret = pnp_bios_set_dev_node ( node - > handle , ( char ) PNPMODE_DYNAMIC , node ) ;
kfree ( node ) ;
if ( ret > 0 )
ret = - 1 ;
return ret ;
}
2007-07-26 10:41:20 -07:00
static void pnpbios_zero_data_stream ( struct pnp_bios_node * node )
2005-04-16 15:20:36 -07:00
{
2007-07-26 10:41:20 -07:00
unsigned char * p = ( char * ) node - > data ;
unsigned char * end = ( char * ) ( node - > data + node - > size ) ;
2005-04-16 15:20:36 -07:00
unsigned int len ;
int i ;
2007-07-26 10:41:21 -07:00
2005-04-16 15:20:36 -07:00
while ( ( char * ) p < ( char * ) end ) {
2007-07-26 10:41:20 -07:00
if ( p [ 0 ] & 0x80 ) { /* large tag */
2005-04-16 15:20:36 -07:00
len = ( p [ 2 ] < < 8 ) | p [ 1 ] ;
p + = 3 ;
} else {
2007-07-26 10:41:20 -07:00
if ( ( ( p [ 0 ] > > 3 ) & 0x0f ) = = 0x0f )
2005-04-16 15:20:36 -07:00
return ;
len = p [ 0 ] & 0x07 ;
p + = 1 ;
}
for ( i = 0 ; i < len ; i + + )
p [ i ] = 0 ;
p + = len ;
}
2007-07-26 10:41:20 -07:00
printk ( KERN_ERR
" PnPBIOS: Resource structure did not contain an end tag. \n " ) ;
2005-04-16 15:20:36 -07:00
}
static int pnpbios_disable_resources ( struct pnp_dev * dev )
{
2007-07-26 10:41:20 -07:00
struct pnp_bios_node * node ;
2005-04-16 15:20:36 -07:00
u8 nodenum = dev - > number ;
int ret ;
2007-07-26 10:41:20 -07:00
if ( dev - > flags & PNPBIOS_NO_DISABLE | | ! pnpbios_is_dynamic ( dev ) )
2005-04-16 15:20:36 -07:00
return - EPERM ;
2006-12-13 00:34:52 -08:00
node = kzalloc ( node_info . max_node_size , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! node )
return - ENOMEM ;
2007-07-26 10:41:20 -07:00
if ( pnp_bios_get_dev_node ( & nodenum , ( char ) PNPMODE_DYNAMIC , node ) ) {
2005-04-16 15:20:36 -07:00
kfree ( node ) ;
return - ENODEV ;
}
pnpbios_zero_data_stream ( node ) ;
ret = pnp_bios_set_dev_node ( dev - > number , ( char ) PNPMODE_DYNAMIC , node ) ;
kfree ( node ) ;
if ( ret > 0 )
ret = - 1 ;
return ret ;
}
/* PnP Layer support */
struct pnp_protocol pnpbios_protocol = {
2007-07-26 10:41:20 -07:00
. name = " Plug and Play BIOS " ,
. get = pnpbios_get_resources ,
. set = pnpbios_set_resources ,
2005-04-16 15:20:36 -07:00
. disable = pnpbios_disable_resources ,
} ;
2008-02-06 01:40:03 -08:00
static int __init insert_device ( struct pnp_bios_node * node )
2005-04-16 15:20:36 -07:00
{
2007-07-26 10:41:20 -07:00
struct list_head * pos ;
2007-10-16 23:31:11 -07:00
struct pnp_dev * dev ;
2005-04-16 15:20:36 -07:00
char id [ 8 ] ;
/* check if the device is already added */
2007-07-26 10:41:20 -07:00
list_for_each ( pos , & pnpbios_protocol . devices ) {
2007-10-16 23:31:11 -07:00
dev = list_entry ( pos , struct pnp_dev , protocol_list ) ;
if ( dev - > number = = node - > handle )
2005-04-16 15:20:36 -07:00
return - 1 ;
}
2008-04-28 16:33:53 -06:00
pnp_eisa_id_to_string ( node - > eisa_id & PNP_EISA_ID_MASK , id ) ;
2008-04-28 16:33:54 -06:00
dev = pnp_alloc_dev ( & pnpbios_protocol , node - > handle , id ) ;
if ( ! dev )
2005-04-16 15:20:36 -07:00
return - 1 ;
2007-10-16 23:31:11 -07:00
2005-04-16 15:20:36 -07:00
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 ;
2006-07-30 03:03:55 -07:00
if ( ! ( dev - > flags & PNPBIOS_NO_DISABLE ) & & pnpbios_is_dynamic ( dev ) )
2005-04-16 15:20:36 -07:00
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 )
2008-04-28 16:34:09 -06:00
pnp_init_resources ( dev ) ;
2005-04-16 15:20:36 -07:00
pnp_add_device ( dev ) ;
pnpbios_interface_attach_device ( node ) ;
return 0 ;
}
static void __init build_devlist ( void )
{
u8 nodenum ;
unsigned int nodes_got = 0 ;
unsigned int devs = 0 ;
struct pnp_bios_node * node ;
2006-12-13 00:34:52 -08:00
node = kzalloc ( node_info . max_node_size , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! node )
return ;
2007-07-26 10:41:20 -07:00
for ( nodenum = 0 ; nodenum < 0xff ; ) {
2005-04-16 15:20:36 -07:00
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 ) {
2007-07-26 10:41:20 -07:00
if ( pnp_bios_get_dev_node
( & nodenum , ( char ) PNPMODE_DYNAMIC , node ) )
2005-04-16 15:20:36 -07:00
break ;
} else {
2007-07-26 10:41:20 -07:00
if ( pnp_bios_get_dev_node
( & nodenum , ( char ) PNPMODE_STATIC , node ) )
2005-04-16 15:20:36 -07:00
break ;
}
nodes_got + + ;
2007-10-16 23:31:11 -07:00
if ( insert_device ( node ) = = 0 )
2005-04-16 15:20:36 -07:00
devs + + ;
if ( nodenum < = thisnodenum ) {
2007-07-26 10:41:20 -07:00
printk ( KERN_ERR
" PnPBIOS: build_devlist: Node number 0x%x is out of sequence following node 0x%x. Aborting. \n " ,
( unsigned int ) nodenum ,
( unsigned int ) thisnodenum ) ;
2005-04-16 15:20:36 -07:00
break ;
}
}
kfree ( node ) ;
2007-07-26 10:41:20 -07:00
printk ( KERN_INFO
" PnPBIOS: %i node%s reported by PnP BIOS; %i recorded by driver \n " ,
nodes_got , nodes_got ! = 1 ? " s " : " " , devs ) ;
2005-04-16 15:20:36 -07:00
}
/*
*
* INIT AND EXIT
*
*/
2007-07-26 10:41:21 -07:00
static int pnpbios_disabled ;
int pnpbios_dont_use_current_config ;
2005-04-16 15:20:36 -07:00
static int __init pnpbios_setup ( char * str )
{
int invert ;
while ( ( str ! = NULL ) & & ( * str ! = ' \0 ' ) ) {
if ( strncmp ( str , " off " , 3 ) = = 0 )
2007-07-26 10:41:20 -07:00
pnpbios_disabled = 1 ;
2005-04-16 15:20:36 -07:00
if ( strncmp ( str , " on " , 2 ) = = 0 )
2007-07-26 10:41:20 -07:00
pnpbios_disabled = 0 ;
2005-04-16 15:20:36 -07:00
invert = ( strncmp ( str , " no- " , 3 ) = = 0 ) ;
if ( invert )
str + = 3 ;
if ( strncmp ( str , " curr " , 4 ) = = 0 )
pnpbios_dont_use_current_config = invert ;
str = strchr ( str , ' , ' ) ;
if ( str ! = NULL )
str + = strspn ( str , " , \t " ) ;
}
return 1 ;
}
__setup ( " pnpbios= " , pnpbios_setup ) ;
/* PnP BIOS signature: "$PnP" */
# define PNP_SIGNATURE (('$' << 0) + ('P' << 8) + ('n' << 16) + ('P' << 24))
static int __init pnpbios_probe_system ( void )
{
union pnp_bios_install_struct * check ;
u8 sum ;
int length , i ;
printk ( KERN_INFO " PnPBIOS: Scanning system for PnP BIOS support... \n " ) ;
/*
2007-07-26 10:41:20 -07:00
* Search the defined area ( 0xf0000 - 0xffff0 ) for a valid PnP BIOS
2005-04-16 15:20:36 -07:00
* structure and , if one is found , sets up the selectors and
* entry points
*/
2007-07-26 10:41:20 -07:00
for ( check = ( union pnp_bios_install_struct * ) __va ( 0xf0000 ) ;
check < ( union pnp_bios_install_struct * ) __va ( 0xffff0 ) ;
2005-04-16 15:20:36 -07:00
check = ( void * ) check + 16 ) {
if ( check - > fields . signature ! = PNP_SIGNATURE )
continue ;
2007-07-26 10:41:20 -07:00
printk ( KERN_INFO
" PnPBIOS: Found PnP BIOS installation structure at 0x%p \n " ,
check ) ;
2005-04-16 15:20:36 -07:00
length = check - > fields . length ;
if ( ! length ) {
2007-07-26 10:41:20 -07:00
printk ( KERN_ERR
" PnPBIOS: installation structure is invalid, skipping \n " ) ;
2005-04-16 15:20:36 -07:00
continue ;
}
for ( sum = 0 , i = 0 ; i < length ; i + + )
sum + = check - > chars [ i ] ;
if ( sum ) {
2007-07-26 10:41:20 -07:00
printk ( KERN_ERR
" PnPBIOS: installation structure is corrupted, skipping \n " ) ;
2005-04-16 15:20:36 -07:00
continue ;
}
if ( check - > fields . version < 0x10 ) {
2007-07-26 10:41:20 -07:00
printk ( KERN_WARNING
" PnPBIOS: PnP BIOS version %d.%d is not supported \n " ,
2005-04-16 15:20:36 -07:00
check - > fields . version > > 4 ,
check - > fields . version & 15 ) ;
continue ;
}
2007-07-26 10:41:20 -07:00
printk ( KERN_INFO
" PnPBIOS: PnP BIOS version %d.%d, entry 0x%x:0x%x, dseg 0x%x \n " ,
check - > fields . version > > 4 , check - > fields . version & 15 ,
2005-04-16 15:20:36 -07:00
check - > fields . pm16cseg , check - > fields . pm16offset ,
check - > fields . pm16dseg ) ;
pnp_bios_install = check ;
return 1 ;
}
printk ( KERN_INFO " PnPBIOS: PnP BIOS support was not detected. \n " ) ;
return 0 ;
}
2007-10-03 15:15:40 -04:00
static int __init exploding_pnp_bios ( const struct dmi_system_id * d )
2005-04-16 15:20:36 -07:00
{
printk ( KERN_WARNING " %s detected. Disabling PnPBIOS \n " , d - > ident ) ;
return 0 ;
}
2005-04-16 15:25:51 -07:00
static struct dmi_system_id pnpbios_dmi_table [ ] __initdata = {
2007-07-26 10:41:20 -07:00
{ /* PnPBIOS GPF on boot */
. callback = exploding_pnp_bios ,
. ident = " Higraded P14H " ,
. matches = {
DMI_MATCH ( DMI_BIOS_VENDOR , " American Megatrends Inc. " ) ,
DMI_MATCH ( DMI_BIOS_VERSION , " 07.00T " ) ,
DMI_MATCH ( DMI_SYS_VENDOR , " Higraded " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " P14H " ) ,
} ,
} ,
{ /* PnPBIOS GPF on boot */
. callback = exploding_pnp_bios ,
. ident = " ASUS P4P800 " ,
. matches = {
DMI_MATCH ( DMI_BOARD_VENDOR , " ASUSTeK Computer Inc. " ) ,
DMI_MATCH ( DMI_BOARD_NAME , " P4P800 " ) ,
} ,
} ,
{ }
2005-04-16 15:20:36 -07:00
} ;
static int __init pnpbios_init ( void )
{
int ret ;
2006-12-07 02:14:08 +01:00
if ( pnpbios_disabled | | dmi_check_system ( pnpbios_dmi_table ) | |
paravirt_enabled ( ) ) {
2005-04-16 15:20:36 -07:00
printk ( KERN_INFO " PnPBIOS: Disabled \n " ) ;
return - ENODEV ;
}
# ifdef CONFIG_PNPACPI
if ( ! acpi_disabled & & ! pnpacpi_disabled ) {
pnpbios_disabled = 1 ;
printk ( KERN_INFO " PnPBIOS: Disabled by ACPI PNP \n " ) ;
return - ENODEV ;
}
2007-07-26 10:41:21 -07:00
# endif /* CONFIG_ACPI */
2005-04-16 15:20:36 -07:00
/* 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 ) {
2007-07-26 10:41:20 -07:00
printk ( KERN_ERR
" PnPBIOS: Unable to get node info. Aborting. \n " ) ;
2005-04-16 15:20:36 -07:00
return ret ;
}
/* register with the pnp layer */
ret = pnp_register_protocol ( & pnpbios_protocol ) ;
if ( ret ) {
2007-07-26 10:41:20 -07:00
printk ( KERN_ERR
" PnPBIOS: Unable to register driver. Aborting. \n " ) ;
2005-04-16 15:20:36 -07:00
return ret ;
}
/* start the proc interface */
ret = pnpbios_proc_init ( ) ;
if ( ret )
printk ( KERN_ERR " PnPBIOS: Failed to create proc interface. \n " ) ;
/* scan for pnpbios devices */
build_devlist ( ) ;
2007-05-08 00:35:54 -07:00
pnp_platform_devices = 1 ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2008-10-10 08:00:17 -07:00
fs_initcall ( pnpbios_init ) ;
2005-04-16 15:20:36 -07:00
static int __init pnpbios_thread_init ( void )
{
2012-11-19 13:19:14 -05:00
struct task_struct * task ;
2013-03-27 00:47:03 +00:00
2005-04-16 15:20:36 -07:00
if ( pnpbios_disabled )
return 0 ;
2012-11-19 13:19:14 -05:00
init_completion ( & unload_sem ) ;
task = kthread_run ( pnp_dock_thread , NULL , " kpnpbiosd " ) ;
if ( IS_ERR ( task ) )
return PTR_ERR ( task ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
/* Start the kernel thread later: */
module_init ( pnpbios_thread_init ) ;
EXPORT_SYMBOL ( pnpbios_protocol ) ;