- kernel CAPI:
- Changed parameter "param" in capi_signal from __u32 to void *. - rewrote notifier handling in kcapi.c - new notifier NCCI_UP and NCCI_DOWN - User CAPI: - /dev/capi20 is now a cloning device. - middleware extentions prepared. - capidrv.c - locking of list operations and module count updates.
This commit is contained in:
parent
58a0fcec05
commit
7fe092d9a5
|
@ -11,6 +11,11 @@
|
|||
# parent makes..
|
||||
#
|
||||
# $Log$
|
||||
# Revision 1.8 2000/01/25 14:33:38 calle
|
||||
# - Added Support AVM B1 PCI V4.0 (tested with prototype)
|
||||
# - splitted up t1pci.c into b1dma.c for common function with b1pciv4
|
||||
# - support for revision register
|
||||
#
|
||||
# Revision 1.7 1999/09/15 08:16:03 calle
|
||||
# Implementation of 64Bit extention complete.
|
||||
#
|
||||
|
@ -82,48 +87,48 @@ ifeq ($(CONFIG_ISDN_DRV_AVMB1),y)
|
|||
OX_OBJS += kcapi.o
|
||||
O_OBJS += capi.o
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA
|
||||
O_OBJS += b1isa.o
|
||||
O_OBJS += b1isa.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI
|
||||
O_OBJS += b1pci.o
|
||||
O_OBJS += b1pci.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA
|
||||
O_OBJS += t1isa.o
|
||||
O_OBJS += t1isa.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
|
||||
OX_OBJS += b1pcmcia.o
|
||||
OX_OBJS += b1pcmcia.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_T1PCI
|
||||
O_OBJS += t1pci.o
|
||||
O_OBJS += t1pci.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_C4
|
||||
O_OBJS += c4.o
|
||||
O_OBJS += c4.o
|
||||
endif
|
||||
OX_OBJS += capiutil.o capidrv.o b1.o b1dma.o
|
||||
else
|
||||
ifeq ($(CONFIG_ISDN_DRV_AVMB1),m)
|
||||
O_TARGET += kernelcapi.o
|
||||
OX_OBJS += kcapi.o
|
||||
M_OBJS += capi.o kernelcapi.o
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA
|
||||
M_OBJS += b1isa.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI
|
||||
M_OBJS += b1pci.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA
|
||||
M_OBJS += t1isa.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
|
||||
MX_OBJS += b1pcmcia.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_T1PCI
|
||||
M_OBJS += t1pci.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_C4
|
||||
M_OBJS += c4.o
|
||||
endif
|
||||
MX_OBJS += capiutil.o capidrv.o b1.o b1dma.o
|
||||
O_TARGET += kernelcapi.o
|
||||
OX_OBJS += kcapi.o
|
||||
M_OBJS += capi.o kernelcapi.o
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA
|
||||
M_OBJS += b1isa.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI
|
||||
M_OBJS += b1pci.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA
|
||||
M_OBJS += t1isa.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
|
||||
MX_OBJS += b1pcmcia.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_T1PCI
|
||||
M_OBJS += t1pci.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_C4
|
||||
M_OBJS += c4.o
|
||||
endif
|
||||
MX_OBJS += capiutil.o capidrv.o b1.o b1dma.o
|
||||
endif
|
||||
endif
|
||||
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
* Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.23 2000/02/26 01:00:53 keil
|
||||
* changes from 2.3.47
|
||||
*
|
||||
* Revision 1.22 1999/11/13 21:27:16 keil
|
||||
* remove KERNELVERSION
|
||||
*
|
||||
|
@ -131,11 +134,14 @@
|
|||
#ifdef HAVE_DEVFS_FS
|
||||
#include <linux/devfs_fs_kernel.h>
|
||||
#endif /* HAVE_DEVFS_FS */
|
||||
|
||||
#include <linux/isdn_compat.h>
|
||||
#include "capiutil.h"
|
||||
#include "capicmd.h"
|
||||
#include "capidev.h"
|
||||
#ifdef COMPAT_HAS_kmem_cache
|
||||
#include <linux/slab.h>
|
||||
#endif
|
||||
|
||||
static char *revision = "$Revision$";
|
||||
|
||||
MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)");
|
||||
|
||||
|
@ -145,33 +151,208 @@ int capi_major = 68; /* allocated */
|
|||
|
||||
MODULE_PARM(capi_major, "i");
|
||||
|
||||
/* -------- defines ------------------------------------------------- */
|
||||
|
||||
#define CAPINC_MAX_RECVQUEUE 10
|
||||
#define CAPINC_MAX_SENDQUEUE 10
|
||||
#define CAPI_MAX_BLKSIZE 2048
|
||||
|
||||
/* -------- data structures ----------------------------------------- */
|
||||
|
||||
struct capidev;
|
||||
struct capincci;
|
||||
|
||||
struct capincci {
|
||||
struct capincci *next;
|
||||
__u32 ncci;
|
||||
struct capidev *cdev;
|
||||
};
|
||||
|
||||
struct capidev {
|
||||
struct capidev *next;
|
||||
struct file *file;
|
||||
__u16 applid;
|
||||
__u16 errcode;
|
||||
unsigned int minor;
|
||||
unsigned userflags;
|
||||
|
||||
struct sk_buff_head recvqueue;
|
||||
#ifdef COMPAT_HAS_NEW_WAITQ
|
||||
wait_queue_head_t recvwait;
|
||||
#else
|
||||
struct wait_queue *recvwait;
|
||||
#endif
|
||||
|
||||
/* Statistic */
|
||||
unsigned long nrecvctlpkt;
|
||||
unsigned long nrecvdatapkt;
|
||||
unsigned long nsentctlpkt;
|
||||
unsigned long nsentdatapkt;
|
||||
|
||||
struct capincci *nccis;
|
||||
};
|
||||
|
||||
/* -------- global variables ---------------------------------------- */
|
||||
|
||||
static struct capidev capidevs[CAPI_MAXMINOR + 1];
|
||||
struct capi_interface *capifuncs;
|
||||
static struct capi_interface *capifuncs = 0;
|
||||
static struct capidev *capidev_openlist = 0;
|
||||
|
||||
/* -------- function called by lower level -------------------------- */
|
||||
#ifdef COMPAT_HAS_kmem_cache
|
||||
static kmem_cache_t *capidev_cachep = 0;
|
||||
static kmem_cache_t *capincci_cachep = 0;
|
||||
#endif
|
||||
|
||||
static void capi_signal(__u16 applid, __u32 minor)
|
||||
/* -------- struct capincci ----------------------------------------- */
|
||||
|
||||
static struct capincci *capincci_alloc(struct capidev *cdev, __u32 ncci)
|
||||
{
|
||||
struct capidev *cdev;
|
||||
struct sk_buff *skb = 0;
|
||||
struct capincci *np, **pp;
|
||||
|
||||
if (minor > CAPI_MAXMINOR || !capidevs[minor].is_registered) {
|
||||
printk(KERN_ERR "BUG: capi_signal: illegal minor %d\n", minor);
|
||||
return;
|
||||
}
|
||||
cdev = &capidevs[minor];
|
||||
(void) (*capifuncs->capi_get_message) (applid, &skb);
|
||||
if (skb) {
|
||||
skb_queue_tail(&cdev->recv_queue, skb);
|
||||
wake_up_interruptible(&cdev->recv_wait);
|
||||
} else {
|
||||
printk(KERN_ERR "BUG: capi_signal: no skb\n");
|
||||
#ifdef COMPAT_HAS_kmem_cache
|
||||
np = (struct capincci *)kmem_cache_alloc(capincci_cachep, GFP_ATOMIC);
|
||||
#else
|
||||
np = (struct capincci *)kmalloc(sizeof(struct capincci), GFP_ATOMIC);
|
||||
#endif
|
||||
if (!np)
|
||||
return 0;
|
||||
memset(np, 0, sizeof(struct capincci));
|
||||
np->ncci = ncci;
|
||||
np->cdev = cdev;
|
||||
for (pp=&cdev->nccis; *pp; pp = &(*pp)->next)
|
||||
;
|
||||
*pp = np;
|
||||
return np;
|
||||
}
|
||||
|
||||
static void capincci_free(struct capidev *cdev, __u32 ncci)
|
||||
{
|
||||
struct capincci *np, **pp;
|
||||
|
||||
pp=&cdev->nccis;
|
||||
while (*pp) {
|
||||
np = *pp;
|
||||
if (ncci == 0xffffffff || np->ncci == ncci) {
|
||||
*pp = (*pp)->next;
|
||||
#ifdef COMPAT_HAS_kmem_cache
|
||||
kmem_cache_free(capincci_cachep, np);
|
||||
#else
|
||||
kfree(np);
|
||||
#endif
|
||||
if (*pp == 0) return;
|
||||
} else {
|
||||
pp = &(*pp)->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------- file_operations ----------------------------------------- */
|
||||
struct capincci *capincci_find(struct capidev *cdev, __u32 ncci)
|
||||
{
|
||||
struct capincci *p;
|
||||
|
||||
for (p=cdev->nccis; p ; p = p->next) {
|
||||
if (p->ncci == ncci)
|
||||
break;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* -------- struct capidev ------------------------------------------ */
|
||||
|
||||
static struct capidev *capidev_alloc(struct file *file)
|
||||
{
|
||||
struct capidev *cdev;
|
||||
struct capidev **pp;
|
||||
|
||||
#ifdef COMPAT_HAS_kmem_cache
|
||||
cdev = (struct capidev *)kmem_cache_alloc(capidev_cachep, GFP_KERNEL);
|
||||
#else
|
||||
cdev = (struct capidev *)kmalloc(sizeof(struct capidev), GFP_KERNEL);
|
||||
#endif
|
||||
if (!cdev)
|
||||
return 0;
|
||||
memset(cdev, 0, sizeof(struct capidev));
|
||||
cdev->file = file;
|
||||
cdev->minor = MINOR_PART(file);
|
||||
|
||||
skb_queue_head_init(&cdev->recvqueue);
|
||||
#ifdef COMPAT_HAS_NEW_WAITQ
|
||||
init_waitqueue_head(&cdev->recvwait);
|
||||
#endif
|
||||
pp=&capidev_openlist;
|
||||
while (*pp) pp = &(*pp)->next;
|
||||
*pp = cdev;
|
||||
return cdev;
|
||||
}
|
||||
|
||||
static void capidev_free(struct capidev *cdev)
|
||||
{
|
||||
struct capidev **pp;
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (cdev->applid)
|
||||
(*capifuncs->capi_release) (cdev->applid);
|
||||
cdev->applid = 0;
|
||||
|
||||
while ((skb = skb_dequeue(&cdev->recvqueue)) != 0) {
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
pp=&capidev_openlist;
|
||||
while (*pp && *pp != cdev) pp = &(*pp)->next;
|
||||
if (*pp)
|
||||
*pp = cdev->next;
|
||||
|
||||
#ifdef COMPAT_HAS_kmem_cache
|
||||
kmem_cache_free(capidev_cachep, cdev);
|
||||
#else
|
||||
kfree(cdev);
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct capidev *capidev_find(__u16 applid)
|
||||
{
|
||||
struct capidev *p;
|
||||
for (p=capidev_openlist; p; p = p->next) {
|
||||
if (p->applid == applid)
|
||||
break;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* -------- function called by lower level -------------------------- */
|
||||
|
||||
static void capi_signal(__u16 applid, void *param)
|
||||
{
|
||||
struct capidev *cdev = (struct capidev *)param;
|
||||
struct capincci *np;
|
||||
struct sk_buff *skb = 0;
|
||||
__u32 ncci;
|
||||
|
||||
(void) (*capifuncs->capi_get_message) (applid, &skb);
|
||||
if (!skb) {
|
||||
printk(KERN_ERR "BUG: capi_signal: no skb\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (CAPIMSG_COMMAND(skb->data) != CAPI_DATA_B3) {
|
||||
skb_queue_tail(&cdev->recvqueue, skb);
|
||||
wake_up_interruptible(&cdev->recvwait);
|
||||
return;
|
||||
}
|
||||
ncci = CAPIMSG_CONTROL(skb->data);
|
||||
for (np = cdev->nccis; np && np->ncci != ncci; np = np->next)
|
||||
;
|
||||
if (!np) {
|
||||
printk(KERN_ERR "BUG: capi_signal: ncci not found\n");
|
||||
skb_queue_tail(&cdev->recvqueue, skb);
|
||||
wake_up_interruptible(&cdev->recvwait);
|
||||
return;
|
||||
}
|
||||
skb_queue_tail(&cdev->recvqueue, skb);
|
||||
wake_up_interruptible(&cdev->recvwait);
|
||||
}
|
||||
|
||||
/* -------- file_operations for capidev ----------------------------- */
|
||||
|
||||
static long long capi_llseek(struct file *file,
|
||||
long long offset, int origin)
|
||||
|
@ -182,29 +363,25 @@ static long long capi_llseek(struct file *file,
|
|||
static ssize_t capi_read(struct file *file, char *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct inode *inode = file->f_dentry->d_inode;
|
||||
unsigned int minor = MINOR(inode->i_rdev);
|
||||
struct capidev *cdev;
|
||||
struct capidev *cdev = (struct capidev *)file->private_data;
|
||||
struct sk_buff *skb;
|
||||
int retval;
|
||||
size_t copied;
|
||||
|
||||
if (ppos != &file->f_pos)
|
||||
if (ppos != &file->f_pos)
|
||||
return -ESPIPE;
|
||||
|
||||
if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
|
||||
if (!cdev->applid)
|
||||
return -ENODEV;
|
||||
|
||||
cdev = &capidevs[minor];
|
||||
|
||||
if ((skb = skb_dequeue(&cdev->recv_queue)) == 0) {
|
||||
if ((skb = skb_dequeue(&cdev->recvqueue)) == 0) {
|
||||
|
||||
if (file->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
|
||||
for (;;) {
|
||||
interruptible_sleep_on(&cdev->recv_wait);
|
||||
if ((skb = skb_dequeue(&cdev->recv_queue)) != 0)
|
||||
interruptible_sleep_on(&cdev->recvwait);
|
||||
if ((skb = skb_dequeue(&cdev->recvqueue)) != 0)
|
||||
break;
|
||||
if (signal_pending(current))
|
||||
break;
|
||||
|
@ -213,20 +390,22 @@ static ssize_t capi_read(struct file *file, char *buf,
|
|||
return -ERESTARTNOHAND;
|
||||
}
|
||||
if (skb->len > count) {
|
||||
skb_queue_head(&cdev->recv_queue, skb);
|
||||
skb_queue_head(&cdev->recvqueue, skb);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
retval = copy_to_user(buf, skb->data, skb->len);
|
||||
if (retval) {
|
||||
skb_queue_head(&cdev->recv_queue, skb);
|
||||
skb_queue_head(&cdev->recvqueue, skb);
|
||||
return retval;
|
||||
}
|
||||
copied = skb->len;
|
||||
|
||||
if (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3
|
||||
&& CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND)
|
||||
if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_IND) {
|
||||
cdev->nrecvdatapkt++;
|
||||
else cdev->nrecvctlpkt++;
|
||||
} else {
|
||||
cdev->nrecvctlpkt++;
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
|
||||
return copied;
|
||||
|
@ -235,41 +414,34 @@ static ssize_t capi_read(struct file *file, char *buf,
|
|||
static ssize_t capi_write(struct file *file, const char *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct inode *inode = file->f_dentry->d_inode;
|
||||
unsigned int minor = MINOR(inode->i_rdev);
|
||||
struct capidev *cdev;
|
||||
struct capidev *cdev = (struct capidev *)file->private_data;
|
||||
struct sk_buff *skb;
|
||||
int retval;
|
||||
__u8 cmd;
|
||||
__u8 subcmd;
|
||||
__u16 mlen;
|
||||
|
||||
if (ppos != &file->f_pos)
|
||||
if (ppos != &file->f_pos)
|
||||
return -ESPIPE;
|
||||
|
||||
if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
|
||||
if (!cdev->applid)
|
||||
return -ENODEV;
|
||||
|
||||
cdev = &capidevs[minor];
|
||||
|
||||
skb = alloc_skb(count, GFP_USER);
|
||||
|
||||
if ((retval = copy_from_user(skb_put(skb, count), buf, count))) {
|
||||
kfree_skb(skb);
|
||||
return retval;
|
||||
}
|
||||
cmd = CAPIMSG_COMMAND(skb->data);
|
||||
subcmd = CAPIMSG_SUBCOMMAND(skb->data);
|
||||
mlen = CAPIMSG_LEN(skb->data);
|
||||
if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ) {
|
||||
__u16 dlen = CAPIMSG_DATALEN(skb->data);
|
||||
if (mlen + dlen != count) {
|
||||
if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
|
||||
if (mlen + CAPIMSG_DATALEN(skb->data) != count) {
|
||||
kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
if (mlen != count) {
|
||||
kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (mlen != count) {
|
||||
kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
}
|
||||
CAPIMSG_SETAPPID(skb->data, cdev->applid);
|
||||
|
||||
|
@ -279,26 +451,26 @@ static ssize_t capi_write(struct file *file, const char *buf,
|
|||
kfree_skb(skb);
|
||||
return -EIO;
|
||||
}
|
||||
if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ)
|
||||
if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
|
||||
cdev->nsentdatapkt++;
|
||||
else cdev->nsentctlpkt++;
|
||||
} else {
|
||||
cdev->nsentctlpkt++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
capi_poll(struct file *file, poll_table * wait)
|
||||
{
|
||||
struct capidev *cdev = (struct capidev *)file->private_data;
|
||||
unsigned int mask = 0;
|
||||
unsigned int minor = MINOR_PART(file);
|
||||
struct capidev *cdev;
|
||||
|
||||
if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
|
||||
if (!cdev->applid)
|
||||
return POLLERR;
|
||||
|
||||
cdev = &capidevs[minor];
|
||||
poll_wait(file, &(cdev->recv_wait), wait);
|
||||
poll_wait(file, &(cdev->recvwait), wait);
|
||||
mask = POLLOUT | POLLWRNORM;
|
||||
if (!skb_queue_empty(&cdev->recv_queue))
|
||||
if (!skb_queue_empty(&cdev->recvqueue))
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
return mask;
|
||||
}
|
||||
|
@ -306,36 +478,28 @@ capi_poll(struct file *file, poll_table * wait)
|
|||
static int capi_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
unsigned int minor = MINOR(inode->i_rdev);
|
||||
struct capidev *cdev;
|
||||
struct capidev *cdev = (struct capidev *)file->private_data;
|
||||
capi_ioctl_struct data;
|
||||
int retval;
|
||||
|
||||
|
||||
if (minor >= CAPI_MAXMINOR || !capidevs[minor].is_open)
|
||||
return -ENODEV;
|
||||
|
||||
cdev = &capidevs[minor];
|
||||
int retval = -EINVAL;
|
||||
|
||||
switch (cmd) {
|
||||
case CAPI_REGISTER:
|
||||
{
|
||||
if (!minor)
|
||||
return -EINVAL;
|
||||
retval = copy_from_user((void *) &data.rparams,
|
||||
(void *) arg, sizeof(struct capi_register_params));
|
||||
if (retval)
|
||||
return -EFAULT;
|
||||
if (cdev->is_registered)
|
||||
if (cdev->applid)
|
||||
return -EEXIST;
|
||||
cdev->errcode = (*capifuncs->capi_register) (&data.rparams,
|
||||
&cdev->applid);
|
||||
if (cdev->errcode)
|
||||
if (cdev->errcode) {
|
||||
cdev->applid = 0;
|
||||
return -EIO;
|
||||
(void) (*capifuncs->capi_set_signal) (cdev->applid, capi_signal, minor);
|
||||
cdev->is_registered = 1;
|
||||
}
|
||||
(void) (*capifuncs->capi_set_signal) (cdev->applid, capi_signal, cdev);
|
||||
}
|
||||
return 0;
|
||||
return (int)cdev->applid;
|
||||
|
||||
case CAPI_GET_VERSION:
|
||||
{
|
||||
|
@ -441,8 +605,6 @@ static int capi_ioctl(struct inode *inode, struct file *file,
|
|||
case CAPI_MANUFACTURER_CMD:
|
||||
{
|
||||
struct capi_manufacturer_cmd mcmd;
|
||||
if (minor)
|
||||
return -EINVAL;
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
retval = copy_from_user((void *) &mcmd, (void *) arg,
|
||||
|
@ -452,62 +614,71 @@ static int capi_ioctl(struct inode *inode, struct file *file,
|
|||
return (*capifuncs->capi_manufacturer) (mcmd.cmd, mcmd.data);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case CAPI_SET_FLAGS:
|
||||
case CAPI_CLR_FLAGS:
|
||||
{
|
||||
unsigned userflags;
|
||||
retval = copy_from_user((void *) &userflags,
|
||||
(void *) arg,
|
||||
sizeof(userflags));
|
||||
if (retval)
|
||||
return -EFAULT;
|
||||
if (cmd == CAPI_SET_FLAGS)
|
||||
cdev->userflags |= userflags;
|
||||
else
|
||||
cdev->userflags &= ~userflags;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case CAPI_GET_FLAGS:
|
||||
{
|
||||
retval = copy_to_user((void *) arg,
|
||||
(void *) &cdev->userflags,
|
||||
sizeof(cdev->userflags));
|
||||
if (retval)
|
||||
return -EFAULT;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case CAPI_NCCI_OPENCOUNT:
|
||||
{
|
||||
struct capincci *nccip;
|
||||
unsigned ncci;
|
||||
int count = 0;
|
||||
retval = copy_from_user((void *) &ncci,
|
||||
(void *) arg,
|
||||
sizeof(ncci));
|
||||
if (retval)
|
||||
return -EFAULT;
|
||||
nccip = capincci_find(cdev, (__u32) ncci);
|
||||
if (!nccip)
|
||||
return 0;
|
||||
return count;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int capi_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
unsigned int minor = MINOR(inode->i_rdev);
|
||||
if (file->private_data)
|
||||
return -EEXIST;
|
||||
|
||||
if (minor >= CAPI_MAXMINOR)
|
||||
return -ENXIO;
|
||||
|
||||
if (minor) {
|
||||
if (capidevs[minor].is_open)
|
||||
return -EEXIST;
|
||||
|
||||
capidevs[minor].is_open = 1;
|
||||
skb_queue_head_init(&capidevs[minor].recv_queue);
|
||||
MOD_INC_USE_COUNT;
|
||||
capidevs[minor].nopen++;
|
||||
|
||||
} else {
|
||||
capidevs[minor].is_open++;
|
||||
MOD_INC_USE_COUNT;
|
||||
}
|
||||
if ((file->private_data = capidev_alloc(file)) == 0)
|
||||
return -ENOMEM;
|
||||
|
||||
MOD_INC_USE_COUNT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
capi_release(struct inode *inode, struct file *file)
|
||||
static int capi_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
unsigned int minor = MINOR(inode->i_rdev);
|
||||
struct capidev *cdev;
|
||||
struct sk_buff *skb;
|
||||
struct capidev *cdev = (struct capidev *)file->private_data;
|
||||
|
||||
if (minor >= CAPI_MAXMINOR || !capidevs[minor].is_open) {
|
||||
printk(KERN_ERR "capi20: release minor %d ???\n", minor);
|
||||
return 0;
|
||||
}
|
||||
cdev = &capidevs[minor];
|
||||
|
||||
if (minor) {
|
||||
|
||||
if (cdev->is_registered)
|
||||
(*capifuncs->capi_release) (cdev->applid);
|
||||
|
||||
cdev->is_registered = 0;
|
||||
cdev->applid = 0;
|
||||
|
||||
while ((skb = skb_dequeue(&cdev->recv_queue)) != 0) {
|
||||
kfree_skb(skb);
|
||||
}
|
||||
cdev->is_open = 0;
|
||||
} else {
|
||||
cdev->is_open--;
|
||||
}
|
||||
capincci_free(cdev, 0xffffffff);
|
||||
capidev_free(cdev);
|
||||
|
||||
MOD_DEC_USE_COUNT;
|
||||
return 0;
|
||||
|
@ -531,30 +702,27 @@ static struct file_operations capi_fops =
|
|||
NULL, /* capi_fasync */
|
||||
};
|
||||
|
||||
/* -------- /proc functions ----------------------------------- */
|
||||
/* -------- /proc functions ----------------------------------------- */
|
||||
|
||||
/*
|
||||
* /proc/capi/capi20:
|
||||
* minor opencount nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
|
||||
* 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)
|
||||
{
|
||||
struct capidev *cp;
|
||||
int i;
|
||||
struct capidev *cdev;
|
||||
int len = 0;
|
||||
off_t begin = 0;
|
||||
|
||||
for (i=0; i < CAPI_MAXMINOR; i++) {
|
||||
cp = &capidevs[i+1];
|
||||
if (cp->nopen == 0) continue;
|
||||
len += sprintf(page+len, "%d %lu %lu %lu %lu %lu\n",
|
||||
i+1,
|
||||
cp->nopen,
|
||||
cp->nrecvctlpkt,
|
||||
cp->nrecvdatapkt,
|
||||
cp->nsentctlpkt,
|
||||
cp->nsentdatapkt);
|
||||
for (cdev=capidev_openlist; cdev; cdev = cdev->next) {
|
||||
len += sprintf(page+len, "%d %d %lu %lu %lu %lu\n",
|
||||
cdev->minor,
|
||||
cdev->applid,
|
||||
cdev->nrecvctlpkt,
|
||||
cdev->nrecvdatapkt,
|
||||
cdev->nsentctlpkt,
|
||||
cdev->nsentdatapkt);
|
||||
if (len+begin > off+count)
|
||||
goto endloop;
|
||||
if (len+begin < off) {
|
||||
|
@ -563,7 +731,42 @@ static int proc_capidev_read_proc(char *page, char **start, off_t off,
|
|||
}
|
||||
}
|
||||
endloop:
|
||||
if (i >= CAPI_MAXMINOR)
|
||||
if (cdev == 0)
|
||||
*eof = 1;
|
||||
if (off >= len+begin)
|
||||
return 0;
|
||||
*start = page + (begin-off);
|
||||
return ((count < begin+len-off) ? count : begin+len-off);
|
||||
}
|
||||
|
||||
/*
|
||||
* /proc/capi/capi20ncci:
|
||||
* applid ncci
|
||||
*/
|
||||
static int proc_capincci_read_proc(char *page, char **start, off_t off,
|
||||
int count, int *eof, void *data)
|
||||
{
|
||||
struct capidev *cdev;
|
||||
struct capincci *np;
|
||||
int len = 0;
|
||||
off_t begin = 0;
|
||||
|
||||
for (cdev=capidev_openlist; cdev; cdev = cdev->next) {
|
||||
for (np=cdev->nccis; np; np = np->next) {
|
||||
len += sprintf(page+len, "%d 0x%x%s\n",
|
||||
cdev->applid,
|
||||
np->ncci,
|
||||
"");
|
||||
if (len+begin > off+count)
|
||||
goto endloop;
|
||||
if (len+begin < off) {
|
||||
begin += len;
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
endloop:
|
||||
if (cdev == 0)
|
||||
*eof = 1;
|
||||
if (off >= len+begin)
|
||||
return 0;
|
||||
|
@ -580,6 +783,7 @@ static struct procfsentries {
|
|||
} procfsentries[] = {
|
||||
/* { "capi", S_IFDIR, 0 }, */
|
||||
{ "capi/capi20", 0 , proc_capidev_read_proc },
|
||||
{ "capi/capi20ncci", 0 , proc_capincci_read_proc },
|
||||
};
|
||||
|
||||
static void proc_init(void)
|
||||
|
@ -607,67 +811,143 @@ static void proc_exit(void)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------- init function and module interface ---------------------- */
|
||||
|
||||
#ifdef COMPAT_HAS_kmem_cache
|
||||
|
||||
static void alloc_exit(void)
|
||||
{
|
||||
if (capidev_cachep) {
|
||||
(void)kmem_cache_destroy(capidev_cachep);
|
||||
capidev_cachep = 0;
|
||||
}
|
||||
if (capincci_cachep) {
|
||||
(void)kmem_cache_destroy(capincci_cachep);
|
||||
capincci_cachep = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int alloc_init(void)
|
||||
{
|
||||
capidev_cachep = kmem_cache_create("capi20_dev",
|
||||
sizeof(struct capidev),
|
||||
0,
|
||||
SLAB_HWCACHE_ALIGN,
|
||||
NULL, NULL);
|
||||
if (!capidev_cachep) {
|
||||
alloc_exit();
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
capincci_cachep = kmem_cache_create("capi20_ncci",
|
||||
sizeof(struct capincci),
|
||||
0,
|
||||
SLAB_HWCACHE_ALIGN,
|
||||
NULL, NULL);
|
||||
if (!capincci_cachep) {
|
||||
alloc_exit();
|
||||
return -ENOMEM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void lower_callback(unsigned int cmd, __u32 contr, void *data)
|
||||
{
|
||||
struct capi_ncciinfo *np;
|
||||
struct capidev *cdev;
|
||||
|
||||
switch (cmd) {
|
||||
case KCI_CONTRUP:
|
||||
printk(KERN_INFO "capi: controller %hu up\n", contr);
|
||||
break;
|
||||
case KCI_CONTRDOWN:
|
||||
printk(KERN_INFO "capi: controller %hu down\n", contr);
|
||||
break;
|
||||
case KCI_NCCIUP:
|
||||
np = (struct capi_ncciinfo *)data;
|
||||
if ((cdev = capidev_find(np->applid)) == 0)
|
||||
return;
|
||||
(void)capincci_alloc(cdev, np->ncci);
|
||||
break;
|
||||
case KCI_NCCIDOWN:
|
||||
np = (struct capi_ncciinfo *)data;
|
||||
if ((cdev = capidev_find(np->applid)) == 0)
|
||||
return;
|
||||
(void)capincci_free(cdev, np->ncci);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MODULE
|
||||
#define capi_init init_module
|
||||
#endif
|
||||
|
||||
static struct capi_interface_user cuser = {
|
||||
"capi20",
|
||||
0,
|
||||
lower_callback,
|
||||
};
|
||||
|
||||
static char rev[10];
|
||||
|
||||
int capi_init(void)
|
||||
{
|
||||
#ifdef COMPAT_HAS_NEW_WAITQ
|
||||
int j;
|
||||
#endif
|
||||
|
||||
memset(capidevs, 0, sizeof(capidevs));
|
||||
#ifdef COMPAT_HAS_NEW_WAITQ
|
||||
for ( j = 0; j < CAPI_MAXMINOR+1; j++ ) {
|
||||
init_waitqueue_head(&capidevs[j].recv_wait);
|
||||
}
|
||||
#endif
|
||||
char *p;
|
||||
|
||||
MOD_INC_USE_COUNT;
|
||||
|
||||
if ((p = strchr(revision, ':'))) {
|
||||
strcpy(rev, p + 2);
|
||||
p = strchr(rev, '$');
|
||||
*(p-1) = 0;
|
||||
} else
|
||||
strcpy(rev, "???");
|
||||
|
||||
if (devfs_register_chrdev(capi_major, "capi20", &capi_fops)) {
|
||||
printk(KERN_ERR "capi20: unable to get major %d\n", capi_major);
|
||||
MOD_DEC_USE_COUNT;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DEVFS_FS
|
||||
devfs_register (NULL, "isdn/capi20", 0, DEVFS_FL_DEFAULT,
|
||||
capi_major, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
|
||||
&capi_fops, NULL);
|
||||
devfs_register_series (NULL, "isdn/capi20.0%u", 10, DEVFS_FL_DEFAULT,
|
||||
capi_major, 1,
|
||||
S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
|
||||
&capi_fops, NULL);
|
||||
devfs_register_series (NULL, "isdn/capi20.1%u", 10, DEVFS_FL_DEFAULT,
|
||||
capi_major, 11,
|
||||
S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
|
||||
&capi_fops, NULL);
|
||||
#endif
|
||||
printk(KERN_NOTICE "capi20: started up with major %d\n", capi_major);
|
||||
|
||||
if ((capifuncs = attach_capi_interface(&cuser)) == 0) {
|
||||
|
||||
MOD_DEC_USE_COUNT;
|
||||
devfs_unregister_chrdev(capi_major, "capi20");
|
||||
#ifdef HAVE_DEVFS_FS
|
||||
devfs_unregister(devfs_find_handle(NULL, "capi20", 0,
|
||||
capi_major, 0,
|
||||
DEVFS_SPECIAL_CHR, 0));
|
||||
for (j = 0; j < 10; j++) {
|
||||
char devname[32];
|
||||
|
||||
sprintf(devname, "isdn/capi20.0%i", j);
|
||||
devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, j + 1, DEVFS_SPECIAL_CHR, 0));
|
||||
sprintf (devname, "isdn/capi20.1%i", j);
|
||||
devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, j + 11, DEVFS_SPECIAL_CHR, 0));
|
||||
}
|
||||
#endif
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
#ifdef COMPAT_HAS_kmem_cache
|
||||
if (alloc_init() < 0) {
|
||||
(void) detach_capi_interface(&cuser);
|
||||
devfs_unregister_chrdev(capi_major, "capi20");
|
||||
MOD_DEC_USE_COUNT;
|
||||
#ifdef HAVE_DEVFS_FS
|
||||
devfs_unregister(devfs_find_handle(NULL, "capi20", 0,
|
||||
capi_major, 0,
|
||||
DEVFS_SPECIAL_CHR, 0));
|
||||
return -ENOMEM;
|
||||
}
|
||||
#endif
|
||||
|
||||
(void)proc_init();
|
||||
|
||||
printk(KERN_NOTICE "capi20: Rev%s: started up with major %d\n",
|
||||
rev, capi_major);
|
||||
|
||||
MOD_DEC_USE_COUNT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -678,6 +958,9 @@ void cleanup_module(void)
|
|||
int i;
|
||||
char devname[32];
|
||||
|
||||
#endif
|
||||
#ifdef COMPAT_HAS_kmem_cache
|
||||
alloc_exit();
|
||||
#endif
|
||||
(void)proc_exit();
|
||||
devfs_unregister_chrdev(capi_major, "capi20");
|
||||
|
@ -691,6 +974,7 @@ void cleanup_module(void)
|
|||
}
|
||||
#endif
|
||||
(void) detach_capi_interface(&cuser);
|
||||
printk(KERN_NOTICE "capi: Rev%s: unloaded\n", rev);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
* Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.1 1997/03/04 21:50:30 calle
|
||||
* Frirst version in isdn4linux
|
||||
*
|
||||
* Revision 2.2 1997/02/12 09:31:39 calle
|
||||
* new version
|
||||
*
|
||||
|
@ -17,6 +20,10 @@
|
|||
#ifndef __CAPICMD_H__
|
||||
#define __CAPICMD_H__
|
||||
|
||||
#define CAPI_MSG_BASELEN 8
|
||||
#define CAPI_DATA_B3_REQ_LEN (CAPI_MSG_BASELEN+4+4+2+2+2)
|
||||
#define CAPI_DATA_B3_RESP_LEN (CAPI_MSG_BASELEN+4+2)
|
||||
|
||||
/*----- CAPI commands -----*/
|
||||
#define CAPI_ALERT 0x01
|
||||
#define CAPI_CONNECT 0x02
|
||||
|
|
|
@ -6,6 +6,22 @@
|
|||
* (c) Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.4 1999/07/01 15:26:32 calle
|
||||
* complete new version (I love it):
|
||||
* + new hardware independed "capi_driver" interface that will make it easy to:
|
||||
* - support other controllers with CAPI-2.0 (i.e. USB Controller)
|
||||
* - write a CAPI-2.0 for the passive cards
|
||||
* - support serial link CAPI-2.0 boxes.
|
||||
* + wrote "capi_driver" for all supported cards.
|
||||
* + "capi_driver" (supported cards) now have to be configured with
|
||||
* make menuconfig, in the past all supported cards where included
|
||||
* at once.
|
||||
* + new and better informations in /proc/capi/
|
||||
* + new ioctl to switch trace of capi messages per controller
|
||||
* using "avmcapictrl trace [contr] on|off|...."
|
||||
* + complete testcircle with all supported cards and also the
|
||||
* PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
|
||||
*
|
||||
* Revision 1.3 1999/07/01 08:22:58 keil
|
||||
* compatibility macros now in <linux/isdn_compat.h>
|
||||
*
|
||||
|
@ -24,22 +40,22 @@
|
|||
*/
|
||||
|
||||
struct capidev {
|
||||
int is_open;
|
||||
int is_registered;
|
||||
__u16 applid;
|
||||
struct capidev *next;
|
||||
struct file *file;
|
||||
__u16 applid;
|
||||
__u16 errcode;
|
||||
unsigned int minor;
|
||||
|
||||
struct sk_buff_head recv_queue;
|
||||
#ifdef COMPAT_HAS_NEW_WAITQ
|
||||
wait_queue_head_t recv_wait;
|
||||
#else
|
||||
struct wait_queue *recv_wait;
|
||||
#endif
|
||||
__u16 errcode;
|
||||
/* Statistic */
|
||||
unsigned long nopen;
|
||||
unsigned long nrecvctlpkt;
|
||||
unsigned long nrecvdatapkt;
|
||||
unsigned long nsentctlpkt;
|
||||
unsigned long nsentdatapkt;
|
||||
};
|
||||
|
||||
#define CAPI_MAXMINOR CAPI_MAXAPPL
|
||||
/* Statistic */
|
||||
unsigned long nrecvctlpkt;
|
||||
unsigned long nrecvdatapkt;
|
||||
unsigned long nsentctlpkt;
|
||||
unsigned long nsentdatapkt;
|
||||
};
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
* Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.29 1999/12/06 17:13:06 calle
|
||||
* Added controller watchdog.
|
||||
*
|
||||
* Revision 1.28 1999/11/05 16:22:37 calle
|
||||
* Bugfix: Missing break in switch on ISDN_CMD_HANGUP.
|
||||
*
|
||||
|
@ -438,25 +441,33 @@ static inline __u8 cip2si2(__u16 cipval)
|
|||
static inline capidrv_contr *findcontrbydriverid(int driverid)
|
||||
{
|
||||
capidrv_contr *p = global.contr_list;
|
||||
long flags;
|
||||
|
||||
save_flags(flags);
|
||||
cli();
|
||||
while (p) {
|
||||
if (p->myid == driverid)
|
||||
return p;
|
||||
break;
|
||||
p = p->next;
|
||||
}
|
||||
return (capidrv_contr *) 0;
|
||||
restore_flags(flags);
|
||||
return p;
|
||||
}
|
||||
|
||||
static capidrv_contr *findcontrbynumber(__u32 contr)
|
||||
{
|
||||
capidrv_contr *p = global.contr_list;
|
||||
long flags;
|
||||
|
||||
save_flags(flags);
|
||||
cli();
|
||||
while (p) {
|
||||
if (p->contrnr == contr)
|
||||
return p;
|
||||
break;
|
||||
p = p->next;
|
||||
}
|
||||
return (capidrv_contr *) 0;
|
||||
restore_flags(flags);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1499,7 +1510,7 @@ static void handle_data(_cmsg * cmsg, struct sk_buff *skb)
|
|||
|
||||
static _cmsg s_cmsg;
|
||||
|
||||
static void capidrv_signal(__u16 applid, __u32 dummy)
|
||||
static void capidrv_signal(__u16 applid, void *dummy)
|
||||
{
|
||||
struct sk_buff *skb = 0;
|
||||
|
||||
|
@ -2218,14 +2229,18 @@ static void listentimerfunc(unsigned long x)
|
|||
static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
|
||||
{
|
||||
capidrv_contr *card;
|
||||
long flags;
|
||||
isdn_ctrl cmd;
|
||||
char id[20];
|
||||
int i;
|
||||
|
||||
MOD_INC_USE_COUNT;
|
||||
|
||||
sprintf(id, "capidrv-%d", contr);
|
||||
if (!(card = (capidrv_contr *) kmalloc(sizeof(capidrv_contr), GFP_ATOMIC))) {
|
||||
printk(KERN_WARNING
|
||||
"capidrv: (%s) Could not allocate contr-struct.\n", id);
|
||||
MOD_DEC_USE_COUNT;
|
||||
return -1;
|
||||
}
|
||||
memset(card, 0, sizeof(capidrv_contr));
|
||||
|
@ -2238,6 +2253,7 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
|
|||
printk(KERN_WARNING
|
||||
"capidrv: (%s) Could not allocate bchan-structs.\n", id);
|
||||
kfree(card);
|
||||
MOD_DEC_USE_COUNT;
|
||||
return -1;
|
||||
}
|
||||
card->interface.channels = profp->nbchannel;
|
||||
|
@ -2262,29 +2278,35 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
|
|||
ISDN_FEATURE_P_UNKNOWN;
|
||||
card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */
|
||||
strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
|
||||
card->next = global.contr_list;
|
||||
global.contr_list = card;
|
||||
global.ncontr++;
|
||||
|
||||
|
||||
card->q931_read = card->q931_buf;
|
||||
card->q931_write = card->q931_buf;
|
||||
card->q931_end = card->q931_buf + sizeof(card->q931_buf) - 1;
|
||||
|
||||
if (!register_isdn(&card->interface)) {
|
||||
global.contr_list = global.contr_list->next;
|
||||
printk(KERN_ERR "capidrv: Unable to register contr %s\n", id);
|
||||
kfree(card->bchans);
|
||||
kfree(card);
|
||||
MOD_DEC_USE_COUNT;
|
||||
return -1;
|
||||
}
|
||||
card->myid = card->interface.channels;
|
||||
|
||||
save_flags(flags);
|
||||
cli();
|
||||
card->next = global.contr_list;
|
||||
global.contr_list = card;
|
||||
global.ncontr++;
|
||||
restore_flags(flags);
|
||||
|
||||
memset(card->bchans, 0, sizeof(capidrv_bchan) * card->nbchan);
|
||||
for (i = 0; i < card->nbchan; i++) {
|
||||
card->bchans[i].contr = card;
|
||||
}
|
||||
|
||||
cmd.driver = card->myid;
|
||||
cmd.command = ISDN_STAT_RUN;
|
||||
cmd.driver = card->myid;
|
||||
card->interface.statcallb(&cmd);
|
||||
|
||||
card->cipmask = 0x1FFF03FF; /* any */
|
||||
|
@ -2308,30 +2330,41 @@ static int capidrv_delcontr(__u16 contr)
|
|||
{
|
||||
capidrv_contr **pp, *card;
|
||||
isdn_ctrl cmd;
|
||||
long flags;
|
||||
int i;
|
||||
|
||||
save_flags(flags);
|
||||
cli();
|
||||
for (pp = &global.contr_list; *pp; pp = &(*pp)->next) {
|
||||
if ((*pp)->contrnr == contr)
|
||||
break;
|
||||
}
|
||||
if (!*pp) {
|
||||
restore_flags(flags);
|
||||
printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr);
|
||||
return -1;
|
||||
}
|
||||
card = *pp;
|
||||
*pp = (*pp)->next;
|
||||
global.ncontr--;
|
||||
restore_flags(flags);
|
||||
|
||||
if (debugmode)
|
||||
printk(KERN_DEBUG "capidrv-%d: id=%d unloading\n",
|
||||
card->contrnr, card->myid);
|
||||
|
||||
cmd.command = ISDN_STAT_UNLOAD;
|
||||
cmd.command = ISDN_STAT_STOP;
|
||||
cmd.driver = card->myid;
|
||||
card->interface.statcallb(&cmd);
|
||||
|
||||
*pp = (*pp)->next;
|
||||
global.ncontr--;
|
||||
|
||||
for (i = 0; i < card->nbchan; i++) {
|
||||
|
||||
cmd.command = ISDN_STAT_DISCH;
|
||||
cmd.driver = card->myid;
|
||||
cmd.arg = i;
|
||||
cmd.parm.num[0] = 0;
|
||||
card->interface.statcallb(&cmd);
|
||||
|
||||
if (card->bchans[i].nccip)
|
||||
free_ncci(card, card->bchans[i].nccip);
|
||||
if (card->bchans[i].plcip)
|
||||
|
@ -2342,10 +2375,16 @@ static int capidrv_delcontr(__u16 contr)
|
|||
kfree(card->bchans);
|
||||
del_timer(&card->listentimer);
|
||||
|
||||
printk(KERN_INFO "%s: now down.\n", card->name);
|
||||
cmd.command = ISDN_STAT_UNLOAD;
|
||||
cmd.driver = card->myid;
|
||||
card->interface.statcallb(&cmd);
|
||||
|
||||
kfree(card);
|
||||
|
||||
printk(KERN_INFO "%s: now down.\n", card->name);
|
||||
|
||||
MOD_DEC_USE_COUNT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2442,10 +2481,14 @@ int capidrv_init(void)
|
|||
__u32 ncontr, contr;
|
||||
__u16 errcode;
|
||||
|
||||
MOD_INC_USE_COUNT;
|
||||
|
||||
capifuncs = attach_capi_interface(&cuser);
|
||||
|
||||
if (!capifuncs)
|
||||
if (!capifuncs) {
|
||||
MOD_DEC_USE_COUNT;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if ((p = strchr(revision, ':'))) {
|
||||
strcpy(rev, p + 1);
|
||||
|
@ -2460,6 +2503,7 @@ int capidrv_init(void)
|
|||
errcode = (*capifuncs->capi_register) (&rparam, &global.appid);
|
||||
if (errcode) {
|
||||
detach_capi_interface(&cuser);
|
||||
MOD_DEC_USE_COUNT;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
@ -2467,6 +2511,7 @@ int capidrv_init(void)
|
|||
if (errcode != CAPI_NOERROR) {
|
||||
(void) (*capifuncs->capi_release) (global.appid);
|
||||
detach_capi_interface(&cuser);
|
||||
MOD_DEC_USE_COUNT;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
@ -2481,6 +2526,9 @@ int capidrv_init(void)
|
|||
}
|
||||
proc_init();
|
||||
|
||||
printk(KERN_NOTICE "capidrv: Rev%s: loaded\n", rev);
|
||||
MOD_DEC_USE_COUNT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2488,6 +2536,7 @@ int capidrv_init(void)
|
|||
void cleanup_module(void)
|
||||
{
|
||||
capidrv_contr *card, *next;
|
||||
long flags;
|
||||
char rev[10];
|
||||
char *p;
|
||||
|
||||
|
@ -2502,8 +2551,15 @@ void cleanup_module(void)
|
|||
for (card = global.contr_list; card; card = next) {
|
||||
next = card->next;
|
||||
disable_dchannel_trace(card);
|
||||
}
|
||||
|
||||
save_flags(flags);
|
||||
cli();
|
||||
for (card = global.contr_list; card; card = next) {
|
||||
next = card->next;
|
||||
capidrv_delcontr(card->contrnr);
|
||||
}
|
||||
restore_flags(flags);
|
||||
|
||||
(void) (*capifuncs->capi_release) (global.appid);
|
||||
detach_capi_interface(&cuser);
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
* Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de)
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.10 1999/08/31 11:19:54 paul
|
||||
* various spelling corrections (new checksums may be needed, Karsten!)
|
||||
*
|
||||
* Revision 1.9 1999/07/09 15:05:46 keil
|
||||
* compat.h is now isdn_compat.h
|
||||
*
|
||||
|
@ -792,7 +795,7 @@ static char *pnames[] =
|
|||
/*15 */ "Class",
|
||||
/*16 */ "ConnectedNumber",
|
||||
/*17 */ "ConnectedSubaddress",
|
||||
/*18 */ "Data",
|
||||
/*18 */ "Data32",
|
||||
/*19 */ "DataHandle",
|
||||
/*1a */ "DataLength",
|
||||
/*1b */ "FacilityConfirmationParameter",
|
||||
|
@ -890,13 +893,7 @@ static void protocol_message_2_pars(_cmsg * cmsg, int level)
|
|||
cmsg->l += 2;
|
||||
break;
|
||||
case _CDWORD:
|
||||
if (strcmp(NAME, "Data") == 0) {
|
||||
bufprint("%-*s = ", slen, NAME);
|
||||
printstructlen((__u8 *) * (__u32 *) (cmsg->m + cmsg->l),
|
||||
*(__u16 *) (cmsg->m + cmsg->l + sizeof(__u32)));
|
||||
bufprint("\n");
|
||||
} else
|
||||
bufprint("%-*s = 0x%lx\n", slen, NAME, *(__u32 *) (cmsg->m + cmsg->l));
|
||||
bufprint("%-*s = 0x%lx\n", slen, NAME, *(__u32 *) (cmsg->m + cmsg->l));
|
||||
cmsg->l += 4;
|
||||
break;
|
||||
case _CSTRUCT:
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
* Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de)
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.4 1999/09/15 08:16:03 calle
|
||||
* Implementation of 64Bit extention complete.
|
||||
*
|
||||
* Revision 1.3 1999/09/07 09:02:53 calle
|
||||
* SETDATA removed. Now inside the kernel the datapart of DATA_B3_REQ and
|
||||
* DATA_B3_IND is always directly after the CAPI message. The "Data" member
|
||||
|
@ -33,28 +36,47 @@
|
|||
|
||||
#include <asm/types.h>
|
||||
|
||||
#define CAPIMSG_LEN(m) (m[0] | (m[1] << 8))
|
||||
#define CAPIMSG_APPID(m) (m[2] | (m[3] << 8))
|
||||
#define CAPIMSG_COMMAND(m) (m[4])
|
||||
#define CAPIMSG_SUBCOMMAND(m) (m[5])
|
||||
#define CAPIMSG_MSGID(m) (m[6] | (m[7] << 8))
|
||||
#define CAPIMSG_BASELEN 8
|
||||
#define CAPIMSG_U8(m, off) (m[off])
|
||||
#define CAPIMSG_U16(m, off) (m[off]|(m[(off)+1]<<8))
|
||||
#define CAPIMSG_U32(m, off) (m[off]|(m[(off)+1]<<8)|(m[(off)+2]<<16)|(m[(off)+3]<<24))
|
||||
#define CAPIMSG_LEN(m) CAPIMSG_U16(m,0)
|
||||
#define CAPIMSG_APPID(m) CAPIMSG_U16(m,2)
|
||||
#define CAPIMSG_COMMAND(m) CAPIMSG_U8(m,4)
|
||||
#define CAPIMSG_SUBCOMMAND(m) CAPIMSG_U8(m,5)
|
||||
#define CAPIMSG_CMD(m) (((m[4])<<8)|(m[5]))
|
||||
#define CAPIMSG_MSGID(m) CAPIMSG_U16(m,6)
|
||||
#define CAPIMSG_CONTROLLER(m) (m[8] & 0x7f)
|
||||
#define CAPIMSG_CONTROL(m) (m[8]|(m[9]<<8)|(m[10]<<16)|(m[11]<<24))
|
||||
#define CAPIMSG_CONTROL(m) CAPIMSG_U32(m, 8)
|
||||
#define CAPIMSG_NCCI(m) CAPIMSG_CONTROL(m)
|
||||
#define CAPIMSG_DATA(m) (m[12]|(m[13]<<8)|(m[14]<<16)|(m[15]<<24))
|
||||
#define CAPIMSG_DATALEN(m) (m[16] | (m[17]<<8))
|
||||
#define CAPIMSG_DATALEN(m) CAPIMSG_U16(m,16) /* DATA_B3_REQ */
|
||||
|
||||
#define CAPIMSG_SETAPPID(m, applid) \
|
||||
do { \
|
||||
((__u8 *)m)[2] = (__u16)(applid) & 0xff; \
|
||||
((__u8 *)m)[3] = ((__u16)(applid) >> 8) & 0xff; \
|
||||
} while (0)
|
||||
static inline void capimsg_setu8(void *m, int off, __u8 val)
|
||||
{
|
||||
((__u8 *)m)[off] = val;
|
||||
}
|
||||
|
||||
#define CAPIMSG_SETLEN(m, len) \
|
||||
do { \
|
||||
((__u8 *)m)[0] = (__u16)(len) & 0xff; \
|
||||
((__u8 *)m)[1] = ((__u16)(len) >> 8) & 0xff; \
|
||||
} while (0)
|
||||
static inline void capimsg_setu16(void *m, int off, __u16 val)
|
||||
{
|
||||
((__u8 *)m)[off] = val & 0xff;
|
||||
((__u8 *)m)[off+1] = (val >> 8) & 0xff;
|
||||
}
|
||||
|
||||
static inline void capimsg_setu32(void *m, int off, __u32 val)
|
||||
{
|
||||
((__u8 *)m)[off] = val & 0xff;
|
||||
((__u8 *)m)[off+1] = (val >> 8) & 0xff;
|
||||
((__u8 *)m)[off+2] = (val >> 16) & 0xff;
|
||||
((__u8 *)m)[off+3] = (val >> 24) & 0xff;
|
||||
}
|
||||
|
||||
#define CAPIMSG_SETLEN(m, len) capimsg_setu16(m, 0, len)
|
||||
#define CAPIMSG_SETAPPID(m, applid) capimsg_setu16(m, 2, applid)
|
||||
#define CAPIMSG_SETCOMMAND(m,cmd) capimsg_setu8(m, 4, cmd)
|
||||
#define CAPIMSG_SETSUBCOMMAND(m, cmd) capimsg_setu8(m, 5, cmd)
|
||||
#define CAPIMSG_SETMSGID(m, msgid) capimsg_setu16(m, 6, msgid)
|
||||
#define CAPIMSG_SETCONTROL(m, contr) capimsg_setu32(m, 8, contr)
|
||||
#define CAPIMSG_SETDATALEN(m, len) capimsg_setu16(m, 16, len)
|
||||
|
||||
/*----- basic-type definitions -----*/
|
||||
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.12 2000/01/28 16:45:39 calle
|
||||
* new manufacturer command KCAPI_CMD_ADDCARD (generic addcard),
|
||||
* will search named driver and call the add_card function if one exist.
|
||||
*
|
||||
* Revision 1.11 1999/11/23 13:29:29 calle
|
||||
* Bugfix: incoming capi message were never traced.
|
||||
*
|
||||
|
@ -74,6 +78,7 @@
|
|||
#include <linux/tqueue.h>
|
||||
#include <linux/capi.h>
|
||||
#include <linux/kernelcapi.h>
|
||||
#include <linux/locks.h>
|
||||
#include <linux/isdn_compat.h>
|
||||
#ifdef COMPAT_NEED_UACCESS
|
||||
#include <asm/uaccess.h>
|
||||
|
@ -124,8 +129,8 @@ struct capi_appl {
|
|||
__u16 applid;
|
||||
capi_register_params rparam;
|
||||
int releasing;
|
||||
__u32 param;
|
||||
void (*signal) (__u16 applid, __u32 param);
|
||||
void *param;
|
||||
void (*signal) (__u16 applid, void *param);
|
||||
struct sk_buff_head recv_queue;
|
||||
int nncci;
|
||||
struct capi_ncci *nccilist;
|
||||
|
@ -136,6 +141,14 @@ struct capi_appl {
|
|||
unsigned long nsentdatapkt;
|
||||
};
|
||||
|
||||
struct capi_notifier {
|
||||
struct capi_notifier *next;
|
||||
unsigned int cmd;
|
||||
__u32 controller;
|
||||
__u16 applid;
|
||||
__u32 ncci;
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
||||
static struct capi_version driver_version = {2, 0, 1, 1<<4};
|
||||
|
@ -159,9 +172,9 @@ static struct capi_ctr cards[CAPI_MAXCONTR];
|
|||
static int ncards = 0;
|
||||
static struct sk_buff_head recv_queue;
|
||||
static struct capi_interface_user *capi_users = 0;
|
||||
static spinlock_t capi_users_lock = SPIN_LOCK_UNLOCKED;
|
||||
static struct capi_driver *drivers;
|
||||
static long notify_up_set = 0;
|
||||
static long notify_down_set = 0;
|
||||
static spinlock_t drivers_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
static struct tq_struct tq_state_notify;
|
||||
static struct tq_struct tq_recv_notify;
|
||||
|
@ -303,6 +316,7 @@ static int proc_driver_read_proc(char *page, char **start, off_t off,
|
|||
int len = 0;
|
||||
off_t begin = 0;
|
||||
|
||||
spin_lock(&drivers_lock);
|
||||
for (driver = drivers; driver; driver = driver->next) {
|
||||
len += sprintf(page+len, "%-32s %d %s\n",
|
||||
driver->name,
|
||||
|
@ -316,6 +330,7 @@ static int proc_driver_read_proc(char *page, char **start, off_t off,
|
|||
}
|
||||
}
|
||||
endloop:
|
||||
spin_unlock(&drivers_lock);
|
||||
if (!driver)
|
||||
*eof = 1;
|
||||
if (off >= len+begin)
|
||||
|
@ -335,6 +350,7 @@ static int proc_users_read_proc(char *page, char **start, off_t off,
|
|||
int len = 0;
|
||||
off_t begin = 0;
|
||||
|
||||
spin_lock(&capi_users_lock);
|
||||
for (cp = capi_users; cp ; cp = cp->next) {
|
||||
len += sprintf(page+len, "%s\n", cp->name);
|
||||
if (len+begin > off+count)
|
||||
|
@ -345,6 +361,7 @@ static int proc_users_read_proc(char *page, char **start, off_t off,
|
|||
}
|
||||
}
|
||||
endloop:
|
||||
spin_unlock(&capi_users_lock);
|
||||
if (cp == 0)
|
||||
*eof = 1;
|
||||
if (off >= len+begin)
|
||||
|
@ -509,6 +526,161 @@ static void proc_capi_exit(void)
|
|||
}
|
||||
}
|
||||
|
||||
/* -------- Notifier handling --------------------------------- */
|
||||
|
||||
static struct capi_notifier_list{
|
||||
struct capi_notifier *head;
|
||||
struct capi_notifier *tail;
|
||||
} notifier_list;
|
||||
|
||||
static inline void notify_enqueue(struct capi_notifier *np)
|
||||
{
|
||||
struct capi_notifier_list *q = ¬ifier_list;
|
||||
unsigned long flags;
|
||||
|
||||
save_flags(flags);
|
||||
cli();
|
||||
if (q->tail) {
|
||||
q->tail->next = np;
|
||||
q->tail = np;
|
||||
} else {
|
||||
q->head = q->tail = np;
|
||||
}
|
||||
restore_flags(flags);
|
||||
}
|
||||
|
||||
static inline struct capi_notifier *notify_dequeue(void)
|
||||
{
|
||||
struct capi_notifier_list *q = ¬ifier_list;
|
||||
struct capi_notifier *np = 0;
|
||||
unsigned long flags;
|
||||
|
||||
save_flags(flags);
|
||||
cli();
|
||||
if (q->head) {
|
||||
np = q->head;
|
||||
if ((q->head = np->next) == 0)
|
||||
q->tail = 0;
|
||||
np->next = 0;
|
||||
}
|
||||
restore_flags(flags);
|
||||
return np;
|
||||
}
|
||||
|
||||
static int notify_push(unsigned int cmd, __u32 controller,
|
||||
__u16 applid, __u32 ncci)
|
||||
{
|
||||
struct capi_notifier *np;
|
||||
|
||||
np = (struct capi_notifier *)kmalloc(sizeof(struct capi_notifier), GFP_ATOMIC);
|
||||
if (!np)
|
||||
return -1;
|
||||
memset(np, 0, sizeof(struct capi_notifier));
|
||||
np->cmd = cmd;
|
||||
np->controller = controller;
|
||||
np->applid = applid;
|
||||
np->ncci = ncci;
|
||||
notify_enqueue(np);
|
||||
MOD_INC_USE_COUNT;
|
||||
queue_task(&tq_state_notify, &tq_immediate);
|
||||
mark_bh(IMMEDIATE_BH);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------- KCI_CONTRUP --------------------------------------- */
|
||||
|
||||
static void notify_up(__u32 contr)
|
||||
{
|
||||
struct capi_interface_user *p;
|
||||
|
||||
printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr);
|
||||
spin_lock(&capi_users_lock);
|
||||
for (p = capi_users; p; p = p->next) {
|
||||
if (!p->callback) continue;
|
||||
(*p->callback) (KCI_CONTRUP, contr, &CARD(contr)->profile);
|
||||
}
|
||||
spin_unlock(&capi_users_lock);
|
||||
}
|
||||
|
||||
/* -------- KCI_CONTRDOWN ------------------------------------- */
|
||||
|
||||
static void notify_down(__u32 contr)
|
||||
{
|
||||
struct capi_interface_user *p;
|
||||
printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr);
|
||||
spin_lock(&capi_users_lock);
|
||||
for (p = capi_users; p; p = p->next) {
|
||||
if (!p->callback) continue;
|
||||
(*p->callback) (KCI_CONTRDOWN, contr, 0);
|
||||
}
|
||||
spin_unlock(&capi_users_lock);
|
||||
}
|
||||
|
||||
/* -------- KCI_NCCIUP ---------------------------------------- */
|
||||
|
||||
static void notify_ncciup(__u32 contr, __u16 applid, __u32 ncci)
|
||||
{
|
||||
struct capi_interface_user *p;
|
||||
struct capi_ncciinfo n;
|
||||
n.applid = applid;
|
||||
n.ncci = ncci;
|
||||
/*printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr);*/
|
||||
spin_lock(&capi_users_lock);
|
||||
for (p = capi_users; p; p = p->next) {
|
||||
if (!p->callback) continue;
|
||||
(*p->callback) (KCI_NCCIUP, contr, &n);
|
||||
}
|
||||
spin_unlock(&capi_users_lock);
|
||||
};
|
||||
|
||||
/* -------- KCI_NCCIDOWN -------------------------------------- */
|
||||
|
||||
static void notify_nccidown(__u32 contr, __u16 applid, __u32 ncci)
|
||||
{
|
||||
struct capi_interface_user *p;
|
||||
struct capi_ncciinfo n;
|
||||
n.applid = applid;
|
||||
n.ncci = ncci;
|
||||
/*printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr);*/
|
||||
spin_lock(&capi_users_lock);
|
||||
for (p = capi_users; p; p = p->next) {
|
||||
if (!p->callback) continue;
|
||||
(*p->callback) (KCI_NCCIDOWN, contr, &n);
|
||||
}
|
||||
spin_unlock(&capi_users_lock);
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
static void inline notify_doit(struct capi_notifier *np)
|
||||
{
|
||||
switch (np->cmd) {
|
||||
case KCI_CONTRUP:
|
||||
notify_up(np->controller);
|
||||
break;
|
||||
case KCI_CONTRDOWN:
|
||||
notify_down(np->controller);
|
||||
break;
|
||||
case KCI_NCCIUP:
|
||||
notify_ncciup(np->controller, np->applid, np->ncci);
|
||||
break;
|
||||
case KCI_NCCIDOWN:
|
||||
notify_nccidown(np->controller, np->applid, np->ncci);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void notify_handler(void *dummy)
|
||||
{
|
||||
struct capi_notifier *np;
|
||||
|
||||
while ((np = notify_dequeue()) != 0) {
|
||||
notify_doit(np);
|
||||
kfree(np);
|
||||
MOD_DEC_USE_COUNT;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------- NCCI Handling ------------------------------------- */
|
||||
|
||||
static inline void mq_init(struct capi_ncci * np)
|
||||
|
@ -616,6 +788,7 @@ static void controllercb_new_ncci(struct capi_ctr * card,
|
|||
APPL(appl)->nncci++;
|
||||
printk(KERN_INFO "kcapi: appl %d ncci 0x%x up\n", appl, ncci);
|
||||
|
||||
notify_push(KCI_NCCIUP, CARDNR(card), appl, ncci);
|
||||
}
|
||||
|
||||
static void controllercb_free_ncci(struct capi_ctr * card,
|
||||
|
@ -633,6 +806,7 @@ static void controllercb_free_ncci(struct capi_ctr * card,
|
|||
kfree(np);
|
||||
APPL(appl)->nncci--;
|
||||
printk(KERN_INFO "kcapi: appl %d ncci 0x%x down\n", appl, ncci);
|
||||
notify_push(KCI_NCCIDOWN, CARDNR(card), appl, ncci);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -733,42 +907,6 @@ error:
|
|||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
/* -------- Notifier ------------------------------------------ */
|
||||
|
||||
static void notify_up(__u32 contr)
|
||||
{
|
||||
struct capi_interface_user *p;
|
||||
|
||||
printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr);
|
||||
for (p = capi_users; p; p = p->next) {
|
||||
if (!p->callback) continue;
|
||||
(*p->callback) (KCI_CONTRUP, contr, &CARD(contr)->profile);
|
||||
}
|
||||
}
|
||||
|
||||
static void notify_down(__u32 contr)
|
||||
{
|
||||
struct capi_interface_user *p;
|
||||
printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr);
|
||||
for (p = capi_users; p; p = p->next) {
|
||||
if (!p->callback) continue;
|
||||
(*p->callback) (KCI_CONTRDOWN, contr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void notify_handler(void *dummy)
|
||||
{
|
||||
__u32 contr;
|
||||
|
||||
for (contr=1; VALID_CARD(contr); contr++)
|
||||
if (test_and_clear_bit(contr, ¬ify_up_set))
|
||||
notify_up(contr);
|
||||
for (contr=1; VALID_CARD(contr); contr++)
|
||||
if (test_and_clear_bit(contr, ¬ify_down_set))
|
||||
notify_down(contr);
|
||||
}
|
||||
|
||||
|
||||
static void controllercb_ready(struct capi_ctr * card)
|
||||
{
|
||||
__u16 appl;
|
||||
|
@ -781,11 +919,10 @@ static void controllercb_ready(struct capi_ctr * card)
|
|||
card->driver->register_appl(card, appl, &APPL(appl)->rparam);
|
||||
}
|
||||
|
||||
set_bit(CARDNR(card), ¬ify_up_set);
|
||||
queue_task(&tq_state_notify, &tq_scheduler);
|
||||
|
||||
printk(KERN_NOTICE "kcapi: card %d \"%s\" ready.\n",
|
||||
CARDNR(card), card->name);
|
||||
|
||||
notify_push(KCI_CONTRUP, CARDNR(card), 0, 0);
|
||||
}
|
||||
|
||||
static void controllercb_reseted(struct capi_ctr * card)
|
||||
|
@ -811,6 +948,7 @@ static void controllercb_reseted(struct capi_ctr * card)
|
|||
struct capi_ncci *np = *pp;
|
||||
*pp = np->next;
|
||||
printk(KERN_INFO "kcapi: appl %d ncci 0x%x forced down!\n", appl, np->ncci);
|
||||
notify_push(KCI_NCCIDOWN, CARDNR(card), appl, np->ncci);
|
||||
kfree(np);
|
||||
nextpp = pp;
|
||||
} else {
|
||||
|
@ -818,9 +956,10 @@ static void controllercb_reseted(struct capi_ctr * card)
|
|||
}
|
||||
}
|
||||
}
|
||||
set_bit(CARDNR(card), ¬ify_down_set);
|
||||
queue_task(&tq_state_notify, &tq_scheduler);
|
||||
|
||||
printk(KERN_NOTICE "kcapi: card %d down.\n", CARDNR(card));
|
||||
|
||||
notify_push(KCI_CONTRDOWN, CARDNR(card), 0, 0);
|
||||
}
|
||||
|
||||
static void controllercb_suspend_output(struct capi_ctr *card)
|
||||
|
@ -951,9 +1090,12 @@ struct capi_driver_interface *attach_capi_driver(struct capi_driver *driver)
|
|||
{
|
||||
struct capi_driver **pp;
|
||||
|
||||
MOD_INC_USE_COUNT;
|
||||
spin_lock(&drivers_lock);
|
||||
for (pp = &drivers; *pp; pp = &(*pp)->next) ;
|
||||
driver->next = 0;
|
||||
*pp = driver;
|
||||
spin_unlock(&drivers_lock);
|
||||
printk(KERN_NOTICE "kcapi: driver %s attached\n", driver->name);
|
||||
sprintf(driver->procfn, "capi/drivers/%s", driver->name);
|
||||
driver->procent = create_proc_entry(driver->procfn, 0, 0);
|
||||
|
@ -973,6 +1115,7 @@ struct capi_driver_interface *attach_capi_driver(struct capi_driver *driver)
|
|||
void detach_capi_driver(struct capi_driver *driver)
|
||||
{
|
||||
struct capi_driver **pp;
|
||||
spin_lock(&drivers_lock);
|
||||
for (pp = &drivers; *pp && *pp != driver; pp = &(*pp)->next) ;
|
||||
if (*pp) {
|
||||
*pp = (*pp)->next;
|
||||
|
@ -980,10 +1123,12 @@ void detach_capi_driver(struct capi_driver *driver)
|
|||
} else {
|
||||
printk(KERN_ERR "kcapi: driver %s double detach ?\n", driver->name);
|
||||
}
|
||||
spin_unlock(&drivers_lock);
|
||||
if (driver->procent) {
|
||||
remove_proc_entry(driver->procfn, 0);
|
||||
driver->procent = 0;
|
||||
}
|
||||
MOD_DEC_USE_COUNT;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
@ -1040,6 +1185,7 @@ static __u16 capi_release(__u16 applid)
|
|||
|
||||
if (!VALID_APPLID(applid) || APPL(applid)->releasing)
|
||||
return CAPI_ILLAPPNR;
|
||||
APPL(applid)->releasing++;
|
||||
while ((skb = skb_dequeue(&APPL(applid)->recv_queue)) != 0)
|
||||
kfree_skb(skb);
|
||||
for (i = 0; i < CAPI_MAXCONTR; i++) {
|
||||
|
@ -1048,6 +1194,7 @@ static __u16 capi_release(__u16 applid)
|
|||
APPL(applid)->releasing++;
|
||||
cards[i].driver->release_appl(&cards[i], applid);
|
||||
}
|
||||
APPL(applid)->releasing--;
|
||||
if (APPL(applid)->releasing <= 0) {
|
||||
APPL(applid)->signal = 0;
|
||||
APPL_MARK_FREE(applid);
|
||||
|
@ -1127,8 +1274,8 @@ static __u16 capi_get_message(__u16 applid, struct sk_buff **msgp)
|
|||
}
|
||||
|
||||
static __u16 capi_set_signal(__u16 applid,
|
||||
void (*signal) (__u16 applid, __u32 param),
|
||||
__u32 param)
|
||||
void (*signal) (__u16 applid, void *param),
|
||||
void *param)
|
||||
{
|
||||
if (!VALID_APPLID(applid))
|
||||
return CAPI_ILLAPPNR;
|
||||
|
@ -1193,10 +1340,12 @@ static __u16 capi_get_profile(__u32 contr, struct capi_profile *profp)
|
|||
static struct capi_driver *find_driver(char *name)
|
||||
{
|
||||
struct capi_driver *dp;
|
||||
spin_lock(&drivers_lock);
|
||||
for (dp = drivers; dp; dp = dp->next)
|
||||
if (strcmp(dp->name, name) == 0)
|
||||
return dp;
|
||||
return 0;
|
||||
break;
|
||||
spin_unlock(&drivers_lock);
|
||||
return dp;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_AVMB1_COMPAT
|
||||
|
@ -1271,6 +1420,10 @@ static int old_capi_manufacturer(unsigned int cmd, void *data)
|
|||
card = CARD(ldef.contr);
|
||||
if (card->cardstate == CARD_FREE)
|
||||
return -ESRCH;
|
||||
if (card->driver->load_firmware == 0) {
|
||||
printk(KERN_DEBUG "kcapi: load: driver \%s\" has no load function\n", card->driver->name);
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
if (ldef.t4file.len <= 0) {
|
||||
printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len);
|
||||
|
@ -1489,16 +1642,20 @@ struct capi_interface *attach_capi_interface(struct capi_interface_user *userp)
|
|||
{
|
||||
struct capi_interface_user *p;
|
||||
|
||||
MOD_INC_USE_COUNT;
|
||||
spin_lock(&capi_users_lock);
|
||||
for (p = capi_users; p; p = p->next) {
|
||||
if (p == userp) {
|
||||
spin_unlock(&capi_users_lock);
|
||||
printk(KERN_ERR "kcapi: double attach from %s\n",
|
||||
userp->name);
|
||||
MOD_DEC_USE_COUNT;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
userp->next = capi_users;
|
||||
capi_users = userp;
|
||||
MOD_INC_USE_COUNT;
|
||||
spin_unlock(&capi_users_lock);
|
||||
printk(KERN_NOTICE "kcapi: %s attached\n", userp->name);
|
||||
|
||||
return &avmb1_interface;
|
||||
|
@ -1508,15 +1665,18 @@ int detach_capi_interface(struct capi_interface_user *userp)
|
|||
{
|
||||
struct capi_interface_user **pp;
|
||||
|
||||
spin_lock(&capi_users_lock);
|
||||
for (pp = &capi_users; *pp; pp = &(*pp)->next) {
|
||||
if (*pp == userp) {
|
||||
*pp = userp->next;
|
||||
spin_unlock(&capi_users_lock);
|
||||
userp->next = 0;
|
||||
MOD_DEC_USE_COUNT;
|
||||
printk(KERN_NOTICE "kcapi: %s detached\n", userp->name);
|
||||
MOD_DEC_USE_COUNT;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
spin_unlock(&capi_users_lock);
|
||||
printk(KERN_ERR "kcapi: double detach from %s\n", userp->name);
|
||||
return -1;
|
||||
}
|
||||
|
@ -1622,7 +1782,6 @@ void cleanup_module(void)
|
|||
strcpy(rev, "1.0");
|
||||
}
|
||||
|
||||
schedule(); /* execute queued tasks .... */
|
||||
proc_capi_exit();
|
||||
printk(KERN_NOTICE "CAPI-driver Rev%s: unloaded\n", rev);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
* Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.1 1997/03/04 21:27:33 calle
|
||||
* First version in isdn4linux
|
||||
*
|
||||
* Revision 2.2 1997/02/12 09:31:39 calle
|
||||
* new version
|
||||
*
|
||||
|
@ -105,6 +108,7 @@ typedef struct capi_manufacturer_cmd {
|
|||
*/
|
||||
#define CAPI_INSTALLED _IOR('C',0x22, __u16)
|
||||
|
||||
|
||||
/*
|
||||
* member contr is input for
|
||||
* CAPI_GET_MANUFACTURER, CAPI_VERSION, CAPI_GET_SERIAL
|
||||
|
@ -121,4 +125,16 @@ typedef union capi_ioctl_struct {
|
|||
__u16 errcode;
|
||||
} capi_ioctl_struct;
|
||||
|
||||
/*
|
||||
* Middleware extension
|
||||
*/
|
||||
|
||||
#define CAPIFLAG_HIGHJACKING 0x0001
|
||||
|
||||
#define CAPI_GET_FLAGS _IOR('C',0x23, unsigned)
|
||||
#define CAPI_SET_FLAGS _IOR('C',0x24, unsigned)
|
||||
#define CAPI_CLR_FLAGS _IOR('C',0x25, unsigned)
|
||||
|
||||
#define CAPI_NCCI_OPENCOUNT _IOR('C',0x26, unsigned)
|
||||
|
||||
#endif /* __LINUX_CAPI_H__ */
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
* (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.5 2000/01/28 16:45:40 calle
|
||||
* new manufacturer command KCAPI_CMD_ADDCARD (generic addcard),
|
||||
* will search named driver and call the add_card function if one exist.
|
||||
*
|
||||
* Revision 1.4 1999/09/10 17:24:19 calle
|
||||
* Changes for proposed standard for CAPI2.0:
|
||||
* - AK148 "Linux Exention"
|
||||
|
@ -90,8 +94,8 @@ struct capi_interface {
|
|||
__u16 (*capi_put_message) (__u16 applid, struct sk_buff * msg);
|
||||
__u16 (*capi_get_message) (__u16 applid, struct sk_buff ** msgp);
|
||||
__u16 (*capi_set_signal) (__u16 applid,
|
||||
void (*signal) (__u16 applid, __u32 param),
|
||||
__u32 param);
|
||||
void (*signal) (__u16 applid, void *param),
|
||||
void *param);
|
||||
__u16 (*capi_get_manufacturer) (__u32 contr, __u8 buf[CAPI_MANUFACTURER_LEN]);
|
||||
__u16 (*capi_get_version) (__u32 contr, struct capi_version * verp);
|
||||
__u16(*capi_get_serial) (__u32 contr, __u8 serial[CAPI_SERIAL_LEN]);
|
||||
|
@ -104,8 +108,15 @@ struct capi_interface {
|
|||
|
||||
};
|
||||
|
||||
#define KCI_CONTRUP 0
|
||||
#define KCI_CONTRDOWN 1
|
||||
struct capi_ncciinfo {
|
||||
__u16 applid;
|
||||
__u32 ncci;
|
||||
};
|
||||
|
||||
#define KCI_CONTRUP 0 /* struct capi_profile */
|
||||
#define KCI_CONTRDOWN 1 /* NULL */
|
||||
#define KCI_NCCIUP 2 /* struct capi_ncciinfo */
|
||||
#define KCI_NCCIDOWN 3 /* struct capi_ncciinfo */
|
||||
|
||||
struct capi_interface_user {
|
||||
char name[20];
|
||||
|
@ -144,6 +155,7 @@ int detach_capi_interface(struct capi_interface_user *);
|
|||
#define CAPI_MSGCTRLERNOTSUPPORTEXTEQUIP 0x110a
|
||||
#define CAPI_MSGCTRLERONLYSUPPORTEXTEQUIP 0x110b
|
||||
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* __KERNELCAPI_H__ */
|
||||
|
|
|
@ -23,6 +23,10 @@
|
|||
#undef COMPAT_HAS_ISA_IOREMAP
|
||||
#define net_device device
|
||||
#define set_current_state(sta) current->state = sta
|
||||
#undef COMPAT_HAS_kmem_cache
|
||||
#undef COMPAT_d_alloc_root_one_parameter
|
||||
#undef COMPAT_HAS_init_special_inode
|
||||
#define THIS_MODULE &__this_module
|
||||
|
||||
#undef CONFIG_ISDN_WITH_ABC
|
||||
#undef CONFIG_ISDN_WITH_ABC_CALLB
|
||||
|
|
|
@ -24,6 +24,11 @@
|
|||
#define net_device device
|
||||
#define set_current_state(sta) current->state = sta
|
||||
#undef COMPAT_HAS_pci_find_subsys
|
||||
#undef COMPAT_HAS_kmem_cache
|
||||
#undef COMPAT_d_alloc_root_one_parameter
|
||||
#undef COMPAT_HAS_init_special_inode
|
||||
#define THIS_MODULE &__this_module
|
||||
|
||||
#define ISDN_TTY_FCLASS1
|
||||
#undef CONFIG_ISDN_WITH_ABC
|
||||
#undef CONFIG_ISDN_WITH_ABC_CALLB
|
||||
|
|
Loading…
Reference in New Issue