!C99Shell v. 1.0 pre-release build #13!

Software: Apache/2.0.54 (Unix) mod_perl/1.99_09 Perl/v5.8.0 mod_ssl/2.0.54 OpenSSL/0.9.7l DAV/2 FrontPage/5.0.2.2635 PHP/4.4.0 mod_gzip/2.0.26.1a 

uname -a: Linux snow.he.net 4.4.276-v2-mono-1 #1 SMP Wed Jul 21 11:21:17 PDT 2021 i686 

uid=99(nobody) gid=98(nobody) groups=98(nobody) 

Safe-mode: OFF (not secure)

/usr/src/linux-2.4.18-xfs-1.1/drivers/isdn/avmb1/   drwxr-xr-x
Free 318.31 GB of 458.09 GB (69.49%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     kcapi.c (40.51 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/* $Id: kcapi.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
 * 
 * Kernel CAPI 2.0 Module
 * 
 * Copyright 1999 by Carsten Paeth <calle@calle.de>
 * 
 * This software may be used and distributed according to the terms
 * of the GNU General Public License, incorporated herein by reference.
 *
 */

#define CONFIG_AVMB1_COMPAT

#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <asm/segment.h>
#include <linux/proc_fs.h>
#include <linux/skbuff.h>
#include <linux/tqueue.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
#include <linux/locks.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include "capicmd.h"
#include "capiutil.h"
#include "capilli.h"
#ifdef CONFIG_AVMB1_COMPAT
#include <linux/b1lli.h>
#endif

static char *revision = "$Revision: 1.1.4.1 $";

/* ------------------------------------------------------------- */

#define CARD_FREE    0
#define CARD_DETECTED    1
#define CARD_LOADING    2
#define CARD_RUNNING    3

/* ------------------------------------------------------------- */

static int showcapimsgs = 0;

MODULE_DESCRIPTION("CAPI4Linux: kernel CAPI layer");
MODULE_AUTHOR("Carsten Paeth");
MODULE_LICENSE("GPL");
MODULE_PARM(showcapimsgs, "i");

/* ------------------------------------------------------------- */

struct msgidqueue {
    struct msgidqueue *next;
    __u16 msgid;
};

struct capi_ncci {
    struct capi_ncci *next;
    __u16 applid;
    __u32 ncci;
    __u32 winsize;
    int   nmsg;
    struct msgidqueue *msgidqueue;
    struct msgidqueue *msgidlast;
    struct msgidqueue *msgidfree;
    struct msgidqueue msgidpool[CAPI_MAXDATAWINDOW];
};

struct capi_appl {
    __u16 applid;
    capi_register_params rparam;
    int releasing;
    void *param;
    void (*signal) (__u16 applid, void *param);
    struct sk_buff_head recv_queue;
    int nncci;
    struct capi_ncci *nccilist;

    unsigned long nrecvctlpkt;
    unsigned long nrecvdatapkt;
    unsigned long nsentctlpkt;
    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};
static char driver_serial[CAPI_SERIAL_LEN] = "0004711";
static char capi_manufakturer[64] = "AVM Berlin";

#define APPL(a)           (&applications[(a)-1])
#define    VALID_APPLID(a)       ((a) && (a) <= CAPI_MAXAPPL && APPL(a)->applid == a)
#define APPL_IS_FREE(a)    (APPL(a)->applid == 0)
#define APPL_MARK_FREE(a)  do{ APPL(a)->applid=0; MOD_DEC_USE_COUNT; }while(0);
#define APPL_MARK_USED(a)  do{ APPL(a)->applid=(a); MOD_INC_USE_COUNT; }while(0);

#define NCCI2CTRL(ncci)    (((ncci) >> 24) & 0x7f)

#define VALID_CARD(c)       ((c) > 0 && (c) <= CAPI_MAXCONTR)
#define CARD(c)           (&cards[(c)-1])
#define CARDNR(cp)       (((cp)-cards)+1)

static struct capi_appl applications[CAPI_MAXAPPL];
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 spinlock_t drivers_lock = SPIN_LOCK_UNLOCKED;

static struct tq_struct tq_state_notify;
static struct tq_struct tq_recv_notify;

/* -------- util functions ------------------------------------ */

static char *cardstate2str(unsigned short cardstate)
{
    switch (cardstate) {
            default:
        case CARD_FREE:        return "free";
        case CARD_DETECTED:    return "detected";
        case CARD_LOADING:    return "loading";
        case CARD_RUNNING:    return "running";
    }
}

static inline int capi_cmd_valid(__u8 cmd)
{
    switch (cmd) {
    case CAPI_ALERT:
    case CAPI_CONNECT:
    case CAPI_CONNECT_ACTIVE:
    case CAPI_CONNECT_B3_ACTIVE:
    case CAPI_CONNECT_B3:
    case CAPI_CONNECT_B3_T90_ACTIVE:
    case CAPI_DATA_B3:
    case CAPI_DISCONNECT_B3:
    case CAPI_DISCONNECT:
    case CAPI_FACILITY:
    case CAPI_INFO:
    case CAPI_LISTEN:
    case CAPI_MANUFACTURER:
    case CAPI_RESET_B3:
    case CAPI_SELECT_B_PROTOCOL:
        return 1;
    }
    return 0;
}

static inline int capi_subcmd_valid(__u8 subcmd)
{
    switch (subcmd) {
    case CAPI_REQ:
    case CAPI_CONF:
    case CAPI_IND:
    case CAPI_RESP:
        return 1;
    }
    return 0;
}

/* -------- /proc functions ----------------------------------- */
/*
 * /proc/capi/applications:
 *      applid l3cnt dblkcnt dblklen #ncci recvqueuelen
 */
static int proc_applications_read_proc(char *page, char **start, off_t off,
                                       int count, int *eof, void *data)
{
    struct capi_appl *ap;
    int i;
    int len = 0;

    for (i=0; i < CAPI_MAXAPPL; i++) {
        ap = &applications[i];
        if (ap->applid == 0) continue;
        len += sprintf(page+len, "%u %d %d %d %d %d\n",
            ap->applid,
            ap->rparam.level3cnt,
            ap->rparam.datablkcnt,
            ap->rparam.datablklen,
            ap->nncci,
                        skb_queue_len(&ap->recv_queue));
        if (len <= off) {
            off -= len;
            len = 0;
        } else {
            if (len-off > count)
                goto endloop;
        }
    }
endloop:
    *start = page+off;
    if (len < count)
        *eof = 1;
    if (len>count) len = count;
    if (len<0) len = 0;
    return len;
}

/*
 * /proc/capi/ncci:
 *    applid ncci winsize nblk
 */
static int proc_ncci_read_proc(char *page, char **start, off_t off,
                                       int count, int *eof, void *data)
{
    struct capi_appl *ap;
    struct capi_ncci *np;
    int i;
    int len = 0;

    for (i=0; i < CAPI_MAXAPPL; i++) {
        ap = &applications[i];
        if (ap->applid == 0) continue;
        for (np = ap->nccilist; np; np = np->next) {
            len += sprintf(page+len, "%d 0x%x %d %d\n",
                np->applid,
                np->ncci,
                np->winsize,
                np->nmsg);
            if (len <= off) {
                off -= len;
                len = 0;
            } else {
                if (len-off > count)
                    goto endloop;
            }
        }
    }
endloop:
    *start = page+off;
    if (len < count)
        *eof = 1;
    if (len>count) len = count;
    if (len<0) len = 0;
    return len;
}

/*
 * /proc/capi/driver:
 *    driver ncontroller
 */
static int proc_driver_read_proc(char *page, char **start, off_t off,
                                       int count, int *eof, void *data)
{
    struct capi_driver *driver;
    int len = 0;

    spin_lock(&drivers_lock);
    for (driver = drivers; driver; driver = driver->next) {
        len += sprintf(page+len, "%-32s %d %s\n",
                    driver->name,
                    driver->ncontroller,
                    driver->revision);
        if (len <= off) {
            off -= len;
            len = 0;
        } else {
            if (len-off > count)
                goto endloop;
        }
    }
endloop:
    spin_unlock(&drivers_lock);
    *start = page+off;
    if (len < count)
        *eof = 1;
    if (len>count) len = count;
    if (len<0) len = 0;
    return len;
}

/*
 * /proc/capi/users:
 *    name
 */
static int proc_users_read_proc(char *page, char **start, off_t off,
                                       int count, int *eof, void *data)
{
        struct capi_interface_user *cp;
    int len = 0;

    spin_lock(&capi_users_lock);
        for (cp = capi_users; cp ; cp = cp->next) {
        len += sprintf(page+len, "%s\n", cp->name);
        if (len <= off) {
            off -= len;
            len = 0;
        } else {
            if (len-off > count)
                goto endloop;
        }
    }
endloop:
    spin_unlock(&capi_users_lock);
    *start = page+off;
    if (len < count)
        *eof = 1;
    if (len>count) len = count;
    if (len<0) len = 0;
    return len;
}

/*
 * /proc/capi/controller:
 *    cnr driver cardstate name driverinfo
 */
static int proc_controller_read_proc(char *page, char **start, off_t off,
                                       int count, int *eof, void *data)
{
    struct capi_ctr *cp;
    int i;
    int len = 0;

    for (i=0; i < CAPI_MAXCONTR; i++) {
        cp = &cards[i];
        if (cp->cardstate == CARD_FREE) continue;
        len += sprintf(page+len, "%d %-10s %-8s %-16s %s\n",
            cp->cnr, cp->driver->name, 
            cardstate2str(cp->cardstate),
            cp->name,
            cp->driver->procinfo ?  cp->driver->procinfo(cp) : ""
            );
        if (len <= off) {
            off -= len;
            len = 0;
        } else {
            if (len-off > count)
                goto endloop;
        }
    }
endloop:
    *start = page+off;
    if (len < count)
        *eof = 1;
    if (len>count) len = count;
    if (len<0) len = 0;
    return len;
}

/*
 * /proc/capi/applstats:
 *    applid nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt
 */
static int proc_applstats_read_proc(char *page, char **start, off_t off,
                                       int count, int *eof, void *data)
{
    struct capi_appl *ap;
    int i;
    int len = 0;

    for (i=0; i < CAPI_MAXAPPL; i++) {
        ap = &applications[i];
        if (ap->applid == 0) continue;
        len += sprintf(page+len, "%u %lu %lu %lu %lu\n",
            ap->applid,
            ap->nrecvctlpkt,
            ap->nrecvdatapkt,
            ap->nsentctlpkt,
            ap->nsentdatapkt);
        if (len <= off) {
            off -= len;
            len = 0;
        } else {
            if (len-off > count)
                goto endloop;
        }
    }
endloop:
    *start = page+off;
    if (len < count)
        *eof = 1;
    if (len>count) len = count;
    if (len<0) len = 0;
    return len;
}

/*
 * /proc/capi/contrstats:
 *    cnr nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt
 */
static int proc_contrstats_read_proc(char *page, char **start, off_t off,
                                       int count, int *eof, void *data)
{
    struct capi_ctr *cp;
    int i;
    int len = 0;

    for (i=0; i < CAPI_MAXCONTR; i++) {
        cp = &cards[i];
        if (cp->cardstate == CARD_FREE) continue;
        len += sprintf(page+len, "%d %lu %lu %lu %lu\n",
            cp->cnr, 
            cp->nrecvctlpkt,
            cp->nrecvdatapkt,
            cp->nsentctlpkt,
            cp->nsentdatapkt);
        if (len <= off) {
            off -= len;
            len = 0;
        } else {
            if (len-off > count)
                goto endloop;
        }
    }
endloop:
    *start = page+off;
    if (len < count)
        *eof = 1;
    if (len>count) len = count;
    if (len<0) len = 0;
    return len;
}

static struct procfsentries {
  char *name;
  mode_t mode;
  int (*read_proc)(char *page, char **start, off_t off,
                                       int count, int *eof, void *data);
  struct proc_dir_entry *procent;
} procfsentries[] = {
   { "capi",          S_IFDIR, 0 },
   { "capi/applications", 0     , proc_applications_read_proc },
   { "capi/ncci",       0     , proc_ncci_read_proc },
   { "capi/driver",       0     , proc_driver_read_proc },
   { "capi/users",       0     , proc_users_read_proc },
   { "capi/controller",   0     , proc_controller_read_proc },
   { "capi/applstats",    0     , proc_applstats_read_proc },
   { "capi/contrstats",   0     , proc_contrstats_read_proc },
   { "capi/drivers",      S_IFDIR, 0 },
   { "capi/controllers",  S_IFDIR, 0 },
};

static void proc_capi_init(void)
{
    int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
    int i;

    for (i=0; i < nelem; i++) {
        struct procfsentries *p = procfsentries + i;
    p->procent = create_proc_entry(p->name, p->mode, 0);
    if (p->procent) p->procent->read_proc = p->read_proc;
    }
}

static void proc_capi_exit(void)
{
    int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
    int i;

    for (i=nelem-1; i >= 0; i--) {
        struct procfsentries *p = procfsentries + i;
    if (p->procent) {
       remove_proc_entry(p->name, 0);
       p->procent = 0;
    }
    }
}

/* -------- Notifier handling --------------------------------- */

static struct capi_notifier_list{
    struct capi_notifier *head;
    struct capi_notifier *tail;
} notifier_list;

static spinlock_t notifier_lock = SPIN_LOCK_UNLOCKED;

static inline void notify_enqueue(struct capi_notifier *np)
{
    struct capi_notifier_list *q = &notifier_list;
    unsigned long flags;

    spin_lock_irqsave(&notifier_lock, flags);
    if (q->tail) {
        q->tail->next = np;
        q->tail = np;
    } else {
        q->head = q->tail = np;
    }
    spin_unlock_irqrestore(&notifier_lock, flags);
}

static inline struct capi_notifier *notify_dequeue(void)
{
    struct capi_notifier_list *q = &notifier_list;
    struct capi_notifier *np = 0;
    unsigned long flags;

    spin_lock_irqsave(&notifier_lock, flags);
    if (q->head) {
        np = q->head;
        if ((q->head = np->next) == 0)
             q->tail = 0;
        np->next = 0;
    }
    spin_unlock_irqrestore(&notifier_lock, flags);
    return np;
}

static int notify_push(unsigned int cmd, __u32 controller,
                __u16 applid, __u32 ncci)
{
    struct capi_notifier *np;

    MOD_INC_USE_COUNT;
    np = (struct capi_notifier *)kmalloc(sizeof(struct capi_notifier), GFP_ATOMIC);
    if (!np) {
        MOD_DEC_USE_COUNT;
        return -1;
    }
    memset(np, 0, sizeof(struct capi_notifier));
    np->cmd = cmd;
    np->controller = controller;
    np->applid = applid;
    np->ncci = ncci;
    notify_enqueue(np);
    /*
     * The notifier will result in adding/deleteing
     * of devices. Devices can only removed in
     * user process, not in bh.
     */
    MOD_INC_USE_COUNT;
    if (schedule_task(&tq_state_notify) == 0)
        MOD_DEC_USE_COUNT;
    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;
    }
    MOD_DEC_USE_COUNT;
}
    
/* -------- NCCI Handling ------------------------------------- */

static inline void mq_init(struct capi_ncci * np)
{
    int i;
    np->msgidqueue = 0;
    np->msgidlast = 0;
    np->nmsg = 0;
    memset(np->msgidpool, 0, sizeof(np->msgidpool));
    np->msgidfree = &np->msgidpool[0];
    for (i = 1; i < np->winsize; i++) {
        np->msgidpool[i].next = np->msgidfree;
        np->msgidfree = &np->msgidpool[i];
    }
}

static inline int mq_enqueue(struct capi_ncci * np, __u16 msgid)
{
    struct msgidqueue *mq;
    if ((mq = np->msgidfree) == 0)
        return 0;
    np->msgidfree = mq->next;
    mq->msgid = msgid;
    mq->next = 0;
    if (np->msgidlast)
        np->msgidlast->next = mq;
    np->msgidlast = mq;
    if (!np->msgidqueue)
        np->msgidqueue = mq;
    np->nmsg++;
    return 1;
}

static inline int mq_dequeue(struct capi_ncci * np, __u16 msgid)
{
    struct msgidqueue **pp;
    for (pp = &np->msgidqueue; *pp; pp = &(*pp)->next) {
        if ((*pp)->msgid == msgid) {
            struct msgidqueue *mq = *pp;
            *pp = mq->next;
            if (mq == np->msgidlast)
                np->msgidlast = 0;
            mq->next = np->msgidfree;
            np->msgidfree = mq;
            np->nmsg--;
            return 1;
        }
    }
    return 0;
}

static void controllercb_appl_registered(struct capi_ctr * card, __u16 appl)
{
}

static void controllercb_appl_released(struct capi_ctr * card, __u16 appl)
{
    struct capi_ncci **pp, **nextpp;
    for (pp = &APPL(appl)->nccilist; *pp; pp = nextpp) {
        if (NCCI2CTRL((*pp)->ncci) == card->cnr) {
            struct capi_ncci *np = *pp;
            *pp = np->next;
            printk(KERN_INFO "kcapi: appl %d ncci 0x%x down!\n", appl, np->ncci);
            kfree(np);
            APPL(appl)->nncci--;
            nextpp = pp;
        } else {
            nextpp = &(*pp)->next;
        }
    }
    APPL(appl)->releasing--;
    if (APPL(appl)->releasing <= 0) {
        APPL(appl)->signal = 0;
        APPL_MARK_FREE(appl);
        printk(KERN_INFO "kcapi: appl %d down\n", appl);
    }
}
/*
 * ncci management
 */

static void controllercb_new_ncci(struct capi_ctr * card,
                    __u16 appl, __u32 ncci, __u32 winsize)
{
    struct capi_ncci *np;
    if (!VALID_APPLID(appl)) {
        printk(KERN_ERR "avmb1_handle_new_ncci: illegal appl %d\n", appl);
        return;
    }
    if ((np = (struct capi_ncci *) kmalloc(sizeof(struct capi_ncci), GFP_ATOMIC)) == 0) {
        printk(KERN_ERR "capi_new_ncci: alloc failed ncci 0x%x\n", ncci);
        return;
    }
    if (winsize > CAPI_MAXDATAWINDOW) {
        printk(KERN_ERR "capi_new_ncci: winsize %d too big, set to %d\n",
               winsize, CAPI_MAXDATAWINDOW);
        winsize = CAPI_MAXDATAWINDOW;
    }
    np->applid = appl;
    np->ncci = ncci;
    np->winsize = winsize;
    mq_init(np);
    np->next = APPL(appl)->nccilist;
    APPL(appl)->nccilist = np;
    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,
                __u16 appl, __u32 ncci)
{
    struct capi_ncci **pp;
    if (!VALID_APPLID(appl)) {
        printk(KERN_ERR "free_ncci: illegal appl %d\n", appl);
        return;
    }
    for (pp = &APPL(appl)->nccilist; *pp; pp = &(*pp)->next) {
        if ((*pp)->ncci == ncci) {
            struct capi_ncci *np = *pp;
            *pp = np->next;
            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;
        }
    }
    printk(KERN_ERR "free_ncci: ncci 0x%x not found\n", ncci);
}


static struct capi_ncci *find_ncci(struct capi_appl * app, __u32 ncci)
{
    struct capi_ncci *np;
    for (np = app->nccilist; np; np = np->next) {
        if (np->ncci == ncci)
            return np;
    }
    return 0;
}

/* -------- Receiver ------------------------------------------ */

static void recv_handler(void *dummy)
{
    struct sk_buff *skb;

    while ((skb = skb_dequeue(&recv_queue)) != 0) {
        __u16 appl = CAPIMSG_APPID(skb->data);
        struct capi_ncci *np;
        if (!VALID_APPLID(appl)) {
            printk(KERN_ERR "kcapi: recv_handler: applid %d ? (%s)\n",
                   appl, capi_message2str(skb->data));
            kfree_skb(skb);
            continue;
        }
        if (APPL(appl)->signal == 0) {
            printk(KERN_ERR "kcapi: recv_handler: applid %d has no signal function\n",
                   appl);
            kfree_skb(skb);
            continue;
        }
        if (   CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3
            && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF
                && (np = find_ncci(APPL(appl), CAPIMSG_NCCI(skb->data))) != 0
            && mq_dequeue(np, CAPIMSG_MSGID(skb->data)) == 0) {
            printk(KERN_ERR "kcapi: msgid %hu ncci 0x%x not on queue\n",
                CAPIMSG_MSGID(skb->data), np->ncci);
        }
        if (   CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3
            && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) {
            APPL(appl)->nrecvdatapkt++;
        } else {
            APPL(appl)->nrecvctlpkt++;
        }
        skb_queue_tail(&APPL(appl)->recv_queue, skb);
        (APPL(appl)->signal) (APPL(appl)->applid, APPL(appl)->param);
    }
}

static void controllercb_handle_capimsg(struct capi_ctr * card,
                __u16 appl, struct sk_buff *skb)
{
    int showctl = 0;
    __u8 cmd, subcmd;

    if (card->cardstate != CARD_RUNNING) {
        printk(KERN_INFO "kcapi: controller %d not active, got: %s",
               card->cnr, capi_message2str(skb->data));
        goto error;
    }
    cmd = CAPIMSG_COMMAND(skb->data);
        subcmd = CAPIMSG_SUBCOMMAND(skb->data);
    if (cmd == CAPI_DATA_B3 && subcmd == CAPI_IND) {
        card->nrecvdatapkt++;
            if (card->traceflag > 2) showctl |= 2;
    } else {
        card->nrecvctlpkt++;
            if (card->traceflag) showctl |= 2;
    }
    showctl |= (card->traceflag & 1);
    if (showctl & 2) {
        if (showctl & 1) {
            printk(KERN_DEBUG "kcapi: got [0x%lx] id#%d %s len=%u\n",
                   (unsigned long) card->cnr,
                   CAPIMSG_APPID(skb->data),
                   capi_cmd2str(cmd, subcmd),
                   CAPIMSG_LEN(skb->data));
        } else {
            printk(KERN_DEBUG "kcapi: got [0x%lx] %s\n",
                    (unsigned long) card->cnr,
                    capi_message2str(skb->data));
        }

    }
    skb_queue_tail(&recv_queue, skb);
    queue_task(&tq_recv_notify, &tq_immediate);
    mark_bh(IMMEDIATE_BH);
    return;

error:
    kfree_skb(skb);
}

static void controllercb_ready(struct capi_ctr * card)
{
    __u16 appl;

    card->cardstate = CARD_RUNNING;

    for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
        if (!VALID_APPLID(appl)) continue;
        if (APPL(appl)->releasing) continue;
        card->driver->register_appl(card, appl, &APPL(appl)->rparam);
    }

        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)
{
    __u16 appl;

        if (card->cardstate == CARD_FREE)
        return;
        if (card->cardstate == CARD_DETECTED)
        return;

        card->cardstate = CARD_DETECTED;

    memset(card->manu, 0, sizeof(card->manu));
    memset(&card->version, 0, sizeof(card->version));
    memset(&card->profile, 0, sizeof(card->profile));
    memset(card->serial, 0, sizeof(card->serial));

    for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
        struct capi_ncci **pp, **nextpp;
        for (pp = &APPL(appl)->nccilist; *pp; pp = nextpp) {
            if (NCCI2CTRL((*pp)->ncci) == card->cnr) {
                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 {
                nextpp = &(*pp)->next;
            }
        }
    }

    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)
{
    if (!card->blocked) {
        printk(KERN_DEBUG "kcapi: card %d suspend\n", CARDNR(card));
        card->blocked = 1;
    }
}

