From 1332f65e809bbff4c641539aebf3c0fff7c84785 Mon Sep 17 00:00:00 2001 From: Adam Belay Date: Mon, 24 Mar 2003 22:24:04 +0000 Subject: PnP Card Service Cleanups Moves probing code to a central location and matches when new cards are added instead of only when new drivers are added. --- include/linux/pnp.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/pnp.h b/include/linux/pnp.h index 2f078ae0f3bb..b2b9b2fcf3f0 100644 --- a/include/linux/pnp.h +++ b/include/linux/pnp.h @@ -315,6 +315,7 @@ struct pnp_driver { #define to_pnp_driver(drv) container_of(drv, struct pnp_driver, driver) struct pnp_card_driver { + struct list_head global_list; char * name; const struct pnp_card_id *id_table; unsigned int flags; -- cgit v1.2.3 From 9645e7b124ee7cb32d2574b4092706f80af2ee8c Mon Sep 17 00:00:00 2001 From: Adam Belay Date: Mon, 24 Mar 2003 22:30:41 +0000 Subject: PnPBIOS Update - Prevents calling the node_info call more than necessary in order to take load off the pnpbios - intregrates the proc registration code with the device scanning code - adds human readable error messages instead of number codes - other small cleanups --- drivers/pnp/pnpbios/core.c | 137 +++++++++++++++++++++++++++++++++------------ drivers/pnp/pnpbios/proc.c | 65 +++++++++------------ include/linux/pnpbios.h | 11 +++- 3 files changed, 137 insertions(+), 76 deletions(-) (limited to 'include/linux') diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index 453ea06b7723..a530fe61c773 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -32,6 +32,18 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* Change Log + * + * Adam Belay - - 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 #include @@ -46,9 +58,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -93,6 +103,7 @@ static struct { } pnp_bios_callpoint; static union pnp_bios_expansion_header * pnp_bios_hdr = NULL; +struct pnp_dev_node_info node_info; /* The PnP BIOS entries in the GDT */ #define PNP_GDT (GDT_ENTRY_PNPBIOS_BASE * 8) @@ -237,9 +248,46 @@ static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3, * */ -static void pnpbios_warn_unexpected_status(const char * module, u16 status) +static void pnpbios_print_status(const char * module, u16 status) { - printk(KERN_ERR "PnPBIOS: %s: Unexpected status 0x%x\n", module, status); + switch(status) { + case PNP_SUCCESS: + printk(KERN_ERR "PnPBIOS: %s: function successful\n", module); + case PNP_NOT_SET_STATICALLY: + printk(KERN_ERR "PnPBIOS: %s: unable to set static resources\n", module); + case PNP_UNKNOWN_FUNCTION: + printk(KERN_ERR "PnPBIOS: %s: invalid function number passed\n", module); + case PNP_FUNCTION_NOT_SUPPORTED: + printk(KERN_ERR "PnPBIOS: %s: function not supported on this system\n", module); + case PNP_INVALID_HANDLE: + printk(KERN_ERR "PnPBIOS: %s: invalid handle\n", module); + case PNP_BAD_PARAMETER: + printk(KERN_ERR "PnPBIOS: %s: invalid parameters were passed\n", module); + case PNP_SET_FAILED: + printk(KERN_ERR "PnPBIOS: %s: unable to set resources\n", module); + case PNP_EVENTS_NOT_PENDING: + printk(KERN_ERR "PnPBIOS: %s: no events are pending\n", module); + case PNP_SYSTEM_NOT_DOCKED: + printk(KERN_ERR "PnPBIOS: %s: the system is not docked\n", module); + case PNP_NO_ISA_PNP_CARDS: + printk(KERN_ERR "PnPBIOS: %s: no isapnp cards are installed on this system\n", module); + case PNP_UNABLE_TO_DETERMINE_DOCK_CAPABILITIES: + printk(KERN_ERR "PnPBIOS: %s: cannot determine the capabilities of the docking station\n", module); + case PNP_CONFIG_CHANGE_FAILED_NO_BATTERY: + printk(KERN_ERR "PnPBIOS: %s: unable to undock, the system does not have a battery\n", module); + case PNP_CONFIG_CHANGE_FAILED_RESOURCE_CONFLICT: + printk(KERN_ERR "PnPBIOS: %s: could not dock due to resource conflicts\n", module); + case PNP_BUFFER_TOO_SMALL: + printk(KERN_ERR "PnPBIOS: %s: the buffer passed is too small\n", module); + case PNP_USE_ESCD_SUPPORT: + printk(KERN_ERR "PnPBIOS: %s: use ESCD instead\n", module); + case PNP_MESSAGE_NOT_SUPPORTED: + printk(KERN_ERR "PnPBIOS: %s: the message is unsupported\n", module); + case PNP_HARDWARE_ERROR: + printk(KERN_ERR "PnPBIOS: %s: a hardware failure has occured\n", module); + default: + printk(KERN_ERR "PnPBIOS: %s: unexpected status 0x%x\n", module, status); + } } void *pnpbios_kmalloc(size_t size, int f) @@ -299,7 +347,7 @@ int pnp_bios_dev_node_info(struct pnp_dev_node_info *data) { int status = __pnp_bios_dev_node_info( data ); if ( status ) - pnpbios_warn_unexpected_status( "dev_node_info", status ); + pnpbios_print_status( "dev_node_info", status ); return status; } @@ -334,7 +382,7 @@ int pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data) int status; status = __pnp_bios_get_dev_node( nodenum, boot, data ); if ( status ) - pnpbios_warn_unexpected_status( "get_dev_node", status ); + pnpbios_print_status( "get_dev_node", status ); return status; } @@ -362,7 +410,7 @@ int pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data) int status; status = __pnp_bios_set_dev_node( nodenum, boot, data ); if ( status ) { - pnpbios_warn_unexpected_status( "set_dev_node", status ); + pnpbios_print_status( "set_dev_node", status ); return status; } if ( !boot ) { /* Update devlist */ @@ -452,7 +500,7 @@ int pnp_bios_get_stat_res(char *info) int status; status = __pnp_bios_get_stat_res( info ); if ( status ) - pnpbios_warn_unexpected_status( "get_stat_res", status ); + pnpbios_print_status( "get_stat_res", status ); return status; } @@ -489,7 +537,7 @@ int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data) int status; status = __pnp_bios_isapnp_config( data ); if ( status ) - pnpbios_warn_unexpected_status( "isapnp_config", status ); + pnpbios_print_status( "isapnp_config", status ); return status; } @@ -511,7 +559,7 @@ int pnp_bios_escd_info(struct escd_info_struc *data) int status; status = __pnp_bios_escd_info( data ); if ( status ) - pnpbios_warn_unexpected_status( "escd_info", status ); + pnpbios_print_status( "escd_info", status ); return status; } @@ -534,7 +582,7 @@ int pnp_bios_read_escd(char *data, u32 nvram_base) int status; status = __pnp_bios_read_escd( data, nvram_base ); if ( status ) - pnpbios_warn_unexpected_status( "read_escd", status ); + pnpbios_print_status( "read_escd", status ); return status; } @@ -658,7 +706,7 @@ static int pnp_dock_thread(void * unused) d = 1; break; default: - pnpbios_warn_unexpected_status( "pnp_dock_thread", status ); + pnpbios_print_status( "pnp_dock_thread", status ); continue; } if(d != docked) @@ -753,19 +801,17 @@ static void node_id_data_to_dev(unsigned char *p, struct pnp_bios_node *node, st static int pnpbios_get_resources(struct pnp_dev * dev, struct pnp_resource_table * res) { - struct pnp_dev_node_info node_info; u8 nodenum = dev->number; struct pnp_bios_node * node; /* just in case */ if(!pnpbios_is_dynamic(dev)) return -EPERM; - if (pnp_bios_dev_node_info(&node_info) != 0) - return -ENODEV; + node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL); if (!node) return -1; - if (pnp_bios_get_dev_node(&nodenum, (char )0, node)) { + if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) { kfree(node); return -ENODEV; } @@ -777,7 +823,6 @@ static int pnpbios_get_resources(struct pnp_dev * dev, struct pnp_resource_table static int pnpbios_set_resources(struct pnp_dev * dev, struct pnp_resource_table * res) { - struct pnp_dev_node_info node_info; u8 nodenum = dev->number; struct pnp_bios_node * node; int ret; @@ -785,18 +830,17 @@ static int pnpbios_set_resources(struct pnp_dev * dev, struct pnp_resource_table /* just in case */ if (!pnpbios_is_dynamic(dev)) return -EPERM; - if (pnp_bios_dev_node_info(&node_info) != 0) - return -ENODEV; + node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL); if (!node) return -1; - if (pnp_bios_get_dev_node(&nodenum, (char )1, node)) + if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_STATIC, node)) return -ENODEV; if(!pnp_write_resources((char *)node->data,(char *)node->data + node->size,res)){ kfree(node); return -1; } - ret = pnp_bios_set_dev_node(node->handle, (char)0, node); + ret = pnp_bios_set_dev_node(node->handle, (char)PNPMODE_DYNAMIC, node); kfree(node); if (ret > 0) ret = -1; @@ -805,23 +849,18 @@ static int pnpbios_set_resources(struct pnp_dev * dev, struct pnp_resource_table static int pnpbios_disable_resources(struct pnp_dev *dev) { - struct pnp_dev_node_info node_info; struct pnp_bios_node * node; int ret; /* just in case */ if(dev->flags & PNPBIOS_NO_DISABLE || !pnpbios_is_dynamic(dev)) return -EPERM; - if (!dev || !dev->active) - return -EINVAL; - if (pnp_bios_dev_node_info(&node_info) != 0) - return -ENODEV; + /* the value of this will be zero */ node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL); if (!node) return -ENOMEM; - ret = pnp_bios_set_dev_node(dev->number, (char)0, node); - dev->active = 0; + ret = pnp_bios_set_dev_node(dev->number, (char)PNPMODE_DYNAMIC, node); kfree(node); if (ret > 0) ret = -1; @@ -879,6 +918,8 @@ static int insert_device(struct pnp_dev *dev, struct pnp_bios_node * node) dev->protocol = &pnpbios_protocol; pnp_add_device(dev); + pnpbios_interface_attach_device(node); + return 0; } @@ -903,8 +944,16 @@ static void __init build_devlist(void) for(nodenum=0; nodenum<0xff; ) { u8 thisnodenum = nodenum; - if (pnp_bios_get_dev_node(&nodenum, (char )0, node)) - break; + /* 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++; dev = pnpbios_kmalloc(sizeof (struct pnp_dev), GFP_KERNEL); if (!dev) @@ -972,7 +1021,8 @@ int __init pnpbios_init(void) if(pnpbios_disabled || (dmi_broken & BROKEN_PNP_BIOS)) { printk(KERN_INFO "PnPBIOS: Disabled\n"); return -ENODEV; - } + } else + printk(KERN_INFO "PnPBIOS: Scanning system for PnP BIOS support...\n"); /* * Search the defined area (0xf0000-0xffff0) for a valid PnP BIOS @@ -1016,17 +1066,34 @@ int __init pnpbios_init(void) } break; } - if (!pnp_bios_present()) + if (!pnp_bios_present()) { + printk(KERN_INFO "PnPBIOS: A PnP BIOS was not detected.\n"); return -ENODEV; + } + + /* + * we found a pnpbios, now let's load the rest of the driver + */ + + /* read the node info */ + if (pnp_bios_dev_node_info(&node_info)) { + printk(KERN_ERR "PnPBIOS: Unable to get node info. Aborting.\n"); + return -EIO; + } + + /* register with the pnp layer */ pnp_register_protocol(&pnpbios_protocol); - build_devlist(); - /*if ( ! dont_reserve_resources )*/ - /*reserve_resources();*/ + #ifdef CONFIG_PROC_FS + /* start the proc interface */ r = pnpbios_proc_init(); if (r) return r; #endif + + /* scan for pnpbios devices */ + build_devlist(); + return 0; } diff --git a/drivers/pnp/pnpbios/proc.c b/drivers/pnp/pnpbios/proc.c index a371eb62ecc5..7b673d4e9e0b 100644 --- a/drivers/pnp/pnpbios/proc.c +++ b/drivers/pnp/pnpbios/proc.c @@ -31,7 +31,6 @@ static struct proc_dir_entry *proc_pnp = NULL; static struct proc_dir_entry *proc_pnp_boot = NULL; -static struct pnp_dev_node_info node_info; static int proc_read_pnpconfig(char *buf, char **start, off_t pos, int count, int *eof, void *data) @@ -136,7 +135,7 @@ static int proc_read_devices(char *buf, char **start, off_t pos, /* 26 = the number of characters per line sprintf'ed */ if ((p - buf + 26) > count) break; - if (pnp_bios_get_dev_node(&nodenum, 1, node)) + if (pnp_bios_get_dev_node(&nodenum, PNPMODE_STATIC, node)) break; p += sprintf(p, "%02x\t%08x\t%02x:%02x:%02x\t%04x\n", node->handle, node->eisa_id, @@ -193,6 +192,30 @@ static int proc_write_node(struct file *file, const char *buf, return count; } +int pnpbios_interface_attach_device(struct pnp_bios_node * node) +{ + char name[3]; + struct proc_dir_entry *ent; + + sprintf(name, "%02x", node->handle); + if ( !pnpbios_dont_use_current_config ) { + ent = create_proc_entry(name, 0, proc_pnp); + if (ent) { + ent->read_proc = proc_read_node; + ent->write_proc = proc_write_node; + ent->data = (void *)(long)(node->handle); + } + } + ent = create_proc_entry(name, 0, proc_pnp_boot); + if (ent) { + ent->read_proc = proc_read_node; + ent->write_proc = proc_write_node; + ent->data = (void *)(long)(node->handle+0x100); + return 0; + } + return -EIO; +} + /* * When this is called, pnpbios functions are assumed to * work and the pnpbios_dont_use_current_config flag @@ -200,14 +223,6 @@ static int proc_write_node(struct file *file, const char *buf, */ int __init pnpbios_proc_init( void ) { - struct pnp_bios_node *node; - struct proc_dir_entry *ent; - char name[3]; - u8 nodenum; - - if (pnp_bios_dev_node_info(&node_info)) - return -EIO; - proc_pnp = proc_mkdir("pnp", proc_bus); if (!proc_pnp) return -EIO; @@ -219,36 +234,6 @@ int __init pnpbios_proc_init( void ) create_proc_read_entry("escd_info", 0, proc_pnp, proc_read_escdinfo, NULL); create_proc_read_entry("escd", S_IRUSR, proc_pnp, proc_read_escd, NULL); create_proc_read_entry("legacy_device_resources", 0, proc_pnp, proc_read_legacyres, NULL); - - node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL); - if (!node) - return -ENOMEM; - - for (nodenum=0; nodenum<0xff; ) { - u8 thisnodenum = nodenum; - if (pnp_bios_get_dev_node(&nodenum, 1, node) != 0) - break; - sprintf(name, "%02x", node->handle); - if ( !pnpbios_dont_use_current_config ) { - ent = create_proc_entry(name, 0, proc_pnp); - if (ent) { - ent->read_proc = proc_read_node; - ent->write_proc = proc_write_node; - ent->data = (void *)(long)(node->handle); - } - } - ent = create_proc_entry(name, 0, proc_pnp_boot); - if (ent) { - ent->read_proc = proc_read_node; - ent->write_proc = proc_write_node; - ent->data = (void *)(long)(node->handle+0x100); - } - if (nodenum <= thisnodenum) { - printk(KERN_ERR "%s Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", "PnPBIOS: proc_init:", (unsigned int)nodenum, (unsigned int)thisnodenum); - break; - } - } - kfree(node); return 0; } diff --git a/include/linux/pnpbios.h b/include/linux/pnpbios.h index 1c1ec9c55d78..39d86068141f 100644 --- a/include/linux/pnpbios.h +++ b/include/linux/pnpbios.h @@ -29,7 +29,7 @@ #include /* - * Status codes (warnings and errors) + * Return codes */ #define PNP_SUCCESS 0x00 #define PNP_NOT_SET_STATICALLY 0x7f @@ -75,6 +75,7 @@ #define PNPMSG_POWER_OFF 0x41 #define PNPMSG_PNP_OS_ACTIVE 0x42 #define PNPMSG_PNP_OS_INACTIVE 0x43 + /* * Plug and Play BIOS flags */ @@ -88,6 +89,12 @@ #define pnpbios_is_static(x) (((x)->flags & 0x0100) == 0x0000) #define pnpbios_is_dynamic(x) ((x)->flags & 0x0080) +/* + * Function Parameters + */ +#define PNPMODE_STATIC 1 +#define PNPMODE_DYNAMIC 0 + /* 0x8000 through 0xffff are OEM defined */ #pragma pack(1) @@ -125,8 +132,10 @@ struct pnp_bios_node { /* non-exported */ extern int pnpbios_dont_use_current_config; +extern struct pnp_dev_node_info node_info; extern void *pnpbios_kmalloc(size_t size, int f); extern int pnpbios_init (void); +extern int pnpbios_interface_attach_device(struct pnp_bios_node * node); extern int pnpbios_proc_init (void); extern void pnpbios_proc_exit (void); -- cgit v1.2.3 From b822f83d3e79caa6f938a56541adfcd9d4d09795 Mon Sep 17 00:00:00 2001 From: Adam Belay Date: Tue, 25 Mar 2003 17:31:57 +0000 Subject: [PATCH 2.5] PnP changes to allow MODULE_DEVICE_TABLE() This patch fixes the MODULE_DEVICE_TABLE problems, the correct code was accidentally lost a few merges back. It is from Daniel Ritz , below is the original message. hello adam, jaroslav, list this patch does: - rename struct pnp_card_id to pnp_card_device_id - fix all references to it this is needed for the MODULE_DEVICE_TABLE() macro to work with pnp_card's. jaroslav did this a while ago (changeset 1.879.79.1), but adam undid it a bit later (changeset 1.889.202.3). but why? w/o the patch gcc dies when compiling als100.c with the message 'storage size of __mod_pnp_card_device_table unknown' (this is from the macro). any reasons why i should not send this to linus? against 2.5.65-bk rgds -daniel --- drivers/isdn/hisax/hisax_fcpcipnp.c | 4 ++-- drivers/pnp/card.c | 6 +++--- include/linux/pnp.h | 6 +++--- sound/isa/als100.c | 8 ++++---- sound/isa/sb/es968.c | 8 ++++---- sound/oss/sb_card.c | 2 +- sound/oss/sb_card.h | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-) (limited to 'include/linux') diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c index 2801da435924..6963d27f4500 100644 --- a/drivers/isdn/hisax/hisax_fcpcipnp.c +++ b/drivers/isdn/hisax/hisax_fcpcipnp.c @@ -909,7 +909,7 @@ static struct pci_driver fcpci_driver = { #ifdef CONFIG_PNP_CARD static int __devinit fcpnp_probe(struct pnp_card *card, - const struct pnp_card_id *card_id) + const struct pnp_card_device_id *card_id) { struct fritz_adapter *adapter; struct pnp_dev *pnp_dev; @@ -955,7 +955,7 @@ static void __devexit fcpnp_remove(struct pnp_card *pcard) delete_adapter(adapter); } -static struct pnp_card_id fcpnp_ids[] __devinitdata = { +static struct pnp_card_device_id fcpnp_ids[] __devinitdata = { { .id = "AVM0900", .driver_data = (unsigned long) "Fritz!Card PnP", .devs = { { "AVM0900" } }, diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c index 2779c5010217..7ea94fc68c8d 100644 --- a/drivers/pnp/card.c +++ b/drivers/pnp/card.c @@ -22,9 +22,9 @@ LIST_HEAD(pnp_cards); LIST_HEAD(pnp_card_drivers); -static const struct pnp_card_id * match_card(struct pnp_card_driver * drv, struct pnp_card * card) +static const struct pnp_card_device_id * match_card(struct pnp_card_driver * drv, struct pnp_card * card) { - const struct pnp_card_id * drv_id = drv->id_table; + const struct pnp_card_device_id * drv_id = drv->id_table; while (*drv_id->id){ if (compare_pnp_id(card->id,drv_id->id)) return drv_id; @@ -52,7 +52,7 @@ static void card_remove_first(struct pnp_dev * dev) static int card_probe(struct pnp_card * card, struct pnp_card_driver * drv) { - const struct pnp_card_id *id = match_card(drv,card); + const struct pnp_card_device_id *id = match_card(drv,card); if (id) { struct pnp_card_link * clink = pnp_alloc(sizeof(struct pnp_card_link)); if (!clink) diff --git a/include/linux/pnp.h b/include/linux/pnp.h index b2b9b2fcf3f0..73d74d0e52a7 100644 --- a/include/linux/pnp.h +++ b/include/linux/pnp.h @@ -295,7 +295,7 @@ struct pnp_device_id { unsigned long driver_data; /* data private to the driver */ }; -struct pnp_card_id { +struct pnp_card_device_id { char id[PNP_ID_LEN]; unsigned long driver_data; /* data private to the driver */ struct { @@ -317,9 +317,9 @@ struct pnp_driver { struct pnp_card_driver { struct list_head global_list; char * name; - const struct pnp_card_id *id_table; + const struct pnp_card_device_id *id_table; unsigned int flags; - int (*probe) (struct pnp_card_link *card, const struct pnp_card_id *card_id); + int (*probe) (struct pnp_card_link *card, const struct pnp_card_device_id *card_id); void (*remove) (struct pnp_card_link *card); struct pnp_driver link; }; diff --git a/sound/isa/als100.c b/sound/isa/als100.c index 196b6ee941ae..fc0a96cee7c3 100644 --- a/sound/isa/als100.c +++ b/sound/isa/als100.c @@ -98,7 +98,7 @@ struct snd_card_als100 { struct pnp_dev *devopl; }; -static struct pnp_card_id snd_als100_pnpids[] __devinitdata = { +static struct pnp_card_device_id snd_als100_pnpids[] __devinitdata = { /* ALS100 - PRO16PNP */ { .id = "ALS0001", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" }, } }, /* ALS110 - MF1000 - Digimate 3D Sound */ @@ -118,7 +118,7 @@ MODULE_DEVICE_TABLE(pnp_card, snd_als100_pnpids); static int __devinit snd_card_als100_isapnp(int dev, struct snd_card_als100 *acard, struct pnp_card_link *card, - const struct pnp_card_id *id) + const struct pnp_card_device_id *id) { struct pnp_dev *pdev; struct pnp_resource_table * cfg = kmalloc(GFP_ATOMIC, sizeof(struct pnp_resource_table)); @@ -210,7 +210,7 @@ static int __devinit snd_card_als100_isapnp(int dev, struct snd_card_als100 *aca static int __init snd_card_als100_probe(int dev, struct pnp_card_link *pcard, - const struct pnp_card_id *pid) + const struct pnp_card_device_id *pid) { int error; sb_t *chip; @@ -288,7 +288,7 @@ static int __init snd_card_als100_probe(int dev, } static int __devinit snd_als100_pnp_detect(struct pnp_card_link *card, - const struct pnp_card_id *id) + const struct pnp_card_device_id *id) { static int dev; int res; diff --git a/sound/isa/sb/es968.c b/sound/isa/sb/es968.c index eab7535c706b..9f71c31eaf08 100644 --- a/sound/isa/sb/es968.c +++ b/sound/isa/sb/es968.c @@ -69,7 +69,7 @@ struct snd_card_es968 { struct pnp_dev *dev; }; -static struct pnp_card_id snd_es968_pnpids[] __devinitdata = { +static struct pnp_card_device_id snd_es968_pnpids[] __devinitdata = { { .id = "ESS0968", .devs = { { "@@@0968" }, } }, { .id = "", } /* end */ }; @@ -92,7 +92,7 @@ static void snd_card_es968_interrupt(int irq, void *dev_id, static int __devinit snd_card_es968_isapnp(int dev, struct snd_card_es968 *acard, struct pnp_card_link *card, - const struct pnp_card_id *id) + const struct pnp_card_device_id *id) { struct pnp_dev *pdev; struct pnp_resource_table * cfg = kmalloc(GFP_ATOMIC, sizeof(struct pnp_resource_table)); @@ -133,7 +133,7 @@ static int __devinit snd_card_es968_isapnp(int dev, struct snd_card_es968 *acard static int __init snd_card_es968_probe(int dev, struct pnp_card_link *pcard, - const struct pnp_card_id *pid) + const struct pnp_card_device_id *pid) { int error; sb_t *chip; @@ -188,7 +188,7 @@ static int __init snd_card_es968_probe(int dev, } static int __devinit snd_es968_pnp_detect(struct pnp_card_link *card, - const struct pnp_card_id *id) + const struct pnp_card_device_id *id) { static int dev; int res; diff --git a/sound/oss/sb_card.c b/sound/oss/sb_card.c index 7ef868123af2..6b2d2c71d4ee 100644 --- a/sound/oss/sb_card.c +++ b/sound/oss/sb_card.c @@ -224,7 +224,7 @@ static void sb_dev2cfg(struct pnp_dev *dev, struct sb_card_config *scc) } /* Probe callback function for the PnP API */ -static int sb_pnp_probe(struct pnp_card_link *card, const struct pnp_card_id *card_id) +static int sb_pnp_probe(struct pnp_card_link *card, const struct pnp_card_device_id *card_id) { struct sb_card_config *scc; struct sb_module_options sbmo = {0}; /* Default to 0 for PnP */ diff --git a/sound/oss/sb_card.h b/sound/oss/sb_card.h index fc19d6138f79..d05046eeef91 100644 --- a/sound/oss/sb_card.h +++ b/sound/oss/sb_card.h @@ -23,7 +23,7 @@ struct sb_card_config { */ /* Card PnP ID Table */ -static struct pnp_card_id sb_pnp_card_table[] = { +static struct pnp_card_device_id sb_pnp_card_table[] = { /* Sound Blaster 16 */ {.id = "CTL0024", .driver_data = 0, devs : { {.id="CTL0031"}, } }, /* Sound Blaster 16 */ -- cgit v1.2.3 From 7777d006d3c38a0bbb254e35d96cf8f2b9f925a2 Mon Sep 17 00:00:00 2001 From: John Levon Date: Fri, 4 Apr 2003 04:12:09 -0800 Subject: [PATCH] bk - fix oprofile for pm driver register OK, so I screwed up - didn't notice the late_initcall() that was introduced, which was obviously bogus. This one should build OK for the module case. I've tested insmod/rmmod alongside a mounted sysfs. I think the built-in case is OK: oprofile/ is after kernel/ in the link order. I tested that too. --- arch/alpha/oprofile/common.c | 6 ++++++ arch/i386/Makefile | 2 +- arch/i386/oprofile/init.c | 9 +++++++++ arch/i386/oprofile/nmi_int.c | 24 ++++++++++++++++++++++-- arch/parisc/oprofile/init.c | 5 +++++ arch/ppc64/oprofile/init.c | 5 +++++ arch/sparc64/oprofile/init.c | 5 +++++ drivers/oprofile/oprof.c | 1 + include/linux/oprofile.h | 5 +++++ 9 files changed, 59 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/arch/alpha/oprofile/common.c b/arch/alpha/oprofile/common.c index 3faf5f796083..4f40b8292e99 100644 --- a/arch/alpha/oprofile/common.c +++ b/arch/alpha/oprofile/common.c @@ -186,3 +186,9 @@ oprofile_arch_init(struct oprofile_operations **ops) return 0; } + + +void __exit +oprofile_arch_exit(void) +{ +} diff --git a/arch/i386/Makefile b/arch/i386/Makefile index 7eea7c1def29..4a748322d50c 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -84,7 +84,7 @@ core-y += arch/i386/kernel/ \ arch/i386/$(mcore-y)/ drivers-$(CONFIG_MATH_EMULATION) += arch/i386/math-emu/ drivers-$(CONFIG_PCI) += arch/i386/pci/ -# FIXME: is drivers- right ? +# must be linked after kernel/ drivers-$(CONFIG_OPROFILE) += arch/i386/oprofile/ CFLAGS += $(mflags-y) diff --git a/arch/i386/oprofile/init.c b/arch/i386/oprofile/init.c index c1d72e747506..911c600eb345 100644 --- a/arch/i386/oprofile/init.c +++ b/arch/i386/oprofile/init.c @@ -17,6 +17,7 @@ */ extern int nmi_init(struct oprofile_operations ** ops); +extern void nmi_exit(void); extern void timer_init(struct oprofile_operations ** ops); int __init oprofile_arch_init(struct oprofile_operations ** ops) @@ -27,3 +28,11 @@ int __init oprofile_arch_init(struct oprofile_operations ** ops) timer_init(ops); return 0; } + + +void __exit oprofile_arch_exit(void) +{ +#ifdef CONFIG_X86_LOCAL_APIC + nmi_exit(); +#endif +} diff --git a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c index c158cc895916..54168cc66918 100644 --- a/arch/i386/oprofile/nmi_int.c +++ b/arch/i386/oprofile/nmi_int.c @@ -67,15 +67,22 @@ static struct device device_nmi = { }; -static int __init init_nmi_driverfs(void) +static int __init init_driverfs(void) { driver_register(&nmi_driver); return device_register(&device_nmi); } -late_initcall(init_nmi_driverfs); +static void __exit exit_driverfs(void) +{ + device_unregister(&device_nmi); + driver_unregister(&nmi_driver); +} +#else +#define init_driverfs() do { } while (0) +#define exit_driverfs() do { } while (0) #endif /* CONFIG_PM */ @@ -297,6 +304,10 @@ static int __init ppro_init(void) #endif /* !CONFIG_X86_64 */ + +/* in order to get driverfs right */ +static int using_nmi; + int __init nmi_init(struct oprofile_operations ** ops) { __u8 vendor = current_cpu_data.x86_vendor; @@ -339,7 +350,16 @@ int __init nmi_init(struct oprofile_operations ** ops) return 0; } + init_driverfs(); + using_nmi = 1; *ops = &nmi_ops; printk(KERN_INFO "oprofile: using NMI interrupt.\n"); return 1; } + + +void __exit nmi_exit(void) +{ + if (using_nmi) + exit_driverfs(); +} diff --git a/arch/parisc/oprofile/init.c b/arch/parisc/oprofile/init.c index c7268ba1a8d2..78adf8e9e5aa 100644 --- a/arch/parisc/oprofile/init.c +++ b/arch/parisc/oprofile/init.c @@ -18,3 +18,8 @@ int __init oprofile_arch_init(struct oprofile_operations ** ops) timer_init(ops); return 0; } + + +void __exit oprofile_arch_exit() +{ +} diff --git a/arch/ppc64/oprofile/init.c b/arch/ppc64/oprofile/init.c index c7268ba1a8d2..cb73527a8900 100644 --- a/arch/ppc64/oprofile/init.c +++ b/arch/ppc64/oprofile/init.c @@ -18,3 +18,8 @@ int __init oprofile_arch_init(struct oprofile_operations ** ops) timer_init(ops); return 0; } + + +void __exit oprofile_arch_exit(void) +{ +} diff --git a/arch/sparc64/oprofile/init.c b/arch/sparc64/oprofile/init.c index c7268ba1a8d2..cb73527a8900 100644 --- a/arch/sparc64/oprofile/init.c +++ b/arch/sparc64/oprofile/init.c @@ -18,3 +18,8 @@ int __init oprofile_arch_init(struct oprofile_operations ** ops) timer_init(ops); return 0; } + + +void __exit oprofile_arch_exit(void) +{ +} diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index 04f9131c8dd5..1515d4a39e85 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -148,6 +148,7 @@ out: static void __exit oprofile_exit(void) { oprofilefs_unregister(); + oprofile_arch_exit(); } diff --git a/include/linux/oprofile.h b/include/linux/oprofile.h index 5d906c21103f..6dba9058bca0 100644 --- a/include/linux/oprofile.h +++ b/include/linux/oprofile.h @@ -45,6 +45,11 @@ struct oprofile_operations { */ int oprofile_arch_init(struct oprofile_operations ** ops); +/** + * One-time exit/cleanup for the arch. + */ +void oprofile_arch_exit(void); + /** * Add a sample. This may be called from any context. Pass * smp_processor_id() as cpu. -- cgit v1.2.3 From da334d91ff7001d234863fc7692de1ff90bed57a Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Fri, 4 Apr 2003 04:12:17 -0800 Subject: [PATCH] linux-2.5.66-signal-cleanup.patch Here is the cleanup patch I promised back in February. Sorry it took a while. The effects should be purely cosmetic in 2.5.66. However, the new interface for the proper way to send thread-specific of process-global signals from inside the kernel is needed for correct implementation of some fixes to timer stuff that Ulrich told me about. This cleans up some obsolete comments and macros in kernel/signal.c, restores send_sig_info to its original behavior, and adds a global entry point send_group_sig_info. I checked all the uses of send_sig and send_sig_info and changed a few to send_group_sig_info. I think it would be cleanest if the whole mess of *_sig* entry points were reduced to two or three, but I did the change that minimized the number of callers I had to fix up. There should be no discernible difference, since the 2.5.66 send_sig_info function did group semantics for those signals by number already. The only exception to that is pdeath_signal, which I guess can be any signal number but I deemed ought to be process-wide. I did not change any of the calls using SIGKILL, though that does have process-wide semantics. There is no need to change it since SIGKILL always kills the whole group, though the code path for send_sig(SIGKILL,...) calls in multithreaded processes will be different now. --- drivers/char/tty_io.c | 4 +- drivers/isdn/i4l/isdn_tty.c | 2 +- fs/fcntl.c | 4 +- include/linux/sched.h | 6 ++ kernel/exit.c | 2 +- kernel/itimer.c | 2 +- kernel/signal.c | 171 ++++++++++++++++++++++++-------------------- 7 files changed, 106 insertions(+), 85 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index f3c2f35381ac..c57b097ac389 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -506,8 +506,8 @@ void do_tty_hangup(void *data) p->tty = NULL; if (!p->leader) continue; - send_sig(SIGHUP, p, 1); - send_sig(SIGCONT, p, 1); + send_group_sig_info(SIGHUP, SEND_SIG_PRIV, p); + send_group_sig_info(SIGCONT, SEND_SIG_PRIV, p); if (tty->pgrp > 0) p->tty_old_pgrp = tty->pgrp; } diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index dd58066f7386..0053c471fb16 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -2036,7 +2036,7 @@ modem_write_profile(atemu * m) memcpy(m->pmsn, m->msn, ISDN_MSNLEN); memcpy(m->plmsn, m->lmsn, ISDN_LMSNLEN); if (dev->profd) - send_sig(SIGIO, dev->profd, 1); + group_send_sig_info(SIGIO, SEND_SIG_PRIV, dev->profd); } int diff --git a/fs/fcntl.c b/fs/fcntl.c index fae2022ada19..f1bf41ec99a5 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -465,7 +465,7 @@ static void send_sigio_to_task(struct task_struct *p, break; /* fall-through: fall back on the old plain SIGIO signal */ case 0: - send_sig(SIGIO, p, 1); + send_group_sig_info(SIGIO, SEND_SIG_PRIV, p); } } @@ -501,7 +501,7 @@ static void send_sigurg_to_task(struct task_struct *p, struct fown_struct *fown) { if (sigio_perm(p, fown)) - send_sig(SIGURG, p, 1); + send_group_sig_info(SIGURG, SEND_SIG_PRIV, p); } int send_sigurg(struct fown_struct *fown) diff --git a/include/linux/sched.h b/include/linux/sched.h index d001088e58b3..f3b4c5891898 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -541,6 +541,7 @@ extern void block_all_signals(int (*notifier)(void *priv), void *priv, extern void unblock_all_signals(void); extern void release_task(struct task_struct * p); extern int send_sig_info(int, struct siginfo *, struct task_struct *); +extern int send_group_sig_info(int, struct siginfo *, struct task_struct *); extern int force_sig_info(int, struct siginfo *, struct task_struct *); extern int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp); extern int kill_pg_info(int, struct siginfo *, pid_t); @@ -558,6 +559,11 @@ extern int kill_proc(pid_t, int, int); extern int do_sigaction(int, const struct k_sigaction *, struct k_sigaction *); extern int do_sigaltstack(const stack_t *, stack_t *, unsigned long); +/* These can be the second arg to send_sig_info/send_group_sig_info. */ +#define SEND_SIG_NOINFO ((struct siginfo *) 0) +#define SEND_SIG_PRIV ((struct siginfo *) 1) +#define SEND_SIG_FORCED ((struct siginfo *) 2) + /* True if we are on the alternate signal stack. */ static inline int on_sig_stack(unsigned long sp) diff --git a/kernel/exit.c b/kernel/exit.c index ffc0973ab074..b393a46247c4 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -488,7 +488,7 @@ static inline void reparent_thread(task_t *p, task_t *father, int traced) p->self_exec_id++; if (p->pdeath_signal) - send_sig(p->pdeath_signal, p, 0); + send_group_sig_info(p->pdeath_signal, 0, p); /* Move the child from its dying parent to the new one. */ if (unlikely(traced)) { diff --git a/kernel/itimer.c b/kernel/itimer.c index 4fc29f3de5e8..4db3b24ec41e 100644 --- a/kernel/itimer.c +++ b/kernel/itimer.c @@ -67,7 +67,7 @@ void it_real_fn(unsigned long __data) struct task_struct * p = (struct task_struct *) __data; unsigned long interval; - send_sig(SIGALRM, p, 1); + send_group_sig_info(SIGALRM, SEND_SIG_PRIV, p); interval = p->it_real_incr; if (interval) { if (interval > (unsigned long) LONG_MAX) diff --git a/kernel/signal.c b/kernel/signal.c index 488134eec0e2..096d58ad5237 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -33,64 +33,79 @@ static kmem_cache_t *sigqueue_cachep; atomic_t nr_queued_signals; int max_queued_signals = 1024; -/********************************************************* - - POSIX thread group signal behavior: - ----------------------------------------------------------- -| | userspace | kernel | ----------------------------------------------------------- -| SIGHUP | load-balance | kill-all | -| SIGINT | load-balance | kill-all | -| SIGQUIT | load-balance | kill-all+core | -| SIGILL | specific | kill-all+core | -| SIGTRAP | specific | kill-all+core | -| SIGABRT/SIGIOT | specific | kill-all+core | -| SIGBUS | specific | kill-all+core | -| SIGFPE | specific | kill-all+core | -| SIGKILL | n/a | kill-all | -| SIGUSR1 | load-balance | kill-all | -| SIGSEGV | specific | kill-all+core | -| SIGUSR2 | load-balance | kill-all | -| SIGPIPE | specific | kill-all | -| SIGALRM | load-balance | kill-all | -| SIGTERM | load-balance | kill-all | -| SIGCHLD | load-balance | ignore | -| SIGCONT | load-balance | ignore | -| SIGSTOP | n/a | stop-all | -| SIGTSTP | load-balance | stop-all | -| SIGTTIN | load-balance | stop-all | -| SIGTTOU | load-balance | stop-all | -| SIGURG | load-balance | ignore | -| SIGXCPU | specific | kill-all+core | -| SIGXFSZ | specific | kill-all+core | -| SIGVTALRM | load-balance | kill-all | -| SIGPROF | specific | kill-all | -| SIGPOLL/SIGIO | load-balance | kill-all | -| SIGSYS/SIGUNUSED | specific | kill-all+core | -| SIGSTKFLT | specific | kill-all | -| SIGWINCH | load-balance | ignore | -| SIGPWR | load-balance | kill-all | -| SIGRTMIN-SIGRTMAX | load-balance | kill-all | ----------------------------------------------------------- - - non-POSIX signal thread group behavior: - ----------------------------------------------------------- -| | userspace | kernel | ----------------------------------------------------------- -| SIGEMT | specific | kill-all+core | ----------------------------------------------------------- -*/ - -/* Some systems do not have a SIGSTKFLT and the kernel never - * generates such signals anyways. +/* + * In POSIX a signal is sent either to a specific thread (Linux task) + * or to the process as a whole (Linux thread group). How the signal + * is sent determines whether it's to one thread or the whole group, + * which determines which signal mask(s) are involved in blocking it + * from being delivered until later. When the signal is delivered, + * either it's caught or ignored by a user handler or it has a default + * effect that applies to the whole thread group (POSIX process). + * + * The possible effects an unblocked signal set to SIG_DFL can have are: + * ignore - Nothing Happens + * terminate - kill the process, i.e. all threads in the group, + * similar to exit_group. The group leader (only) reports + * WIFSIGNALED status to its parent. + * coredump - write a core dump file describing all threads using + * the same mm and then kill all those threads + * stop - stop all the threads in the group, i.e. TASK_STOPPED state + * + * SIGKILL and SIGSTOP cannot be caught, blocked, or ignored. + * Other signals when not blocked and set to SIG_DFL behaves as follows. + * The job control signals also have other special effects. + * + * +--------------------+------------------+ + * | POSIX signal | default action | + * +--------------------+------------------+ + * | SIGHUP | terminate | + * | SIGINT | terminate | + * | SIGQUIT | coredump | + * | SIGILL | coredump | + * | SIGTRAP | coredump | + * | SIGABRT/SIGIOT | coredump | + * | SIGBUS | coredump | + * | SIGFPE | coredump | + * | SIGKILL | terminate(+) | + * | SIGUSR1 | terminate | + * | SIGSEGV | coredump | + * | SIGUSR2 | terminate | + * | SIGPIPE | terminate | + * | SIGALRM | terminate | + * | SIGTERM | terminate | + * | SIGCHLD | ignore | + * | SIGCONT | ignore(*) | + * | SIGSTOP | stop(*)(+) | + * | SIGTSTP | stop(*) | + * | SIGTTIN | stop(*) | + * | SIGTTOU | stop(*) | + * | SIGURG | ignore | + * | SIGXCPU | coredump | + * | SIGXFSZ | coredump | + * | SIGVTALRM | terminate | + * | SIGPROF | terminate | + * | SIGPOLL/SIGIO | terminate | + * | SIGSYS/SIGUNUSED | coredump | + * | SIGSTKFLT | terminate | + * | SIGWINCH | ignore | + * | SIGPWR | terminate | + * | SIGRTMIN-SIGRTMAX | terminate | + * +--------------------+------------------+ + * | non-POSIX signal | default action | + * +--------------------+------------------+ + * | SIGEMT | coredump | + * +--------------------+------------------+ + * + * (+) For SIGKILL and SIGSTOP the action is "always", not just "default". + * (*) Special job control effects: + * When SIGCONT is sent, it resumes the process (all threads in the group) + * from TASK_STOPPED state and also clears any pending/queued stop signals + * (any of those marked with "stop(*)"). This happens regardless of blocking, + * catching, or ignoring SIGCONT. When any stop signal is sent, it clears + * any pending/queued SIGCONT signals; this happens regardless of blocking, + * catching, or ignored the stop signal, though (except for SIGSTOP) the + * default action of stopping the process may happen later or never. */ -#ifdef SIGSTKFLT -#define M_SIGSTKFLT M(SIGSTKFLT) -#else -#define M_SIGSTKFLT 0 -#endif #ifdef SIGEMT #define M_SIGEMT M(SIGEMT) @@ -105,16 +120,6 @@ int max_queued_signals = 1024; #endif #define T(sig, mask) (M(sig) & (mask)) -#define SIG_KERNEL_BROADCAST_MASK (\ - M(SIGHUP) | M(SIGINT) | M(SIGQUIT) | M(SIGILL) | \ - M(SIGTRAP) | M(SIGABRT) | M(SIGBUS) | M(SIGFPE) | \ - M(SIGKILL) | M(SIGUSR1) | M(SIGSEGV) | M(SIGUSR2) | \ - M(SIGPIPE) | M(SIGALRM) | M(SIGTERM) | M(SIGXCPU) | \ - M(SIGXFSZ) | M(SIGVTALRM) | M(SIGPROF) | M(SIGPOLL) | \ - M(SIGSYS) | M_SIGSTKFLT | M(SIGPWR) | M(SIGCONT) | \ - M(SIGSTOP) | M(SIGTSTP) | M(SIGTTIN) | M(SIGTTOU) | \ - M_SIGEMT ) - #define SIG_KERNEL_ONLY_MASK (\ M(SIGKILL) | M(SIGSTOP) ) @@ -599,7 +604,7 @@ static void do_notify_parent_cldstop(struct task_struct *tsk, struct task_struct *parent); /* - * Handle magic process-wide effects of stop/continue signals, and SIGKILL. + * Handle magic process-wide effects of stop/continue signals. * Unlike the signal actions, these happen immediately at signal-generation * time regardless of blocking, ignoring, or handling. This does the * actual continuing for SIGCONT, but not the actual stopping for stop @@ -1134,9 +1139,8 @@ static int kill_something_info(int sig, struct siginfo *info, int pid) */ /* - * XXX should probably nix these interfaces and update the kernel - * to specify explicitly whether the signal is a group signal or - * specific to a thread. + * These two are the most common entry points. They send a signal + * just to the specific thread. */ int send_sig_info(int sig, struct siginfo *info, struct task_struct *p) @@ -1150,13 +1154,9 @@ send_sig_info(int sig, struct siginfo *info, struct task_struct *p) * going away or changing from under us. */ read_lock(&tasklist_lock); - if (T(sig, SIG_KERNEL_BROADCAST_MASK)) { - ret = group_send_sig_info(sig, info, p); - } else { - spin_lock_irq(&p->sighand->siglock); - ret = specific_send_sig_info(sig, info, p); - spin_unlock_irq(&p->sighand->siglock); - } + spin_lock_irq(&p->sighand->siglock); + ret = specific_send_sig_info(sig, info, p); + spin_unlock_irq(&p->sighand->siglock); read_unlock(&tasklist_lock); return ret; } @@ -1167,6 +1167,20 @@ send_sig(int sig, struct task_struct *p, int priv) return send_sig_info(sig, (void*)(long)(priv != 0), p); } +/* + * This is the entry point for "process-wide" signals. + * They will go to an appropriate thread in the thread group. + */ +int +send_group_sig_info(int sig, struct siginfo *info, struct task_struct *p) +{ + int ret; + read_lock(&tasklist_lock); + ret = group_send_sig_info(sig, info, p); + read_unlock(&tasklist_lock); + return ret; +} + void force_sig(int sig, struct task_struct *p) { @@ -1642,6 +1656,7 @@ EXPORT_SYMBOL(kill_sl_info); EXPORT_SYMBOL(notify_parent); EXPORT_SYMBOL(send_sig); EXPORT_SYMBOL(send_sig_info); +EXPORT_SYMBOL(send_group_sig_info); EXPORT_SYMBOL(sigprocmask); EXPORT_SYMBOL(block_all_signals); EXPORT_SYMBOL(unblock_all_signals); -- cgit v1.2.3