patch-2.3.99-pre3 linux/drivers/isdn/avmb1/kcapi.c
Next file: linux/drivers/isdn/divert/divert_procfs.c
Previous file: linux/drivers/isdn/avmb1/capiutil.h
Back to the patch index
Back to the overall index
- Lines: 504
- Date:
Thu Mar 23 08:38:57 2000
- Orig file:
v2.3.99-pre2/linux/drivers/isdn/avmb1/kcapi.c
- Orig date:
Wed Feb 16 17:03:52 2000
diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/avmb1/kcapi.c linux/drivers/isdn/avmb1/kcapi.c
@@ -1,11 +1,22 @@
/*
- * $Id: kcapi.c,v 1.12 2000/01/28 16:45:39 calle Exp $
+ * $Id: kcapi.c,v 1.13 2000/03/03 15:50:42 calle Exp $
*
* Kernel CAPI 2.0 Module
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: kcapi.c,v $
+ * Revision 1.13 2000/03/03 15:50:42 calle
+ * - kernel CAPI:
+ * - Changed parameter "param" in capi_signal from __u32 to void *.
+ * - rewrote notifier handling in kcapi.c
+ * - new notifier NCCI_UP and NCCI_DOWN
+ * - User CAPI:
+ * - /dev/capi20 is now a cloning device.
+ * - middleware extentions prepared.
+ * - capidrv.c
+ * - locking of list operations and module count updates.
+ *
* Revision 1.12 2000/01/28 16:45:39 calle
* new manufacturer command KCAPI_CMD_ADDCARD (generic addcard),
* will search named driver and call the add_card function if one exist.
@@ -78,6 +89,7 @@
#include <linux/tqueue.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
+#include <linux/locks.h>
#include <asm/uaccess.h>
#include "capicmd.h"
#include "capiutil.h"
@@ -86,7 +98,7 @@
#include <linux/b1lli.h>
#endif
-static char *revision = "$Revision: 1.12 $";
+static char *revision = "$Revision: 1.13 $";
/* ------------------------------------------------------------- */
@@ -125,8 +137,8 @@
__u16 applid;
capi_register_params rparam;
int releasing;
- __u32 param;
- void (*signal) (__u16 applid, __u32 param);
+ void *param;
+ void (*signal) (__u16 applid, void *param);
struct sk_buff_head recv_queue;
int nncci;
struct capi_ncci *nccilist;
@@ -137,6 +149,14 @@
unsigned long nsentdatapkt;
};
+struct capi_notifier {
+ struct capi_notifier *next;
+ unsigned int cmd;
+ __u32 controller;
+ __u16 applid;
+ __u32 ncci;
+};
+
/* ------------------------------------------------------------- */
static struct capi_version driver_version = {2, 0, 1, 1<<4};
@@ -160,9 +180,9 @@
static int ncards = 0;
static struct sk_buff_head recv_queue;
static struct capi_interface_user *capi_users = 0;
+static spinlock_t capi_users_lock = SPIN_LOCK_UNLOCKED;
static struct capi_driver *drivers;
-static long notify_up_set = 0;
-static long notify_down_set = 0;
+static spinlock_t drivers_lock = SPIN_LOCK_UNLOCKED;
static struct tq_struct tq_state_notify;
static struct tq_struct tq_recv_notify;
@@ -304,6 +324,7 @@
int len = 0;
off_t begin = 0;
+ spin_lock(&drivers_lock);
for (driver = drivers; driver; driver = driver->next) {
len += sprintf(page+len, "%-32s %d %s\n",
driver->name,
@@ -317,6 +338,7 @@
}
}
endloop:
+ spin_unlock(&drivers_lock);
if (!driver)
*eof = 1;
if (off >= len+begin)
@@ -336,6 +358,7 @@
int len = 0;
off_t begin = 0;
+ spin_lock(&capi_users_lock);
for (cp = capi_users; cp ; cp = cp->next) {
len += sprintf(page+len, "%s\n", cp->name);
if (len+begin > off+count)
@@ -346,6 +369,7 @@
}
}
endloop:
+ spin_unlock(&capi_users_lock);
if (cp == 0)
*eof = 1;
if (off >= len+begin)
@@ -510,6 +534,161 @@
}
}
+/* -------- Notifier handling --------------------------------- */
+
+static struct capi_notifier_list{
+ struct capi_notifier *head;
+ struct capi_notifier *tail;
+} notifier_list;
+
+static inline void notify_enqueue(struct capi_notifier *np)
+{
+ struct capi_notifier_list *q = ¬ifier_list;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (q->tail) {
+ q->tail->next = np;
+ q->tail = np;
+ } else {
+ q->head = q->tail = np;
+ }
+ restore_flags(flags);
+}
+
+static inline struct capi_notifier *notify_dequeue(void)
+{
+ struct capi_notifier_list *q = ¬ifier_list;
+ struct capi_notifier *np = 0;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (q->head) {
+ np = q->head;
+ if ((q->head = np->next) == 0)
+ q->tail = 0;
+ np->next = 0;
+ }
+ restore_flags(flags);
+ return np;
+}
+
+static int notify_push(unsigned int cmd, __u32 controller,
+ __u16 applid, __u32 ncci)
+{
+ struct capi_notifier *np;
+
+ np = (struct capi_notifier *)kmalloc(sizeof(struct capi_notifier), GFP_ATOMIC);
+ if (!np)
+ return -1;
+ memset(np, 0, sizeof(struct capi_notifier));
+ np->cmd = cmd;
+ np->controller = controller;
+ np->applid = applid;
+ np->ncci = ncci;
+ notify_enqueue(np);
+ MOD_INC_USE_COUNT;
+ queue_task(&tq_state_notify, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ return 0;
+}
+
+/* -------- KCI_CONTRUP --------------------------------------- */
+
+static void notify_up(__u32 contr)
+{
+ struct capi_interface_user *p;
+
+ printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr);
+ spin_lock(&capi_users_lock);
+ for (p = capi_users; p; p = p->next) {
+ if (!p->callback) continue;
+ (*p->callback) (KCI_CONTRUP, contr, &CARD(contr)->profile);
+ }
+ spin_unlock(&capi_users_lock);
+}
+
+/* -------- KCI_CONTRDOWN ------------------------------------- */
+
+static void notify_down(__u32 contr)
+{
+ struct capi_interface_user *p;
+ printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr);
+ spin_lock(&capi_users_lock);
+ for (p = capi_users; p; p = p->next) {
+ if (!p->callback) continue;
+ (*p->callback) (KCI_CONTRDOWN, contr, 0);
+ }
+ spin_unlock(&capi_users_lock);
+}
+
+/* -------- KCI_NCCIUP ---------------------------------------- */
+
+static void notify_ncciup(__u32 contr, __u16 applid, __u32 ncci)
+{
+ struct capi_interface_user *p;
+ struct capi_ncciinfo n;
+ n.applid = applid;
+ n.ncci = ncci;
+ /*printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr);*/
+ spin_lock(&capi_users_lock);
+ for (p = capi_users; p; p = p->next) {
+ if (!p->callback) continue;
+ (*p->callback) (KCI_NCCIUP, contr, &n);
+ }
+ spin_unlock(&capi_users_lock);
+};
+
+/* -------- KCI_NCCIDOWN -------------------------------------- */
+
+static void notify_nccidown(__u32 contr, __u16 applid, __u32 ncci)
+{
+ struct capi_interface_user *p;
+ struct capi_ncciinfo n;
+ n.applid = applid;
+ n.ncci = ncci;
+ /*printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr);*/
+ spin_lock(&capi_users_lock);
+ for (p = capi_users; p; p = p->next) {
+ if (!p->callback) continue;
+ (*p->callback) (KCI_NCCIDOWN, contr, &n);
+ }
+ spin_unlock(&capi_users_lock);
+};
+
+/* ------------------------------------------------------------ */
+
+static void inline notify_doit(struct capi_notifier *np)
+{
+ switch (np->cmd) {
+ case KCI_CONTRUP:
+ notify_up(np->controller);
+ break;
+ case KCI_CONTRDOWN:
+ notify_down(np->controller);
+ break;
+ case KCI_NCCIUP:
+ notify_ncciup(np->controller, np->applid, np->ncci);
+ break;
+ case KCI_NCCIDOWN:
+ notify_nccidown(np->controller, np->applid, np->ncci);
+ break;
+ }
+}
+
+static void notify_handler(void *dummy)
+{
+ struct capi_notifier *np;
+
+ while ((np = notify_dequeue()) != 0) {
+ notify_doit(np);
+ kfree(np);
+ MOD_DEC_USE_COUNT;
+ }
+}
+
/* -------- NCCI Handling ------------------------------------- */
static inline void mq_init(struct capi_ncci * np)
@@ -617,6 +796,7 @@
APPL(appl)->nncci++;
printk(KERN_INFO "kcapi: appl %d ncci 0x%x up\n", appl, ncci);
+ notify_push(KCI_NCCIUP, CARDNR(card), appl, ncci);
}
static void controllercb_free_ncci(struct capi_ctr * card,
@@ -634,6 +814,7 @@
kfree(np);
APPL(appl)->nncci--;
printk(KERN_INFO "kcapi: appl %d ncci 0x%x down\n", appl, ncci);
+ notify_push(KCI_NCCIDOWN, CARDNR(card), appl, ncci);
return;
}
}
@@ -734,42 +915,6 @@
kfree_skb(skb);
}
-/* -------- Notifier ------------------------------------------ */
-
-static void notify_up(__u32 contr)
-{
- struct capi_interface_user *p;
-
- printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr);
- for (p = capi_users; p; p = p->next) {
- if (!p->callback) continue;
- (*p->callback) (KCI_CONTRUP, contr, &CARD(contr)->profile);
- }
-}
-
-static void notify_down(__u32 contr)
-{
- struct capi_interface_user *p;
- printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr);
- for (p = capi_users; p; p = p->next) {
- if (!p->callback) continue;
- (*p->callback) (KCI_CONTRDOWN, contr, 0);
- }
-}
-
-static void notify_handler(void *dummy)
-{
- __u32 contr;
-
- for (contr=1; VALID_CARD(contr); contr++)
- if (test_and_clear_bit(contr, ¬ify_up_set))
- notify_up(contr);
- for (contr=1; VALID_CARD(contr); contr++)
- if (test_and_clear_bit(contr, ¬ify_down_set))
- notify_down(contr);
-}
-
-
static void controllercb_ready(struct capi_ctr * card)
{
__u16 appl;
@@ -782,11 +927,10 @@
card->driver->register_appl(card, appl, &APPL(appl)->rparam);
}
- set_bit(CARDNR(card), ¬ify_up_set);
- queue_task(&tq_state_notify, &tq_scheduler);
-
printk(KERN_NOTICE "kcapi: card %d \"%s\" ready.\n",
CARDNR(card), card->name);
+
+ notify_push(KCI_CONTRUP, CARDNR(card), 0, 0);
}
static void controllercb_reseted(struct capi_ctr * card)
@@ -812,6 +956,7 @@
struct capi_ncci *np = *pp;
*pp = np->next;
printk(KERN_INFO "kcapi: appl %d ncci 0x%x forced down!\n", appl, np->ncci);
+ notify_push(KCI_NCCIDOWN, CARDNR(card), appl, np->ncci);
kfree(np);
nextpp = pp;
} else {
@@ -819,9 +964,10 @@
}
}
}
- set_bit(CARDNR(card), ¬ify_down_set);
- queue_task(&tq_state_notify, &tq_scheduler);
+
printk(KERN_NOTICE "kcapi: card %d down.\n", CARDNR(card));
+
+ notify_push(KCI_CONTRDOWN, CARDNR(card), 0, 0);
}
static void controllercb_suspend_output(struct capi_ctr *card)
@@ -952,9 +1098,12 @@
{
struct capi_driver **pp;
+ MOD_INC_USE_COUNT;
+ spin_lock(&drivers_lock);
for (pp = &drivers; *pp; pp = &(*pp)->next) ;
driver->next = 0;
*pp = driver;
+ spin_unlock(&drivers_lock);
printk(KERN_NOTICE "kcapi: driver %s attached\n", driver->name);
sprintf(driver->procfn, "capi/drivers/%s", driver->name);
driver->procent = create_proc_entry(driver->procfn, 0, 0);
@@ -974,6 +1123,7 @@
void detach_capi_driver(struct capi_driver *driver)
{
struct capi_driver **pp;
+ spin_lock(&drivers_lock);
for (pp = &drivers; *pp && *pp != driver; pp = &(*pp)->next) ;
if (*pp) {
*pp = (*pp)->next;
@@ -981,10 +1131,12 @@
} else {
printk(KERN_ERR "kcapi: driver %s double detach ?\n", driver->name);
}
+ spin_unlock(&drivers_lock);
if (driver->procent) {
remove_proc_entry(driver->procfn, 0);
driver->procent = 0;
}
+ MOD_DEC_USE_COUNT;
}
/* ------------------------------------------------------------- */
@@ -1041,6 +1193,7 @@
if (!VALID_APPLID(applid) || APPL(applid)->releasing)
return CAPI_ILLAPPNR;
+ APPL(applid)->releasing++;
while ((skb = skb_dequeue(&APPL(applid)->recv_queue)) != 0)
kfree_skb(skb);
for (i = 0; i < CAPI_MAXCONTR; i++) {
@@ -1049,6 +1202,7 @@
APPL(applid)->releasing++;
cards[i].driver->release_appl(&cards[i], applid);
}
+ APPL(applid)->releasing--;
if (APPL(applid)->releasing <= 0) {
APPL(applid)->signal = 0;
APPL_MARK_FREE(applid);
@@ -1128,8 +1282,8 @@
}
static __u16 capi_set_signal(__u16 applid,
- void (*signal) (__u16 applid, __u32 param),
- __u32 param)
+ void (*signal) (__u16 applid, void *param),
+ void *param)
{
if (!VALID_APPLID(applid))
return CAPI_ILLAPPNR;
@@ -1194,10 +1348,12 @@
static struct capi_driver *find_driver(char *name)
{
struct capi_driver *dp;
+ spin_lock(&drivers_lock);
for (dp = drivers; dp; dp = dp->next)
if (strcmp(dp->name, name) == 0)
- return dp;
- return 0;
+ break;
+ spin_unlock(&drivers_lock);
+ return dp;
}
#ifdef CONFIG_AVMB1_COMPAT
@@ -1272,6 +1428,10 @@
card = CARD(ldef.contr);
if (card->cardstate == CARD_FREE)
return -ESRCH;
+ if (card->driver->load_firmware == 0) {
+ printk(KERN_DEBUG "kcapi: load: driver \%s\" has no load function\n", card->driver->name);
+ return -ESRCH;
+ }
if (ldef.t4file.len <= 0) {
printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len);
@@ -1490,16 +1650,20 @@
{
struct capi_interface_user *p;
+ MOD_INC_USE_COUNT;
+ spin_lock(&capi_users_lock);
for (p = capi_users; p; p = p->next) {
if (p == userp) {
+ spin_unlock(&capi_users_lock);
printk(KERN_ERR "kcapi: double attach from %s\n",
userp->name);
+ MOD_DEC_USE_COUNT;
return 0;
}
}
userp->next = capi_users;
capi_users = userp;
- MOD_INC_USE_COUNT;
+ spin_unlock(&capi_users_lock);
printk(KERN_NOTICE "kcapi: %s attached\n", userp->name);
return &avmb1_interface;
@@ -1509,15 +1673,18 @@
{
struct capi_interface_user **pp;
+ spin_lock(&capi_users_lock);
for (pp = &capi_users; *pp; pp = &(*pp)->next) {
if (*pp == userp) {
*pp = userp->next;
+ spin_unlock(&capi_users_lock);
userp->next = 0;
- MOD_DEC_USE_COUNT;
printk(KERN_NOTICE "kcapi: %s detached\n", userp->name);
+ MOD_DEC_USE_COUNT;
return 0;
}
}
+ spin_unlock(&capi_users_lock);
printk(KERN_ERR "kcapi: double detach from %s\n", userp->name);
return -1;
}
@@ -1623,7 +1790,6 @@
strcpy(rev, "1.0");
}
- schedule(); /* execute queued tasks .... */
proc_capi_exit();
printk(KERN_NOTICE "CAPI-driver Rev%s: unloaded\n", rev);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)