static void controllercb_resume_output(struct capi_ctr *card)
{
    if (card->blocked) {
        printk(KERN_DEBUG "kcapi: card %d resume\n", CARDNR(card));
        card->blocked = 0;
    }
}

/* ------------------------------------------------------------- */


struct capi_ctr *
drivercb_attach_ctr(struct capi_driver *driver, char *name, void *driverdata)
{
    struct capi_ctr *card, **pp;
    int i;

    for (i=0; i < CAPI_MAXCONTR && cards[i].cardstate != CARD_FREE; i++) ;
   
    if (i == CAPI_MAXCONTR) {
        printk(KERN_ERR "kcapi: out of controller slots\n");
           return 0;
    }
    card = &cards[i];
    memset(card, 0, sizeof(struct capi_ctr));
    card->driver = driver;
    card->cnr = CARDNR(card);
    strncpy(card->name, name, sizeof(card->name));
    card->cardstate = CARD_DETECTED;
    card->blocked = 0;
    card->driverdata = driverdata;
    card->traceflag = showcapimsgs;

        card->ready = controllercb_ready; 
        card->reseted = controllercb_reseted; 
        card->suspend_output = controllercb_suspend_output;
        card->resume_output = controllercb_resume_output;
        card->handle_capimsg = controllercb_handle_capimsg;
    card->appl_registered = controllercb_appl_registered;
    card->appl_released = controllercb_appl_released;
        card->new_ncci = controllercb_new_ncci;
        card->free_ncci = controllercb_free_ncci;

    for (pp = &driver->controller; *pp; pp = &(*pp)->next) ;
    card->next = 0;
    *pp = card;
    driver->ncontroller++;
    sprintf(card->procfn, "capi/controllers/%d", card->cnr);
    card->procent = create_proc_entry(card->procfn, 0, 0);
    if (card->procent) {
       card->procent->read_proc = 
        (int (*)(char *,char **,off_t,int,int *,void *))
            driver->ctr_read_proc;
       card->procent->data = card;
    }

    ncards++;
    printk(KERN_NOTICE "kcapi: Controller %d: %s attached\n",
            card->cnr, card->name);
    return card;
}

