aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn/capi
diff options
context:
space:
mode:
authorJan Kiszka <jan.kiszka@web.de>2010-02-08 05:12:13 -0500
committerDavid S. Miller <davem@davemloft.net>2010-02-16 19:01:21 -0500
commitef69bb2ec6036945da1d3d3f07b75253f484f693 (patch)
treead309906a7b20b0b13b573abfb3be9d524f08086 /drivers/isdn/capi
parent3efecf7a49cde47e5f2deb1d5504951ff4bede53 (diff)
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')
-rw-r--r--drivers/isdn/capi/capidrv.c22
-rw-r--r--drivers/isdn/capi/kcapi.c112
2 files changed, 67 insertions, 67 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
2213static void lower_callback(unsigned int cmd, u32 contr, void *data) 2213static int
2214lower_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
2270static struct notifier_block capictr_nb = {
2271 .notifier_call = lower_callback,
2272};
2273
2265static int __init capidrv_init(void) 2274static 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
2301static void __exit capidrv_exit(void) 2310static 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
47struct capi_notifier { 47struct 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
72static int ncontrollers; 70static int ncontrollers;
73 71
72static BLOCKING_NOTIFIER_HEAD(ctr_notifier_list);
73
74/* -------- controller ref counting -------------------------------------- */ 74/* -------- controller ref counting -------------------------------------- */
75 75
76static inline struct capi_ctr * 76static 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
170static void notify_up(u32 contr) 168static 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
201static void ctr_down(struct capi_ctr *ctr) 194static 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
240static void notify_handler(struct work_struct *work) 230static int
231notify_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
246static 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 */
261static int notify_push(unsigned int cmd, u32 controller, u16 applid, u32 ncci) 260static 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 275int register_capictr_notifier(struct notifier_block *nb)
276{
277 return blocking_notifier_chain_register(&ctr_notifier_list, nb);
278}
279EXPORT_SYMBOL_GPL(register_capictr_notifier);
280
281int unregister_capictr_notifier(struct notifier_block *nb)
282{
283 return blocking_notifier_chain_unregister(&ctr_notifier_list, nb);
284}
285EXPORT_SYMBOL_GPL(unregister_capictr_notifier);
286
279/* -------- Receiver ------------------------------------------ */ 287/* -------- Receiver ------------------------------------------ */
280 288
281static void recv_handler(struct work_struct *work) 289static 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
407EXPORT_SYMBOL(capi_ctr_ready); 415EXPORT_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
424EXPORT_SYMBOL(capi_ctr_down); 432EXPORT_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
1138EXPORT_SYMBOL(capi20_manufacturer); 1145EXPORT_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
1156void capi20_set_callback(struct capi20_appl *ap,
1157 void (*callback) (unsigned int cmd, __u32 contr, void *data))
1158{
1159 ap->callback = callback;
1160}
1161
1162EXPORT_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
1155static struct notifier_block capictr_nb = {
1156 .notifier_call = notify_handler,
1157 .priority = INT_MAX,
1158};
1159
1172static int __init kcapi_init(void) 1160static 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();