diff options
author | Tilman Schmidt <tilman@imap.cc> | 2010-03-14 08:58:05 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-03-15 19:00:49 -0400 |
commit | bc35b4e347c047fb1c665bb761ddb22482539f7f (patch) | |
tree | 4f5b4b1c882b2f36015e0aada78e9307e812a0f9 /drivers/isdn | |
parent | 4d823be98c5b24d94c7f41a384a4bb60d7848ad5 (diff) |
gigaset: avoid registering CAPI driver more than once
Registering/unregistering the Gigaset CAPI driver when a device is
connected/disconnected causes an Oops when disconnecting two Gigaset
devices in a row, because the same capi_driver structure gets
unregistered twice. Fix by making driver registration/unregistration
a separate operation (empty in the ISDN4Linux case) called when the
main module is loaded/unloaded.
Impact: bugfix
Signed-off-by: Tilman Schmidt <tilman@imap.cc>
Acked-by: Karsten Keil <keil@b1-systems.de>
CC: stable@kernel.org
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/isdn')
-rw-r--r-- | drivers/isdn/gigaset/capi.c | 44 | ||||
-rw-r--r-- | drivers/isdn/gigaset/common.c | 6 | ||||
-rw-r--r-- | drivers/isdn/gigaset/gigaset.h | 6 | ||||
-rw-r--r-- | drivers/isdn/gigaset/i4l.c | 28 |
4 files changed, 53 insertions, 31 deletions
diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c index 6643d6533ccb..4a31962ddf71 100644 --- a/drivers/isdn/gigaset/capi.c +++ b/drivers/isdn/gigaset/capi.c | |||
@@ -2191,36 +2191,24 @@ static const struct file_operations gigaset_proc_fops = { | |||
2191 | .release = single_release, | 2191 | .release = single_release, |
2192 | }; | 2192 | }; |
2193 | 2193 | ||
2194 | static struct capi_driver capi_driver_gigaset = { | ||
2195 | .name = "gigaset", | ||
2196 | .revision = "1.0", | ||
2197 | }; | ||
2198 | |||
2199 | /** | 2194 | /** |
2200 | * gigaset_isdn_register() - register to LL | 2195 | * gigaset_isdn_regdev() - register device to LL |
2201 | * @cs: device descriptor structure. | 2196 | * @cs: device descriptor structure. |
2202 | * @isdnid: device name. | 2197 | * @isdnid: device name. |
2203 | * | 2198 | * |
2204 | * Called by main module to register the device with the LL. | ||
2205 | * | ||
2206 | * Return value: 1 for success, 0 for failure | 2199 | * Return value: 1 for success, 0 for failure |
2207 | */ | 2200 | */ |
2208 | int gigaset_isdn_register(struct cardstate *cs, const char *isdnid) | 2201 | int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid) |
2209 | { | 2202 | { |
2210 | struct gigaset_capi_ctr *iif; | 2203 | struct gigaset_capi_ctr *iif; |
2211 | int rc; | 2204 | int rc; |
2212 | 2205 | ||
2213 | pr_info("Kernel CAPI interface\n"); | ||
2214 | |||
2215 | iif = kmalloc(sizeof(*iif), GFP_KERNEL); | 2206 | iif = kmalloc(sizeof(*iif), GFP_KERNEL); |
2216 | if (!iif) { | 2207 | if (!iif) { |
2217 | pr_err("%s: out of memory\n", __func__); | 2208 | pr_err("%s: out of memory\n", __func__); |
2218 | return 0; | 2209 | return 0; |
2219 | } | 2210 | } |
2220 | 2211 | ||
2221 | /* register driver with CAPI (ToDo: what for?) */ | ||
2222 | register_capi_driver(&capi_driver_gigaset); | ||
2223 | |||
2224 | /* prepare controller structure */ | 2212 | /* prepare controller structure */ |
2225 | iif->ctr.owner = THIS_MODULE; | 2213 | iif->ctr.owner = THIS_MODULE; |
2226 | iif->ctr.driverdata = cs; | 2214 | iif->ctr.driverdata = cs; |
@@ -2241,7 +2229,6 @@ int gigaset_isdn_register(struct cardstate *cs, const char *isdnid) | |||
2241 | rc = attach_capi_ctr(&iif->ctr); | 2229 | rc = attach_capi_ctr(&iif->ctr); |
2242 | if (rc) { | 2230 | if (rc) { |
2243 | pr_err("attach_capi_ctr failed (%d)\n", rc); | 2231 | pr_err("attach_capi_ctr failed (%d)\n", rc); |
2244 | unregister_capi_driver(&capi_driver_gigaset); | ||
2245 | kfree(iif); | 2232 | kfree(iif); |
2246 | return 0; | 2233 | return 0; |
2247 | } | 2234 | } |
@@ -2252,17 +2239,36 @@ int gigaset_isdn_register(struct cardstate *cs, const char *isdnid) | |||
2252 | } | 2239 | } |
2253 | 2240 | ||
2254 | /** | 2241 | /** |
2255 | * gigaset_isdn_unregister() - unregister from LL | 2242 | * gigaset_isdn_unregdev() - unregister device from LL |
2256 | * @cs: device descriptor structure. | 2243 | * @cs: device descriptor structure. |
2257 | * | ||
2258 | * Called by main module to unregister the device from the LL. | ||
2259 | */ | 2244 | */ |
2260 | void gigaset_isdn_unregister(struct cardstate *cs) | 2245 | void gigaset_isdn_unregdev(struct cardstate *cs) |
2261 | { | 2246 | { |
2262 | struct gigaset_capi_ctr *iif = cs->iif; | 2247 | struct gigaset_capi_ctr *iif = cs->iif; |
2263 | 2248 | ||
2264 | detach_capi_ctr(&iif->ctr); | 2249 | detach_capi_ctr(&iif->ctr); |
2265 | kfree(iif); | 2250 | kfree(iif); |
2266 | cs->iif = NULL; | 2251 | cs->iif = NULL; |
2252 | } | ||
2253 | |||
2254 | static struct capi_driver capi_driver_gigaset = { | ||
2255 | .name = "gigaset", | ||
2256 | .revision = "1.0", | ||
2257 | }; | ||
2258 | |||
2259 | /** | ||
2260 | * gigaset_isdn_regdrv() - register driver to LL | ||
2261 | */ | ||
2262 | void gigaset_isdn_regdrv(void) | ||
2263 | { | ||
2264 | pr_info("Kernel CAPI interface\n"); | ||
2265 | register_capi_driver(&capi_driver_gigaset); | ||
2266 | } | ||
2267 | |||
2268 | /** | ||
2269 | * gigaset_isdn_unregdrv() - unregister driver from LL | ||
2270 | */ | ||
2271 | void gigaset_isdn_unregdrv(void) | ||
2272 | { | ||
2267 | unregister_capi_driver(&capi_driver_gigaset); | 2273 | unregister_capi_driver(&capi_driver_gigaset); |
2268 | } | 2274 | } |
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index 85de3399a2f2..bdc01cb9f0ab 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c | |||
@@ -507,7 +507,7 @@ void gigaset_freecs(struct cardstate *cs) | |||
507 | case 2: /* error in initcshw */ | 507 | case 2: /* error in initcshw */ |
508 | /* Deregister from LL */ | 508 | /* Deregister from LL */ |
509 | make_invalid(cs, VALID_ID); | 509 | make_invalid(cs, VALID_ID); |
510 | gigaset_isdn_unregister(cs); | 510 | gigaset_isdn_unregdev(cs); |
511 | 511 | ||
512 | /* fall through */ | 512 | /* fall through */ |
513 | case 1: /* error when registering to LL */ | 513 | case 1: /* error when registering to LL */ |
@@ -769,7 +769,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, | |||
769 | cs->cmdbytes = 0; | 769 | cs->cmdbytes = 0; |
770 | 770 | ||
771 | gig_dbg(DEBUG_INIT, "setting up iif"); | 771 | gig_dbg(DEBUG_INIT, "setting up iif"); |
772 | if (!gigaset_isdn_register(cs, modulename)) { | 772 | if (!gigaset_isdn_regdev(cs, modulename)) { |
773 | pr_err("error registering ISDN device\n"); | 773 | pr_err("error registering ISDN device\n"); |
774 | goto error; | 774 | goto error; |
775 | } | 775 | } |
@@ -1205,11 +1205,13 @@ static int __init gigaset_init_module(void) | |||
1205 | gigaset_debuglevel = DEBUG_DEFAULT; | 1205 | gigaset_debuglevel = DEBUG_DEFAULT; |
1206 | 1206 | ||
1207 | pr_info(DRIVER_DESC DRIVER_DESC_DEBUG "\n"); | 1207 | pr_info(DRIVER_DESC DRIVER_DESC_DEBUG "\n"); |
1208 | gigaset_isdn_regdrv(); | ||
1208 | return 0; | 1209 | return 0; |
1209 | } | 1210 | } |
1210 | 1211 | ||
1211 | static void __exit gigaset_exit_module(void) | 1212 | static void __exit gigaset_exit_module(void) |
1212 | { | 1213 | { |
1214 | gigaset_isdn_unregdrv(); | ||
1213 | } | 1215 | } |
1214 | 1216 | ||
1215 | module_init(gigaset_init_module); | 1217 | module_init(gigaset_init_module); |
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index 1875ab80b335..cdd144ecdc5f 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h | |||
@@ -675,8 +675,10 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size); | |||
675 | */ | 675 | */ |
676 | 676 | ||
677 | /* Called from common.c for setting up/shutting down with the ISDN subsystem */ | 677 | /* Called from common.c for setting up/shutting down with the ISDN subsystem */ |
678 | int gigaset_isdn_register(struct cardstate *cs, const char *isdnid); | 678 | void gigaset_isdn_regdrv(void); |
679 | void gigaset_isdn_unregister(struct cardstate *cs); | 679 | void gigaset_isdn_unregdrv(void); |
680 | int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid); | ||
681 | void gigaset_isdn_unregdev(struct cardstate *cs); | ||
680 | 682 | ||
681 | /* Called from hardware module to indicate completion of an skb */ | 683 | /* Called from hardware module to indicate completion of an skb */ |
682 | void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb); | 684 | void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb); |
diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c index f0acb9dc9e33..c22e5ace8276 100644 --- a/drivers/isdn/gigaset/i4l.c +++ b/drivers/isdn/gigaset/i4l.c | |||
@@ -592,15 +592,13 @@ void gigaset_isdn_stop(struct cardstate *cs) | |||
592 | } | 592 | } |
593 | 593 | ||
594 | /** | 594 | /** |
595 | * gigaset_isdn_register() - register to LL | 595 | * gigaset_isdn_regdev() - register to LL |
596 | * @cs: device descriptor structure. | 596 | * @cs: device descriptor structure. |
597 | * @isdnid: device name. | 597 | * @isdnid: device name. |
598 | * | 598 | * |
599 | * Called by main module to register the device with the LL. | ||
600 | * | ||
601 | * Return value: 1 for success, 0 for failure | 599 | * Return value: 1 for success, 0 for failure |
602 | */ | 600 | */ |
603 | int gigaset_isdn_register(struct cardstate *cs, const char *isdnid) | 601 | int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid) |
604 | { | 602 | { |
605 | isdn_if *iif; | 603 | isdn_if *iif; |
606 | 604 | ||
@@ -650,15 +648,29 @@ int gigaset_isdn_register(struct cardstate *cs, const char *isdnid) | |||
650 | } | 648 | } |
651 | 649 | ||
652 | /** | 650 | /** |
653 | * gigaset_isdn_unregister() - unregister from LL | 651 | * gigaset_isdn_unregdev() - unregister device from LL |
654 | * @cs: device descriptor structure. | 652 | * @cs: device descriptor structure. |
655 | * | ||
656 | * Called by main module to unregister the device from the LL. | ||
657 | */ | 653 | */ |
658 | void gigaset_isdn_unregister(struct cardstate *cs) | 654 | void gigaset_isdn_unregdev(struct cardstate *cs) |
659 | { | 655 | { |
660 | gig_dbg(DEBUG_CMD, "sending UNLOAD"); | 656 | gig_dbg(DEBUG_CMD, "sending UNLOAD"); |
661 | gigaset_i4l_cmd(cs, ISDN_STAT_UNLOAD); | 657 | gigaset_i4l_cmd(cs, ISDN_STAT_UNLOAD); |
662 | kfree(cs->iif); | 658 | kfree(cs->iif); |
663 | cs->iif = NULL; | 659 | cs->iif = NULL; |
664 | } | 660 | } |
661 | |||
662 | /** | ||
663 | * gigaset_isdn_regdrv() - register driver to LL | ||
664 | */ | ||
665 | void gigaset_isdn_regdrv(void) | ||
666 | { | ||
667 | /* nothing to do */ | ||
668 | } | ||
669 | |||
670 | /** | ||
671 | * gigaset_isdn_unregdrv() - unregister driver from LL | ||
672 | */ | ||
673 | void gigaset_isdn_unregdrv(void) | ||
674 | { | ||
675 | /* nothing to do */ | ||
676 | } | ||