static int drivercb_detach_ctr(struct capi_ctr *card)
{
    struct capi_driver *driver = card->driver;
    struct capi_ctr **pp;

        if (card->cardstate == CARD_FREE)
        return 0;
        if (card->cardstate != CARD_DETECTED)
        controllercb_reseted(card);
    for (pp = &driver->controller; *pp ; pp = &(*pp)->next) {
            if (*pp == card) {
                *pp = card->next;
            driver->ncontroller--;
            ncards--;
                break;
        }
    }
    if (card->procent) {
       remove_proc_entry(card->procfn, 0);
       card->procent = 0;
    }
    card->cardstate = CARD_FREE;
    printk(KERN_NOTICE "kcapi: Controller %d: %s unregistered\n",
            card->cnr, card->name);
    return 0;
}

/* ------------------------------------------------------------- */

/* fallback if no driver read_proc function defined by driver */

static int driver_read_proc(char *page, char **start, off_t off,
                int count, int *eof, void *data)
{
    struct capi_driver *driver = (struct capi_driver *)data;
    int len = 0;

    len += sprintf(page+len, "%-16s %s\n", "name", driver->name);
    len += sprintf(page+len, "%-16s %s\n", "revision", driver->revision);

    if (len < off) 
           return 0;
    *eof = 1;
    *start = page + off;
    return ((count < len-off) ? count : len-off);
}

