diff options
| -rw-r--r-- | drivers/isdn/capi/capidrv.c | 22 | ||||
| -rw-r--r-- | drivers/isdn/capi/kcapi.c | 112 | ||||
| -rw-r--r-- | include/linux/kernelcapi.h | 17 |
3 files changed, 72 insertions, 79 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) | |||
| 2210 | } | 2210 | } |
| 2211 | 2211 | ||
| 2212 | 2212 | ||
| 2213 | static void lower_callback(unsigned int cmd, u32 contr, void *data) | 2213 | static int |
| 2214 | lower_callback(struct notifier_block *nb, unsigned long val, void *v) | ||
| 2214 | { | 2215 | { |
| 2216 | capi_profile profile; | ||
| 2217 | u32 contr = (long)v; | ||
| 2215 | 2218 | ||
| 2216 | switch (cmd) { | 2219 | switch (val) { |
| 2217 | case KCI_CONTRUP: | 2220 | case CAPICTR_UP: |
| 2218 | printk(KERN_INFO "capidrv: controller %hu up\n", contr); | 2221 | printk(KERN_INFO "capidrv: controller %hu up\n", contr); |
| 2219 | (void) capidrv_addcontr(contr, (capi_profile *) data); | 2222 | if (capi20_get_profile(contr, &profile) == CAPI_NOERROR) |
| 2223 | (void) capidrv_addcontr(contr, &profile); | ||
| 2220 | break; | 2224 | break; |
| 2221 | case KCI_CONTRDOWN: | 2225 | case CAPICTR_DOWN: |
| 2222 | printk(KERN_INFO "capidrv: controller %hu down\n", contr); | 2226 | printk(KERN_INFO "capidrv: controller %hu down\n", contr); |
| 2223 | (void) capidrv_delcontr(contr); | 2227 | (void) capidrv_delcontr(contr); |
| 2224 | break; | 2228 | break; |
| 2225 | } | 2229 | } |
| 2230 | return NOTIFY_OK; | ||
| 2226 | } | 2231 | } |
| 2227 | 2232 | ||
| 2228 | /* | 2233 | /* |
| @@ -2262,6 +2267,10 @@ static void __exit proc_exit(void) | |||
| 2262 | remove_proc_entry("capi/capidrv", NULL); | 2267 | remove_proc_entry("capi/capidrv", NULL); |
| 2263 | } | 2268 | } |
| 2264 | 2269 | ||
| 2270 | static struct notifier_block capictr_nb = { | ||
| 2271 | .notifier_call = lower_callback, | ||
| 2272 | }; | ||
| 2273 | |||
| 2265 | static int __init capidrv_init(void) | 2274 | static int __init capidrv_init(void) |
| 2266 | { | 2275 | { |
| 2267 | capi_profile profile; | 2276 | capi_profile profile; |
| @@ -2278,7 +2287,7 @@ static int __init capidrv_init(void) | |||
| 2278 | return -EIO; | 2287 | return -EIO; |
| 2279 | } | 2288 | } |
| 2280 | 2289 | ||
| 2281 | capi20_set_callback(&global.ap, lower_callback); | 2290 | register_capictr_notifier(&capictr_nb); |
| 2282 | 2291 | ||
| 2283 | errcode = capi20_get_profile(0, &profile); | 2292 | errcode = capi20_get_profile(0, &profile); |
| 2284 | if (errcode != CAPI_NOERROR) { | 2293 | if (errcode != CAPI_NOERROR) { |
| @@ -2300,6 +2309,7 @@ static int __init capidrv_init(void) | |||
| 2300 | 2309 | ||
| 2301 | static void __exit capidrv_exit(void) | 2310 | static void __exit capidrv_exit(void) |
| 2302 | { | 2311 | { |
| 2312 | unregister_capictr_notifier(&capictr_nb); | ||
| 2303 | capi20_release(&global.ap); | 2313 | capi20_release(&global.ap); |
| 2304 | 2314 | ||
| 2305 | proc_exit(); | 2315 | proc_exit(); |
diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index 9362a7a66aa1..e08914d33be1 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c | |||
| @@ -44,12 +44,10 @@ module_param(showcapimsgs, uint, 0); | |||
| 44 | 44 | ||
| 45 | /* ------------------------------------------------------------- */ | 45 | /* ------------------------------------------------------------- */ |
| 46 | 46 | ||
| 47 | struct capi_notifier { | 47 | struct capictr_event { |
| 48 | struct work_struct work; | 48 | struct work_struct work; |
| 49 | unsigned int cmd; | 49 | unsigned int type; |
| 50 | u32 controller; | 50 | u32 controller; |
| 51 | u16 applid; | ||
| 52 | u32 ncci; | ||
| 53 | }; | 51 | }; |
| 54 | 52 | ||
| 55 | /* ------------------------------------------------------------- */ | 53 | /* ------------------------------------------------------------- */ |
| @@ -71,6 +69,8 @@ struct capi_ctr *capi_controller[CAPI_MAXCONTR]; | |||
| 71 | 69 | ||
| 72 | static int ncontrollers; | 70 | static int ncontrollers; |
| 73 | 71 | ||
| 72 | static BLOCKING_NOTIFIER_HEAD(ctr_notifier_list); | ||
| 73 | |||
| 74 | /* -------- controller ref counting -------------------------------------- */ | 74 | /* -------- controller ref counting -------------------------------------- */ |
| 75 | 75 | ||
| 76 | static inline struct capi_ctr * | 76 | static inline struct capi_ctr * |
| @@ -165,8 +165,6 @@ static void release_appl(struct capi_ctr *ctr, u16 applid) | |||
| 165 | capi_ctr_put(ctr); | 165 | capi_ctr_put(ctr); |
| 166 | } | 166 | } |
| 167 | 167 | ||
| 168 | /* -------- KCI_CONTRUP --------------------------------------- */ | ||
| 169 | |||
| 170 | static void notify_up(u32 contr) | 168 | static void notify_up(u32 contr) |
| 171 | { | 169 | { |
| 172 | struct capi20_appl *ap; | 170 | struct capi20_appl *ap; |
| @@ -188,16 +186,11 @@ static void notify_up(u32 contr) | |||
| 188 | if (!ap || ap->release_in_progress) | 186 | if (!ap || ap->release_in_progress) |
| 189 | continue; | 187 | continue; |
| 190 | register_appl(ctr, applid, &ap->rparam); | 188 | register_appl(ctr, applid, &ap->rparam); |
| 191 | if (ap->callback && !ap->release_in_progress) | ||
| 192 | ap->callback(KCI_CONTRUP, contr, | ||
| 193 | &ctr->profile); | ||
| 194 | } | 189 | } |
| 195 | } else | 190 | } else |
| 196 | printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr); | 191 | printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr); |
| 197 | } | 192 | } |
| 198 | 193 | ||
| 199 | /* -------- KCI_CONTRDOWN ------------------------------------- */ | ||
| 200 | |||
| 201 | static void ctr_down(struct capi_ctr *ctr) | 194 | static void ctr_down(struct capi_ctr *ctr) |
| 202 | { | 195 | { |
| 203 | struct capi20_appl *ap; | 196 | struct capi20_appl *ap; |
| @@ -215,11 +208,8 @@ static void ctr_down(struct capi_ctr *ctr) | |||
| 215 | 208 | ||
| 216 | for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { | 209 | for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { |
| 217 | ap = get_capi_appl_by_nr(applid); | 210 | ap = get_capi_appl_by_nr(applid); |
| 218 | if (ap && !ap->release_in_progress) { | 211 | if (ap && !ap->release_in_progress) |
| 219 | if (ap->callback) | ||
| 220 | ap->callback(KCI_CONTRDOWN, ctr->cnr, NULL); | ||
| 221 | capi_ctr_put(ctr); | 212 | capi_ctr_put(ctr); |
| 222 | } | ||
| 223 | } | 213 | } |
| 224 | } | 214 | } |
| 225 | 215 | ||
| @@ -237,45 +227,63 @@ static void notify_down(u32 contr) | |||
| 237 | printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr); | 227 | printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr); |
| 238 | } | 228 | } |
| 239 | 229 | ||
| 240 | static void notify_handler(struct work_struct *work) | 230 | static int |
| 231 | notify_handler(struct notifier_block *nb, unsigned long val, void *v) | ||
| 241 | { | 232 | { |
| 242 | struct capi_notifier *np = | 233 | u32 contr = (long)v; |
| 243 | container_of(work, struct capi_notifier, work); | ||
| 244 | 234 | ||
| 245 | switch (np->cmd) { | 235 | switch (val) { |
| 246 | case KCI_CONTRUP: | 236 | case CAPICTR_UP: |
| 247 | notify_up(np->controller); | 237 | notify_up(contr); |
| 248 | break; | 238 | break; |
| 249 | case KCI_CONTRDOWN: | 239 | case CAPICTR_DOWN: |
| 250 | notify_down(np->controller); | 240 | notify_down(contr); |
| 251 | break; | 241 | break; |
| 252 | } | 242 | } |
| 243 | return NOTIFY_OK; | ||
| 244 | } | ||
| 245 | |||
| 246 | static void do_notify_work(struct work_struct *work) | ||
| 247 | { | ||
| 248 | struct capictr_event *event = | ||
| 249 | container_of(work, struct capictr_event, work); | ||
| 253 | 250 | ||
| 254 | kfree(np); | 251 | blocking_notifier_call_chain(&ctr_notifier_list, event->type, |
| 252 | (void *)(long)event->controller); | ||
| 253 | kfree(event); | ||
| 255 | } | 254 | } |
| 256 | 255 | ||
| 257 | /* | 256 | /* |
| 258 | * The notifier will result in adding/deleteing of devices. Devices can | 257 | * The notifier will result in adding/deleteing of devices. Devices can |
| 259 | * only removed in user process, not in bh. | 258 | * only removed in user process, not in bh. |
| 260 | */ | 259 | */ |
| 261 | static int notify_push(unsigned int cmd, u32 controller, u16 applid, u32 ncci) | 260 | static int notify_push(unsigned int event_type, u32 controller) |
| 262 | { | 261 | { |
| 263 | struct capi_notifier *np = kmalloc(sizeof(*np), GFP_ATOMIC); | 262 | struct capictr_event *event = kmalloc(sizeof(*event), GFP_ATOMIC); |
| 264 | 263 | ||
| 265 | if (!np) | 264 | if (!event) |
| 266 | return -ENOMEM; | 265 | return -ENOMEM; |
| 267 | 266 | ||
| 268 | INIT_WORK(&np->work, notify_handler); | 267 | INIT_WORK(&event->work, do_notify_work); |
| 269 | np->cmd = cmd; | 268 | event->type = event_type; |
| 270 | np->controller = controller; | 269 | event->controller = controller; |
| 271 | np->applid = applid; | ||
| 272 | np->ncci = ncci; | ||
| 273 | 270 | ||
| 274 | schedule_work(&np->work); | 271 | schedule_work(&event->work); |
| 275 | return 0; | 272 | return 0; |
| 276 | } | 273 | } |
| 277 | 274 | ||
| 278 | 275 | int register_capictr_notifier(struct notifier_block *nb) | |
| 276 | { | ||
| 277 | return blocking_notifier_chain_register(&ctr_notifier_list, nb); | ||
| 278 | } | ||
| 279 | EXPORT_SYMBOL_GPL(register_capictr_notifier); | ||
| 280 | |||
| 281 | int unregister_capictr_notifier(struct notifier_block *nb) | ||
| 282 | { | ||
| 283 | return blocking_notifier_chain_unregister(&ctr_notifier_list, nb); | ||
| 284 | } | ||
| 285 | EXPORT_SYMBOL_GPL(unregister_capictr_notifier); | ||
| 286 | |||
| 279 | /* -------- Receiver ------------------------------------------ */ | 287 | /* -------- Receiver ------------------------------------------ */ |
| 280 | 288 | ||
| 281 | static void recv_handler(struct work_struct *work) | 289 | static void recv_handler(struct work_struct *work) |
| @@ -401,7 +409,7 @@ void capi_ctr_ready(struct capi_ctr *ctr) | |||
| 401 | printk(KERN_NOTICE "kcapi: controller [%03d] \"%s\" ready.\n", | 409 | printk(KERN_NOTICE "kcapi: controller [%03d] \"%s\" ready.\n", |
| 402 | ctr->cnr, ctr->name); | 410 | ctr->cnr, ctr->name); |
| 403 | 411 | ||
| 404 | notify_push(KCI_CONTRUP, ctr->cnr, 0, 0); | 412 | notify_push(CAPICTR_UP, ctr->cnr); |
| 405 | } | 413 | } |
| 406 | 414 | ||
| 407 | EXPORT_SYMBOL(capi_ctr_ready); | 415 | EXPORT_SYMBOL(capi_ctr_ready); |
| @@ -418,7 +426,7 @@ void capi_ctr_down(struct capi_ctr *ctr) | |||
| 418 | { | 426 | { |
| 419 | printk(KERN_NOTICE "kcapi: controller [%03d] down.\n", ctr->cnr); | 427 | printk(KERN_NOTICE "kcapi: controller [%03d] down.\n", ctr->cnr); |
| 420 | 428 | ||
| 421 | notify_push(KCI_CONTRDOWN, ctr->cnr, 0, 0); | 429 | notify_push(CAPICTR_DOWN, ctr->cnr); |
| 422 | } | 430 | } |
| 423 | 431 | ||
| 424 | EXPORT_SYMBOL(capi_ctr_down); | 432 | EXPORT_SYMBOL(capi_ctr_down); |
| @@ -633,7 +641,6 @@ u16 capi20_register(struct capi20_appl *ap) | |||
| 633 | ap->nrecvdatapkt = 0; | 641 | ap->nrecvdatapkt = 0; |
| 634 | ap->nsentctlpkt = 0; | 642 | ap->nsentctlpkt = 0; |
| 635 | ap->nsentdatapkt = 0; | 643 | ap->nsentdatapkt = 0; |
| 636 | ap->callback = NULL; | ||
| 637 | mutex_init(&ap->recv_mtx); | 644 | mutex_init(&ap->recv_mtx); |
| 638 | skb_queue_head_init(&ap->recv_queue); | 645 | skb_queue_head_init(&ap->recv_queue); |
| 639 | INIT_WORK(&ap->recv_work, recv_handler); | 646 | INIT_WORK(&ap->recv_work, recv_handler); |
| @@ -1137,30 +1144,6 @@ int capi20_manufacturer(unsigned int cmd, void __user *data) | |||
| 1137 | 1144 | ||
| 1138 | EXPORT_SYMBOL(capi20_manufacturer); | 1145 | EXPORT_SYMBOL(capi20_manufacturer); |
| 1139 | 1146 | ||
| 1140 | /* temporary hack */ | ||
| 1141 | |||
| 1142 | /** | ||
| 1143 | * capi20_set_callback() - set CAPI application notification callback function | ||
| 1144 | * @ap: CAPI application descriptor structure. | ||
| 1145 | * @callback: callback function (NULL to remove). | ||
| 1146 | * | ||
| 1147 | * If not NULL, the callback function will be called to notify the | ||
| 1148 | * application of the addition or removal of a controller. | ||
| 1149 | * The first argument (cmd) will tell whether the controller was added | ||
| 1150 | * (KCI_CONTRUP) or removed (KCI_CONTRDOWN). | ||
| 1151 | * The second argument (contr) will be the controller number. | ||
| 1152 | * For cmd==KCI_CONTRUP the third argument (data) will be a pointer to the | ||
| 1153 | * new controller's capability profile structure. | ||
| 1154 | */ | ||
| 1155 | |||
| 1156 | void capi20_set_callback(struct capi20_appl *ap, | ||
| 1157 | void (*callback) (unsigned int cmd, __u32 contr, void *data)) | ||
| 1158 | { | ||
| 1159 | ap->callback = callback; | ||
| 1160 | } | ||
| 1161 | |||
| 1162 | EXPORT_SYMBOL(capi20_set_callback); | ||
| 1163 | |||
| 1164 | /* ------------------------------------------------------------- */ | 1147 | /* ------------------------------------------------------------- */ |
| 1165 | /* -------- Init & Cleanup ------------------------------------- */ | 1148 | /* -------- Init & Cleanup ------------------------------------- */ |
| 1166 | /* ------------------------------------------------------------- */ | 1149 | /* ------------------------------------------------------------- */ |
| @@ -1169,10 +1152,17 @@ EXPORT_SYMBOL(capi20_set_callback); | |||
| 1169 | * init / exit functions | 1152 | * init / exit functions |
| 1170 | */ | 1153 | */ |
| 1171 | 1154 | ||
| 1155 | static struct notifier_block capictr_nb = { | ||
| 1156 | .notifier_call = notify_handler, | ||
| 1157 | .priority = INT_MAX, | ||
| 1158 | }; | ||
| 1159 | |||
| 1172 | static int __init kcapi_init(void) | 1160 | static int __init kcapi_init(void) |
| 1173 | { | 1161 | { |
| 1174 | int err; | 1162 | int err; |
| 1175 | 1163 | ||
| 1164 | register_capictr_notifier(&capictr_nb); | ||
| 1165 | |||
| 1176 | err = cdebug_init(); | 1166 | err = cdebug_init(); |
| 1177 | if (!err) | 1167 | if (!err) |
| 1178 | kcapi_proc_init(); | 1168 | kcapi_proc_init(); |
diff --git a/include/linux/kernelcapi.h b/include/linux/kernelcapi.h index a53e932f80fb..9c2683929fd3 100644 --- a/include/linux/kernelcapi.h +++ b/include/linux/kernelcapi.h | |||
| @@ -48,9 +48,7 @@ typedef struct kcapi_carddef { | |||
| 48 | #include <linux/list.h> | 48 | #include <linux/list.h> |
| 49 | #include <linux/skbuff.h> | 49 | #include <linux/skbuff.h> |
| 50 | #include <linux/workqueue.h> | 50 | #include <linux/workqueue.h> |
| 51 | 51 | #include <linux/notifier.h> | |
| 52 | #define KCI_CONTRUP 0 /* arg: struct capi_profile */ | ||
| 53 | #define KCI_CONTRDOWN 1 /* arg: NULL */ | ||
| 54 | 52 | ||
| 55 | struct capi20_appl { | 53 | struct capi20_appl { |
| 56 | u16 applid; | 54 | u16 applid; |
| @@ -67,11 +65,6 @@ struct capi20_appl { | |||
| 67 | struct sk_buff_head recv_queue; | 65 | struct sk_buff_head recv_queue; |
| 68 | struct work_struct recv_work; | 66 | struct work_struct recv_work; |
| 69 | int release_in_progress; | 67 | int release_in_progress; |
| 70 | |||
| 71 | /* ugly hack to allow for notification of added/removed | ||
| 72 | * controllers. The Right Way (tm) is known. XXX | ||
| 73 | */ | ||
| 74 | void (*callback) (unsigned int cmd, __u32 contr, void *data); | ||
| 75 | }; | 68 | }; |
| 76 | 69 | ||
| 77 | u16 capi20_isinstalled(void); | 70 | u16 capi20_isinstalled(void); |
| @@ -84,11 +77,11 @@ u16 capi20_get_serial(u32 contr, u8 serial[CAPI_SERIAL_LEN]); | |||
| 84 | u16 capi20_get_profile(u32 contr, struct capi_profile *profp); | 77 | u16 capi20_get_profile(u32 contr, struct capi_profile *profp); |
| 85 | int capi20_manufacturer(unsigned int cmd, void __user *data); | 78 | int capi20_manufacturer(unsigned int cmd, void __user *data); |
| 86 | 79 | ||
| 87 | /* temporary hack XXX */ | 80 | #define CAPICTR_UP 0 |
| 88 | void capi20_set_callback(struct capi20_appl *ap, | 81 | #define CAPICTR_DOWN 1 |
| 89 | void (*callback) (unsigned int cmd, __u32 contr, void *data)); | ||
| 90 | |||
| 91 | 82 | ||
| 83 | int register_capictr_notifier(struct notifier_block *nb); | ||
| 84 | int unregister_capictr_notifier(struct notifier_block *nb); | ||
| 92 | 85 | ||
| 93 | #define CAPI_NOERROR 0x0000 | 86 | #define CAPI_NOERROR 0x0000 |
| 94 | 87 | ||
