- 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:
Carsten Paeth 2000-03-03 15:50:42 +00:00
parent 58a0fcec05
commit 7fe092d9a5
13 changed files with 887 additions and 301 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
};

View File

@ -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);

View File

@ -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:

View File

@ -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 -----*/

View File

@ -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 = &notifier_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 = &notifier_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, &notify_up_set))
notify_up(contr);
for (contr=1; VALID_CARD(contr); contr++)
if (test_and_clear_bit(contr, &notify_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), &notify_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), &notify_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);
}

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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

View File

@ -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

View File

@ -21,6 +21,9 @@
#define COMPAT_HAS_NEW_SETUP
#define COMPAT_HAS_ISA_IOREMAP
#define COMPAT_HAS_pci_find_subsys
#define COMPAT_HAS_kmem_cache
#define COMPAT_d_alloc_root_one_parameter
#define COMPAT_HAS_init_special_inode
#define ISDN_TTY_FCLASS1
#undef CONFIG_ISDN_WITH_ABC