/* ------------------------------------------------------------- */

static struct capi_driver_interface di = {
    drivercb_attach_ctr,
    drivercb_detach_ctr,
};

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);
    if (driver->procent) {
       if (driver->driver_read_proc) {
           driver->procent->read_proc = 
                   (int (*)(char *,char **,off_t,int,int *,void *))
                    driver->driver_read_proc;
       } else {
           driver->procent->read_proc = driver_read_proc;
       }
       driver->procent->data = driver;
    }
    return &di;
}

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;
        printk(KERN_NOTICE "kcapi: driver %s detached\n", driver->name);
    } 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;
}

/* ------------------------------------------------------------- */
/* -------- CAPI2.0 Interface ---------------------------------- */
/* ------------------------------------------------------------- */

static __u16 capi_isinstalled(void)
{
    int i;
    for (i = 0; i < CAPI_MAXCONTR; i++) {
        if (cards[i].cardstate == CARD_RUNNING)
            return CAPI_NOERROR;
    }
    return CAPI_REGNOTINSTALLED;
}

static __u16 capi_register(capi_register_params * rparam, __u16 * applidp)
{
    int appl;
    int i;

    if (rparam->datablklen < 128)
        return CAPI_LOGBLKSIZETOSMALL;

    for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
        if (APPL_IS_FREE(appl))
            break;
    }
    if (appl > CAPI_MAXAPPL)
        return CAPI_TOOMANYAPPLS;

    APPL_MARK_USED(appl);
    skb_queue_head_init(&APPL(appl)->recv_queue);
    APPL(appl)->nncci = 0;

    memcpy(&APPL(appl)->rparam, rparam, sizeof(capi_register_params));

    for (i = 0; i < CAPI_MAXCONTR; i++) {
        if (cards[i].cardstate != CARD_RUNNING)
            continue;
        cards[i].driver->register_appl(&cards[i], appl,
                        &APPL(appl)->rparam);
    }
    *applidp = appl;
    printk(KERN_INFO "kcapi: appl %d up\n", appl);

    return CAPI_NOERROR;
}

