diff options
Diffstat (limited to 'drivers/isdn/capi')
| -rw-r--r-- | drivers/isdn/capi/Kconfig | 50 | ||||
| -rw-r--r-- | drivers/isdn/capi/Makefile | 1 | ||||
| -rw-r--r-- | drivers/isdn/capi/capi.c | 1515 | ||||
| -rw-r--r-- | drivers/isdn/capi/capidrv.c | 1317 | ||||
| -rw-r--r-- | drivers/isdn/capi/capidrv.h | 42 | ||||
| -rw-r--r-- | drivers/isdn/capi/capifs.c | 221 | ||||
| -rw-r--r-- | drivers/isdn/capi/capifs.h | 11 | ||||
| -rw-r--r-- | drivers/isdn/capi/capilib.c | 17 | ||||
| -rw-r--r-- | drivers/isdn/capi/capiutil.c | 722 | ||||
| -rw-r--r-- | drivers/isdn/capi/kcapi.c | 1087 | ||||
| -rw-r--r-- | drivers/isdn/capi/kcapi.h | 24 | ||||
| -rw-r--r-- | drivers/isdn/capi/kcapi_proc.c | 64 |
12 files changed, 2500 insertions, 2571 deletions
diff --git a/drivers/isdn/capi/Kconfig b/drivers/isdn/capi/Kconfig index e1afd60924f..7641b3096ea 100644 --- a/drivers/isdn/capi/Kconfig +++ b/drivers/isdn/capi/Kconfig @@ -1,14 +1,3 @@ -# -# Config.in for the CAPI subsystem -# -config ISDN_DRV_AVMB1_VERBOSE_REASON - bool "Verbose reason code reporting" - default y - help - If you say Y here, the CAPI drivers will give verbose reasons for - disconnecting. This will increase the size of the kernel by 7 KB. If - unsure, say Y. - config CAPI_TRACE bool "CAPI trace support" default y @@ -19,37 +8,23 @@ config CAPI_TRACE This will increase the size of the kernelcapi module by 20 KB. If unsure, say Y. -config ISDN_CAPI_MIDDLEWARE - bool "CAPI2.0 Middleware support (EXPERIMENTAL)" - depends on EXPERIMENTAL - help - This option will enhance the capabilities of the /dev/capi20 - interface. It will provide a means of moving a data connection, - established via the usual /dev/capi20 interface to a special tty - device. If you want to use pppd with pppdcapiplugin to dial up to - your ISP, say Y here. - config ISDN_CAPI_CAPI20 - tristate "CAPI2.0 /dev/capi support" + tristate "CAPI2.0 /dev/capi20 support" help This option will provide the CAPI 2.0 interface to userspace applications via /dev/capi20. Applications should use the standardized libcapi20 to access this functionality. You should say Y/M here. -config ISDN_CAPI_CAPIFS_BOOL - bool "CAPI2.0 filesystem support" - depends on ISDN_CAPI_MIDDLEWARE && ISDN_CAPI_CAPI20 - -config ISDN_CAPI_CAPIFS - tristate - depends on ISDN_CAPI_CAPIFS_BOOL - default ISDN_CAPI_CAPI20 +config ISDN_CAPI_MIDDLEWARE + bool "CAPI2.0 Middleware support" + depends on ISDN_CAPI_CAPI20 && TTY help - This option provides a special file system, similar to /dev/pts with - device nodes for the special ttys established by using the - middleware extension above. If you want to use pppd with - pppdcapiplugin to dial up to your ISP, say Y here. + This option will enhance the capabilities of the /dev/capi20 + interface. It will provide a means of moving a data connection, + established via the usual /dev/capi20 interface to a special tty + device. If you want to use pppd with pppdcapiplugin to dial up to + your ISP, say Y here. config ISDN_CAPI_CAPIDRV tristate "CAPI2.0 capidrv interface support" @@ -60,3 +35,10 @@ config ISDN_CAPI_CAPIDRV supported by a CAPI driver, but still want to use old features like ippp interfaces or ttyI emulation, say Y/M here. +config ISDN_CAPI_CAPIDRV_VERBOSE + bool "Verbose reason code reporting" + depends on ISDN_CAPI_CAPIDRV + help + If you say Y here, the capidrv interface will give verbose reasons + for disconnecting. This will increase the size of the kernel by 7 KB. + If unsure, say N. diff --git a/drivers/isdn/capi/Makefile b/drivers/isdn/capi/Makefile index 57123e3e497..4d5b4b71db1 100644 --- a/drivers/isdn/capi/Makefile +++ b/drivers/isdn/capi/Makefile @@ -7,7 +7,6 @@ obj-$(CONFIG_ISDN_CAPI) += kernelcapi.o obj-$(CONFIG_ISDN_CAPI_CAPI20) += capi.o obj-$(CONFIG_ISDN_CAPI_CAPIDRV) += capidrv.o -obj-$(CONFIG_ISDN_CAPI_CAPIFS) += capifs.o # Multipart objects. diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 1b5bf87c4cf..f9a87ed2392 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -20,19 +20,15 @@ #include <linux/signal.h> #include <linux/mutex.h> #include <linux/mm.h> -#include <linux/smp_lock.h> #include <linux/timer.h> #include <linux/wait.h> -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE #include <linux/tty.h> -#ifdef CONFIG_PPP #include <linux/netdevice.h> #include <linux/ppp_defs.h> -#include <linux/if_ppp.h> -#endif /* CONFIG_PPP */ -#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ +#include <linux/ppp-ioctl.h> #include <linux/skbuff.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <linux/poll.h> #include <linux/capi.h> #include <linux/kernelcapi.h> @@ -41,35 +37,25 @@ #include <linux/moduleparam.h> #include <linux/isdn/capiutil.h> #include <linux/isdn/capicmd.h> -#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE) -#include "capifs.h" -#endif - -static char *revision = "$Revision: 1.1.2.7 $"; MODULE_DESCRIPTION("CAPI4Linux: Userspace /dev/capi20 interface"); MODULE_AUTHOR("Carsten Paeth"); MODULE_LICENSE("GPL"); -#undef _DEBUG_REFCOUNT /* alloc/free and open/close debug */ -#undef _DEBUG_TTYFUNCS /* call to tty_driver */ -#undef _DEBUG_DATAFLOW /* data flow */ - /* -------- driver information -------------------------------------- */ +static DEFINE_MUTEX(capi_mutex); static struct class *capi_class; - static int capi_major = 68; /* allocated */ + +module_param_named(major, capi_major, uint, 0); + #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE -#define CAPINC_NR_PORTS 32 +#define CAPINC_NR_PORTS 32 #define CAPINC_MAX_PORTS 256 -static int capi_ttymajor = 191; + static int capi_ttyminors = CAPINC_NR_PORTS; -#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ -module_param_named(major, capi_major, uint, 0); -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE -module_param_named(ttymajor, capi_ttymajor, uint, 0); module_param_named(ttyminors, capi_ttyminors, uint, 0); #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ @@ -83,53 +69,40 @@ module_param_named(ttyminors, capi_ttyminors, uint, 0); struct capidev; struct capincci; -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE struct capiminor; -struct datahandle_queue { +struct ackqueue_entry { struct list_head list; u16 datahandle; }; struct capiminor { - struct list_head list; - struct capincci *nccip; unsigned int minor; - struct capi20_appl *ap; - u32 ncci; - u16 datahandle; - u16 msgid; + struct capi20_appl *ap; + u32 ncci; + atomic_t datahandle; + atomic_t msgid; - struct tty_struct *tty; + struct tty_port port; int ttyinstop; int ttyoutstop; - struct sk_buff *ttyskb; - atomic_t ttyopencount; - struct sk_buff_head inqueue; - int inbytes; - struct sk_buff_head outqueue; - int outbytes; + struct sk_buff_head inqueue; + + struct sk_buff_head outqueue; + int outbytes; + struct sk_buff *outskb; + spinlock_t outlock; /* transmit path */ struct list_head ackqueue; int nack; spinlock_t ackqlock; }; -#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ - -/* FIXME: The following lock is a sledgehammer-workaround to a - * locking issue with the capiminor (and maybe other) data structure(s). - * Access to this data is done in a racy way and crashes the machine with - * a FritzCard DSL driver; sooner or later. This is a workaround - * which trades scalability vs stability, so it doesn't crash the kernel anymore. - * The correct (and scalable) fix for the issue seems to require - * an API change to the drivers... . */ -static DEFINE_SPINLOCK(workaround_lock); struct capincci { - struct capincci *next; + struct list_head list; u32 ncci; struct capidev *cdev; #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE @@ -146,28 +119,28 @@ struct capidev { struct sk_buff_head recvqueue; wait_queue_head_t recvwait; - struct capincci *nccis; + struct list_head nccis; - struct mutex ncci_list_mtx; + struct mutex lock; }; /* -------- global variables ---------------------------------------- */ -static DEFINE_RWLOCK(capidev_list_lock); +static DEFINE_MUTEX(capidev_list_lock); static LIST_HEAD(capidev_list); #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE -static DEFINE_RWLOCK(capiminor_list_lock); -static LIST_HEAD(capiminor_list); -#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE +static DEFINE_SPINLOCK(capiminors_lock); +static struct capiminor **capiminors; + +static struct tty_driver *capinc_tty_driver; + /* -------- datahandles --------------------------------------------- */ -static int capincci_add_ack(struct capiminor *mp, u16 datahandle) +static int capiminor_add_ack(struct capiminor *mp, u16 datahandle) { - struct datahandle_queue *n; - unsigned long flags; + struct ackqueue_entry *n; n = kmalloc(sizeof(*n), GFP_ATOMIC); if (unlikely(!n)) { @@ -176,271 +149,249 @@ static int capincci_add_ack(struct capiminor *mp, u16 datahandle) } n->datahandle = datahandle; INIT_LIST_HEAD(&n->list); - spin_lock_irqsave(&mp->ackqlock, flags); + spin_lock_bh(&mp->ackqlock); list_add_tail(&n->list, &mp->ackqueue); mp->nack++; - spin_unlock_irqrestore(&mp->ackqlock, flags); + spin_unlock_bh(&mp->ackqlock); return 0; } static int capiminor_del_ack(struct capiminor *mp, u16 datahandle) { - struct datahandle_queue *p, *tmp; - unsigned long flags; + struct ackqueue_entry *p, *tmp; - spin_lock_irqsave(&mp->ackqlock, flags); + spin_lock_bh(&mp->ackqlock); list_for_each_entry_safe(p, tmp, &mp->ackqueue, list) { - if (p->datahandle == datahandle) { + if (p->datahandle == datahandle) { list_del(&p->list); - kfree(p); mp->nack--; - spin_unlock_irqrestore(&mp->ackqlock, flags); + spin_unlock_bh(&mp->ackqlock); + kfree(p); return 0; } } - spin_unlock_irqrestore(&mp->ackqlock, flags); + spin_unlock_bh(&mp->ackqlock); return -1; } static void capiminor_del_all_ack(struct capiminor *mp) { - struct datahandle_queue *p, *tmp; - unsigned long flags; + struct ackqueue_entry *p, *tmp; - spin_lock_irqsave(&mp->ackqlock, flags); list_for_each_entry_safe(p, tmp, &mp->ackqueue, list) { list_del(&p->list); kfree(p); mp->nack--; } - spin_unlock_irqrestore(&mp->ackqlock, flags); } /* -------- struct capiminor ---------------------------------------- */ +static void capiminor_destroy(struct tty_port *port) +{ + struct capiminor *mp = container_of(port, struct capiminor, port); + + kfree_skb(mp->outskb); + skb_queue_purge(&mp->inqueue); + skb_queue_purge(&mp->outqueue); + capiminor_del_all_ack(mp); + kfree(mp); +} + +static const struct tty_port_operations capiminor_port_ops = { + .destruct = capiminor_destroy, +}; + static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci) { - struct capiminor *mp, *p; - unsigned int minor = 0; - unsigned long flags; + struct capiminor *mp; + struct device *dev; + unsigned int minor; - mp = kzalloc(sizeof(*mp), GFP_ATOMIC); - if (!mp) { - printk(KERN_ERR "capi: can't alloc capiminor\n"); + mp = kzalloc(sizeof(*mp), GFP_KERNEL); + if (!mp) { + printk(KERN_ERR "capi: can't alloc capiminor\n"); return NULL; } mp->ap = ap; mp->ncci = ncci; - mp->msgid = 0; - atomic_set(&mp->ttyopencount,0); INIT_LIST_HEAD(&mp->ackqueue); spin_lock_init(&mp->ackqlock); skb_queue_head_init(&mp->inqueue); skb_queue_head_init(&mp->outqueue); + spin_lock_init(&mp->outlock); - /* Allocate the least unused minor number. - */ - write_lock_irqsave(&capiminor_list_lock, flags); - if (list_empty(&capiminor_list)) - list_add(&mp->list, &capiminor_list); - else { - list_for_each_entry(p, &capiminor_list, list) { - if (p->minor > minor) - break; - minor++; - } - - if (minor < capi_ttyminors) { - mp->minor = minor; - list_add(&mp->list, p->list.prev); + tty_port_init(&mp->port); + mp->port.ops = &capiminor_port_ops; + + /* Allocate the least unused minor number. */ + spin_lock(&capiminors_lock); + for (minor = 0; minor < capi_ttyminors; minor++) + if (!capiminors[minor]) { + capiminors[minor] = mp; + break; } - } - write_unlock_irqrestore(&capiminor_list_lock, flags); + spin_unlock(&capiminors_lock); - if (!(minor < capi_ttyminors)) { + if (minor == capi_ttyminors) { printk(KERN_NOTICE "capi: out of minors\n"); - kfree(mp); - return NULL; + goto err_out1; } + mp->minor = minor; + + dev = tty_port_register_device(&mp->port, capinc_tty_driver, minor, + NULL); + if (IS_ERR(dev)) + goto err_out2; + return mp; + +err_out2: + spin_lock(&capiminors_lock); + capiminors[minor] = NULL; + spin_unlock(&capiminors_lock); + +err_out1: + tty_port_put(&mp->port); + return NULL; } -static void capiminor_free(struct capiminor *mp) +static struct capiminor *capiminor_get(unsigned int minor) { - unsigned long flags; + struct capiminor *mp; - write_lock_irqsave(&capiminor_list_lock, flags); - list_del(&mp->list); - write_unlock_irqrestore(&capiminor_list_lock, flags); + spin_lock(&capiminors_lock); + mp = capiminors[minor]; + if (mp) + tty_port_get(&mp->port); + spin_unlock(&capiminors_lock); - if (mp->ttyskb) kfree_skb(mp->ttyskb); - mp->ttyskb = NULL; - skb_queue_purge(&mp->inqueue); - skb_queue_purge(&mp->outqueue); - capiminor_del_all_ack(mp); - kfree(mp); + return mp; } -static struct capiminor *capiminor_find(unsigned int minor) +static inline void capiminor_put(struct capiminor *mp) { - struct list_head *l; - struct capiminor *p = NULL; + tty_port_put(&mp->port); +} - read_lock(&capiminor_list_lock); - list_for_each(l, &capiminor_list) { - p = list_entry(l, struct capiminor, list); - if (p->minor == minor) - break; - } - read_unlock(&capiminor_list_lock); - if (l == &capiminor_list) - return NULL; +static void capiminor_free(struct capiminor *mp) +{ + tty_unregister_device(capinc_tty_driver, mp->minor); + + spin_lock(&capiminors_lock); + capiminors[mp->minor] = NULL; + spin_unlock(&capiminors_lock); - return p; + capiminor_put(mp); } -#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ /* -------- struct capincci ----------------------------------------- */ -static struct capincci *capincci_alloc(struct capidev *cdev, u32 ncci) +static void capincci_alloc_minor(struct capidev *cdev, struct capincci *np) { - struct capincci *np, **pp; -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE - struct capiminor *mp = NULL; -#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ - - np = kzalloc(sizeof(*np), GFP_ATOMIC); - if (!np) - return NULL; - np->ncci = ncci; - np->cdev = cdev; -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE - mp = NULL; if (cdev->userflags & CAPIFLAG_HIGHJACKING) - mp = np->minorp = capiminor_alloc(&cdev->ap, ncci); - if (mp) { - mp->nccip = np; -#ifdef _DEBUG_REFCOUNT - printk(KERN_DEBUG "set mp->nccip\n"); -#endif -#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE) - capifs_new_ncci(mp->minor, MKDEV(capi_ttymajor, mp->minor)); -#endif - } -#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ - for (pp=&cdev->nccis; *pp; pp = &(*pp)->next) - ; - *pp = np; - return np; + np->minorp = capiminor_alloc(&cdev->ap, np->ncci); } -static void capincci_free(struct capidev *cdev, u32 ncci) +static void capincci_free_minor(struct capincci *np) { - struct capincci *np, **pp; -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE - struct capiminor *mp; -#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + struct capiminor *mp = np->minorp; + struct tty_struct *tty; - pp=&cdev->nccis; - while (*pp) { - np = *pp; - if (ncci == 0xffffffff || np->ncci == ncci) { - *pp = (*pp)->next; -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE - if ((mp = np->minorp) != NULL) { -#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE) - capifs_free_ncci(mp->minor); -#endif - if (mp->tty) { - mp->nccip = NULL; -#ifdef _DEBUG_REFCOUNT - printk(KERN_DEBUG "reset mp->nccip\n"); -#endif - tty_hangup(mp->tty); - } else { - capiminor_free(mp); - } - } -#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ - kfree(np); - if (*pp == NULL) return; - } else { - pp = &(*pp)->next; + if (mp) { + tty = tty_port_tty_get(&mp->port); + if (tty) { + tty_vhangup(tty); + tty_kref_put(tty); } + + capiminor_free(mp); } } -static struct capincci *capincci_find(struct capidev *cdev, u32 ncci) +static inline unsigned int capincci_minor_opencount(struct capincci *np) { - struct capincci *p; + struct capiminor *mp = np->minorp; + unsigned int count = 0; + struct tty_struct *tty; - for (p=cdev->nccis; p ; p = p->next) { - if (p->ncci == ncci) - break; + if (mp) { + tty = tty_port_tty_get(&mp->port); + if (tty) { + count = tty->count; + tty_kref_put(tty); + } } - return p; + return count; } -/* -------- struct capidev ------------------------------------------ */ +#else /* !CONFIG_ISDN_CAPI_MIDDLEWARE */ + +static inline void +capincci_alloc_minor(struct capidev *cdev, struct capincci *np) { } +static inline void capincci_free_minor(struct capincci *np) { } + +#endif /* !CONFIG_ISDN_CAPI_MIDDLEWARE */ -static struct capidev *capidev_alloc(void) +static struct capincci *capincci_alloc(struct capidev *cdev, u32 ncci) { - struct capidev *cdev; - unsigned long flags; + struct capincci *np; - cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); - if (!cdev) + np = kzalloc(sizeof(*np), GFP_KERNEL); + if (!np) return NULL; + np->ncci = ncci; + np->cdev = cdev; - mutex_init(&cdev->ncci_list_mtx); - skb_queue_head_init(&cdev->recvqueue); - init_waitqueue_head(&cdev->recvwait); - write_lock_irqsave(&capidev_list_lock, flags); - list_add_tail(&cdev->list, &capidev_list); - write_unlock_irqrestore(&capidev_list_lock, flags); - return cdev; + capincci_alloc_minor(cdev, np); + + list_add_tail(&np->list, &cdev->nccis); + + return np; } -static void capidev_free(struct capidev *cdev) +static void capincci_free(struct capidev *cdev, u32 ncci) { - unsigned long flags; + struct capincci *np, *tmp; - if (cdev->ap.applid) { - capi20_release(&cdev->ap); - cdev->ap.applid = 0; - } - skb_queue_purge(&cdev->recvqueue); + list_for_each_entry_safe(np, tmp, &cdev->nccis, list) + if (ncci == 0xffffffff || np->ncci == ncci) { + capincci_free_minor(np); + list_del(&np->list); + kfree(np); + } +} - mutex_lock(&cdev->ncci_list_mtx); - capincci_free(cdev, 0xffffffff); - mutex_unlock(&cdev->ncci_list_mtx); +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE +static struct capincci *capincci_find(struct capidev *cdev, u32 ncci) +{ + struct capincci *np; - write_lock_irqsave(&capidev_list_lock, flags); - list_del(&cdev->list); - write_unlock_irqrestore(&capidev_list_lock, flags); - kfree(cdev); + list_for_each_entry(np, &cdev->nccis, list) + if (np->ncci == ncci) + return np; + return NULL; } -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE /* -------- handle data queue --------------------------------------- */ static struct sk_buff * gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb) { struct sk_buff *nskb; - nskb = alloc_skb(CAPI_DATA_B3_RESP_LEN, GFP_ATOMIC); + nskb = alloc_skb(CAPI_DATA_B3_RESP_LEN, GFP_KERNEL); if (nskb) { - u16 datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4+4+2); + u16 datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4 + 4 + 2); unsigned char *s = skb_put(nskb, CAPI_DATA_B3_RESP_LEN); capimsg_setu16(s, 0, CAPI_DATA_B3_RESP_LEN); capimsg_setu16(s, 2, mp->ap->applid); capimsg_setu8 (s, 4, CAPI_DATA_B3); capimsg_setu8 (s, 5, CAPI_RESP); - capimsg_setu16(s, 6, mp->msgid++); + capimsg_setu16(s, 6, atomic_inc_return(&mp->msgid)); capimsg_setu32(s, 8, mp->ncci); capimsg_setu16(s, 12, datahandle); } @@ -449,142 +400,166 @@ gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb) static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb) { + unsigned int datalen = skb->len - CAPIMSG_LEN(skb->data); + struct tty_struct *tty; struct sk_buff *nskb; - int datalen; u16 errcode, datahandle; struct tty_ldisc *ld; - - datalen = skb->len - CAPIMSG_LEN(skb->data); - if (mp->tty == NULL) - { -#ifdef _DEBUG_DATAFLOW - printk(KERN_DEBUG "capi: currently no receiver\n"); -#endif + int ret = -1; + + tty = tty_port_tty_get(&mp->port); + if (!tty) { + pr_debug("capi: currently no receiver\n"); return -1; } - - ld = tty_ldisc_ref(mp->tty); - if (ld == NULL) - return -1; + + ld = tty_ldisc_ref(tty); + if (!ld) { + /* fatal error, do not requeue */ + ret = 0; + kfree_skb(skb); + goto deref_tty; + } + if (ld->ops->receive_buf == NULL) { -#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) - printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n"); -#endif - goto bad; + pr_debug("capi: ldisc has no receive_buf function\n"); + /* fatal error, do not requeue */ + goto free_skb; } if (mp->ttyinstop) { -#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) - printk(KERN_DEBUG "capi: recv tty throttled\n"); -#endif - goto bad; + pr_debug("capi: recv tty throttled\n"); + goto deref_ldisc; } - if (mp->tty->receive_room < datalen) { -#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) - printk(KERN_DEBUG "capi: no room in tty\n"); -#endif - goto bad; + + if (tty->receive_room < datalen) { + pr_debug("capi: no room in tty\n"); + goto deref_ldisc; } - if ((nskb = gen_data_b3_resp_for(mp, skb)) == NULL) { + + nskb = gen_data_b3_resp_for(mp, skb); + if (!nskb) { printk(KERN_ERR "capi: gen_data_b3_resp failed\n"); - goto bad; + goto deref_ldisc; } - datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4); + + datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4); + errcode = capi20_put_message(mp->ap, nskb); - if (errcode != CAPI_NOERROR) { + + if (errcode == CAPI_NOERROR) { + skb_pull(skb, CAPIMSG_LEN(skb->data)); + pr_debug("capi: DATA_B3_RESP %u len=%d => ldisc\n", + datahandle, skb->len); + ld->ops->receive_buf(tty, skb->data, NULL, skb->len); + } else { printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n", - errcode); + errcode); kfree_skb(nskb); - goto bad; + + if (errcode == CAPI_SENDQUEUEFULL) + goto deref_ldisc; } - (void)skb_pull(skb, CAPIMSG_LEN(skb->data)); -#ifdef _DEBUG_DATAFLOW - printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n", - datahandle, skb->len); -#endif - ld->ops->receive_buf(mp->tty, skb->data, NULL, skb->len); + +free_skb: + ret = 0; kfree_skb(skb); + +deref_ldisc: tty_ldisc_deref(ld); - return 0; -bad: - tty_ldisc_deref(ld); - return -1; + +deref_tty: + tty_kref_put(tty); + return ret; } static void handle_minor_recv(struct capiminor *mp) { struct sk_buff *skb; - while ((skb = skb_dequeue(&mp->inqueue)) != NULL) { - unsigned int len = skb->len; - mp->inbytes -= len; + + while ((skb = skb_dequeue(&mp->inqueue)) != NULL) if (handle_recv_skb(mp, skb) < 0) { skb_queue_head(&mp->inqueue, skb); - mp->inbytes += len; return; } - } } -static int handle_minor_send(struct capiminor *mp) +static void handle_minor_send(struct capiminor *mp) { + struct tty_struct *tty; struct sk_buff *skb; u16 len; - int count = 0; u16 errcode; u16 datahandle; - if (mp->tty && mp->ttyoutstop) { -#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) - printk(KERN_DEBUG "capi: send: tty stopped\n"); -#endif - return 0; + tty = tty_port_tty_get(&mp->port); + if (!tty) + return; + + if (mp->ttyoutstop) { + pr_debug("capi: send: tty stopped\n"); + tty_kref_put(tty); + return; } - while ((skb = skb_dequeue(&mp->outqueue)) != NULL) { - datahandle = mp->datahandle; + while (1) { + spin_lock_bh(&mp->outlock); + skb = __skb_dequeue(&mp->outqueue); + if (!skb) { + spin_unlock_bh(&mp->outlock); + break; + } len = (u16)skb->len; + mp->outbytes -= len; + spin_unlock_bh(&mp->outlock); + + datahandle = atomic_inc_return(&mp->datahandle); skb_push(skb, CAPI_DATA_B3_REQ_LEN); memset(skb->data, 0, CAPI_DATA_B3_REQ_LEN); capimsg_setu16(skb->data, 0, CAPI_DATA_B3_REQ_LEN); capimsg_setu16(skb->data, 2, mp->ap->applid); capimsg_setu8 (skb->data, 4, CAPI_DATA_B3); capimsg_setu8 (skb->data, 5, CAPI_REQ); - capimsg_setu16(skb->data, 6, mp->msgid++); + capimsg_setu16(skb->data, 6, atomic_inc_return(&mp->msgid)); capimsg_setu32(skb->data, 8, mp->ncci); /* NCCI */ capimsg_setu32(skb->data, 12, (u32)(long)skb->data);/* Data32 */ capimsg_setu16(skb->data, 16, len); /* Data length */ capimsg_setu16(skb->data, 18, datahandle); capimsg_setu16(skb->data, 20, 0); /* Flags */ - if (capincci_add_ack(mp, datahandle) < 0) { + if (capiminor_add_ack(mp, datahandle) < 0) { skb_pull(skb, CAPI_DATA_B3_REQ_LEN); - skb_queue_head(&mp->outqueue, skb); - return count; + + spin_lock_bh(&mp->outlock); + __skb_queue_head(&mp->outqueue, skb); + mp->outbytes += len; + spin_unlock_bh(&mp->outlock); + + break; } errcode = capi20_put_message(mp->ap, skb); if (errcode == CAPI_NOERROR) { - mp->datahandle++; - count++; - mp->outbytes -= len; -#ifdef _DEBUG_DATAFLOW - printk(KERN_DEBUG "capi: DATA_B3_REQ %u len=%u\n", - datahandle, len); -#endif + pr_debug("capi: DATA_B3_REQ %u len=%u\n", + datahandle, len); continue; } capiminor_del_ack(mp, datahandle); if (errcode == CAPI_SENDQUEUEFULL) { skb_pull(skb, CAPI_DATA_B3_REQ_LEN); - skb_queue_head(&mp->outqueue, skb); + + spin_lock_bh(&mp->outlock); + __skb_queue_head(&mp->outqueue, skb); + mp->outbytes += len; + spin_unlock_bh(&mp->outlock); + break; } /* ups, drop packet */ printk(KERN_ERR "capi: put_message = %x\n", errcode); - mp->outbytes -= len; kfree_skb(skb); } - return count; + tty_kref_put(tty); } #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ @@ -596,78 +571,63 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb) #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE struct capiminor *mp; u16 datahandle; -#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ struct capincci *np; - u32 ncci; - unsigned long flags; +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + + mutex_lock(&cdev->lock); if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_CONF) { u16 info = CAPIMSG_U16(skb->data, 12); // Info field - if (info == 0) { - mutex_lock(&cdev->ncci_list_mtx); + if ((info & 0xff00) == 0) capincci_alloc(cdev, CAPIMSG_NCCI(skb->data)); - mutex_unlock(&cdev->ncci_list_mtx); - } } - if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_IND) { - mutex_lock(&cdev->ncci_list_mtx); + if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_IND) capincci_alloc(cdev, CAPIMSG_NCCI(skb->data)); - mutex_unlock(&cdev->ncci_list_mtx); - } - spin_lock_irqsave(&workaround_lock, flags); + if (CAPIMSG_COMMAND(skb->data) != CAPI_DATA_B3) { skb_queue_tail(&cdev->recvqueue, skb); wake_up_interruptible(&cdev->recvwait); - spin_unlock_irqrestore(&workaround_lock, flags); - return; + goto unlock_out; } - ncci = CAPIMSG_CONTROL(skb->data); - for (np = cdev->nccis; np && np->ncci != ncci; np = np->next) - ; + +#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE + skb_queue_tail(&cdev->recvqueue, skb); + wake_up_interruptible(&cdev->recvwait); + +#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + + np = capincci_find(cdev, CAPIMSG_CONTROL(skb->data)); if (!np) { printk(KERN_ERR "BUG: capi_signal: ncci not found\n"); skb_queue_tail(&cdev->recvqueue, skb); wake_up_interruptible(&cdev->recvwait); - spin_unlock_irqrestore(&workaround_lock, flags); - return; + goto unlock_out; } -#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE - skb_queue_tail(&cdev->recvqueue, skb); - wake_up_interruptible(&cdev->recvwait); -#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + mp = np->minorp; if (!mp) { skb_queue_tail(&cdev->recvqueue, skb); wake_up_interruptible(&cdev->recvwait); - spin_unlock_irqrestore(&workaround_lock, flags); - return; + goto unlock_out; } - - if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) { - - datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+4+2); -#ifdef _DEBUG_DATAFLOW - printk(KERN_DEBUG "capi_signal: DATA_B3_IND %u len=%d\n", - datahandle, skb->len-CAPIMSG_LEN(skb->data)); -#endif + datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4 + 4 + 2); + pr_debug("capi_signal: DATA_B3_IND %u len=%d\n", + datahandle, skb->len-CAPIMSG_LEN(skb->data)); skb_queue_tail(&mp->inqueue, skb); - mp->inbytes += skb->len; + handle_minor_recv(mp); } else if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF) { - datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4); -#ifdef _DEBUG_DATAFLOW - printk(KERN_DEBUG "capi_signal: DATA_B3_CONF %u 0x%x\n", - datahandle, - CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+2)); -#endif + datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4); + pr_debug("capi_signal: DATA_B3_CONF %u 0x%x\n", + datahandle, + CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4 + 2)); kfree_skb(skb); - (void)capiminor_del_ack(mp, datahandle); - if (mp->tty) - tty_wakeup(mp->tty); - (void)handle_minor_send(mp); + capiminor_del_ack(mp, datahandle); + tty_port_tty_wakeup(&mp->port); + handle_minor_send(mp); } else { /* ups, let capi application handle it :-) */ @@ -675,7 +635,9 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb) wake_up_interruptible(&cdev->recvwait); } #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ - spin_unlock_irqrestore(&workaround_lock, flags); + +unlock_out: + mutex_unlock(&cdev->lock); } /* -------- file_operations for capidev ----------------------------- */ @@ -683,27 +645,22 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb) static ssize_t capi_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - struct capidev *cdev = (struct capidev *)file->private_data; + struct capidev *cdev = file->private_data; struct sk_buff *skb; size_t copied; + int err; if (!cdev->ap.applid) return -ENODEV; - if ((skb = skb_dequeue(&cdev->recvqueue)) == NULL) { - + skb = skb_dequeue(&cdev->recvqueue); + if (!skb) { if (file->f_flags & O_NONBLOCK) return -EAGAIN; - - for (;;) { - interruptible_sleep_on(&cdev->recvwait); - if ((skb = skb_dequeue(&cdev->recvqueue)) != NULL) - break; - if (signal_pending(current)) - break; - } - if (skb == NULL) - return -ERESTARTNOHAND; + err = wait_event_interruptible(cdev->recvwait, + (skb = skb_dequeue(&cdev->recvqueue))); + if (err) + return err; } if (skb->len > count) { skb_queue_head(&cdev->recvqueue, skb); @@ -723,7 +680,7 @@ capi_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) static ssize_t capi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - struct capidev *cdev = (struct capidev *)file->private_data; + struct capidev *cdev = file->private_data; struct sk_buff *skb; u16 mlen; @@ -753,9 +710,9 @@ capi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos CAPIMSG_SETAPPID(skb->data, cdev->ap.applid); if (CAPIMSG_CMD(skb->data) == CAPI_DISCONNECT_B3_RESP) { - mutex_lock(&cdev->ncci_list_mtx); + mutex_lock(&cdev->lock); capincci_free(cdev, CAPIMSG_NCCI(skb->data)); - mutex_unlock(&cdev->ncci_list_mtx); + mutex_unlock(&cdev->lock); } cdev->errcode = capi20_put_message(&cdev->ap, skb); @@ -768,9 +725,9 @@ capi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos } static unsigned int -capi_poll(struct file *file, poll_table * wait) +capi_poll(struct file *file, poll_table *wait) { - struct capidev *cdev = (struct capidev *)file->private_data; + struct capidev *cdev = file->private_data; unsigned int mask = 0; if (!cdev->ap.applid) @@ -784,105 +741,103 @@ capi_poll(struct file *file, poll_table * wait) } static int -capi_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +capi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct capidev *cdev = file->private_data; - struct capi20_appl *ap = &cdev->ap; capi_ioctl_struct data; int retval = -EINVAL; void __user *argp = (void __user *)arg; switch (cmd) { case CAPI_REGISTER: - { - if (ap->applid) - return -EEXIST; + mutex_lock(&cdev->lock); - if (copy_from_user(&cdev->ap.rparam, argp, - sizeof(struct capi_register_params))) - return -EFAULT; - - cdev->ap.private = cdev; - cdev->ap.recv_message = capi_recv_message; - cdev->errcode = capi20_register(ap); - if (cdev->errcode) { - ap->applid = 0; - return -EIO; - } + if (cdev->ap.applid) { + retval = -EEXIST; + goto register_out; + } + if (copy_from_user(&cdev->ap.rparam, argp, + sizeof(struct capi_register_params))) { + retval = -EFAULT; + goto register_out; + } + cdev->ap.private = cdev; + cdev->ap.recv_message = capi_recv_message; + cdev->errcode = capi20_register(&cdev->ap); + retval = (int)cdev->ap.applid; + if (cdev->errcode) { + cdev->ap.applid = 0; + retval = -EIO; } - return (int)ap->applid; + +register_out: + mutex_unlock(&cdev->lock); + return retval; case CAPI_GET_VERSION: - { - if (copy_from_user(&data.contr, argp, - sizeof(data.contr))) - return -EFAULT; - cdev->errcode = capi20_get_version(data.contr, &data.version); - if (cdev->errcode) - return -EIO; - if (copy_to_user(argp, &data.version, - sizeof(data.version))) - return -EFAULT; - } + if (copy_from_user(&data.contr, argp, + sizeof(data.contr))) + return -EFAULT; + cdev->errcode = capi20_get_version(data.contr, &data.version); + if (cdev->errcode) + return -EIO; + if (copy_to_user(argp, &data.version, + sizeof(data.version))) + return -EFAULT; return 0; case CAPI_GET_SERIAL: - { - if (copy_from_user(&data.contr, argp, - sizeof(data.contr))) - return -EFAULT; - cdev->errcode = capi20_get_serial (data.contr, data.serial); - if (cdev->errcode) - return -EIO; - if (copy_to_user(argp, data.serial, - sizeof(data.serial))) - return -EFAULT; - } + if (copy_from_user(&data.contr, argp, + sizeof(data.contr))) + return -EFAULT; + cdev->errcode = capi20_get_serial(data.contr, data.serial); + if (cdev->errcode) + return -EIO; + if (copy_to_user(argp, data.serial, + sizeof(data.serial))) + return -EFAULT; return 0; + case CAPI_GET_PROFILE: - { - if (copy_from_user(&data.contr, argp, - sizeof(data.contr))) - return -EFAULT; + if (copy_from_user(&data.contr, argp, + sizeof(data.contr))) + return -EFAULT; - if (data.contr == 0) { - cdev->errcode = capi20_get_profile(data.contr, &data.profile); - if (cdev->errcode) - return -EIO; + if (data.contr == 0) { + cdev->errcode = capi20_get_profile(data.contr, &data.profile); + if (cdev->errcode) + return -EIO; - retval = copy_to_user(argp, - &data.profile.ncontroller, - sizeof(data.profile.ncontroller)); + retval = copy_to_user(argp, + &data.profile.ncontroller, + sizeof(data.profile.ncontroller)); - } else { - cdev->errcode = capi20_get_profile(data.contr, &data.profile); - if (cdev->errcode) - return -EIO; + } else { + cdev->errcode = capi20_get_profile(data.contr, &data.profile); + if (cdev->errcode) + return -EIO; - retval = copy_to_user(argp, &data.profile, - sizeof(data.profile)); - } - if (retval) - return -EFAULT; + retval = copy_to_user(argp, &data.profile, + sizeof(data.profile)); } + if (retval) + return -EFAULT; return 0; case CAPI_GET_MANUFACTURER: - { - if (copy_from_user(&data.contr, argp, - sizeof(data.contr))) - return -EFAULT; - cdev->errcode = capi20_get_manufacturer(data.contr, data.manufacturer); - if (cdev->errcode) - return -EIO; + if (copy_from_user(&data.contr, argp, + sizeof(data.contr))) + return -EFAULT; + cdev->errcode = capi20_get_manufacturer(data.contr, data.manufacturer); + if (cdev->errcode) + return -EIO; - if (copy_to_user(argp, data.manufacturer, - sizeof(data.manufacturer))) - return -EFAULT; + if (copy_to_user(argp, data.manufacturer, + sizeof(data.manufacturer))) + return -EFAULT; - } return 0; + case CAPI_GET_ERRCODE: data.errcode = cdev->errcode; cdev->errcode = CAPI_NOERROR; @@ -898,113 +853,129 @@ capi_ioctl(struct inode *inode, struct file *file, return 0; return -ENXIO; - case CAPI_MANUFACTURER_CMD: - { - struct capi_manufacturer_cmd mcmd; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (copy_from_user(&mcmd, argp, sizeof(mcmd))) - return -EFAULT; - return capi20_manufacturer(mcmd.cmd, mcmd.data); - } - return 0; - + case CAPI_MANUFACTURER_CMD: { + struct capi_manufacturer_cmd mcmd; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (copy_from_user(&mcmd, argp, sizeof(mcmd))) + return -EFAULT; + return capi20_manufacturer(mcmd.cmd, mcmd.data); + } case CAPI_SET_FLAGS: - case CAPI_CLR_FLAGS: - { - unsigned userflags; - if (copy_from_user(&userflags, argp, - sizeof(userflags))) - return -EFAULT; - if (cmd == CAPI_SET_FLAGS) - cdev->userflags |= userflags; - else - cdev->userflags &= ~userflags; - } - return 0; + case CAPI_CLR_FLAGS: { + unsigned userflags; + + if (copy_from_user(&userflags, argp, sizeof(userflags))) + return -EFAULT; + mutex_lock(&cdev->lock); + if (cmd == CAPI_SET_FLAGS) + cdev->userflags |= userflags; + else + cdev->userflags &= ~userflags; + mutex_unlock(&cdev->lock); + return 0; + } case CAPI_GET_FLAGS: if (copy_to_user(argp, &cdev->userflags, sizeof(cdev->userflags))) return -EFAULT; return 0; +#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE case CAPI_NCCI_OPENCOUNT: - { - struct capincci *nccip; -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE - struct capiminor *mp; -#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ - unsigned ncci; - int count = 0; - if (copy_from_user(&ncci, argp, sizeof(ncci))) - return -EFAULT; - - mutex_lock(&cdev->ncci_list_mtx); - if ((nccip = capincci_find(cdev, (u32) ncci)) == NULL) { - mutex_unlock(&cdev->ncci_list_mtx); - return 0; - } -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE - if ((mp = nccip->minorp) != NULL) { - count += atomic_read(&mp->ttyopencount); - } -#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ - mutex_unlock(&cdev->ncci_list_mtx); - return count; - } return 0; -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE - case CAPI_NCCI_GETUNIT: - { - struct capincci *nccip; - struct capiminor *mp; - unsigned ncci; - int unit = 0; - if (copy_from_user(&ncci, argp, - sizeof(ncci))) - return -EFAULT; - mutex_lock(&cdev->ncci_list_mtx); - nccip = capincci_find(cdev, (u32) ncci); - if (!nccip || (mp = nccip->minorp) == NULL) { - mutex_unlock(&cdev->ncci_list_mtx); - return -ESRCH; - } - unit = mp->minor; - mutex_unlock(&cdev->ncci_list_mtx); - return unit; +#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + case CAPI_NCCI_OPENCOUNT: { + struct capincci *nccip; + unsigned ncci; + int count = 0; + + if (copy_from_user(&ncci, argp, sizeof(ncci))) + return -EFAULT; + + mutex_lock(&cdev->lock); + nccip = capincci_find(cdev, (u32)ncci); + if (nccip) + count = capincci_minor_opencount(nccip); + mutex_unlock(&cdev->lock); + return count; + } + + case CAPI_NCCI_GETUNIT: { + struct capincci *nccip; + struct capiminor *mp; + unsigned ncci; + int unit = -ESRCH; + + if (copy_from_user(&ncci, argp, sizeof(ncci))) + return -EFAULT; + + mutex_lock(&cdev->lock); + nccip = capincci_find(cdev, (u32)ncci); + if (nccip) { + mp = nccip->minorp; + if (mp) + unit = mp->minor; } - return 0; + mutex_unlock(&cdev->lock); + return unit; + } #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + + default: + return -EINVAL; } - return -EINVAL; } -static int -capi_open(struct inode *inode, struct file *file) +static long +capi_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret; - - lock_kernel(); - if (file->private_data) - ret = -EEXIST; - else if ((file->private_data = capidev_alloc()) == NULL) - ret = -ENOMEM; - else - ret = nonseekable_open(inode, file); - unlock_kernel(); + + mutex_lock(&capi_mutex); + ret = capi_ioctl(file, cmd, arg); + mutex_unlock(&capi_mutex); + return ret; } -static int -capi_release(struct inode *inode, struct file *file) +static int capi_open(struct inode *inode, struct file *file) +{ + struct capidev *cdev; + + cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); + if (!cdev) + return -ENOMEM; + + mutex_init(&cdev->lock); + skb_queue_head_init(&cdev->recvqueue); + init_waitqueue_head(&cdev->recvwait); + INIT_LIST_HEAD(&cdev->nccis); + file->private_data = cdev; + + mutex_lock(&capidev_list_lock); + list_add_tail(&cdev->list, &capidev_list); + mutex_unlock(&capidev_list_lock); + + return nonseekable_open(inode, file); +} + +static int capi_release(struct inode *inode, struct file *file) { - struct capidev *cdev = (struct capidev *)file->private_data; + struct capidev *cdev = file->private_data; - capidev_free(cdev); - file->private_data = NULL; - + mutex_lock(&capidev_list_lock); + list_del(&cdev->list); + mutex_unlock(&capidev_list_lock); + + if (cdev->ap.applid) + capi20_release(&cdev->ap); + skb_queue_purge(&cdev->recvqueue); + capincci_free(cdev, 0xffffffff); + + kfree(cdev); return 0; } @@ -1015,7 +986,7 @@ static const struct file_operations capi_fops = .read = capi_read, .write = capi_write, .poll = capi_poll, - .ioctl = capi_ioctl, + .unlocked_ioctl = capi_unlocked_ioctl, .open = capi_open, .release = capi_release, }; @@ -1023,322 +994,239 @@ static const struct file_operations capi_fops = #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE /* -------- tty_operations for capincci ----------------------------- */ -static int capinc_tty_open(struct tty_struct * tty, struct file * file) +static int +capinc_tty_install(struct tty_driver *driver, struct tty_struct *tty) { - struct capiminor *mp; - unsigned long flags; + struct capiminor *mp = capiminor_get(tty->index); + int ret = tty_standard_install(driver, tty); - if ((mp = capiminor_find(iminor(file->f_path.dentry->d_inode))) == NULL) - return -ENXIO; - if (mp->nccip == NULL) - return -ENXIO; + if (ret == 0) + tty->driver_data = mp; + else + capiminor_put(mp); + return ret; +} - tty->driver_data = (void *)mp; +static void capinc_tty_cleanup(struct tty_struct *tty) +{ + struct capiminor *mp = tty->driver_data; + tty->driver_data = NULL; + capiminor_put(mp); +} + +static int capinc_tty_open(struct tty_struct *tty, struct file *filp) +{ + struct capiminor *mp = tty->driver_data; + int err; + + err = tty_port_open(&mp->port, tty, filp); + if (err) + return err; - spin_lock_irqsave(&workaround_lock, flags); - if (atomic_read(&mp->ttyopencount) == 0) - mp->tty = tty; - atomic_inc(&mp->ttyopencount); -#ifdef _DEBUG_REFCOUNT - printk(KERN_DEBUG "capinc_tty_open ocount=%d\n", atomic_read(&mp->ttyopencount)); -#endif handle_minor_recv(mp); - spin_unlock_irqrestore(&workaround_lock, flags); return 0; } -static void capinc_tty_close(struct tty_struct * tty, struct file * file) +static void capinc_tty_close(struct tty_struct *tty, struct file *filp) { - struct capiminor *mp; + struct capiminor *mp = tty->driver_data; - mp = (struct capiminor *)tty->driver_data; - if (mp) { - if (atomic_dec_and_test(&mp->ttyopencount)) { -#ifdef _DEBUG_REFCOUNT - printk(KERN_DEBUG "capinc_tty_close lastclose\n"); -#endif - tty->driver_data = NULL; - mp->tty = NULL; - } -#ifdef _DEBUG_REFCOUNT - printk(KERN_DEBUG "capinc_tty_close ocount=%d\n", atomic_read(&mp->ttyopencount)); -#endif - if (mp->nccip == NULL) - capiminor_free(mp); - } - -#ifdef _DEBUG_REFCOUNT - printk(KERN_DEBUG "capinc_tty_close\n"); -#endif + tty_port_close(&mp->port, tty, filp); } -static int capinc_tty_write(struct tty_struct * tty, +static int capinc_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) { - struct capiminor *mp = (struct capiminor *)tty->driver_data; + struct capiminor *mp = tty->driver_data; struct sk_buff *skb; - unsigned long flags; - -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_write(count=%d)\n", count); -#endif - if (!mp || !mp->nccip) { -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_write: mp or mp->ncci NULL\n"); -#endif - return 0; - } + pr_debug("capinc_tty_write(count=%d)\n", count); - spin_lock_irqsave(&workaround_lock, flags); - skb = mp->ttyskb; + spin_lock_bh(&mp->outlock); + skb = mp->outskb; if (skb) { - mp->ttyskb = NULL; - skb_queue_tail(&mp->outqueue, skb); + mp->outskb = NULL; + __skb_queue_tail(&mp->outqueue, skb); mp->outbytes += skb->len; } - skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+count, GFP_ATOMIC); + skb = alloc_skb(CAPI_DATA_B3_REQ_LEN + count, GFP_ATOMIC); if (!skb) { printk(KERN_ERR "capinc_tty_write: alloc_skb failed\n"); - spin_unlock_irqrestore(&workaround_lock, flags); + spin_unlock_bh(&mp->outlock); return -ENOMEM; } skb_reserve(skb, CAPI_DATA_B3_REQ_LEN); memcpy(skb_put(skb, count), buf, count); - skb_queue_tail(&mp->outqueue, skb); + __skb_queue_tail(&mp->outqueue, skb); mp->outbytes += skb->len; - (void)handle_minor_send(mp); - (void)handle_minor_recv(mp); - spin_unlock_irqrestore(&workaround_lock, flags); + spin_unlock_bh(&mp->outlock); + + handle_minor_send(mp); + return count; } static int capinc_tty_put_char(struct tty_struct *tty, unsigned char ch) { - struct capiminor *mp = (struct capiminor *)tty->driver_data; + struct capiminor *mp = tty->driver_data; + bool invoke_send = false; struct sk_buff *skb; - unsigned long flags; int ret = 1; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_put_char(%u)\n", ch); -#endif - - if (!mp || !mp->nccip) { -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_put_char: mp or mp->ncci NULL\n"); -#endif - return 0; - } + pr_debug("capinc_put_char(%u)\n", ch); - spin_lock_irqsave(&workaround_lock, flags); - skb = mp->ttyskb; + spin_lock_bh(&mp->outlock); + skb = mp->outskb; if (skb) { if (skb_tailroom(skb) > 0) { *(skb_put(skb, 1)) = ch; - spin_unlock_irqrestore(&workaround_lock, flags); - return 1; + goto unlock_out; } - mp->ttyskb = NULL; - skb_queue_tail(&mp->outqueue, skb); + mp->outskb = NULL; + __skb_queue_tail(&mp->outqueue, skb); mp->outbytes += skb->len; - (void)handle_minor_send(mp); + invoke_send = true; } - skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+CAPI_MAX_BLKSIZE, GFP_ATOMIC); + + skb = alloc_skb(CAPI_DATA_B3_REQ_LEN + CAPI_MAX_BLKSIZE, GFP_ATOMIC); if (skb) { skb_reserve(skb, CAPI_DATA_B3_REQ_LEN); *(skb_put(skb, 1)) = ch; - mp->ttyskb = skb; + mp->outskb = skb; } else { printk(KERN_ERR "capinc_put_char: char %u lost\n", ch); ret = 0; } - spin_unlock_irqrestore(&workaround_lock, flags); + +unlock_out: + spin_unlock_bh(&mp->outlock); + + if (invoke_send) + handle_minor_send(mp); + return ret; } static void capinc_tty_flush_chars(struct tty_struct *tty) { - struct capiminor *mp = (struct capiminor *)tty->driver_data; + struct capiminor *mp = tty->driver_data; struct sk_buff *skb; - unsigned long flags; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_flush_chars\n"); -#endif + pr_debug("capinc_tty_flush_chars\n"); - if (!mp || !mp->nccip) { -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_flush_chars: mp or mp->ncci NULL\n"); -#endif - return; - } - - spin_lock_irqsave(&workaround_lock, flags); - skb = mp->ttyskb; + spin_lock_bh(&mp->outlock); + skb = mp->outskb; if (skb) { - mp->ttyskb = NULL; - skb_queue_tail(&mp->outqueue, skb); + mp->outskb = NULL; + __skb_queue_tail(&mp->outqueue, skb); mp->outbytes += skb->len; - (void)handle_minor_send(mp); - } - (void)handle_minor_recv(mp); - spin_unlock_irqrestore(&workaround_lock, flags); + spin_unlock_bh(&mp->outlock); + + handle_minor_send(mp); + } else + spin_unlock_bh(&mp->outlock); + + handle_minor_recv(mp); } static int capinc_tty_write_room(struct tty_struct *tty) { - struct capiminor *mp = (struct capiminor *)tty->driver_data; + struct capiminor *mp = tty->driver_data; int room; - if (!mp || !mp->nccip) { -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_write_room: mp or mp->ncci NULL\n"); -#endif - return 0; - } + room = CAPINC_MAX_SENDQUEUE-skb_queue_len(&mp->outqueue); room *= CAPI_MAX_BLKSIZE; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_write_room = %d\n", room); -#endif + pr_debug("capinc_tty_write_room = %d\n", room); return room; } static int capinc_tty_chars_in_buffer(struct tty_struct *tty) { - struct capiminor *mp = (struct capiminor *)tty->driver_data; - if (!mp || !mp->nccip) { -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_chars_in_buffer: mp or mp->ncci NULL\n"); -#endif - return 0; - } -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_chars_in_buffer = %d nack=%d sq=%d rq=%d\n", - mp->outbytes, mp->nack, - skb_queue_len(&mp->outqueue), - skb_queue_len(&mp->inqueue)); -#endif + struct capiminor *mp = tty->driver_data; + + pr_debug("capinc_tty_chars_in_buffer = %d nack=%d sq=%d rq=%d\n", + mp->outbytes, mp->nack, + skb_queue_len(&mp->outqueue), + skb_queue_len(&mp->inqueue)); return mp->outbytes; } -static int capinc_tty_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) +static int capinc_tty_ioctl(struct tty_struct *tty, + unsigned int cmd, unsigned long arg) { - int error = 0; - switch (cmd) { - default: - error = n_tty_ioctl_helper(tty, file, cmd, arg); - break; - } - return error; + return -ENOIOCTLCMD; } -static void capinc_tty_set_termios(struct tty_struct *tty, struct ktermios * old) +static void capinc_tty_set_termios(struct tty_struct *tty, struct ktermios *old) { -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_set_termios\n"); -#endif + pr_debug("capinc_tty_set_termios\n"); } -static void capinc_tty_throttle(struct tty_struct * tty) +static void capinc_tty_throttle(struct tty_struct *tty) { - struct capiminor *mp = (struct capiminor *)tty->driver_data; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_throttle\n"); -#endif - if (mp) - mp->ttyinstop = 1; + struct capiminor *mp = tty->driver_data; + pr_debug("capinc_tty_throttle\n"); + mp->ttyinstop = 1; } -static void capinc_tty_unthrottle(struct tty_struct * tty) +static void capinc_tty_unthrottle(struct tty_struct *tty) { - struct capiminor *mp = (struct capiminor *)tty->driver_data; - unsigned long flags; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_unthrottle\n"); -#endif - if (mp) { - spin_lock_irqsave(&workaround_lock, flags); - mp->ttyinstop = 0; - handle_minor_recv(mp); - spin_unlock_irqrestore(&workaround_lock, flags); - } + struct capiminor *mp = tty->driver_data; + + pr_debug("capinc_tty_unthrottle\n"); + mp->ttyinstop = 0; + handle_minor_recv(mp); } static void capinc_tty_stop(struct tty_struct *tty) { - struct capiminor *mp = (struct capiminor *)tty->driver_data; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_stop\n"); -#endif - if (mp) { - mp->ttyoutstop = 1; - } + struct capiminor *mp = tty->driver_data; + + pr_debug("capinc_tty_stop\n"); + mp->ttyoutstop = 1; } static void capinc_tty_start(struct tty_struct *tty) { - struct capiminor *mp = (struct capiminor *)tty->driver_data; - unsigned long flags; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_start\n"); -#endif - if (mp) { - spin_lock_irqsave(&workaround_lock, flags); - mp->ttyoutstop = 0; - (void)handle_minor_send(mp); - spin_unlock_irqrestore(&workaround_lock, flags); - } + struct capiminor *mp = tty->driver_data; + + pr_debug("capinc_tty_start\n"); + mp->ttyoutstop = 0; + handle_minor_send(mp); } static void capinc_tty_hangup(struct tty_struct *tty) { -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_hangup\n"); -#endif + struct capiminor *mp = tty->driver_data; + + pr_debug("capinc_tty_hangup\n"); + tty_port_hangup(&mp->port); } static int capinc_tty_break_ctl(struct tty_struct *tty, int state) { -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_break_ctl(%d)\n", state); -#endif + pr_debug("capinc_tty_break_ctl(%d)\n", state); return 0; } static void capinc_tty_flush_buffer(struct tty_struct *tty) { -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_flush_buffer\n"); -#endif + pr_debug("capinc_tty_flush_buffer\n"); } static void capinc_tty_set_ldisc(struct tty_struct *tty) { -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_set_ldisc\n"); -#endif + pr_debug("capinc_tty_set_ldisc\n"); } static void capinc_tty_send_xchar(struct tty_struct *tty, char ch) { -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_send_xchar(%d)\n", ch); -#endif -} - -static int capinc_tty_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - return 0; + pr_debug("capinc_tty_send_xchar(%d)\n", ch); } -static struct tty_driver *capinc_tty_driver; - static const struct tty_operations capinc_ops = { .open = capinc_tty_open, .close = capinc_tty_close, @@ -1358,26 +1246,33 @@ static const struct tty_operations capinc_ops = { .flush_buffer = capinc_tty_flush_buffer, .set_ldisc = capinc_tty_set_ldisc, .send_xchar = capinc_tty_send_xchar, - .read_proc = capinc_tty_read_proc, + .install = capinc_tty_install, + .cleanup = capinc_tty_cleanup, }; -static int capinc_tty_init(void) +static int __init capinc_tty_init(void) { struct tty_driver *drv; - + int err; + if (capi_ttyminors > CAPINC_MAX_PORTS) capi_ttyminors = CAPINC_MAX_PORTS; if (capi_ttyminors <= 0) capi_ttyminors = CAPINC_NR_PORTS; - drv = alloc_tty_driver(capi_ttyminors); - if (!drv) + capiminors = kzalloc(sizeof(struct capi_minor *) * capi_ttyminors, + GFP_KERNEL); + if (!capiminors) return -ENOMEM; - drv->owner = THIS_MODULE; + drv = alloc_tty_driver(capi_ttyminors); + if (!drv) { + kfree(capiminors); + return -ENOMEM; + } drv->driver_name = "capi_nc"; - drv->name = "capi"; - drv->major = capi_ttymajor; + drv->name = "capi!"; + drv->major = 0; drv->minor_start = 0; drv->type = TTY_DRIVER_TYPE_SERIAL; drv->subtype = SERIAL_TYPE_NORMAL; @@ -1386,27 +1281,39 @@ static int capinc_tty_init(void) drv->init_termios.c_oflag = OPOST | ONLCR; drv->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; drv->init_termios.c_lflag = 0; - drv->flags = TTY_DRIVER_REAL_RAW|TTY_DRIVER_RESET_TERMIOS; + drv->flags = + TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS | + TTY_DRIVER_DYNAMIC_DEV; tty_set_operations(drv, &capinc_ops); - if (tty_register_driver(drv)) { + + err = tty_register_driver(drv); + if (err) { put_tty_driver(drv); + kfree(capiminors); printk(KERN_ERR "Couldn't register capi_nc driver\n"); - return -1; + return err; } capinc_tty_driver = drv; return 0; } -static void capinc_tty_exit(void) +static void __exit capinc_tty_exit(void) { - struct tty_driver *drv = capinc_tty_driver; - int retval; - if ((retval = tty_unregister_driver(drv))) - printk(KERN_ERR "capi: failed to unregister capi_nc driver (%d)\n", retval); - put_tty_driver(drv); + tty_unregister_driver(capinc_tty_driver); + put_tty_driver(capinc_tty_driver); + kfree(capiminors); } -#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ +#else /* !CONFIG_ISDN_CAPI_MIDDLEWARE */ + +static inline int capinc_tty_init(void) +{ + return 0; +} + +static inline void capinc_tty_exit(void) { } + +#endif /* !CONFIG_ISDN_CAPI_MIDDLEWARE */ /* -------- /proc functions ----------------------------------------- */ @@ -1414,134 +1321,91 @@ static void capinc_tty_exit(void) * /proc/capi/capi20: * minor applid nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt */ -static int proc_capidev_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int capi20_proc_show(struct seq_file *m, void *v) { - struct capidev *cdev; + struct capidev *cdev; struct list_head *l; - int len = 0; - read_lock(&capidev_list_lock); + mutex_lock(&capidev_list_lock); list_for_each(l, &capidev_list) { cdev = list_entry(l, struct capidev, list); - len += sprintf(page+len, "0 %d %lu %lu %lu %lu\n", - cdev->ap.applid, - cdev->ap.nrecvctlpkt, - cdev->ap.nrecvdatapkt, - cdev->ap.nsentctlpkt, - cdev->ap.nsentdatapkt); - if (len <= off) { - off -= len; - len = 0; - } else { - if (len-off > count) - goto endloop; - } + seq_printf(m, "0 %d %lu %lu %lu %lu\n", + cdev->ap.applid, + cdev->ap.nrecvctlpkt, + cdev->ap.nrecvdatapkt, + cdev->ap.nsentctlpkt, + cdev->ap.nsentdatapkt); } + mutex_unlock(&capidev_list_lock); + return 0; +} -endloop: - read_unlock(&capidev_list_lock); - if (len < count) - *eof = 1; - if (len > count) len = count; - if (len < 0) len = 0; - return len; +static int capi20_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, capi20_proc_show, NULL); } +static const struct file_operations capi20_proc_fops = { + .owner = THIS_MODULE, + .open = capi20_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /* * /proc/capi/capi20ncci: * applid ncci */ -static int proc_capincci_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int capi20ncci_proc_show(struct seq_file *m, void *v) { - struct capidev *cdev; - struct capincci *np; - struct list_head *l; - int len = 0; + struct capidev *cdev; + struct capincci *np; - read_lock(&capidev_list_lock); - list_for_each(l, &capidev_list) { - cdev = list_entry(l, struct capidev, list); - for (np=cdev->nccis; np; np = np->next) { - len += sprintf(page+len, "%d 0x%x\n", - cdev->ap.applid, - np->ncci); - if (len <= off) { - off -= len; - len = 0; - } else { - if (len-off > count) - goto endloop; - } - } + mutex_lock(&capidev_list_lock); + list_for_each_entry(cdev, &capidev_list, list) { + mutex_lock(&cdev->lock); + list_for_each_entry(np, &cdev->nccis, list) + seq_printf(m, "%d 0x%x\n", cdev->ap.applid, np->ncci); + mutex_unlock(&cdev->lock); } -endloop: - read_unlock(&capidev_list_lock); - *start = page+off; - if (len < count) - *eof = 1; - if (len>count) len = count; - if (len<0) len = 0; - return len; + mutex_unlock(&capidev_list_lock); + return 0; } -static struct procfsentries { - char *name; - mode_t mode; - int (*read_proc)(char *page, char **start, off_t off, - int count, int *eof, void *data); - struct proc_dir_entry *procent; -} procfsentries[] = { - /* { "capi", S_IFDIR, 0 }, */ - { "capi/capi20", 0 , proc_capidev_read_proc }, - { "capi/capi20ncci", 0 , proc_capincci_read_proc }, +static int capi20ncci_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, capi20ncci_proc_show, NULL); +} + +static const struct file_operations capi20ncci_proc_fops = { + .owner = THIS_MODULE, + .open = capi20ncci_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, }; static void __init proc_init(void) { - int nelem = ARRAY_SIZE(procfsentries); - int i; - - for (i=0; i < nelem; i++) { - struct procfsentries *p = procfsentries + i; - p->procent = create_proc_entry(p->name, p->mode, NULL); - if (p->procent) p->procent->read_proc = p->read_proc; - } + proc_create("capi/capi20", 0, NULL, &capi20_proc_fops); + proc_create("capi/capi20ncci", 0, NULL, &capi20ncci_proc_fops); } static void __exit proc_exit(void) { - int nelem = ARRAY_SIZE(procfsentries); - int i; - - for (i=nelem-1; i >= 0; i--) { - struct procfsentries *p = procfsentries + i; - if (p->procent) { - remove_proc_entry(p->name, NULL); - p->procent = NULL; - } - } + remove_proc_entry("capi/capi20", NULL); + remove_proc_entry("capi/capi20ncci", NULL); } /* -------- init function and module interface ---------------------- */ -static char rev[32]; - static int __init capi_init(void) { - char *p; - char *compileinfo; + const char *compileinfo; int major_ret; - if ((p = strchr(revision, ':')) != NULL && p[1]) { - strlcpy(rev, p + 2, sizeof(rev)); - if ((p = strchr(rev, '$')) != NULL && p > rev) - *(p-1) = 0; - } else - strcpy(rev, "1.0"); - major_ret = register_chrdev(capi_major, "capi20", &capi_fops); if (major_ret < 0) { printk(KERN_ERR "capi20: unable to get major %d\n", capi_major); @@ -1553,30 +1417,24 @@ static int __init capi_init(void) return PTR_ERR(capi_class); } - device_create(capi_class, NULL, MKDEV(capi_major, 0), NULL, "capi"); + device_create(capi_class, NULL, MKDEV(capi_major, 0), NULL, "capi20"); -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE if (capinc_tty_init() < 0) { device_destroy(capi_class, MKDEV(capi_major, 0)); class_destroy(capi_class); unregister_chrdev(capi_major, "capi20"); return -ENOMEM; } -#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ proc_init(); #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE -#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE) - compileinfo = " (middleware+capifs)"; -#else - compileinfo = " (no capifs)"; -#endif + compileinfo = " (middleware)"; #else - compileinfo = " (no middleware)"; + compileinfo = " (no middleware)"; #endif - printk(KERN_NOTICE "capi20: Rev %s: started up with major %d%s\n", - rev, capi_major, compileinfo); + printk(KERN_NOTICE "CAPI 2.0 started up with major %d%s\n", + capi_major, compileinfo); return 0; } @@ -1589,10 +1447,7 @@ static void __exit capi_exit(void) class_destroy(capi_class); unregister_chrdev(capi_major, "capi20"); -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE capinc_tty_exit(); -#endif - printk(KERN_NOTICE "capi: Rev %s: unloaded\n", rev); } module_init(capi_init); diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c index 650120261ab..fd6d28f3fc3 100644 --- a/drivers/isdn/capi/capidrv.c +++ b/drivers/isdn/capi/capidrv.c @@ -24,6 +24,7 @@ #include <linux/isdn.h> #include <linux/isdnif.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <linux/capi.h> #include <linux/kernelcapi.h> #include <linux/ctype.h> @@ -34,13 +35,12 @@ #include <linux/isdn/capicmd.h> #include "capidrv.h" -static char *revision = "$Revision: 1.1.2.2 $"; static int debugmode = 0; MODULE_DESCRIPTION("CAPI4Linux: Interface to ISDN4Linux"); MODULE_AUTHOR("Carsten Paeth"); MODULE_LICENSE("GPL"); -module_param(debugmode, uint, 0); +module_param(debugmode, uint, S_IRUGO | S_IWUSR); /* -------- type definitions ----------------------------------------- */ @@ -64,7 +64,7 @@ struct capidrv_contr { int state; u32 cipmask; u32 cipmask2; - struct timer_list listentimer; + struct timer_list listentimer; /* * ID of capi message sent @@ -105,9 +105,9 @@ struct capidrv_contr { /* */ u16 datahandle; struct ncci_datahandle_queue { - struct ncci_datahandle_queue *next; - u16 datahandle; - int len; + struct ncci_datahandle_queue *next; + u16 datahandle; + int len; } *ackqueue; } *ncci_list; } *plcip; @@ -142,7 +142,7 @@ static capidrv_data global; static DEFINE_SPINLOCK(global_lock); static void handle_dtrace_data(capidrv_contr *card, - int send, int level2, u8 *data, u16 len); + int send, int level2, u8 *data, u16 len); /* -------- convert functions ---------------------------------------- */ @@ -158,11 +158,11 @@ static inline u32 b1prot(int l2, int l3) return 0; case ISDN_PROTO_L2_TRANS: return 1; - case ISDN_PROTO_L2_V11096: - case ISDN_PROTO_L2_V11019: - case ISDN_PROTO_L2_V11038: + case ISDN_PROTO_L2_V11096: + case ISDN_PROTO_L2_V11019: + case ISDN_PROTO_L2_V11038: return 2; - case ISDN_PROTO_L2_FAX: + case ISDN_PROTO_L2_FAX: return 4; case ISDN_PROTO_L2_MODEM: return 8; @@ -179,12 +179,12 @@ static inline u32 b2prot(int l2, int l3) return 0; case ISDN_PROTO_L2_HDLC: case ISDN_PROTO_L2_TRANS: - case ISDN_PROTO_L2_V11096: - case ISDN_PROTO_L2_V11019: - case ISDN_PROTO_L2_V11038: + case ISDN_PROTO_L2_V11096: + case ISDN_PROTO_L2_V11019: + case ISDN_PROTO_L2_V11038: case ISDN_PROTO_L2_MODEM: return 1; - case ISDN_PROTO_L2_FAX: + case ISDN_PROTO_L2_FAX: return 4; } } @@ -197,13 +197,13 @@ static inline u32 b3prot(int l2, int l3) case ISDN_PROTO_L2_X75BUI: case ISDN_PROTO_L2_HDLC: case ISDN_PROTO_L2_TRANS: - case ISDN_PROTO_L2_V11096: - case ISDN_PROTO_L2_V11019: - case ISDN_PROTO_L2_V11038: + case ISDN_PROTO_L2_V11096: + case ISDN_PROTO_L2_V11019: + case ISDN_PROTO_L2_V11038: case ISDN_PROTO_L2_MODEM: default: return 0; - case ISDN_PROTO_L2_FAX: + case ISDN_PROTO_L2_FAX: return 4; } } @@ -231,38 +231,38 @@ static _cstruct b1config(int l2, int l3) case ISDN_PROTO_L2_TRANS: default: return NULL; - case ISDN_PROTO_L2_V11096: - return b1config_async_v110(9600); - case ISDN_PROTO_L2_V11019: - return b1config_async_v110(19200); - case ISDN_PROTO_L2_V11038: - return b1config_async_v110(38400); + case ISDN_PROTO_L2_V11096: + return b1config_async_v110(9600); + case ISDN_PROTO_L2_V11019: + return b1config_async_v110(19200); + case ISDN_PROTO_L2_V11038: + return b1config_async_v110(38400); } } static inline u16 si2cip(u8 si1, u8 si2) { static const u8 cip[17][5] = - { - /* 0 1 2 3 4 */ - {0, 0, 0, 0, 0}, /*0 */ - {16, 16, 4, 26, 16}, /*1 */ - {17, 17, 17, 4, 4}, /*2 */ - {2, 2, 2, 2, 2}, /*3 */ - {18, 18, 18, 18, 18}, /*4 */ - {2, 2, 2, 2, 2}, /*5 */ - {0, 0, 0, 0, 0}, /*6 */ - {2, 2, 2, 2, 2}, /*7 */ - {2, 2, 2, 2, 2}, /*8 */ - {21, 21, 21, 21, 21}, /*9 */ - {19, 19, 19, 19, 19}, /*10 */ - {0, 0, 0, 0, 0}, /*11 */ - {0, 0, 0, 0, 0}, /*12 */ - {0, 0, 0, 0, 0}, /*13 */ - {0, 0, 0, 0, 0}, /*14 */ - {22, 22, 22, 22, 22}, /*15 */ - {27, 27, 27, 28, 27} /*16 */ - }; + { + /* 0 1 2 3 4 */ + {0, 0, 0, 0, 0}, /*0 */ + {16, 16, 4, 26, 16}, /*1 */ + {17, 17, 17, 4, 4}, /*2 */ + {2, 2, 2, 2, 2}, /*3 */ + {18, 18, 18, 18, 18}, /*4 */ + {2, 2, 2, 2, 2}, /*5 */ + {0, 0, 0, 0, 0}, /*6 */ + {2, 2, 2, 2, 2}, /*7 */ + {2, 2, 2, 2, 2}, /*8 */ + {21, 21, 21, 21, 21}, /*9 */ + {19, 19, 19, 19, 19}, /*10 */ + {0, 0, 0, 0, 0}, /*11 */ + {0, 0, 0, 0, 0}, /*12 */ + {0, 0, 0, 0, 0}, /*13 */ + {0, 0, 0, 0, 0}, /*14 */ + {22, 22, 22, 22, 22}, /*15 */ + {27, 27, 27, 28, 27} /*16 */ + }; if (si1 > 16) si1 = 0; if (si2 > 4) @@ -274,10 +274,10 @@ static inline u16 si2cip(u8 si1, u8 si2) static inline u8 cip2si1(u16 cipval) { static const u8 si[32] = - {7, 1, 7, 7, 1, 1, 7, 7, /*0-7 */ - 7, 1, 0, 0, 0, 0, 0, 0, /*8-15 */ - 1, 2, 4, 10, 9, 9, 15, 7, /*16-23 */ - 7, 7, 1, 16, 16, 0, 0, 0}; /*24-31 */ + {7, 1, 7, 7, 1, 1, 7, 7, /*0-7 */ + 7, 1, 0, 0, 0, 0, 0, 0, /*8-15 */ + 1, 2, 4, 10, 9, 9, 15, 7, /*16-23 */ + 7, 7, 1, 16, 16, 0, 0, 0}; /*24-31 */ if (cipval > 31) cipval = 0; /* .... */ @@ -287,10 +287,10 @@ static inline u8 cip2si1(u16 cipval) static inline u8 cip2si2(u16 cipval) { static const u8 si[32] = - {0, 0, 0, 0, 2, 3, 0, 0, /*0-7 */ - 0, 3, 0, 0, 0, 0, 0, 0, /*8-15 */ - 1, 2, 0, 0, 9, 0, 0, 0, /*16-23 */ - 0, 0, 3, 2, 3, 0, 0, 0}; /*24-31 */ + {0, 0, 0, 0, 2, 3, 0, 0, /*0-7 */ + 0, 3, 0, 0, 0, 0, 0, 0, /*8-15 */ + 1, 2, 0, 0, 9, 0, 0, 0, /*16-23 */ + 0, 0, 3, 2, 3, 0, 0, 0}; /*24-31 */ if (cipval > 31) cipval = 0; /* .... */ @@ -302,7 +302,7 @@ static inline u8 cip2si2(u16 cipval) static inline capidrv_contr *findcontrbydriverid(int driverid) { - unsigned long flags; + unsigned long flags; capidrv_contr *p; spin_lock_irqsave(&global_lock, flags); @@ -329,7 +329,7 @@ static capidrv_contr *findcontrbynumber(u32 contr) /* -------- plci management ------------------------------------------ */ -static capidrv_plci *new_plci(capidrv_contr * card, int chan) +static capidrv_plci *new_plci(capidrv_contr *card, int chan) { capidrv_plci *plcip; @@ -349,7 +349,7 @@ static capidrv_plci *new_plci(capidrv_contr * card, int chan) return plcip; } -static capidrv_plci *find_plci_by_plci(capidrv_contr * card, u32 plci) +static capidrv_plci *find_plci_by_plci(capidrv_contr *card, u32 plci) { capidrv_plci *p; for (p = card->plci_list; p; p = p->next) @@ -358,7 +358,7 @@ static capidrv_plci *find_plci_by_plci(capidrv_contr * card, u32 plci) return NULL; } -static capidrv_plci *find_plci_by_msgid(capidrv_contr * card, u16 msgid) +static capidrv_plci *find_plci_by_msgid(capidrv_contr *card, u16 msgid) { capidrv_plci *p; for (p = card->plci_list; p; p = p->next) @@ -367,7 +367,7 @@ static capidrv_plci *find_plci_by_msgid(capidrv_contr * card, u16 msgid) return NULL; } -static capidrv_plci *find_plci_by_ncci(capidrv_contr * card, u32 ncci) +static capidrv_plci *find_plci_by_ncci(capidrv_contr *card, u32 ncci) { capidrv_plci *p; for (p = card->plci_list; p; p = p->next) @@ -376,7 +376,7 @@ static capidrv_plci *find_plci_by_ncci(capidrv_contr * card, u32 ncci) return NULL; } -static void free_plci(capidrv_contr * card, capidrv_plci * plcip) +static void free_plci(capidrv_contr *card, capidrv_plci *plcip) { capidrv_plci **pp; @@ -396,8 +396,8 @@ static void free_plci(capidrv_contr * card, capidrv_plci * plcip) /* -------- ncci management ------------------------------------------ */ -static inline capidrv_ncci *new_ncci(capidrv_contr * card, - capidrv_plci * plcip, +static inline capidrv_ncci *new_ncci(capidrv_contr *card, + capidrv_plci *plcip, u32 ncci) { capidrv_ncci *nccip; @@ -421,7 +421,7 @@ static inline capidrv_ncci *new_ncci(capidrv_contr * card, return nccip; } -static inline capidrv_ncci *find_ncci(capidrv_contr * card, u32 ncci) +static inline capidrv_ncci *find_ncci(capidrv_contr *card, u32 ncci) { capidrv_plci *plcip; capidrv_ncci *p; @@ -435,7 +435,7 @@ static inline capidrv_ncci *find_ncci(capidrv_contr * card, u32 ncci) return NULL; } -static inline capidrv_ncci *find_ncci_by_msgid(capidrv_contr * card, +static inline capidrv_ncci *find_ncci_by_msgid(capidrv_contr *card, u32 ncci, u16 msgid) { capidrv_plci *plcip; @@ -450,7 +450,7 @@ static inline capidrv_ncci *find_ncci_by_msgid(capidrv_contr * card, return NULL; } -static void free_ncci(capidrv_contr * card, struct capidrv_ncci *nccip) +static void free_ncci(capidrv_contr *card, struct capidrv_ncci *nccip) { struct capidrv_ncci **pp; @@ -465,20 +465,19 @@ static void free_ncci(capidrv_contr * card, struct capidrv_ncci *nccip) } static int capidrv_add_ack(struct capidrv_ncci *nccip, - u16 datahandle, int len) + u16 datahandle, int len) { struct ncci_datahandle_queue *n, **pp; - n = (struct ncci_datahandle_queue *) - kmalloc(sizeof(struct ncci_datahandle_queue), GFP_ATOMIC); + n = kmalloc(sizeof(struct ncci_datahandle_queue), GFP_ATOMIC); if (!n) { - printk(KERN_ERR "capidrv: kmalloc ncci_datahandle failed\n"); - return -1; + printk(KERN_ERR "capidrv: kmalloc ncci_datahandle failed\n"); + return -1; } n->next = NULL; n->datahandle = datahandle; n->len = len; - for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) ; + for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next); *pp = n; return 0; } @@ -489,11 +488,11 @@ static int capidrv_del_ack(struct capidrv_ncci *nccip, u16 datahandle) int len; for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) { - if ((*pp)->datahandle == datahandle) { + if ((*pp)->datahandle == datahandle) { p = *pp; len = p->len; *pp = (*pp)->next; - kfree(p); + kfree(p); return len; } } @@ -502,7 +501,7 @@ static int capidrv_del_ack(struct capidrv_ncci *nccip, u16 datahandle) /* -------- convert and send capi message ---------------------------- */ -static void send_message(capidrv_contr * card, _cmsg * cmsg) +static void send_message(capidrv_contr *card, _cmsg *cmsg) { struct sk_buff *skb; size_t len; @@ -529,18 +528,18 @@ struct listenstatechange { static struct listenstatechange listentable[] = { - {ST_LISTEN_NONE, ST_LISTEN_WAIT_CONF, EV_LISTEN_REQ}, - {ST_LISTEN_ACTIVE, ST_LISTEN_ACTIVE_WAIT_CONF, EV_LISTEN_REQ}, - {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_ERROR}, - {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_ERROR}, - {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY}, - {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY}, - {ST_LISTEN_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK}, - {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK}, - {}, + {ST_LISTEN_NONE, ST_LISTEN_WAIT_CONF, EV_LISTEN_REQ}, + {ST_LISTEN_ACTIVE, ST_LISTEN_ACTIVE_WAIT_CONF, EV_LISTEN_REQ}, + {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_ERROR}, + {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_ERROR}, + {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY}, + {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY}, + {ST_LISTEN_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK}, + {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK}, + {}, }; -static void listen_change_state(capidrv_contr * card, int event) +static void listen_change_state(capidrv_contr *card, int event) { struct listenstatechange *p = listentable; while (p->event) { @@ -560,7 +559,7 @@ static void listen_change_state(capidrv_contr * card, int event) /* ------------------------------------------------------------------ */ -static void p0(capidrv_contr * card, capidrv_plci * plci) +static void p0(capidrv_contr *card, capidrv_plci *plci) { isdn_ctrl cmd; @@ -578,71 +577,71 @@ struct plcistatechange { int actstate; int nextstate; int event; - void (*changefunc) (capidrv_contr * card, capidrv_plci * plci); + void (*changefunc)(capidrv_contr *card, capidrv_plci *plci); }; static struct plcistatechange plcitable[] = { - /* P-0 */ - {ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, NULL}, - {ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, NULL}, - {ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, NULL}, - {ST_PLCI_NONE, ST_PLCI_RESUMEING, EV_PLCI_RESUME_REQ, NULL}, - /* P-0.1 */ - {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0}, - {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, NULL}, - /* P-1 */ - {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, NULL}, - {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL}, - {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL}, - {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, - /* P-ACT */ - {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL}, - {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL}, - {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, - {ST_PLCI_ACTIVE, ST_PLCI_HELD, EV_PLCI_HOLD_IND, NULL}, - {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_SUSPEND_IND, NULL}, - /* P-2 */ - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, NULL}, - {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, NULL}, - {ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, NULL}, - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL}, - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL}, - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CD_IND, NULL}, - /* P-3 */ - {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, NULL}, - {ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, NULL}, - {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL}, - {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL}, - {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, - /* P-4 */ - {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, NULL}, - {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL}, - {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL}, - {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, - /* P-5 */ - {ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, - /* P-6 */ - {ST_PLCI_DISCONNECTED, ST_PLCI_NONE, EV_PLCI_DISCONNECT_RESP, p0}, - /* P-0.Res */ - {ST_PLCI_RESUMEING, ST_PLCI_NONE, EV_PLCI_RESUME_CONF_ERROR, p0}, - {ST_PLCI_RESUMEING, ST_PLCI_RESUME, EV_PLCI_RESUME_CONF_OK, NULL}, - /* P-RES */ - {ST_PLCI_RESUME, ST_PLCI_ACTIVE, EV_PLCI_RESUME_IND, NULL}, - /* P-HELD */ - {ST_PLCI_HELD, ST_PLCI_ACTIVE, EV_PLCI_RETRIEVE_IND, NULL}, - {}, + /* P-0 */ + {ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, NULL}, + {ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, NULL}, + {ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, NULL}, + {ST_PLCI_NONE, ST_PLCI_RESUMEING, EV_PLCI_RESUME_REQ, NULL}, + /* P-0.1 */ + {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0}, + {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, NULL}, + /* P-1 */ + {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, NULL}, + {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL}, + {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL}, + {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, + /* P-ACT */ + {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL}, + {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL}, + {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, + {ST_PLCI_ACTIVE, ST_PLCI_HELD, EV_PLCI_HOLD_IND, NULL}, + {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_SUSPEND_IND, NULL}, + /* P-2 */ + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, NULL}, + {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, NULL}, + {ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, NULL}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CD_IND, NULL}, + /* P-3 */ + {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, NULL}, + {ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, NULL}, + {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL}, + {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL}, + {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, + /* P-4 */ + {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, NULL}, + {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL}, + {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL}, + {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, + /* P-5 */ + {ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, + /* P-6 */ + {ST_PLCI_DISCONNECTED, ST_PLCI_NONE, EV_PLCI_DISCONNECT_RESP, p0}, + /* P-0.Res */ + {ST_PLCI_RESUMEING, ST_PLCI_NONE, EV_PLCI_RESUME_CONF_ERROR, p0}, + {ST_PLCI_RESUMEING, ST_PLCI_RESUME, EV_PLCI_RESUME_CONF_OK, NULL}, + /* P-RES */ + {ST_PLCI_RESUME, ST_PLCI_ACTIVE, EV_PLCI_RESUME_IND, NULL}, + /* P-HELD */ + {ST_PLCI_HELD, ST_PLCI_ACTIVE, EV_PLCI_RETRIEVE_IND, NULL}, + {}, }; -static void plci_change_state(capidrv_contr * card, capidrv_plci * plci, int event) +static void plci_change_state(capidrv_contr *card, capidrv_plci *plci, int event) { struct plcistatechange *p = plcitable; while (p->event) { if (plci->state == p->actstate && p->event == event) { if (debugmode) printk(KERN_DEBUG "capidrv-%d: plci_change_state:0x%x %d -> %d\n", - card->contrnr, plci->plci, plci->state, p->nextstate); + card->contrnr, plci->plci, plci->state, p->nextstate); plci->state = p->nextstate; if (p->changefunc) p->changefunc(card, plci); @@ -658,7 +657,7 @@ static void plci_change_state(capidrv_contr * card, capidrv_plci * plci, int eve static _cmsg cmsg; -static void n0(capidrv_contr * card, capidrv_ncci * ncci) +static void n0(capidrv_contr *card, capidrv_ncci *ncci) { isdn_ctrl cmd; @@ -670,9 +669,9 @@ static void n0(capidrv_contr * card, capidrv_ncci * ncci) NULL, /* Keypadfacility */ NULL, /* Useruserdata */ /* $$$$ */ NULL /* Facilitydataarray */ - ); - send_message(card, &cmsg); + ); plci_change_state(card, ncci->plcip, EV_PLCI_DISCONNECT_REQ); + send_message(card, &cmsg); cmd.command = ISDN_STAT_BHUP; cmd.driver = card->myid; @@ -687,51 +686,51 @@ struct nccistatechange { int actstate; int nextstate; int event; - void (*changefunc) (capidrv_contr * card, capidrv_ncci * ncci); + void (*changefunc)(capidrv_contr *card, capidrv_ncci *ncci); }; static struct nccistatechange nccitable[] = { - /* N-0 */ - {ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, NULL}, - {ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, NULL}, - /* N-0.1 */ - {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, NULL}, - {ST_NCCI_OUTGOING, ST_NCCI_NONE, EV_NCCI_CONNECT_B3_CONF_ERROR, n0}, - /* N-1 */ - {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, NULL}, - {ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, NULL}, - {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL}, - {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL}, - /* N-2 */ - {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, NULL}, - {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL}, - {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL}, - /* N-ACT */ - {ST_NCCI_ACTIVE, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, NULL}, - {ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, NULL}, - {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL}, - {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL}, - /* N-3 */ - {ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, NULL}, - {ST_NCCI_RESETING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL}, - {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL}, - /* N-4 */ - {ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL}, - {ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR,NULL}, - /* N-5 */ - {ST_NCCI_DISCONNECTED, ST_NCCI_NONE, EV_NCCI_DISCONNECT_B3_RESP, n0}, - {}, + /* N-0 */ + {ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, NULL}, + {ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, NULL}, + /* N-0.1 */ + {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, NULL}, + {ST_NCCI_OUTGOING, ST_NCCI_NONE, EV_NCCI_CONNECT_B3_CONF_ERROR, n0}, + /* N-1 */ + {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, NULL}, + {ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, NULL}, + {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL}, + {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL}, + /* N-2 */ + {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, NULL}, + {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL}, + {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL}, + /* N-ACT */ + {ST_NCCI_ACTIVE, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, NULL}, + {ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, NULL}, + {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL}, + {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL}, + /* N-3 */ + {ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, NULL}, + {ST_NCCI_RESETING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL}, + {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL}, + /* N-4 */ + {ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL}, + {ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR, NULL}, + /* N-5 */ + {ST_NCCI_DISCONNECTED, ST_NCCI_NONE, EV_NCCI_DISCONNECT_B3_RESP, n0}, + {}, }; -static void ncci_change_state(capidrv_contr * card, capidrv_ncci * ncci, int event) +static void ncci_change_state(capidrv_contr *card, capidrv_ncci *ncci, int event) { struct nccistatechange *p = nccitable; while (p->event) { if (ncci->state == p->actstate && p->event == event) { if (debugmode) printk(KERN_DEBUG "capidrv-%d: ncci_change_state:0x%x %d -> %d\n", - card->contrnr, ncci->ncci, ncci->state, p->nextstate); + card->contrnr, ncci->ncci, ncci->state, p->nextstate); if (p->nextstate == ST_NCCI_PREVIOUS) { ncci->state = ncci->oldstate; ncci->oldstate = p->actstate; @@ -751,7 +750,7 @@ static void ncci_change_state(capidrv_contr * card, capidrv_ncci * ncci, int eve /* ------------------------------------------------------------------- */ -static inline int new_bchan(capidrv_contr * card) +static inline int new_bchan(capidrv_contr *card) { int i; for (i = 0; i < card->nbchan; i++) { @@ -764,8 +763,203 @@ static inline int new_bchan(capidrv_contr * card) } /* ------------------------------------------------------------------- */ +static char *capi_info2str(u16 reason) +{ +#ifndef CONFIG_ISDN_CAPI_CAPIDRV_VERBOSE + return ".."; +#else + switch (reason) { + +/*-- informative values (corresponding message was processed) -----*/ + case 0x0001: + return "NCPI not supported by current protocol, NCPI ignored"; + case 0x0002: + return "Flags not supported by current protocol, flags ignored"; + case 0x0003: + return "Alert already sent by another application"; + +/*-- error information concerning CAPI_REGISTER -----*/ + case 0x1001: + return "Too many applications"; + case 0x1002: + return "Logical block size too small, must be at least 128 Bytes"; + case 0x1003: + return "Buffer exceeds 64 kByte"; + case 0x1004: + return "Message buffer size too small, must be at least 1024 Bytes"; + case 0x1005: + return "Max. number of logical connections not supported"; + case 0x1006: + return "Reserved"; + case 0x1007: + return "The message could not be accepted because of an internal busy condition"; + case 0x1008: + return "OS resource error (no memory ?)"; + case 0x1009: + return "CAPI not installed"; + case 0x100A: + return "Controller does not support external equipment"; + case 0x100B: + return "Controller does only support external equipment"; + +/*-- error information concerning message exchange functions -----*/ + case 0x1101: + return "Illegal application number"; + case 0x1102: + return "Illegal command or subcommand or message length less than 12 bytes"; + case 0x1103: + return "The message could not be accepted because of a queue full condition !! The error code does not imply that CAPI cannot receive messages directed to another controller, PLCI or NCCI"; + case 0x1104: + return "Queue is empty"; + case 0x1105: + return "Queue overflow, a message was lost !! This indicates a configuration error. The only recovery from this error is to perform a CAPI_RELEASE"; + case 0x1106: + return "Unknown notification parameter"; + case 0x1107: + return "The Message could not be accepted because of an internal busy condition"; + case 0x1108: + return "OS Resource error (no memory ?)"; + case 0x1109: + return "CAPI not installed"; + case 0x110A: + return "Controller does not support external equipment"; + case 0x110B: + return "Controller does only support external equipment"; + +/*-- error information concerning resource / coding problems -----*/ + case 0x2001: + return "Message not supported in current state"; + case 0x2002: + return "Illegal Controller / PLCI / NCCI"; + case 0x2003: + return "Out of PLCI"; + case 0x2004: + return "Out of NCCI"; + case 0x2005: + return "Out of LISTEN"; + case 0x2006: + return "Out of FAX resources (protocol T.30)"; + case 0x2007: + return "Illegal message parameter coding"; + +/*-- error information concerning requested services -----*/ + case 0x3001: + return "B1 protocol not supported"; + case 0x3002: + return "B2 protocol not supported"; + case 0x3003: + return "B3 protocol not supported"; + case 0x3004: + return "B1 protocol parameter not supported"; + case 0x3005: + return "B2 protocol parameter not supported"; + case 0x3006: + return "B3 protocol parameter not supported"; + case 0x3007: + return "B protocol combination not supported"; + case 0x3008: + return "NCPI not supported"; + case 0x3009: + return "CIP Value unknown"; + case 0x300A: + return "Flags not supported (reserved bits)"; + case 0x300B: + return "Facility not supported"; + case 0x300C: + return "Data length not supported by current protocol"; + case 0x300D: + return "Reset procedure not supported by current protocol"; + +/*-- informations about the clearing of a physical connection -----*/ + case 0x3301: + return "Protocol error layer 1 (broken line or B-channel removed by signalling protocol)"; + case 0x3302: + return "Protocol error layer 2"; + case 0x3303: + return "Protocol error layer 3"; + case 0x3304: + return "Another application got that call"; +/*-- T.30 specific reasons -----*/ + case 0x3311: + return "Connecting not successful (remote station is no FAX G3 machine)"; + case 0x3312: + return "Connecting not successful (training error)"; + case 0x3313: + return "Disconnected before transfer (remote station does not support transfer mode, e.g. resolution)"; + case 0x3314: + return "Disconnected during transfer (remote abort)"; + case 0x3315: + return "Disconnected during transfer (remote procedure error, e.g. unsuccessful repetition of T.30 commands)"; + case 0x3316: + return "Disconnected during transfer (local tx data underrun)"; + case 0x3317: + return "Disconnected during transfer (local rx data overflow)"; + case 0x3318: + return "Disconnected during transfer (local abort)"; + case 0x3319: + return "Illegal parameter coding (e.g. SFF coding error)"; + +/*-- disconnect causes from the network according to ETS 300 102-1/Q.931 -----*/ + case 0x3481: return "Unallocated (unassigned) number"; + case 0x3482: return "No route to specified transit network"; + case 0x3483: return "No route to destination"; + case 0x3486: return "Channel unacceptable"; + case 0x3487: + return "Call awarded and being delivered in an established channel"; + case 0x3490: return "Normal call clearing"; + case 0x3491: return "User busy"; + case 0x3492: return "No user responding"; + case 0x3493: return "No answer from user (user alerted)"; + case 0x3495: return "Call rejected"; + case 0x3496: return "Number changed"; + case 0x349A: return "Non-selected user clearing"; + case 0x349B: return "Destination out of order"; + case 0x349C: return "Invalid number format"; + case 0x349D: return "Facility rejected"; + case 0x349E: return "Response to STATUS ENQUIRY"; + case 0x349F: return "Normal, unspecified"; + case 0x34A2: return "No circuit / channel available"; + case 0x34A6: return "Network out of order"; + case 0x34A9: return "Temporary failure"; + case 0x34AA: return "Switching equipment congestion"; + case 0x34AB: return "Access information discarded"; + case 0x34AC: return "Requested circuit / channel not available"; + case 0x34AF: return "Resources unavailable, unspecified"; + case 0x34B1: return "Quality of service unavailable"; + case 0x34B2: return "Requested facility not subscribed"; + case 0x34B9: return "Bearer capability not authorized"; + case 0x34BA: return "Bearer capability not presently available"; + case 0x34BF: return "Service or option not available, unspecified"; + case 0x34C1: return "Bearer capability not implemented"; + case 0x34C2: return "Channel type not implemented"; + case 0x34C5: return "Requested facility not implemented"; + case 0x34C6: return "Only restricted digital information bearer capability is available"; + case 0x34CF: return "Service or option not implemented, unspecified"; + case 0x34D1: return "Invalid call reference value"; + case 0x34D2: return "Identified channel does not exist"; + case 0x34D3: return "A suspended call exists, but this call identity does not"; + case 0x34D4: return "Call identity in use"; + case 0x34D5: return "No call suspended"; + case 0x34D6: return "Call having the requested call identity has been cleared"; + case 0x34D8: return "Incompatible destination"; + case 0x34DB: return "Invalid transit network selection"; + case 0x34DF: return "Invalid message, unspecified"; + case 0x34E0: return "Mandatory information element is missing"; + case 0x34E1: return "Message type non-existent or not implemented"; + case 0x34E2: return "Message not compatible with call state or message type non-existent or not implemented"; + case 0x34E3: return "Information element non-existent or not implemented"; + case 0x34E4: return "Invalid information element contents"; + case 0x34E5: return "Message not compatible with call state"; + case 0x34E6: return "Recovery on timer expiry"; + case 0x34EF: return "Protocol error, unspecified"; + case 0x34FF: return "Interworking, unspecified"; + + default: return "No additional information"; + } +#endif +} -static void handle_controller(_cmsg * cmsg) +static void handle_controller(_cmsg *cmsg) { capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f); @@ -791,54 +985,54 @@ static void handle_controller(_cmsg * cmsg) break; case CAPI_MANUFACTURER_IND: /* Controller */ - if ( cmsg->ManuID == 0x214D5641 + if (cmsg->ManuID == 0x214D5641 && cmsg->Class == 0 && cmsg->Function == 1) { - u8 *data = cmsg->ManuData+3; - u16 len = cmsg->ManuData[0]; - u16 layer; - int direction; - if (len == 255) { - len = (cmsg->ManuData[1] | (cmsg->ManuData[2] << 8)); - data += 2; - } - len -= 2; - layer = ((*(data-1)) << 8) | *(data-2); - if (layer & 0x300) - direction = (layer & 0x200) ? 0 : 1; - else direction = (layer & 0x800) ? 0 : 1; - if (layer & 0x0C00) { - if ((layer & 0xff) == 0x80) { - handle_dtrace_data(card, direction, 1, data, len); - break; - } - } else if ((layer & 0xff) < 0x80) { - handle_dtrace_data(card, direction, 0, data, len); - break; - } - printk(KERN_INFO "capidrv-%d: %s from controller 0x%x layer 0x%x, ignored\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrController, layer); - break; + u8 *data = cmsg->ManuData + 3; + u16 len = cmsg->ManuData[0]; + u16 layer; + int direction; + if (len == 255) { + len = (cmsg->ManuData[1] | (cmsg->ManuData[2] << 8)); + data += 2; + } + len -= 2; + layer = ((*(data - 1)) << 8) | *(data - 2); + if (layer & 0x300) + direction = (layer & 0x200) ? 0 : 1; + else direction = (layer & 0x800) ? 0 : 1; + if (layer & 0x0C00) { + if ((layer & 0xff) == 0x80) { + handle_dtrace_data(card, direction, 1, data, len); + break; + } + } else if ((layer & 0xff) < 0x80) { + handle_dtrace_data(card, direction, 0, data, len); + break; + } + printk(KERN_INFO "capidrv-%d: %s from controller 0x%x layer 0x%x, ignored\n", + card->contrnr, + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrController, layer); + break; } goto ignored; case CAPI_MANUFACTURER_CONF: /* Controller */ if (cmsg->ManuID == 0x214D5641) { - char *s = NULL; - switch (cmsg->Class) { - case 0: break; - case 1: s = "unknown class"; break; - case 2: s = "unknown function"; break; - default: s = "unkown error"; break; - } - if (s) - printk(KERN_INFO "capidrv-%d: %s from controller 0x%x function %d: %s\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrController, - cmsg->Function, s); - break; + char *s = NULL; + switch (cmsg->Class) { + case 0: break; + case 1: s = "unknown class"; break; + case 2: s = "unknown function"; break; + default: s = "unknown error"; break; + } + if (s) + printk(KERN_INFO "capidrv-%d: %s from controller 0x%x function %d: %s\n", + card->contrnr, + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrController, + cmsg->Function, s); + break; } goto ignored; case CAPI_FACILITY_IND: /* Controller/plci/ncci */ @@ -858,14 +1052,14 @@ static void handle_controller(_cmsg * cmsg) } return; - ignored: +ignored: printk(KERN_INFO "capidrv-%d: %s from controller 0x%x ignored\n", card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrController); } -static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg) +static void handle_incoming_call(capidrv_contr *card, _cmsg *cmsg) { capidrv_plci *plcip; capidrv_bchan *bchan; @@ -890,27 +1084,27 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg) cmd.arg = chan; memset(&cmd.parm.setup, 0, sizeof(cmd.parm.setup)); strncpy(cmd.parm.setup.phone, - cmsg->CallingPartyNumber + 3, + cmsg->CallingPartyNumber + 3, cmsg->CallingPartyNumber[0] - 2); strncpy(cmd.parm.setup.eazmsn, - cmsg->CalledPartyNumber + 2, + cmsg->CalledPartyNumber + 2, cmsg->CalledPartyNumber[0] - 1); cmd.parm.setup.si1 = cip2si1(cmsg->CIPValue); cmd.parm.setup.si2 = cip2si2(cmsg->CIPValue); cmd.parm.setup.plan = cmsg->CallingPartyNumber[1]; cmd.parm.setup.screen = cmsg->CallingPartyNumber[2]; - printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s\n", - card->contrnr, - cmd.parm.setup.phone, - cmd.parm.setup.si1, - cmd.parm.setup.si2, - cmd.parm.setup.eazmsn); + printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s\n", + card->contrnr, + cmd.parm.setup.phone, + cmd.parm.setup.si1, + cmd.parm.setup.si2, + cmd.parm.setup.eazmsn); if (cmd.parm.setup.si1 == 1 && cmd.parm.setup.si2 != 0) { - printk(KERN_INFO "capidrv-%d: patching si2=%d to 0 for VBOX\n", - card->contrnr, - cmd.parm.setup.si2); + printk(KERN_INFO "capidrv-%d: patching si2=%d to 0 for VBOX\n", + card->contrnr, + cmd.parm.setup.si2); cmd.parm.setup.si2 = 0; } @@ -924,14 +1118,14 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg) */ capi_cmsg_answer(cmsg); cmsg->Reject = 1; /* ignore */ - send_message(card, cmsg); plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT); + send_message(card, cmsg); printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s ignored\n", - card->contrnr, - cmd.parm.setup.phone, - cmd.parm.setup.si1, - cmd.parm.setup.si2, - cmd.parm.setup.eazmsn); + card->contrnr, + cmd.parm.setup.phone, + cmd.parm.setup.si1, + cmd.parm.setup.si2, + cmd.parm.setup.eazmsn); break; case 1: /* At least one device matching this call (RING on ttyI) @@ -945,11 +1139,11 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg) */ if (plcip->state == ST_PLCI_INCOMING) { printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s tty alerting\n", - card->contrnr, - cmd.parm.setup.phone, - cmd.parm.setup.si1, - cmd.parm.setup.si2, - cmd.parm.setup.eazmsn); + card->contrnr, + cmd.parm.setup.phone, + cmd.parm.setup.si1, + cmd.parm.setup.si2, + cmd.parm.setup.eazmsn); capi_fill_ALERT_REQ(cmsg, global.ap.applid, card->msgid++, @@ -958,24 +1152,24 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg) NULL,/* Keypadfacility */ NULL,/* Useruserdata */ NULL /* Facilitydataarray */ - ); + ); plcip->msgid = cmsg->Messagenumber; send_message(card, cmsg); } else { printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s on netdev\n", - card->contrnr, - cmd.parm.setup.phone, - cmd.parm.setup.si1, - cmd.parm.setup.si2, - cmd.parm.setup.eazmsn); + card->contrnr, + cmd.parm.setup.phone, + cmd.parm.setup.si1, + cmd.parm.setup.si2, + cmd.parm.setup.eazmsn); } break; case 2: /* Call will be rejected. */ capi_cmsg_answer(cmsg); cmsg->Reject = 2; /* reject call, normal call clearing */ - send_message(card, cmsg); plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT); + send_message(card, cmsg); break; default: @@ -983,14 +1177,14 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg) capi_cmsg_answer(cmsg); cmsg->Reject = 8; /* reject call, destination out of order */ - send_message(card, cmsg); plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT); + send_message(card, cmsg); break; } return; } -static void handle_plci(_cmsg * cmsg) +static void handle_plci(_cmsg *cmsg) { capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f); capidrv_plci *plcip; @@ -1008,8 +1202,8 @@ static void handle_plci(_cmsg * cmsg) case CAPI_DISCONNECT_IND: /* plci */ if (cmsg->Reason) { printk(KERN_INFO "capidrv-%d: %s reason 0x%x (%s) for plci 0x%x\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), + card->contrnr, + capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->Reason, capi_info2str(cmsg->Reason), cmsg->adr.adrPLCI); } if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) { @@ -1020,16 +1214,16 @@ static void handle_plci(_cmsg * cmsg) card->bchans[plcip->chan].disconnecting = 1; plci_change_state(card, plcip, EV_PLCI_DISCONNECT_IND); capi_cmsg_answer(cmsg); - send_message(card, cmsg); plci_change_state(card, plcip, EV_PLCI_DISCONNECT_RESP); + send_message(card, cmsg); break; case CAPI_DISCONNECT_CONF: /* plci */ if (cmsg->Info) { printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->Info, capi_info2str(cmsg->Info), + card->contrnr, + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->Info, capi_info2str(cmsg->Info), cmsg->adr.adrPLCI); } if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) @@ -1041,9 +1235,9 @@ static void handle_plci(_cmsg * cmsg) case CAPI_ALERT_CONF: /* plci */ if (cmsg->Info) { printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->Info, capi_info2str(cmsg->Info), + card->contrnr, + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->Info, capi_info2str(cmsg->Info), cmsg->adr.adrPLCI); } break; @@ -1055,9 +1249,9 @@ static void handle_plci(_cmsg * cmsg) case CAPI_CONNECT_CONF: /* plci */ if (cmsg->Info) { printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->Info, capi_info2str(cmsg->Info), + card->contrnr, + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->Info, capi_info2str(cmsg->Info), cmsg->adr.adrPLCI); } if (!(plcip = find_plci_by_msgid(card, cmsg->Messagenumber))) @@ -1078,8 +1272,8 @@ static void handle_plci(_cmsg * cmsg) if (card->bchans[plcip->chan].incoming) { capi_cmsg_answer(cmsg); - send_message(card, cmsg); plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND); + send_message(card, cmsg); } else { capidrv_ncci *nccip; capi_cmsg_answer(cmsg); @@ -1096,15 +1290,16 @@ static void handle_plci(_cmsg * cmsg) card->msgid++, plcip->plci, /* adr */ NULL /* NCPI */ - ); + ); nccip->msgid = cmsg->Messagenumber; + plci_change_state(card, plcip, + EV_PLCI_CONNECT_ACTIVE_IND); + ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_REQ); send_message(card, cmsg); cmd.command = ISDN_STAT_DCONN; cmd.driver = card->myid; cmd.arg = plcip->chan; card->interface.statcallb(&cmd); - plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND); - ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_REQ); } break; @@ -1121,8 +1316,8 @@ static void handle_plci(_cmsg * cmsg) sprintf(cmd.parm.num, "%lu", (unsigned long) ((u32) cmsg->InfoElement[1] - | ((u32) (cmsg->InfoElement[2]) << 8) - | ((u32) (cmsg->InfoElement[3]) << 16) + | ((u32) (cmsg->InfoElement[2]) << 8) + | ((u32) (cmsg->InfoElement[3]) << 16) | ((u32) (cmsg->InfoElement[4]) << 24))); card->interface.statcallb(&cmd); break; @@ -1131,11 +1326,11 @@ static void handle_plci(_cmsg * cmsg) cdb = capi_cmsg2str(cmsg); if (cdb) { printk(KERN_WARNING "capidrv-%d: %s\n", - card->contrnr, cdb->buf); + card->contrnr, cdb->buf); cdebbuf_free(cdb); } else printk(KERN_WARNING "capidrv-%d: CAPI_INFO_IND InfoNumber %x not handled\n", - card->contrnr, cmsg->InfoNumber); + card->contrnr, cmsg->InfoNumber); break; @@ -1158,13 +1353,13 @@ static void handle_plci(_cmsg * cmsg) cmsg->adr.adrPLCI); } return; - ignored: +ignored: printk(KERN_INFO "capidrv-%d: %s for plci 0x%x ignored\n", card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrPLCI); return; - notfound: +notfound: printk(KERN_ERR "capidrv-%d: %s: plci 0x%x not found\n", card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), @@ -1172,7 +1367,7 @@ static void handle_plci(_cmsg * cmsg) return; } -static void handle_ncci(_cmsg * cmsg) +static void handle_ncci(_cmsg *cmsg) { capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f); capidrv_plci *plcip; @@ -1193,8 +1388,8 @@ static void handle_ncci(_cmsg * cmsg) goto notfound; capi_cmsg_answer(cmsg); - send_message(card, cmsg); ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_ACTIVE_IND); + send_message(card, cmsg); cmd.command = ISDN_STAT_BCONN; cmd.driver = card->myid; @@ -1221,16 +1416,16 @@ static void handle_ncci(_cmsg * cmsg) nccip->ncci, /* adr */ 0, /* Reject */ NULL /* NCPI */ - ); - send_message(card, cmsg); + ); ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_RESP); + send_message(card, cmsg); break; } printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr); } else { printk(KERN_ERR "capidrv-%d: %s: plci for ncci 0x%x not found\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), + card->contrnr, + capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrNCCI); } capi_fill_CONNECT_B3_RESP(cmsg, @@ -1239,7 +1434,7 @@ static void handle_ncci(_cmsg * cmsg) cmsg->adr.adrNCCI, 2, /* Reject */ NULL /* NCPI */ - ); + ); send_message(card, cmsg); break; @@ -1253,9 +1448,9 @@ static void handle_ncci(_cmsg * cmsg) nccip->ncci = cmsg->adr.adrNCCI; if (cmsg->Info) { printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->Info, capi_info2str(cmsg->Info), + card->contrnr, + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->Info, capi_info2str(cmsg->Info), cmsg->adr.adrNCCI); } @@ -1277,7 +1472,7 @@ static void handle_ncci(_cmsg * cmsg) case CAPI_DATA_B3_CONF: /* ncci */ if (cmsg->Info) { printk(KERN_WARNING "CAPI_DATA_B3_CONF: Info %x - %s\n", - cmsg->Info, capi_info2str(cmsg->Info)); + cmsg->Info, capi_info2str(cmsg->Info)); } if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) goto notfound; @@ -1285,11 +1480,11 @@ static void handle_ncci(_cmsg * cmsg) len = capidrv_del_ack(nccip, cmsg->DataHandle); if (len < 0) break; - cmd.command = ISDN_STAT_BSENT; - cmd.driver = card->myid; - cmd.arg = nccip->chan; + cmd.command = ISDN_STAT_BSENT; + cmd.driver = card->myid; + cmd.arg = nccip->chan; cmd.parm.length = len; - card->interface.statcallb(&cmd); + card->interface.statcallb(&cmd); break; case CAPI_DISCONNECT_B3_IND: /* ncci */ @@ -1299,8 +1494,8 @@ static void handle_ncci(_cmsg * cmsg) card->bchans[nccip->chan].disconnecting = 1; ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_IND); capi_cmsg_answer(cmsg); - send_message(card, cmsg); ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_RESP); + send_message(card, cmsg); break; case CAPI_DISCONNECT_B3_CONF: /* ncci */ @@ -1308,9 +1503,9 @@ static void handle_ncci(_cmsg * cmsg) goto notfound; if (cmsg->Info) { printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->Info, capi_info2str(cmsg->Info), + card->contrnr, + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->Info, capi_info2str(cmsg->Info), cmsg->adr.adrNCCI); ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_CONF_ERROR); } @@ -1339,13 +1534,13 @@ static void handle_ncci(_cmsg * cmsg) cmsg->adr.adrNCCI); } return; - ignored: +ignored: printk(KERN_INFO "capidrv-%d: %s for ncci 0x%x ignored\n", card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrNCCI); return; - notfound: +notfound: printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n", card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), @@ -1353,7 +1548,7 @@ static void handle_ncci(_cmsg * cmsg) } -static void handle_data(_cmsg * cmsg, struct sk_buff *skb) +static void handle_data(_cmsg *cmsg, struct sk_buff *skb) { capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f); capidrv_ncci *nccip; @@ -1389,12 +1584,12 @@ static void capidrv_recv_message(struct capi20_appl *ap, struct sk_buff *skb) if (cdb) { printk(KERN_DEBUG "%s: applid=%d %s\n", __func__, - ap->applid, cdb->buf); + ap->applid, cdb->buf); cdebbuf_free(cdb); } else printk(KERN_DEBUG "%s: applid=%d %s not traced\n", - __func__, ap->applid, - capi_cmd2str(s_cmsg.Command, s_cmsg.Subcommand)); + __func__, ap->applid, + capi_cmd2str(s_cmsg.Command, s_cmsg.Subcommand)); } if (s_cmsg.Command == CAPI_DATA_B3 && s_cmsg.Subcommand == CAPI_IND) { @@ -1417,50 +1612,47 @@ static void capidrv_recv_message(struct capi20_appl *ap, struct sk_buff *skb) /* ------------------------------------------------------------------- */ -#define PUTBYTE_TO_STATUS(card, byte) \ - do { \ - *(card)->q931_write++ = (byte); \ - if ((card)->q931_write > (card)->q931_end) \ - (card)->q931_write = (card)->q931_buf; \ +#define PUTBYTE_TO_STATUS(card, byte) \ + do { \ + *(card)->q931_write++ = (byte); \ + if ((card)->q931_write > (card)->q931_end) \ + (card)->q931_write = (card)->q931_buf; \ } while (0) static void handle_dtrace_data(capidrv_contr *card, - int send, int level2, u8 *data, u16 len) + int send, int level2, u8 *data, u16 len) { - u8 *p, *end; - isdn_ctrl cmd; + u8 *p, *end; + isdn_ctrl cmd; - if (!len) { + if (!len) { printk(KERN_DEBUG "capidrv-%d: avmb1_q931_data: len == %d\n", - card->contrnr, len); + card->contrnr, len); return; } if (level2) { PUTBYTE_TO_STATUS(card, 'D'); PUTBYTE_TO_STATUS(card, '2'); - PUTBYTE_TO_STATUS(card, send ? '>' : '<'); - PUTBYTE_TO_STATUS(card, ':'); + PUTBYTE_TO_STATUS(card, send ? '>' : '<'); + PUTBYTE_TO_STATUS(card, ':'); } else { - PUTBYTE_TO_STATUS(card, 'D'); - PUTBYTE_TO_STATUS(card, '3'); - PUTBYTE_TO_STATUS(card, send ? '>' : '<'); - PUTBYTE_TO_STATUS(card, ':'); - } - - for (p = data, end = data+len; p < end; p++) { - u8 w; + PUTBYTE_TO_STATUS(card, 'D'); + PUTBYTE_TO_STATUS(card, '3'); + PUTBYTE_TO_STATUS(card, send ? '>' : '<'); + PUTBYTE_TO_STATUS(card, ':'); + } + + for (p = data, end = data + len; p < end; p++) { PUTBYTE_TO_STATUS(card, ' '); - w = (*p >> 4) & 0xf; - PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w); - w = *p & 0xf; - PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w); + PUTBYTE_TO_STATUS(card, hex_asc_hi(*p)); + PUTBYTE_TO_STATUS(card, hex_asc_lo(*p)); } PUTBYTE_TO_STATUS(card, '\n'); cmd.command = ISDN_STAT_STAVAIL; cmd.driver = card->myid; - cmd.arg = len*3+5; + cmd.arg = len * 3 + 5; card->interface.statcallb(&cmd); } @@ -1468,17 +1660,17 @@ static void handle_dtrace_data(capidrv_contr *card, static _cmsg cmdcmsg; -static int capidrv_ioctl(isdn_ctrl * c, capidrv_contr * card) +static int capidrv_ioctl(isdn_ctrl *c, capidrv_contr *card) { switch (c->arg) { case 1: debugmode = (int)(*((unsigned int *)c->parm.num)); printk(KERN_DEBUG "capidrv-%d: debugmode=%d\n", - card->contrnr, debugmode); + card->contrnr, debugmode); return 0; default: printk(KERN_DEBUG "capidrv-%d: capidrv_ioctl(%ld) called ??\n", - card->contrnr, c->arg); + card->contrnr, c->arg); return -EINVAL; } return -EINVAL; @@ -1489,9 +1681,9 @@ static int capidrv_ioctl(isdn_ctrl * c, capidrv_contr * card) */ struct internal_bchannelinfo { - unsigned short channelalloc; - unsigned short operation; - unsigned char cmask[31]; + unsigned short channelalloc; + unsigned short operation; + unsigned char cmask[31]; }; static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep) @@ -1517,8 +1709,13 @@ static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep) while (*s) { int digit1 = 0; int digit2 = 0; - if (!isdigit(*s)) return -3; - while (isdigit(*s)) { digit1 = digit1*10 + (*s - '0'); s++; } + char *endp; + + digit1 = simple_strtoul(s, &endp, 10); + if (s == endp) + return -3; + s = endp; + if (digit1 <= 0 || digit1 > 30) return -4; if (*s == 0 || *s == ',' || *s == ' ') { bmask |= (1 << digit1); @@ -1528,15 +1725,19 @@ static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep) } if (*s != '-') return -5; s++; - if (!isdigit(*s)) return -3; - while (isdigit(*s)) { digit2 = digit2*10 + (*s - '0'); s++; } + + digit2 = simple_strtoul(s, &endp, 10); + if (s == endp) + return -3; + s = endp; + if (digit2 <= 0 || digit2 > 30) return -4; if (*s == 0 || *s == ',' || *s == ' ') { if (digit1 > digit2) - for (i = digit2; i <= digit1 ; i++) + for (i = digit2; i <= digit1; i++) bmask |= (1 << i); - else - for (i = digit1; i <= digit2 ; i++) + else + for (i = digit1; i <= digit2; i++) bmask |= (1 << i); digit1 = digit2 = 0; if (*s) s++; @@ -1549,131 +1750,131 @@ static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep) return 0; } -static int FVteln2capi20(char *teln, u8 AdditionalInfo[1+2+2+31]) +static int FVteln2capi20(char *teln, u8 AdditionalInfo[1 + 2 + 2 + 31]) { unsigned long bmask; int active; int rc, i; - + rc = decodeFVteln(teln, &bmask, &active); if (rc) return rc; /* Length */ - AdditionalInfo[0] = 2+2+31; - /* Channel: 3 => use channel allocation */ - AdditionalInfo[1] = 3; AdditionalInfo[2] = 0; + AdditionalInfo[0] = 2 + 2 + 31; + /* Channel: 3 => use channel allocation */ + AdditionalInfo[1] = 3; AdditionalInfo[2] = 0; /* Operation: 0 => DTE mode, 1 => DCE mode */ - if (active) { - AdditionalInfo[3] = 0; AdditionalInfo[4] = 0; - } else { - AdditionalInfo[3] = 1; AdditionalInfo[4] = 0; + if (active) { + AdditionalInfo[3] = 0; AdditionalInfo[4] = 0; + } else { + AdditionalInfo[3] = 1; AdditionalInfo[4] = 0; } /* Channel mask array */ AdditionalInfo[5] = 0; /* no D-Channel */ - for (i=1; i <= 30; i++) - AdditionalInfo[5+i] = (bmask & (1 << i)) ? 0xff : 0; + for (i = 1; i <= 30; i++) + AdditionalInfo[5 + i] = (bmask & (1 << i)) ? 0xff : 0; return 0; } -static int capidrv_command(isdn_ctrl * c, capidrv_contr * card) +static int capidrv_command(isdn_ctrl *c, capidrv_contr *card) { isdn_ctrl cmd; struct capidrv_bchan *bchan; struct capidrv_plci *plcip; - u8 AdditionalInfo[1+2+2+31]; - int rc, isleasedline = 0; + u8 AdditionalInfo[1 + 2 + 2 + 31]; + int rc, isleasedline = 0; if (c->command == ISDN_CMD_IOCTL) return capidrv_ioctl(c, card); switch (c->command) { - case ISDN_CMD_DIAL:{ - u8 calling[ISDN_MSNLEN + 3]; - u8 called[ISDN_MSNLEN + 2]; + case ISDN_CMD_DIAL: { + u8 calling[ISDN_MSNLEN + 3]; + u8 called[ISDN_MSNLEN + 2]; - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_DIAL(ch=%ld,\"%s,%d,%d,%s\")\n", - card->contrnr, - c->arg, - c->parm.setup.phone, - c->parm.setup.si1, - c->parm.setup.si2, - c->parm.setup.eazmsn); - - bchan = &card->bchans[c->arg % card->nbchan]; - - if (bchan->plcip) { - printk(KERN_ERR "capidrv-%d: dail ch=%ld,\"%s,%d,%d,%s\" in use (plci=0x%x)\n", - card->contrnr, - c->arg, - c->parm.setup.phone, - c->parm.setup.si1, - c->parm.setup.si2, - c->parm.setup.eazmsn, - bchan->plcip->plci); - return 0; - } - bchan->si1 = c->parm.setup.si1; - bchan->si2 = c->parm.setup.si2; - - strncpy(bchan->num, c->parm.setup.phone, sizeof(bchan->num)); - strncpy(bchan->mynum, c->parm.setup.eazmsn, sizeof(bchan->mynum)); - rc = FVteln2capi20(bchan->num, AdditionalInfo); - isleasedline = (rc == 0); - if (rc < 0) - printk(KERN_ERR "capidrv-%d: WARNING: invalid leased linedefinition \"%s\"\n", card->contrnr, bchan->num); - - if (isleasedline) { - calling[0] = 0; - called[0] = 0; - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: connecting leased line\n", card->contrnr); - } else { - calling[0] = strlen(bchan->mynum) + 2; - calling[1] = 0; - calling[2] = 0x80; - strncpy(calling + 3, bchan->mynum, ISDN_MSNLEN); - called[0] = strlen(bchan->num) + 1; - called[1] = 0x80; - strncpy(called + 2, bchan->num, ISDN_MSNLEN); - } + if (debugmode) + printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_DIAL(ch=%ld,\"%s,%d,%d,%s\")\n", + card->contrnr, + c->arg, + c->parm.setup.phone, + c->parm.setup.si1, + c->parm.setup.si2, + c->parm.setup.eazmsn); - capi_fill_CONNECT_REQ(&cmdcmsg, - global.ap.applid, - card->msgid++, - card->contrnr, /* adr */ - si2cip(bchan->si1, bchan->si2), /* cipvalue */ - called, /* CalledPartyNumber */ - calling, /* CallingPartyNumber */ - NULL, /* CalledPartySubaddress */ - NULL, /* CallingPartySubaddress */ - b1prot(bchan->l2, bchan->l3), /* B1protocol */ - b2prot(bchan->l2, bchan->l3), /* B2protocol */ - b3prot(bchan->l2, bchan->l3), /* B3protocol */ - b1config(bchan->l2, bchan->l3), /* B1configuration */ - NULL, /* B2configuration */ - NULL, /* B3configuration */ - NULL, /* BC */ - NULL, /* LLC */ - NULL, /* HLC */ - /* BChannelinformation */ - isleasedline ? AdditionalInfo : NULL, - NULL, /* Keypadfacility */ - NULL, /* Useruserdata */ - NULL /* Facilitydataarray */ - ); - if ((plcip = new_plci(card, (c->arg % card->nbchan))) == NULL) { - cmd.command = ISDN_STAT_DHUP; - cmd.driver = card->myid; - cmd.arg = (c->arg % card->nbchan); - card->interface.statcallb(&cmd); - return -1; - } - plcip->msgid = cmdcmsg.Messagenumber; - plcip->leasedline = isleasedline; - plci_change_state(card, plcip, EV_PLCI_CONNECT_REQ); - send_message(card, &cmdcmsg); + bchan = &card->bchans[c->arg % card->nbchan]; + + if (bchan->plcip) { + printk(KERN_ERR "capidrv-%d: dail ch=%ld,\"%s,%d,%d,%s\" in use (plci=0x%x)\n", + card->contrnr, + c->arg, + c->parm.setup.phone, + c->parm.setup.si1, + c->parm.setup.si2, + c->parm.setup.eazmsn, + bchan->plcip->plci); return 0; } + bchan->si1 = c->parm.setup.si1; + bchan->si2 = c->parm.setup.si2; + + strncpy(bchan->num, c->parm.setup.phone, sizeof(bchan->num)); + strncpy(bchan->mynum, c->parm.setup.eazmsn, sizeof(bchan->mynum)); + rc = FVteln2capi20(bchan->num, AdditionalInfo); + isleasedline = (rc == 0); + if (rc < 0) + printk(KERN_ERR "capidrv-%d: WARNING: invalid leased linedefinition \"%s\"\n", card->contrnr, bchan->num); + + if (isleasedline) { + calling[0] = 0; + called[0] = 0; + if (debugmode) + printk(KERN_DEBUG "capidrv-%d: connecting leased line\n", card->contrnr); + } else { + calling[0] = strlen(bchan->mynum) + 2; + calling[1] = 0; + calling[2] = 0x80; + strncpy(calling + 3, bchan->mynum, ISDN_MSNLEN); + called[0] = strlen(bchan->num) + 1; + called[1] = 0x80; + strncpy(called + 2, bchan->num, ISDN_MSNLEN); + } + + capi_fill_CONNECT_REQ(&cmdcmsg, + global.ap.applid, + card->msgid++, + card->contrnr, /* adr */ + si2cip(bchan->si1, bchan->si2), /* cipvalue */ + called, /* CalledPartyNumber */ + calling, /* CallingPartyNumber */ + NULL, /* CalledPartySubaddress */ + NULL, /* CallingPartySubaddress */ + b1prot(bchan->l2, bchan->l3), /* B1protocol */ + b2prot(bchan->l2, bchan->l3), /* B2protocol */ + b3prot(bchan->l2, bchan->l3), /* B3protocol */ + b1config(bchan->l2, bchan->l3), /* B1configuration */ + NULL, /* B2configuration */ + NULL, /* B3configuration */ + NULL, /* BC */ + NULL, /* LLC */ + NULL, /* HLC */ + /* BChannelinformation */ + isleasedline ? AdditionalInfo : NULL, + NULL, /* Keypadfacility */ + NULL, /* Useruserdata */ + NULL /* Facilitydataarray */ + ); + if ((plcip = new_plci(card, (c->arg % card->nbchan))) == NULL) { + cmd.command = ISDN_STAT_DHUP; + cmd.driver = card->myid; + cmd.arg = (c->arg % card->nbchan); + card->interface.statcallb(&cmd); + return -1; + } + plcip->msgid = cmdcmsg.Messagenumber; + plcip->leasedline = isleasedline; + plci_change_state(card, plcip, EV_PLCI_CONNECT_REQ); + send_message(card, &cmdcmsg); + return 0; + } case ISDN_CMD_ACCEPTD: @@ -1701,7 +1902,7 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card) NULL, /* Keypadfacility */ NULL, /* Useruserdata */ NULL /* Facilitydataarray */ - ); + ); capi_cmsg2message(&cmdcmsg, cmdcmsg.buf); plci_change_state(card, bchan->plcip, EV_PLCI_CONNECT_RESP); send_message(card, &cmdcmsg); @@ -1735,7 +1936,7 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card) card->msgid++, bchan->nccip->ncci, NULL /* NCPI */ - ); + ); ncci_change_state(card, bchan->nccip, EV_NCCI_DISCONNECT_B3_REQ); send_message(card, &cmdcmsg); return 0; @@ -1754,12 +1955,12 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card) capi_fill_DISCONNECT_REQ(&cmdcmsg, global.ap.applid, card->msgid++, - bchan->plcip->plci, + bchan->plcip->plci, NULL, /* BChannelinformation */ NULL, /* Keypadfacility */ NULL, /* Useruserdata */ NULL /* Facilitydataarray */ - ); + ); plci_change_state(card, bchan->plcip, EV_PLCI_DISCONNECT_REQ); send_message(card, &cmdcmsg); return 0; @@ -1771,8 +1972,8 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card) } } printk(KERN_ERR "capidrv-%d: chan %ld disconnect request on free channel\n", - card->contrnr, - c->arg); + card->contrnr, + c->arg); return -EINVAL; /* ready */ @@ -1806,20 +2007,20 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card) case ISDN_CMD_CLREAZ: if (debugmode) printk(KERN_DEBUG "capidrv-%d: clearing EAZ on chan %ld\n", - card->contrnr, c->arg); + card->contrnr, c->arg); bchan = &card->bchans[c->arg % card->nbchan]; bchan->msn[0] = 0; return 0; default: printk(KERN_ERR "capidrv-%d: ISDN_CMD_%d, Huh?\n", - card->contrnr, c->command); + card->contrnr, c->command); return -EINVAL; } return 0; } -static int if_command(isdn_ctrl * c) +static int if_command(isdn_ctrl *c) { capidrv_contr *card = findcontrbydriverid(c->driver); @@ -1827,8 +2028,8 @@ static int if_command(isdn_ctrl * c) return capidrv_command(c, card); printk(KERN_ERR - "capidrv: if_command %d called with invalid driverId %d!\n", - c->command, c->driver); + "capidrv: if_command %d called with invalid driverId %d!\n", + c->command, c->driver); return -ENODEV; } @@ -1852,7 +2053,7 @@ static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb) } if (debugmode > 4) printk(KERN_DEBUG "capidrv-%d: sendbuf len=%d skb=%p doack=%d\n", - card->contrnr, len, skb, doack); + card->contrnr, len, skb, doack); bchan = &card->bchans[channel % card->nbchan]; nccip = bchan->nccip; if (!nccip || nccip->state != ST_NCCI_ACTIVE) { @@ -1884,10 +2085,10 @@ static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb) skb->len, /* DataLength */ datahandle, /* DataHandle */ 0 /* Flags */ - ); + ); if (capidrv_add_ack(nccip, datahandle, doack ? (int)skb->len : -1) < 0) - return 0; + return 0; capi_cmsg2message(&sendcmsg, sendcmsg.buf); msglen = CAPIMSG_LEN(sendcmsg.buf); @@ -1895,8 +2096,8 @@ static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb) struct sk_buff *nskb = skb_realloc_headroom(skb, msglen); if (!nskb) { printk(KERN_ERR "capidrv-%d: if_sendbuf: no memory\n", - card->contrnr); - (void)capidrv_del_ack(nccip, datahandle); + card->contrnr); + (void)capidrv_del_ack(nccip, datahandle); return 0; } printk(KERN_DEBUG "capidrv-%d: only %d bytes headroom, need %d\n", @@ -1910,9 +2111,9 @@ static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb) } if (debugmode > 3) printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n", - card->contrnr, errcode, capi_info2str(errcode)); - (void)capidrv_del_ack(nccip, datahandle); - dev_kfree_skb(nskb); + card->contrnr, errcode, capi_info2str(errcode)); + (void)capidrv_del_ack(nccip, datahandle); + dev_kfree_skb(nskb); return errcode == CAPI_SENDQUEUEFULL ? 0 : -1; } else { memcpy(skb_push(skb, msglen), sendcmsg.buf, msglen); @@ -1923,9 +2124,9 @@ static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb) } if (debugmode > 3) printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n", - card->contrnr, errcode, capi_info2str(errcode)); + card->contrnr, errcode, capi_info2str(errcode)); skb_pull(skb, msglen); - (void)capidrv_del_ack(nccip, datahandle); + (void)capidrv_del_ack(nccip, datahandle); return errcode == CAPI_SENDQUEUEFULL ? 0 : -1; } } @@ -1942,11 +2143,11 @@ static int if_readstat(u8 __user *buf, int len, int id, int channel) return -ENODEV; } - for (p=buf, count=0; count < len; p++, count++) { + for (p = buf, count = 0; count < len; p++, count++) { if (put_user(*card->q931_read++, p)) return -EFAULT; - if (card->q931_read > card->q931_end) - card->q931_read = card->q931_buf; + if (card->q931_read > card->q931_end) + card->q931_read = card->q931_buf; } return count; @@ -1954,35 +2155,35 @@ static int if_readstat(u8 __user *buf, int len, int id, int channel) static void enable_dchannel_trace(capidrv_contr *card) { - u8 manufacturer[CAPI_MANUFACTURER_LEN]; - capi_version version; + u8 manufacturer[CAPI_MANUFACTURER_LEN]; + capi_version version; u16 contr = card->contrnr; u16 errcode; u16 avmversion[3]; - errcode = capi20_get_manufacturer(contr, manufacturer); - if (errcode != CAPI_NOERROR) { - printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n", - card->name, errcode); - return; + errcode = capi20_get_manufacturer(contr, manufacturer); + if (errcode != CAPI_NOERROR) { + printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n", + card->name, errcode); + return; } if (strstr(manufacturer, "AVM") == NULL) { - printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n", - card->name, manufacturer); - return; + printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n", + card->name, manufacturer); + return; } - errcode = capi20_get_version(contr, &version); - if (errcode != CAPI_NOERROR) { - printk(KERN_ERR "%s: can't get version (0x%x)\n", - card->name, errcode); - return; + errcode = capi20_get_version(contr, &version); + if (errcode != CAPI_NOERROR) { + printk(KERN_ERR "%s: can't get version (0x%x)\n", + card->name, errcode); + return; } avmversion[0] = (version.majormanuversion >> 4) & 0x0f; avmversion[1] = (version.majormanuversion << 4) & 0xf0; avmversion[1] |= (version.minormanuversion >> 4) & 0x0f; avmversion[2] |= version.minormanuversion & 0x0f; - if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) { + if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) { printk(KERN_INFO "%s: D2 trace enabled\n", card->name); capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.ap.applid, card->msgid++, @@ -2014,8 +2215,8 @@ static void send_listen(capidrv_contr *card) card->cipmask, card->cipmask2, NULL, NULL); - send_message(card, &cmdcmsg); listen_change_state(card, EV_LISTEN_REQ); + send_message(card, &cmdcmsg); } static void listentimerfunc(unsigned long x) @@ -2023,8 +2224,8 @@ static void listentimerfunc(unsigned long x) capidrv_contr *card = (capidrv_contr *)x; if (card->state != ST_LISTEN_NONE && card->state != ST_LISTEN_ACTIVE) printk(KERN_ERR "%s: controller dead ??\n", card->name); - send_listen(card); - mod_timer(&card->listentimer, jiffies + 60*HZ); + send_listen(card); + mod_timer(&card->listentimer, jiffies + 60 * HZ); } @@ -2043,7 +2244,7 @@ static int capidrv_addcontr(u16 contr, struct capi_profile *profp) } if (!(card = kzalloc(sizeof(capidrv_contr), GFP_ATOMIC))) { printk(KERN_WARNING - "capidrv: (%s) Could not allocate contr-struct.\n", id); + "capidrv: (%s) Could not allocate contr-struct.\n", id); return -1; } card->owner = THIS_MODULE; @@ -2054,7 +2255,7 @@ static int capidrv_addcontr(u16 contr, struct capi_profile *profp) card->bchans = kmalloc(sizeof(capidrv_bchan) * card->nbchan, GFP_ATOMIC); if (!card->bchans) { printk(KERN_WARNING - "capidrv: (%s) Could not allocate bchan-structs.\n", id); + "capidrv: (%s) Could not allocate bchan-structs.\n", id); module_put(card->owner); kfree(card); return -1; @@ -2065,18 +2266,20 @@ static int capidrv_addcontr(u16 contr, struct capi_profile *profp) card->interface.writebuf_skb = if_sendbuf; card->interface.writecmd = NULL; card->interface.readstat = if_readstat; - card->interface.features = ISDN_FEATURE_L2_HDLC | - ISDN_FEATURE_L2_TRANS | - ISDN_FEATURE_L3_TRANS | - ISDN_FEATURE_P_UNKNOWN | - ISDN_FEATURE_L2_X75I | - ISDN_FEATURE_L2_X75UI | - ISDN_FEATURE_L2_X75BUI; - if (profp->support1 & (1<<2)) - card->interface.features |= ISDN_FEATURE_L2_V11096 | - ISDN_FEATURE_L2_V11019 | - ISDN_FEATURE_L2_V11038; - if (profp->support1 & (1<<8)) + card->interface.features = + ISDN_FEATURE_L2_HDLC | + ISDN_FEATURE_L2_TRANS | + ISDN_FEATURE_L3_TRANS | + ISDN_FEATURE_P_UNKNOWN | + ISDN_FEATURE_L2_X75I | + ISDN_FEATURE_L2_X75UI | + ISDN_FEATURE_L2_X75BUI; + if (profp->support1 & (1 << 2)) + card->interface.features |= + ISDN_FEATURE_L2_V11096 | + ISDN_FEATURE_L2_V11019 | + ISDN_FEATURE_L2_V11038; + if (profp->support1 & (1 << 8)) card->interface.features |= ISDN_FEATURE_L2_MODEM; card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */ strncpy(card->interface.id, id, sizeof(card->interface.id) - 1); @@ -2115,10 +2318,10 @@ static int capidrv_addcontr(u16 contr, struct capi_profile *profp) card->listentimer.data = (unsigned long)card; card->listentimer.function = listentimerfunc; send_listen(card); - mod_timer(&card->listentimer, jiffies + 60*HZ); + mod_timer(&card->listentimer, jiffies + 60 * HZ); printk(KERN_INFO "%s: now up (%d B channels)\n", - card->name, card->nbchan); + card->name, card->nbchan); enable_dchannel_trace(card); @@ -2151,7 +2354,7 @@ static int capidrv_delcontr(u16 contr) if (debugmode) printk(KERN_DEBUG "capidrv-%d: id=%d unloading\n", - card->contrnr, card->myid); + card->contrnr, card->myid); cmd.command = ISDN_STAT_STOP; cmd.driver = card->myid; @@ -2161,17 +2364,17 @@ static int capidrv_delcontr(u16 contr) cmd.command = ISDN_STAT_DISCH; cmd.driver = card->myid; - cmd.arg = card->nbchan-1; - cmd.parm.num[0] = 0; + cmd.arg = card->nbchan - 1; + cmd.parm.num[0] = 0; if (debugmode) printk(KERN_DEBUG "capidrv-%d: id=%d disable chan=%ld\n", - card->contrnr, card->myid, cmd.arg); + card->contrnr, card->myid, cmd.arg); card->interface.statcallb(&cmd); - if (card->bchans[card->nbchan-1].nccip) - free_ncci(card, card->bchans[card->nbchan-1].nccip); - if (card->bchans[card->nbchan-1].plcip) - free_plci(card, card->bchans[card->nbchan-1].plcip); + if (card->bchans[card->nbchan - 1].nccip) + free_ncci(card, card->bchans[card->nbchan - 1].nccip); + if (card->bchans[card->nbchan - 1].plcip) + free_plci(card, card->bchans[card->nbchan - 1].plcip); if (card->plci_list) printk(KERN_ERR "capidrv: bug in free_plci()\n"); card->nbchan--; @@ -2181,7 +2384,7 @@ static int capidrv_delcontr(u16 contr) if (debugmode) printk(KERN_DEBUG "capidrv-%d: id=%d isdn unload\n", - card->contrnr, card->myid); + card->contrnr, card->myid); cmd.command = ISDN_STAT_UNLOAD; cmd.driver = card->myid; @@ -2189,7 +2392,7 @@ static int capidrv_delcontr(u16 contr) if (debugmode) printk(KERN_DEBUG "capidrv-%d: id=%d remove contr from list\n", - card->contrnr, card->myid); + card->contrnr, card->myid); spin_lock_irqsave(&global_lock, flags); for (pp = &global.contr_list; *pp; pp = &(*pp)->next) { @@ -2209,96 +2412,73 @@ 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; } /* * /proc/capi/capidrv: * nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt */ -static int proc_capidrv_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int capidrv_proc_show(struct seq_file *m, void *v) +{ + seq_printf(m, "%lu %lu %lu %lu\n", + global.ap.nrecvctlpkt, + global.ap.nrecvdatapkt, + global.ap.nsentctlpkt, + global.ap.nsentdatapkt); + return 0; +} + +static int capidrv_proc_open(struct inode *inode, struct file *file) { - int len = 0; - - len += sprintf(page+len, "%lu %lu %lu %lu\n", - global.ap.nrecvctlpkt, - global.ap.nrecvdatapkt, - global.ap.nsentctlpkt, - global.ap.nsentdatapkt); - if (off+count >= len) - *eof = 1; - if (len < off) - return 0; - *start = page + off; - return ((count < len-off) ? count : len-off); + return single_open(file, capidrv_proc_show, NULL); } -static struct procfsentries { - char *name; - mode_t mode; - int (*read_proc)(char *page, char **start, off_t off, - int count, int *eof, void *data); - struct proc_dir_entry *procent; -} procfsentries[] = { - /* { "capi", S_IFDIR, 0 }, */ - { "capi/capidrv", 0 , proc_capidrv_read_proc }, +static const struct file_operations capidrv_proc_fops = { + .owner = THIS_MODULE, + .open = capidrv_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, }; static void __init proc_init(void) { - int nelem = ARRAY_SIZE(procfsentries); - int i; - - for (i=0; i < nelem; i++) { - struct procfsentries *p = procfsentries + i; - p->procent = create_proc_entry(p->name, p->mode, NULL); - if (p->procent) p->procent->read_proc = p->read_proc; - } + proc_create("capi/capidrv", 0, NULL, &capidrv_proc_fops); } static void __exit proc_exit(void) { - int nelem = ARRAY_SIZE(procfsentries); - int i; - - for (i=nelem-1; i >= 0; i--) { - struct procfsentries *p = procfsentries + i; - if (p->procent) { - remove_proc_entry(p->name, NULL); - p->procent = NULL; - } - } + 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; - char rev[32]; - char *p; u32 ncontr, contr; u16 errcode; - if ((p = strchr(revision, ':')) != NULL && p[1]) { - strncpy(rev, p + 2, sizeof(rev)); - rev[sizeof(rev)-1] = 0; - if ((p = strchr(rev, '$')) != NULL && p > rev) - *(p-1) = 0; - } else - strcpy(rev, "1.0"); - global.ap.rparam.level3cnt = -2; /* number of bchannels twice */ global.ap.rparam.datablkcnt = 16; global.ap.rparam.datablklen = 2048; @@ -2309,10 +2489,11 @@ 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) { + unregister_capictr_notifier(&capictr_nb); capi20_release(&global.ap); return -EIO; } @@ -2326,29 +2507,15 @@ static int __init capidrv_init(void) } proc_init(); - printk(KERN_NOTICE "capidrv: Rev %s: loaded\n", rev); return 0; } static void __exit capidrv_exit(void) { - char rev[32]; - char *p; - - if ((p = strchr(revision, ':')) != NULL) { - strncpy(rev, p + 1, sizeof(rev)); - rev[sizeof(rev)-1] = 0; - if ((p = strchr(rev, '$')) != NULL) - *p = 0; - } else { - strcpy(rev, " ??? "); - } - + unregister_capictr_notifier(&capictr_nb); capi20_release(&global.ap); proc_exit(); - - printk(KERN_NOTICE "capidrv: Rev%s: unloaded\n", rev); } module_init(capidrv_init); diff --git a/drivers/isdn/capi/capidrv.h b/drivers/isdn/capi/capidrv.h index 1e698e1e269..4466b2e0176 100644 --- a/drivers/isdn/capi/capidrv.h +++ b/drivers/isdn/capi/capidrv.h @@ -34,7 +34,7 @@ * per plci state machine */ #define ST_PLCI_NONE 0 /* P-0 */ -#define ST_PLCI_OUTGOING 1 /* P-0.1 */ +#define ST_PLCI_OUTGOING 1 /* P-0.1 */ #define ST_PLCI_ALLOCATED 2 /* P-1 */ #define ST_PLCI_ACTIVE 3 /* P-ACT */ #define ST_PLCI_INCOMING 4 /* P-2 */ @@ -47,20 +47,20 @@ #define ST_PLCI_HELD 11 /* P-HELD */ #define EV_PLCI_CONNECT_REQ 1 /* P-0 -> P-0.1 - */ + */ #define EV_PLCI_CONNECT_CONF_ERROR 2 /* P-0.1 -> P-0 - */ + */ #define EV_PLCI_CONNECT_CONF_OK 3 /* P-0.1 -> P-1 - */ + */ #define EV_PLCI_FACILITY_IND_UP 4 /* P-0 -> P-1 - */ + */ #define EV_PLCI_CONNECT_IND 5 /* P-0 -> P-2 - */ + */ #define EV_PLCI_CONNECT_ACTIVE_IND 6 /* P-1 -> P-ACT - */ + */ #define EV_PLCI_CONNECT_REJECT 7 /* P-2 -> P-5 P-3 -> P-5 - */ + */ #define EV_PLCI_DISCONNECT_REQ 8 /* P-1 -> P-5 P-2 -> P-5 P-3 -> P-5 @@ -68,7 +68,7 @@ P-ACT -> P-5 P-Res -> P-5 (*) P-HELD -> P-5 (*) - */ + */ #define EV_PLCI_DISCONNECT_IND 9 /* P-1 -> P-6 P-2 -> P-6 P-3 -> P-6 @@ -77,35 +77,35 @@ P-ACT -> P-6 P-Res -> P-6 (*) P-HELD -> P-6 (*) - */ + */ #define EV_PLCI_FACILITY_IND_DOWN 10 /* P-0.1 -> P-5 P-1 -> P-5 P-ACT -> P-5 P-2 -> P-5 P-3 -> P-5 P-4 -> P-5 - */ + */ #define EV_PLCI_DISCONNECT_RESP 11 /* P-6 -> P-0 - */ + */ #define EV_PLCI_CONNECT_RESP 12 /* P-6 -> P-0 - */ + */ #define EV_PLCI_RESUME_REQ 13 /* P-0 -> P-0.Res - */ + */ #define EV_PLCI_RESUME_CONF_OK 14 /* P-0.Res -> P-Res - */ + */ #define EV_PLCI_RESUME_CONF_ERROR 15 /* P-0.Res -> P-0 - */ + */ #define EV_PLCI_RESUME_IND 16 /* P-Res -> P-ACT - */ + */ #define EV_PLCI_HOLD_IND 17 /* P-ACT -> P-HELD - */ + */ #define EV_PLCI_RETRIEVE_IND 18 /* P-HELD -> P-ACT - */ + */ #define EV_PLCI_SUSPEND_IND 19 /* P-ACT -> P-5 - */ + */ #define EV_PLCI_CD_IND 20 /* P-2 -> P-5 - */ + */ /* * per ncci state machine diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c deleted file mode 100644 index b129409925a..00000000000 --- a/drivers/isdn/capi/capifs.c +++ /dev/null @@ -1,221 +0,0 @@ -/* $Id: capifs.c,v 1.1.2.3 2004/01/16 21:09:26 keil Exp $ - * - * Copyright 2000 by Carsten Paeth <calle@calle.de> - * - * Heavily based on devpts filesystem from H. Peter Anvin - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/fs.h> -#include <linux/mount.h> -#include <linux/namei.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/ctype.h> -#include <linux/sched.h> /* current */ - -#include "capifs.h" - -MODULE_DESCRIPTION("CAPI4Linux: /dev/capi/ filesystem"); -MODULE_AUTHOR("Carsten Paeth"); -MODULE_LICENSE("GPL"); - -/* ------------------------------------------------------------------ */ - -static char *revision = "$Revision: 1.1.2.3 $"; - -/* ------------------------------------------------------------------ */ - -#define CAPIFS_SUPER_MAGIC (('C'<<8)|'N') - -static struct vfsmount *capifs_mnt; -static struct dentry *capifs_root; - -static struct { - int setuid; - int setgid; - uid_t uid; - gid_t gid; - umode_t mode; -} config = {.mode = 0600}; - -/* ------------------------------------------------------------------ */ - -static int capifs_remount(struct super_block *s, int *flags, char *data) -{ - int setuid = 0; - int setgid = 0; - uid_t uid = 0; - gid_t gid = 0; - umode_t mode = 0600; - char *this_char; - char *new_opt = kstrdup(data, GFP_KERNEL); - - this_char = NULL; - while ((this_char = strsep(&data, ",")) != NULL) { - int n; - char dummy; - if (!*this_char) - continue; - if (sscanf(this_char, "uid=%i%c", &n, &dummy) == 1) { - setuid = 1; - uid = n; - } else if (sscanf(this_char, "gid=%i%c", &n, &dummy) == 1) { - setgid = 1; - gid = n; - } else if (sscanf(this_char, "mode=%o%c", &n, &dummy) == 1) - mode = n & ~S_IFMT; - else { - kfree(new_opt); - printk("capifs: called with bogus options\n"); - return -EINVAL; - } - } - - kfree(s->s_options); - s->s_options = new_opt; - - config.setuid = setuid; - config.setgid = setgid; - config.uid = uid; - config.gid = gid; - config.mode = mode; - - return 0; -} - -static struct super_operations capifs_sops = -{ - .statfs = simple_statfs, - .remount_fs = capifs_remount, - .show_options = generic_show_options, -}; - - -static int -capifs_fill_super(struct super_block *s, void *data, int silent) -{ - struct inode * inode; - - s->s_blocksize = 1024; - s->s_blocksize_bits = 10; - s->s_magic = CAPIFS_SUPER_MAGIC; - s->s_op = &capifs_sops; - s->s_time_gran = 1; - - inode = new_inode(s); - if (!inode) - goto fail; - inode->i_ino = 1; - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; - inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; - inode->i_op = &simple_dir_inode_operations; - inode->i_fop = &simple_dir_operations; - inode->i_nlink = 2; - - capifs_root = s->s_root = d_alloc_root(inode); - if (s->s_root) - return 0; - - printk("capifs: get root dentry failed\n"); - iput(inode); -fail: - return -ENOMEM; -} - -static int capifs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) -{ - return get_sb_single(fs_type, flags, data, capifs_fill_super, mnt); -} - -static struct file_system_type capifs_fs_type = { - .owner = THIS_MODULE, - .name = "capifs", - .get_sb = capifs_get_sb, - .kill_sb = kill_anon_super, -}; - -static struct dentry *get_node(int num) -{ - char s[10]; - struct dentry *root = capifs_root; - mutex_lock(&root->d_inode->i_mutex); - return lookup_one_len(s, root, sprintf(s, "%d", num)); -} - -void capifs_new_ncci(unsigned int number, dev_t device) -{ - struct dentry *dentry; - struct inode *inode = new_inode(capifs_mnt->mnt_sb); - if (!inode) - return; - inode->i_ino = number+2; - inode->i_uid = config.setuid ? config.uid : current_fsuid(); - inode->i_gid = config.setgid ? config.gid : current_fsgid(); - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; - init_special_inode(inode, S_IFCHR|config.mode, device); - //inode->i_op = &capifs_file_inode_operations; - - dentry = get_node(number); - if (!IS_ERR(dentry) && !dentry->d_inode) - d_instantiate(dentry, inode); - mutex_unlock(&capifs_root->d_inode->i_mutex); -} - -void capifs_free_ncci(unsigned int number) -{ - struct dentry *dentry = get_node(number); - - if (!IS_ERR(dentry)) { - struct inode *inode = dentry->d_inode; - if (inode) { - inode->i_nlink--; - d_delete(dentry); - dput(dentry); - } - dput(dentry); - } - mutex_unlock(&capifs_root->d_inode->i_mutex); -} - -static int __init capifs_init(void) -{ - char rev[32]; - char *p; - int err; - - if ((p = strchr(revision, ':')) != NULL && p[1]) { - strlcpy(rev, p + 2, sizeof(rev)); - if ((p = strchr(rev, '$')) != NULL && p > rev) - *(p-1) = 0; - } else - strcpy(rev, "1.0"); - - err = register_filesystem(&capifs_fs_type); - if (!err) { - capifs_mnt = kern_mount(&capifs_fs_type); - if (IS_ERR(capifs_mnt)) { - err = PTR_ERR(capifs_mnt); - unregister_filesystem(&capifs_fs_type); - } - } - if (!err) - printk(KERN_NOTICE "capifs: Rev %s\n", rev); - return err; -} - -static void __exit capifs_exit(void) -{ - unregister_filesystem(&capifs_fs_type); - mntput(capifs_mnt); -} - -EXPORT_SYMBOL(capifs_new_ncci); -EXPORT_SYMBOL(capifs_free_ncci); - -module_init(capifs_init); -module_exit(capifs_exit); diff --git a/drivers/isdn/capi/capifs.h b/drivers/isdn/capi/capifs.h deleted file mode 100644 index d0bd4c3c430..00000000000 --- a/drivers/isdn/capi/capifs.h +++ /dev/null @@ -1,11 +0,0 @@ -/* $Id: capifs.h,v 1.1.2.2 2004/01/16 21:09:26 keil Exp $ - * - * Copyright 2000 by Carsten Paeth <calle@calle.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -void capifs_new_ncci(unsigned int num, dev_t device); -void capifs_free_ncci(unsigned int num); diff --git a/drivers/isdn/capi/capilib.c b/drivers/isdn/capi/capilib.c index fcaa1241ee7..33361f833c0 100644 --- a/drivers/isdn/capi/capilib.c +++ b/drivers/isdn/capi/capilib.c @@ -1,11 +1,12 @@ +#include <linux/slab.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/isdn/capilli.h> -#define DBG(format, arg...) do { \ -printk(KERN_DEBUG "%s: " format "\n" , __func__ , ## arg); \ -} while (0) +#define DBG(format, arg...) do { \ + printk(KERN_DEBUG "%s: " format "\n" , __func__ , ## arg); \ + } while (0) struct capilib_msgidqueue { struct capilib_msgidqueue *next; @@ -27,7 +28,7 @@ struct capilib_ncci { // --------------------------------------------------------------------------- // NCCI Handling -static inline void mq_init(struct capilib_ncci * np) +static inline void mq_init(struct capilib_ncci *np) { u_int i; np->msgidqueue = NULL; @@ -41,7 +42,7 @@ static inline void mq_init(struct capilib_ncci * np) } } -static inline int mq_enqueue(struct capilib_ncci * np, u16 msgid) +static inline int mq_enqueue(struct capilib_ncci *np, u16 msgid) { struct capilib_msgidqueue *mq; if ((mq = np->msgidfree) == NULL) @@ -58,7 +59,7 @@ static inline int mq_enqueue(struct capilib_ncci * np, u16 msgid) return 1; } -static inline int mq_dequeue(struct capilib_ncci * np, u16 msgid) +static inline int mq_dequeue(struct capilib_ncci *np, u16 msgid) { struct capilib_msgidqueue **pp; for (pp = &np->msgidqueue; *pp; pp = &(*pp)->next) { @@ -164,7 +165,7 @@ u16 capilib_data_b3_req(struct list_head *head, u16 applid, u32 ncci, u16 msgid) continue; if (np->ncci != ncci) continue; - + if (mq_enqueue(np, msgid) == 0) return CAPI_SENDQUEUEFULL; @@ -187,7 +188,7 @@ void capilib_data_b3_conf(struct list_head *head, u16 applid, u32 ncci, u16 msgi continue; if (np->ncci != ncci) continue; - + if (mq_dequeue(np, msgid) == 0) { printk(KERN_ERR "kcapi: msgid %hu ncci 0x%x not on queue\n", msgid, ncci); diff --git a/drivers/isdn/capi/capiutil.c b/drivers/isdn/capi/capiutil.c index 29419a8d31d..6e797e502cf 100644 --- a/drivers/isdn/capi/capiutil.c +++ b/drivers/isdn/capi/capiutil.c @@ -18,208 +18,10 @@ #include <linux/mm.h> #include <linux/init.h> #include <linux/isdn/capiutil.h> +#include <linux/slab.h> /* from CAPI2.0 DDK AVM Berlin GmbH */ -#ifndef CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON -char *capi_info2str(u16 reason) -{ - return ".."; -} -#else -char *capi_info2str(u16 reason) -{ - switch (reason) { - -/*-- informative values (corresponding message was processed) -----*/ - case 0x0001: - return "NCPI not supported by current protocol, NCPI ignored"; - case 0x0002: - return "Flags not supported by current protocol, flags ignored"; - case 0x0003: - return "Alert already sent by another application"; - -/*-- error information concerning CAPI_REGISTER -----*/ - case 0x1001: - return "Too many applications"; - case 0x1002: - return "Logical block size too small, must be at least 128 Bytes"; - case 0x1003: - return "Buffer exceeds 64 kByte"; - case 0x1004: - return "Message buffer size too small, must be at least 1024 Bytes"; - case 0x1005: - return "Max. number of logical connections not supported"; - case 0x1006: - return "Reserved"; - case 0x1007: - return "The message could not be accepted because of an internal busy condition"; - case 0x1008: - return "OS resource error (no memory ?)"; - case 0x1009: - return "CAPI not installed"; - case 0x100A: - return "Controller does not support external equipment"; - case 0x100B: - return "Controller does only support external equipment"; - -/*-- error information concerning message exchange functions -----*/ - case 0x1101: - return "Illegal application number"; - case 0x1102: - return "Illegal command or subcommand or message length less than 12 bytes"; - case 0x1103: - return "The message could not be accepted because of a queue full condition !! The error code does not imply that CAPI cannot receive messages directed to another controller, PLCI or NCCI"; - case 0x1104: - return "Queue is empty"; - case 0x1105: - return "Queue overflow, a message was lost !! This indicates a configuration error. The only recovery from this error is to perform a CAPI_RELEASE"; - case 0x1106: - return "Unknown notification parameter"; - case 0x1107: - return "The Message could not be accepted because of an internal busy condition"; - case 0x1108: - return "OS Resource error (no memory ?)"; - case 0x1109: - return "CAPI not installed"; - case 0x110A: - return "Controller does not support external equipment"; - case 0x110B: - return "Controller does only support external equipment"; - -/*-- error information concerning resource / coding problems -----*/ - case 0x2001: - return "Message not supported in current state"; - case 0x2002: - return "Illegal Controller / PLCI / NCCI"; - case 0x2003: - return "Out of PLCI"; - case 0x2004: - return "Out of NCCI"; - case 0x2005: - return "Out of LISTEN"; - case 0x2006: - return "Out of FAX resources (protocol T.30)"; - case 0x2007: - return "Illegal message parameter coding"; - -/*-- error information concerning requested services -----*/ - case 0x3001: - return "B1 protocol not supported"; - case 0x3002: - return "B2 protocol not supported"; - case 0x3003: - return "B3 protocol not supported"; - case 0x3004: - return "B1 protocol parameter not supported"; - case 0x3005: - return "B2 protocol parameter not supported"; - case 0x3006: - return "B3 protocol parameter not supported"; - case 0x3007: - return "B protocol combination not supported"; - case 0x3008: - return "NCPI not supported"; - case 0x3009: - return "CIP Value unknown"; - case 0x300A: - return "Flags not supported (reserved bits)"; - case 0x300B: - return "Facility not supported"; - case 0x300C: - return "Data length not supported by current protocol"; - case 0x300D: - return "Reset procedure not supported by current protocol"; - -/*-- informations about the clearing of a physical connection -----*/ - case 0x3301: - return "Protocol error layer 1 (broken line or B-channel removed by signalling protocol)"; - case 0x3302: - return "Protocol error layer 2"; - case 0x3303: - return "Protocol error layer 3"; - case 0x3304: - return "Another application got that call"; -/*-- T.30 specific reasons -----*/ - case 0x3311: - return "Connecting not successful (remote station is no FAX G3 machine)"; - case 0x3312: - return "Connecting not successful (training error)"; - case 0x3313: - return "Disconnected before transfer (remote station does not support transfer mode, e.g. resolution)"; - case 0x3314: - return "Disconnected during transfer (remote abort)"; - case 0x3315: - return "Disconnected during transfer (remote procedure error, e.g. unsuccessful repetition of T.30 commands)"; - case 0x3316: - return "Disconnected during transfer (local tx data underrun)"; - case 0x3317: - return "Disconnected during transfer (local rx data overflow)"; - case 0x3318: - return "Disconnected during transfer (local abort)"; - case 0x3319: - return "Illegal parameter coding (e.g. SFF coding error)"; - -/*-- disconnect causes from the network according to ETS 300 102-1/Q.931 -----*/ - case 0x3481: return "Unallocated (unassigned) number"; - case 0x3482: return "No route to specified transit network"; - case 0x3483: return "No route to destination"; - case 0x3486: return "Channel unacceptable"; - case 0x3487: - return "Call awarded and being delivered in an established channel"; - case 0x3490: return "Normal call clearing"; - case 0x3491: return "User busy"; - case 0x3492: return "No user responding"; - case 0x3493: return "No answer from user (user alerted)"; - case 0x3495: return "Call rejected"; - case 0x3496: return "Number changed"; - case 0x349A: return "Non-selected user clearing"; - case 0x349B: return "Destination out of order"; - case 0x349C: return "Invalid number format"; - case 0x349D: return "Facility rejected"; - case 0x349E: return "Response to STATUS ENQUIRY"; - case 0x349F: return "Normal, unspecified"; - case 0x34A2: return "No circuit / channel available"; - case 0x34A6: return "Network out of order"; - case 0x34A9: return "Temporary failure"; - case 0x34AA: return "Switching equipment congestion"; - case 0x34AB: return "Access information discarded"; - case 0x34AC: return "Requested circuit / channel not available"; - case 0x34AF: return "Resources unavailable, unspecified"; - case 0x34B1: return "Quality of service unavailable"; - case 0x34B2: return "Requested facility not subscribed"; - case 0x34B9: return "Bearer capability not authorized"; - case 0x34BA: return "Bearer capability not presently available"; - case 0x34BF: return "Service or option not available, unspecified"; - case 0x34C1: return "Bearer capability not implemented"; - case 0x34C2: return "Channel type not implemented"; - case 0x34C5: return "Requested facility not implemented"; - case 0x34C6: return "Only restricted digital information bearer capability is available"; - case 0x34CF: return "Service or option not implemented, unspecified"; - case 0x34D1: return "Invalid call reference value"; - case 0x34D2: return "Identified channel does not exist"; - case 0x34D3: return "A suspended call exists, but this call identity does not"; - case 0x34D4: return "Call identity in use"; - case 0x34D5: return "No call suspended"; - case 0x34D6: return "Call having the requested call identity has been cleared"; - case 0x34D8: return "Incompatible destination"; - case 0x34DB: return "Invalid transit network selection"; - case 0x34DF: return "Invalid message, unspecified"; - case 0x34E0: return "Mandatory information element is missing"; - case 0x34E1: return "Message type non-existent or not implemented"; - case 0x34E2: return "Message not compatible with call state or message type non-existent or not implemented"; - case 0x34E3: return "Information element non-existent or not implemented"; - case 0x34E4: return "Invalid information element contents"; - case 0x34E5: return "Message not compatible with call state"; - case 0x34E6: return "Recovery on timer expiry"; - case 0x34EF: return "Protocol error, unspecified"; - case 0x34FF: return "Interworking, unspecified"; - - default: return "No additional information"; - } -} -#endif - typedef struct { int typ; size_t off; @@ -234,169 +36,169 @@ typedef struct { static _cdef cdef[] = { - /*00 */ - {_CEND}, - /*01 */ - {_CEND}, - /*02 */ - {_CEND}, - /*03 */ - {_CDWORD, offsetof(_cmsg, adr.adrController)}, - /*04 */ - {_CMSTRUCT, offsetof(_cmsg, AdditionalInfo)}, - /*05 */ - {_CSTRUCT, offsetof(_cmsg, B1configuration)}, - /*06 */ - {_CWORD, offsetof(_cmsg, B1protocol)}, - /*07 */ - {_CSTRUCT, offsetof(_cmsg, B2configuration)}, - /*08 */ - {_CWORD, offsetof(_cmsg, B2protocol)}, - /*09 */ - {_CSTRUCT, offsetof(_cmsg, B3configuration)}, - /*0a */ - {_CWORD, offsetof(_cmsg, B3protocol)}, - /*0b */ - {_CSTRUCT, offsetof(_cmsg, BC)}, - /*0c */ - {_CSTRUCT, offsetof(_cmsg, BChannelinformation)}, - /*0d */ - {_CMSTRUCT, offsetof(_cmsg, BProtocol)}, - /*0e */ - {_CSTRUCT, offsetof(_cmsg, CalledPartyNumber)}, - /*0f */ - {_CSTRUCT, offsetof(_cmsg, CalledPartySubaddress)}, - /*10 */ - {_CSTRUCT, offsetof(_cmsg, CallingPartyNumber)}, - /*11 */ - {_CSTRUCT, offsetof(_cmsg, CallingPartySubaddress)}, - /*12 */ - {_CDWORD, offsetof(_cmsg, CIPmask)}, - /*13 */ - {_CDWORD, offsetof(_cmsg, CIPmask2)}, - /*14 */ - {_CWORD, offsetof(_cmsg, CIPValue)}, - /*15 */ - {_CDWORD, offsetof(_cmsg, Class)}, - /*16 */ - {_CSTRUCT, offsetof(_cmsg, ConnectedNumber)}, - /*17 */ - {_CSTRUCT, offsetof(_cmsg, ConnectedSubaddress)}, - /*18 */ - {_CDWORD, offsetof(_cmsg, Data)}, - /*19 */ - {_CWORD, offsetof(_cmsg, DataHandle)}, - /*1a */ - {_CWORD, offsetof(_cmsg, DataLength)}, - /*1b */ - {_CSTRUCT, offsetof(_cmsg, FacilityConfirmationParameter)}, - /*1c */ - {_CSTRUCT, offsetof(_cmsg, Facilitydataarray)}, - /*1d */ - {_CSTRUCT, offsetof(_cmsg, FacilityIndicationParameter)}, - /*1e */ - {_CSTRUCT, offsetof(_cmsg, FacilityRequestParameter)}, - /*1f */ - {_CWORD, offsetof(_cmsg, FacilitySelector)}, - /*20 */ - {_CWORD, offsetof(_cmsg, Flags)}, - /*21 */ - {_CDWORD, offsetof(_cmsg, Function)}, - /*22 */ - {_CSTRUCT, offsetof(_cmsg, HLC)}, - /*23 */ - {_CWORD, offsetof(_cmsg, Info)}, - /*24 */ - {_CSTRUCT, offsetof(_cmsg, InfoElement)}, - /*25 */ - {_CDWORD, offsetof(_cmsg, InfoMask)}, - /*26 */ - {_CWORD, offsetof(_cmsg, InfoNumber)}, - /*27 */ - {_CSTRUCT, offsetof(_cmsg, Keypadfacility)}, - /*28 */ - {_CSTRUCT, offsetof(_cmsg, LLC)}, - /*29 */ - {_CSTRUCT, offsetof(_cmsg, ManuData)}, - /*2a */ - {_CDWORD, offsetof(_cmsg, ManuID)}, - /*2b */ - {_CSTRUCT, offsetof(_cmsg, NCPI)}, - /*2c */ - {_CWORD, offsetof(_cmsg, Reason)}, - /*2d */ - {_CWORD, offsetof(_cmsg, Reason_B3)}, - /*2e */ - {_CWORD, offsetof(_cmsg, Reject)}, - /*2f */ - {_CSTRUCT, offsetof(_cmsg, Useruserdata)} + /*00 */ + {_CEND}, + /*01 */ + {_CEND}, + /*02 */ + {_CEND}, + /*03 */ + {_CDWORD, offsetof(_cmsg, adr.adrController)}, + /*04 */ + {_CMSTRUCT, offsetof(_cmsg, AdditionalInfo)}, + /*05 */ + {_CSTRUCT, offsetof(_cmsg, B1configuration)}, + /*06 */ + {_CWORD, offsetof(_cmsg, B1protocol)}, + /*07 */ + {_CSTRUCT, offsetof(_cmsg, B2configuration)}, + /*08 */ + {_CWORD, offsetof(_cmsg, B2protocol)}, + /*09 */ + {_CSTRUCT, offsetof(_cmsg, B3configuration)}, + /*0a */ + {_CWORD, offsetof(_cmsg, B3protocol)}, + /*0b */ + {_CSTRUCT, offsetof(_cmsg, BC)}, + /*0c */ + {_CSTRUCT, offsetof(_cmsg, BChannelinformation)}, + /*0d */ + {_CMSTRUCT, offsetof(_cmsg, BProtocol)}, + /*0e */ + {_CSTRUCT, offsetof(_cmsg, CalledPartyNumber)}, + /*0f */ + {_CSTRUCT, offsetof(_cmsg, CalledPartySubaddress)}, + /*10 */ + {_CSTRUCT, offsetof(_cmsg, CallingPartyNumber)}, + /*11 */ + {_CSTRUCT, offsetof(_cmsg, CallingPartySubaddress)}, + /*12 */ + {_CDWORD, offsetof(_cmsg, CIPmask)}, + /*13 */ + {_CDWORD, offsetof(_cmsg, CIPmask2)}, + /*14 */ + {_CWORD, offsetof(_cmsg, CIPValue)}, + /*15 */ + {_CDWORD, offsetof(_cmsg, Class)}, + /*16 */ + {_CSTRUCT, offsetof(_cmsg, ConnectedNumber)}, + /*17 */ + {_CSTRUCT, offsetof(_cmsg, ConnectedSubaddress)}, + /*18 */ + {_CDWORD, offsetof(_cmsg, Data)}, + /*19 */ + {_CWORD, offsetof(_cmsg, DataHandle)}, + /*1a */ + {_CWORD, offsetof(_cmsg, DataLength)}, + /*1b */ + {_CSTRUCT, offsetof(_cmsg, FacilityConfirmationParameter)}, + /*1c */ + {_CSTRUCT, offsetof(_cmsg, Facilitydataarray)}, + /*1d */ + {_CSTRUCT, offsetof(_cmsg, FacilityIndicationParameter)}, + /*1e */ + {_CSTRUCT, offsetof(_cmsg, FacilityRequestParameter)}, + /*1f */ + {_CWORD, offsetof(_cmsg, FacilitySelector)}, + /*20 */ + {_CWORD, offsetof(_cmsg, Flags)}, + /*21 */ + {_CDWORD, offsetof(_cmsg, Function)}, + /*22 */ + {_CSTRUCT, offsetof(_cmsg, HLC)}, + /*23 */ + {_CWORD, offsetof(_cmsg, Info)}, + /*24 */ + {_CSTRUCT, offsetof(_cmsg, InfoElement)}, + /*25 */ + {_CDWORD, offsetof(_cmsg, InfoMask)}, + /*26 */ + {_CWORD, offsetof(_cmsg, InfoNumber)}, + /*27 */ + {_CSTRUCT, offsetof(_cmsg, Keypadfacility)}, + /*28 */ + {_CSTRUCT, offsetof(_cmsg, LLC)}, + /*29 */ + {_CSTRUCT, offsetof(_cmsg, ManuData)}, + /*2a */ + {_CDWORD, offsetof(_cmsg, ManuID)}, + /*2b */ + {_CSTRUCT, offsetof(_cmsg, NCPI)}, + /*2c */ + {_CWORD, offsetof(_cmsg, Reason)}, + /*2d */ + {_CWORD, offsetof(_cmsg, Reason_B3)}, + /*2e */ + {_CWORD, offsetof(_cmsg, Reject)}, + /*2f */ + {_CSTRUCT, offsetof(_cmsg, Useruserdata)} }; static unsigned char *cpars[] = { - /* ALERT_REQ */ [0x01] = "\x03\x04\x0c\x27\x2f\x1c\x01\x01", - /* CONNECT_REQ */ [0x02] = "\x03\x14\x0e\x10\x0f\x11\x0d\x06\x08\x0a\x05\x07\x09\x01\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01", - /* DISCONNECT_REQ */ [0x04] = "\x03\x04\x0c\x27\x2f\x1c\x01\x01", - /* LISTEN_REQ */ [0x05] = "\x03\x25\x12\x13\x10\x11\x01", - /* INFO_REQ */ [0x08] = "\x03\x0e\x04\x0c\x27\x2f\x1c\x01\x01", - /* FACILITY_REQ */ [0x09] = "\x03\x1f\x1e\x01", - /* SELECT_B_PROTOCOL_REQ */ [0x0a] = "\x03\x0d\x06\x08\x0a\x05\x07\x09\x01\x01", - /* CONNECT_B3_REQ */ [0x0b] = "\x03\x2b\x01", - /* DISCONNECT_B3_REQ */ [0x0d] = "\x03\x2b\x01", - /* DATA_B3_REQ */ [0x0f] = "\x03\x18\x1a\x19\x20\x01", - /* RESET_B3_REQ */ [0x10] = "\x03\x2b\x01", - /* ALERT_CONF */ [0x13] = "\x03\x23\x01", - /* CONNECT_CONF */ [0x14] = "\x03\x23\x01", - /* DISCONNECT_CONF */ [0x16] = "\x03\x23\x01", - /* LISTEN_CONF */ [0x17] = "\x03\x23\x01", - /* MANUFACTURER_REQ */ [0x18] = "\x03\x2a\x15\x21\x29\x01", - /* INFO_CONF */ [0x1a] = "\x03\x23\x01", - /* FACILITY_CONF */ [0x1b] = "\x03\x23\x1f\x1b\x01", - /* SELECT_B_PROTOCOL_CONF */ [0x1c] = "\x03\x23\x01", - /* CONNECT_B3_CONF */ [0x1d] = "\x03\x23\x01", - /* DISCONNECT_B3_CONF */ [0x1f] = "\x03\x23\x01", - /* DATA_B3_CONF */ [0x21] = "\x03\x19\x23\x01", - /* RESET_B3_CONF */ [0x22] = "\x03\x23\x01", - /* CONNECT_IND */ [0x26] = "\x03\x14\x0e\x10\x0f\x11\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01", - /* CONNECT_ACTIVE_IND */ [0x27] = "\x03\x16\x17\x28\x01", - /* DISCONNECT_IND */ [0x28] = "\x03\x2c\x01", - /* MANUFACTURER_CONF */ [0x2a] = "\x03\x2a\x15\x21\x29\x01", - /* INFO_IND */ [0x2c] = "\x03\x26\x24\x01", - /* FACILITY_IND */ [0x2d] = "\x03\x1f\x1d\x01", - /* CONNECT_B3_IND */ [0x2f] = "\x03\x2b\x01", - /* CONNECT_B3_ACTIVE_IND */ [0x30] = "\x03\x2b\x01", - /* DISCONNECT_B3_IND */ [0x31] = "\x03\x2d\x2b\x01", - /* DATA_B3_IND */ [0x33] = "\x03\x18\x1a\x19\x20\x01", - /* RESET_B3_IND */ [0x34] = "\x03\x2b\x01", - /* CONNECT_B3_T90_ACTIVE_IND */ [0x35] = "\x03\x2b\x01", - /* CONNECT_RESP */ [0x38] = "\x03\x2e\x0d\x06\x08\x0a\x05\x07\x09\x01\x16\x17\x28\x04\x0c\x27\x2f\x1c\x01\x01", - /* CONNECT_ACTIVE_RESP */ [0x39] = "\x03\x01", - /* DISCONNECT_RESP */ [0x3a] = "\x03\x01", - /* MANUFACTURER_IND */ [0x3c] = "\x03\x2a\x15\x21\x29\x01", - /* INFO_RESP */ [0x3e] = "\x03\x01", - /* FACILITY_RESP */ [0x3f] = "\x03\x1f\x01", - /* CONNECT_B3_RESP */ [0x41] = "\x03\x2e\x2b\x01", - /* CONNECT_B3_ACTIVE_RESP */ [0x42] = "\x03\x01", - /* DISCONNECT_B3_RESP */ [0x43] = "\x03\x01", - /* DATA_B3_RESP */ [0x45] = "\x03\x19\x01", - /* RESET_B3_RESP */ [0x46] = "\x03\x01", - /* CONNECT_B3_T90_ACTIVE_RESP */ [0x47] = "\x03\x01", - /* MANUFACTURER_RESP */ [0x4e] = "\x03\x2a\x15\x21\x29\x01", + /* ALERT_REQ */ [0x01] = "\x03\x04\x0c\x27\x2f\x1c\x01\x01", + /* CONNECT_REQ */ [0x02] = "\x03\x14\x0e\x10\x0f\x11\x0d\x06\x08\x0a\x05\x07\x09\x01\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01", + /* DISCONNECT_REQ */ [0x04] = "\x03\x04\x0c\x27\x2f\x1c\x01\x01", + /* LISTEN_REQ */ [0x05] = "\x03\x25\x12\x13\x10\x11\x01", + /* INFO_REQ */ [0x08] = "\x03\x0e\x04\x0c\x27\x2f\x1c\x01\x01", + /* FACILITY_REQ */ [0x09] = "\x03\x1f\x1e\x01", + /* SELECT_B_PROTOCOL_REQ */ [0x0a] = "\x03\x0d\x06\x08\x0a\x05\x07\x09\x01\x01", + /* CONNECT_B3_REQ */ [0x0b] = "\x03\x2b\x01", + /* DISCONNECT_B3_REQ */ [0x0d] = "\x03\x2b\x01", + /* DATA_B3_REQ */ [0x0f] = "\x03\x18\x1a\x19\x20\x01", + /* RESET_B3_REQ */ [0x10] = "\x03\x2b\x01", + /* ALERT_CONF */ [0x13] = "\x03\x23\x01", + /* CONNECT_CONF */ [0x14] = "\x03\x23\x01", + /* DISCONNECT_CONF */ [0x16] = "\x03\x23\x01", + /* LISTEN_CONF */ [0x17] = "\x03\x23\x01", + /* MANUFACTURER_REQ */ [0x18] = "\x03\x2a\x15\x21\x29\x01", + /* INFO_CONF */ [0x1a] = "\x03\x23\x01", + /* FACILITY_CONF */ [0x1b] = "\x03\x23\x1f\x1b\x01", + /* SELECT_B_PROTOCOL_CONF */ [0x1c] = "\x03\x23\x01", + /* CONNECT_B3_CONF */ [0x1d] = "\x03\x23\x01", + /* DISCONNECT_B3_CONF */ [0x1f] = "\x03\x23\x01", + /* DATA_B3_CONF */ [0x21] = "\x03\x19\x23\x01", + /* RESET_B3_CONF */ [0x22] = "\x03\x23\x01", + /* CONNECT_IND */ [0x26] = "\x03\x14\x0e\x10\x0f\x11\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01", + /* CONNECT_ACTIVE_IND */ [0x27] = "\x03\x16\x17\x28\x01", + /* DISCONNECT_IND */ [0x28] = "\x03\x2c\x01", + /* MANUFACTURER_CONF */ [0x2a] = "\x03\x2a\x15\x21\x29\x01", + /* INFO_IND */ [0x2c] = "\x03\x26\x24\x01", + /* FACILITY_IND */ [0x2d] = "\x03\x1f\x1d\x01", + /* CONNECT_B3_IND */ [0x2f] = "\x03\x2b\x01", + /* CONNECT_B3_ACTIVE_IND */ [0x30] = "\x03\x2b\x01", + /* DISCONNECT_B3_IND */ [0x31] = "\x03\x2d\x2b\x01", + /* DATA_B3_IND */ [0x33] = "\x03\x18\x1a\x19\x20\x01", + /* RESET_B3_IND */ [0x34] = "\x03\x2b\x01", + /* CONNECT_B3_T90_ACTIVE_IND */ [0x35] = "\x03\x2b\x01", + /* CONNECT_RESP */ [0x38] = "\x03\x2e\x0d\x06\x08\x0a\x05\x07\x09\x01\x16\x17\x28\x04\x0c\x27\x2f\x1c\x01\x01", + /* CONNECT_ACTIVE_RESP */ [0x39] = "\x03\x01", + /* DISCONNECT_RESP */ [0x3a] = "\x03\x01", + /* MANUFACTURER_IND */ [0x3c] = "\x03\x2a\x15\x21\x29\x01", + /* INFO_RESP */ [0x3e] = "\x03\x01", + /* FACILITY_RESP */ [0x3f] = "\x03\x1f\x01", + /* CONNECT_B3_RESP */ [0x41] = "\x03\x2e\x2b\x01", + /* CONNECT_B3_ACTIVE_RESP */ [0x42] = "\x03\x01", + /* DISCONNECT_B3_RESP */ [0x43] = "\x03\x01", + /* DATA_B3_RESP */ [0x45] = "\x03\x19\x01", + /* RESET_B3_RESP */ [0x46] = "\x03\x01", + /* CONNECT_B3_T90_ACTIVE_RESP */ [0x47] = "\x03\x01", + /* MANUFACTURER_RESP */ [0x4e] = "\x03\x2a\x15\x21\x29\x01", }; /*-------------------------------------------------------*/ -#define byteTLcpy(x,y) *(u8 *)(x)=*(u8 *)(y); -#define wordTLcpy(x,y) *(u16 *)(x)=*(u16 *)(y); -#define dwordTLcpy(x,y) memcpy(x,y,4); -#define structTLcpy(x,y,l) memcpy (x,y,l) -#define structTLcpyovl(x,y,l) memmove (x,y,l) +#define byteTLcpy(x, y) *(u8 *)(x) = *(u8 *)(y); +#define wordTLcpy(x, y) *(u16 *)(x) = *(u16 *)(y); +#define dwordTLcpy(x, y) memcpy(x, y, 4); +#define structTLcpy(x, y, l) memcpy(x, y, l) +#define structTLcpyovl(x, y, l) memmove(x, y, l) -#define byteTRcpy(x,y) *(u8 *)(y)=*(u8 *)(x); -#define wordTRcpy(x,y) *(u16 *)(y)=*(u16 *)(x); -#define dwordTRcpy(x,y) memcpy(y,x,4); -#define structTRcpy(x,y,l) memcpy (y,x,l) -#define structTRcpyovl(x,y,l) memmove (y,x,l) +#define byteTRcpy(x, y) *(u8 *)(y) = *(u8 *)(x); +#define wordTRcpy(x, y) *(u16 *)(y) = *(u16 *)(x); +#define dwordTRcpy(x, y) memcpy(y, x, 4); +#define structTRcpy(x, y, l) memcpy(y, x, l) +#define structTRcpyovl(x, y, l) memmove(y, x, l) /*-------------------------------------------------------*/ static unsigned command_2_index(unsigned c, unsigned sc) @@ -413,9 +215,9 @@ static unsigned command_2_index(unsigned c, unsigned sc) /*-------------------------------------------------------*/ #define TYP (cdef[cmsg->par[cmsg->p]].typ) -#define OFF (((u8 *)cmsg)+cdef[cmsg->par[cmsg->p]].off) +#define OFF (((u8 *)cmsg) + cdef[cmsg->par[cmsg->p]].off) -static void jumpcstruct(_cmsg * cmsg) +static void jumpcstruct(_cmsg *cmsg) { unsigned layer; for (cmsg->p++, layer = 1; layer;) { @@ -432,7 +234,7 @@ static void jumpcstruct(_cmsg * cmsg) } } /*-------------------------------------------------------*/ -static void pars_2_message(_cmsg * cmsg) +static void pars_2_message(_cmsg *cmsg) { for (; TYP != _CEND; cmsg->p++) { @@ -490,8 +292,15 @@ static void pars_2_message(_cmsg * cmsg) } } -/*-------------------------------------------------------*/ -unsigned capi_cmsg2message(_cmsg * cmsg, u8 * msg) +/** + * capi_cmsg2message() - assemble CAPI 2.0 message from _cmsg structure + * @cmsg: _cmsg structure + * @msg: buffer for assembled message + * + * Return value: 0 for success + */ + +unsigned capi_cmsg2message(_cmsg *cmsg, u8 *msg) { cmsg->m = msg; cmsg->l = 8; @@ -510,7 +319,7 @@ unsigned capi_cmsg2message(_cmsg * cmsg, u8 * msg) } /*-------------------------------------------------------*/ -static void message_2_pars(_cmsg * cmsg) +static void message_2_pars(_cmsg *cmsg) { for (; TYP != _CEND; cmsg->p++) { @@ -553,8 +362,15 @@ static void message_2_pars(_cmsg * cmsg) } } -/*-------------------------------------------------------*/ -unsigned capi_message2cmsg(_cmsg * cmsg, u8 * msg) +/** + * capi_message2cmsg() - disassemble CAPI 2.0 message into _cmsg structure + * @cmsg: _cmsg structure + * @msg: buffer for assembled message + * + * Return value: 0 for success + */ + +unsigned capi_message2cmsg(_cmsg *cmsg, u8 *msg) { memset(cmsg, 0, sizeof(_cmsg)); cmsg->m = msg; @@ -573,8 +389,19 @@ unsigned capi_message2cmsg(_cmsg * cmsg, u8 * msg) return 0; } -/*-------------------------------------------------------*/ -unsigned capi_cmsg_header(_cmsg * cmsg, u16 _ApplId, +/** + * capi_cmsg_header() - initialize header part of _cmsg structure + * @cmsg: _cmsg structure + * @_ApplId: ApplID field value + * @_Command: Command field value + * @_Subcommand: Subcommand field value + * @_Messagenumber: Message Number field value + * @_Controller: Controller/PLCI/NCCI field value + * + * Return value: 0 for success + */ + +unsigned capi_cmsg_header(_cmsg *cmsg, u16 _ApplId, u8 _Command, u8 _Subcommand, u16 _Messagenumber, u32 _Controller) { @@ -641,6 +468,14 @@ static char *mnames[] = [0x4e] = "MANUFACTURER_RESP" }; +/** + * capi_cmd2str() - convert CAPI 2.0 command/subcommand number to name + * @cmd: command number + * @subcmd: subcommand number + * + * Return value: static string, NULL if command/subcommand unknown + */ + char *capi_cmd2str(u8 cmd, u8 subcmd) { return mnames[command_2_index(cmd, subcmd)]; @@ -655,54 +490,54 @@ char *capi_cmd2str(u8 cmd, u8 subcmd) static char *pnames[] = { - /*00 */ NULL, - /*01 */ NULL, - /*02 */ NULL, - /*03 */ "Controller/PLCI/NCCI", - /*04 */ "AdditionalInfo", - /*05 */ "B1configuration", - /*06 */ "B1protocol", - /*07 */ "B2configuration", - /*08 */ "B2protocol", - /*09 */ "B3configuration", - /*0a */ "B3protocol", - /*0b */ "BC", - /*0c */ "BChannelinformation", - /*0d */ "BProtocol", - /*0e */ "CalledPartyNumber", - /*0f */ "CalledPartySubaddress", - /*10 */ "CallingPartyNumber", - /*11 */ "CallingPartySubaddress", - /*12 */ "CIPmask", - /*13 */ "CIPmask2", - /*14 */ "CIPValue", - /*15 */ "Class", - /*16 */ "ConnectedNumber", - /*17 */ "ConnectedSubaddress", - /*18 */ "Data32", - /*19 */ "DataHandle", - /*1a */ "DataLength", - /*1b */ "FacilityConfirmationParameter", - /*1c */ "Facilitydataarray", - /*1d */ "FacilityIndicationParameter", - /*1e */ "FacilityRequestParameter", - /*1f */ "FacilitySelector", - /*20 */ "Flags", - /*21 */ "Function", - /*22 */ "HLC", - /*23 */ "Info", - /*24 */ "InfoElement", - /*25 */ "InfoMask", - /*26 */ "InfoNumber", - /*27 */ "Keypadfacility", - /*28 */ "LLC", - /*29 */ "ManuData", - /*2a */ "ManuID", - /*2b */ "NCPI", - /*2c */ "Reason", - /*2d */ "Reason_B3", - /*2e */ "Reject", - /*2f */ "Useruserdata" + /*00 */ NULL, + /*01 */ NULL, + /*02 */ NULL, + /*03 */ "Controller/PLCI/NCCI", + /*04 */ "AdditionalInfo", + /*05 */ "B1configuration", + /*06 */ "B1protocol", + /*07 */ "B2configuration", + /*08 */ "B2protocol", + /*09 */ "B3configuration", + /*0a */ "B3protocol", + /*0b */ "BC", + /*0c */ "BChannelinformation", + /*0d */ "BProtocol", + /*0e */ "CalledPartyNumber", + /*0f */ "CalledPartySubaddress", + /*10 */ "CallingPartyNumber", + /*11 */ "CallingPartySubaddress", + /*12 */ "CIPmask", + /*13 */ "CIPmask2", + /*14 */ "CIPValue", + /*15 */ "Class", + /*16 */ "ConnectedNumber", + /*17 */ "ConnectedSubaddress", + /*18 */ "Data32", + /*19 */ "DataHandle", + /*1a */ "DataLength", + /*1b */ "FacilityConfirmationParameter", + /*1c */ "Facilitydataarray", + /*1d */ "FacilityIndicationParameter", + /*1e */ "FacilityRequestParameter", + /*1f */ "FacilitySelector", + /*20 */ "Flags", + /*21 */ "Function", + /*22 */ "HLC", + /*23 */ "Info", + /*24 */ "InfoElement", + /*25 */ "InfoMask", + /*26 */ "InfoNumber", + /*27 */ "Keypadfacility", + /*28 */ "LLC", + /*29 */ "ManuData", + /*2a */ "ManuID", + /*2b */ "NCPI", + /*2c */ "Reason", + /*2d */ "Reason_B3", + /*2e */ "Reject", + /*2f */ "Useruserdata" }; @@ -710,10 +545,10 @@ static char *pnames[] = #include <stdarg.h> /*-------------------------------------------------------*/ -static _cdebbuf *bufprint(_cdebbuf *cdb, char *fmt,...) +static _cdebbuf *bufprint(_cdebbuf *cdb, char *fmt, ...) { va_list f; - size_t n,r; + size_t n, r; if (!cdb) return NULL; @@ -749,7 +584,7 @@ static _cdebbuf *bufprint(_cdebbuf *cdb, char *fmt,...) return cdb; } -static _cdebbuf *printstructlen(_cdebbuf *cdb, u8 * m, unsigned len) +static _cdebbuf *printstructlen(_cdebbuf *cdb, u8 *m, unsigned len) { unsigned hex = 0; @@ -773,7 +608,7 @@ static _cdebbuf *printstructlen(_cdebbuf *cdb, u8 * m, unsigned len) return cdb; } -static _cdebbuf *printstruct(_cdebbuf *cdb, u8 * m) +static _cdebbuf *printstruct(_cdebbuf *cdb, u8 *m) { unsigned len; @@ -879,6 +714,11 @@ init: return cdb; } +/** + * cdebbuf_free() - free CAPI debug buffer + * @cdb: buffer to free + */ + void cdebbuf_free(_cdebbuf *cdb) { if (likely(cdb == g_debbuf)) { @@ -891,7 +731,17 @@ void cdebbuf_free(_cdebbuf *cdb) } -_cdebbuf *capi_message2str(u8 * msg) +/** + * capi_message2str() - format CAPI 2.0 message for printing + * @msg: CAPI 2.0 message + * + * Allocates a CAPI debug buffer and fills it with a printable representation + * of the CAPI 2.0 message in @msg. + * Return value: allocated debug buffer, NULL on error + * The returned buffer should be freed by a call to cdebbuf_free() after use. + */ + +_cdebbuf *capi_message2str(u8 *msg) { _cdebbuf *cdb; _cmsg *cmsg; @@ -915,10 +765,10 @@ _cdebbuf *capi_message2str(u8 * msg) cmsg->par = cpars[command_2_index(cmsg->Command, cmsg->Subcommand)]; cdb = bufprint(cdb, "%-26s ID=%03d #0x%04x LEN=%04d\n", - mnames[command_2_index(cmsg->Command, cmsg->Subcommand)], - ((unsigned short *) msg)[1], - ((unsigned short *) msg)[3], - ((unsigned short *) msg)[0]); + mnames[command_2_index(cmsg->Command, cmsg->Subcommand)], + ((unsigned short *) msg)[1], + ((unsigned short *) msg)[3], + ((unsigned short *) msg)[0]); cdb = protocol_message_2_pars(cdb, cmsg, 1); if (unlikely(cmsg != g_cmsg)) @@ -926,27 +776,40 @@ _cdebbuf *capi_message2str(u8 * msg) return cdb; } -_cdebbuf *capi_cmsg2str(_cmsg * cmsg) +/** + * capi_cmsg2str() - format _cmsg structure for printing + * @cmsg: _cmsg structure + * + * Allocates a CAPI debug buffer and fills it with a printable representation + * of the CAPI 2.0 message stored in @cmsg by a previous call to + * capi_cmsg2message() or capi_message2cmsg(). + * Return value: allocated debug buffer, NULL on error + * The returned buffer should be freed by a call to cdebbuf_free() after use. + */ + +_cdebbuf *capi_cmsg2str(_cmsg *cmsg) { _cdebbuf *cdb; + if (!cmsg->m) + return NULL; /* no message */ cdb = cdebbuf_alloc(); if (!cdb) return NULL; cmsg->l = 8; cmsg->p = 0; cdb = bufprint(cdb, "%s ID=%03d #0x%04x LEN=%04d\n", - mnames[command_2_index(cmsg->Command, cmsg->Subcommand)], - ((u16 *) cmsg->m)[1], - ((u16 *) cmsg->m)[3], - ((u16 *) cmsg->m)[0]); + mnames[command_2_index(cmsg->Command, cmsg->Subcommand)], + ((u16 *) cmsg->m)[1], + ((u16 *) cmsg->m)[3], + ((u16 *) cmsg->m)[0]); cdb = protocol_message_2_pars(cdb, cmsg, 1); return cdb; } int __init cdebug_init(void) { - g_cmsg= kmalloc(sizeof(_cmsg), GFP_KERNEL); + g_cmsg = kmalloc(sizeof(_cmsg), GFP_KERNEL); if (!g_cmsg) return -ENOMEM; g_debbuf = kmalloc(sizeof(_cdebbuf), GFP_KERNEL); @@ -958,7 +821,7 @@ int __init cdebug_init(void) if (!g_debbuf->buf) { kfree(g_cmsg); kfree(g_debbuf); - return -ENOMEM;; + return -ENOMEM; } g_debbuf->size = CDEBUG_GSIZE; g_debbuf->buf[0] = 0; @@ -979,12 +842,12 @@ void __exit cdebug_exit(void) static _cdebbuf g_debbuf = {"CONFIG_CAPI_TRACE not enabled", NULL, 0, 0}; -_cdebbuf *capi_message2str(u8 * msg) +_cdebbuf *capi_message2str(u8 *msg) { return &g_debbuf; } -_cdebbuf *capi_cmsg2str(_cmsg * cmsg) +_cdebbuf *capi_cmsg2str(_cmsg *cmsg) { return &g_debbuf; } @@ -1011,4 +874,3 @@ EXPORT_SYMBOL(capi_cmsg_header); EXPORT_SYMBOL(capi_cmd2str); EXPORT_SYMBOL(capi_cmsg2str); EXPORT_SYMBOL(capi_message2str); -EXPORT_SYMBOL(capi_info2str); diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index 5360c4fd473..c123709acf8 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c @@ -1,10 +1,10 @@ /* $Id: kcapi.c,v 1.1.2.8 2004/03/26 19:57:20 armin Exp $ - * + * * Kernel CAPI 2.0 Module - * + * * Copyright 1999 by Carsten Paeth <calle@calle.de> * Copyright 2002 by Kai Germaschewski <kai@germaschewski.name> - * + * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * @@ -18,6 +18,7 @@ #include <linux/interrupt.h> #include <linux/ioport.h> #include <linux/proc_fs.h> +#include <linux/sched.h> #include <linux/seq_file.h> #include <linux/skbuff.h> #include <linux/workqueue.h> @@ -26,6 +27,7 @@ #include <linux/init.h> #include <linux/moduleparam.h> #include <linux/delay.h> +#include <linux/slab.h> #include <asm/uaccess.h> #include <linux/isdn/capicmd.h> #include <linux/isdn/capiutil.h> @@ -33,12 +35,10 @@ #include <linux/b1lli.h> #endif #include <linux/mutex.h> - -static char *revision = "$Revision: 1.1.2.8 $"; - -/* ------------------------------------------------------------- */ +#include <linux/rcupdate.h> static int showcapimsgs = 0; +static struct workqueue_struct *kcapi_wq; MODULE_DESCRIPTION("CAPI4Linux: kernel CAPI layer"); MODULE_AUTHOR("Carsten Paeth"); @@ -47,67 +47,76 @@ module_param(showcapimsgs, uint, 0); /* ------------------------------------------------------------- */ -struct capi_notifier { +struct capictr_event { struct work_struct work; - unsigned int cmd; + unsigned int type; u32 controller; - u16 applid; - u32 ncci; }; /* ------------------------------------------------------------- */ -static struct capi_version driver_version = {2, 0, 1, 1<<4}; +static struct capi_version driver_version = {2, 0, 1, 1 << 4}; static char driver_serial[CAPI_SERIAL_LEN] = "0004711"; static char capi_manufakturer[64] = "AVM Berlin"; #define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f) LIST_HEAD(capi_drivers); -DEFINE_RWLOCK(capi_drivers_list_lock); +DEFINE_MUTEX(capi_drivers_lock); -static DEFINE_RWLOCK(application_lock); -static DEFINE_MUTEX(controller_mutex); +struct capi_ctr *capi_controller[CAPI_MAXCONTR]; +DEFINE_MUTEX(capi_controller_lock); struct capi20_appl *capi_applications[CAPI_MAXAPPL]; -struct capi_ctr *capi_cards[CAPI_MAXCONTR]; -static int ncards; +static int ncontrollers; + +static BLOCKING_NOTIFIER_HEAD(ctr_notifier_list); /* -------- controller ref counting -------------------------------------- */ static inline struct capi_ctr * -capi_ctr_get(struct capi_ctr *card) +capi_ctr_get(struct capi_ctr *ctr) { - if (!try_module_get(card->owner)) + if (!try_module_get(ctr->owner)) return NULL; - return card; + return ctr; } static inline void -capi_ctr_put(struct capi_ctr *card) +capi_ctr_put(struct capi_ctr *ctr) { - module_put(card->owner); + module_put(ctr->owner); } /* ------------------------------------------------------------- */ static inline struct capi_ctr *get_capi_ctr_by_nr(u16 contr) { - if (contr - 1 >= CAPI_MAXCONTR) + if (contr < 1 || contr - 1 >= CAPI_MAXCONTR) return NULL; - return capi_cards[contr - 1]; + return capi_controller[contr - 1]; } -static inline struct capi20_appl *get_capi_appl_by_nr(u16 applid) +static inline struct capi20_appl *__get_capi_appl_by_nr(u16 applid) { - if (applid - 1 >= CAPI_MAXAPPL) + lockdep_assert_held(&capi_controller_lock); + + if (applid < 1 || applid - 1 >= CAPI_MAXAPPL) return NULL; return capi_applications[applid - 1]; } +static inline struct capi20_appl *get_capi_appl_by_nr(u16 applid) +{ + if (applid < 1 || applid - 1 >= CAPI_MAXAPPL) + return NULL; + + return rcu_dereference(capi_applications[applid - 1]); +} + /* -------- util functions ------------------------------------ */ static inline int capi_cmd_valid(u8 cmd) @@ -147,106 +156,158 @@ static inline int capi_subcmd_valid(u8 subcmd) /* ------------------------------------------------------------ */ -static void register_appl(struct capi_ctr *card, u16 applid, capi_register_params *rparam) +static void +register_appl(struct capi_ctr *ctr, u16 applid, capi_register_params *rparam) { - card = capi_ctr_get(card); + ctr = capi_ctr_get(ctr); - if (card) - card->register_appl(card, applid, rparam); + if (ctr) + ctr->register_appl(ctr, applid, rparam); else - printk(KERN_WARNING "%s: cannot get card resources\n", __func__); + printk(KERN_WARNING "%s: cannot get controller resources\n", + __func__); } -static void release_appl(struct capi_ctr *card, u16 applid) +static void release_appl(struct capi_ctr *ctr, u16 applid) { DBG("applid %#x", applid); - - card->release_appl(card, applid); - capi_ctr_put(card); -} -/* -------- KCI_CONTRUP --------------------------------------- */ + ctr->release_appl(ctr, applid); + capi_ctr_put(ctr); +} static void notify_up(u32 contr) { - struct capi_ctr *card = get_capi_ctr_by_nr(contr); struct capi20_appl *ap; + struct capi_ctr *ctr; u16 applid; - if (showcapimsgs & 1) { - printk(KERN_DEBUG "kcapi: notify up contr %d\n", contr); - } - if (!card) { + mutex_lock(&capi_controller_lock); + + if (showcapimsgs & 1) + printk(KERN_DEBUG "kcapi: notify up contr %d\n", contr); + + ctr = get_capi_ctr_by_nr(contr); + if (ctr) { + if (ctr->state == CAPI_CTR_RUNNING) + goto unlock_out; + + ctr->state = CAPI_CTR_RUNNING; + + for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { + ap = __get_capi_appl_by_nr(applid); + if (ap) + register_appl(ctr, applid, &ap->rparam); + } + + wake_up_interruptible_all(&ctr->state_wait_queue); + } else printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr); - return; - } - for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { - ap = get_capi_appl_by_nr(applid); - if (!ap || ap->release_in_progress) continue; - register_appl(card, applid, &ap->rparam); - if (ap->callback && !ap->release_in_progress) - ap->callback(KCI_CONTRUP, contr, &card->profile); - } -} -/* -------- KCI_CONTRDOWN ------------------------------------- */ +unlock_out: + mutex_unlock(&capi_controller_lock); +} -static void notify_down(u32 contr) +static void ctr_down(struct capi_ctr *ctr, int new_state) { struct capi20_appl *ap; u16 applid; - if (showcapimsgs & 1) { - printk(KERN_DEBUG "kcapi: notify down contr %d\n", contr); - } + if (ctr->state == CAPI_CTR_DETECTED || ctr->state == CAPI_CTR_DETACHED) + return; + + ctr->state = new_state; + + memset(ctr->manu, 0, sizeof(ctr->manu)); + memset(&ctr->version, 0, sizeof(ctr->version)); + memset(&ctr->profile, 0, sizeof(ctr->profile)); + memset(ctr->serial, 0, sizeof(ctr->serial)); for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { - ap = get_capi_appl_by_nr(applid); - if (ap && ap->callback && !ap->release_in_progress) - ap->callback(KCI_CONTRDOWN, contr, NULL); + ap = __get_capi_appl_by_nr(applid); + if (ap) + capi_ctr_put(ctr); } + + wake_up_interruptible_all(&ctr->state_wait_queue); +} + +static void notify_down(u32 contr) +{ + struct capi_ctr *ctr; + + mutex_lock(&capi_controller_lock); + + if (showcapimsgs & 1) + printk(KERN_DEBUG "kcapi: notify down contr %d\n", contr); + + ctr = get_capi_ctr_by_nr(contr); + if (ctr) + ctr_down(ctr, CAPI_CTR_DETECTED); + else + printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr); + + mutex_unlock(&capi_controller_lock); } -static void notify_handler(struct work_struct *work) +static int +notify_handler(struct notifier_block *nb, unsigned long val, void *v) { - struct capi_notifier *np = - container_of(work, struct capi_notifier, work); + u32 contr = (long)v; - switch (np->cmd) { - case KCI_CONTRUP: - notify_up(np->controller); + switch (val) { + case CAPICTR_UP: + notify_up(contr); break; - case KCI_CONTRDOWN: - notify_down(np->controller); + case CAPICTR_DOWN: + notify_down(contr); break; } + return NOTIFY_OK; +} + +static void do_notify_work(struct work_struct *work) +{ + struct capictr_event *event = + container_of(work, struct capictr_event, work); - kfree(np); + blocking_notifier_call_chain(&ctr_notifier_list, event->type, + (void *)(long)event->controller); + kfree(event); } /* * The notifier will result in adding/deleteing of devices. Devices can * only removed in user process, not in bh. */ -static int notify_push(unsigned int cmd, u32 controller, u16 applid, u32 ncci) +static int notify_push(unsigned int event_type, u32 controller) { - struct capi_notifier *np = kmalloc(sizeof(*np), GFP_ATOMIC); + struct capictr_event *event = kmalloc(sizeof(*event), GFP_ATOMIC); - if (!np) + if (!event) return -ENOMEM; - INIT_WORK(&np->work, notify_handler); - np->cmd = cmd; - np->controller = controller; - np->applid = applid; - np->ncci = ncci; + INIT_WORK(&event->work, do_notify_work); + event->type = event_type; + event->controller = controller; - schedule_work(&np->work); + queue_work(kcapi_wq, &event->work); return 0; } - +int register_capictr_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&ctr_notifier_list, nb); +} +EXPORT_SYMBOL_GPL(register_capictr_notifier); + +int unregister_capictr_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&ctr_notifier_list, nb); +} +EXPORT_SYMBOL_GPL(unregister_capictr_notifier); + /* -------- Receiver ------------------------------------------ */ static void recv_handler(struct work_struct *work) @@ -270,75 +331,86 @@ static void recv_handler(struct work_struct *work) mutex_unlock(&ap->recv_mtx); } -void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *skb) +/** + * capi_ctr_handle_message() - handle incoming CAPI message + * @ctr: controller descriptor structure. + * @appl: application ID. + * @skb: message. + * + * Called by hardware driver to pass a CAPI message to the application. + */ + +void capi_ctr_handle_message(struct capi_ctr *ctr, u16 appl, + struct sk_buff *skb) { struct capi20_appl *ap; int showctl = 0; u8 cmd, subcmd; - unsigned long flags; _cdebbuf *cdb; - if (card->cardstate != CARD_RUNNING) { + if (ctr->state != CAPI_CTR_RUNNING) { cdb = capi_message2str(skb->data); if (cdb) { printk(KERN_INFO "kcapi: controller [%03d] not active, got: %s", - card->cnr, cdb->buf); + ctr->cnr, cdb->buf); cdebbuf_free(cdb); } else printk(KERN_INFO "kcapi: controller [%03d] not active, cannot trace\n", - card->cnr); + ctr->cnr); goto error; } cmd = CAPIMSG_COMMAND(skb->data); - subcmd = CAPIMSG_SUBCOMMAND(skb->data); + subcmd = CAPIMSG_SUBCOMMAND(skb->data); if (cmd == CAPI_DATA_B3 && subcmd == CAPI_IND) { - card->nrecvdatapkt++; - if (card->traceflag > 2) showctl |= 2; + ctr->nrecvdatapkt++; + if (ctr->traceflag > 2) + showctl |= 2; } else { - card->nrecvctlpkt++; - if (card->traceflag) showctl |= 2; + ctr->nrecvctlpkt++; + if (ctr->traceflag) + showctl |= 2; } - showctl |= (card->traceflag & 1); + showctl |= (ctr->traceflag & 1); if (showctl & 2) { if (showctl & 1) { printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u\n", - card->cnr, CAPIMSG_APPID(skb->data), + ctr->cnr, CAPIMSG_APPID(skb->data), capi_cmd2str(cmd, subcmd), CAPIMSG_LEN(skb->data)); } else { cdb = capi_message2str(skb->data); if (cdb) { printk(KERN_DEBUG "kcapi: got [%03d] %s\n", - card->cnr, cdb->buf); + ctr->cnr, cdb->buf); cdebbuf_free(cdb); } else printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u, cannot trace\n", - card->cnr, CAPIMSG_APPID(skb->data), - capi_cmd2str(cmd, subcmd), - CAPIMSG_LEN(skb->data)); + ctr->cnr, CAPIMSG_APPID(skb->data), + capi_cmd2str(cmd, subcmd), + CAPIMSG_LEN(skb->data)); } } - read_lock_irqsave(&application_lock, flags); + rcu_read_lock(); ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data)); - if ((!ap) || (ap->release_in_progress)) { - read_unlock_irqrestore(&application_lock, flags); + if (!ap) { + rcu_read_unlock(); cdb = capi_message2str(skb->data); if (cdb) { printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s)\n", - CAPIMSG_APPID(skb->data), cdb->buf); + CAPIMSG_APPID(skb->data), cdb->buf); cdebbuf_free(cdb); } else printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s) cannot trace\n", - CAPIMSG_APPID(skb->data), - capi_cmd2str(cmd, subcmd)); + CAPIMSG_APPID(skb->data), + capi_cmd2str(cmd, subcmd)); goto error; } skb_queue_tail(&ap->recv_queue, skb); - schedule_work(&ap->recv_work); - read_unlock_irqrestore(&application_lock, flags); + queue_work(kcapi_wq, &ap->recv_work); + rcu_read_unlock(); return; @@ -348,64 +420,77 @@ error: EXPORT_SYMBOL(capi_ctr_handle_message); -void capi_ctr_ready(struct capi_ctr * card) -{ - card->cardstate = CARD_RUNNING; +/** + * capi_ctr_ready() - signal CAPI controller ready + * @ctr: controller descriptor structure. + * + * Called by hardware driver to signal that the controller is up and running. + */ - printk(KERN_NOTICE "kcapi: card [%03d] \"%s\" ready.\n", - card->cnr, card->name); +void capi_ctr_ready(struct capi_ctr *ctr) +{ + printk(KERN_NOTICE "kcapi: controller [%03d] \"%s\" ready.\n", + ctr->cnr, ctr->name); - notify_push(KCI_CONTRUP, card->cnr, 0, 0); + notify_push(CAPICTR_UP, ctr->cnr); } EXPORT_SYMBOL(capi_ctr_ready); -void capi_ctr_reseted(struct capi_ctr * card) -{ - u16 appl; - - DBG(""); - - if (card->cardstate == CARD_DETECTED) - return; - - card->cardstate = CARD_DETECTED; - - memset(card->manu, 0, sizeof(card->manu)); - memset(&card->version, 0, sizeof(card->version)); - memset(&card->profile, 0, sizeof(card->profile)); - memset(card->serial, 0, sizeof(card->serial)); - - for (appl = 1; appl <= CAPI_MAXAPPL; appl++) { - struct capi20_appl *ap = get_capi_appl_by_nr(appl); - if (!ap || ap->release_in_progress) - continue; - - capi_ctr_put(card); - } +/** + * capi_ctr_down() - signal CAPI controller not ready + * @ctr: controller descriptor structure. + * + * Called by hardware driver to signal that the controller is down and + * unavailable for use. + */ - printk(KERN_NOTICE "kcapi: card [%03d] down.\n", card->cnr); +void capi_ctr_down(struct capi_ctr *ctr) +{ + printk(KERN_NOTICE "kcapi: controller [%03d] down.\n", ctr->cnr); - notify_push(KCI_CONTRDOWN, card->cnr, 0, 0); + notify_push(CAPICTR_DOWN, ctr->cnr); } -EXPORT_SYMBOL(capi_ctr_reseted); +EXPORT_SYMBOL(capi_ctr_down); -void capi_ctr_suspend_output(struct capi_ctr *card) +/** + * capi_ctr_suspend_output() - suspend controller + * @ctr: controller descriptor structure. + * + * Called by hardware driver to stop data flow. + * + * Note: The caller is responsible for synchronizing concurrent state changes + * as well as invocations of capi_ctr_handle_message. + */ + +void capi_ctr_suspend_output(struct capi_ctr *ctr) { - if (!card->blocked) { - printk(KERN_DEBUG "kcapi: card [%03d] suspend\n", card->cnr); - card->blocked = 1; + if (!ctr->blocked) { + printk(KERN_DEBUG "kcapi: controller [%03d] suspend\n", + ctr->cnr); + ctr->blocked = 1; } } EXPORT_SYMBOL(capi_ctr_suspend_output); -void capi_ctr_resume_output(struct capi_ctr *card) +/** + * capi_ctr_resume_output() - resume controller + * @ctr: controller descriptor structure. + * + * Called by hardware driver to resume data flow. + * + * Note: The caller is responsible for synchronizing concurrent state changes + * as well as invocations of capi_ctr_handle_message. + */ + +void capi_ctr_resume_output(struct capi_ctr *ctr) { - if (card->blocked) { - printk(KERN_DEBUG "kcapi: card [%03d] resume\n", card->cnr); - card->blocked = 0; + if (ctr->blocked) { + printk(KERN_DEBUG "kcapi: controller [%03d] resumed\n", + ctr->cnr); + ctr->blocked = 0; } } @@ -413,90 +498,121 @@ EXPORT_SYMBOL(capi_ctr_resume_output); /* ------------------------------------------------------------- */ -int -attach_capi_ctr(struct capi_ctr *card) +/** + * attach_capi_ctr() - register CAPI controller + * @ctr: controller descriptor structure. + * + * Called by hardware driver to register a controller with the CAPI subsystem. + * Return value: 0 on success, error code < 0 on error + */ + +int attach_capi_ctr(struct capi_ctr *ctr) { int i; - mutex_lock(&controller_mutex); + mutex_lock(&capi_controller_lock); for (i = 0; i < CAPI_MAXCONTR; i++) { - if (capi_cards[i] == NULL) + if (!capi_controller[i]) break; } if (i == CAPI_MAXCONTR) { - mutex_unlock(&controller_mutex); + mutex_unlock(&capi_controller_lock); printk(KERN_ERR "kcapi: out of controller slots\n"); - return -EBUSY; - } - capi_cards[i] = card; - - mutex_unlock(&controller_mutex); - - card->nrecvctlpkt = 0; - card->nrecvdatapkt = 0; - card->nsentctlpkt = 0; - card->nsentdatapkt = 0; - card->cnr = i + 1; - card->cardstate = CARD_DETECTED; - card->blocked = 0; - card->traceflag = showcapimsgs; - - sprintf(card->procfn, "capi/controllers/%d", card->cnr); - card->procent = create_proc_entry(card->procfn, 0, NULL); - if (card->procent) { - card->procent->read_proc = - (int (*)(char *,char **,off_t,int,int *,void *)) - card->ctr_read_proc; - card->procent->data = card; + return -EBUSY; } + capi_controller[i] = ctr; + + ctr->nrecvctlpkt = 0; + ctr->nrecvdatapkt = 0; + ctr->nsentctlpkt = 0; + ctr->nsentdatapkt = 0; + ctr->cnr = i + 1; + ctr->state = CAPI_CTR_DETECTED; + ctr->blocked = 0; + ctr->traceflag = showcapimsgs; + init_waitqueue_head(&ctr->state_wait_queue); - ncards++; - printk(KERN_NOTICE "kcapi: Controller [%03d]: %s attached\n", - card->cnr, card->name); + sprintf(ctr->procfn, "capi/controllers/%d", ctr->cnr); + ctr->procent = proc_create_data(ctr->procfn, 0, NULL, ctr->proc_fops, ctr); + + ncontrollers++; + + mutex_unlock(&capi_controller_lock); + + printk(KERN_NOTICE "kcapi: controller [%03d]: %s attached\n", + ctr->cnr, ctr->name); return 0; } EXPORT_SYMBOL(attach_capi_ctr); -int detach_capi_ctr(struct capi_ctr *card) +/** + * detach_capi_ctr() - unregister CAPI controller + * @ctr: controller descriptor structure. + * + * Called by hardware driver to remove the registration of a controller + * with the CAPI subsystem. + * Return value: 0 on success, error code < 0 on error + */ + +int detach_capi_ctr(struct capi_ctr *ctr) { - if (card->cardstate != CARD_DETECTED) - capi_ctr_reseted(card); + int err = 0; - ncards--; + mutex_lock(&capi_controller_lock); - if (card->procent) { - remove_proc_entry(card->procfn, NULL); - card->procent = NULL; + ctr_down(ctr, CAPI_CTR_DETACHED); + + if (capi_controller[ctr->cnr - 1] != ctr) { + err = -EINVAL; + goto unlock_out; } - capi_cards[card->cnr - 1] = NULL; - printk(KERN_NOTICE "kcapi: Controller [%03d]: %s unregistered\n", - card->cnr, card->name); + capi_controller[ctr->cnr - 1] = NULL; + ncontrollers--; - return 0; + if (ctr->procent) + remove_proc_entry(ctr->procfn, NULL); + + printk(KERN_NOTICE "kcapi: controller [%03d]: %s unregistered\n", + ctr->cnr, ctr->name); + +unlock_out: + mutex_unlock(&capi_controller_lock); + + return err; } EXPORT_SYMBOL(detach_capi_ctr); +/** + * register_capi_driver() - register CAPI driver + * @driver: driver descriptor structure. + * + * Called by hardware driver to register itself with the CAPI subsystem. + */ + void register_capi_driver(struct capi_driver *driver) { - unsigned long flags; - - write_lock_irqsave(&capi_drivers_list_lock, flags); + mutex_lock(&capi_drivers_lock); list_add_tail(&driver->list, &capi_drivers); - write_unlock_irqrestore(&capi_drivers_list_lock, flags); + mutex_unlock(&capi_drivers_lock); } EXPORT_SYMBOL(register_capi_driver); +/** + * unregister_capi_driver() - unregister CAPI driver + * @driver: driver descriptor structure. + * + * Called by hardware driver to unregister itself from the CAPI subsystem. + */ + void unregister_capi_driver(struct capi_driver *driver) { - unsigned long flags; - - write_lock_irqsave(&capi_drivers_list_lock, flags); + mutex_lock(&capi_drivers_lock); list_del(&driver->list); - write_unlock_irqrestore(&capi_drivers_list_lock, flags); + mutex_unlock(&capi_drivers_lock); } EXPORT_SYMBOL(unregister_capi_driver); @@ -505,62 +621,87 @@ EXPORT_SYMBOL(unregister_capi_driver); /* -------- CAPI2.0 Interface ---------------------------------- */ /* ------------------------------------------------------------- */ +/** + * capi20_isinstalled() - CAPI 2.0 operation CAPI_INSTALLED + * + * Return value: CAPI result code (CAPI_NOERROR if at least one ISDN controller + * is ready for use, CAPI_REGNOTINSTALLED otherwise) + */ + u16 capi20_isinstalled(void) { + u16 ret = CAPI_REGNOTINSTALLED; int i; - for (i = 0; i < CAPI_MAXCONTR; i++) { - if (capi_cards[i] && capi_cards[i]->cardstate == CARD_RUNNING) - return CAPI_NOERROR; - } - return CAPI_REGNOTINSTALLED; + + mutex_lock(&capi_controller_lock); + + for (i = 0; i < CAPI_MAXCONTR; i++) + if (capi_controller[i] && + capi_controller[i]->state == CAPI_CTR_RUNNING) { + ret = CAPI_NOERROR; + break; + } + + mutex_unlock(&capi_controller_lock); + + return ret; } EXPORT_SYMBOL(capi20_isinstalled); +/** + * capi20_register() - CAPI 2.0 operation CAPI_REGISTER + * @ap: CAPI application descriptor structure. + * + * Register an application's presence with CAPI. + * A unique application ID is assigned and stored in @ap->applid. + * After this function returns successfully, the message receive + * callback function @ap->recv_message() may be called at any time + * until capi20_release() has been called for the same @ap. + * Return value: CAPI result code + */ + u16 capi20_register(struct capi20_appl *ap) { int i; u16 applid; - unsigned long flags; DBG(""); if (ap->rparam.datablklen < 128) return CAPI_LOGBLKSIZETOSMALL; - write_lock_irqsave(&application_lock, flags); + ap->nrecvctlpkt = 0; + ap->nrecvdatapkt = 0; + ap->nsentctlpkt = 0; + ap->nsentdatapkt = 0; + mutex_init(&ap->recv_mtx); + skb_queue_head_init(&ap->recv_queue); + INIT_WORK(&ap->recv_work, recv_handler); + ap->release_in_progress = 0; + + mutex_lock(&capi_controller_lock); for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { if (capi_applications[applid - 1] == NULL) break; } if (applid > CAPI_MAXAPPL) { - write_unlock_irqrestore(&application_lock, flags); + mutex_unlock(&capi_controller_lock); return CAPI_TOOMANYAPPLS; } ap->applid = applid; capi_applications[applid - 1] = ap; - ap->nrecvctlpkt = 0; - ap->nrecvdatapkt = 0; - ap->nsentctlpkt = 0; - ap->nsentdatapkt = 0; - ap->callback = NULL; - mutex_init(&ap->recv_mtx); - skb_queue_head_init(&ap->recv_queue); - INIT_WORK(&ap->recv_work, recv_handler); - ap->release_in_progress = 0; - - write_unlock_irqrestore(&application_lock, flags); - - mutex_lock(&controller_mutex); for (i = 0; i < CAPI_MAXCONTR; i++) { - if (!capi_cards[i] || capi_cards[i]->cardstate != CARD_RUNNING) + if (!capi_controller[i] || + capi_controller[i]->state != CAPI_CTR_RUNNING) continue; - register_appl(capi_cards[i], applid, &ap->rparam); + register_appl(capi_controller[i], applid, &ap->rparam); } - mutex_unlock(&controller_mutex); + + mutex_unlock(&capi_controller_lock); if (showcapimsgs & 1) { printk(KERN_DEBUG "kcapi: appl %d up\n", applid); @@ -571,27 +712,39 @@ u16 capi20_register(struct capi20_appl *ap) EXPORT_SYMBOL(capi20_register); +/** + * capi20_release() - CAPI 2.0 operation CAPI_RELEASE + * @ap: CAPI application descriptor structure. + * + * Terminate an application's registration with CAPI. + * After this function returns successfully, the message receive + * callback function @ap->recv_message() will no longer be called. + * Return value: CAPI result code + */ + u16 capi20_release(struct capi20_appl *ap) { int i; - unsigned long flags; DBG("applid %#x", ap->applid); - write_lock_irqsave(&application_lock, flags); + mutex_lock(&capi_controller_lock); + ap->release_in_progress = 1; capi_applications[ap->applid - 1] = NULL; - write_unlock_irqrestore(&application_lock, flags); - mutex_lock(&controller_mutex); + synchronize_rcu(); + for (i = 0; i < CAPI_MAXCONTR; i++) { - if (!capi_cards[i] || capi_cards[i]->cardstate != CARD_RUNNING) + if (!capi_controller[i] || + capi_controller[i]->state != CAPI_CTR_RUNNING) continue; - release_appl(capi_cards[i], ap->applid); + release_appl(capi_controller[i], ap->applid); } - mutex_unlock(&controller_mutex); - flush_scheduled_work(); + mutex_unlock(&capi_controller_lock); + + flush_workqueue(kcapi_wq); skb_queue_purge(&ap->recv_queue); if (showcapimsgs & 1) { @@ -603,15 +756,24 @@ u16 capi20_release(struct capi20_appl *ap) EXPORT_SYMBOL(capi20_release); +/** + * capi20_put_message() - CAPI 2.0 operation CAPI_PUT_MESSAGE + * @ap: CAPI application descriptor structure. + * @skb: CAPI message. + * + * Transfer a single message to CAPI. + * Return value: CAPI result code + */ + u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb) { - struct capi_ctr *card; + struct capi_ctr *ctr; int showctl = 0; u8 cmd, subcmd; DBG("applid %#x", ap->applid); - - if (ncards == 0) + + if (ncontrollers == 0) return CAPI_REGNOTINSTALLED; if ((ap->applid == 0) || ap->release_in_progress) return CAPI_ILLAPPNR; @@ -619,28 +781,33 @@ u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb) || !capi_cmd_valid(CAPIMSG_COMMAND(skb->data)) || !capi_subcmd_valid(CAPIMSG_SUBCOMMAND(skb->data))) return CAPI_ILLCMDORSUBCMDORMSGTOSMALL; - card = get_capi_ctr_by_nr(CAPIMSG_CONTROLLER(skb->data)); - if (!card || card->cardstate != CARD_RUNNING) { - card = get_capi_ctr_by_nr(1); // XXX why? - if (!card || card->cardstate != CARD_RUNNING) - return CAPI_REGNOTINSTALLED; - } - if (card->blocked) + + /* + * The controller reference is protected by the existence of the + * application passed to us. We assume that the caller properly + * synchronizes this service with capi20_release. + */ + ctr = get_capi_ctr_by_nr(CAPIMSG_CONTROLLER(skb->data)); + if (!ctr || ctr->state != CAPI_CTR_RUNNING) + return CAPI_REGNOTINSTALLED; + if (ctr->blocked) return CAPI_SENDQUEUEFULL; cmd = CAPIMSG_COMMAND(skb->data); - subcmd = CAPIMSG_SUBCOMMAND(skb->data); + subcmd = CAPIMSG_SUBCOMMAND(skb->data); - if (cmd == CAPI_DATA_B3 && subcmd== CAPI_REQ) { - card->nsentdatapkt++; + if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ) { + ctr->nsentdatapkt++; ap->nsentdatapkt++; - if (card->traceflag > 2) showctl |= 2; + if (ctr->traceflag > 2) + showctl |= 2; } else { - card->nsentctlpkt++; + ctr->nsentctlpkt++; ap->nsentctlpkt++; - if (card->traceflag) showctl |= 2; + if (ctr->traceflag) + showctl |= 2; } - showctl |= (card->traceflag & 1); + showctl |= (ctr->traceflag & 1); if (showctl & 2) { if (showctl & 1) { printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u\n", @@ -652,94 +819,198 @@ u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb) _cdebbuf *cdb = capi_message2str(skb->data); if (cdb) { printk(KERN_DEBUG "kcapi: put [%03d] %s\n", - CAPIMSG_CONTROLLER(skb->data), - cdb->buf); + CAPIMSG_CONTROLLER(skb->data), + cdb->buf); cdebbuf_free(cdb); } else printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u cannot trace\n", - CAPIMSG_CONTROLLER(skb->data), - CAPIMSG_APPID(skb->data), - capi_cmd2str(cmd, subcmd), - CAPIMSG_LEN(skb->data)); + CAPIMSG_CONTROLLER(skb->data), + CAPIMSG_APPID(skb->data), + capi_cmd2str(cmd, subcmd), + CAPIMSG_LEN(skb->data)); } } - return card->send_message(card, skb); + return ctr->send_message(ctr, skb); } EXPORT_SYMBOL(capi20_put_message); +/** + * capi20_get_manufacturer() - CAPI 2.0 operation CAPI_GET_MANUFACTURER + * @contr: controller number. + * @buf: result buffer (64 bytes). + * + * Retrieve information about the manufacturer of the specified ISDN controller + * or (for @contr == 0) the driver itself. + * Return value: CAPI result code + */ + u16 capi20_get_manufacturer(u32 contr, u8 *buf) { - struct capi_ctr *card; + struct capi_ctr *ctr; + u16 ret; if (contr == 0) { strlcpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN); return CAPI_NOERROR; } - card = get_capi_ctr_by_nr(contr); - if (!card || card->cardstate != CARD_RUNNING) - return CAPI_REGNOTINSTALLED; - strlcpy(buf, card->manu, CAPI_MANUFACTURER_LEN); - return CAPI_NOERROR; + + mutex_lock(&capi_controller_lock); + + ctr = get_capi_ctr_by_nr(contr); + if (ctr && ctr->state == CAPI_CTR_RUNNING) { + strlcpy(buf, ctr->manu, CAPI_MANUFACTURER_LEN); + ret = CAPI_NOERROR; + } else + ret = CAPI_REGNOTINSTALLED; + + mutex_unlock(&capi_controller_lock); + return ret; } EXPORT_SYMBOL(capi20_get_manufacturer); +/** + * capi20_get_version() - CAPI 2.0 operation CAPI_GET_VERSION + * @contr: controller number. + * @verp: result structure. + * + * Retrieve version information for the specified ISDN controller + * or (for @contr == 0) the driver itself. + * Return value: CAPI result code + */ + u16 capi20_get_version(u32 contr, struct capi_version *verp) { - struct capi_ctr *card; + struct capi_ctr *ctr; + u16 ret; if (contr == 0) { *verp = driver_version; return CAPI_NOERROR; } - card = get_capi_ctr_by_nr(contr); - if (!card || card->cardstate != CARD_RUNNING) - return CAPI_REGNOTINSTALLED; - memcpy((void *) verp, &card->version, sizeof(capi_version)); - return CAPI_NOERROR; + mutex_lock(&capi_controller_lock); + + ctr = get_capi_ctr_by_nr(contr); + if (ctr && ctr->state == CAPI_CTR_RUNNING) { + memcpy(verp, &ctr->version, sizeof(capi_version)); + ret = CAPI_NOERROR; + } else + ret = CAPI_REGNOTINSTALLED; + + mutex_unlock(&capi_controller_lock); + return ret; } EXPORT_SYMBOL(capi20_get_version); +/** + * capi20_get_serial() - CAPI 2.0 operation CAPI_GET_SERIAL_NUMBER + * @contr: controller number. + * @serial: result buffer (8 bytes). + * + * Retrieve the serial number of the specified ISDN controller + * or (for @contr == 0) the driver itself. + * Return value: CAPI result code + */ + u16 capi20_get_serial(u32 contr, u8 *serial) { - struct capi_ctr *card; + struct capi_ctr *ctr; + u16 ret; if (contr == 0) { strlcpy(serial, driver_serial, CAPI_SERIAL_LEN); return CAPI_NOERROR; } - card = get_capi_ctr_by_nr(contr); - if (!card || card->cardstate != CARD_RUNNING) - return CAPI_REGNOTINSTALLED; - strlcpy((void *) serial, card->serial, CAPI_SERIAL_LEN); - return CAPI_NOERROR; + mutex_lock(&capi_controller_lock); + + ctr = get_capi_ctr_by_nr(contr); + if (ctr && ctr->state == CAPI_CTR_RUNNING) { + strlcpy(serial, ctr->serial, CAPI_SERIAL_LEN); + ret = CAPI_NOERROR; + } else + ret = CAPI_REGNOTINSTALLED; + + mutex_unlock(&capi_controller_lock); + return ret; } EXPORT_SYMBOL(capi20_get_serial); +/** + * capi20_get_profile() - CAPI 2.0 operation CAPI_GET_PROFILE + * @contr: controller number. + * @profp: result structure. + * + * Retrieve capability information for the specified ISDN controller + * or (for @contr == 0) the number of installed controllers. + * Return value: CAPI result code + */ + u16 capi20_get_profile(u32 contr, struct capi_profile *profp) { - struct capi_ctr *card; + struct capi_ctr *ctr; + u16 ret; if (contr == 0) { - profp->ncontroller = ncards; + profp->ncontroller = ncontrollers; return CAPI_NOERROR; } - card = get_capi_ctr_by_nr(contr); - if (!card || card->cardstate != CARD_RUNNING) - return CAPI_REGNOTINSTALLED; - memcpy((void *) profp, &card->profile, - sizeof(struct capi_profile)); - return CAPI_NOERROR; + mutex_lock(&capi_controller_lock); + + ctr = get_capi_ctr_by_nr(contr); + if (ctr && ctr->state == CAPI_CTR_RUNNING) { + memcpy(profp, &ctr->profile, sizeof(struct capi_profile)); + ret = CAPI_NOERROR; + } else + ret = CAPI_REGNOTINSTALLED; + + mutex_unlock(&capi_controller_lock); + return ret; } EXPORT_SYMBOL(capi20_get_profile); +/* Must be called with capi_controller_lock held. */ +static int wait_on_ctr_state(struct capi_ctr *ctr, unsigned int state) +{ + DEFINE_WAIT(wait); + int retval = 0; + + ctr = capi_ctr_get(ctr); + if (!ctr) + return -ESRCH; + + for (;;) { + prepare_to_wait(&ctr->state_wait_queue, &wait, + TASK_INTERRUPTIBLE); + + if (ctr->state == state) + break; + if (ctr->state == CAPI_CTR_DETACHED) { + retval = -ESRCH; + break; + } + if (signal_pending(current)) { + retval = -EINTR; + break; + } + + mutex_unlock(&capi_controller_lock); + schedule(); + mutex_lock(&capi_controller_lock); + } + finish_wait(&ctr->state_wait_queue, &wait); + + capi_ctr_put(ctr); + + return retval; +} + #ifdef AVMB1_COMPAT static int old_capi_manufacturer(unsigned int cmd, void __user *data) { @@ -747,63 +1018,60 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data) avmb1_extcarddef cdef; avmb1_resetdef rdef; capicardparams cparams; - struct capi_ctr *card; + struct capi_ctr *ctr; struct capi_driver *driver = NULL; capiloaddata ldata; struct list_head *l; - unsigned long flags; int retval; switch (cmd) { case AVMB1_ADDCARD: case AVMB1_ADDCARD_WITH_TYPE: if (cmd == AVMB1_ADDCARD) { - if ((retval = copy_from_user(&cdef, data, - sizeof(avmb1_carddef)))) - return retval; - cdef.cardtype = AVM_CARDTYPE_B1; + if ((retval = copy_from_user(&cdef, data, + sizeof(avmb1_carddef)))) + return -EFAULT; + cdef.cardtype = AVM_CARDTYPE_B1; } else { - if ((retval = copy_from_user(&cdef, data, - sizeof(avmb1_extcarddef)))) - return retval; + if ((retval = copy_from_user(&cdef, data, + sizeof(avmb1_extcarddef)))) + return -EFAULT; } cparams.port = cdef.port; cparams.irq = cdef.irq; cparams.cardnr = cdef.cardnr; - read_lock_irqsave(&capi_drivers_list_lock, flags); - switch (cdef.cardtype) { - case AVM_CARDTYPE_B1: - list_for_each(l, &capi_drivers) { - driver = list_entry(l, struct capi_driver, list); - if (strcmp(driver->name, "b1isa") == 0) - break; - } - break; - case AVM_CARDTYPE_T1: - list_for_each(l, &capi_drivers) { - driver = list_entry(l, struct capi_driver, list); - if (strcmp(driver->name, "t1isa") == 0) - break; - } - break; - default: - driver = NULL; - break; + mutex_lock(&capi_drivers_lock); + + switch (cdef.cardtype) { + case AVM_CARDTYPE_B1: + list_for_each(l, &capi_drivers) { + driver = list_entry(l, struct capi_driver, list); + if (strcmp(driver->name, "b1isa") == 0) + break; + } + break; + case AVM_CARDTYPE_T1: + list_for_each(l, &capi_drivers) { + driver = list_entry(l, struct capi_driver, list); + if (strcmp(driver->name, "t1isa") == 0) + break; + } + break; + default: + driver = NULL; + break; } if (!driver) { - read_unlock_irqrestore(&capi_drivers_list_lock, flags); printk(KERN_ERR "kcapi: driver not loaded.\n"); - return -EIO; - } - if (!driver->add_card) { - read_unlock_irqrestore(&capi_drivers_list_lock, flags); + retval = -EIO; + } else if (!driver->add_card) { printk(KERN_ERR "kcapi: driver has no add card function.\n"); - return -EIO; - } + retval = -EIO; + } else + retval = driver->add_card(driver, &cparams); - retval = driver->add_card(driver, &cparams); - read_unlock_irqrestore(&capi_drivers_list_lock, flags); + mutex_unlock(&capi_drivers_lock); return retval; case AVMB1_LOAD: @@ -820,27 +1088,30 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data) sizeof(avmb1_loadandconfigdef))) return -EFAULT; } - card = get_capi_ctr_by_nr(ldef.contr); - if (!card) - return -EINVAL; - card = capi_ctr_get(card); - if (!card) - return -ESRCH; - if (card->load_firmware == NULL) { + + mutex_lock(&capi_controller_lock); + + ctr = get_capi_ctr_by_nr(ldef.contr); + if (!ctr) { + retval = -EINVAL; + goto load_unlock_out; + } + + if (ctr->load_firmware == NULL) { printk(KERN_DEBUG "kcapi: load: no load function\n"); - capi_ctr_put(card); - return -ESRCH; + retval = -ESRCH; + goto load_unlock_out; } if (ldef.t4file.len <= 0) { printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len); - capi_ctr_put(card); - return -EINVAL; + retval = -EINVAL; + goto load_unlock_out; } if (ldef.t4file.data == NULL) { printk(KERN_DEBUG "kcapi: load: invalid parameter: dataptr is 0\n"); - capi_ctr_put(card); - return -EINVAL; + retval = -EINVAL; + goto load_unlock_out; } ldata.firmware.user = 1; @@ -850,62 +1121,73 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data) ldata.configuration.data = ldef.t4config.data; ldata.configuration.len = ldef.t4config.len; - if (card->cardstate != CARD_DETECTED) { + if (ctr->state != CAPI_CTR_DETECTED) { printk(KERN_INFO "kcapi: load: contr=%d not in detect state\n", ldef.contr); - capi_ctr_put(card); - return -EBUSY; + retval = -EBUSY; + goto load_unlock_out; } - card->cardstate = CARD_LOADING; - - retval = card->load_firmware(card, &ldata); + ctr->state = CAPI_CTR_LOADING; + retval = ctr->load_firmware(ctr, &ldata); if (retval) { - card->cardstate = CARD_DETECTED; - capi_ctr_put(card); - return retval; + ctr->state = CAPI_CTR_DETECTED; + goto load_unlock_out; } - while (card->cardstate != CARD_RUNNING) { + retval = wait_on_ctr_state(ctr, CAPI_CTR_RUNNING); - msleep_interruptible(100); /* 0.1 sec */ - - if (signal_pending(current)) { - capi_ctr_put(card); - return -EINTR; - } - } - capi_ctr_put(card); - return 0; + load_unlock_out: + mutex_unlock(&capi_controller_lock); + return retval; case AVMB1_RESETCARD: if (copy_from_user(&rdef, data, sizeof(avmb1_resetdef))) return -EFAULT; - card = get_capi_ctr_by_nr(rdef.contr); - if (!card) - return -ESRCH; - if (card->cardstate == CARD_DETECTED) - return 0; + retval = 0; - card->reset_ctr(card); + mutex_lock(&capi_controller_lock); - while (card->cardstate > CARD_DETECTED) { + ctr = get_capi_ctr_by_nr(rdef.contr); + if (!ctr) { + retval = -ESRCH; + goto reset_unlock_out; + } - msleep_interruptible(100); /* 0.1 sec */ + if (ctr->state == CAPI_CTR_DETECTED) + goto reset_unlock_out; - if (signal_pending(current)) - return -EINTR; + if (ctr->reset_ctr == NULL) { + printk(KERN_DEBUG "kcapi: reset: no reset function\n"); + retval = -ESRCH; + goto reset_unlock_out; } - return 0; + ctr->reset_ctr(ctr); + + retval = wait_on_ctr_state(ctr, CAPI_CTR_DETECTED); + + reset_unlock_out: + mutex_unlock(&capi_controller_lock); + return retval; } return -EINVAL; } #endif +/** + * capi20_manufacturer() - CAPI 2.0 operation CAPI_MANUFACTURER + * @cmd: command. + * @data: parameter. + * + * Perform manufacturer specific command. + * Return value: CAPI result code + */ + int capi20_manufacturer(unsigned int cmd, void __user *data) { - struct capi_ctr *card; + struct capi_ctr *ctr; + int retval; switch (cmd) { #ifdef AVMB1_COMPAT @@ -923,14 +1205,20 @@ int capi20_manufacturer(unsigned int cmd, void __user *data) if (copy_from_user(&fdef, data, sizeof(kcapi_flagdef))) return -EFAULT; - card = get_capi_ctr_by_nr(fdef.contr); - if (!card) - return -ESRCH; + mutex_lock(&capi_controller_lock); + + ctr = get_capi_ctr_by_nr(fdef.contr); + if (ctr) { + ctr->traceflag = fdef.flag; + printk(KERN_INFO "kcapi: contr [%03d] set trace=%d\n", + ctr->cnr, ctr->traceflag); + retval = 0; + } else + retval = -ESRCH; + + mutex_unlock(&capi_controller_lock); - card->traceflag = fdef.flag; - printk(KERN_INFO "kcapi: contr [%03d] set trace=%d\n", - card->cnr, card->traceflag); - return 0; + return retval; } case KCAPI_CMD_ADDCARD: { @@ -938,17 +1226,18 @@ int capi20_manufacturer(unsigned int cmd, void __user *data) struct capi_driver *driver = NULL; capicardparams cparams; kcapi_carddef cdef; - int retval; if ((retval = copy_from_user(&cdef, data, sizeof(cdef)))) - return retval; + return -EFAULT; cparams.port = cdef.port; cparams.irq = cdef.irq; cparams.membase = cdef.membase; cparams.cardnr = cdef.cardnr; cparams.cardtype = 0; - cdef.driver[sizeof(cdef.driver)-1] = 0; + cdef.driver[sizeof(cdef.driver) - 1] = 0; + + mutex_lock(&capi_drivers_lock); list_for_each(l, &capi_drivers) { driver = list_entry(l, struct capi_driver, list); @@ -957,21 +1246,21 @@ int capi20_manufacturer(unsigned int cmd, void __user *data) } if (driver == NULL) { printk(KERN_ERR "kcapi: driver \"%s\" not loaded.\n", - cdef.driver); - return -ESRCH; - } - - if (!driver->add_card) { + cdef.driver); + retval = -ESRCH; + } else if (!driver->add_card) { printk(KERN_ERR "kcapi: driver \"%s\" has no add card function.\n", cdef.driver); - return -EIO; - } + retval = -EIO; + } else + retval = driver->add_card(driver, &cparams); - return driver->add_card(driver, &cparams); + mutex_unlock(&capi_drivers_lock); + return retval; } default: printk(KERN_ERR "kcapi: manufacturer command %d unknown.\n", - cmd); + cmd); break; } @@ -980,15 +1269,6 @@ int capi20_manufacturer(unsigned int cmd, void __user *data) EXPORT_SYMBOL(capi20_manufacturer); -/* temporary hack */ -void capi20_set_callback(struct capi20_appl *ap, - void (*callback) (unsigned int cmd, __u32 contr, void *data)) -{ - ap->callback = callback; -} - -EXPORT_SYMBOL(capi20_set_callback); - /* ------------------------------------------------------------- */ /* -------- Init & Cleanup ------------------------------------- */ /* ------------------------------------------------------------- */ @@ -997,36 +1277,39 @@ EXPORT_SYMBOL(capi20_set_callback); * init / exit functions */ +static struct notifier_block capictr_nb = { + .notifier_call = notify_handler, + .priority = INT_MAX, +}; + static int __init kcapi_init(void) { - char *p; - char rev[32]; - int ret; - - ret = cdebug_init(); - if (ret) - return ret; - kcapi_proc_init(); - - if ((p = strchr(revision, ':')) != NULL && p[1]) { - strlcpy(rev, p + 2, sizeof(rev)); - if ((p = strchr(rev, '$')) != NULL && p > rev) - *(p-1) = 0; - } else - strcpy(rev, "1.0"); + int err; - printk(KERN_NOTICE "CAPI Subsystem Rev %s\n", rev); + kcapi_wq = alloc_workqueue("kcapi", 0, 0); + if (!kcapi_wq) + return -ENOMEM; + + register_capictr_notifier(&capictr_nb); + + err = cdebug_init(); + if (err) { + unregister_capictr_notifier(&capictr_nb); + destroy_workqueue(kcapi_wq); + return err; + } + kcapi_proc_init(); return 0; } static void __exit kcapi_exit(void) { - kcapi_proc_exit(); + kcapi_proc_exit(); - /* make sure all notifiers are finished */ - flush_scheduled_work(); + unregister_capictr_notifier(&capictr_nb); cdebug_exit(); + destroy_workqueue(kcapi_wq); } module_init(kcapi_init); diff --git a/drivers/isdn/capi/kcapi.h b/drivers/isdn/capi/kcapi.h index 244711f7f83..6d439f9a76b 100644 --- a/drivers/isdn/capi/kcapi.h +++ b/drivers/isdn/capi/kcapi.h @@ -1,9 +1,9 @@ /* * Kernel CAPI 2.0 Module - * + * * Copyright 1999 by Carsten Paeth <calle@calle.de> * Copyright 2002 by Kai Germaschewski <kai@germaschewski.name> - * + * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * @@ -16,24 +16,27 @@ #include <linux/isdn/capilli.h> #ifdef KCAPI_DEBUG -#define DBG(format, arg...) do { \ -printk(KERN_DEBUG "%s: " format "\n" , __func__ , ## arg); \ -} while (0) +#define DBG(format, arg...) do { \ + printk(KERN_DEBUG "%s: " format "\n" , __func__ , ## arg); \ + } while (0) #else #define DBG(format, arg...) /* */ #endif enum { - CARD_DETECTED = 1, - CARD_LOADING = 2, - CARD_RUNNING = 3, + CAPI_CTR_DETACHED = 0, + CAPI_CTR_DETECTED = 1, + CAPI_CTR_LOADING = 2, + CAPI_CTR_RUNNING = 3, }; extern struct list_head capi_drivers; -extern rwlock_t capi_drivers_list_lock; +extern struct mutex capi_drivers_lock; + +extern struct capi_ctr *capi_controller[CAPI_MAXCONTR]; +extern struct mutex capi_controller_lock; extern struct capi20_appl *capi_applications[CAPI_MAXAPPL]; -extern struct capi_ctr *capi_cards[CAPI_MAXCONTR]; #ifdef CONFIG_PROC_FS @@ -46,4 +49,3 @@ static inline void kcapi_proc_init(void) { }; static inline void kcapi_proc_exit(void) { }; #endif - diff --git a/drivers/isdn/capi/kcapi_proc.c b/drivers/isdn/capi/kcapi_proc.c index c29208bd752..68db3c5a106 100644 --- a/drivers/isdn/capi/kcapi_proc.c +++ b/drivers/isdn/capi/kcapi_proc.c @@ -1,9 +1,9 @@ /* * Kernel CAPI 2.0 Module - /proc/capi handling - * + * * Copyright 1999 by Carsten Paeth <calle@calle.de> * Copyright 2002 by Kai Germaschewski <kai@germaschewski.name> - * + * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * @@ -14,14 +14,14 @@ #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/init.h> +#include <linux/export.h> -static char * -cardstate2str(unsigned short cardstate) +static char *state2str(unsigned short state) { - switch (cardstate) { - case CARD_DETECTED: return "detected"; - case CARD_LOADING: return "loading"; - case CARD_RUNNING: return "running"; + switch (state) { + case CAPI_CTR_DETECTED: return "detected"; + case CAPI_CTR_LOADING: return "loading"; + case CAPI_CTR_RUNNING: return "running"; default: return "???"; } } @@ -29,16 +29,19 @@ cardstate2str(unsigned short cardstate) // /proc/capi // =========================================================================== -// /proc/capi/controller: +// /proc/capi/controller: // cnr driver cardstate name driverinfo // /proc/capi/contrstats: // cnr nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt // --------------------------------------------------------------------------- static void *controller_start(struct seq_file *seq, loff_t *pos) + __acquires(capi_controller_lock) { + mutex_lock(&capi_controller_lock); + if (*pos < CAPI_MAXCONTR) - return &capi_cards[*pos]; + return &capi_controller[*pos]; return NULL; } @@ -47,13 +50,15 @@ static void *controller_next(struct seq_file *seq, void *v, loff_t *pos) { ++*pos; if (*pos < CAPI_MAXCONTR) - return &capi_cards[*pos]; + return &capi_controller[*pos]; return NULL; } static void controller_stop(struct seq_file *seq, void *v) + __releases(capi_controller_lock) { + mutex_unlock(&capi_controller_lock); } static int controller_show(struct seq_file *seq, void *v) @@ -65,7 +70,7 @@ static int controller_show(struct seq_file *seq, void *v) seq_printf(seq, "%d %-10s %-8s %-16s %s\n", ctr->cnr, ctr->driver_name, - cardstate2str(ctr->cardstate), + state2str(ctr->state), ctr->name, ctr->procinfo ? ctr->procinfo(ctr) : ""); @@ -80,7 +85,7 @@ static int contrstats_show(struct seq_file *seq, void *v) return 0; seq_printf(seq, "%d %lu %lu %lu %lu\n", - ctr->cnr, + ctr->cnr, ctr->nrecvctlpkt, ctr->nrecvdatapkt, ctr->nsentctlpkt, @@ -89,14 +94,14 @@ static int contrstats_show(struct seq_file *seq, void *v) return 0; } -static struct seq_operations seq_controller_ops = { +static const struct seq_operations seq_controller_ops = { .start = controller_start, .next = controller_next, .stop = controller_stop, .show = controller_show, }; -static struct seq_operations seq_contrstats_ops = { +static const struct seq_operations seq_contrstats_ops = { .start = controller_start, .next = controller_next, .stop = controller_stop, @@ -129,15 +134,17 @@ static const struct file_operations proc_contrstats_ops = { .release = seq_release, }; -// /proc/capi/applications: +// /proc/capi/applications: // applid l3cnt dblkcnt dblklen #ncci recvqueuelen -// /proc/capi/applstats: +// /proc/capi/applstats: // applid nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt // --------------------------------------------------------------------------- -static void * -applications_start(struct seq_file *seq, loff_t *pos) +static void *applications_start(struct seq_file *seq, loff_t *pos) + __acquires(capi_controller_lock) { + mutex_lock(&capi_controller_lock); + if (*pos < CAPI_MAXAPPL) return &capi_applications[*pos]; @@ -154,9 +161,10 @@ applications_next(struct seq_file *seq, void *v, loff_t *pos) return NULL; } -static void -applications_stop(struct seq_file *seq, void *v) +static void applications_stop(struct seq_file *seq, void *v) + __releases(capi_controller_lock) { + mutex_unlock(&capi_controller_lock); } static int @@ -194,14 +202,14 @@ applstats_show(struct seq_file *seq, void *v) return 0; } -static struct seq_operations seq_applications_ops = { +static const struct seq_operations seq_applications_ops = { .start = applications_start, .next = applications_next, .stop = applications_stop, .show = applications_show, }; -static struct seq_operations seq_applstats_ops = { +static const struct seq_operations seq_applstats_ops = { .start = applications_start, .next = applications_next, .stop = applications_stop, @@ -239,8 +247,9 @@ static const struct file_operations proc_applstats_ops = { // --------------------------------------------------------------------------- static void *capi_driver_start(struct seq_file *seq, loff_t *pos) + __acquires(&capi_drivers_lock) { - read_lock(&capi_drivers_list_lock); + mutex_lock(&capi_drivers_lock); return seq_list_start(&capi_drivers, *pos); } @@ -250,8 +259,9 @@ static void *capi_driver_next(struct seq_file *seq, void *v, loff_t *pos) } static void capi_driver_stop(struct seq_file *seq, void *v) + __releases(&capi_drivers_lock) { - read_unlock(&capi_drivers_list_lock); + mutex_unlock(&capi_drivers_lock); } static int capi_driver_show(struct seq_file *seq, void *v) @@ -262,7 +272,7 @@ static int capi_driver_show(struct seq_file *seq, void *v) return 0; } -static struct seq_operations seq_capi_driver_ops = { +static const struct seq_operations seq_capi_driver_ops = { .start = capi_driver_start, .next = capi_driver_next, .stop = capi_driver_stop, @@ -287,7 +297,7 @@ static const struct file_operations proc_driver_ops = { // --------------------------------------------------------------------------- -void __init +void __init kcapi_proc_init(void) { proc_mkdir("capi", NULL); |
