summaryrefslogtreecommitdiffstats
path: root/drivers/isdn/capi/capidrv.c
diff options
context:
space:
mode:
authorJan Kiszka <jan.kiszka@web.de>2010-02-08 10:12:13 +0000
committerDavid S. Miller <davem@davemloft.net>2010-02-16 16:01:21 -0800
commitef69bb2ec6036945da1d3d3f07b75253f484f693 (patch)
treead309906a7b20b0b13b573abfb3be9d524f08086 /drivers/isdn/capi/capidrv.c
parent3efecf7a49cde47e5f2deb1d5504951ff4bede53 (diff)
downloadlinux-ef69bb2ec6036945da1d3d3f07b75253f484f693.tar.gz
linux-ef69bb2ec6036945da1d3d3f07b75253f484f693.tar.bz2
linux-ef69bb2ec6036945da1d3d3f07b75253f484f693.zip
CAPI: Rework controller state notifier
Another step towards proper locking: Rework the callback provided to capidrv for controller state changes. This is so far attached to an application, which would require us to hold the corresponding lock across notification calls. But there is no direct relation between a controller up/down event and an application, so let's decouple them and provide a notifier call chain for those events instead. This notifier chain is first of all used internally. Here we request the highest priority to unsure that housekeeping work is done before any other notifications. The chain is exported via [un]register_capictr_notifier to our only user, capidrv, to replace the racy and unfixable capi20_set_callback. Signed-off-by: Jan Kiszka <jan.kiszka@web.de> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/isdn/capi/capidrv.c')
-rw-r--r--drivers/isdn/capi/capidrv.c22
1 files changed, 16 insertions, 6 deletions
diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
index 7d8899ad5796..bf55ed5f38e3 100644
--- a/drivers/isdn/capi/capidrv.c
+++ b/drivers/isdn/capi/capidrv.c
@@ -2210,19 +2210,24 @@ static int capidrv_delcontr(u16 contr)
}
-static void lower_callback(unsigned int cmd, u32 contr, void *data)
+static int
+lower_callback(struct notifier_block *nb, unsigned long val, void *v)
{
+ capi_profile profile;
+ u32 contr = (long)v;
- switch (cmd) {
- case KCI_CONTRUP:
+ switch (val) {
+ case CAPICTR_UP:
printk(KERN_INFO "capidrv: controller %hu up\n", contr);
- (void) capidrv_addcontr(contr, (capi_profile *) data);
+ if (capi20_get_profile(contr, &profile) == CAPI_NOERROR)
+ (void) capidrv_addcontr(contr, &profile);
break;
- case KCI_CONTRDOWN:
+ case CAPICTR_DOWN:
printk(KERN_INFO "capidrv: controller %hu down\n", contr);
(void) capidrv_delcontr(contr);
break;
}
+ return NOTIFY_OK;
}
/*
@@ -2262,6 +2267,10 @@ static void __exit proc_exit(void)
remove_proc_entry("capi/capidrv", NULL);
}
+static struct notifier_block capictr_nb = {
+ .notifier_call = lower_callback,
+};
+
static int __init capidrv_init(void)
{
capi_profile profile;
@@ -2278,7 +2287,7 @@ static int __init capidrv_init(void)
return -EIO;
}
- capi20_set_callback(&global.ap, lower_callback);
+ register_capictr_notifier(&capictr_nb);
errcode = capi20_get_profile(0, &profile);
if (errcode != CAPI_NOERROR) {
@@ -2300,6 +2309,7 @@ static int __init capidrv_init(void)
static void __exit capidrv_exit(void)
{
+ unregister_capictr_notifier(&capictr_nb);
capi20_release(&global.ap);
proc_exit();