static __u16 capi_release(__u16 applid)
{
    int i;

    if (!VALID_APPLID(applid) || APPL(applid)->releasing)
        return CAPI_ILLAPPNR;
    APPL(applid)->releasing++;
    skb_queue_purge(&APPL(applid)->recv_queue);
    for (i = 0; i < CAPI_MAXCONTR; i++) {
        if (cards[i].cardstate != CARD_RUNNING)
            continue;
        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);
        printk(KERN_INFO "kcapi: appl %d down\n", applid);
    }
    return CAPI_NOERROR;
}

static __u16 capi_put_message(__u16 applid, struct sk_buff *skb)
{
    struct capi_ncci *np;
    __u32 contr;
    int showctl = 0;
    __u8 cmd, subcmd;

    if (ncards == 0)
        return CAPI_REGNOTINSTALLED;
    if (!VALID_APPLID(applid))
        return CAPI_ILLAPPNR;
    if (skb->len < 12
        || !capi_cmd_valid(CAPIMSG_COMMAND(skb->data))
        || !capi_subcmd_valid(CAPIMSG_SUBCOMMAND(skb->data)))
        return CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
    contr = CAPIMSG_CONTROLLER(skb->data);
    if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) {
        contr = 1;
            if (CARD(contr)->cardstate != CARD_RUNNING) 
            return CAPI_REGNOTINSTALLED;
    }
    if (CARD(contr)->blocked)
        return CAPI_SENDQUEUEFULL;

    cmd = CAPIMSG_COMMAND(skb->data);
        subcmd = CAPIMSG_SUBCOMMAND(skb->data);

    if (cmd == CAPI_DATA_B3 && subcmd== CAPI_REQ) {
            if ((np = find_ncci(APPL(applid), CAPIMSG_NCCI(skb->data))) != 0
                && mq_enqueue(np, CAPIMSG_MSGID(skb->data)) == 0)
            return CAPI_SENDQUEUEFULL;
        CARD(contr)->nsentdatapkt++;
        APPL(applid)->nsentdatapkt++;
            if (CARD(contr)->traceflag > 2) showctl |= 2;
    } else {
        CARD(contr)->nsentctlpkt++;
        APPL(applid)->nsentctlpkt++;
            if (CARD(contr)->traceflag) showctl |= 2;
    }
    showctl |= (CARD(contr)->traceflag & 1);
    if (showctl & 2) {
        if (showctl & 1) {
            printk(KERN_DEBUG "kcapi: put [0x%lx] id#%d %s len=%u\n",
                   (unsigned long) contr,
                   CAPIMSG_APPID(skb->data),
                   capi_cmd2str(cmd, subcmd),
                   CAPIMSG_LEN(skb->data));
        } else {
            printk(KERN_DEBUG "kcapi: put [0x%lx] %s\n",
                    (unsigned long) contr,
                    capi_message2str(skb->data));
        }

    }
    CARD(contr)->driver->send_message(CARD(contr), skb);
    return CAPI_NOERROR;
}

