2005-04-17 02:20:36 +04:00
/*
* core . c - contains all core device and protocol registration functions
*
* Copyright 2002 Adam Belay < ambx1 @ neo . rr . com >
*/
# include <linux/pnp.h>
# include <linux/types.h>
# include <linux/list.h>
# include <linux/device.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/string.h>
# include <linux/slab.h>
# include <linux/errno.h>
2007-05-08 11:25:29 +04:00
# include <linux/dma-mapping.h>
2005-04-17 02:20:36 +04:00
# include "base.h"
static LIST_HEAD ( pnp_protocols ) ;
LIST_HEAD ( pnp_global ) ;
DEFINE_SPINLOCK ( pnp_lock ) ;
2007-05-08 11:35:54 +04:00
/*
* ACPI or PNPBIOS should tell us about all platform devices , so we can
* skip some blind probes . ISAPNP typically enumerates only plug - in ISA
* devices , not built - in things like COM ports .
*/
int pnp_platform_devices ;
EXPORT_SYMBOL ( pnp_platform_devices ) ;
2005-04-17 02:20:36 +04:00
void * pnp_alloc ( long size )
{
void * result ;
some kmalloc/memset ->kzalloc (tree wide)
Transform some calls to kmalloc/memset to a single kzalloc (or kcalloc).
Here is a short excerpt of the semantic patch performing
this transformation:
@@
type T2;
expression x;
identifier f,fld;
expression E;
expression E1,E2;
expression e1,e2,e3,y;
statement S;
@@
x =
- kmalloc
+ kzalloc
(E1,E2)
... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\)
- memset((T2)x,0,E1);
@@
expression E1,E2,E3;
@@
- kzalloc(E1 * E2,E3)
+ kcalloc(E1,E2,E3)
[akpm@linux-foundation.org: get kcalloc args the right way around]
Signed-off-by: Yoann Padioleau <padator@wanadoo.fr>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Acked-by: Russell King <rmk@arm.linux.org.uk>
Cc: Bryan Wu <bryan.wu@analog.com>
Acked-by: Jiri Slaby <jirislaby@gmail.com>
Cc: Dave Airlie <airlied@linux.ie>
Acked-by: Roland Dreier <rolandd@cisco.com>
Cc: Jiri Kosina <jkosina@suse.cz>
Acked-by: Dmitry Torokhov <dtor@mail.ru>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Acked-by: Pierre Ossman <drzeus-list@drzeus.cx>
Cc: Jeff Garzik <jeff@garzik.org>
Cc: "David S. Miller" <davem@davemloft.net>
Acked-by: Greg KH <greg@kroah.com>
Cc: James Bottomley <James.Bottomley@steeleye.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-19 12:49:03 +04:00
result = kzalloc ( size , GFP_KERNEL ) ;
2007-07-26 21:41:20 +04:00
if ( ! result ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " pnp: Out of Memory \n " ) ;
return NULL ;
}
return result ;
}
/**
* pnp_protocol_register - adds a pnp protocol to the pnp layer
* @ protocol : pointer to the corresponding pnp_protocol structure
*
* Ex protocols : ISAPNP , PNPBIOS , etc
*/
int pnp_register_protocol ( struct pnp_protocol * protocol )
{
int nodenum ;
2007-07-26 21:41:20 +04:00
struct list_head * pos ;
2005-04-17 02:20:36 +04:00
INIT_LIST_HEAD ( & protocol - > devices ) ;
INIT_LIST_HEAD ( & protocol - > cards ) ;
nodenum = 0 ;
spin_lock ( & pnp_lock ) ;
/* assign the lowest unused number */
2007-07-26 21:41:20 +04:00
list_for_each ( pos , & pnp_protocols ) {
struct pnp_protocol * cur = to_pnp_protocol ( pos ) ;
if ( cur - > number = = nodenum ) {
2005-04-17 02:20:36 +04:00
pos = & pnp_protocols ;
nodenum + + ;
}
}
list_add_tail ( & protocol - > protocol_list , & pnp_protocols ) ;
spin_unlock ( & pnp_lock ) ;
protocol - > number = nodenum ;
sprintf ( protocol - > dev . bus_id , " pnp%d " , nodenum ) ;
return device_register ( & protocol - > dev ) ;
}
/**
* pnp_protocol_unregister - removes a pnp protocol from the pnp layer
* @ protocol : pointer to the corresponding pnp_protocol structure
*/
void pnp_unregister_protocol ( struct pnp_protocol * protocol )
{
spin_lock ( & pnp_lock ) ;
list_del ( & protocol - > protocol_list ) ;
spin_unlock ( & pnp_lock ) ;
device_unregister ( & protocol - > dev ) ;
}
static void pnp_free_ids ( struct pnp_dev * dev )
{
2007-07-26 21:41:20 +04:00
struct pnp_id * id ;
struct pnp_id * next ;
2007-07-26 21:41:21 +04:00
2005-04-17 02:20:36 +04:00
id = dev - > id ;
while ( id ) {
next = id - > next ;
kfree ( id ) ;
id = next ;
}
}
static void pnp_release_device ( struct device * dmdev )
{
2007-07-26 21:41:20 +04:00
struct pnp_dev * dev = to_pnp_dev ( dmdev ) ;
2007-07-26 21:41:21 +04:00
2005-04-17 02:20:36 +04:00
pnp_free_option ( dev - > independent ) ;
pnp_free_option ( dev - > dependent ) ;
pnp_free_ids ( dev ) ;
kfree ( dev ) ;
}
2008-04-29 02:33:54 +04:00
struct pnp_dev * pnp_alloc_dev ( struct pnp_protocol * protocol , int id , char * pnpid )
2005-04-17 02:20:36 +04:00
{
2008-04-29 02:33:54 +04:00
struct pnp_dev * dev ;
struct pnp_id * dev_id ;
2007-07-26 21:41:21 +04:00
2008-04-29 02:33:54 +04:00
dev = kzalloc ( sizeof ( struct pnp_dev ) , GFP_KERNEL ) ;
if ( ! dev )
return NULL ;
dev - > protocol = protocol ;
dev - > number = id ;
dev - > dma_mask = DMA_24BIT_MASK ;
dev - > dev . parent = & dev - > protocol - > dev ;
2005-04-17 02:20:36 +04:00
dev - > dev . bus = & pnp_bus_type ;
2007-05-08 11:25:29 +04:00
dev - > dev . dma_mask = & dev - > dma_mask ;
2008-04-29 02:33:54 +04:00
dev - > dev . coherent_dma_mask = dev - > dma_mask ;
2005-04-17 02:20:36 +04:00
dev - > dev . release = & pnp_release_device ;
2008-04-29 02:33:54 +04:00
sprintf ( dev - > dev . bus_id , " %02x:%02x " , dev - > protocol - > number ,
dev - > number ) ;
dev_id = pnp_add_id ( dev , pnpid ) ;
if ( ! dev_id ) {
kfree ( dev ) ;
return NULL ;
}
return dev ;
}
int __pnp_add_device ( struct pnp_dev * dev )
{
int ret ;
pnp_fixup_device ( dev ) ;
2005-04-17 02:20:36 +04:00
dev - > status = PNP_READY ;
spin_lock ( & pnp_lock ) ;
list_add_tail ( & dev - > global_list , & pnp_global ) ;
list_add_tail ( & dev - > protocol_list , & dev - > protocol - > devices ) ;
spin_unlock ( & pnp_lock ) ;
ret = device_register ( & dev - > dev ) ;
2007-10-17 10:31:12 +04:00
if ( ret )
return ret ;
pnp_interface_attach_device ( dev ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
/*
* pnp_add_device - adds a pnp device to the pnp layer
* @ dev : pointer to dev to add
*
* adds to driver model , name database , fixups , interface , etc .
*/
int pnp_add_device ( struct pnp_dev * dev )
{
2007-10-17 10:31:12 +04:00
int ret ;
2007-08-15 20:32:13 +04:00
if ( dev - > card )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2007-10-17 10:31:12 +04:00
ret = __pnp_add_device ( dev ) ;
if ( ret )
return ret ;
# ifdef CONFIG_PNP_DEBUG
{
struct pnp_id * id ;
dev_printk ( KERN_DEBUG , & dev - > dev , " %s device, IDs " ,
dev - > protocol - > name ) ;
for ( id = dev - > id ; id ; id = id - > next )
printk ( " %s " , id - > id ) ;
printk ( " (%s) \n " , dev - > active ? " active " : " disabled " ) ;
}
# endif
return 0 ;
2005-04-17 02:20:36 +04:00
}
void __pnp_remove_device ( struct pnp_dev * dev )
{
spin_lock ( & pnp_lock ) ;
list_del ( & dev - > global_list ) ;
list_del ( & dev - > protocol_list ) ;
spin_unlock ( & pnp_lock ) ;
device_unregister ( & dev - > dev ) ;
}
static int __init pnp_init ( void )
{
printk ( KERN_INFO " Linux Plug and Play Support v0.97 (c) Adam Belay \n " ) ;
return bus_register ( & pnp_bus_type ) ;
}
subsys_initcall ( pnp_init ) ;