static __u16 capi_get_message(__u16 applid, struct sk_buff **msgp)
{
    struct sk_buff *skb;

    if (!VALID_APPLID(applid))
        return CAPI_ILLAPPNR;
    if ((skb = skb_dequeue(&APPL(applid)->recv_queue)) == 0)
        return CAPI_RECEIVEQUEUEEMPTY;
    *msgp = skb;
    return CAPI_NOERROR;
}

static __u16 capi_set_signal(__u16 applid,
                 void (*signal) (__u16 applid, void *param),
                 void *param)
{
    if (!VALID_APPLID(applid))
        return CAPI_ILLAPPNR;
    APPL(applid)->signal = signal;
    APPL(applid)->param = param;
    return CAPI_NOERROR;
}

static __u16 capi_get_manufacturer(__u32 contr, __u8 buf[CAPI_MANUFACTURER_LEN])
{
    if (contr == 0) {
        strncpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN);
        return CAPI_NOERROR;
    }
    if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) 
        return CAPI_REGNOTINSTALLED;

    strncpy(buf, CARD(contr)->manu, CAPI_MANUFACTURER_LEN);
    return CAPI_NOERROR;
}

static __u16 capi_get_version(__u32 contr, struct capi_version *verp)
{
    if (contr == 0) {
        *verp = driver_version;
        return CAPI_NOERROR;
    }
    if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) 
        return CAPI_REGNOTINSTALLED;

    memcpy((void *) verp, &CARD(contr)->version, sizeof(capi_version));
    return CAPI_NOERROR;
}

static __u16 capi_get_serial(__u32 contr, __u8 serial[CAPI_SERIAL_LEN])
{
    if (contr == 0) {
        strncpy(serial, driver_serial, CAPI_SERIAL_LEN);
        return CAPI_NOERROR;
    }
    if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) 
        return CAPI_REGNOTINSTALLED;

    strncpy((void *) serial, CARD(contr)->serial, CAPI_SERIAL_LEN);
    return CAPI_NOERROR;
}

static __u16 capi_get_profile(__u32 contr, struct capi_profile *profp)
{
    if (contr == 0) {
        profp->ncontroller = ncards;
        return CAPI_NOERROR;
    }
    if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) 
        return CAPI_REGNOTINSTALLED;

    memcpy((void *) profp, &CARD(contr)->profile,
            sizeof(struct capi_profile));
    return CAPI_NOERROR;
}

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)
            break;
    spin_unlock(&drivers_lock);
    return dp;
}

#ifdef CONFIG_AVMB1_COMPAT
static int old_capi_manufacturer(unsigned int cmd, void *data)
{
    avmb1_loadandconfigdef ldef;
    avmb1_extcarddef cdef;
    avmb1_resetdef rdef;
    avmb1_getdef gdef;
    struct capi_driver *driver;
    struct capi_ctr *card;
    capicardparams cparams;
    capiloaddata ldata;
    int retval;

    switch (cmd) {
    case AVMB1_ADDCARD:
    case AVMB1_ADDCARD_WITH_TYPE:
        if (cmd == AVMB1_ADDCARD) {
           if ((retval = copy_from_user((void *) &cdef, data,
                        sizeof(avmb1_carddef))))
               return retval;
           cdef.cardtype = AVM_CARDTYPE_B1;
        } else {
           if ((retval = copy_from_user((void *) &cdef, data,
                        sizeof(avmb1_extcarddef))))
               return retval;
        }
        cparams.port = cdef.port;
        cparams.irq = cdef.irq;
        cparams.cardnr = cdef.cardnr;

                switch (cdef.cardtype) {
            case AVM_CARDTYPE_B1:
                driver = find_driver("b1isa");
                break;
            case AVM_CARDTYPE_T1:
                driver = find_driver("t1isa");
                break;
            default:
                driver = 0;
                break;
        }
        if (!driver) {
            printk(KERN_ERR "kcapi: driver not loaded.\n");
            return -EIO;
        }
        if (!driver->add_card) {
            printk(KERN_ERR "kcapi: driver has no add card function.\n");
            return -EIO;
        }

        return driver->add_card(driver, &cparams);

    case AVMB1_LOAD:
    case AVMB1_LOAD_AND_CONFIG:

        if (cmd == AVMB1_LOAD) {
            if ((retval = copy_from_user((void *) &ldef, data,
                        sizeof(avmb1_loaddef))))
                return retval;
            ldef.t4config.len = 0;
            ldef.t4config.data = 0;
        } else {
            if ((retval = copy_from_user((void *) &ldef, data,
                            sizeof(avmb1_loadandconfigdef))))
                return retval;
        }
        if (!VALID_CARD(ldef.contr))
            return -ESRCH;

        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);
            return -EINVAL;
        }
        if (ldef.t4file.data == 0) {
            printk(KERN_DEBUG "kcapi: load: invalid parameter: dataptr is 0\n");
            return -EINVAL;
        }

        ldata.firmware.user = 1;
        ldata.firmware.data = ldef.t4file.data;
        ldata.firmware.len = ldef.t4file.len;
        ldata.configuration.user = 1;
        ldata.configuration.data = ldef.t4config.data;
        ldata.configuration.len = ldef.t4config.len;

        if (card->cardstate != CARD_DETECTED) {
            printk(KERN_INFO "kcapi: load: contr=%d not in detect state\n", ldef.contr);
            return -EBUSY;
        }
        card->cardstate = CARD_LOADING;

        retval = card->driver->load_firmware(card, &ldata);

        if (retval) {
            card->cardstate = CARD_DETECTED;
            return retval;
        }

        while (card->cardstate != CARD_RUNNING) {

            set_current_state(TASK_INTERRUPTIBLE);
            schedule_timeout(HZ/10);    /* 0.1 sec */

            if (signal_pending(current))
                return -EINTR;
        }
        return 0;

    case AVMB1_RESETCARD:
        if ((retval = copy_from_user((void *) &rdef, data,
                     sizeof(avmb1_resetdef))))
            return retval;
        if (!VALID_CARD(rdef.contr))
            return -ESRCH;
        card = CARD(rdef.contr);

        if (card->cardstate == CARD_FREE)
            return -ESRCH;
        if (card->cardstate == CARD_DETECTED)
            return 0;

        card->driver->reset_ctr(card);

        while (card->cardstate > CARD_DETECTED) {

            set_current_state(TASK_INTERRUPTIBLE);
            schedule_timeout(HZ/10);    /* 0.1 sec */

            if (signal_pending(current))
                return -EINTR;
        }
        return 0;

    case AVMB1_GET_CARDINFO:
        if ((retval = copy_from_user((void *) &gdef, data,
                     sizeof(avmb1_getdef))))
            return retval;

        if (!VALID_CARD(gdef.contr))
            return -ESRCH;

        card = CARD(gdef.contr);

        if (card->cardstate == CARD_FREE)
            return -ESRCH;

        gdef.cardstate = card->cardstate;
        if (card->driver == find_driver("t1isa"))
            gdef.cardtype = AVM_CARDTYPE_T1;
        else gdef.cardtype = AVM_CARDTYPE_B1;

        if ((retval = copy_to_user(data, (void *) &gdef,
                     sizeof(avmb1_getdef))))
            return retval;

        return 0;

    case AVMB1_REMOVECARD:
        if ((retval = copy_from_user((void *) &rdef, data,
                     sizeof(avmb1_resetdef))))
            return retval;

        if (!VALID_CARD(rdef.contr))
            return -ESRCH;
        card = CARD(rdef.contr);

        if (card->cardstate == CARD_FREE)
            return -ESRCH;

        if (card->cardstate != CARD_DETECTED)
            return -EBUSY;

        card->driver->remove_ctr(card);

        while (card->cardstate != CARD_FREE) {

            set_current_state(TASK_INTERRUPTIBLE);
            schedule_timeout(HZ/10);    /* 0.1 sec */

            if (signal_pending(current))
                return -EINTR;
        }
        return 0;
    }
    return -EINVAL;
}
#endif

static int capi_manufacturer(unsigned int cmd, void *data)
{
        struct capi_ctr *card;
    int retval;

    switch (cmd) {
#ifdef CONFIG_AVMB1_COMPAT
    case AVMB1_ADDCARD:
    case AVMB1_ADDCARD_WITH_TYPE:
    case AVMB1_LOAD:
    case AVMB1_LOAD_AND_CONFIG:
    case AVMB1_RESETCARD:
    case AVMB1_GET_CARDINFO:
    case AVMB1_REMOVECARD:
        return old_capi_manufacturer(cmd, data);
#endif
    case KCAPI_CMD_TRACE:
    {
        kcapi_flagdef fdef;

        if ((retval = copy_from_user((void *) &fdef, data,
                     sizeof(kcapi_flagdef))))
            return retval;

        if (!VALID_CARD(fdef.contr))
            return -ESRCH;
        card = CARD(fdef.contr);
        if (card->cardstate == CARD_FREE)
            return -ESRCH;
        card->traceflag = fdef.flag;
        printk(KERN_INFO "kcapi: contr %d set trace=%d\n",
            card->cnr, card->traceflag);
        return 0;
    }

    case KCAPI_CMD_ADDCARD:
    {
        struct capi_driver *driver;
        capicardparams cparams;
        kcapi_carddef cdef;

        if ((retval = copy_from_user((void *) &cdef, data,
                            sizeof(cdef))))
            return retval;

        cparams.port = cdef.port;
        cparams.irq = cdef.irq;
        cparams.membase = cdef.membase;
        cparams.cardnr = cdef.cardnr;
        cparams.cardtype = 0;
        cdef.driver[sizeof(cdef.driver)-1] = 0;

        if ((driver = find_driver(cdef.driver)) == 0) {
            printk(KERN_ERR "kcapi: driver \"%s\" not loaded.\n",
                    cdef.driver);
            return -ESRCH;
        }

        if (!driver->add_card) {
            printk(KERN_ERR "kcapi: driver \"%s\" has no add card function.\n", cdef.driver);
            return -EIO;
        }

        return driver->add_card(driver, &cparams);
    }

    default:
        printk(KERN_ERR "kcapi: manufacturer command %d unknown.\n",
                    cmd);
        break;

    }
    return -EINVAL;
}

struct capi_interface avmb1_interface =
{
    capi_isinstalled,
    capi_register,
    capi_release,
    capi_put_message,
    capi_get_message,
    capi_set_signal,
    capi_get_manufacturer,
    capi_get_version,
    capi_get_serial,
    capi_get_profile,
    capi_manufacturer
};

/* ------------------------------------------------------------- */
/* -------- Exported Functions --------------------------------- */
/* ------------------------------------------------------------- */

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;
    spin_unlock(&capi_users_lock);
    printk(KERN_NOTICE "kcapi: %s attached\n", userp->name);

    return &avmb1_interface;
}

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

/* ------------------------------------------------------------- */
/* -------- Init & Cleanup ------------------------------------- */
/* ------------------------------------------------------------- */

EXPORT_SYMBOL(attach_capi_interface);
EXPORT_SYMBOL(detach_capi_interface);
EXPORT_SYMBOL(attach_capi_driver);
EXPORT_SYMBOL(detach_capi_driver);

/*
 * init / exit functions
 */

static int __init kcapi_init(void)
{
    char *p;
    char rev[32];

    MOD_INC_USE_COUNT;

    skb_queue_head_init(&recv_queue);

    tq_state_notify.routine = notify_handler;
    tq_state_notify.data = 0;

    tq_recv_notify.routine = recv_handler;
    tq_recv_notify.data = 0;

        proc_capi_init();

    if ((p = strchr(revision, ':')) != 0 && p[1]) {
        strncpy(rev, p + 2, sizeof(rev));
        rev[sizeof(rev)-1] = 0;
        if ((p = strchr(rev, '$')) != 0 && p > rev)
           *(p-1) = 0;
    } else
        strcpy(rev, "1.0");

#ifdef MODULE
        printk(KERN_NOTICE "CAPI-driver Rev %s: loaded\n", rev);
#else
    printk(KERN_NOTICE "CAPI-driver Rev %s: started\n", rev);
#endif
    MOD_DEC_USE_COUNT;
    return 0;
}

static void __exit kcapi_exit(void)
{
    char rev[10];
    char *p;

    if ((p = strchr(revision, ':'))) {
        strcpy(rev, p + 1);
        p = strchr(rev, '$');
        *p = 0;
    } else {
        strcpy(rev, "1.0");
    }

        proc_capi_exit();
    printk(KERN_NOTICE "CAPI-driver Rev%s: unloaded\n", rev);
}

module_init(kcapi_init);
module_exit(kcapi_exit);

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 1.0 pre-release build #13 powered by Captain Crunch Security Team | http://ccteam.ru | Generation time: 0.0069 ]--